Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 90.9% 10 / 0 / 11
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenUtilSimulation.tpl
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 // This file defines util functions for templates for transforming Modelica/MetaModelica code to C like
37 // code. They are used in the code generator phase of the compiler to write
38 // target code.
39 //
40 // There are two root templates intended to be called from the code generator:
41 // translateModel and translateFunctions. These templates do not return any
42 // result but instead write the result to files. All other templates return
43 // text and are used by the root templates (most of them indirectly).
44 //
45 // To future maintainers of this file:
46 //
47 // - A line like this
48 // # var = "" /*BUFD*/
49 // declares a text buffer that you can later append text to. It can also be
50 // passed to other templates that in turn can append text to it. In the new
51 // version of Susan it should be written like this instead:
52 // let &var = buffer ""
53 //
54 // - A line like this
55 // ..., Text var /*BUFP*/, ...
56 // declares that a template takes a text buffer as input parameter. In the
57 // new version of Susan it should be written like this instead:
58 // ..., Text &var, ...
59 //
60 // - A line like this:
61 // ..., var /*BUFC*/, ...
62 // passes a text buffer to a template. In the new version of Susan it should
63 // be written like this instead:
64 // ..., &var, ...
65 //
66 // - Style guidelines:
67 //
68 // - Try (hard) to limit each row to 80 characters
69 //
70 // - Code for a template should be indented with 2 spaces
71 //
72 // - Exception to this rule is if you have only a single case, then that
73 // single case can be written using no indentation
74 //
75 // This single case can be seen as a clarification of the input to the
76 // template
77 //
78 // - Code after a case should be indented with 2 spaces if not written on the
79 // same line
80
81 package CodegenUtilSimulation
82
83 import interface SimCodeTV;
84 import ExpressionDumpTpl.*;
85 import CodegenUtil.*;
86
87 42131 template modelNamePrefix(SimCode simCode)
88 ::=
89 match simCode
90 case simCode as SIMCODE(__) then makeC89Identifier(fileNamePrefix)
91 end modelNamePrefix;
92
93 2400 template fileNamePrefix(SimCode simCode)
94 ::=
95 match simCode
96 case simCode as SIMCODE(__) then fileNamePrefix
97 end fileNamePrefix;
98
99 ✗ template fullPathPrefix(SimCode simCode)
100 ::=
101 match simCode
102 case simCode as SIMCODE(__) then fullPathPrefix
103 end fullPathPrefix;
104
105 /********* Equation Dumps *****************************/
106
107 806289 template equationIndex(SimEqSystem eq)
108 "Generates an equation."
109 ::=
110 match eq
111 case SES_RESIDUAL(__)
112 case SES_FOR_RESIDUAL(__)
113 case SES_GENERIC_RESIDUAL(__)
114 case SES_SIMPLE_ASSIGN(__)
115 case SES_SIMPLE_ASSIGN_CONSTRAINTS(__)
116 case SES_ARRAY_CALL_ASSIGN(__)
117 case SES_RESIZABLE_ASSIGN(__)
118 case SES_GENERIC_ASSIGN(__)
119 case SES_ENTWINED_ASSIGN(__)
120 case SES_IFEQUATION(__)
121 case SES_ALGORITHM(__)
122 case SES_INVERSE_ALGORITHM(__)
123 then index
124 case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__))
125 then ls.index
126 case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__))
127 then nls.index
128 case SES_MIXED(__)
129 case SES_WHEN(__)
130 case SES_FOR_LOOP(__)
131 then index
132 case SES_FOR_EQUATION(__)
133 then index
134 case SES_ALIAS(__)
135 then aliasOf
136 else error(sourceInfo(), "equationIndex failed")
137 end equationIndex;
138
139 18 template equationIndexAlternativeTearing(SimEqSystem eq)
140 "Generates an equation."
141 ::=
142 match eq
143 case SES_LINEAR(alternativeTearing=SOME(at as LINEARSYSTEM(__)))
144 then at.index
145 case SES_NONLINEAR(alternativeTearing=SOME(at as NONLINEARSYSTEM(__)))
146 then at.index
147 end equationIndexAlternativeTearing;
148
149 481467 template equationIndexGeneral(SimEqSystem eq)
150 ::=
151 match eq
152 case SES_LINEAR(alternativeTearing = SOME(LINEARSYSTEM))
153 case SES_NONLINEAR(alternativeTearing = SOME(NONLINEARSYSTEM)) then
154 equationIndexAlternativeTearing(eq)
155 else
156 equationIndex(eq)
157 end match
158 end equationIndexGeneral;
159
160 229993 template dumpEqs(list<SimEqSystem> eqs)
161 ::= match getConfigString(OBFUSCATE)
162 case "none" then dumpEqsWork(eqs)
163 end dumpEqs;
164
165 229993 template dumpEqsWork(list<SimEqSystem> eqs)
166 ::= eqs |> eq hasindex i0 =>
167 match eq
168 case e as SES_RESIDUAL(__) then
169 <<
170 equation index: <%equationIndex(eq)%>
171 type: RESIDUAL
172 <%escapeCComments(dumpExp(e.exp,"\""))%>
173 >>
174 case e as SES_FOR_RESIDUAL(__) then
175 <<
176 equation index: <%equationIndex(eq)%>
177 type: FOR_RESIDUAL
178 <%escapeCComments(dumpExp(e.exp,"\""))%>
179 >>
180 case e as SES_GENERIC_RESIDUAL(__) then
181 <<
182 equation index: <%equationIndex(eq)%>
183 type: GENERIC_RESIDUAL
184 <%escapeCComments(dumpExp(e.exp,"\""))%>
185 >>
186 case e as SES_SIMPLE_ASSIGN(__) then
187 <<
188 equation index: <%equationIndex(eq)%>
189 type: SIMPLE_ASSIGN
190 <%escapeCComments(dumpCref(e.cref))%> = <%escapeCComments(dumpExp(e.exp,"\""))%>
191 >>
192 case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then
193 <<
194 equation index: <%equationIndex(eq)%>
195 type: SIMPLE_ASSIGN_CONSTRAINTS
196 <%escapeCComments(dumpCref(e.cref))%> = <%escapeCComments(dumpExp(e.exp,"\""))%>
197 constraints: <%escapeCComments(dumpConstraints(e.cons))%>
198 >>
199 case e as SES_ARRAY_CALL_ASSIGN(lhs=lhs as CREF(__)) then
200 <<
201 equation index: <%equationIndex(eq)%>
202 type: ARRAY_CALL_ASSIGN
203
204 <%escapeCComments(dumpCref(lhs.componentRef))%> = <%escapeCComments(dumpExp(e.exp,"\""))%>
205 >>
206 case e as SES_RESIZABLE_ASSIGN(__) then
207 <<
208 equation index: <%equationIndex(eq)%>
209 type: SES_RESIZABLE_ASSIGN call index: <%e.call_index%>
210 >>
211 case e as SES_GENERIC_ASSIGN(__) then
212 <<
213 equation index: <%equationIndex(eq)%>
214 type: SES_GENERIC_ASSIGN call index: <%e.call_index%>
215 >>
216 case e as SES_ALGORITHM(statements={}) then
217 <<
218 empty algorithm
219 >>
220 case e as SES_ALGORITHM(statements=first::_) then
221 <<
222 equation index: <%equationIndex(eq)%>
223 type: ALGORITHM
224
225 <%e.statements |> stmt => escapeCComments(ppStmtStr(stmt,2))%>
226 >>
227 case e as SES_INVERSE_ALGORITHM(statements=first::_) then
228 <<
229 equation index: <%equationIndex(eq)%>
230 type: INVERSE ALGORITHM
231
232 <%e.statements |> stmt => escapeCComments(ppStmtStr(stmt,2))%>
233 >>
234 case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__)) then
235 <<
236 equation index: <%equationIndex(eq)%>
237 type: LINEAR
238
239 <%ls.vars |> SIMVAR(name=cr) => '<var><%escapeCComments(dumpCref(cr))%></var>' ; separator = "\n" %>
240 <row>
241 <%ls.beqs |> exp => '<cell><%escapeCComments(dumpExp(exp,"\""))%></cell>' ; separator = "\n" %><%\n%>
242 </row>
243 <matrix>
244 <%ls.simJac |> (i1,i2,eq) =>
245 <<
246 <cell row="<%i1%>" col="<%i2%>">
247 <%match eq
248 case e as SES_RESIDUAL(__) then
249 <<
250 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
251 >>
252 case e as SES_FOR_RESIDUAL(__) then
253 <<
254 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
255 >>
256 case e as SES_GENERIC_RESIDUAL(__) then
257 <<
258 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
259 >>
260 %>
261 </cell>
262 >>
263 %>
264 </matrix>
265 >>
266 case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__)) then
267 <<
268 equation index: <%equationIndex(eq)%>
269 indexNonlinear: <%nls.indexNonLinearSystem%>
270 type: NONLINEAR
271
272 vars: {<%nls.crefs |> cr => '<%escapeCComments(dumpCref(cr))%>' ; separator = ", "%>}
273 eqns: {<%nls.eqs |> eq => '<%equationIndex(eq)%>' ; separator = ", "%>}
274 >>
275 case e as SES_MIXED(__) then
276 <<
277 equation index: <%equationIndex(eq)%>
278 type: MIXED
279
280 <%dumpEqs(fill(e.cont,1))%>
281 <%dumpEqs(e.discEqs)%><%\n%>
282
283 <mixed>
284 <continuous index="<%equationIndex(e.cont)%>" />
285 <%e.discVars |> SIMVAR(name=cr) => '<var><%escapeCComments(dumpCref(cr))%></var>' ; separator = ","%>
286 <%e.discEqs |> eq => '<discrete index="<%equationIndex(eq)%>" />'%>
287 </mixed>
288 >>
289 case e as SES_WHEN(__) then
290 let body = dumpWhenOps(whenStmtLst)
291 <<
292 equation index: <%equationIndex(eq)%>
293 type: WHEN
294
295 when {<%conditions |> cond => '<%escapeCComments(dumpCref(cond))%>' ; separator=", " %>} then
296 <%body%>
297 end when;
298 >>
299 case e as SES_IFEQUATION(__) then
300 let branches = ifbranches |> (_,eqs) => dumpEqs(eqs)
301 let elsebr = dumpEqs(elsebranch)
302 <<
303 equation index: <%equationIndex(eq)%>
304 type: IFEQUATION
305
306 <%branches%>
307 <%elsebr%>
308 >>
309 case e as SES_FOR_LOOP(__) then
310 let &forstatement = buffer ""
311 let &forstatement += 'for ' + escapeCComments(dumpExp(e.iter,"\"")) + ' in ' + escapeCComments(dumpExp(e.startIt,"\""))
312 let &forstatement += ' : ' + escapeCComments(dumpExp(e.endIt,"\"")) + ' loop<%\n%>'
313 let &forstatement += ' <%escapeCComments(dumpCref(e.cref))%> = <%escapeCComments(dumpExp(e.exp,"\""))%>; '
314 let &forstatement += 'end for'
315 <<
316 equation index: <%equationIndex(e)%>
317 type: FOR_LOOP
318 <%forstatement%>
319 >>
320 case e as SES_FOR_EQUATION(__) then
321 let &forstatement = buffer ""
322 let &forstatement += 'for ' + escapeCComments(dumpExp(e.iter,"\"")) + ' in ' + escapeCComments(dumpExp(e.startIt,"\""))
323 let &forstatement += ' : ' + escapeCComments(dumpExp(e.endIt,"\"")) + ' loop<%\n%>'
324 let &forstatement += ' <%dumpEqs(e.body)%>;'
325 let &forstatement += 'end for'
326 <<
327 equation index: <%equationIndex(e)%>
328 type: FOR_EQUATION
329 <%forstatement%>
330 >>
331 case e as SES_ALIAS(__) then
332 <<
333 equation index: <%equationIndex(e)%>
334 type: ALIAS
335 alias of <%e.aliasOf%>
336 >>
337 case e as SES_ENTWINED_ASSIGN(__) then
338 <<
339 equation index: <%equationIndex(e)%>
340 type: ENTWINED_ASSIGN
341 <%dumpEqs(e.single_calls)%>
342 >>
343 else
344 <<
345 unknown equation
346 >>
347 end dumpEqsWork;
348
349
350 477 template dumpWhenOps(list<BackendDAE.WhenOperator> whenOps)
351 ::=
352 match whenOps
353 case ({}) then <<>>
354 case ((e as BackendDAE.ASSIGN(left=left as CREF(__)))::rest) then
355 let restbody = dumpWhenOps(rest)
356 <<
357 <%dumpCref(left.componentRef)%> = <%escapeCComments(dumpExp(e.right,"\""))%>;
358 <%restbody%>
359 >>
360 case ((e as BackendDAE.ASSIGN(left=left))::rest) then
361 let restbody = dumpWhenOps(rest)
362 <<
363 <%dumpExp(e.left,"\"")%> = <%escapeCComments(dumpExp(e.right,"\""))%>;
364 <%restbody%>
365 >>
366 case ((e as BackendDAE.REINIT(__))::rest) then
367 let restbody = dumpWhenOps(rest)
368 <<
369 reinit(<%dumpCref(e.stateVar)%>, <%escapeCComments(dumpExp(e.value,"\""))%>);
370 <%restbody%>
371 >>
372 case ((e as BackendDAE.ASSERT(__))::rest) then
373 let restbody = dumpWhenOps(rest)
374 <<
375 assert(<%escapeCComments(dumpExp(e.condition,"\""))%>, <%escapeCComments(dumpExp(e.message,"\""))%>, <%escapeCComments(dumpExp(e.level,"\""))%>);
376 <%restbody%>
377 >>
378 case ((e as BackendDAE.TERMINATE(__))::rest) then
379 let restbody = dumpWhenOps(rest)
380 <<
381 terminate(<%escapeCComments(dumpExp(e.message,"\""))%>)%>);
382 <%restbody%>
383 >>
384 case ((e as BackendDAE.NORETCALL(__))::rest) then
385 let restbody = dumpWhenOps(rest)
386 <<
387 noReturnCall(<%escapeCComments(dumpExp(e.exp,"\""))%>)%>);
388 <%restbody%>
389 >>
390 else error(sourceInfo(),"dumpEqs: Unknown equation")
391 end dumpWhenOps;
392
393 3 template dumpEqsAlternativeTearing(list<SimEqSystem> eqs)
394 ::= match getConfigString(OBFUSCATE)
395 case "none" then dumpEqsAlternativeTearingWork(eqs)
396 end dumpEqsAlternativeTearing;
397
398 3 template dumpEqsAlternativeTearingWork(list<SimEqSystem> eqs)
399 ::= eqs |> eq hasindex i0 =>
400 match eq
401 case e as SES_LINEAR(alternativeTearing=SOME(at as LINEARSYSTEM(__))) then
402 <<
403 equation index: <%equationIndexAlternativeTearing(eq)%>
404 type: LINEAR
405
406 <%at.vars |> SIMVAR(name=cr) => '<var><%dumpCref(cr)%></var>' ; separator = "\n" %>
407 <row>
408 <%at.beqs |> exp => '<cell><%escapeCComments(dumpExp(exp,"\""))%></cell>' ; separator = "\n" %><%\n%>
409 </row>
410 <matrix>
411 <%at.simJac |> (i1,i2,eq) =>
412 <<
413 <cell row="<%i1%>" col="<%i2%>">
414 <%match eq
415 case e as SES_RESIDUAL(__) then
416 <<
417 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
418 >>
419 case e as SES_FOR_RESIDUAL(__) then
420 <<
421 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
422 >>
423 case e as SES_GENERIC_RESIDUAL(__) then
424 <<
425 <residual><%escapeCComments(dumpExp(e.exp,"\""))%></residual>
426 >>
427 %>
428 </cell>
429 >>
430 %>
431 </matrix>
432
433 This is the alternative tearing set with casual solvability rules.
434 If it fails, this function will call the strict tearing set.
435 >>
436 case e as SES_NONLINEAR(alternativeTearing=SOME(at as NONLINEARSYSTEM(__))) then
437 <<
438 equation index: <%equationIndexAlternativeTearing(eq)%>
439 indexNonlinear: <%at.indexNonLinearSystem%>
440 type: NONLINEAR
441
442 vars: {<%at.crefs |> cr => '<%dumpCref(cr)%>' ; separator = ", "%>}
443 eqns: {<%at.eqs |> eq => '<%equationIndex(eq)%>' ; separator = ", "%>}
444
445 This is the alternative tearing set with casual solvability rules.
446 If it fails, this function will call the strict tearing set.
447 >>
448 else
449 <<
450 unknown equation
451 >>
452 end dumpEqsAlternativeTearingWork;
453
454 annotation(__OpenModelica_Interface="codegen");
455 end CodegenUtilSimulation;
456
457 // vim: filetype=susan sw=2 sts=2
458