X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=org.simantics.fmil.core%2Fnative%2FFMILibrary%2Fsrc%2FXML%2Fsrc%2FFMI2%2Ffmi2_xml_model_structure.c;fp=org.simantics.fmil.core%2Fnative%2FFMILibrary%2Fsrc%2FXML%2Fsrc%2FFMI2%2Ffmi2_xml_model_structure.c;h=1b809cbd03b6dab7c2805e5a28dd8f1f81db5d4d;hb=4bed8078f3f6d15b8539d7357b8815f8bfeec2c4;hp=0000000000000000000000000000000000000000;hpb=87cc423aefd98832c6c8d0979afc21551f8ceca3;p=simantics%2Ffmil.git diff --git a/org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI2/fmi2_xml_model_structure.c b/org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI2/fmi2_xml_model_structure.c new file mode 100644 index 0000000..1b809cb --- /dev/null +++ b/org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI2/fmi2_xml_model_structure.c @@ -0,0 +1,499 @@ +/* + Copyright (C) 2012 Modelon AB + + This program is free software: you can redistribute it and/or modify + it under the terms of the BSD style license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + FMILIB_License.txt file for more details. + + You should have received a copy of the FMILIB_License.txt file + along with this program. If not, contact Modelon AB . +*/ + +/** \file fmi2_xml_model_structure.c +* \brief Implementation for the model structure interface. +*/ +#include +#include + +#include "fmi2_xml_parser.h" +#include "fmi2_xml_model_structure_impl.h" +#include "fmi2_xml_model_description_impl.h" + +static const char * module = "FMI2XML"; + +fmi2_xml_model_structure_t* fmi2_xml_allocate_model_structure(jm_callbacks* cb) { + fmi2_xml_model_structure_t* ms = (fmi2_xml_model_structure_t*)(cb->calloc(1, sizeof(fmi2_xml_model_structure_t))); + if(!ms) return 0; + + jm_vector_init(jm_voidp)(&ms->outputs,0,cb); + jm_vector_init(jm_voidp)(&ms->derivatives,0,cb); + jm_vector_init(jm_voidp)(&ms->discreteStates,0,cb); + jm_vector_init(jm_voidp)(&ms->initialUnknowns,0,cb); + + ms->isValidFlag = 1; + + ms->outputDeps = fmi2_xml_allocate_dependencies(cb); + ms->derivativeDeps = fmi2_xml_allocate_dependencies(cb); + ms->discreteStateDeps = fmi2_xml_allocate_dependencies(cb); + ms->initialUnknownDeps = fmi2_xml_allocate_dependencies(cb); + + if(!ms->outputDeps || !ms->derivativeDeps || !ms->discreteStateDeps || !ms->initialUnknownDeps) { + fmi2_xml_free_model_structure(ms); + return 0; + } + + return ms; +} + +void fmi2_xml_free_model_structure(fmi2_xml_model_structure_t* ms) { + jm_callbacks* cb; + if(!ms) return; + cb = ms->outputs.callbacks; + + jm_vector_free_data(jm_voidp)(&ms->outputs); + jm_vector_free_data(jm_voidp)(&ms->derivatives); + jm_vector_free_data(jm_voidp)(&ms->discreteStates); + jm_vector_free_data(jm_voidp)(&ms->initialUnknowns); + + fmi2_xml_free_dependencies(ms->outputDeps); + fmi2_xml_free_dependencies(ms->derivativeDeps); + fmi2_xml_free_dependencies(ms->discreteStateDeps); + fmi2_xml_free_dependencies(ms->initialUnknownDeps); + cb->free(ms); +} + +jm_vector(jm_voidp)* fmi2_xml_get_outputs(fmi2_xml_model_structure_t* ms) { + return &ms->outputs; +} + +jm_vector(jm_voidp)* fmi2_xml_get_derivatives(fmi2_xml_model_structure_t* ms){ + return &ms->derivatives; +} + +jm_vector(jm_voidp)* fmi2_xml_get_discrete_states(fmi2_xml_model_structure_t* ms){ + return &ms->discreteStates; +} + +jm_vector(jm_voidp)* fmi2_xml_get_initial_unknowns(fmi2_xml_model_structure_t* ms){ + return &ms->initialUnknowns; +} + + +void fmi2_xml_get_dependencies(fmi2_xml_dependencies_t* dep, size_t** startIndex, size_t** dependency, char** factorKind){ + if(dep) { + if (jm_vector_get_size(size_t)(&dep->dependencyIndex) == 0) { + *startIndex = NULL; + *dependency = NULL; + *factorKind = NULL; + } else { + *startIndex = jm_vector_get_itemp(size_t)(&dep->startIndex, 0); + *dependency = jm_vector_get_itemp(size_t)(&dep->dependencyIndex, 0); + *factorKind = jm_vector_get_itemp(char)(&dep->dependencyFactorKind, 0); + } + } + else { + *startIndex = 0; + } +} + +void fmi2_xml_get_outputs_dependencies(fmi2_xml_model_structure_t* ms, + size_t** startIndex, size_t** dependency, char** factorKind) { + fmi2_xml_get_dependencies(ms->outputDeps, startIndex, dependency, factorKind); +} + +void fmi2_xml_get_derivatives_dependencies(fmi2_xml_model_structure_t* ms, + size_t** startIndex, size_t** dependency, char** factorKind) { + fmi2_xml_get_dependencies(ms->derivativeDeps, startIndex, dependency, factorKind); +} + +void fmi2_xml_get_discrete_states_dependencies(fmi2_xml_model_structure_t* ms, + size_t** startIndex, size_t** dependency, char** factorKind) { + fmi2_xml_get_dependencies(ms->discreteStateDeps, startIndex, dependency, factorKind); +} + +void fmi2_xml_get_initial_unknowns_dependencies(fmi2_xml_model_structure_t* ms, + size_t** startIndex, size_t** dependency, char** factorKind) { + fmi2_xml_get_dependencies(ms->initialUnknownDeps, startIndex, dependency, factorKind); +} + + +fmi2_xml_dependencies_t* fmi2_xml_allocate_dependencies(jm_callbacks* cb) { + fmi2_xml_dependencies_t* dep = (fmi2_xml_dependencies_t*)(cb->malloc(sizeof(fmi2_xml_dependencies_t))); + if(!dep) return 0; + jm_vector_init(size_t)(&dep->startIndex, 0, cb); + jm_vector_push_back(size_t)(&dep->startIndex, 0); + + jm_vector_init(size_t)(&dep->dependencyIndex, 0, cb); + jm_vector_init(char)(&dep->dependencyFactorKind, 0, cb); + + dep->isRowMajor = 1; + + return dep; +} + +void fmi2_xml_zero_empty_dependencies(fmi2_xml_dependencies_t** pdep) { + fmi2_xml_dependencies_t* dep =*pdep; + size_t ndep = jm_vector_get_size(size_t)(&dep->dependencyIndex); + size_t i; + if(!dep) return; + for(i = 0; idependencyIndex, i)) break; + } + if(i == ndep) { + fmi2_xml_free_dependencies(dep); + *pdep = 0; + } +} + + +void fmi2_xml_free_dependencies(fmi2_xml_dependencies_t* dep) { + jm_callbacks* cb; + if(!dep) return; + cb = dep->startIndex.callbacks; + jm_vector_free_data(size_t)(&dep->startIndex); + + jm_vector_free_data(size_t)(&dep->dependencyIndex); + jm_vector_free_data(char)(&dep->dependencyFactorKind); + cb->free(dep); +} + + +int fmi2_xml_check_model_structure(fmi2_xml_model_description_t* md) { + fmi2_xml_model_structure_t* ms = md->modelStructure; + + if(!ms || !ms->isValidFlag) return 0; + + return ms->isValidFlag; +} + +int fmi2_xml_handle_ModelStructure(fmi2_xml_parser_context_t *context, const char* data) { + fmi2_xml_model_description_t* md = context->modelDescription; + if(!data) { + jm_log_verbose(context->callbacks, module,"Parsing XML element ModelStructure"); + /** allocate model structure */ + md->modelStructure = fmi2_xml_allocate_model_structure(md->callbacks); + if(!md->modelStructure) { + fmi2_xml_parse_fatal(context, module, "Could not allocate memory"); + return -1; + } + } + else { + /** make sure model structure information is consistent */ + + if(!fmi2_xml_check_model_structure(md)) { + fmi2_xml_parse_fatal(context, "Model structure is not valid due to detected errors. Cannot continue."); + return -1; + } +/* md->numberOfContinuousStates = jm_vector_get_size(jm_voidp)(&md->modelStructure->states); */ + + } + return 0; +} + + +int fmi2_xml_handle_Outputs(fmi2_xml_parser_context_t *context, const char* data) { + if (!data) { + jm_log_verbose(context->callbacks, module, "Parsing XML element Outputs"); + /* reset handles for the elements that are specific under Outputs */ +/* fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(OutputUnknown));*/ + fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(Unknown)); + } + return 0; +} +int fmi2_xml_handle_Derivatives(fmi2_xml_parser_context_t *context, const char* data) { + if (!data) { + jm_log_verbose(context->callbacks, module, "Parsing XML element Derivatives"); + /* reset handles for the elements that are specific under Derivatives */ + fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(DerivativeUnknown)); + } + else { + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + /* count the number of continuous states as the number of elements under */ + md->numberOfContinuousStates = jm_vector_get_size(jm_voidp)(&ms->derivatives); + } + return 0; +} +int fmi2_xml_handle_DiscreteStates(fmi2_xml_parser_context_t *context, const char* data) { + if (!data) { + jm_log_verbose(context->callbacks, module, "Parsing XML element DiscreteStates"); + /* reset handles for the elements that are specific under DiscreteStates */ + fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(DiscreteStateUnknown)); + } + return 0; +} +int fmi2_xml_handle_InitialUnknowns(fmi2_xml_parser_context_t *context, const char* data) { + if (!data) { + jm_log_verbose(context->callbacks, module, "Parsing XML element InitialUnknowns"); + /* reset handles for the elements that are specific under InitialUnknowns */ + fmi2_xml_set_element_handle(context, "Unknown", FMI2_XML_ELM_ID(InitialUnknown)); + } + return 0; +} + + +int fmi2_xml_parse_dependencies(fmi2_xml_parser_context_t *context, + fmi2_xml_elm_enu_t parentElmID, + fmi2_xml_dependencies_t* deps) +{ + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + + const char* listInd; + const char* listKind; + size_t numDepInd = 0; + size_t numDepKind = 0; + size_t totNumDep = jm_vector_get_size(size_t)(&deps->dependencyIndex); + + /* + + + + */ + if(fmi2_xml_get_attr_str(context, fmi2_xml_elmID_Unknown, fmi_attr_id_dependencies, 0, &listInd)) { + ms->isValidFlag = 0; + return 0; + } + if(listInd) { + const char* cur = listInd; + int ind; + while(*cur) { + char ch = *cur; + while((ch ==' ') || (ch == '\t') || (ch =='\n') || (ch == '\r')) { + cur++; ch = *cur; + if(!ch) break; + } + if(!ch) break; + if(sscanf(cur, "%d", &ind) != 1) { + fmi2_xml_parse_error(context, "XML element 'Unknown': could not parse item %d in the list for attribute 'dependencies'", + numDepInd); + ms->isValidFlag = 0; + return 0; + } + if(ind < 1) { + fmi2_xml_parse_error(context, "XML element 'Unknown': item %d=%d is less than one in the list for attribute 'dependencies'", + numDepInd, ind); + ms->isValidFlag = 0; + return 0; + } + if(!jm_vector_push_back(size_t)(&deps->dependencyIndex, (size_t)ind)) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + return -1; + } + while((*cur >= '0') && (*cur <= '9')) cur++; + numDepInd++; + } + } + + /* + + + + + + + + + + + + + + + + */ + if(fmi2_xml_get_attr_str(context, fmi2_xml_elmID_Unknown, fmi_attr_id_dependenciesKind, 0, &listKind)) { + ms->isValidFlag = 0; + return 0; + } + if(listKind) { + const char* cur = listKind; + char kind; + while(*cur) { + char ch = *cur; + while(ch && ((ch ==' ') || (ch == '\t') || (ch =='\n') || (ch == '\r'))) { + cur++; ch = *cur; + } + if(!ch) break; + if(strncmp("dependent", cur, 9) == 0) { + kind = fmi2_dependency_factor_kind_dependent; + cur+=9; + } + else if(strncmp("constant", cur, 8) == 0) { + kind = fmi2_dependency_factor_kind_constant; + cur+=8; + } + else if(strncmp("fixed", cur, 5) == 0) { + kind = fmi2_dependency_factor_kind_fixed; + cur+=5; + } + else if(strncmp("tunable", cur, 7) == 0) { + kind = fmi2_dependency_factor_kind_tunable; + cur+=7; + } + else if(strncmp("discrete", cur, 8) == 0) { + kind = fmi2_dependency_factor_kind_discrete; + cur+=8; + } + else { + fmi2_xml_parse_error(context, "XML element 'Unknown': could not parse item %d in the list for attribute 'dependenciesKind'", + numDepKind); + ms->isValidFlag = 0; + return 0; + } + if (parentElmID == fmi2_xml_elmID_InitialUnknowns) { + if (kind == fmi2_dependency_factor_kind_fixed) { + fmi2_xml_parse_error(context, "XML element 'Unknown' within 'InitialUnknowns': 'fixed' is not allowed in list for attribute 'dependenciesKind'; setting to 'dependent'"); + kind = fmi2_dependency_factor_kind_dependent; + } + else if (!(kind == fmi2_dependency_factor_kind_dependent || kind == fmi2_dependency_factor_kind_constant)) { + fmi2_xml_parse_error(context, "XML element 'Unknown' within 'InitialUnknowns': only 'dependent' and 'constant' allowed in list for attribute 'dependenciesKind'"); + ms->isValidFlag = 0; + return 0; + } + } + if(!jm_vector_push_back(char)(&deps->dependencyFactorKind, kind)) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + return -1; + } + numDepKind++; + } + } + if(listInd && listKind) { + /* both lists are present - the number of items must match */ + if(numDepInd != numDepKind) { + fmi2_xml_parse_error(context, "XML element 'Unknown': different number of items (%u and %u) in the lists for 'dependencies' and 'dependenciesKind'", + numDepInd, numDepKind); + ms->isValidFlag = 0; + return 0; + } + } + else if(listInd) { + /* only Dependencies are present, set all kinds to dependent */ + char kind = fmi2_dependency_factor_kind_dependent; + if(jm_vector_reserve(char)(&deps->dependencyFactorKind,totNumDep + numDepInd) < totNumDep + numDepInd) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + return -1; + } + for(;numDepKind < numDepInd; numDepKind++) + jm_vector_push_back(char)(&deps->dependencyFactorKind, kind); + } + else if(listKind) { + fmi2_xml_parse_error(context, "XML element 'Unknown': if `dependenciesKind` attribute is present then the `dependencies` attribute must be present also."); + ms->isValidFlag = 0; + return 0; + } + else { + /* Dependencies are not provided. Put zero index/dependent to indicate that full row must be considered. */ + numDepInd = numDepKind = 1; + if(!jm_vector_push_back(char)(&deps->dependencyFactorKind, fmi2_dependency_factor_kind_dependent) || + !jm_vector_push_back(size_t)(&deps->dependencyIndex, 0) + ) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + return -1; + } + } + if(!jm_vector_push_back(size_t)(&deps->startIndex, totNumDep + numDepInd)) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + return -1; + } + + return 0; +} + + +int fmi2_xml_parse_unknown(fmi2_xml_parser_context_t *context, + fmi2_xml_elm_enu_t parentElmID, + jm_vector(jm_voidp) *destVarList, + fmi2_xml_dependencies_t* deps) +{ + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + + unsigned int index; + fmi2_xml_variable_t* variable; + + /* */ + if (fmi2_xml_set_attr_uint(context, fmi2_xml_elmID_Unknown, fmi_attr_id_index, 1, &index, 0)) return -1; + index--; /* Convert from one- to zero-based indexing */ + + /* Ok to just check upper bound since index is unsigned. */ + if (index >= jm_vector_get_size(jm_voidp)(md->variablesOrigOrder)) { + fmi2_xml_parse_error(context, "The index attribute must have a value between 1 and the number of model variables."); + ms->isValidFlag = 0; + return -1; + } + variable = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesOrigOrder, index); + + if (!jm_vector_push_back(jm_voidp)(destVarList, variable)) { + fmi2_xml_parse_fatal(context, "Could not allocate memory"); + ms->isValidFlag = 0; + return -1; + } + + return fmi2_xml_parse_dependencies(context, parentElmID, deps); +} + + +/*int fmi2_xml_handle_OutputUnknown(fmi2_xml_parser_context_t *context, const char* data) {*/ +int fmi2_xml_handle_Unknown(fmi2_xml_parser_context_t *context, const char* data) { + if(!data) { + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + + return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_Outputs, &ms->outputs, ms->outputDeps); + } + else { + } + return 0; +} + +int fmi2_xml_handle_DerivativeUnknown(fmi2_xml_parser_context_t *context, const char* data) { + if(!data) { + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + int status = fmi2_xml_parse_unknown(context, fmi2_xml_elmID_Derivatives, &ms->derivatives, ms->derivativeDeps); + + if (status) { + return status; + } else { + fmi2_xml_real_variable_t *der = (fmi2_xml_real_variable_t*) jm_vector_get_last(jm_voidp)(&ms->derivatives); + if (!fmi2_xml_get_real_variable_derivative_of(der)) { + ms->isValidFlag = 0; + fmi2_xml_parse_error(context, + "The state derivative '%s' does not specify the state variable that it is a derivative of.", + fmi2_xml_get_variable_name((fmi2_xml_variable_t *) der)); + return -1; + } + } + } + return 0; +} + +int fmi2_xml_handle_DiscreteStateUnknown(fmi2_xml_parser_context_t *context, const char* data) { + if(!data) { + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + + return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_DiscreteStates, &ms->discreteStates, ms->discreteStateDeps); + } + else { + } + return 0; +} + +int fmi2_xml_handle_InitialUnknown(fmi2_xml_parser_context_t *context, const char* data) { + if(!data) { + fmi2_xml_model_description_t* md = context->modelDescription; + fmi2_xml_model_structure_t* ms = md->modelStructure; + + return fmi2_xml_parse_unknown(context, fmi2_xml_elmID_InitialUnknowns, &ms->initialUnknowns, ms->initialUnknownDeps); + } + else { + } + return 0; +}