2 Copyright (C) 2012 Modelon AB
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the BSD style license.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 FMILIB_License.txt file for more details.
12 You should have received a copy of the FMILIB_License.txt file
13 along with this program. If not, contact Modelon AB <http://www.modelon.com>.
16 /** \file fmi2_xml_model_structure.c
17 * \brief Implementation for the model structure interface.
22 #include "fmi2_xml_parser.h"
23 #include "fmi2_xml_model_structure_impl.h"
24 #include "fmi2_xml_model_description_impl.h"
26 static const char * module = "FMI2XML";
28 fmi2_xml_model_structure_t* fmi2_xml_allocate_model_structure(jm_callbacks* cb) {
29 fmi2_xml_model_structure_t* ms = (fmi2_xml_model_structure_t*)(cb->calloc(1, sizeof(fmi2_xml_model_structure_t)));
32 jm_vector_init(jm_voidp)(&ms->outputs,0,cb);
33 jm_vector_init(jm_voidp)(&ms->derivatives,0,cb);
34 jm_vector_init(jm_voidp)(&ms->discreteStates,0,cb);
35 jm_vector_init(jm_voidp)(&ms->initialUnknowns,0,cb);
39 ms->outputDeps = fmi2_xml_allocate_dependencies(cb);
40 ms->derivativeDeps = fmi2_xml_allocate_dependencies(cb);
41 ms->discreteStateDeps = fmi2_xml_allocate_dependencies(cb);
42 ms->initialUnknownDeps = fmi2_xml_allocate_dependencies(cb);
44 if(!ms->outputDeps || !ms->derivativeDeps || !ms->discreteStateDeps || !ms->initialUnknownDeps) {
45 fmi2_xml_free_model_structure(ms);
52 void fmi2_xml_free_model_structure(fmi2_xml_model_structure_t* ms) {
55 cb = ms->outputs.callbacks;
57 jm_vector_free_data(jm_voidp)(&ms->outputs);
58 jm_vector_free_data(jm_voidp)(&ms->derivatives);
59 jm_vector_free_data(jm_voidp)(&ms->discreteStates);
60 jm_vector_free_data(jm_voidp)(&ms->initialUnknowns);
62 fmi2_xml_free_dependencies(ms->outputDeps);
63 fmi2_xml_free_dependencies(ms->derivativeDeps);
64 fmi2_xml_free_dependencies(ms->discreteStateDeps);
65 fmi2_xml_free_dependencies(ms->initialUnknownDeps);
69 jm_vector(jm_voidp)* fmi2_xml_get_outputs(fmi2_xml_model_structure_t* ms) {
73 jm_vector(jm_voidp)* fmi2_xml_get_derivatives(fmi2_xml_model_structure_t* ms){
74 return &ms->derivatives;
77 jm_vector(jm_voidp)* fmi2_xml_get_discrete_states(fmi2_xml_model_structure_t* ms){
78 return &ms->discreteStates;
81 jm_vector(jm_voidp)* fmi2_xml_get_initial_unknowns(fmi2_xml_model_structure_t* ms){
82 return &ms->initialUnknowns;
86 void fmi2_xml_get_dependencies(fmi2_xml_dependencies_t* dep, size_t** startIndex, size_t** dependency, char** factorKind){
88 if (jm_vector_get_size(size_t)(&dep->dependencyIndex) == 0) {
93 *startIndex = jm_vector_get_itemp(size_t)(&dep->startIndex, 0);
94 *dependency = jm_vector_get_itemp(size_t)(&dep->dependencyIndex, 0);
95 *factorKind = jm_vector_get_itemp(char)(&dep->dependencyFactorKind, 0);
103 void fmi2_xml_get_outputs_dependencies(fmi2_xml_model_structure_t* ms,
104 size_t** startIndex, size_t** dependency, char** factorKind) {
105 fmi2_xml_get_dependencies(ms->outputDeps, startIndex, dependency, factorKind);
108 void fmi2_xml_get_derivatives_dependencies(fmi2_xml_model_structure_t* ms,
109 size_t** startIndex, size_t** dependency, char** factorKind) {
110 fmi2_xml_get_dependencies(ms->derivativeDeps, startIndex, dependency, factorKind);
113 void fmi2_xml_get_discrete_states_dependencies(fmi2_xml_model_structure_t* ms,
114 size_t** startIndex, size_t** dependency, char** factorKind) {
115 fmi2_xml_get_dependencies(ms->discreteStateDeps, startIndex, dependency, factorKind);
118 void fmi2_xml_get_initial_unknowns_dependencies(fmi2_xml_model_structure_t* ms,
119 size_t** startIndex, size_t** dependency, char** factorKind) {
120 fmi2_xml_get_dependencies(ms->initialUnknownDeps, startIndex, dependency, factorKind);
124 fmi2_xml_dependencies_t* fmi2_xml_allocate_dependencies(jm_callbacks* cb) {
125 fmi2_xml_dependencies_t* dep = (fmi2_xml_dependencies_t*)(cb->malloc(sizeof(fmi2_xml_dependencies_t)));
127 jm_vector_init(size_t)(&dep->startIndex, 0, cb);
128 jm_vector_push_back(size_t)(&dep->startIndex, 0);
130 jm_vector_init(size_t)(&dep->dependencyIndex, 0, cb);
131 jm_vector_init(char)(&dep->dependencyFactorKind, 0, cb);
138 void fmi2_xml_zero_empty_dependencies(fmi2_xml_dependencies_t** pdep) {
139 fmi2_xml_dependencies_t* dep =*pdep;
140 size_t ndep = jm_vector_get_size(size_t)(&dep->dependencyIndex);
143 for(i = 0; i<ndep;i++) {
144 if(jm_vector_get_item(size_t)(&dep->dependencyIndex, i)) break;
147 fmi2_xml_free_dependencies(dep);
153 void fmi2_xml_free_dependencies(fmi2_xml_dependencies_t* dep) {
156 cb = dep->startIndex.callbacks;
157 jm_vector_free_data(size_t)(&dep->startIndex);
159 jm_vector_free_data(size_t)(&dep->dependencyIndex);
160 jm_vector_free_data(char)(&dep->dependencyFactorKind);
165 int fmi2_xml_check_model_structure(fmi2_xml_model_description_t* md) {
166 fmi2_xml_model_structure_t* ms = md->modelStructure;
168 if(!ms || !ms->isValidFlag) return 0;
170 return ms->isValidFlag;
173 int fmi2_xml_handle_ModelStructure(fmi2_xml_parser_context_t *context, const char* data) {
174 fmi2_xml_model_description_t* md = context->modelDescription;
176 jm_log_verbose(context->callbacks, module,"Parsing XML element ModelStructure");
177 /** allocate model structure */
178 md->modelStructure = fmi2_xml_allocate_model_structure(md->callbacks);
179 if(!md->modelStructure) {
180 fmi2_xml_parse_fatal(context, module, "Could not allocate memory");
185 /** make sure model structure information is consistent */
187 if(!fmi2_xml_check_model_structure(md)) {
188 fmi2_xml_parse_fatal(context, "Model structure is not valid due to detected errors. Cannot continue.");
191 /* md->numberOfContinuousStates = jm_vector_get_size(jm_voidp)(&md->modelStructure->states); */
198 int fmi2_xml_handle_Outputs(fmi2_xml_parser_context_t *context, const char* data) {
200 jm_log_verbose(context->callbacks, module, "Parsing XML element Outputs");
201 /* reset handles for the elements that are specific under Outputs */
202 /* fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(OutputUnknown));*/
203 fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(Unknown));
207 int fmi2_xml_handle_Derivatives(fmi2_xml_parser_context_t *context, const char* data) {
209 jm_log_verbose(context->callbacks, module, "Parsing XML element Derivatives");
210 /* reset handles for the elements that are specific under Derivatives */
211 fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(DerivativeUnknown));
214 fmi2_xml_model_description_t* md = context->modelDescription;
215 fmi2_xml_model_structure_t* ms = md->modelStructure;
216 /* count the number of continuous states as the number of <Unknown> elements under <Derivatives> */
217 md->numberOfContinuousStates = jm_vector_get_size(jm_voidp)(&ms->derivatives);
221 int fmi2_xml_handle_DiscreteStates(fmi2_xml_parser_context_t *context, const char* data) {
223 jm_log_verbose(context->callbacks, module, "Parsing XML element DiscreteStates");
224 /* reset handles for the elements that are specific under DiscreteStates */
225 fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(DiscreteStateUnknown));
229 int fmi2_xml_handle_InitialUnknowns(fmi2_xml_parser_context_t *context, const char* data) {
231 jm_log_verbose(context->callbacks, module, "Parsing XML element InitialUnknowns");
232 /* reset handles for the elements that are specific under InitialUnknowns */
233 fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(InitialUnknown));
239 int fmi2_xml_parse_dependencies(fmi2_xml_parser_context_t *context,
240 fmi2_xml_elm_enu_t parentElmID,
241 fmi2_xml_dependencies_t* deps)
243 fmi2_xml_model_description_t* md = context->modelDescription;
244 fmi2_xml_model_structure_t* ms = md->modelStructure;
247 const char* listKind;
248 size_t numDepInd = 0;
249 size_t numDepKind = 0;
250 size_t totNumDep = jm_vector_get_size(size_t)(&deps->dependencyIndex);
252 /* <xs:attribute name="dependencies">
254 <xs:list itemType="xs:unsignedInt"/>
257 if(fmi2_xml_get_attr_str(context, fmi2_xml_elmID_Unknown, fmi_attr_id_dependencies, 0, &listInd)) {
262 const char* cur = listInd;
266 while((ch ==' ') || (ch == '\t') || (ch =='\n') || (ch == '\r')) {
271 if(sscanf(cur, "%d", &ind) != 1) {
272 fmi2_xml_parse_error(context, "XML element 'Unknown': could not parse item %d in the list for attribute 'dependencies'",
278 fmi2_xml_parse_error(context, "XML element 'Unknown': item %d=%d is less than one in the list for attribute 'dependencies'",
283 if(!jm_vector_push_back(size_t)(&deps->dependencyIndex, (size_t)ind)) {
284 fmi2_xml_parse_fatal(context, "Could not allocate memory");
287 while((*cur >= '0') && (*cur <= '9')) cur++;
293 <xs:attribute name="dependenciesKind">
297 <xs:restriction base="xs:normalizedString">
298 <xs:enumeration value="dependent"/>
299 <xs:enumeration value="constant"/>
300 <xs:enumeration value="fixed"/>
301 <xs:enumeration value="tunable"/>
302 <xs:enumeration value="discrete"/>
309 if(fmi2_xml_get_attr_str(context, fmi2_xml_elmID_Unknown, fmi_attr_id_dependenciesKind, 0, &listKind)) {
314 const char* cur = listKind;
318 while(ch && ((ch ==' ') || (ch == '\t') || (ch =='\n') || (ch == '\r'))) {
322 if(strncmp("dependent", cur, 9) == 0) {
323 kind = fmi2_dependency_factor_kind_dependent;
326 else if(strncmp("constant", cur, 8) == 0) {
327 kind = fmi2_dependency_factor_kind_constant;
330 else if(strncmp("fixed", cur, 5) == 0) {
331 kind = fmi2_dependency_factor_kind_fixed;
334 else if(strncmp("tunable", cur, 7) == 0) {
335 kind = fmi2_dependency_factor_kind_tunable;
338 else if(strncmp("discrete", cur, 8) == 0) {
339 kind = fmi2_dependency_factor_kind_discrete;
343 fmi2_xml_parse_error(context, "XML element 'Unknown': could not parse item %d in the list for attribute 'dependenciesKind'",
348 if (parentElmID == fmi2_xml_elmID_InitialUnknowns) {
349 if (kind == fmi2_dependency_factor_kind_fixed) {
350 fmi2_xml_parse_error(context, "XML element 'Unknown' within 'InitialUnknowns': 'fixed' is not allowed in list for attribute 'dependenciesKind'; setting to 'dependent'");
351 kind = fmi2_dependency_factor_kind_dependent;
353 else if (!(kind == fmi2_dependency_factor_kind_dependent || kind == fmi2_dependency_factor_kind_constant)) {
354 fmi2_xml_parse_error(context, "XML element 'Unknown' within 'InitialUnknowns': only 'dependent' and 'constant' allowed in list for attribute 'dependenciesKind'");
359 if(!jm_vector_push_back(char)(&deps->dependencyFactorKind, kind)) {
360 fmi2_xml_parse_fatal(context, "Could not allocate memory");
366 if(listInd && listKind) {
367 /* both lists are present - the number of items must match */
368 if(numDepInd != numDepKind) {
369 fmi2_xml_parse_error(context, "XML element 'Unknown': different number of items (%u and %u) in the lists for 'dependencies' and 'dependenciesKind'",
370 numDepInd, numDepKind);
376 /* only Dependencies are present, set all kinds to dependent */
377 char kind = fmi2_dependency_factor_kind_dependent;
378 if(jm_vector_reserve(char)(&deps->dependencyFactorKind,totNumDep + numDepInd) < totNumDep + numDepInd) {
379 fmi2_xml_parse_fatal(context, "Could not allocate memory");
382 for(;numDepKind < numDepInd; numDepKind++)
383 jm_vector_push_back(char)(&deps->dependencyFactorKind, kind);
386 fmi2_xml_parse_error(context, "XML element 'Unknown': if `dependenciesKind` attribute is present then the `dependencies` attribute must be present also.");
391 /* Dependencies are not provided. Put zero index/dependent to indicate that full row must be considered. */
392 numDepInd = numDepKind = 1;
393 if(!jm_vector_push_back(char)(&deps->dependencyFactorKind, fmi2_dependency_factor_kind_dependent) ||
394 !jm_vector_push_back(size_t)(&deps->dependencyIndex, 0)
396 fmi2_xml_parse_fatal(context, "Could not allocate memory");
400 if(!jm_vector_push_back(size_t)(&deps->startIndex, totNumDep + numDepInd)) {
401 fmi2_xml_parse_fatal(context, "Could not allocate memory");
409 int fmi2_xml_parse_unknown(fmi2_xml_parser_context_t *context,
410 fmi2_xml_elm_enu_t parentElmID,
411 jm_vector(jm_voidp) *destVarList,
412 fmi2_xml_dependencies_t* deps)
414 fmi2_xml_model_description_t* md = context->modelDescription;
415 fmi2_xml_model_structure_t* ms = md->modelStructure;
418 fmi2_xml_variable_t* variable;
420 /* <xs:attribute name="index" type="xs:unsignedInt" use="required"> */
421 if (fmi2_xml_set_attr_uint(context, fmi2_xml_elmID_Unknown, fmi_attr_id_index, 1, &index, 0)) return -1;
422 index--; /* Convert from one- to zero-based indexing */
424 /* Ok to just check upper bound since index is unsigned. */
425 if (index >= jm_vector_get_size(jm_voidp)(md->variablesOrigOrder)) {
426 fmi2_xml_parse_error(context, "The index attribute must have a value between 1 and the number of model variables.");
430 variable = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesOrigOrder, index);
432 if (!jm_vector_push_back(jm_voidp)(destVarList, variable)) {
433 fmi2_xml_parse_fatal(context, "Could not allocate memory");
438 return fmi2_xml_parse_dependencies(context, parentElmID, deps);
442 /*int fmi2_xml_handle_OutputUnknown(fmi2_xml_parser_context_t *context, const char* data) {*/
443 int fmi2_xml_handle_Unknown(fmi2_xml_parser_context_t *context, const char* data) {
445 fmi2_xml_model_description_t* md = context->modelDescription;
446 fmi2_xml_model_structure_t* ms = md->modelStructure;
448 return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_Outputs, &ms->outputs, ms->outputDeps);
455 int fmi2_xml_handle_DerivativeUnknown(fmi2_xml_parser_context_t *context, const char* data) {
457 fmi2_xml_model_description_t* md = context->modelDescription;
458 fmi2_xml_model_structure_t* ms = md->modelStructure;
459 int status = fmi2_xml_parse_unknown(context, fmi2_xml_elmID_Derivatives, &ms->derivatives, ms->derivativeDeps);
464 fmi2_xml_real_variable_t *der = (fmi2_xml_real_variable_t*) jm_vector_get_last(jm_voidp)(&ms->derivatives);
465 if (!fmi2_xml_get_real_variable_derivative_of(der)) {
467 fmi2_xml_parse_error(context,
468 "The state derivative '%s' does not specify the state variable that it is a derivative of.",
469 fmi2_xml_get_variable_name((fmi2_xml_variable_t *) der));
477 int fmi2_xml_handle_DiscreteStateUnknown(fmi2_xml_parser_context_t *context, const char* data) {
479 fmi2_xml_model_description_t* md = context->modelDescription;
480 fmi2_xml_model_structure_t* ms = md->modelStructure;
482 return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_DiscreteStates, &ms->discreteStates, ms->discreteStateDeps);
489 int fmi2_xml_handle_InitialUnknown(fmi2_xml_parser_context_t *context, const char* data) {
491 fmi2_xml_model_description_t* md = context->modelDescription;
492 fmi2_xml_model_structure_t* ms = md->modelStructure;
494 return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_InitialUnknowns, &ms->initialUnknowns, ms->initialUnknownDeps);