Skip to content

Commit daf9d9d

Browse files
committed
feat(core): fmi 3.0 extended precision getters, clock APIs, and scheduled execution
1 parent 1071f0c commit daf9d9d

2 files changed

Lines changed: 103 additions & 54 deletions

File tree

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,14 @@ function generateModelDescriptionXml3(
851851
);
852852
}
853853

854+
// ScheduledExecution element
855+
if (opts.fmuType.scheduledExecution) {
856+
lines.push("");
857+
lines.push(
858+
` <ScheduledExecution modelIdentifier="${escapeXml(opts.modelIdentifier)}" needsExecutionTool="false" canBeInstantiatedOnlyOncePerProcess="false" canGetAndSetFMUState="true" canSerializeFMUState="true" providesDirectionalDerivatives="true" />`,
859+
);
860+
}
861+
854862
// ScheduledExecution element
855863
if (opts.fmuType.scheduledExecution) {
856864
lines.push("");

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

Lines changed: 95 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -450,67 +450,118 @@ function generateFmi3FunctionsC(
450450
L.push("fmi3Status fmi3Reset(fmi3Instance instance) { (void)instance; return fmi3OK; }");
451451
L.push("");
452452

453-
// Get/Set Float64 (array-aware batching)
453+
const numericTypes = ["Float32", "Float64", "Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64"];
454+
for (const t of numericTypes) {
455+
L.push(` // Get/Set ${t} (array-aware batching)`);
456+
L.push(
457+
` fmi3Status fmi3Get${t}(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3${t} value[], size_t nValues) {`,
458+
);
459+
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
460+
L.push(" size_t vi = 0;");
461+
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
462+
L.push(" if (vr[i] < N_VARS) {");
463+
L.push(" size_t sz = varSizes[vr[i]];");
464+
L.push(
465+
` for (size_t j = 0; j < sz && vi < nValues; j++) value[vi++] = (fmi3${t})inst->model.vars[vr[i] + j];`,
466+
);
467+
L.push(" }");
468+
L.push(" }");
469+
L.push(" return fmi3OK;");
470+
L.push(" }");
471+
L.push(
472+
` fmi3Status fmi3Set${t}(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3${t} value[], size_t nValues) {`,
473+
);
474+
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
475+
L.push(" size_t vi = 0;");
476+
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
477+
L.push(" if (vr[i] < N_VARS) {");
478+
L.push(" size_t sz = varSizes[vr[i]];");
479+
L.push(
480+
" for (size_t j = 0; j < sz && vi < nValues; j++) inst->model.vars[vr[i] + j] = (double)value[vi++];",
481+
);
482+
L.push(" }");
483+
L.push(" }");
484+
L.push(" return fmi3OK;");
485+
L.push(" }");
486+
L.push("");
487+
}
488+
489+
// Get/Set Boolean (array-aware batching)
454490
L.push(
455-
"fmi3Status fmi3GetFloat64(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 value[], size_t nValues) {",
491+
"fmi3Status fmi3GetBoolean(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) {",
456492
);
457493
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
458494
L.push(" size_t vi = 0;");
459495
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
460496
L.push(" if (vr[i] < N_VARS) {");
461497
L.push(" size_t sz = varSizes[vr[i]];");
462-
L.push(" for (size_t j = 0; j < sz && vi < nValues; j++) value[vi++] = inst->model.vars[vr[i] + j];");
498+
L.push(" for (size_t j = 0; j < sz && vi < nValues; j++) value[vi++] = inst->model.vars[vr[i] + j] != 0.0;");
463499
L.push(" }");
464500
L.push(" }");
465501
L.push(" return fmi3OK;");
466502
L.push("}");
467503
L.push(
468-
"fmi3Status fmi3SetFloat64(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 value[], size_t nValues) {",
504+
"fmi3Status fmi3SetBoolean(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) {",
469505
);
470506
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
471507
L.push(" size_t vi = 0;");
472508
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
473509
L.push(" if (vr[i] < N_VARS) {");
474510
L.push(" size_t sz = varSizes[vr[i]];");
475-
L.push(" for (size_t j = 0; j < sz && vi < nValues; j++) inst->model.vars[vr[i] + j] = value[vi++];");
511+
L.push(
512+
" for (size_t j = 0; j < sz && vi < nValues; j++) inst->model.vars[vr[i] + j] = value[vi++] ? 1.0 : 0.0;",
513+
);
476514
L.push(" }");
477515
L.push(" }");
478516
L.push(" return fmi3OK;");
479517
L.push("}");
480518
L.push("");
481519

482-
// Get/Set Int32 (array-aware batching)
520+
// Get/Set String
483521
L.push(
484-
"fmi3Status fmi3GetInt32(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Int32 value[], size_t nValues) {",
522+
"fmi3Status fmi3GetString(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) {",
523+
);
524+
L.push(" FMU3Instance* inst = (FMU3Instance*)instance; (void)nValues;");
525+
L.push(
526+
' for (size_t i = 0; i < nvr; i++) { if (vr[i] < N_STRING_VARS) value[i] = inst->model.stringVars[vr[i]] ? inst->model.stringVars[vr[i]] : ""; }',
485527
);
486-
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
487-
L.push(" size_t vi = 0;");
488-
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
489-
L.push(" if (vr[i] < N_VARS) {");
490-
L.push(" size_t sz = varSizes[vr[i]];");
491-
L.push(" for (size_t j = 0; j < sz && vi < nValues; j++) value[vi++] = (fmi3Int32)inst->model.vars[vr[i] + j];");
492-
L.push(" }");
493-
L.push(" }");
494528
L.push(" return fmi3OK;");
495529
L.push("}");
496530
L.push(
497-
"fmi3Status fmi3SetInt32(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Int32 value[], size_t nValues) {",
531+
"fmi3Status fmi3SetString(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) {",
498532
);
499-
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
500-
L.push(" size_t vi = 0;");
501-
L.push(" for (size_t i = 0; i < nvr && vi < nValues; i++) {");
502-
L.push(" if (vr[i] < N_VARS) {");
503-
L.push(" size_t sz = varSizes[vr[i]];");
504-
L.push(" for (size_t j = 0; j < sz && vi < nValues; j++) inst->model.vars[vr[i] + j] = (double)value[vi++];");
533+
L.push(" FMU3Instance* inst = (FMU3Instance*)instance; (void)nValues;");
534+
L.push(" for (size_t i = 0; i < nvr; i++) {");
535+
L.push(" if (vr[i] < N_STRING_VARS) {");
536+
L.push(" if (inst->model.stringVars[vr[i]]) free(inst->model.stringVars[vr[i]]);");
537+
L.push(" inst->model.stringVars[vr[i]] = value[i] ? strdup(value[i]) : NULL;");
505538
L.push(" }");
506539
L.push(" }");
507540
L.push(" return fmi3OK;");
508541
L.push("}");
509542
L.push("");
510543

511-
// Get/Set Boolean (array-aware batching)
544+
// Get/Set Binary (FMI 3.0 opaque payload)
512545
L.push(
513-
"fmi3Status fmi3GetBoolean(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Boolean value[], size_t nValues) {",
546+
"fmi3Status fmi3GetBinary(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, size_t sizes[], fmi3Binary value[], size_t nValues) {",
547+
);
548+
L.push(" (void)instance; (void)vr; (void)nvr; (void)sizes; (void)value; (void)nValues;");
549+
L.push(" /* Binary variables are not produced by Modelica — stub returns empty */");
550+
L.push(" for (size_t i = 0; i < nvr; i++) { sizes[i] = 0; value[i] = NULL; }");
551+
L.push(" return fmi3OK;");
552+
L.push("}");
553+
L.push(
554+
"fmi3Status fmi3SetBinary(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const size_t sizes[], const fmi3Binary value[], size_t nValues) {",
555+
);
556+
L.push(" (void)instance; (void)vr; (void)nvr; (void)sizes; (void)value; (void)nValues;");
557+
L.push(" /* Binary variables are not produced by Modelica — stub ignores */");
558+
L.push(" return fmi3OK;");
559+
L.push("}");
560+
L.push("");
561+
562+
// Clocks and Intervals
563+
L.push(
564+
"fmi3Status fmi3GetClock(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Clock value[], size_t nValues) {",
514565
);
515566
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
516567
L.push(" size_t vi = 0;");
@@ -523,7 +574,7 @@ function generateFmi3FunctionsC(
523574
L.push(" return fmi3OK;");
524575
L.push("}");
525576
L.push(
526-
"fmi3Status fmi3SetBoolean(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Boolean value[], size_t nValues) {",
577+
"fmi3Status fmi3SetClock(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Clock value[], size_t nValues) {",
527578
);
528579
L.push(" FMU3Instance* inst = (FMU3Instance*)instance;");
529580
L.push(" size_t vi = 0;");
@@ -537,47 +588,27 @@ function generateFmi3FunctionsC(
537588
L.push(" }");
538589
L.push(" return fmi3OK;");
539590
L.push("}");
540-
L.push("");
541-
542-
// Get/Set String
543591
L.push(
544-
"fmi3Status fmi3GetString(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3String value[], size_t nValues) {",
592+
"fmi3Status fmi3GetIntervalDecimal(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3Float64 interval[], fmi3IntervalQualifier qualifier[]) {",
545593
);
546-
L.push(" FMU3Instance* inst = (FMU3Instance*)instance; (void)nValues;");
594+
L.push(" (void)instance; (void)vr; (void)nvr; (void)interval; (void)qualifier; return fmi3Error;");
595+
L.push("}");
547596
L.push(
548-
' for (size_t i = 0; i < nvr; i++) { if (vr[i] < N_STRING_VARS) value[i] = inst->model.stringVars[vr[i]] ? inst->model.stringVars[vr[i]] : ""; }',
597+
"fmi3Status fmi3GetIntervalFraction(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, fmi3UInt64 intervalCounter[], fmi3UInt64 resolution[], fmi3IntervalQualifier qualifier[]) {",
549598
);
550-
L.push(" return fmi3OK;");
551-
L.push("}");
552599
L.push(
553-
"fmi3Status fmi3SetString(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3String value[], size_t nValues) {",
600+
" (void)instance; (void)vr; (void)nvr; (void)intervalCounter; (void)resolution; (void)qualifier; return fmi3Error;",
554601
);
555-
L.push(" FMU3Instance* inst = (FMU3Instance*)instance; (void)nValues;");
556-
L.push(" for (size_t i = 0; i < nvr; i++) {");
557-
L.push(" if (vr[i] < N_STRING_VARS) {");
558-
L.push(" if (inst->model.stringVars[vr[i]]) free(inst->model.stringVars[vr[i]]);");
559-
L.push(" inst->model.stringVars[vr[i]] = value[i] ? strdup(value[i]) : NULL;");
560-
L.push(" }");
561-
L.push(" }");
562-
L.push(" return fmi3OK;");
563602
L.push("}");
564-
L.push("");
565-
566-
// Get/Set Binary (FMI 3.0 opaque payload)
567603
L.push(
568-
"fmi3Status fmi3GetBinary(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, size_t sizes[], fmi3Binary value[], size_t nValues) {",
604+
"fmi3Status fmi3SetIntervalDecimal(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3Float64 interval[]) {",
569605
);
570-
L.push(" (void)instance; (void)vr; (void)nvr; (void)sizes; (void)value; (void)nValues;");
571-
L.push(" /* Binary variables are not produced by Modelica — stub returns empty */");
572-
L.push(" for (size_t i = 0; i < nvr; i++) { sizes[i] = 0; value[i] = NULL; }");
573-
L.push(" return fmi3OK;");
606+
L.push(" (void)instance; (void)vr; (void)nvr; (void)interval; return fmi3Error;");
574607
L.push("}");
575608
L.push(
576-
"fmi3Status fmi3SetBinary(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const size_t sizes[], const fmi3Binary value[], size_t nValues) {",
609+
"fmi3Status fmi3SetIntervalFraction(fmi3Instance instance, const fmi3ValueReference vr[], size_t nvr, const fmi3UInt64 intervalCounter[], const fmi3UInt64 resolution[]) {",
577610
);
578-
L.push(" (void)instance; (void)vr; (void)nvr; (void)sizes; (void)value; (void)nValues;");
579-
L.push(" /* Binary variables are not produced by Modelica — stub ignores */");
580-
L.push(" return fmi3OK;");
611+
L.push(" (void)instance; (void)vr; (void)nvr; (void)intervalCounter; (void)resolution; return fmi3Error;");
581612
L.push("}");
582613
L.push("");
583614

@@ -796,6 +827,16 @@ function generateFmi3FunctionsC(
796827
L.push(
797828
"fmi3Status fmi3FreeFMUState(fmi3Instance instance, fmi3FMUState* state) { (void)instance; if (state && *state) { free(*state); *state = NULL; } return fmi3OK; }",
798829
);
830+
L.push("");
831+
832+
// Scheduled Execution
833+
L.push("/* --- Scheduled Execution --- */");
834+
L.push(
835+
"fmi3Status fmi3ActivateModelPartition(fmi3Instance instance, fmi3ValueReference clockReference, fmi3Float64 activationTime) {",
836+
);
837+
L.push(" (void)instance; (void)clockReference; (void)activationTime; return fmi3Error;");
838+
L.push("}");
839+
L.push("");
799840
L.push(
800841
"fmi3Status fmi3SerializedFMUStateSize(fmi3Instance instance, fmi3FMUState state, size_t* size) { (void)instance; (void)state; *size = sizeof(FMU3Instance); return fmi3OK; }",
801842
);

0 commit comments

Comments
 (0)