Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 76.5% 39 / 0 / 51
Functions: -% 0 / 0 / 0
Branches: -% 0 / 0 / 0

OMCompiler/Compiler/Template/CodegenFMU3.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 templates for generating the modelDescription.xml file for
37 // the FMI 3.0 (released, "3.0") export of OpenModelica.
38 //
39 // The most important differences from FMI 2.0 (CodegenFMU2.tpl) are:
40 //
41 // - the root attribute is `instantiationToken` instead of `guid`;
42 // - the FMU may declare ModelExchange, CoSimulation and ScheduledExecution;
43 // - ModelVariables contains typed variable elements (<Float64>, <Int32>,
44 // <Boolean>, <String>, <Enumeration>, ...) instead of <ScalarVariable> with
45 // a nested type element;
46 // - the independent variable (time) must be declared explicitly with
47 // causality="independent";
48 // - value references must be globally unique (in FMI 2.0 they only had to be
49 // unique per base type); we achieve this with the per-base-type offset
50 // scheme implemented in SimCodeCodegenUtil.getFMI3ValueReference;
51 // - ModelStructure references unknowns by valueReference (Output,
52 // ContinuousStateDerivative, InitialUnknown, EventIndicator) instead of by
53 // a 1-based index.
54
55 package CodegenFMU3
56
57 import interface SimCodeTV;
58 import interface SimCodeBackendTV;
59 import CodegenUtil.*;
60 import CodegenUtilSimulation.*;
61 import CodegenC.*; //unqualified import, no need the CodegenC is optional when calling a template; or mandatory when the same named template exists in this package (name hiding)
62 import CodegenFMUCommon.*;
63
64 // Code for generating modelDescription.xml file for FMI 3.0.
65 16 template fmiModelDescription(SimCode simCode, String guid, String FMUType, list<String> sourceFiles)
66 "Generates code for ModelDescription file for FMI 3.0 FMU target."
67 ::=
68 match simCode
69 case SIMCODE(__) then
70 <<
71 <fmiModelDescription
72 <%fmiModelDescriptionAttributes(simCode,guid)%>>
73 <%if isFMIMEType(FMUType) then ModelExchange3(simCode, sourceFiles)%>
74 <%if isFMICSType(FMUType) then CoSimulation3(simCode, sourceFiles)%>
75 <%if isFMISEType(FMUType) then ScheduledExecution3(simCode, sourceFiles)%>
76 <%UnitDefinitions(simCode)%>
77 <%TypeDefinitions3(simCode)%>
78 <% if Flags.isSet(Flags.FMU_EXPERIMENTAL) then
79 <<
80 <LogCategories>
81 <Category name="logEvents" description="logEvents" />
82 <Category name="logSingularLinearSystems" description="logSingularLinearSystems" />
83 <Category name="logNonlinearSystems" description="logNonlinearSystems" />
84 <Category name="logDynamicStateSelection" description="logDynamicStateSelection" />
85 <Category name="logStatusWarning" description="logStatusWarning" />
86 <Category name="logStatusDiscard" description="logStatusDiscard" />
87 <Category name="logStatusError" description="logStatusError" />
88 <Category name="logStatusFatal" description="logStatusFatal" />
89 <Category name="logStatusPending" description="logStatusPending" />
90 <Category name="logAll" description="logAll" />
91 <Category name="logFmi3Call" description="logFmi3Call" />
92 </LogCategories>
93 >> else
94 <<
95 <LogCategories>
96 <Category name="logEvents" />
97 <Category name="logSingularLinearSystems" />
98 <Category name="logNonlinearSystems" />
99 <Category name="logDynamicStateSelection" />
100 <Category name="logStatusWarning" />
101 <Category name="logStatusDiscard" />
102 <Category name="logStatusError" />
103 <Category name="logStatusFatal" />
104 <Category name="logStatusPending" />
105 <Category name="logAll" />
106 <Category name="logFmi3Call" />
107 </LogCategories>
108 >> %>
109 <%DefaultExperiment3(simulationSettingsOpt)%>
110 <%fmiModelVariablesAndStructure3(simCode, FMUType)%>
111 <%fmiOpenModelicaAnnotations(simCode)%>
112 </fmiModelDescription>
113 >>
114 end fmiModelDescription;
115
116 16 template fmiModelVariablesAndStructure3(SimCode simCode, String FMUType)
117 "<ModelVariables> and <ModelStructure>, from the view with one variable per
118 array, with the alias and value reference tables built for the length of them:
119 without them each entry searches every variable the model has."
120 ::=
121 let _ = SimCodeCodegenUtil.cacheFMI3VariableAliases(simCode)
122 match SimCodeCodegenUtil.fmi3ArrayView(simCode)
123 case view as SIMCODE(modelStructure=viewStructure) then
124 let variables = fmiModelVariables3(view, FMUType)
125 let structure = modelStructure3(view, viewStructure)
126 let _ = SimCodeCodegenUtil.clearFMI3VariableAliases()
127 <<
128 <%variables%>
129 <%structure%>
130 >>
131 end fmiModelVariablesAndStructure3;
132
133 16 template fmiOpenModelicaAnnotations(SimCode simCode)
134 "OpenModelica vendor annotations (<Figures> and <Visualization>) under one Annotation
135 element; empty when the model has neither. FMI 3.0 replaced 2.0\'s <Tool name=...>
136 with <Annotation type=...>, which is what fmi3Annotation.xsd validates."
137 ::=
138 let figures = fmiFiguresBody(simCode)
139 let visualization = fmiVisualizationElement(simCode)
140 if boolAnd(stringEq(figures,""), stringEq(visualization,"")) then '' else
141 <<
142 <Annotations>
143 <Annotation type="org.openmodelica">
144 <%figures%>
145 <%visualization%>
146 </Annotation>
147 </Annotations>
148 >>
149 end fmiOpenModelicaAnnotations;
150
151 ✗ template fmiFiguresBody(SimCode simCode)
152 "The <Figures> element, or nothing when no figures resolve."
153 ::=
154 match simCode
155 case SIMCODE(fmiFigures = {}) then ''
156 case SIMCODE(fmiFigures = figures) then
157 <<
158 <Figures version="1">
159 <%figures |> f => Figure3(f) ;separator="\n"%>
160 </Figures>
161 >>
162 end fmiFiguresBody;
163
164 16 template fmiVisualizationElement(SimCode simCode)
165 "A <Visualization> element pointing at the _visual.xml resource, or nothing."
166 ::=
167 let resource = SimCodeCodegenUtil.getFMI3VisualizationResource(simCode)
168 if stringEq(resource, "") then '' else
169 '<Visualization version="1" file="<%Util.escapeModelicaStringToXmlString(resource)%>"/>'
170 end fmiVisualizationElement;
171
172 ✗ template Figure3(FmiFigure figure)
173 ::=
174 match figure
175 case FMI_FIGURE(__) then
176 let titleAttr = figureStrAttr("title", title)
177 let groupAttr = figureStrAttr("group", group)
178 let prefAttr = if preferred then ' preferred="true"'
179 let captionElt = if boolNot(stringEq(caption, "")) then '<%\n%> <Caption><%Util.escapeModelicaStringToXmlString(caption)%></Caption>'
180 <<
181 <Figure<%titleAttr%><%groupAttr%><%prefAttr%>>
182 <%plots |> p => FigurePlot3(p) ;separator="\n"%><%captionElt%>
183 </Figure>
184 >>
185 end Figure3;
186
187 ✗ template FigurePlot3(FmiPlot plot)
188 ::=
189 match plot
190 case FMI_PLOT(__) then
191 let titleAttr = figureStrAttr("title", title)
192 let xAxisElt = FigureAxis3("x", xAxis)
193 let yAxisElt = FigureAxis3("y", yAxis)
194 let curveElts = (curves |> c => FigureCurve3(c) ;separator="\n")
195 let termRef = match terminal case SOME(t) then '<%\n%> <TerminalRef terminal="<%Util.escapeModelicaStringToXmlString(t)%>"/>'
196 <<
197 <Plot<%titleAttr%>>
198 <%xAxisElt%><%yAxisElt%><%curveElts%><%termRef%>
199 </Plot>
200 >>
201 end FigurePlot3;
202
203 ✗ template FigureAxis3(String role, FmiFigureAxis axis)
204 "An <Axis> element, emitted only when it carries a non-default attribute."
205 ::=
206 match axis
207 case FMI_FIGURE_AXIS(__) then
208 let labelAttr = figureStrAttr("label", label)
209 let unitAttr = figureStrAttr("unit", unit)
210 let minAttr = match min case SOME(r) then ' min="<%r%>"'
211 let maxAttr = match max case SOME(r) then ' max="<%r%>"'
212 let scaleAttr = if logScale then ' scale="Log"'
213 let body = '<%labelAttr%><%unitAttr%><%minAttr%><%maxAttr%><%scaleAttr%>'
214 if stringEq(body, "") then '' else '<Axis role="<%role%>"<%body%>/><%\n%> '
215 end FigureAxis3;
216
217 ✗ template FigureCurve3(FmiCurve curve)
218 ::=
219 match curve
220 case FMI_CURVE(__) then
221 let yAttr = ' y="<%figureCrefName(yVariable)%>"'
222 let xAttr = match xVariable case SOME(x) then ' x="<%figureCrefName(x)%>"'
223 let legendAttr = figureStrAttr("legend", legend)
224 '<Curve<%yAttr%><%xAttr%><%legendAttr%>/>'
225 end FigureCurve3;
226
227 ✗ template figureCrefName(DAE.ComponentRef cref)
228 "A cref formatted exactly like a variable name in modelDescription.xml."
229 ::=
230 Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(cref),"$", "_D_"))
231 end figureCrefName;
232
233 ✗ template figureStrAttr(String name, String value)
234 "A non-empty XML attribute, or nothing."
235 ::=
236 if stringEq(value, "") then '' else ' <%name%>="<%Util.escapeModelicaStringToXmlString(value)%>"'
237 end figureStrAttr;
238
239 15 template fmiBuildDescriptionFile(SimCode simCode, list<String> sourceFiles, String fileNamePrefixHash)
240 "Writes sources/buildDescription.xml (FMI 3.0). Returns the empty string (the
241 content is written to a file). Skipped when there are no source files
242 (--fmiFilter=blackBox or fmiSources=false)."
243 ::=
244 match sourceFiles
245 case {} then ''
246 else
247 let()= textFile(fmiBuildDescription(simCode, sourceFiles), '<%fileNamePrefixHash%>.fmutmp/sources/buildDescription.xml')
248 ''
249 end fmiBuildDescriptionFile;
250
251 2 template fmiBuildDescription(SimCode simCode, list<String> sourceFiles)
252 "Generates the FMI 3.0 sources/buildDescription.xml: the C source files, include
253 directories and preprocessor definitions needed to build the source FMU. In FMI
254 2.0 the source file list lived in modelDescription.xml (<SourceFiles>); FMI 3.0
255 moves it here. Paths are relative to the sources/ directory."
256 ::=
257 match simCode
258 case SIMCODE(__) then
259 let modelIdentifier = modelNamePrefix(simCode)
260 <<
261 <?xml version="1.0" encoding="UTF-8"?>
262 <fmiBuildDescription fmiVersion="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/modelica/fmi-standard/v3.0.2/schema/fmi3BuildDescription.xsd">
263 <BuildConfiguration modelIdentifier="<%modelIdentifier%>">
264 <SourceFileSet language="C17">
265 <%sourceFiles |> file => if boolNot(StringUtil.endsWith(file, ".rs")) then '<SourceFile name="<%file%>"/>' ;separator="\n"%>
266 <PreprocessorDefinition name="FMI2_OVERRIDE_FUNCTION_PREFIX"/>
267 <PreprocessorDefinition name="FMI3_OVERRIDE_FUNCTION_PREFIX"/>
268 <IncludeDirectory name="."/>
269 <IncludeDirectory name="fmi"/>
270 </SourceFileSet>
271 <%rustSourceFileSet(sourceFiles)%>
272 </BuildConfiguration>
273 </fmiBuildDescription>
274 >>
275 end fmiBuildDescription;
276
277 2 template rustSourceFileSet(list<String> sourceFiles)
278 "The Rust half of a --simCodeTarget=C source FMU: the crate roots, built into
279 the libSimulationRuntimeRust archive the C set links (see sources/CMakeLists.txt)."
280 ::=
281 let files = (sourceFiles |> file => if StringUtil.endsWith(file, ".rs") then '<SourceFile name="<%file%>"/>' ;separator="\n")
282 if files then
283 <<
284 <SourceFileSet language="Rust2024" compiler="cargo" compilerOptions="rustc --release --manifest-path rust/SimulationRuntime/rust/Cargo.toml -p openmodelica_simulation_runtime --lib --crate-type staticlib">
285 <%files%>
286 </SourceFileSet>
287 >>
288 end rustSourceFileSet;
289
290 15 template fmiTerminalsAndIconsFile(SimCode simCode, String fileNamePrefixHash)
291 "Writes terminalsAndIcons/terminalsAndIcons.xml into the FMU when the model has
292 connector-derived terminals. Returns the empty string (the content is written to
293 a file). The terminalsAndIcons/ directory is created in SimCodeMain beforehand."
294 ::=
295 match SimCodeCodegenUtil.getFMI3Terminals(simCode)
296 case {} then ''
297 case terminals then
298 let()= textFile(fmiTerminalsAndIcons(terminals), '<%fileNamePrefixHash%>.fmutmp/terminalsAndIcons/terminalsAndIcons.xml')
299 ''
300 end fmiTerminalsAndIconsFile;
301
302 8 template fmiTerminalsAndIcons(list<FmiTerminal> terminals)
303 "Generates the terminalsAndIcons.xml content (FMI 3.0 Terminals): one <Terminal>
304 per connector instance, grouping its member variables. The connector membership
305 is detected from the flat-model component type (a connector-typed cref qualifier)
306 in SimCodeCodegenUtil.getFMI3Terminals."
307 ::=
308 <<
309 <?xml version="1.0" encoding="UTF-8"?>
310 <fmiTerminalsAndIcons fmiVersion="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/modelica/fmi-standard/v3.0.2/schema/fmi3TerminalsAndIcons.xsd">
311 <Terminals>
312 <%terminals |> t => Terminal3(t) ;separator="\n"%>
313 </Terminals>
314 </fmiTerminalsAndIcons>
315 >>
316 end fmiTerminalsAndIcons;
317
318 130 template Terminal3(FmiTerminal terminal)
319 "Generates one <Terminal>. Members are matched by name (memberName) when two
320 terminals are connected: matchingRule=\"plug\" for an ordinary, fully-defined
321 Modelica connector (all members must match), \"bus\" for an expandable connector
322 (partial matching allowed). terminalKind, when known, carries the connector type
323 path so importers can check type compatibility."
324 ::=
325 match terminal
326 case FMI_TERMINAL(__) then
327 let rule = if isExpandable then "bus" else "plug"
328 let kindAttr = if stringEq(terminalKind, "") then "" else ' terminalKind="<%Util.escapeModelicaStringToXmlString(terminalKind)%>"'
329 <<
330 <Terminal name="<%Util.escapeModelicaStringToXmlString(name)%>" matchingRule="<%rule%>"<%kindAttr%>>
331 <%members |> m => TerminalMember3(m) ;separator="\n"%>
332 </Terminal>
333 >>
334 end Terminal3;
335
336 376 template TerminalMember3(FmiTerminalMember member)
337 "Generates a <TerminalMemberVariable> referencing a modelDescription variable.
338 variableName is formatted exactly like the variable name in modelDescription.xml."
339 ::=
340 match member
341 case FMI_TERMINAL_MEMBER(__) then
342 let varName = Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(variable),"$", "_D_"))
343 '<TerminalMemberVariable variableName="<%varName%>" memberName="<%Util.escapeModelicaStringToXmlString(memberName)%>" variableKind="<%variableKind%>"/>'
344 end TerminalMember3;
345
346 16 template fmiModelDescriptionAttributes(SimCode simCode, String guid)
347 "Generates the attributes of the fmiModelDescription element for FMI 3.0."
348 ::=
349 match simCode
350 case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__), vars = SIMVARS(stateVars = listStates))) then
351 let fmiVersion = '3.0'
352 let modelName = dotPath(modelInfo.name)
353 let description = modelInfo.description
354 let author = modelInfo.author
355 let version = modelInfo.version
356 let copyright = modelInfo.copyright
357 let license = modelInfo.license
358 let generationTool= 'OpenModelica Compiler <%getVersionNr()%>'
359 let generationDateAndTime = xsdateTime(Util.getCurrentDateTime())
360 let variableNamingConvention = 'structured'
361 let numberOfEventIndicators = getNumberOfEventIndicators(simCode)
362 <<
363 fmiVersion="<%fmiVersion%>"
364 modelName="<%Util.escapeModelicaStringToXmlString(modelName)%>"
365 instantiationToken="{<%guid%>}"
366 description="<%Util.escapeModelicaStringToXmlString(description)%>"
367 version="<%Util.escapeModelicaStringToXmlString(version)%>"
368 <% if stringEq(author, "") then '' else 'author="<%Util.escapeModelicaStringToXmlString(author)%>"'%>
369 <% if stringEq(copyright, "") then '' else 'copyright="<%Util.escapeModelicaStringToXmlString(copyright)%>"'%>
370 <% if stringEq(license, "") then '' else 'license="<%Util.escapeModelicaStringToXmlString(license)%>"'%>
371 generationTool="<%Util.escapeModelicaStringToXmlString(generationTool)%>"
372 generationDateAndTime="<%Util.escapeModelicaStringToXmlString(generationDateAndTime)%>"
373 variableNamingConvention="<%variableNamingConvention%>"
374 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
375 xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/modelica/fmi-standard/main/schema/fmi3ModelDescription.xsd"
376 >>
377 end fmiModelDescriptionAttributes;
378
379 14 template ModelExchange3(SimCode simCode, list<String> sourceFiles)
380 "Generates the ModelExchange element for FMI 3.0."
381 ::=
382 match simCode
383 case SIMCODE(__) then
384 let modelIdentifier = modelNamePrefix(simCode)
385 <<
386 <ModelExchange
387 modelIdentifier="<%modelIdentifier%>"
388 needsExecutionTool="false"
389 canBeInstantiatedOnlyOncePerProcess="false"
390 canGetAndSetFMUState="true"
391 canSerializeFMUState="true"
392 <% if providesDirectionalDerivative(simCode) then 'providesDirectionalDerivatives="true"' else 'providesDirectionalDerivatives="false"'%>
393 providesAdjointDerivatives="false"
394 providesPerElementDependencies="false"
395 needsCompletedIntegratorStep="true"/>
396 >>
397 end ModelExchange3;
398
399 2 template CoSimulation3(SimCode simCode, list<String> sourceFiles)
400 "Generates the CoSimulation element for FMI 3.0."
401 ::=
402 match simCode
403 case SIMCODE(__) then
404 let modelIdentifier = modelNamePrefix(simCode)
405 <<
406 <CoSimulation
407 modelIdentifier="<%Util.escapeModelicaStringToXmlString(modelIdentifier)%>"
408 needsExecutionTool="false"
409 canHandleVariableCommunicationStepSize="true"
410 canBeInstantiatedOnlyOncePerProcess="false"
411 maxOutputDerivativeOrder="1"
412 providesIntermediateUpdate="false"
413 mightReturnEarlyFromDoStep="true"
414 canReturnEarlyAfterIntermediateUpdate="false"
415 hasEventMode="true"
416 providesEvaluateDiscreteStates="false"
417 recommendedIntermediateInputSmoothness="0"
418 canGetAndSetFMUState="true"
419 canSerializeFMUState="true"
420 <% if providesDirectionalDerivative(simCode) then 'providesDirectionalDerivatives="true"' else 'providesDirectionalDerivatives="false"'%>
421 providesAdjointDerivatives="false"
422 providesPerElementDependencies="false"/>
423 >>
424 end CoSimulation3;
425
426 ✗ template ScheduledExecution3(SimCode simCode, list<String> sourceFiles)
427 "Generates the ScheduledExecution element for FMI 3.0."
428 ::=
429 match simCode
430 case SIMCODE(__) then
431 let modelIdentifier = modelNamePrefix(simCode)
432 <<
433 <ScheduledExecution
434 modelIdentifier="<%Util.escapeModelicaStringToXmlString(modelIdentifier)%>"
435 needsExecutionTool="false"
436 canBeInstantiatedOnlyOncePerProcess="false"
437 canGetAndSetFMUState="true"
438 canSerializeFMUState="true"
439 <% if providesDirectionalDerivative(simCode) then 'providesDirectionalDerivatives="true"' else 'providesDirectionalDerivatives="false"'%>
440 providesAdjointDerivatives="false"
441 providesPerElementDependencies="false"/>
442 >>
443 end ScheduledExecution3;
444
445 16 template DefaultExperiment3(Option<SimulationSettings> simulationSettingsOpt)
446 "Generates the DefaultExperiment element for FMI 3.0."
447 ::=
448 match simulationSettingsOpt
449 case SOME(SIMULATION_SETTINGS(startTime=startTime, stopTime=stopTime, tolerance=tolerance, stepSize=stepSize)) then
450 <<
451 <DefaultExperiment startTime="<%startTime%>" stopTime="<%stopTime%>" tolerance="<%tolerance%>" stepSize="<%stepSize%>"/>
452 >>
453 end DefaultExperiment3;
454
455 16 template TypeDefinitions3(SimCode simCode)
456 "Generates TypeDefinitions for FMI 3.0 (enumeration declared types)."
457 ::=
458 match simCode
459 case SIMCODE(modelInfo=modelInfo) then
460 match modelInfo
461 case MODELINFO(vars=SIMVARS(__)) then
462 let types = (SimCodeCodegenUtil.getEnumerationTypes(vars) |> var => TypeDefinition3(var) ;separator="\n")
463 if boolNot(stringEq(types, "")) then
464 <<
465 <TypeDefinitions>
466 <%types%>
467 </TypeDefinitions>
468 >>
469 end TypeDefinitions3;
470
471 4 template TypeDefinition3(SimVar simVar)
472 ::=
473 match simVar
474 case SIMVAR(type_ = T_ENUMERATION(path=path, names=names)) then
475 <<
476 <EnumerationType name="<%AbsynUtil.pathString(path, ".", false, false)%>" quantity="<%AbsynUtil.pathString(path, ".", false, false)%>">
477 <%names |> name hasindex i0 fromindex 1 => '<Item name="<%name%>" value="<%i0%>"/>' ;separator="\n"%>
478 </EnumerationType>
479 >>
480 end TypeDefinition3;
481
482 16 template fmiModelVariables3(SimCode simCode, String FMUType)
483 "Generates the ModelVariables element for FMI 3.0. FMUType selects the clock
484 causality: Scheduled Execution clocks are input clocks (the importer activates
485 the model partition), all others are output clocks."
486 ::=
487 match simCode
488 case SIMCODE(modelInfo=modelInfo) then
489 match modelInfo
490 case MODELINFO(vars=SIMVARS(stateVars=stateVars)) then
491 let numScalarStates = SimCodeCodegenUtil.numScalarElems(stateVars)
492 <<
493 <ModelVariables>
494 <%TimeVariable3(simCode)%>
495 <%vars.stateVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
496 <%vars.derivativeVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
497 <%vars.algVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
498 <%vars.discreteAlgVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
499 <%vars.paramVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
500 <%vars.aliasVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
501 <%vars.intAlgVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
502 <%vars.intParamVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
503 <%vars.intAliasVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
504 <%vars.boolAlgVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
505 <%vars.boolParamVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
506 <%vars.boolAliasVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
507 <%vars.stringAlgVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
508 <%vars.stringParamVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
509 <%vars.stringAliasVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
510 <%vars.extObjVars |> var => Variable3(var, simCode, numScalarStates) ;separator="\n"%>
511 <%SimCodeCodegenUtil.getFMI3Clocks(simCode) |> clk => Clock3(clk, FMUType) ;separator="\n"%>
512 <%EventIndicatorVariables3(simCode)%>
513 <%if isFMIMEType(FMUType) then DaeModeVariables3(simCode)%>
514 </ModelVariables>
515 >>
516 end fmiModelVariables3;
517
518 ✗ template DaeModeVariables3(SimCode simCode)
519 "fmi-ls-dae, for a Model Exchange FMU of a --daeMode model: the structural
520 parameter that switches it into DAE mode (false: an ordinary ODE FMU), and one
521 Float64 per residual of the DAE formulation. Their value references follow the
522 event indicators; the manifest (fmiLsDaeManifest) names them."
523 ::=
524 match simCode
525 case SIMCODE(daeModeData=SOME(dmd as DAEMODEDATA(__))) then
526 let daeModeVR = SimCodeCodegenUtil.getFMI3DaeModeValueReference(simCode)
527 <<
528 <Boolean name="_D_daeMode" valueReference="<%daeModeVR%>" causality="structuralParameter" variability="fixed" start="false" description="Set to true to enable DAE mode as defined by FMI-LS-DAE."/>
529 <%dmd.residualVars |> var => DaeResidualVariable3(var, daeModeVR) ;separator="\n"%>
530 >>
531 end DaeModeVariables3;
532
533 ✗ template DaeResidualVariable3(SimVar simVar, String daeModeVR)
534 ::=
535 match simVar
536 case SIMVAR(__) then
537 let nm = Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(name),"$", "_D_"))
538 '<Float64 name="<%nm%>" valueReference="<%intAdd(stringInt(daeModeVR), intAdd(1, index))%>" causality="local" variability="continuous" initial="calculated" description="DAE-mode residual <%index%>"/>'
539 end DaeResidualVariable3;
540
541 ✗ template fmiLsDaeManifest(SimCode simCode)
542 "fmi-ls-dae's manifest (extra/org.fmi-standard.fmi-ls-dae/fmi-ls-manifest.xml)
543 for a --daeMode Model Exchange FMU: the switch, the algebraic variables the
544 importer solves for beside the states, and a ModelStructure that restates the
545 model description's and adds the residuals — the fully implicit form
546 F(der(x), x, a, t) = 0, so no ContinuousStateDerivative entries."
547 ::=
548 match simCode
549 case SIMCODE(daeModeData=SOME(dmd as DAEMODEDATA(__)), modelStructure=modelStructure) then
550 let _ = SimCodeCodegenUtil.cacheFMI3ValueReferences(simCode)
551 let structure = match modelStructure
552 case SOME(fmistruct as FMIMODELSTRUCTURE(__)) then
553 <<
554 <%ModelStructureOutputs3(simCode, fmistruct.fmiOutputs)%>
555 <%ModelStructureInitialUnknowns3(simCode, fmistruct.fmiInitialUnknowns)%>
556 >>
557 else ''
558 let indicators = EventIndicators3(simCode)
559 let residuals = (SimCodeCodegenUtil.fmi3DaeResiduals(simCode) |> (vr, dependencyAttributes) => DaeResidual3(vr, dependencyAttributes) ;separator="\n")
560 let _ = SimCodeCodegenUtil.clearFMI3ValueReferences()
561 <<
562 <fmiDAEManifest
563 xmlns:fmi-ls="http://fmi-standard.org/fmi-ls-manifest"
564 fmi-ls:fmi-ls-name="org.fmi-standard.fmi-ls-dae"
565 fmi-ls:fmi-ls-version="<%SimCodeCodegenUtil.fmiLsDaeVersion()%>"
566 fmi-ls:fmi-ls-description="Layered standard for DAE support in FMI.">
567 <EnableDAEParameter valueReference="<%SimCodeCodegenUtil.getFMI3DaeModeValueReference(simCode)%>"/>
568 <AlgebraicVariables>
569 <%dmd.algebraicVars |> var => '<AlgebraicVariable valueReference="<%SimCodeCodegenUtil.getFMI3ValueReference(var, simCode)%>"/>' ;separator="\n"%>
570 </AlgebraicVariables>
571 <ModelStructure>
572 <%structure%>
573 <%indicators%>
574 <%residuals%>
575 </ModelStructure>
576 </fmiDAEManifest>
577 >>
578 end fmiLsDaeManifest;
579
580 ✗ template DaeResidual3(String vr, String dependencyAttributes)
581 ::=
582 '<Residual valueReference="<%vr%>"<%dependencyAttributes%>/>'
583 end DaeResidual3;
584
585 16 template EventIndicatorVariables3(SimCode simCode)
586 "FMI 3.0 requires event indicators to be exposed as Float64 variables that are
587 then referenced by valueReference from the ModelStructure EventIndicator list.
588 OpenModelica does not expose event indicators as named Modelica variables, so
589 we declare synthetic local Float64 variables for them. Their value references
590 form a contiguous block starting right after the time value reference
591 (FMI3_EVENT_INDICATOR_VR_START in the generated runtime), and the runtime
592 returns their values from the event indicators array in fmi3GetFloat64."
593 ::=
594 let n = getNumberOfEventIndicators(simCode)
595 let timeVR = SimCodeCodegenUtil.getFMI3TimeValueReference(simCode)
596 if intGt(stringInt(n), 0) then
597 (List.intRange(stringInt(n)) |> i =>
598 '<Float64 name="__zc_<%intSub(i,1)%>" valueReference="<%intAdd(stringInt(timeVR), i)%>" causality="local" variability="continuous" initial="calculated" description="event indicator <%intSub(i,1)%>"/>' ;separator="\n")
599 end EventIndicatorVariables3;
600
601 16 template TimeVariable3(SimCode simCode)
602 "Generates the mandatory independent variable (time) for FMI 3.0."
603 ::=
604 <<
605 <Float64 name="time" valueReference="<%SimCodeCodegenUtil.getFMI3TimeValueReference(simCode)%>" causality="independent" variability="continuous" description="Simulation time"/>
606 >>
607 end TimeVariable3;
608
609 3134 template Variable3(SimVar simVar, SimCode simCode, String numScalarStates)
610 "Generates a typed variable element for FMI 3.0."
611 ::=
612 match simVar
613 case SIMVAR(name = name, type_ = T_COMPLEX(complexClassType = ClassInf.EXTERNAL_OBJ(__))) then
614 // FMI 3.0 Binary variable: a Modelica ExternalObject is an opaque handle
615 // (void*); it is exported as a Binary whose value is the raw handle bytes (see
616 // fmi3GetBinary/fmi3SetBinary in fmu3_model_interface.c).
617 '<Binary <%BinaryVariableAttributes3(simVar, simCode)%>/>'
618 case SIMVAR(name = name, exportVar = exportVar, type_ = T_ARRAY(ty = arrayElementType)) then
619 // FMI 3.0 native array variable: one element with one valueReference and
620 // <Dimension> children (the value reference of the first scalar element; the
621 // array occupies a contiguous block of scalar value references).
622 if boolNot(isSome(exportVar)) then ''
623 else
624 match arrayElementType
625 case T_REAL(__) then
626 '<Float64 <%VariableCommonAttributes3(simVar, simCode)%><%DerivativeAttribute3(simVar, simCode, numScalarStates)%><%ArrayStartString3(simVar)%><%MinString2(simVar)%><%MaxString2(simVar)%><%NominalString2(simVar)%><%UnitString3(simVar, simCode)%><%relativeQuantity(simVar)%>><%Dimensions3(simVar)%></Float64>'
627 case T_INTEGER(__) then
628 '<Int32 <%VariableCommonAttributes3(simVar, simCode)%><%ArrayStartString3(simVar)%><%MinString2(simVar)%><%MaxString2(simVar)%>><%Dimensions3(simVar)%></Int32>'
629 case T_BOOL(__) then
630 '<Boolean <%VariableCommonAttributes3(simVar, simCode)%><%ArrayStartString3(simVar)%>><%Dimensions3(simVar)%></Boolean>'
631 case T_STRING(__) then
632 '<String <%VariableCommonAttributes3(simVar, simCode)%>><%Dimensions3(simVar)%></String>'
633 case T_ENUMERATION(path = path) then
634 '<Enumeration <%VariableCommonAttributes3(simVar, simCode)%>declaredType="<%AbsynUtil.pathString(path, ".", false, false)%>"<%ArrayStartString3(simVar)%>><%Dimensions3(simVar)%></Enumeration>'
635 else '<!-- UNKNOWN_ARRAY_TYPE <%CodegenUtil.crefStr(name)%> -->'
636 case SIMVAR(__) then
637 if SimCodeCodegenUtil.isFMI3NestableAlias(simVar) then
638 // emitted as an <Alias> child of its canonical variable (shares its
639 // valueReference), not as a separate ModelVariables entry
640 ''
641 else if stringEq(CodegenUtil.crefStr(name),"$dummy") then
642 <<>>
643 else if stringEq(CodegenUtil.crefStr(name),"der($dummy)") then
644 <<>>
645 else if boolNot(isSome(exportVar)) then
646 ''
647 else
648 match type_
649 case T_REAL(__) then
650 '<Float64 <%VariableCommonAttributes3(simVar, simCode)%><%DerivativeAttribute3(simVar, simCode, numScalarStates)%><%StartString2(simVar)%><%MinString2(simVar)%><%MaxString2(simVar)%><%NominalString2(simVar)%><%UnitString3(simVar, simCode)%><%relativeQuantity(simVar)%><%CloseWithAliases3("Float64", simVar, simCode)%>'
651 case T_INTEGER(__) then
652 '<Int32 <%VariableCommonAttributes3(simVar, simCode)%><%StartString2(simVar)%><%MinString2(simVar)%><%MaxString2(simVar)%><%CloseWithAliases3("Int32", simVar, simCode)%>'
653 case T_BOOL(__) then
654 '<Boolean <%VariableCommonAttributes3(simVar, simCode)%><%StartString2(simVar)%><%CloseWithAliases3("Boolean", simVar, simCode)%>'
655 case T_STRING(__) then
656 '<String <%VariableCommonAttributes3(simVar, simCode)%>><%StringStartChild3(simVar)%><%AliasElements3(simVar, simCode)%></String>'
657 case T_ENUMERATION(path=path) then
658 '<Enumeration <%VariableCommonAttributes3(simVar, simCode)%>declaredType="<%AbsynUtil.pathString(path, ".", false, false)%>"<%StartString2(simVar)%><%MinString2(simVar)%><%MaxString2(simVar)%><%CloseWithAliases3("Enumeration", simVar, simCode)%>'
659 else '<!-- UNKNOWN_TYPE <%CodegenUtil.crefStr(name)%> -->'
660 end Variable3;
661
662 997 template CloseWithAliases3(String tag, SimVar simVar, SimCode simCode)
663 "Close a typed FMI 3.0 variable element: self-closing when it has no FMI 3.0
664 <Alias> members, otherwise an open/close pair wrapping the <Alias> children."
665 ::=
666 let kids = AliasElements3(simVar, simCode)
667 if stringEq(kids, "") then '/>'
668 else '><%\n%><%kids%><%\n%> </<%tag%>>'
669 end CloseWithAliases3;
670
671 1009 template AliasElements3(SimVar simVar, SimCode simCode)
672 "Emit the FMI 3.0 <Alias> child elements of a canonical variable: one per
673 positive local alias that shares this variable's valueReference."
674 ::=
675 match simVar
676 case SIMVAR(__) then
677 match SimCodeCodegenUtil.getFMI3VariableAliases(simCode, simVar)
678 case {} then ''
679 case aliases then (aliases |> a => AliasElement3(a) ;separator="\n")
680 end AliasElements3;
681
682 802 template AliasElement3(SimVar aliasVar)
683 "One FMI 3.0 <Alias> element. The name is formatted exactly like a variable name
684 in modelDescription.xml; the alias shares the parent variable's valueReference."
685 ::=
686 match aliasVar
687 case SIMVAR(__) then
688 let nm = Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(Util.getOption(exportVar)),"$", "_D_"))
689 let desc = if comment then ' description="<%Util.escapeModelicaStringToXmlString(comment)%>"'
690 ' <Alias name="<%nm%>"<%desc%>/>'
691 end AliasElement3;
692
693 1 template Clock3(FmiClock clock, String FMUType)
694 "Generates an FMI 3.0 <Clock> variable for a model clock. For Scheduled
695 Execution the clock is an input clock (the importer activates the associated
696 model partition via fmi3ActivateModelPartition); otherwise it is an output
697 clock the FMU activates. intervalVariability is required; the period
698 (intervalDecimal) or the counter/resolution fraction is emitted when known."
699 ::=
700 match clock
701 case FMI_CLOCK(__) then
702 let causality = if isFMISEType(FMUType) then "input" else "output"
703 let nm = Util.escapeModelicaStringToXmlString(System.stringReplace(name,"$", "_D_"))
704 let intervalDec = if boolNot(stringEq(intervalDecimal, "")) then ' intervalDecimal="<%intervalDecimal%>"'
705 let fraction = if supportsFraction then ' supportsFraction="true"'
706 let counter = if boolNot(stringEq(intervalCounter, "")) then ' intervalCounter="<%intervalCounter%>"'
707 let res = if boolNot(stringEq(resolution, "")) then ' resolution="<%resolution%>"'
708 '<Clock name="<%nm%>" valueReference="<%valueReference%>" causality="<%causality%>" intervalVariability="<%intervalVariability%>"<%intervalDec%><%fraction%><%counter%><%res%>/>'
709 end Clock3;
710
711 52 template ArrayStartString3(SimVar simVar)
712 "Generates the start attribute (a space separated list of the scalar element
713 start values) for an FMI 3.0 array variable. Emitted only where a scalar would
714 emit a start (exact/approx initial or input), to keep the schema consistent."
715 ::=
716 match simVar
717 case SIMVAR(aliasvar = SimCodeVar.ALIAS(__)) then ''
718 case SIMVAR(varKind = STATE(__)) then arrayStartAttr(simVar)
719 case SIMVAR(initial_ = SOME(SimCodeVar.EXACT())) then arrayStartAttr(simVar)
720 case SIMVAR(initial_ = SOME(SimCodeVar.APPROX())) then arrayStartAttr(simVar)
721 case SIMVAR(causality = SOME(SimCodeVar.INPUT())) then arrayStartAttr(simVar)
722 else ''
723 end ArrayStartString3;
724
725 55 template arrayStartAttr(SimVar simVar)
726 ::=
727 let s = SimCodeCodegenUtil.getFMI3ArrayStart(simVar)
728 if stringEq(s, "") then '' else ' start="<%s%>"'
729 end arrayStartAttr;
730
731 216 template Dimensions3(SimVar simVar)
732 "Generates the <Dimension start='N'/> children of an FMI 3.0 array variable
733 from the variable's dimension sizes (row major)."
734 ::=
735 match simVar
736 case SIMVAR(numArrayElement = dims) then
737 (dims |> d => '<Dimension start="<%d%>"/>' ;separator="")
738 end Dimensions3;
739
740 1198 template FmiInitialAttribute3(SimVar simVar)
741 "Generates the FMI 3.0 initial attribute. Continuous-time states are special:
742 the non-scalarized array backend does not populate their initial_ field, so we
743 derive it from the variable's fixed attribute here. A fixed start is an exact
744 initial value (initial=\"exact\"), an unfixed start is a guess (initial=\"approx\").
745 All other variables fall back to the generic SimCode-derived attribute."
746 ::=
747 match simVar
748 case SIMVAR(varKind = STATE(__), isFixed = true) then "exact"
749 case SIMVAR(varKind = STATE(__)) then "approx"
750 else getFmiInitialAttributeStr(simVar)
751 end FmiInitialAttribute3;
752
753 1225 template VariableCommonAttributes3(SimVar simVar, SimCode simCode)
754 "Generates the common attributes (name, valueReference, description, causality,
755 variability, initial) shared by all FMI 3.0 typed variable elements. Note the
756 trailing space so type-specific attributes can be appended directly."
757 ::=
758 match simVar
759 case SIMVAR(__) then
760 let name = Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(Util.getOption(exportVar)),"$", "_D_"))
761 let valueReference = SimCodeCodegenUtil.getFMI3ValueReference(simVar, simCode)
762 let description = if comment then 'description="<%Util.escapeModelicaStringToXmlString(comment)%>" '
763 let variability_ = getVariability2(variability)
764 let caus = getCausality2(causality)
765 let initial = FmiInitialAttribute3(simVar)
766 <<
767 name="<%name%>" valueReference="<%valueReference%>" <%description%><%if boolNot(stringEq(caus, "")) then 'causality="'+caus+'" '%><%if boolNot(stringEq(variability_, "")) then 'variability="'+variability_+'" '%><%if boolNot(stringEq(initial, "")) then 'initial="'+initial+'" '%>
768 >>
769 end VariableCommonAttributes3;
770
771 1 template BinaryVariableAttributes3(SimVar simVar, SimCode simCode)
772 "Generates the attributes for an FMI 3.0 Binary variable (a Modelica
773 ExternalObject). External objects have no exportVar/start; the name is taken
774 directly from the SimVar cref. They are constructed during initialization and
775 constant afterwards, hence variability=\"fixed\", causality=\"local\"."
776 ::=
777 match simVar
778 case SIMVAR(__) then
779 let nm = Util.escapeModelicaStringToXmlString(System.stringReplace(crefStrNoUnderscore(name),"$", "_D_"))
780 let valueReference = SimCodeCodegenUtil.getFMI3ValueReference(simVar, simCode)
781 let description = if comment then 'description="<%Util.escapeModelicaStringToXmlString(comment)%>" '
782 <<
783 name="<%nm%>" valueReference="<%valueReference%>" <%description%>causality="local" variability="fixed"
784 >>
785 end BinaryVariableAttributes3;
786
787 27 template DerivativeAttribute3(SimVar simVar, SimCode simCode, String numScalarStates)
788 "Generates the derivative attribute (FMI 3.0 references the *valueReference* of
789 the state variable). For the C runtime the state value references precede the
790 state derivative value references contiguously in the real block, hence the
791 state value reference is the derivative value reference minus the number of
792 states. Scalar elements, not list entries: the new backend leaves a
793 non-scalarized array state as one entry (and one `varInfo.numStateVars`)."
794 ::=
795 match simVar
796 case SIMVAR(varKind = STATE_DER(__)) then
797 ' derivative="<%intSub(stringInt(SimCodeCodegenUtil.getFMI3ValueReference(simVar, simCode)), stringInt(numScalarStates))%>"'
798 else ''
799 end DerivativeAttribute3;
800
801 12 template StringStartChild3(SimVar simVar)
802 "Generates the nested <Start value=.../> element for an FMI 3.0 String variable."
803 ::=
804 match simVar
805 case SIMVAR(aliasvar = SimCodeVar.ALIAS(__)) then ''
806 case SIMVAR(initialValue = SOME(e as SCONST(__))) then
807 '<Start value="<%initValXml(e, "")%>"/>'
808 case SIMVAR(causality = SOME(SimCodeVar.INPUT())) then
809 '<Start value=""/>'
810 else ''
811 end StringStartChild3;
812
813 16 template modelStructure3(SimCode simCode, Option<FmiModelStructure> fmiModelStructure)
814 "Generates the FMI 3.0 ModelStructure. Unknowns are referenced by valueReference."
815 ::=
816 match fmiModelStructure
817 case SOME(fmistruct as FMIMODELSTRUCTURE(__)) then
818 // Every entry below looks its index up; without the table each lookup searches
819 // every variable the model has.
820 let _ = SimCodeCodegenUtil.cacheFMI3ValueReferences(simCode)
821 let outputs = ModelStructureOutputs3(simCode, fmistruct.fmiOutputs)
822 let derivatives = ModelStructureDerivatives3(simCode, fmistruct.fmiDerivatives)
823 let initials = ModelStructureInitialUnknowns3(simCode, fmistruct.fmiInitialUnknowns)
824 let indicators = EventIndicators3(simCode)
825 let _ = SimCodeCodegenUtil.clearFMI3ValueReferences()
826 <<
827 <ModelStructure>
828 <%outputs%>
829 <%derivatives%>
830 <%initials%>
831 <%indicators%>
832 </ModelStructure>
833 >>
834 else
835 <<
836 <ModelStructure>
837 <%EventIndicators3(simCode)%>
838 </ModelStructure>
839 >>
840 end modelStructure3;
841
842 16 template ModelStructureOutputs3(SimCode simCode, FmiOutputs fmiOutputs)
843 ::=
844 match fmiOutputs
845 case FMIOUTPUTS(fmiUnknownsList={}) then ""
846 case FMIOUTPUTS(__) then
847 (fmiUnknownsList |> u => FmiUnknown3(simCode, u, "Output") ;separator="\n")
848 end ModelStructureOutputs3;
849
850 16 template ModelStructureDerivatives3(SimCode simCode, FmiDerivatives fmiDerivatives)
851 ::=
852 match fmiDerivatives
853 case FMIDERIVATIVES(fmiUnknownsList={}) then ""
854 case FMIDERIVATIVES(__) then
855 (fmiUnknownsList |> u => FmiUnknown3(simCode, u, "ContinuousStateDerivative") ;separator="\n")
856 end ModelStructureDerivatives3;
857
858 16 template ModelStructureInitialUnknowns3(SimCode simCode, FmiInitialUnknowns fmiInitialUnknowns)
859 ::=
860 match fmiInitialUnknowns
861 case FMIINITIALUNKNOWNS(fmiUnknownsList={}) then ""
862 case FMIINITIALUNKNOWNS(__) then
863 (fmiUnknownsList |> u => FmiUnknown3(simCode, u, "InitialUnknown") ;separator="\n")
864 end ModelStructureInitialUnknowns3;
865
866 510 template FmiUnknown3(SimCode simCode, FmiUnknown fmiUnknown, String element)
867 "Generates a single FMI 3.0 ModelStructure entry, mapping the stored FMI index
868 to its value reference. Dependencies (also stored as indices) are mapped to
869 the value references of the corresponding knowns."
870 ::=
871 match fmiUnknown
872 case FMIUNKNOWN(__) then
873 <<
874 <<%element%> valueReference="<%SimCodeCodegenUtil.getFMI3ValueReferenceFromFMIIndex(simCode, index)%>"<%SimCodeCodegenUtil.fmi3UnknownDependencyAttributes(simCode, fmiUnknown)%>/>
875 >>
876 end FmiUnknown3;
877
878 16 template EventIndicators3(SimCode simCode)
879 "Generates the EventIndicator entries for FMI 3.0. The event indicators have
880 their own value reference range starting at FMI3_EVENT_INDICATOR_VR_START in
881 the generated runtime; here we only need them to be unique within the FMU."
882 ::=
883 let n = getNumberOfEventIndicators(simCode)
884 let timeVR = SimCodeCodegenUtil.getFMI3TimeValueReference(simCode)
885 if intGt(stringInt(n), 0) then
886 (List.intRange(stringInt(n)) |> i =>
887 '<EventIndicator valueReference="<%intAdd(stringInt(timeVR), i)%>"/>' ;separator="\n")
888 end EventIndicators3;
889
890 annotation(__OpenModelica_Interface="codegen_fmu");
891 end CodegenFMU3;
892
893 // vim: filetype=susan sw=2 sts=2
894