]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/XML/src/FMI2/fmi2_xml_variable.c
Add FMILibrary-2.0.3 to org.simantics.fmil.core\native.
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / XML / src / FMI2 / fmi2_xml_variable.c
1 /*
2     Copyright (C) 2012 Modelon AB
3
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the BSD style license.
6
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.
11
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>.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18
19 #include <JM/jm_vector.h>
20
21 #include "fmi2_xml_parser.h"
22 #include "fmi2_xml_type_impl.h"
23 #include "fmi2_xml_model_description_impl.h"
24
25 #include "fmi2_xml_variable_impl.h"
26
27 static const char* module = "FMI2XML";
28
29 const char* fmi2_xml_get_variable_name(fmi2_xml_variable_t* v) {
30     return v->name;
31 }
32
33 const char* fmi2_xml_get_variable_description(fmi2_xml_variable_t* v) {
34     return v->description;
35 }
36
37 size_t fmi2_xml_get_variable_original_order(fmi2_xml_variable_t* v) {
38         return v->originalIndex;
39 }
40
41 fmi2_value_reference_t fmi2_xml_get_variable_vr(fmi2_xml_variable_t* v) {
42     return v->vr;
43 }
44
45 fmi2_variable_alias_kind_enu_t fmi2_xml_get_variable_alias_kind(fmi2_xml_variable_t* v) {
46     return (fmi2_variable_alias_kind_enu_t)v->aliasKind;
47 }
48
49 fmi2_xml_variable_t* fmi2_xml_get_variable_alias_base(fmi2_xml_model_description_t* md, fmi2_xml_variable_t* v) {
50     fmi2_xml_variable_t key;
51     fmi2_xml_variable_t *pkey = &key, *base;
52     void ** found;
53         if(!md->variablesByVR) return 0;
54     if(v->aliasKind == fmi2_variable_is_not_alias) return v;
55     key = *v;
56     key.aliasKind = fmi2_variable_is_not_alias;
57
58     found = jm_vector_bsearch(jm_voidp)(md->variablesByVR,(void**)&pkey, fmi2_xml_compare_vr);
59     assert(found);
60     base = *found;
61     return base;
62 }
63
64 /*
65     Return the list of all the variables aliased to the given one (including the base one.
66     The list is ordered: base variable, aliases.
67 */
68 jm_status_enu_t fmi2_xml_get_variable_aliases(fmi2_xml_model_description_t* md,fmi2_xml_variable_t* v, jm_vector(jm_voidp)* list) {
69     fmi2_xml_variable_t key, *cur;
70     fmi2_value_reference_t vr = fmi2_xml_get_variable_vr(v);
71     size_t baseIndex, i, num = jm_vector_get_size(jm_voidp)(md->variablesByVR);
72     key = *v;
73     key.aliasKind = 0;
74     cur = &key;
75     baseIndex = jm_vector_bsearch_index(jm_voidp)(md->variablesByVR,(void**)&cur, fmi2_xml_compare_vr);
76     cur = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, baseIndex);
77     assert(cur);
78     i = baseIndex + 1;
79     while(fmi2_xml_get_variable_vr(cur) == vr) {
80         if(!jm_vector_push_back(jm_voidp)(list, cur)) {
81                         jm_log_fatal(md->callbacks,module,"Could not allocate memory");
82             return jm_status_error;
83         };
84         if(i >= num) break;
85         cur = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i);
86         assert(cur);
87         i++;
88     }
89     if(baseIndex) {
90         i = baseIndex - 1;
91         cur = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i);
92         while(fmi2_xml_get_variable_vr(cur) == vr) {
93             if(!jm_vector_push_back(jm_voidp)(list, cur)) {
94                 jm_log_fatal(md->callbacks,module,"Could not allocate memory");
95                 return jm_status_error;
96             };
97             i--;
98             if(!i) break;
99             cur = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesByVR, i - 1);
100             assert(cur);
101         }
102     }
103     return jm_status_success;
104 }
105
106
107 fmi2_xml_variable_typedef_t* fmi2_xml_get_variable_declared_type(fmi2_xml_variable_t* v) {
108     return (fmi2_xml_variable_typedef_t*)(fmi2_xml_find_type_struct(v->typeBase, fmi2_xml_type_struct_enu_typedef));
109 }
110
111 fmi2_base_type_enu_t fmi2_xml_get_variable_base_type(fmi2_xml_variable_t* v) {
112     fmi2_xml_variable_type_base_t* type = v->typeBase;
113     return (type->baseType);
114 }
115
116 int fmi2_xml_get_variable_has_start(fmi2_xml_variable_t* v) {
117     return (v->typeBase->structKind == fmi2_xml_type_struct_enu_start);
118 }
119
120 fmi2_variability_enu_t fmi2_xml_get_variability(fmi2_xml_variable_t* v) {
121     return (fmi2_variability_enu_t)v->variability;
122 }
123
124 fmi2_causality_enu_t fmi2_xml_get_causality(fmi2_xml_variable_t* v) {
125     return (fmi2_causality_enu_t)v->causality;
126 }
127
128 fmi2_initial_enu_t fmi2_xml_get_initial(fmi2_xml_variable_t* v) {
129         return (fmi2_initial_enu_t)v->initial;
130 }
131
132 fmi2_xml_variable_t* fmi2_xml_get_previous(fmi2_xml_variable_t* v) {
133     return v->previous;
134 }
135
136 fmi2_boolean_t fmi2_xml_get_canHandleMultipleSetPerTimeInstant(fmi2_xml_variable_t* v) {
137     return (fmi2_boolean_t)v->canHandleMultipleSetPerTimeInstant;
138 }
139
140
141 double fmi2_xml_get_real_variable_start(fmi2_xml_real_variable_t* v) {
142     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
143     if(fmi2_xml_get_variable_has_start(vv)) {
144         fmi2_xml_variable_start_real_t* start = (fmi2_xml_variable_start_real_t*)(vv->typeBase);
145         return start->start;
146     }
147         return fmi2_xml_get_real_variable_nominal(v);
148 }
149
150 fmi2_xml_real_variable_t* fmi2_xml_get_real_variable_derivative_of(fmi2_xml_real_variable_t* v) {
151     fmi2_xml_variable_t *vv = (fmi2_xml_variable_t *)v;
152
153     return (fmi2_xml_real_variable_t *)vv->derivativeOf;
154 }
155
156 fmi2_boolean_t fmi2_xml_get_real_variable_reinit(fmi2_xml_real_variable_t* v) {
157     fmi2_xml_variable_t *vv = (fmi2_xml_variable_t *)v;
158     return (fmi2_boolean_t)vv->reinit;
159 }
160
161 fmi2_xml_unit_t* fmi2_xml_get_real_variable_unit(fmi2_xml_real_variable_t* v) {
162     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
163     fmi2_xml_real_type_props_t* props = (fmi2_xml_real_type_props_t*)(fmi2_xml_find_type_struct(vv->typeBase, fmi2_xml_type_struct_enu_props));
164     if(!props || !props->displayUnit) return 0;
165     return props->displayUnit->baseUnit;
166 }
167
168 fmi2_xml_display_unit_t* fmi2_xml_get_real_variable_display_unit(fmi2_xml_real_variable_t* v) {
169     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
170     fmi2_xml_real_type_props_t* props = (fmi2_xml_real_type_props_t*)(fmi2_xml_find_type_struct(vv->typeBase, fmi2_xml_type_struct_enu_props));
171     if(!props || !props->displayUnit || !props->displayUnit->displayUnit[0]) return 0;
172     return props->displayUnit;
173 }
174
175 double fmi2_xml_get_real_variable_max(fmi2_xml_real_variable_t* v) {
176     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
177     fmi2_xml_real_type_props_t* props = (fmi2_xml_real_type_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
178         assert(props);
179         return props->typeMax;
180 }
181
182 double fmi2_xml_get_real_variable_min(fmi2_xml_real_variable_t* v) {
183     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
184     fmi2_xml_real_type_props_t* props = (fmi2_xml_real_type_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
185         assert(props);
186         return props->typeMin;
187 }
188
189 double fmi2_xml_get_real_variable_nominal(fmi2_xml_real_variable_t* v){
190     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
191     fmi2_xml_real_type_props_t* props = (fmi2_xml_real_type_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
192         assert(props);
193         return props->typeNominal;
194 }
195
196 int fmi2_xml_get_integer_variable_start(fmi2_xml_integer_variable_t* v){
197     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
198     if(fmi2_xml_get_variable_has_start(vv)) {
199         fmi2_xml_variable_start_integer_t* start = (fmi2_xml_variable_start_integer_t*)(vv->typeBase);
200         return start->start;
201     }
202         return 0;
203 }
204
205 int fmi2_xml_get_integer_variable_min(fmi2_xml_integer_variable_t* v){
206     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
207     fmi2_xml_integer_type_props_t* props = (fmi2_xml_integer_type_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
208         assert(props);
209         return props->typeMin;
210 }
211
212 int fmi2_xml_get_integer_variable_max(fmi2_xml_integer_variable_t* v){
213     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
214     fmi2_xml_integer_type_props_t* props = (fmi2_xml_integer_type_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
215         assert(props);
216         return props->typeMax;
217 }
218
219 int fmi2_xml_get_enum_variable_min(fmi2_xml_enum_variable_t* v){
220     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
221         fmi2_xml_variable_type_base_t* props = fmi2_xml_find_type_props(vv->typeBase);
222         return ((fmi2_xml_enum_variable_props_t*)props)->typeMin;
223 }
224
225 int fmi2_xml_get_enum_variable_max(fmi2_xml_enum_variable_t* v){
226     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
227     fmi2_xml_enum_variable_props_t* props =
228                 (fmi2_xml_enum_variable_props_t*)(fmi2_xml_find_type_props(vv->typeBase));
229         assert(props);
230         return props->typeMax;
231 }
232
233 const char* fmi2_xml_get_string_variable_start(fmi2_xml_string_variable_t* v){
234     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
235     if(fmi2_xml_get_variable_has_start(vv)) {
236         fmi2_xml_variable_start_string_t* start = (fmi2_xml_variable_start_string_t*)(vv->typeBase);
237         return start->start;
238     }
239     return 0;
240 }
241
242 int fmi2_xml_get_enum_variable_start(fmi2_xml_enum_variable_t* v) {
243     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
244     if(fmi2_xml_get_variable_has_start(vv)) {
245         fmi2_xml_variable_start_integer_t* start = (fmi2_xml_variable_start_integer_t*)(vv->typeBase);
246         return start->start;
247     }
248         return 0;
249 }
250
251 fmi2_boolean_t fmi2_xml_get_boolean_variable_start(fmi2_xml_bool_variable_t* v) {
252     fmi2_xml_variable_t* vv = (fmi2_xml_variable_t*)v;
253     if(fmi2_xml_get_variable_has_start(vv)) {
254         fmi2_xml_variable_start_integer_t* start = (fmi2_xml_variable_start_integer_t*)(vv->typeBase);
255         return start->start;
256     }
257         return 0;
258 }
259
260 fmi2_xml_real_variable_t* fmi2_xml_get_variable_as_real(fmi2_xml_variable_t* v) {
261     if(fmi2_xml_get_variable_base_type(v) == fmi2_base_type_real)  return (void*)v;
262     return 0;
263 }
264
265 fmi2_xml_integer_variable_t* fmi2_xml_get_variable_as_integer(fmi2_xml_variable_t*v){
266     if(fmi2_xml_get_variable_base_type(v) == fmi2_base_type_int)  return (void*)v;
267     return 0;
268 }
269 fmi2_xml_enum_variable_t* fmi2_xml_get_variable_as_enum(fmi2_xml_variable_t* v){
270     if(fmi2_xml_get_variable_base_type(v) == fmi2_base_type_enum)  return (void*)v;
271     return 0;
272 }
273 fmi2_xml_string_variable_t* fmi2_xml_get_variable_as_string(fmi2_xml_variable_t* v){
274     if(fmi2_xml_get_variable_base_type(v) == fmi2_base_type_str)  return (void*)v;
275     return 0;
276 }
277 fmi2_xml_bool_variable_t* fmi2_xml_get_variable_as_boolean(fmi2_xml_variable_t* v){
278     if(fmi2_xml_get_variable_base_type(v) == fmi2_base_type_bool)  return (void*)v;
279     return 0;
280 }
281
282 int fmi2_xml_handle_ScalarVariable(fmi2_xml_parser_context_t *context, const char* data) {
283     if(!data) {
284             fmi2_xml_model_description_t* md = context->modelDescription;
285             fmi2_xml_variable_t* variable;
286             fmi2_xml_variable_t dummyV;
287             const char* description = 0;
288             jm_named_ptr named, *pnamed;
289             jm_vector(char)* bufName = fmi2_xml_reserve_parse_buffer(context,1,100);
290             jm_vector(char)* bufDescr = fmi2_xml_reserve_parse_buffer(context,2,100);
291             unsigned int vr;
292
293             if(!bufName || !bufDescr) return -1;
294
295             /*   <xs:attribute name="valueReference" type="xs:unsignedInt" use="optional but required for FMI"> */
296             if(fmi2_xml_set_attr_uint(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_valueReference, 1, &vr, 0)) return -1;
297
298             if(
299             /*  <xs:attribute name="name" type="xs:normalizedString" use="required"/> */
300                 fmi2_xml_set_attr_string(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_name, 1, bufName) ||
301             /* <xs:attribute name="description" type="xs:string"/> */
302                 fmi2_xml_set_attr_string(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_description, 0, bufDescr)
303             ) return -1;
304
305             if(context->skipOneVariableFlag) {
306                                 jm_log_error(context->callbacks,module, "Ignoring variable with undefined vr '%s'", jm_vector_get_itemp(char)(bufName,0));
307                 return 0;
308             }
309             if(jm_vector_get_size(char)(bufDescr)) {
310                 description = jm_string_set_put(&md->descriptions, jm_vector_get_itemp(char)(bufDescr,0));
311             }
312
313             named.ptr = 0;
314                         named.name = 0;
315             pnamed = jm_vector_push_back(jm_named_ptr)(&md->variablesByName, named);
316
317             if(pnamed) *pnamed = named = jm_named_alloc_v(bufName,sizeof(fmi2_xml_variable_t), dummyV.name - (char*)&dummyV, context->callbacks);
318             variable = named.ptr;
319             if( !pnamed || !variable ) {
320                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
321                 return -1;
322             }
323             variable->vr = vr;
324             variable->description = description;
325             variable->typeBase = 0;
326                         variable->originalIndex = jm_vector_get_size(jm_named_ptr)(&md->variablesByName) - 1;
327             variable->derivativeOf = 0;
328             variable->previous = 0;
329             variable->aliasKind = fmi2_variable_is_not_alias;
330             variable->reinit = 0;
331             variable->canHandleMultipleSetPerTimeInstant = 1;
332
333             {
334                 jm_name_ID_map_t causalityConventionMap[] = {{"local",fmi2_causality_enu_local},
335                                                              {"input",fmi2_causality_enu_input},
336                                                              {"output",fmi2_causality_enu_output},
337                                                              {"parameter",fmi2_causality_enu_parameter},
338                                                              {"calculatedParameter",fmi2_causality_enu_calculated_parameter},
339                                                              {"independent",fmi2_causality_enu_independent},
340                                                                                                                         {0,0}};
341                 jm_name_ID_map_t variabilityConventionMap[] = {{"continuous",fmi2_variability_enu_continuous},
342                                                                {"constant", fmi2_variability_enu_constant},
343                                                                {"fixed", fmi2_variability_enu_fixed},
344                                                                {"tunable", fmi2_variability_enu_tunable},
345                                                                {"discrete", fmi2_variability_enu_discrete},
346                                                                                                                                 {0,0}};
347                 jm_name_ID_map_t initialConventionMap[] = {{"approx",fmi2_initial_enu_approx},
348                                                             {"calculated",fmi2_initial_enu_calculated},
349                                                             {"exact",fmi2_initial_enu_exact},
350                                                                                                                         {0,0}};
351                 unsigned int causality, variability, initial;
352                                 fmi2_initial_enu_t defaultInitial;
353                 /* <xs:attribute name="causality" default="local"> */
354                 if(fmi2_xml_set_attr_enum(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_causality,0,&causality,fmi2_causality_enu_local,causalityConventionMap))
355                     causality = fmi2_causality_enu_local;
356                 variable->causality = causality;
357                 /*  <xs:attribute name="variability" default="continuous"> */
358                 if(fmi2_xml_set_attr_enum(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_variability,0,&variability,fmi2_variability_enu_continuous,variabilityConventionMap))
359                     variability = fmi2_variability_enu_continuous;
360
361                                 defaultInitial = fmi2_get_default_initial((fmi2_variability_enu_t)variability, (fmi2_causality_enu_t)causality);
362                                 if(defaultInitial == fmi2_initial_enu_unknown) {
363                                         fmi2_xml_parse_error(context,"Invalid combination of variability %s and causality %s. Setting variability to 'fixed'",
364                                                 fmi2_variability_to_string((fmi2_variability_enu_t)variability),
365                                                 fmi2_causality_to_string((fmi2_causality_enu_t)causality));
366                                         variability = fmi2_variability_enu_fixed;
367                                         defaultInitial = fmi2_get_default_initial((fmi2_variability_enu_t)variability, (fmi2_causality_enu_t)causality);
368                                 }
369                 variable->variability = variability;
370
371                 /* <xs:attribute name="initial"> */
372                 if(fmi2_xml_set_attr_enum(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_initial,0,&initial,defaultInitial,initialConventionMap))
373                     initial = defaultInitial;
374                                 defaultInitial = fmi2_get_valid_initial((fmi2_variability_enu_t)variability, (fmi2_causality_enu_t)causality, (fmi2_initial_enu_t) initial);
375                                 if(defaultInitial != initial) {
376                                         fmi2_xml_parse_error(context,"Initial '%s' is not allowed for variability '%s' and causality '%s'. Setting initial to '%s'",
377                                                 fmi2_initial_to_string((fmi2_initial_enu_t)initial),
378                                                 fmi2_variability_to_string((fmi2_variability_enu_t)variability),
379                                                 fmi2_causality_to_string((fmi2_causality_enu_t)causality),
380                                                 fmi2_initial_to_string(defaultInitial));
381                                         initial = defaultInitial;
382                                 }
383                 variable->initial = initial;
384             }
385             {
386                 unsigned int previous, multipleSet;
387                 if (
388                 /*   <xs:attribute name="previous" type="xs:unsignedInt"> */
389                    fmi2_xml_set_attr_uint(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_previous, 0, &previous, 0) ||
390                 /*   <xs:attribute name="canHandleMultipleSetPerTimeInstant" type="xs:boolean"> */
391                    fmi2_xml_set_attr_boolean(context, fmi2_xml_elmID_ScalarVariable, fmi_attr_id_canHandleMultipleSetPerTimeInstant, 0, &multipleSet, 1)
392                 ) return -1;
393
394                  /* Store the index as a pointer since we cannot access the variables list yet (we are constructing it). */
395                 variable->previous = (void*)((char *)NULL + previous);
396                 variable->canHandleMultipleSetPerTimeInstant = (char)multipleSet;
397
398                 if (variable->variability != fmi2_causality_enu_input && !multipleSet) {
399                     fmi2_xml_parse_error(context, "Only variables with causality='input' can have canHandleMultipleSetPerTimeInstant=false");
400                     return -1;
401                 }
402             }
403     }
404     else {
405         if(context->skipOneVariableFlag) {
406             context->skipOneVariableFlag = 0;
407         }
408         else {
409             /* check that the type for the variable is set */
410             fmi2_xml_model_description_t* md = context->modelDescription;
411             fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
412             if(!variable->typeBase) {
413                                 jm_log_error(context->callbacks, module, "No variable type element for variable %s. Assuming Real.", variable->name);
414
415                                 return fmi2_xml_handle_RealVariable(context, data);
416             }
417         }
418         /* might give out a warning if(data[0] != 0) */
419     }
420     return 0;
421 }
422
423 int   fmi2_xml_get_has_start(fmi2_xml_parser_context_t *context, fmi2_xml_variable_t* variable) {
424         int hasStart = fmi2_xml_is_attr_defined(context, fmi_attr_id_start);
425         if(!hasStart)  {
426                 /*
427                    Variables with causality = "parameter" or "input", as well as variables with variability = "constant", must have a "start" value.
428                    If initial = exact or approx, a start value must be provided.
429                    The second condition is actually enough since parameters and inputs and constants must be "initial=exact"
430                 */
431                 if(    (variable->causality == (char)fmi2_causality_enu_parameter)
432                         || (variable->causality == (char)fmi2_causality_enu_input)
433                         || (variable->variability == (char)fmi2_variability_enu_constant)) {
434                                 assert(variable->initial != (char)fmi2_initial_enu_exact);
435                 }
436
437                 if (variable->initial != (char)fmi2_initial_enu_calculated)
438                 {
439                         fmi2_xml_parse_error(context, "Start attribute is required for this causality, variability and initial combination");
440                         hasStart = 1;
441                 }
442         }
443         else {
444                 /* If initial = calculated, it is not allowed to provide a start value. */
445                 if(variable->initial == (char)fmi2_initial_enu_calculated) {
446                         fmi2_xml_parse_error(context, "Start attribute is not allowed for variables with initial='calculated'");
447                         hasStart = 0;
448                 }
449         }
450         return hasStart;
451 }
452
453 static void fmi2_log_error_if_start_required(
454     fmi2_xml_parser_context_t *context,
455     fmi2_xml_variable_t *variable)
456 {
457     if (variable->causality == fmi2_causality_enu_input) {
458         jm_log_error(context->callbacks,
459                        "Error: variable %s: start value required for input variables",
460                        variable->name);
461     } else if (variable->causality == fmi2_causality_enu_parameter) {
462         jm_log_error(context->callbacks,
463                        "Error: variable %s: start value required for parameter variables",
464                        variable->name);
465     } else if (variable->variability == fmi2_variability_enu_constant) {
466         jm_log_error(context->callbacks,
467                        "Error: variable %s: start value required for variables with constant variability",
468                        variable->name);
469     } else if (variable->initial == fmi2_initial_enu_exact) {
470         jm_log_error(context->callbacks,
471                        "Error: variable %s: start value required for variables with initial == \"exact\"",
472                        variable->name);
473     } else if (variable->initial == fmi2_initial_enu_approx) {
474         jm_log_error(context->callbacks,
475                        "Error: variable %s: start value required for variables with initial == \"approx\"",
476                        variable->name);
477     }
478 }
479
480 int fmi2_xml_handle_RealVariable(fmi2_xml_parser_context_t *context, const char* data) {
481     if(context->skipOneVariableFlag) return 0;
482
483     if(!data) {
484         fmi2_xml_model_description_t* md = context->modelDescription;
485         fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
486         fmi2_xml_type_definitions_t* td = &md->typeDefinitions;
487         fmi2_xml_variable_type_base_t * declaredType = 0;
488         fmi2_xml_real_type_props_t * type = 0;
489         int hasStart;
490
491         assert(!variable->typeBase);
492
493         declaredType = fmi2_get_declared_type(context, fmi2_xml_elmID_Real, &td->defaultRealType.typeBase);
494
495         if(!declaredType) return -1;
496
497         {
498             int hasUnit = fmi2_xml_is_attr_defined(context, fmi_attr_id_unit) ||
499                     fmi2_xml_is_attr_defined(context, fmi_attr_id_displayUnit);
500             int hasMin =  fmi2_xml_is_attr_defined(context, fmi_attr_id_min);
501             int hasMax = fmi2_xml_is_attr_defined(context, fmi_attr_id_max);
502             int hasNom = fmi2_xml_is_attr_defined(context, fmi_attr_id_nominal);
503             int hasQuan = fmi2_xml_is_attr_defined(context, fmi_attr_id_quantity);
504             int hasRelQ = fmi2_xml_is_attr_defined(context, fmi_attr_id_relativeQuantity);
505             int hasUnb = fmi2_xml_is_attr_defined(context, fmi_attr_id_unbounded);
506
507
508             if(hasUnit || hasMin || hasMax || hasNom || hasQuan || hasRelQ ||hasUnb) {
509                 fmi2_xml_real_type_props_t* props = 0;
510
511                 if(declaredType->structKind == fmi2_xml_type_struct_enu_typedef)
512                     props = (fmi2_xml_real_type_props_t*)(declaredType->baseTypeStruct);
513                 else
514                     props = (fmi2_xml_real_type_props_t* )declaredType;
515
516                 fmi2_xml_reserve_parse_buffer(context, 1, 0);
517                 fmi2_xml_reserve_parse_buffer(context, 2, 0);
518
519                 type = fmi2_xml_parse_real_type_properties(context, fmi2_xml_elmID_Real);
520
521                 if(!type) return -1;
522                 type->typeBase.baseTypeStruct = declaredType;
523                 if( !hasUnit) type->displayUnit = props->displayUnit;
524                 if( !hasMin)  type->typeMin = props->typeMin;
525                 if( !hasMax) type->typeMax = props->typeMax;
526                 if( !hasNom) type->typeNominal = props->typeNominal;
527                 if( !hasQuan) type->quantity = props->quantity;
528                                 if( !hasRelQ) type->typeBase.isRelativeQuantity = type->typeBase.isRelativeQuantity;
529                                 if( !hasUnb) type->typeBase.isUnbounded = type->typeBase.isUnbounded;
530             }
531             else
532                 type = (fmi2_xml_real_type_props_t*)declaredType;
533         }
534         variable->typeBase = &type->typeBase;
535
536         hasStart = fmi2_xml_get_has_start(context, variable);
537
538         if(hasStart) {
539             fmi2_xml_variable_start_real_t * start = (fmi2_xml_variable_start_real_t*)fmi2_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi2_xml_variable_start_real_t));
540             if(!start) {
541                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
542                 return -1;
543             }
544             if(
545                 /*  <xs:attribute name="start" type="xs:double"/> */
546                     fmi2_xml_set_attr_double(context, fmi2_xml_elmID_Real, fmi_attr_id_start, 0, &start->start, 0)
547                 )
548                     return -1;
549             variable->typeBase = &start->typeBase;
550         } else {
551             fmi2_log_error_if_start_required(context, variable);
552         }
553
554         {
555             /*   <xs:attribute name="derivative" type="xs:unsignedInt"> */
556             unsigned int derivativeOf;
557             unsigned int reinit;
558
559             if(fmi2_xml_set_attr_uint(context, fmi2_xml_elmID_Real,
560                 fmi_attr_id_derivative, 0, &derivativeOf, 0)) return -1;
561             /* TODO: consider: is it ok to read in an unsigned int to store in a size_t? */
562             /* Store the index as a pointer since we cannot access the variables list yet (we are constructing it). */
563             variable->derivativeOf = (void *)((char *)NULL + derivativeOf);
564
565             /*   <xs:attribute name="reinit" type="xs:boolean" use="optional" default="false"> */
566             if(fmi2_xml_set_attr_boolean(context, fmi2_xml_elmID_Real,
567                 fmi_attr_id_reinit, 0, &reinit, 0)) return -1;
568             variable->reinit = (char)reinit;
569
570             if (variable->variability != fmi2_variability_enu_continuous && reinit) {
571                 /* If reinit is true, this variable must be continuous. */
572                 fmi2_xml_parse_error(context, "The reinit attribute may only be set on continuous-time states.");
573                 return -1;
574             }
575         }
576     }
577     else {
578         /* don't do anything. might give out a warning if(data[0] != 0) */
579         return 0;
580     }
581     return 0;
582 }
583
584 int fmi2_xml_handle_IntegerVariable(fmi2_xml_parser_context_t *context, const char* data) {
585     if(context->skipOneVariableFlag) return 0;
586
587     if(!data) {
588         fmi2_xml_model_description_t* md = context->modelDescription;
589         fmi2_xml_type_definitions_t* td = &md->typeDefinitions;
590         fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
591         fmi2_xml_variable_type_base_t * declaredType = 0;
592         fmi2_xml_integer_type_props_t * type = 0;
593         int hasStart;
594
595         declaredType = fmi2_get_declared_type(context, fmi2_xml_elmID_Integer,&td->defaultIntegerType.typeBase) ;
596
597         if(!declaredType) return -1;
598                 {
599                         int hasMin = fmi2_xml_is_attr_defined(context,fmi_attr_id_min);
600                         int hasMax = fmi2_xml_is_attr_defined(context,fmi_attr_id_max);
601                         int hasQuan =  fmi2_xml_is_attr_defined(context,fmi_attr_id_quantity);
602         if( hasMin || hasMax || hasQuan) {
603             fmi2_xml_integer_type_props_t* props = 0;
604
605             if(declaredType->structKind != fmi2_xml_type_struct_enu_typedef)
606                 props = (fmi2_xml_integer_type_props_t*)declaredType;
607             else
608                 props = (fmi2_xml_integer_type_props_t*)(declaredType->baseTypeStruct);
609             assert(props->typeBase.structKind == fmi2_xml_type_struct_enu_props);
610             fmi2_xml_reserve_parse_buffer(context, 1, 0);
611             fmi2_xml_reserve_parse_buffer(context, 2, 0);
612             type = fmi2_xml_parse_integer_type_properties(context, fmi2_xml_elmID_Integer);
613             if(!type) return -1;
614             type->typeBase.baseTypeStruct = declaredType;
615             if(!hasMin) type->typeMin = props->typeMin;
616             if(!hasMax) type->typeMax = props->typeMax;
617             if(!hasQuan) type->quantity = props->quantity;
618         }
619         else
620             type = (fmi2_xml_integer_type_props_t*)declaredType;
621                 }
622         variable->typeBase = &type->typeBase;
623
624         hasStart = fmi2_xml_get_has_start(context, variable);
625                 if(hasStart) {
626             fmi2_xml_variable_start_integer_t * start = (fmi2_xml_variable_start_integer_t*)fmi2_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi2_xml_variable_start_integer_t));
627             if(!start) {
628                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
629                 return -1;
630             }
631             if(
632                 /*  <xs:attribute name="start" type="xs:integer"/> */
633                     fmi2_xml_set_attr_int(context, fmi2_xml_elmID_Integer, fmi_attr_id_start, 0, &start->start, 0)
634                 ) {
635                                         /* not sure how to peek a default here (and start is probably required attriute)*/
636                                         jm_log_error(context->callbacks, module, "Start value zero will be assumed.");
637                                         start->start = 0;
638                         }
639                         variable->typeBase = &start->typeBase;
640         } else {
641             fmi2_log_error_if_start_required(context, variable);
642         }
643     }
644     else {
645         /* don't do anything. might give out a warning if(data[0] != 0) */
646         return 0;
647     }
648     return 0;
649 }
650
651 int fmi2_xml_handle_BooleanVariable(fmi2_xml_parser_context_t *context, const char* data) {
652     if(context->skipOneVariableFlag) return 0;
653
654     if(!data) {
655         fmi2_xml_model_description_t* md = context->modelDescription;
656         fmi2_xml_type_definitions_t* td = &md->typeDefinitions;
657         fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
658         int hasStart;
659
660                 assert(!variable->typeBase);
661
662         variable->typeBase = fmi2_get_declared_type(context, fmi2_xml_elmID_Boolean, &td->defaultBooleanType) ;
663
664         if(!variable->typeBase) return -1;
665
666         hasStart = fmi2_xml_get_has_start(context, variable);
667         if(hasStart) {
668             fmi2_xml_variable_start_integer_t * start = (fmi2_xml_variable_start_integer_t*)fmi2_xml_alloc_variable_type_start(td, variable->typeBase, sizeof(fmi2_xml_variable_start_integer_t ));
669             if(!start) {
670                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
671                 return -1;
672             }
673             if(
674                   /*  <xs:attribute name="start" type="xs:boolean"/> */
675                     fmi2_xml_set_attr_boolean(context, fmi2_xml_elmID_Boolean, fmi_attr_id_start, 0, (unsigned*)&start->start, 0)
676                 )
677                     return -1;
678             variable->typeBase = &start->typeBase;
679         } else {
680             fmi2_log_error_if_start_required(context, variable);
681         }
682     }
683     else {
684         /* don't do anything. might give out a warning if(data[0] != 0) */
685         return 0;
686     }
687     return 0;
688 }
689
690 int fmi2_xml_handle_StringVariable(fmi2_xml_parser_context_t *context, const char* data) {
691     if(context->skipOneVariableFlag) return 0;
692
693     if(!data) {
694         fmi2_xml_model_description_t* md = context->modelDescription;
695         fmi2_xml_type_definitions_t* td = &md->typeDefinitions;
696         fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
697         int hasStart;
698
699                 assert(!variable->typeBase);
700
701         variable->typeBase = fmi2_get_declared_type(context, fmi2_xml_elmID_String,&td->defaultStringType) ;
702
703         if(!variable->typeBase) return -1;
704
705         hasStart = fmi2_xml_get_has_start(context, variable);
706         if(hasStart) {
707             jm_vector(char)* bufStartStr = fmi2_xml_reserve_parse_buffer(context,1, 100);
708             size_t strlen;
709             fmi2_xml_variable_start_string_t * start;
710             if(
711                  /*   <xs:attribute name="start" type="xs:string"/> */
712                     fmi2_xml_set_attr_string(context, fmi2_xml_elmID_String, fmi_attr_id_start, 0, bufStartStr)
713                 )
714                     return -1;
715             strlen = jm_vector_get_size_char(bufStartStr);
716
717             start = (fmi2_xml_variable_start_string_t*)fmi2_xml_alloc_variable_type_start(td, variable->typeBase, sizeof(fmi2_xml_variable_start_string_t) + strlen);
718
719             if(!start) {
720                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
721                 return -1;
722             }
723             if (strlen != 0) { /* No need to memcpy empty strings (gives assetion error) */
724                 memcpy(start->start, jm_vector_get_itemp_char(bufStartStr,0), strlen);
725             }
726             start->start[strlen] = 0;
727             variable->typeBase = &start->typeBase;
728         } else {
729             fmi2_log_error_if_start_required(context, variable);
730         }
731     }
732     else {
733         /* don't do anything. might give out a warning if(data[0] != 0) */
734         return 0;
735     }
736     return 0;
737 }
738
739 fmi2_xml_enum_variable_props_t * fmi2_xml_parse_enum_properties(fmi2_xml_parser_context_t* context, fmi2_xml_enum_variable_props_t* declaredType) {
740
741     fmi2_xml_model_description_t* md = context->modelDescription;
742     fmi2_xml_enum_variable_props_t * props = 0;
743         fmi2_xml_elm_enu_t elmID = fmi2_xml_elmID_Enumeration;
744     const char* quantity = 0;
745
746     /*        jm_vector(char)* bufName = fmi_get_parse_buffer(context,1);
747             jm_vector(char)* bufDescr = fmi_get_parse_buffer(context,2); */
748     jm_vector(char)* bufQuantity = fmi2_xml_reserve_parse_buffer(context,3,100);
749
750         props = (fmi2_xml_enum_variable_props_t*)fmi2_xml_alloc_variable_type_props(&md->typeDefinitions,
751                                         &md->typeDefinitions.defaultEnumType.base.typeBase, sizeof(fmi2_xml_enum_variable_props_t));
752
753     if(!bufQuantity || !props ||
754             /* <xs:attribute name="quantity" type="xs:normalizedString"/> */
755             fmi2_xml_set_attr_string(context, elmID, fmi_attr_id_quantity, 0, bufQuantity)
756             )
757         return 0;
758     if(jm_vector_get_size(char)(bufQuantity))
759         quantity = jm_string_set_put(&md->typeDefinitions.quantities, jm_vector_get_itemp(char)(bufQuantity, 0));
760
761         props->quantity = (quantity == 0) ? declaredType->quantity: quantity;
762
763     if(     /* <xs:attribute name="min" type="xs:int"/> */
764                         fmi2_xml_set_attr_int(context, elmID, fmi_attr_id_min, 0, &props->typeMin, declaredType->typeMin) ||
765             /* <xs:attribute name="max" type="xs:int"/> */
766                         fmi2_xml_set_attr_int(context, elmID, fmi_attr_id_max, 0, &props->typeMax, declaredType->typeMax)
767             ) return 0;
768     return props;
769 }
770
771 int fmi2_xml_handle_EnumerationVariable(fmi2_xml_parser_context_t *context, const char* data) {
772     if(context->skipOneVariableFlag) return 0;
773
774     if(!data) {
775         fmi2_xml_model_description_t* md = context->modelDescription;
776         fmi2_xml_type_definitions_t* td = &md->typeDefinitions;
777         fmi2_xml_variable_t* variable = jm_vector_get_last(jm_named_ptr)(&md->variablesByName).ptr;
778         fmi2_xml_variable_type_base_t * declaredType = 0;
779         fmi2_xml_enum_variable_props_t * type = 0;
780         int hasStart;
781
782                 assert(!variable->typeBase);
783
784         declaredType = fmi2_get_declared_type(context, fmi2_xml_elmID_Enumeration,&td->defaultEnumType.base.typeBase);
785
786         if(!declaredType) return -1;
787
788         if(
789                 fmi2_xml_is_attr_defined(context,fmi_attr_id_min) ||
790                 fmi2_xml_is_attr_defined(context,fmi_attr_id_max) ||
791                 fmi2_xml_is_attr_defined(context,fmi_attr_id_quantity)
792                 ) {
793             fmi2_xml_enum_variable_props_t* props = 0;
794
795             if(declaredType->structKind != fmi2_xml_type_struct_enu_typedef)
796                 props = (fmi2_xml_enum_variable_props_t*)declaredType;
797             else
798                 props = (fmi2_xml_enum_variable_props_t*)declaredType->baseTypeStruct;
799             assert(props->typeBase.structKind == fmi2_xml_type_struct_enu_props);
800             fmi2_xml_reserve_parse_buffer(context, 1, 0);
801             fmi2_xml_reserve_parse_buffer(context, 2, 0);
802                         type = fmi2_xml_parse_enum_properties(context, props);
803             if(!type) return -1;
804             type->typeBase.baseTypeStruct = declaredType;
805         }
806         else
807             type = (fmi2_xml_enum_variable_props_t*)declaredType;
808
809         variable->typeBase = &type->typeBase;
810
811         hasStart = fmi2_xml_get_has_start(context, variable);
812         if(hasStart) {
813             fmi2_xml_variable_start_integer_t * start = (fmi2_xml_variable_start_integer_t*)fmi2_xml_alloc_variable_type_start(td, &type->typeBase, sizeof(fmi2_xml_variable_start_integer_t ));
814             if(!start) {
815                 fmi2_xml_parse_fatal(context, "Could not allocate memory");
816                 return -1;
817             }
818             if(
819                 /*  <xs:attribute name="start" type="xs:integer"/> */
820                     fmi2_xml_set_attr_int(context, fmi2_xml_elmID_Enumeration, fmi_attr_id_start, 0, &start->start, 0)
821                 )
822                                 start->start = type->typeMin;
823             variable->typeBase = &start->typeBase;
824         } else {
825             fmi2_log_error_if_start_required(context, variable);
826         }
827     }
828     else {
829         /* don't do anything. might give out a warning if(data[0] != 0) */
830         return 0;
831     }
832     return 0;
833 }
834
835 static int fmi2_xml_compare_variable_original_index (const void* first, const void* second) {
836         size_t a = (*(fmi2_xml_variable_t**)first)->originalIndex;
837         size_t b = (*(fmi2_xml_variable_t**)second)->originalIndex;
838     if(a < b) return -1;
839     if(a > b) return 1;
840         return 0;
841 }
842
843 void fmi2_xml_eliminate_bad_alias(fmi2_xml_parser_context_t *context, size_t indexVR) {
844     fmi2_xml_model_description_t* md = context->modelDescription;
845     jm_vector(jm_voidp)* varByVR = md->variablesByVR;
846     fmi2_xml_variable_t* v = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, indexVR);
847     fmi2_value_reference_t vr = v->vr;
848     fmi2_base_type_enu_t vt = fmi2_xml_get_variable_base_type(v);
849     size_t i, n = jm_vector_get_size(jm_voidp)(varByVR);
850     for(i = 0; i< n; i++) {
851         jm_named_ptr key;
852         size_t index;
853         v = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, i);
854         if((v->vr != vr)||(vt != fmi2_xml_get_variable_base_type(v))) continue;
855         jm_vector_remove_item_jm_voidp(varByVR,i);
856         n--; i--;
857         key.name = v->name;
858         index = jm_vector_bsearch_index(jm_named_ptr)(&md->variablesByName, &key, jm_compare_named);
859         assert(index <= n);
860         jm_vector_remove_item(jm_named_ptr)(&md->variablesByName,index);
861
862                 index = jm_vector_bsearch_index(jm_voidp)(md->variablesOrigOrder, (jm_voidp*)&v, fmi2_xml_compare_variable_original_index);
863         assert(index <= n);
864
865                 jm_vector_remove_item(jm_voidp)(md->variablesOrigOrder,index);
866
867                 jm_log_error(context->callbacks, module,"Removing incorrect alias variable '%s'", v->name);
868         md->callbacks->free(v);
869     }
870 }
871
872 static int fmi2_xml_compare_vr_and_original_index (const void* first, const void* second) {
873         int ret = fmi2_xml_compare_vr(first, second);
874         if(ret != 0) return ret;
875
876         {
877             fmi2_xml_variable_t* a = *(fmi2_xml_variable_t**)first;
878                 fmi2_xml_variable_t* b = *(fmi2_xml_variable_t**)second;
879                 ret = a->causality - b->causality;
880                 if(ret != 0 ) return ret;
881                 ret = a->variability - b->variability;
882                 if(ret != 0) return ret;
883                 {
884                         size_t ai = a->originalIndex;
885                         size_t bi = b->originalIndex;
886                         if(ai > bi) return 1;
887                         if(ai < bi) return -1;
888                 }
889         }
890
891         return 0;
892 }
893
894 int fmi2_xml_handle_ModelVariables(fmi2_xml_parser_context_t *context, const char* data) {
895     if(!data) {
896                 jm_log_verbose(context->callbacks, module,"Parsing XML element ModelVariables");
897                 /*  reset handles for the elements that are specific under ModelVariables */
898                 fmi2_xml_set_element_handle(context, "Real", FMI2_XML_ELM_ID(RealVariable));
899                 fmi2_xml_set_element_handle(context, "Integer", FMI2_XML_ELM_ID(IntegerVariable));
900                 fmi2_xml_set_element_handle(context, "Enumeration", FMI2_XML_ELM_ID(EnumerationVariable));
901                 fmi2_xml_set_element_handle(context, "String", FMI2_XML_ELM_ID(StringVariable));
902                 fmi2_xml_set_element_handle(context, "Boolean", FMI2_XML_ELM_ID(BooleanVariable));
903                 fmi2_xml_set_element_handle(context, "Tool", FMI2_XML_ELM_ID(VariableTool));
904     }
905     else {
906          /* postprocess variable list */
907
908         fmi2_xml_model_description_t* md = context->modelDescription;
909         jm_vector(jm_voidp)* varByVR;
910         size_t i, numvar;
911
912         numvar = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
913
914         /* store the list of vars in original order */
915                 {
916                         size_t size = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
917                         md->variablesOrigOrder = jm_vector_alloc(jm_voidp)(size,size,md->callbacks);
918                         if(md->variablesOrigOrder) {
919                                 size_t i;
920                                 for(i= 0; i < size; ++i) {
921                                         jm_vector_set_item(jm_voidp)(md->variablesOrigOrder, i, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
922                                 }
923                         }
924                 }
925
926         /* look up actual pointers for the derivativeOf and previous fields in variablesOrigOrder */
927         {
928             size_t size = jm_vector_get_size(jm_voidp)(md->variablesOrigOrder);
929             size_t k;
930             for (k=0; k < size; k++) {
931                 fmi2_xml_variable_t *variable = jm_vector_get_item(jm_voidp)(md->variablesOrigOrder, k);
932
933                 if (variable->derivativeOf) {
934                     /* Retrieve index that was stored as a pointer */
935                     size_t index = (char*)variable->derivativeOf - (char *)NULL;
936                     /* Convert from one- to zero-based indexing */
937                     index--;
938                     /* Ok to just check upper bound since index is unsigned. */
939                     if (index >= size) {
940                         fmi2_xml_parse_error(context, "The 'derivative' attribute must have a value between 1 and the number of model variables.");
941                         /* todo: free allocated memory? */
942                         return -1;
943                     }
944                     variable->derivativeOf = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesOrigOrder, index);
945                 }
946                 if (variable->previous) {
947                     /* retrieve index that was stored as a pointer */
948                     size_t index = (char*)variable->previous - (char *)NULL;
949                     /* Convert from one- to zero-based indexing */
950                     index--;
951                     /* Ok to just check upper bound since index is unsigned. */
952                     if (index >= size) {
953                         fmi2_xml_parse_error(context, "The 'previous' attribute must have a value between 1 and the number of model variables.");
954                         /* todo: free allocated memory? */
955                         return -1;
956                     }
957                     variable->previous = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(md->variablesOrigOrder, index);
958                 }
959             }
960         }
961
962         /* sort the variables by names */
963         jm_vector_qsort(jm_named_ptr)(&md->variablesByName,jm_compare_named);
964
965         /* create VR index */
966         md->status = fmi2_xml_model_description_enu_ok;
967                 {
968                         size_t size = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
969                         md->variablesByVR = jm_vector_alloc(jm_voidp)(size,size,md->callbacks);
970                         if(md->variablesByVR) {
971                                 size_t i;
972                                 for(i= 0; i < size; ++i) {
973                                         jm_vector_set_item(jm_voidp)(md->variablesByVR, i, jm_vector_get_item(jm_named_ptr)(&md->variablesByName,i).ptr);
974                                 }
975                         }
976                 }
977
978         md->status = fmi2_xml_model_description_enu_empty;
979                 if(!md->variablesByVR || !md->variablesOrigOrder) {
980             fmi2_xml_parse_fatal(context, "Could not allocate memory");
981             return -1;
982         }
983         varByVR = md->variablesByVR;
984         jm_vector_qsort(jm_voidp)(varByVR, fmi2_xml_compare_vr_and_original_index);
985
986         numvar = jm_vector_get_size(jm_voidp)(varByVR);
987
988         if(numvar > 1){
989             int foundBadAlias;
990
991                         jm_log_verbose(context->callbacks, module,"Building alias index");
992             do {
993                 fmi2_xml_variable_t* a = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, 0);
994                                 int startPresent = fmi2_xml_get_variable_has_start(a);
995                 int isConstant = (fmi2_xml_get_variability(a) == fmi2_variability_enu_constant);
996                                 a->aliasKind = fmi2_variable_is_not_alias;
997
998                 foundBadAlias = 0;
999
1000                 for(i = 1; i< numvar; i++) {
1001                     fmi2_xml_variable_t* b = (fmi2_xml_variable_t*)jm_vector_get_item(jm_voidp)(varByVR, i);
1002                                         int b_startPresent = fmi2_xml_get_variable_has_start(b);
1003                     int b_isConstant = (fmi2_xml_get_variability(b) == fmi2_variability_enu_constant);
1004                     if((fmi2_xml_get_variable_base_type(a) == fmi2_xml_get_variable_base_type(b))
1005                             && (a->vr == b->vr)) {
1006                                 /* an alias */
1007                             jm_log_verbose(context->callbacks,module,"Variables %s and %s reference the same vr %u. Marking '%s' as alias.",
1008                                                                                               a->name, b->name, b->vr, b->name);
1009                             b->aliasKind = fmi2_variable_is_alias;
1010
1011                             if(!isConstant != !b_isConstant) {
1012                                 jm_log_error(context->callbacks,module,
1013                                 "Only constants can be aliases with constants (variables: %s and %s)",
1014                                     a->name, b->name);
1015                                 fmi2_xml_eliminate_bad_alias(context,i);
1016                                 numvar = jm_vector_get_size(jm_voidp)(varByVR);
1017                                 foundBadAlias = 1;
1018                                 break;
1019                             } else if (isConstant) {
1020                                 if (!startPresent  || !b_startPresent) {
1021                                     jm_log_error(context->callbacks,module,
1022                                         "Constants in alias set must all have start attributes (variables: %s and %s)",
1023                                         a->name, b->name);
1024                                     fmi2_xml_eliminate_bad_alias(context,i);
1025                                     numvar = jm_vector_get_size(jm_voidp)(varByVR);
1026                                     foundBadAlias = 1;
1027                                     break;
1028                                 }
1029                                 /* TODO: Check that both start values are the same */
1030                             } else if(startPresent && b_startPresent) {
1031                                 jm_log_error(context->callbacks,module,
1032                                     "Only one variable among non constant aliases is allowed to have start attribute (variables: %s and %s) %d, %d, const enum value: %d",
1033                                         a->name, b->name, fmi2_xml_get_variability(a), fmi2_xml_get_variability(b), fmi2_variability_enu_constant);
1034                                                                 fmi2_xml_eliminate_bad_alias(context,i);
1035                                 numvar = jm_vector_get_size(jm_voidp)(varByVR);
1036                                                                 foundBadAlias = 1;
1037                                                                 break;
1038                                                         }
1039                                                         if(b_startPresent) {
1040                                                                 startPresent = 1;
1041                                                                 a = b;
1042                                                         }
1043                                         }
1044                                         else {
1045                                                 b->aliasKind = fmi2_variable_is_not_alias;
1046                                                 startPresent = b_startPresent;
1047                         isConstant = b_isConstant;
1048                                                 a = b;
1049                                         }
1050                 }
1051             } while(foundBadAlias);
1052         }
1053
1054         numvar = jm_vector_get_size(jm_named_ptr)(&md->variablesByName);
1055
1056         /* might give out a warning if(data[0] != 0) */
1057     }
1058     return 0;
1059 }