|
| 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