Skip to content

[FMI] Add FMI 3.0 export (#15686)#15692

Open
adrpo wants to merge 18 commits into
OpenModelica:masterfrom
adrpo:Ticket15686-FMI3Export
Open

[FMI] Add FMI 3.0 export (#15686)#15692
adrpo wants to merge 18 commits into
OpenModelica:masterfrom
adrpo:Ticket15686-FMI3Export

Conversation

@adrpo

@adrpo adrpo commented May 29, 2026

Copy link
Copy Markdown
Member

This is currently work in progress to support FMI3 export in OM (#15686).

  • runtime and codegen for FMI3
  • support eventEncountered in FMI3 for co-simulation
  • add support for arrays variables in FMI3 export
  • add support for terminals
  • add support for exporting ExternalObject as BinaryType
  • add support for serialization and deserialization of FMU state in FMI3 implementation
  • add support for directional derivatives in FMI3
  • generate buildDescription.xml
  • add basic support of Clocks
  • add support for graphical annotations
  • fix new backend modelDescription.xml input/output causality
  • add basic support for scheduled execution
  • generate inputs for unconnected non-top-level connectors (for terminals)

Check the commits for the latest updates to the messages

@adrpo adrpo force-pushed the Ticket15686-FMI3Export branch 2 times, most recently from 76c87c7 to 23cf0a6 Compare May 29, 2026 19:20
@adrpo adrpo added CI/Build MSYS2-UCRT64 Build pull request with Windows MSYS2 UCRT64 CI/CMake/Enable/MSYS2-UCRT64 Make Jenkins enable CMake build with MSYS2 UCRT64 on Windows. labels May 29, 2026
@adrpo adrpo force-pushed the Ticket15686-FMI3Export branch from 0910f52 to b32ff74 Compare May 30, 2026 00:07
@adrpo adrpo mentioned this pull request Jun 5, 2026
@adrpo adrpo force-pushed the Ticket15686-FMI3Export branch 5 times, most recently from 6130336 to 2c74f9d Compare June 7, 2026 14:31
adrpo and others added 10 commits June 7, 2026 17:05
Add support for exporting Functional Mock-up Units in FMI 3.0 format from
OpenModelica, for both the C and the C++ (Cpp) simulation runtimes. Covers
Model Exchange and Co-Simulation for the C runtime and Model Exchange for the
Cpp runtime; a first cut of Scheduled Execution is present for the C runtime.

The FMI 3.0 C and C++ model interfaces are self-contained and do not depend on
the FMI 2.0 OpenModelica wrapper files, so the two can evolve independently.

Verified with fmpy: exported FMUs validate against the FMI 3.0 schema and
simulate correctly (Model Exchange matches the analytic solution; Co-Simulation
matches the FMI 2.0 behaviour of the same model). Real/Integer/Boolean/String
variables map to the FMI 3.0 typed elements with correct, globally unique value
references.

Compiler / scripting
  - FMI.mo: accept "3.0" in checkFMIVersion/canExportFMU, add isFMIVersion30 and
    the "se" type / isFMISEType.
  - SimCodeUtil.mo: FMI 3.0 value-reference helpers (per-base-type offsets that
    make the references globally unique), the FMI ModelStructure and the
    remaining FMI-2.0-only SimVar code paths extended to FMI 3.0.
  - SimCodeMain.mo: generate the FMIDER jacobian and the output-alias preOpt
    modules for FMI 3.0; package only the FMI 3.0 model interface source.
  - SimCodeTV/SimCodeBackendTV: expose the new helpers/predicates to templates.
  - boot/LoadCompilerSources.mos and Compiler/.cmake/{template_compilation,
    meta_modelica_source_list}.cmake: register CodegenFMU3 for both bootstrap
    build systems.

Code generation
  - CodegenFMU3.tpl: new released-FMI-3.0 modelDescription.xml generator (typed
    ModelVariables, instantiationToken, explicit time variable, ModelStructure
    referencing value references, ModelExchange/CoSimulation/ScheduledExecution).
  - CodegenFMU.tpl / CodegenFMUCpp.tpl: dispatch the FMI 3.0 modelDescription and
    runtime, emit the FMI3_*_VR_OFFSET macros, .def exports, include paths and
    the FMI 3.0 platform tuple (e.g. x86_64-linux) for the binaries folder.

Runtime
  - fmi/export/fmi/fmi3*.h, cpp/FMU3/fmi3*.h: vendored official FMI 3.0 headers.
  - fmi/export/openmodelica/fmu3_model_interface.c/.h: self-contained FMI 3.0 C
    interface (own model engine + inlined Co-Simulation solver setup).
  - cpp/FMU3/FMU3Wrapper.{h,cpp}, FMU3GlobalSettings.h, FMU3Interface.cpp:
    FMI-3.0-native C++ wrapper and interface (no FMI 2.0 files or headers).

Build / packaging
  - RuntimeSources (.tpl/.cmake) + c/Makefile.common + fmi/CMakeLists.txt +
    cpp/CMakeLists.txt + cpp/cmake_3.14.cmake + fmi/export/buildproject/
    CMakeLists.txt.in: package and install the FMI 3.0 sources/headers for both
    the autotools and the CMake builds.

Tests
  - testsuite/openmodelica/fmi/ModelExchange/3.0 (fmi3_attributes_01, fmi3_types)
  - testsuite/openmodelica/fmi/CoSimulation/3.0 (fmi3_cs_01)
  - testsuite/openmodelica/cppruntime/fmu/modelExchange/3.0 (testCppFMI3)
    registered in the top-level testsuite Makefile.
  - .CI/scripts/SimulationRuntime-license-exceptions.txt: list the vendored
    FMI 3.0 reference headers.

Follow-ups: full Scheduled Execution (currently a stub), FMUState / directional
derivatives / Clocks / binary (stubbed), and a generated buildDescription.xml.

Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…a#15686)

Add FMI 3.0 FMU export for the new backend (--newBackend), including
native FMI 3.0 array variables (--newBackend --simCodeScalarize=false).
Previously the new backend had no FMU export at all:
generateModelCodeNewBackend only called callTargetTemplates (plain
simulation), so buildModelFMU(..., --newBackend) failed.

Compiler / SimCode:
  - SimCodeMain.mo: thread TranslateModelKind through the new-backend
    dispatch; for FMU() call callTargetTemplatesFMU on the converted
    SimCode and set fullPathPrefix / fmuTargetName / valueReferences /
    a minimal ModelStructure (continuous state derivatives + outputs).
  - NSimVar.mo: populate the FMI SimVar attributes (exportVar, causality,
    variability, initial_) and numArrayElement (dimension sizes).
  - SimCodeUtil.mo: getValueReferenceMapping public and element-aware;
    the FMI 3.0 value references (getFMI3ValueReference / getFMI3TypeOffset
    / getFMI3TimeValueReference) use the per-scalar, element-cumulative
    layout so each (array) variable occupies a contiguous, non-colliding
    block; numScalarElems / getFMIScalarVRs / getFMI3ArrayStart /
    createMinimalFMIModelStructure; getNumElems made public.
  - SimCodeTV.mo: expose the new helpers to the templates.

Code generation:
  - CodegenFMU.tpl: native array variables; per-scalar NUMBER_OF_* sizes
    and getReal/setReal block boundaries; STATES/STATESDERIVATIVES expand
    arrays to their scalar element value references; DimensionsFMU sets the
    runtime array dimensions in read_input_fmu so the value vectors are
    sized correctly; the broadcast scalar of an array start (array
    constructor / reduction) is used for the start attribute.
  - CodegenFMU3.tpl: native array variables
    (<Float64 ...><Dimension start="N"/></Float64>), per-scalar derivative
    attribute and array start attribute.

Runtime:
  - fmu3_model_interface.c: the typed get/set functions handle nValues
    (the contiguous scalar block of an array variable); read_input_fmu is
    called before calculateAllScalarLength so the array dimensions are
    known before the value vectors are sized.

Verified with fmpy: scalar and array models (e.g. Real x[3], mixed
Real/Integer arrays) export, compile, validate against the FMI 3.0 schema
and simulate to the analytic solution (Model Exchange); Co-Simulation also
runs. Scalar export (new and old backend) is unaffected. Adds the
testsuite case openmodelica/fmi/ModelExchange/3.0/fmi3_arrays.mos.

Follow-ups: explicit non-uniform array starts (currently broadcast); more
than one array variable in a single get/set call; ModelStructure
dependencies; integer/boolean/string multi-array refinements.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
Generate terminalsAndIcons/terminalsAndIcons.xml grouping the variables that
stem from a connector into one Terminal per connector instance.

Connector membership is taken from the flat-model component type: a variable
whose exported cref has a connector-typed qualifier (identType T_COMPLEX/
T_SUBTYPE_BASIC with ClassInf.CONNECTOR) is a member of that connector. The
terminal info is computed in SimCodeUtil.getFMI3Terminals from the SimVars and
emitted by CodegenFMU3, so it flows through SimCode to the templates (no
scripting post-step). Works for both the old and the new backend.

- SimCode.mo / SimCodeTV.mo: FmiTerminal, FmiTerminalMember
- SimCodeUtil.getFMI3Terminals (+ connector cref detection helpers)
- CodegenFMU3: fmiTerminalsAndIcons{,File}, Terminal3, TerminalMember3
- CodegenFMU.translateModel: write the file for FMI 3.0
- SimCodeMain: create terminalsAndIcons/ when the model has terminals
- testsuite: openmodelica/fmi/ModelExchange/3.0/fmi3_terminals.mos

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…ca#15686)

A Modelica ExternalObject is an opaque handle (void*) stored in the runtime's
extObjs array. It is now exported as an FMI 3.0 <Binary> variable whose value is
the raw bytes of the handle (sizeof(void*)). Previously external objects were
not exported at all.

- SimCodeUtil: external objects get their own per-base-type value-reference
  block; getFMI3TypeOffset places Binary after the strings; the independent
  variable (time) shifts past the binary block.
- CodegenFMU3: ModelVariables now iterates extObjVars; Variable3 emits <Binary>
  (causality=local, variability=fixed) via BinaryVariableAttributes3 (uses the
  SimVar cref directly, as external objects carry no exportVar).
- CodegenFMU: NUMBER_OF_EXTERNALOBJECTS and FMI3_BINARY_VR_OFFSET defines; time
  VR shifted accordingly. CodegenFMUCpp: matching offset defines for VR
  consistency (the C++ runtime Binary get/set remain stubs).
- fmu3_model_interface.c: fmi3GetBinary/fmi3SetBinary read/write the external
  object handle from fmuData->simulationInfo->extObjs (bounds-checked, one
  void*-sized value per reference).
- testsuite: openmodelica/fmi/ModelExchange/3.0/fmi3_binary_extobj.mos

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…5686)

Wire up FMU state save/restore and serialization for FMI 3.0, for both the C
and the C++ runtime, and advertise the capability in modelDescription.xml.

C runtime (fmu3_model_interface.c):
- the public fmi3GetFMUState/fmi3SetFMUState/fmi3FreeFMUState and
  fmi3SerializedFMUStateSize/fmi3SerializeFMUState/fmi3DeserializeFMUState were
  stubs returning fmi3Error; delegate them to the existing native omc*FMUstate
  helpers (which snapshot the simulation ring buffer and the parameters).
- broaden the get/set/free state masks to allow ContinuousTimeMode and
  Terminated, so FMU state can be taken/restored while stepping.

C++ runtime (FMU3/FMU3Wrapper, FMU3Interface):
- implement getFMUState/setFMUState/freeFMUState and the (de)serialization on
  FMU3Wrapper, snapshotting time, the continuous states and the full
  real/integer/boolean/string arrays through the bulk IContinuous accessors;
- wire the FMU3Interface entry points to the wrapper.

CodegenFMU3: ModelExchange/CoSimulation/ScheduledExecution now advertise
canGetAndSetFMUState="true" and canSerializeFMUState="true" unconditionally
(decoupled from the FMU_EXPERIMENTAL switch, which also gates unrelated
experimental features).

testsuite: add fmi3_fmustate.mos; update fmi3_cs_01.mos expected flags.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
Implement fmi3GetDirectionalDerivative for both runtimes. The symbolic FMIDER
Jacobian generation and the native evaluation helpers already existed and are
shared with FMI 2.0 (enabled with -d=-disableDirectionalDerivatives); only the
public FMI 3.0 entry points were stubs returning fmi3Error.

- C runtime (fmu3_model_interface.c): delegate fmi3GetDirectionalDerivative to
  omcGetDirectionalDerivative, mapping the unknown/known value references back to
  the per-real-type references (seed -> dvKnown, sensitivity -> dvUnknown).
- C++ runtime (FMU3/FMU3Interface.cpp): delegate to FMU3Wrapper::getDirectionalDerivative
  with the same value-reference mapping.

When directional derivatives are enabled the ModelExchange/CoSimulation element
already advertises providesDirectionalDerivatives="true" (it follows the FMIDER
Jacobian). fmi3GetAdjointDerivative stays a stub (not provided).

testsuite: add fmi3_directional_derivatives.mos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
In FMI 2.0 the FMU source file list was carried in modelDescription.xml
(<SourceFiles>); FMI 3.0 removed that and uses sources/buildDescription.xml
instead. Generate it for the C source FMU.

- CodegenFMU3: fmiBuildDescription emits a BuildConfiguration with the model
  identifier, a C SourceFileSet listing every source file, the
  FMI2_/FMI3_OVERRIDE_FUNCTION_PREFIX preprocessor definitions and the "." and
  "fmi" include directories (matching the FMU's own CMake/Make recipe).
  fmiBuildDescriptionFile writes sources/buildDescription.xml (skipped when no
  sources are shipped, e.g. --fmiFilter=blackBox).
- CodegenFMU.translateModel: write it for FMI 3.0 alongside modelDescription.xml.

Verified schema-valid and importer-buildable: compiling exactly per the
buildDescription (the listed sources, -I. -Ifmi and the two defines) produces a
working binary that simulates to the analytic solution.

testsuite: add fmi3_builddescription.mos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…ica#15686)

Export the model's clocked partitions as FMI 3.0 output <Clock> variables and
make them functional at runtime. The engine already ticks the clocks internally
during event mode (handleTimersFMI); this surfaces them through the FMI 3.0 API.

- SimCode / SimCodeUtil: FmiClock type and getFMI3Clocks, mapping each base
  clock (REAL/RATIONAL/EVENT clock kind) to an output clock with its
  intervalVariability and period/fraction. Clocks get their own value-reference
  block after the binary block; the time value reference shifts past it.
- CodegenFMU3: emit <Clock> variables (Clock3).
- CodegenFMU / CodegenFMUCpp: NUMBER_OF_CLOCKS and FMI3_CLOCK_VR_OFFSET defines,
  time VR shifted accordingly.
- fmu3_model_interface.c: implement fmi3GetClock (active when the base clock
  fired at the current event, from baseClocks[i].stats), fmi3GetIntervalDecimal
  and fmi3GetIntervalFraction (the clock period). fmi3SetClock stays a stub (no
  input clocks).
- C++ runtime: VR offsets kept consistent and fmi3GetClock/fmi3GetIntervalDecimal
  wired to FMU3Wrapper (output-clock activation is a C++ runtime limitation).

Verified: a periodic Clock(0.1) is declared as an output clock and ticks at
t=0.1/0.2/0.3 with interval 0.1 via the FMI 3.0 C API (Model Exchange).

testsuite: add fmi3_clocks.mos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
The FMU-state commit made canGetAndSetFMUState / canSerializeFMUState
unconditionally "true" for FMI 3.0 (the runtime now implements them). The Cpp
runtime ModelExchange test still expected "false" — update its baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…delica#15686)

Adds FMI 3.0 graphical user annotations (ticket OpenModelica#15686 task 9): the model
Icon is rendered to an SVG and an <GraphicalRepresentation> plus per-port
<TerminalGraphicalRepresentation> are written into terminalsAndIcons.xml.

New Qt-free C++ library OMGraphics (Compiler/runtime), mirroring OMEdit's
annotation graphics model:
- OMGraphics.{h,cpp}: data model (shapes/coordinate system/icon) + an SVG
  renderer (rectangle/line/polygon/ellipse+arc/text/bitmap, Modelica y-up to
  SVG y-down, %name substitution), a generic JSON value, an iconFromJson
  annotation parser and the FMI 3.0 GraphicalRepresentation XML emitter. Pure
  and standalone-testable.
- OMGraphics_omc.cpp: walks the in-memory model-instance reference of issue
  OpenModelica#15219 (boxed list-form MetaModelica JSON) into the renderer. Used only for
  the graphical side: the model icon, and each placed connector's placement box
  and connector-type icon.
- Registered in the CMake, autoconf (Makefile.common) and OMDev mingw builds.

Split of concerns:
- Ports and their input/output direction come from the flat model.
  SimCodeUtil.getFMI3Terminals also emits a single-member terminal for each
  top-level scalar input/output variable (from SimVars inputVars/outputVars);
  signal connectors such as RealInput/RealOutput collapse to plain input/output
  Real in the flat model and are detected this way. No JSON or
  modelDescription.xml is consulted for the direction.
- Placement geometry and icon shapes come from the model instance (graphics
  only). CevalScriptBackend renders icons/<modelIdentifier>.svg and
  icons/<iconBaseName>.svg, and injects a TerminalGraphicalRepresentation
  (placement box + iconBaseName) into the matching SimCode <Terminal>, keeping
  the FMI 3.0 schema order (GraphicalRepresentation before Terminals).

New backend support: the new backend marked no variable as FMI input/output
(modelDescription had no causality, outputVars was empty). NFVariable gains an
isOutput helper; NSimVar.parseBinding now sets INPUT/OUTPUT causality from the
variable direction and the SimVars build collects the output interface, so the
FMI 3.0 terminals (and modelDescription causality) work with --newBackend too.

Testsuite: new fmi3_graphics.mos (model icon, GraphicalRepresentation, placed
input/output ports with their TerminalGraphicalRepresentation and rendered port
icons); fmi3_terminals.mos updated for the new top-level output port terminal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
@adrpo adrpo force-pushed the Ticket15686-FMI3Export branch from 2c74f9d to 918a685 Compare June 7, 2026 15:06
…elica#15686)

Implements a simple Scheduled Execution (SE) strategy (ticket OpenModelica#15686 task 10),
building on the FMI 3.0 clock support: each base clock is one model partition,
and the simulation algorithm activates it via fmi3ActivateModelPartition.

- fmu3_model_interface.c: fmi3ActivateModelPartition was a no-op. It now maps the
  clock value reference to its base-clock index (FMI3_CLOCK_VR_OFFSET + index, the
  same scheme as fmi3GetClock), advances the model to the activation time and runs
  that clocked partition (its synchronous equations + interval update) directly,
  i.e. without handleBaseClock's Model-Exchange sub-clock timer scheduling and its
  initialization-time deferral (there is no internal event loop in SE). Any pending
  continuous/algebraic evaluation is flushed first and the deferred-update flag is
  cleared afterwards so the next fmi3Get* returns the freshly computed clocked
  outputs instead of re-evaluating over them. The clock activation stats are
  updated so fmi3GetClock / fmi3GetInterval* keep working.
- CodegenFMU3.tpl: for a Scheduled Execution FMU the model clocks are declared as
  input clocks (causality="input"); the importer activates the associated model
  partition. Model Exchange / Co-Simulation keep output clocks. The FMU type is
  threaded through fmiModelVariables3 to Clock3.

Verified with a Scheduled Execution driver on a clocked counter
(y = previous(y) + 1 on Clock(0.1)): activating the partition at t=0.1,0.2,0.3
yields y=1,2,3. Testsuite: new fmi3_scheduled.mos (ScheduledExecution element and
input clock). All 11 FMI 3.0 ModelExchange/3.0 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
adrpo and others added 6 commits June 8, 2026 18:07
…nModelica#15686)

The FMI 3.0 standard resolves a TerminalGraphicalRepresentation iconBaseName
as a relative URI against terminalsAndIcons/terminalsAndIcons.xml, and requires
a PNG image file (the SVG is only an optional companion); the FMU-layout section
likewise places the FMU/terminal icon files in terminalsAndIcons/. The previous
export instead wrote SVG-only icons to a top-level icons/ directory and emitted
iconBaseName without an extension, so an importer could not resolve them.

Now all icon files are written to terminalsAndIcons/: the model icon as
icon.png (+ icon.svg companion) and each placed connector port icon as
<base>.png (+ <base>.svg), with iconBaseName="<base>.png". A
TerminalGraphicalRepresentation is only emitted when its PNG was written, since
iconBaseName is mandatory.

To produce the mandatory PNG without pulling in Qt or an image library, add a
small zlib-only rasteriser to the OMGraphics runtime (renderIconPNG):
supersampled anti-aliased scanline fill for Rectangle/Polygon/Ellipse and thick
polylines for Line (Text/Bitmap are skipped), encoded as an RGBA PNG via zlib
compress2 + crc32. PNG bytes contain NUL and cannot pass through a
NUL-terminated MetaModelica String, so the new extern-C entry points
OMGraphics_writeIconPNGFromHandle / OMGraphics_writePlacedConnectorIconPNG
write the file directly given a destination path.

Updated fmi3_graphics.mos to the new terminalsAndIcons/ layout (PNG + SVG per
icon, iconBaseName with .png).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…5686)

A connector potential variable is often eliminated as an alias (e.g.
flange_a.phi == flange_b.phi == the state phi). Such a variable is still a real
member of its terminal and is emitted in modelDescription.xml (CodegenFMU3
writes the alias var lists into ModelVariables), but getFMI3Terminals only
scanned the non-alias var lists, so the member was dropped: a mechanical flange
exported with only its flow member (tau) and not its potential member (phi).

getFMI3Terminals now also scans the alias var lists (aliasVars, intAliasVars,
boolAliasVars, stringAliasVars); connectorMemberOf already filters to connector
members, so non-connector aliases are ignored. Real vars are scanned first so
the canonical member ordering is preserved, and members are de-duplicated by
memberName (which must be unique per terminal in FMI 3.0).

Adds fmi3_terminals_alias.mos covering a two-flange inertia whose phi members
are aliases: each flange terminal now keeps both tau and phi, and every member
variableName resolves to a variable in modelDescription.xml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…ule (OpenModelica#15686)

Align the terminalsAndIcons.xml terminals with the FMI 3.0 semantics (and with
Dymola's export):

- variableKind is now the connection-semantics kind, not the variable causality:
  "inflow" for a flow connector member (Kirchhoff's law), "signal" otherwise
  (values intended to be equal across a connection). The previous code emitted
  causality strings (input/output/local/parameter), which are not the predefined
  variableKind values and conflate two different concepts (causality is already
  in modelDescription.xml).
- matchingRule is "plug" for an ordinary, fully-defined Modelica connector (all
  members must match) and "bus" only for expandable connectors, instead of
  always "bus".
- terminalKind now carries the connector type path (e.g.
  Modelica.Mechanics.Rotational.Interfaces.Flange_a), taken from the connector
  type in the cref, so importers can check type compatibility.

The flow flag cannot be read from the connector type stored in the cref (it
keeps only the type path, not the member attributes), so it is captured from the
BackendDAE connectorType in a new SimVar field isConnectorFlow, set in
dlowvarToSimvar. The new backend does not yet track this and emits "signal" for
flow members (TODO noted in NSimVar.convert).

Updates fmi3_terminals.mos, fmi3_terminals_alias.mos and fmi3_graphics.mos to
the new attribute values.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…penModelica#15686)

The new backend's SimVar did not carry the connector flow flag, so flow
connector members were exported with variableKind="signal" instead of "inflow".
NFVariable already exposes the flow attribute (Variable.isFlow, reading
attributes.connectorType), so add an isConnectorFlow field to the new-backend
SimVar, populate it in NSimVar.create, and forward it in the conversion to the
old SimCodeVar instead of the previous hard-coded false.

With this, --newBackend produces the same terminal variableKind (inflow for
flow members, signal otherwise) as the default backend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…penModelica#15686)

FMI 3.0 represents an alias variable as an <Alias> child element of its canonical
variable, sharing that variable's valueReference (it carries no own
valueReference, factor or causality). OM instead emitted every alias as a
separate ModelVariables entry with its own valueReference. This switches local
positive aliases to the FMI 3.0 <Alias> form (matching e.g. Dymola), which also
lets terminal members reference connector-member aliases (such as
flange_a.phi == phi) by name without giving them a separate variable.

- getFMI3VariableAliases / isFMI3NestableAlias (SimCodeUtil): a SimVar is nestable
  when it is a positive (non-negated), scalar alias with no causality of its own
  (local); an <Alias> cannot express a factor or a causality, so negated and
  input/output/parameter aliases stay as full variables.
- CodegenFMU3.tpl: nestable aliases are skipped in the ModelVariables loop and
  instead emitted as <Alias> children of their canonical variable (CloseWithAliases3
  turns the self-closing element into an open/close pair when children exist).

The canonical variable keeps its valueReference, so nothing is renumbered; the
alias' former value reference simply becomes an unused gap (allowed by FMI 3.0).
Validated with fmpy on the sandbox models (terminals referencing the alias names
resolve); all FMI 3.0 ME and CS testsuite cases pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…ctors (OpenModelica#15686)

Export a model's unconnected acausal (physical) connectors as a causal FMU
boundary so the FMU can be reconnected into a physical circuit (as Dymola does
for FMI terminal export). An unconnected flow variable is normally given a
`flow = 0` equation; for FMI 3.0 export this instead exposes the flow as an input
and the connector's potential variable(s) as outputs, and drops the zero-flow
equation. The backend then causalizes the model in the natural
"component driven by its boundary flows" form.

For Modelica.Mechanics.Rotational MyInertia this yields flange_a.tau/flange_b.tau
as inputs and flange_a.phi/flange_b.phi as outputs (der(w) now depends on the
torque inputs), matching Dymola's causalization. Verified functionally: driving
flange_a.tau = 1 (J = 1) gives w(1) = 1 and phi(1) = 0.5 (rigid-body response).

- NFFlatten.causalizeAcausalConnectors / causalizeAcausalVar: run at the end of
  resolveConnections, gated on BUILDING_FMU and FMI_VERSION == "3.0". Finds the
  `flow = 0` equations of unconnected flow connector members, drops them, marks
  those flows as inputs and the matching potentials (same connector instance) as
  outputs. Balance-neutral, so it does not change solvability.
- fmi3_terminals_alias.mos updated: the flange members are now causalized
  (potential -> output, flow -> input) and still appear in the terminal.

Only FMI 3.0 export is affected. fmpy validates the result and all FMI 3.0 ME/CS
testsuite cases pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
…kend test (OpenModelica#15686)

The flange causalization breaks the new backend: once the zero-flow equations are
replaced by boundary inputs, NBResolveSingularities.balanceInitialization fails
and no FMU is produced. Gate causalizeAcausalConnectors on `not settings.newBackend`
so the new backend keeps building (it exports the unconnected flange as before:
flow as a fixed parameter, potential as an <Alias> of the state). The old backend
is unaffected and still produces the causal boundary.

The other FMI 3.0 terminal features added in this series (terminals, variableKind
inflow/signal, terminalKind, matchingRule=plug, <Alias> emission, flow detection)
work correctly on both backends. Add fmi3_terminals_alias_nb.mos, the --newBackend
counterpart of fmi3_terminals_alias.mos, asserting those features and documenting
that causalization is not applied on the new backend. (Broader new-backend FMI 3.0
modelDescription/ModelStructure has separate pre-existing limitations and is not
covered here.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Adrian Pop <adrian.pop@liu.se>
@AnHeuermann AnHeuermann self-requested a review June 9, 2026 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/Build MSYS2-UCRT64 Build pull request with Windows MSYS2 UCRT64 CI/CMake/Enable/MSYS2-UCRT64 Make Jenkins enable CMake build with MSYS2 UCRT64 on Windows.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant