Skip to content

Commit f351149

Browse files
authored
Prototype CasADi/DaeBuilder template (#5)
* Fresh clone of casadi_daebuilder.jinja from casadi_sx.jinja Signed-off-by: Joel Andersson <joel@jaeandersson.com> * Creating DaeBuilder symbols instead of SX symbols Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Setting parameter values with assign Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Setting constant values with assign Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Setting start values Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Output symbols Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Removed dead code Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Passing differential equations Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Refactored assignments Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Refactored referencing Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Calling not implemented Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] No space after , in composite name Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Separate reference arguments in assignment and references Signed-off-by: Joel Andersson <joel@jaeandersson.com> * [DaeBuilder] Square brackets instead of curly braces for ndarrays Signed-off-by: Joel Andersson <joel@jaeandersson.com> --------- Signed-off-by: Joel Andersson <joel@jaeandersson.com>
1 parent f96e925 commit f351149

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
{%- macro render_class(class) %}
2+
class {% if class.class_type == "Function" -%}__{% endif -%}{{ class.name }}(BaseModel):
3+
"""
4+
{{ class.description }}
5+
"""
6+
7+
def __init__(self):
8+
super().__init__('{{ class.name }}')
9+
10+
# Constants
11+
{{ render_variables(class, class.c, "c") | indent(4) }}
12+
13+
# Constant values
14+
{{ render_bindings(class, class.c) | indent(4) }}
15+
16+
# Parameters
17+
{{ render_variables(class, class.p, "p") | indent(4) }}
18+
19+
# Parameter values
20+
{{ render_bindings(class, class.p) | indent(4) }}
21+
22+
# Discrete states
23+
{{ render_variables(class, class.z, "x") | indent(4) }}
24+
25+
# Discrete states start values
26+
{{ render_start(class, class.z) | indent(4) }}
27+
28+
# Inputs
29+
{{ render_variables(class, class.u, "u") | indent(4) }}
30+
31+
# Outputs
32+
{{ render_variables(class, class.y, "y") | indent(4) }}
33+
34+
# Internal variables
35+
{{ render_variables(class, class.w, "w") | indent(4) }}
36+
37+
# Differential states
38+
{{ render_variables(class, class.x, "x") | indent(4) }}
39+
40+
# Differential states start values
41+
{{ render_start(class, class.x) | indent(4) }}
42+
43+
# Algorithmic statements
44+
{{ render_statement_list(class.algorithm) | indent(4) }}
45+
46+
# Algebraic equations
47+
{{ render_statement_list(class.algebric) | indent(4) }}
48+
49+
# Differential equations
50+
{{ render_ode(class.ode, class.x) | indent(4) }}
51+
52+
{% if class.class_type == "Function" %}
53+
def __call__(self, *args):
54+
raise NotImplementedError
55+
56+
# callable function singleton
57+
{{ class.name }} = __{{ class .name }}()
58+
59+
{% endif %}
60+
{%- endmacro %}
61+
62+
{%- macro render_ndarray(array) -%}
63+
{%- if array.dim | length == 1 -%}
64+
{%- if array.dim == [1] -%}
65+
{{ array.data[0] }}
66+
{%- else -%}
67+
{{ "[" }}{%- for i in range(array.dim[0]) -%}
68+
{{ array.data[i]}}{% if not loop.last %},{% endif -%}
69+
{%- endfor -%}{{ "]" }}
70+
{%- endif -%}
71+
{%- else -%}
72+
{{ "[" }}{%- for i in range(array.dim[0]) -%}
73+
{{ render_ndarray(array[i]) }}{% if not loop.last %},{% endif -%}
74+
{%- endfor -%}{{ "]" }}
75+
{%- endif -%}
76+
{%- endmacro -%}
77+
78+
{%- macro render_variables(class, var_list, ca_type) -%}
79+
{%- for var in var_list -%}
80+
self.dae.add('{{ var }}', dict(type = '{{ca_type}}'
81+
{%- set comp = class.components[var] -%}
82+
{%- if comp.array_subscripts | length > 0 -%}{{ ", dimension = [" }}
83+
{%- for sub in comp.array_subscripts -%}
84+
{{ render_subscript(sub) -}}{% if not loop.last %},{% endif -%}
85+
{%- endfor -%}
86+
{{ "]" }}{%- endif -%}))
87+
{% endfor -%}
88+
{%- endmacro -%}
89+
90+
{%- macro render_bindings(class, var_list) -%}
91+
{%- for var in var_list -%}
92+
{%- set comp = class.components[var] -%}
93+
self.dae.bind('{{ var }}', {{ render_ndarray(comp.start_value) | indent(4) }})
94+
{% endfor -%}
95+
{%- endmacro -%}
96+
97+
{%- macro render_start(class, var_list) -%}
98+
{%- for var in var_list -%}
99+
{%- set comp = class.components[var] -%}
100+
self.dae.set_start('{{ var }}', {{ render_ndarray(comp.start_value) | indent(4) }})
101+
{% endfor -%}
102+
{%- endmacro -%}
103+
104+
{%- macro render_ode(map, var_list) -%}
105+
{%- for var in var_list -%}
106+
{%- set expr = map[var] -%}
107+
self.dae.bind(self.dae.der('{{ var }}'), {{ render_expression(expr=expr) }})
108+
{% endfor -%}
109+
{%- endmacro -%}
110+
111+
{%- macro render_binary(op, expr) -%}
112+
{{ render_expression(expr=expr.lhs) }}{{ op }}{{ render_expression(expr=expr.rhs) -}}
113+
{%- endmacro -%}
114+
115+
{%- macro render_unary(op, expr) -%}
116+
{{ op }}{{ render_expression(expr=expr.rhs) -}}
117+
{%- endmacro -%}
118+
119+
{%- macro render_subscript(sub) -%}
120+
{%- for key, value in sub | items -%}
121+
{%- if key == "Expression" -%}
122+
{{ render_expression(expr=sub.Expression) | int }}
123+
{%- elif key == "Colon" -%}
124+
:
125+
{%- endif -%}
126+
{%- endfor -%}
127+
{%- endmacro -%}
128+
129+
{%- macro render_component_reference(comp) -%}
130+
{%- if comp.local %}.{% endif -%}
131+
{%- for part in comp.parts -%}
132+
'{{ part.name }}'
133+
{%- if part.array_subscripts | length > 0 %}, [
134+
{%- for sub in part.array_subscripts -%}
135+
{#- handles index from 1 to 0 from Modelica to python-#}
136+
{{ render_subscript(sub) | int -1 }}{% if not loop.last -%}, {% endif %}
137+
{%- endfor -%}]
138+
{%- endif -%}
139+
{%- endfor -%}
140+
{%- endmacro -%}
141+
142+
{%- macro render_expression(expr) -%}
143+
{%- for key, value in expr | items -%}
144+
{%- if key == "UnsignedReal" -%}
145+
{{ value }}
146+
{%- elif key == "UnsignedInteger" -%}
147+
{{ value }}
148+
{%- elif key == "Ref" -%}
149+
self.dae({{ render_component_reference(comp=value.comp) }})
150+
{%- elif key == "Add" -%}
151+
{{ render_binary(op=" + ", expr=value) -}}
152+
{%- elif key == "Sub" -%}
153+
{{ render_binary(op=" - ", expr=value) -}}
154+
{%- elif key == "Mul" -%}
155+
{{ render_binary(op="*", expr=value) -}}
156+
{%- elif key == "Div" -%}
157+
{{ render_binary(op="/", expr=value) -}}
158+
{%- elif key == "Exp" -%}
159+
{{- render_binary(op="^", expr=value) -}}
160+
{%- elif key == "Negative" -%}
161+
{{ render_unary(op="-", expr=value) -}}
162+
{%- elif key == "Parenthesis" -%}
163+
( {{- render_expression(expr=value.rhs) -}} )
164+
{%- elif key == "Not" %}
165+
{{- render_unary(op="!", expr=value) -}}
166+
{%- elif key == "Or" -%}
167+
ca.logic_or(
168+
{{- render_expression(expr=value.lhs) -}},
169+
{{- render_expression(expr=value.rhs) -}})
170+
{%- elif key == "And" -%}
171+
ca.logic_and(
172+
{{- render_expression(expr=value.lhs) -}},
173+
{{- render_expression(expr=value.rhs) -}})
174+
{%- elif key == "Equal" -%}
175+
{{- render_expression(expr=value.lhs) -}} ==
176+
{{- render_expression(expr=value.rhs) -}}
177+
{%- elif key == "ArrayArguments" -%}
178+
ca.vertcat(
179+
{%- for arg in value.args -%}
180+
{{- "\n " }} {{ render_expression(expr=arg) }} {%- if not loop.last -%},{% endif %}
181+
{%- endfor -%})
182+
{%- elif key == "FunctionCall" -%}
183+
{{ value.comp.name }}(
184+
{%- for arg in value.args -%}
185+
{{ render_expression(expr=arg) }} {% if not loop.last -%}, {% endif %}
186+
{%- endfor -%})
187+
{%- else -%}
188+
{{ warn("unknown expression: " + key + value | pprint) }}
189+
{%- endif -%}
190+
{%- endfor -%}
191+
{%- endmacro -%}
192+
193+
{%- macro render_statement_list(stmt_list) -%}
194+
{%- for stmt in stmt_list -%}
195+
{{ render_statement(stmt=stmt) }}
196+
{% endfor -%}
197+
{%- endmacro -%}
198+
199+
{%- macro render_statement(stmt) -%}
200+
{%- for key, value in stmt | items -%}
201+
{%- if key == "Assignment" -%}
202+
self.dae.bind({{ render_component_reference(comp=value.comp) }}, {{ render_expression(expr=value.rhs) }})
203+
{%- else -%}
204+
{{ warn("unknown statement: " + key) }}
205+
{%- endif %}
206+
{%- endfor -%}
207+
{%- endmacro -%}
208+
# rumoca pkg version : {{ def.rumoca_version }}
209+
# rumoca git version : {{ def.rumoca_git_hash }}
210+
# template md5 : {{ def.template_md5 }}
211+
# model md5 : {{ def.model_md5 }}
212+
213+
import casadi as ca
214+
import numpy as np
215+
216+
217+
class BaseModel:
218+
219+
def __init__(self, name):
220+
# Underlying DaeBuilder instance
221+
self.dae = ca.DaeBuilder(name)
222+
223+
def __repr__(self):
224+
return repr(self.dae)
225+
226+
{%- for key, val in def.classes | items %}
227+
228+
{{ render_class(class=val) }}
229+
{%- endfor %}

0 commit comments

Comments
 (0)