Skip to content

Commit ec7a64a

Browse files
authored
Read and check variability (#383)
and add missing variability to Resource/FMI1CS.xml
1 parent fd8828f commit ec7a64a

File tree

3 files changed

+151
-32
lines changed

3 files changed

+151
-32
lines changed

Resource/FMI1CS.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<ScalarVariable name="time" valueReference="0" causality="internal" variability="continuous" description="Simulation time">
1616
<Real/>
1717
</ScalarVariable>
18-
<ScalarVariable name="y" valueReference="1" description="Value of the first character in resources/y.txt" causality="output">
18+
<ScalarVariable name="y" valueReference="1" description="Value of the first character in resources/y.txt" causality="output" variability="discrete">
1919
<Integer/>
2020
</ScalarVariable>
2121
</ModelVariables>

fmusim/FMIModelDescription.c

Lines changed: 139 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,40 @@ static FMIModelDescription* readModelDescriptionFMI1(xmlNodePtr root) {
103103

104104
const char* typeName = (char*)typeNode->name;
105105

106+
const char* causality = (char*)xmlGetProp(variableNode, (xmlChar*)"causality");
107+
108+
if (!causality) {
109+
// default
110+
variable->causality = FMILocal;
111+
} else if (!strcmp(causality, "input")) {
112+
variable->causality = FMIInput;
113+
} else if (!strcmp(causality, "output")) {
114+
variable->causality = FMIOutput;
115+
} else {
116+
// "internal" or "none"
117+
variable->causality = FMILocal;
118+
}
119+
120+
xmlFree((void*)causality);
121+
122+
const char* variability = (char*)xmlGetProp(variableNode, (xmlChar*)"variability");
123+
124+
if (!variability) {
125+
// default
126+
variable->variability = FMIContinuous;
127+
} else if (!strcmp(variability, "constant")) {
128+
variable->variability = FMIConstant;
129+
} else if (!strcmp(variability, "parameter")) {
130+
variable->causality = FMIParameter;
131+
variable->variability = FMITunable;
132+
} else if (!strcmp(variability, "discrete")) {
133+
variable->variability = FMIDiscrete;
134+
} else if (!strcmp(variability, "continuous")) {
135+
variable->variability = FMIContinuous;
136+
}
137+
138+
free((void*)variability);
139+
106140
if (!strcmp(typeName, "Real")) {
107141
const char* variability = (char*)xmlGetProp(variableNode, (xmlChar*)"variability");
108142
if (variability && !strcmp(variability, "discrete")) {
@@ -123,29 +157,30 @@ static FMIModelDescription* readModelDescriptionFMI1(xmlNodePtr root) {
123157

124158
variable->valueReference = getUInt32Attribute(variableNode, "valueReference");
125159

126-
const char* causality = (char*)xmlGetProp(variableNode, (xmlChar*)"causality");
160+
}
127161

128-
if (!causality) {
129-
variable->causality = FMILocal;
130-
} else if (!strcmp(causality, "parameter")) {
131-
variable->causality = FMIParameter;
132-
} else if (!strcmp(causality, "input")) {
133-
variable->causality = FMIInput;
134-
} else if (!strcmp(causality, "output")) {
135-
variable->causality = FMIOutput;
136-
} else if (!strcmp(causality, "independent")) {
137-
variable->causality = FMIIndependent;
138-
} else {
139-
variable->causality = FMILocal;
140-
}
162+
size_t nProblems = 0;
141163

142-
xmlFree((void*)causality);
164+
// check variabilities
165+
for (size_t i = 0; i < modelDescription->nModelVariables; i++) {
166+
FMIModelVariable* variable = &modelDescription->modelVariables[i];
167+
if (variable->type != FMIRealType && variable->type != FMIDiscreteRealType && variable->variability == FMIContinuous) {
168+
printf("Variable \"%s\" is not of type Real but has variability = continuous.\n", variable->name);
169+
nProblems++;
170+
}
143171
}
144172

145173
xmlXPathFreeObject(xpathObj);
146174

147175
xmlXPathFreeContext(xpathCtx);
148176

177+
if (nProblems > 0) {
178+
FMIFreeModelDescription(modelDescription);
179+
modelDescription = NULL;
180+
}
181+
182+
return modelDescription;
183+
149184
return modelDescription;
150185
}
151186

@@ -260,29 +295,38 @@ static FMIModelDescription* readModelDescriptionFMI2(xmlNodePtr root) {
260295

261296
variable->derivative = (FMIModelVariable*)xmlGetProp(typeNode, (xmlChar*)"derivative");
262297

263-
FMIVariableType type;
264298
const char* typeName = (char*)typeNode->name;
265299

300+
const char* variability = (char*)xmlGetProp(variableNode, (xmlChar*)"variability");
301+
302+
if (!variability) {
303+
variable->variability = FMIContinuous;
304+
} else if(!strcmp(variability, "constant")) {
305+
variable->variability = FMIConstant;
306+
} else if (!strcmp(variability, "fixed")) {
307+
variable->variability = FMIFixed;
308+
} else if (!strcmp(variability, "tunable")) {
309+
variable->variability = FMITunable;
310+
} else if (!strcmp(variability, "discrete")) {
311+
variable->variability = FMIDiscrete;
312+
} else {
313+
variable->variability = FMIContinuous;
314+
}
315+
316+
free((void*)variability);
317+
266318
if (!strcmp(typeName, "Real")) {
267-
const char* variability = (char*)xmlGetProp(variableNode, (xmlChar*)"variability");
268-
if (variability && (!strcmp(variability, "discrete") || !strcmp(variability, "tunable"))) {
269-
type = FMIDiscreteRealType;
270-
} else {
271-
type = FMIRealType;
272-
}
273-
free((void*)variability);
319+
variable->type = variable->variability == FMIDiscrete ? FMIDiscreteRealType : FMIRealType;
274320
} else if (!strcmp(typeName, "Integer") || !strcmp(typeName, "Enumeration")) {
275-
type = FMIIntegerType;
321+
variable->type = FMIIntegerType;
276322
} else if (!strcmp(typeName, "Boolean")) {
277-
type = FMIBooleanType;
323+
variable->type = FMIBooleanType;
278324
} else if (!strcmp(typeName, "String")) {
279-
type = FMIStringType;
325+
variable->type = FMIStringType;
280326
} else {
281327
continue;
282328
}
283329

284-
variable->type = type;
285-
286330
const char* vr = (char*)xmlGetProp(variableNode, (xmlChar*)"valueReference");
287331

288332
variable->valueReference = FMIValueReferenceForLiteral(vr);
@@ -332,6 +376,15 @@ static FMIModelDescription* readModelDescriptionFMI2(xmlNodePtr root) {
332376
}
333377
}
334378

379+
// check variabilities
380+
for (size_t i = 0; i < modelDescription->nModelVariables; i++) {
381+
FMIModelVariable* variable = &modelDescription->modelVariables[i];
382+
if (variable->type != FMIRealType && variable->type != FMIDiscreteRealType && variable->variability == FMIContinuous) {
383+
printf("Variable \"%s\" is not of type Real but has variability = continuous.\n", variable->name);
384+
nProblems++;
385+
}
386+
}
387+
335388
nProblems += FMIValidateModelStructure(modelDescription);
336389

337390
if (nProblems > 0) {
@@ -420,13 +473,43 @@ static FMIModelDescription* readModelDescriptionFMI3(xmlNodePtr root) {
420473
const char* name = (char*)node->name;
421474

422475
const char* variability = (char*)xmlGetProp(node, (xmlChar*)"variability");
423-
const bool discrete = variability && (!strcmp(variability, "discrete") || !strcmp(variability, "tunable"));
476+
477+
if (!variability) {
478+
variable->variability = -1; // infer from type
479+
} else if (!strcmp(variability, "constant")) {
480+
variable->variability = FMIConstant;
481+
} else if (!strcmp(variability, "fixed")) {
482+
variable->variability = FMIFixed;
483+
} else if (!strcmp(variability, "tunable")) {
484+
variable->variability = FMITunable;
485+
} else if (!strcmp(variability, "discrete")) {
486+
variable->variability = FMIDiscrete;
487+
} else {
488+
variable->variability = FMIContinuous;
489+
}
490+
424491
free((void*)variability);
425492

426493
if (!strcmp(name, "Float32")) {
427-
type = discrete ? FMIDiscreteFloat32Type : FMIFloat32Type;
494+
switch (variable->variability) {
495+
case -1:
496+
case FMIContinuous:
497+
type = FMIFloat32Type;
498+
break;
499+
default:
500+
type = FMIDiscreteFloat32Type;
501+
break;
502+
}
428503
} else if (!strcmp(name, "Float64")) {
429-
type = discrete ? FMIDiscreteFloat64Type : FMIFloat64Type;
504+
switch (variable->variability) {
505+
case -1:
506+
case FMIContinuous:
507+
type = FMIFloat64Type;
508+
break;
509+
default:
510+
type = FMIDiscreteFloat64Type;
511+
break;
512+
}
430513
} else if (!strcmp(name, "Int8")) {
431514
type = FMIInt8Type;
432515
} else if (!strcmp(name, "UInt8")) {
@@ -457,6 +540,18 @@ static FMIModelDescription* readModelDescriptionFMI3(xmlNodePtr root) {
457540

458541
variable->type = type;
459542

543+
if (variable->variability == -1) {
544+
switch (variable->type) {
545+
case FMIFloat32Type:
546+
case FMIFloat64Type:
547+
variable->variability = FMIContinuous;
548+
break;
549+
default:
550+
variable->variability = FMIDiscrete;
551+
break;
552+
}
553+
}
554+
460555
const char* vr = (char*)xmlGetProp(node, (xmlChar*)"valueReference");
461556

462557
variable->valueReference = FMIValueReferenceForLiteral(vr);
@@ -483,6 +578,8 @@ static FMIModelDescription* readModelDescriptionFMI3(xmlNodePtr root) {
483578
variable->causality = FMILocal;
484579
}
485580

581+
free(causality);
582+
486583
variable->derivative = (FMIModelVariable*)xmlGetProp(node, (xmlChar*)"derivative");
487584

488585
xmlXPathObjectPtr xpathObj2 = xmlXPathNodeEval(node, ".//Dimension", xpathCtx);
@@ -532,6 +629,17 @@ static FMIModelDescription* readModelDescriptionFMI3(xmlNodePtr root) {
532629

533630
size_t nProblems = 0;
534631

632+
// check variabilities
633+
for (size_t i = 0; i < modelDescription->nModelVariables; i++) {
634+
635+
FMIModelVariable* variable = &modelDescription->modelVariables[i];
636+
637+
if (variable->type != FMIFloat32Type && variable->type != FMIFloat64Type && variable->variability == FMIContinuous) {
638+
printf("Variable \"%s\" is not of type Float{32|64} but has variability = continuous.\n", variable->name);
639+
nProblems++;
640+
}
641+
}
642+
535643
// resolve derivatives
536644
for (size_t i = 0; i < modelDescription->nModelVariables; i++) {
537645

fmusim/FMIModelDescription.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ typedef enum {
1818

1919
} FMICausality;
2020

21+
typedef enum {
22+
23+
FMIConstant,
24+
FMIFixed,
25+
FMITunable,
26+
FMIDiscrete,
27+
FMIContinuous
28+
29+
} FMIVariability;
30+
2131
typedef struct FMIDimension FMIDimension;
2232

2333
typedef struct FMIModelVariable FMIModelVariable;
@@ -29,6 +39,7 @@ struct FMIModelVariable {
2939
const char* description;
3040
unsigned int valueReference;
3141
FMICausality causality;
42+
FMIVariability variability;
3243
size_t nDimensions;
3344
FMIDimension* dimensions;
3445
FMIModelVariable* derivative;

0 commit comments

Comments
 (0)