Skip to content

Commit acd0f22

Browse files
committed
feat(core): implement fmu state save/restore (fmi2GetFMUstate, fmi2SetFMUstate, serialization)
1 parent b95b336 commit acd0f22

3 files changed

Lines changed: 83 additions & 18 deletions

File tree

packages/core/src/compiler/modelica/fmi.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,13 +327,17 @@ function generateModelDescriptionXml(
327327
// ModelExchange element
328328
if (opts.fmuType.modelExchange) {
329329
lines.push("");
330-
lines.push(` <ModelExchange modelIdentifier="${escapeXml(opts.modelIdentifier)}" />`);
330+
lines.push(
331+
` <ModelExchange modelIdentifier="${escapeXml(opts.modelIdentifier)}" canGetAndSetFMUstate="true" canSerializeFMUstate="true" />`,
332+
);
331333
}
332334

333335
// CoSimulation element
334336
if (opts.fmuType.coSimulation) {
335337
lines.push("");
336-
lines.push(` <CoSimulation modelIdentifier="${escapeXml(opts.modelIdentifier)}" />`);
338+
lines.push(
339+
` <CoSimulation modelIdentifier="${escapeXml(opts.modelIdentifier)}" canGetAndSetFMUstate="true" canSerializeFMUstate="true" />`,
340+
);
337341
}
338342

339343
// Default experiment

packages/core/src/compiler/modelica/fmu-codegen.ts

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -664,24 +664,62 @@ function generateFmi2FunctionsC(id: string, nVars: number, nStates: number, resu
664664
lines.push(
665665
"fmi2Status fmi2SetDebugLogging(fmi2Component c, fmi2Boolean loggingOn, size_t nCategories, const fmi2String categories[]) { (void)c; (void)loggingOn; (void)nCategories; (void)categories; return fmi2OK; }",
666666
);
667+
// ── FMU State Save/Restore ──
668+
lines.push("/* --- FMU State Management --- */");
669+
lines.push("fmi2Status fmi2GetFMUstate(fmi2Component c, fmi2FMUstate* state) {");
670+
lines.push(" FMUInstance* inst = (FMUInstance*)c;");
671+
lines.push(" FMUInstance* copy = (FMUInstance*)malloc(sizeof(FMUInstance));");
672+
lines.push(" if (!copy) return fmi2Error;");
673+
lines.push(" memcpy(copy, inst, sizeof(FMUInstance));");
674+
lines.push(" *state = (fmi2FMUstate)copy;");
675+
lines.push(" return fmi2OK;");
676+
lines.push("}");
677+
lines.push("");
678+
lines.push("fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate state) {");
679+
lines.push(" if (!state) return fmi2Error;");
680+
lines.push(" FMUInstance* inst = (FMUInstance*)c;");
681+
lines.push(" /* Preserve the callback pointers — they belong to the master, not the snapshot */");
682+
lines.push(" fmi2CallbackFunctions savedCb = inst->callbacks;");
683+
lines.push(" fmi2String savedName = inst->instanceName;");
684+
lines.push(" memcpy(inst, (FMUInstance*)state, sizeof(FMUInstance));");
685+
lines.push(" inst->callbacks = savedCb;");
686+
lines.push(" inst->instanceName = savedName;");
687+
lines.push(" return fmi2OK;");
688+
lines.push("}");
689+
lines.push("");
690+
lines.push("fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* state) {");
691+
lines.push(" (void)c;");
692+
lines.push(" if (!state || !*state) return fmi2Error;");
693+
lines.push(" free(*state);");
694+
lines.push(" *state = NULL;");
695+
lines.push(" return fmi2OK;");
696+
lines.push("}");
697+
lines.push("");
698+
lines.push("fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate state, size_t* size) {");
699+
lines.push(" (void)c; (void)state;");
700+
lines.push(" if (!size) return fmi2Error;");
701+
lines.push(" *size = sizeof(FMUInstance);");
702+
lines.push(" return fmi2OK;");
703+
lines.push("}");
704+
lines.push("");
705+
lines.push("fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate state, fmi2Byte buf[], size_t size) {");
706+
lines.push(" (void)c;");
707+
lines.push(" if (!state || !buf || size < sizeof(FMUInstance)) return fmi2Error;");
708+
lines.push(" memcpy(buf, (FMUInstance*)state, sizeof(FMUInstance));");
709+
lines.push(" return fmi2OK;");
710+
lines.push("}");
711+
lines.push("");
667712
lines.push(
668-
"fmi2Status fmi2GetFMUstate(fmi2Component c, fmi2FMUstate* state) { (void)c; (void)state; return fmi2Error; }",
669-
);
670-
lines.push(
671-
"fmi2Status fmi2SetFMUstate(fmi2Component c, fmi2FMUstate state) { (void)c; (void)state; return fmi2Error; }",
672-
);
673-
lines.push(
674-
"fmi2Status fmi2FreeFMUstate(fmi2Component c, fmi2FMUstate* state) { (void)c; (void)state; return fmi2Error; }",
675-
);
676-
lines.push(
677-
"fmi2Status fmi2SerializedFMUstateSize(fmi2Component c, fmi2FMUstate state, size_t* size) { (void)c; (void)state; (void)size; return fmi2Error; }",
678-
);
679-
lines.push(
680-
"fmi2Status fmi2SerializeFMUstate(fmi2Component c, fmi2FMUstate state, fmi2Byte buf[], size_t size) { (void)c; (void)state; (void)buf; (void)size; return fmi2Error; }",
681-
);
682-
lines.push(
683-
"fmi2Status fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte buf[], size_t size, fmi2FMUstate* state) { (void)c; (void)buf; (void)size; (void)state; return fmi2Error; }",
713+
"fmi2Status fmi2DeSerializeFMUstate(fmi2Component c, const fmi2Byte buf[], size_t size, fmi2FMUstate* state) {",
684714
);
715+
lines.push(" (void)c;");
716+
lines.push(" if (!buf || !state || size < sizeof(FMUInstance)) return fmi2Error;");
717+
lines.push(" FMUInstance* copy = (FMUInstance*)malloc(sizeof(FMUInstance));");
718+
lines.push(" if (!copy) return fmi2Error;");
719+
lines.push(" memcpy(copy, buf, sizeof(FMUInstance));");
720+
lines.push(" *state = (fmi2FMUstate)copy;");
721+
lines.push(" return fmi2OK;");
722+
lines.push("}");
685723
lines.push(
686724
"fmi2Status fmi2GetDirectionalDerivative(fmi2Component c, const fmi2ValueReference unknown[], size_t nUnknown, const fmi2ValueReference known[], size_t nKnown, const fmi2Real dvKnown[], fmi2Real dvUnknown[]) { (void)c; (void)unknown; (void)nUnknown; (void)known; (void)nKnown; (void)dvKnown; (void)dvUnknown; return fmi2Error; }",
687725
);

packages/cosim/src/participant.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,27 @@ export interface CoSimParticipant {
5858
* Terminate the participant and release resources.
5959
*/
6060
terminate(): Promise<void>;
61+
62+
// ── Optional: FMU state save/restore (for advanced master algorithms) ──
63+
64+
/** Whether this participant supports state save/restore. */
65+
readonly canGetAndSetState?: boolean;
66+
67+
/**
68+
* Save a snapshot of the current FMU state.
69+
* @returns An opaque state handle.
70+
*/
71+
getState?(): Promise<unknown>;
72+
73+
/**
74+
* Restore a previously saved FMU state.
75+
* @param state The opaque state handle from getState().
76+
*/
77+
setState?(state: unknown): Promise<void>;
78+
79+
/**
80+
* Free a previously saved FMU state.
81+
* @param state The opaque state handle to free.
82+
*/
83+
freeState?(state: unknown): Promise<void>;
6184
}

0 commit comments

Comments
 (0)