Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 53.2% 177 / 0 / 333
Functions: 65.2% 15 / 0 / 23
Branches: 28.4% 65 / 0 / 229

OMCompiler/SimulationRuntime/c/simulation/arrayIndex.c
Line Branch Exec Source
1 /*
2 * This file belongs to the OpenModelica Run-Time System
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), c/o Linköpings
5 * universitet, Department of Computer and Information Science, SE-58183 Linköping, Sweden. All rights
6 * reserved.
7 *
8 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
9 * AGPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. ANY
10 * USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
11 * ACCEPTANCE OF THE BSD NEW LICENSE OR THE OSMC PUBLIC LICENSE OR THE AGPL
12 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
13 *
14 * The OpenModelica software and the OSMC (Open Source Modelica Consortium) Public License
15 * (OSMC-PL) are obtained from OSMC, either from the above address, from the URLs:
16 * http://www.openmodelica.org or https://github.com/OpenModelica/ or
17 * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica distribution. GNU
18 * AGPL version 3 is obtained from: https://www.gnu.org/licenses/licenses.html#GPL. The BSD NEW
19 * License is obtained from: http://www.opensource.org/licenses/BSD-3-Clause.
20 *
21 * This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY
23 * SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF
24 * OSMC-PL.
25 *
26 */
27
28 /*! \file arrayIndex.c
29 *
30 * Handling of Index mapping between array variables and scalar representation
31 * in simulation data.
32 */
33
34 #include "arrayIndex.h"
35 #include "../util/omc_error.h"
36
37 #include <string.h>
38
39 /**
40 * @brief Allocate memory for index maps.
41 *
42 * Free with `freeArrayIndexMaps`.
43 *
44 * @param modelData Model data containing number of variables.
45 * @param simulationInfo Simulation information with index arrays to allocate
46 * memory for.
47 * @param threadData Thread data for error handling.
48 */
49 1 void allocateArrayIndexMaps(MODEL_DATA *modelData,
50 SIMULATION_INFO *simulationInfo,
51 threadData_t *threadData)
52 {
53 // Variables
54 1 simulationInfo->realVarsIndex = (size_t *)calloc(modelData->nVariablesRealArray + 1, sizeof(size_t));
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->realVarsIndex != NULL, "Out of memory");
56 1 simulationInfo->integerVarsIndex = (size_t *)calloc(modelData->nVariablesIntegerArray + 1, sizeof(size_t));
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->integerVarsIndex != NULL, "Out of memory");
58 1 simulationInfo->booleanVarsIndex = (size_t *)calloc(modelData->nVariablesBooleanArray + 1, sizeof(size_t));
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->booleanVarsIndex != NULL, "Out of memory");
60 1 simulationInfo->stringVarsIndex = (size_t *)calloc(modelData->nVariablesStringArray + 1, sizeof(size_t));
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->stringVarsIndex != NULL, "Out of memory");
62
63 // Parameters
64 1 simulationInfo->realParamsIndex = (size_t *)calloc(modelData->nParametersRealArray + 1, sizeof(size_t));
65
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->realParamsIndex != NULL, "Out of memory");
66 1 simulationInfo->integerParamsIndex = (size_t *)calloc(modelData->nParametersIntegerArray + 1, sizeof(size_t));
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->integerParamsIndex != NULL, "Out of memory");
68 1 simulationInfo->booleanParamsIndex = (size_t *)calloc(modelData->nParametersBooleanArray + 1, sizeof(size_t));
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->booleanParamsIndex != NULL, "Out of memory");
70 1 simulationInfo->stringParamsIndex = (size_t *)calloc(modelData->nParametersStringArray + 1, sizeof(size_t));
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->stringParamsIndex != NULL, "Out of memory");
72
73 // Alias variables
74 1 simulationInfo->realAliasIndex = (size_t *)calloc(modelData->nAliasRealArray + 1, sizeof(size_t));
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->realAliasIndex != NULL, "Out of memory");
76 1 simulationInfo->integerAliasIndex = (size_t *)calloc(modelData->nAliasIntegerArray + 1, sizeof(size_t));
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->integerAliasIndex != NULL, "Out of memory");
78 1 simulationInfo->booleanAliasIndex = (size_t *)calloc(modelData->nAliasBooleanArray + 1, sizeof(size_t));
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->booleanAliasIndex != NULL, "Out of memory");
80 1 simulationInfo->stringAliasIndex = (size_t *)calloc(modelData->nAliasStringArray + 1, sizeof(size_t));
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->stringAliasIndex != NULL, "Out of memory");
82 1 }
83
84 /**
85 * @brief Free memory of variable index maps.
86 *
87 * Free memory allocated by `allocateArrayIndexMaps`.
88 *
89 * @param simulationInfo Simulation info with index arrays to free.
90 */
91 1 void freeArrayIndexMaps(SIMULATION_INFO *simulationInfo)
92 {
93 // Variables
94 1 free(simulationInfo->realVarsIndex);
95 1 free(simulationInfo->integerVarsIndex);
96 1 free(simulationInfo->booleanVarsIndex);
97 1 free(simulationInfo->stringVarsIndex);
98
99 // Parameters
100 1 free(simulationInfo->realParamsIndex);
101 1 free(simulationInfo->integerParamsIndex);
102 1 free(simulationInfo->booleanParamsIndex);
103 1 free(simulationInfo->stringParamsIndex);
104
105 // Alias variables
106 1 free(simulationInfo->realAliasIndex);
107 1 free(simulationInfo->integerAliasIndex);
108 1 free(simulationInfo->booleanAliasIndex);
109 1 free(simulationInfo->stringAliasIndex);
110 1 }
111
112 /**
113 * @brief Allocate memory for reverse index maps.
114 *
115 * Free with `freeArrayReverseIndexMaps`.
116 *
117 * TODO: Allocate memory for missing maps or remove.
118 *
119 * @param modelData Model data containing number of scalarized variables.
120 * @param simulationInfo Simulation information with reverse index arrays to
121 * allocate memory for.
122 * @param threadData Thread data for error handling.
123 */
124 1 void allocateArrayReverseIndexMaps(MODEL_DATA *modelData,
125 SIMULATION_INFO *simulationInfo,
126 threadData_t *threadData)
127 {
128 // Variables
129 1 simulationInfo->realVarsReverseIndex = (array_index_t *)calloc(modelData->nVariablesReal, sizeof(array_index_t));
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->realVarsReverseIndex != NULL, "Out of memory");
131 1 simulationInfo->integerVarsReverseIndex = (array_index_t *)calloc(modelData->nVariablesInteger, sizeof(array_index_t));
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->integerVarsReverseIndex != NULL, "Out of memory");
133 1 simulationInfo->booleanVarsReverseIndex = (array_index_t *)calloc(modelData->nVariablesBoolean, sizeof(array_index_t));
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->booleanVarsReverseIndex != NULL, "Out of memory");
135 1 simulationInfo->stringVarsReverseIndex = (array_index_t *)calloc(modelData->nVariablesString, sizeof(array_index_t));
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->stringVarsReverseIndex != NULL, "Out of memory");
137
138 // Parameters
139 1 simulationInfo->realParamsReverseIndex = (array_index_t *)calloc(modelData->nParametersReal, sizeof(array_index_t));
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->realParamsReverseIndex != NULL, "Out of memory");
141 1 simulationInfo->integerParamsReverseIndex = (array_index_t *)calloc(modelData->nParametersInteger, sizeof(array_index_t));
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->integerParamsReverseIndex != NULL, "Out of memory");
143 1 simulationInfo->booleanParamsReverseIndex = (array_index_t *)calloc(modelData->nParametersBoolean, sizeof(array_index_t));
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->booleanParamsReverseIndex != NULL, "Out of memory");
145 1 simulationInfo->stringParamsReverseIndex = (array_index_t *)calloc(modelData->nParametersString, sizeof(array_index_t));
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 assertStreamPrint(threadData, simulationInfo->stringParamsReverseIndex != NULL, "Out of memory");
147
148 // Alias variables
149 1 simulationInfo->realAliasReverseIndex = NULL;
150 // simulationInfo->realAliasReverseIndex = (array_index_t *)calloc(modelData->nAliasReal, sizeof(array_index_t));
151 // assertStreamPrint(threadData, simulationInfo->realAliasReverseIndex != NULL, "Out of memory");
152 1 simulationInfo->integerAliasReverseIndex = NULL;
153 // simulationInfo->integerAliasReverseIndex = (array_index_t *)calloc(modelData->nAliasInteger, sizeof(array_index_t));
154 // assertStreamPrint(threadData, simulationInfo->integerAliasReverseIndex != NULL, "Out of memory");
155 1 simulationInfo->booleanAliasReverseIndex = NULL;
156 // simulationInfo->booleanAliasReverseIndex = (array_index_t *)calloc(modelData->nAliasBoolean, sizeof(array_index_t));
157 // assertStreamPrint(threadData, simulationInfo->booleanAliasReverseIndex != NULL, "Out of memory");
158 1 simulationInfo->stringAliasReverseIndex = NULL;
159 // simulationInfo->stringAliasReverseIndex = (array_index_t *)calloc(modelData->nAliasString, sizeof(array_index_t));
160 // assertStreamPrint(threadData, simulationInfo->stringAliasReverseIndex != NULL, "Out of memory");
161 1 }
162
163 /**
164 * @brief Free memory of reverse variable index maps.
165 *
166 * Free memory allocated by `allocateArrayReverseIndexMaps`.
167 *
168 * @param simulationInfo Simulation info with reverse index arrays to free.
169 */
170 1 void freeArrayReverseIndexMaps(SIMULATION_INFO *simulationInfo)
171 {
172 // Variables
173 1 free(simulationInfo->realVarsReverseIndex);
174 1 free(simulationInfo->integerVarsReverseIndex);
175 1 free(simulationInfo->booleanVarsReverseIndex);
176 1 free(simulationInfo->stringVarsReverseIndex);
177
178 // Parameters
179 1 free(simulationInfo->realParamsReverseIndex);
180 1 free(simulationInfo->integerParamsReverseIndex);
181 1 free(simulationInfo->booleanParamsReverseIndex);
182 1 free(simulationInfo->stringParamsReverseIndex);
183
184 // Alias variables
185 1 free(simulationInfo->realAliasReverseIndex);
186 1 free(simulationInfo->integerAliasReverseIndex);
187 1 free(simulationInfo->booleanAliasReverseIndex);
188 1 free(simulationInfo->stringAliasReverseIndex);
189 1 }
190
191 /**
192 * @brief Get parameter by ID.
193 *
194 * @param id Identifier (value reference) to search for.
195 * @param integerParameters Array of parameters to search in.
196 * @param nParameters Length of array `integerParameters`.
197 * @return STATIC_INTEGER_DATA* Return reference to parameter with identifier
198 * `ID`. Will return NULL if no matching parameter
199 * can be found.
200 */
201 ✗ STATIC_INTEGER_DATA *getParamById(int id,
202 STATIC_INTEGER_DATA *integerParameters,
203 long nParameters)
204 {
205 long i;
206 ✗ for (i = 0; i < nParameters; i++)
207 {
208 ✗ if (integerParameters[i].info.id == id)
209 {
210 ✗ return &integerParameters[i];
211 }
212 }
213
214 return NULL;
215 }
216
217 /**
218 * @brief Calculate length of multi-dimensional array.
219 *
220 * #### Example
221 *
222 * Tensor T[2][3][4]:
223 * <dimension start="2">
224 * <dimension start="3">
225 * <dimension start="4">
226 * will result in length 2*3*4 = 24
227 *
228 * Array a[p]:
229 * <dimension valueReference="1001">
230 * <dimension start="2">
231 * will result in length p.start*2
232 *
233 * A scalar variable with no dimension info will always be size 1.
234 *
235 * @param dimensionInfo Information about model dimension
236 * @param integerParameterData Used to look up start value of structural
237 * parameters for start value by value reference.
238 * @param nParametersIntegerArray Number of parameters in `integerParameterData`.
239 * @return size_t Scalar length (product of dimensions).
240 */
241 3 size_t calculateLength(DIMENSION_INFO *dimensionInfo,
242 STATIC_INTEGER_DATA *integerParameterData,
243 long nParametersIntegerArray)
244 {
245 size_t length = 1;
246 size_t dim_idx;
247 DIMENSION_ATTRIBUTE *dimensionAttribute;
248 STATIC_INTEGER_DATA *structuralParameter;
249
250
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 if (dimensionInfo == NULL || dimensionInfo->numberOfDimensions == 0 || dimensionInfo->dimensions == NULL)
251 {
252 return length;
253 }
254
255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (dim_idx = 0; dim_idx < dimensionInfo->numberOfDimensions; dim_idx++)
256 {
257 3 dimensionAttribute = &dimensionInfo->dimensions[dim_idx];
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assertStreamPrint(NULL, dimensionAttribute != NULL, "DIMENSION_ATTRIBUTE is NULL");
259
260
1/3
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
3 switch (dimensionAttribute->type)
261 {
262 3 case DIMENSION_BY_START:
263 3 length = length * dimensionAttribute->start;
264 3 break;
265
266 ✗ case DIMENSION_BY_VALUE_REFERENCE:
267 ✗ structuralParameter = getParamById(dimensionAttribute->valueReference, integerParameterData, nParametersIntegerArray);
268 ✗ assertStreamPrint(NULL, structuralParameter != NULL,
269 "Could not find parameter with id '" OMC_INT_FORMAT "'.\n"
270 "Failed to calculate length of variable.",
271 dimensionAttribute->valueReference);
272
273 ✗ assertStreamPrint(NULL, structuralParameter->dimension.numberOfDimensions == 0,
274 "Structural parameter '%s' specifying a dimension has to be a scalar.",
275 structuralParameter->info.name);
276 ✗ dimensionAttribute->start = integer_get(structuralParameter->attribute.start, 0);
277 ✗ length = length * dimensionAttribute->start;
278 ✗ break;
279
280 ✗ default:
281 ✗ throwStreamPrint(NULL, "calculateLength: Illegal dimension attribute type case!");
282 break;
283 }
284 }
285
286 return length;
287 }
288
289 /**
290 * @brief Print flattened names of array variable `name` to `stream`.
291 *
292 * @param stream Stream to write to.
293 * @param separator Seperator to use, e.g. `", "`.
294 * @param name Name of array variable.
295 * @param dimension_info Dimension info for array variable.
296 */
297 ✗ void printFlattenedNames(FILE *stream,
298 const char* separator,
299 const char *name,
300 DIMENSION_INFO *dimension_info)
301 {
302 ✗ assertStreamPrint(NULL, dimension_info != NULL && dimension_info->numberOfDimensions > 0 && dimension_info->dimensions != NULL, "Invalid dimension info.");
303 ✗ assertStreamPrint(NULL, stream != NULL, "Invalid stream.");
304 ✗ assertStreamPrint(NULL, separator != NULL, "Invalid separator.");
305
306 /* Temporary index array */
307 ✗ size_t *idx = (size_t *)calloc(dimension_info->numberOfDimensions, sizeof(size_t)); // FIXME allocate once, outside this function
308 ✗ assertStreamPrint(NULL, idx != NULL, "Out of memory");
309
310 /* initialize with all ones (Modelica subscripts are one-based) */
311 ✗ for (size_t k = 0; k < dimension_info->numberOfDimensions; k++) {
312 ✗ idx[k] = 1;
313 }
314
315 ✗ for (size_t linear = 0; linear < dimension_info->scalar_length; linear++) {
316 /* write indices */
317 ✗ fprintf(stream, "%s\"%s[%zu", separator, name, idx[0]);
318 ✗ for (size_t k = 1; k < dimension_info->numberOfDimensions; ++k) {
319 ✗ fprintf(stream, ",%zu", idx[k]);
320 }
321 fprintf(stream, "]\"");
322
323 /* increment multi-dimensional indices (row-major) */
324 ✗ for (size_t k = dimension_info->numberOfDimensions - 1; k < dimension_info->numberOfDimensions; --k) {
325 ✗ if (idx[k] < (size_t)dimension_info->dimensions[k].start) {
326 ✗ idx[k]++; /* increment minor index if possible */
327 ✗ break; /* done */
328 } else {
329 ✗ idx[k] = 1; /* go back to start, carry to major index */
330 ✗ if (k == 0) {
331 break; /* we are back at all ones, outer for-loop should be done */
332 }
333 }
334 }
335 }
336
337 ✗ free(idx);
338 ✗ }
339
340 /**
341 * @brief Convert index from linear to lexicographical access order.
342 *
343 * The linear storage assumes row-major-order representation.
344 * Linear version of an array is also called flattened or scalarized version.
345 *
346 * #### Example:
347 *
348 * For a 2x3 Matrix A =
349 * ```txt
350 * a_{1,1} a_{1,2} a_{1,3}
351 * a_{2,1} a_{2,2} a_{2,3}
352 * ```
353 *
354 * convert `Address` to `Access` according to
355 *
356 * ```txt
357 * Address | Access | Value
358 * --------|---------|--------
359 * 0 | A[0][0] | a_{1,1}
360 * 1 | A[0][1] | a_{1,2}
361 * 2 | A[0][2] | a_{1,3}
362 * 3 | A[1][0] | a_{2,1}
363 * 4 | A[1][1] | a_{2,2}
364 * 5 | A[1][2] | a_{2,3}
365 * ```
366 *
367 * @param dimension_info Dimensions of multi-dimensional array.
368 * @param linear_address Linear array address.
369 * @return size_t* Array of indices (zero-based),
370 * caller is responsible to free with `free`.
371 */
372 ✗ size_t *linearToMultiDimArrayIndex(DIMENSION_INFO *dimension_info,
373 size_t linear_address)
374 {
375 ✗ assertStreamPrint(NULL, dimension_info != NULL && dimension_info->numberOfDimensions > 0 && dimension_info->dimensions != NULL, "Invalid dimension info.");
376 ✗ assertStreamPrint(NULL, linear_address < dimension_info->scalar_length, "Array out of range: %zu not in [0, %zu]", linear_address, dimension_info->scalar_length);
377
378 /* Allocate array for indices; caller is responsible for freeing */
379 ✗ size_t *array_index = (size_t *)calloc(dimension_info->numberOfDimensions, sizeof(size_t));
380 ✗ assertStreamPrint(NULL, array_index != NULL, "Out of memory");
381
382 ✗ for (size_t k = dimension_info->numberOfDimensions -1; k < dimension_info->numberOfDimensions; --k) {
383 ✗ array_index[k] = linear_address % dimension_info->dimensions[k].start;
384 ✗ linear_address = linear_address / dimension_info->dimensions[k].start;
385 }
386
387 ✗ return array_index;
388 }
389
390 /**
391 * @brief Format a flattened (row-major) index into multi-dimensional indices.
392 *
393 * Converts `linear_address` into a sequence of multi-dimensional indices
394 * according to `dimension_info` and writes the result into `buffer` as
395 * for example "[i][j][k]". If `dimension_info` is NULL or has zero
396 * dimensions an empty string is written.
397 *
398 * The caller must ensure `buffer` has sufficient space for the output. When
399 * `dimension_info` is non-NULL the `linear_address` must be within bounds
400 * (i.e. less than `dimension_info->scalar_length`).
401 *
402 * @param dimension_info Pointer to the dimension metadata (may be NULL).
403 * @param linear_address Flattened (row-major) index to convert.
404 * @param buffer Destination buffer where formatted indices are written.
405 * @param buffer_size Size of `buffer` in bytes.
406 */
407 ✗ void printMultiDimArrayIndex(DIMENSION_INFO *dimension_info,
408 size_t linear_address,
409 char* buffer,
410 size_t buffer_size)
411 {
412 ✗ if (dimension_info == NULL || dimension_info->numberOfDimensions == 0)
413 {
414 ✗ if (buffer_size > 0)
415 {
416 ✗ buffer[0] = '\0';
417 }
418 ✗ return;
419 }
420
421 size_t written = 0;
422 ✗ size_t *array_index = linearToMultiDimArrayIndex(dimension_info, linear_address);
423
424 ✗ for (size_t dim = 0; dim < dimension_info->numberOfDimensions; dim++)
425 {
426 ✗ written += snprintf(buffer + written, buffer_size - written - 1, "[%zu]", array_index[dim]);
427 }
428
429 ✗ free(array_index);
430 ✗ return;
431 }
432
433 /**
434 * @brief Write name of an element of an array variable.
435 *
436 * Uses the Modelica structured naming `"<name>[i,j,...]"` with 1-based
437 * indices. For scalar variables `name` is written.
438 *
439 * A state derivative named `"der(<name>)"` gets `"der(<name>[i,j,...])"`, like
440 * in the result files, if `derivativeSubscriptInside` is set, and
441 * `"der(<name>)[i,j,...]"` otherwise.
442 *
443 * @param buffer Buffer to write into.
444 * @param buffer_size Size of `buffer`.
445 * @param name Name of array variable.
446 * @param dimension_info Dimensions of array variable, may be NULL for scalars.
447 * @param linear_address Flattened (row-major) index of element.
448 * @param derivativeSubscriptInside Put the subscripts of a state derivative inside `der()`.
449 * @return int Number of characters written, like snprintf.
450 */
451 10 int printArrayElementName(char *buffer,
452 size_t buffer_size,
453 const char *name,
454 const DIMENSION_INFO *dimension_info,
455 size_t linear_address,
456 modelica_boolean derivativeSubscriptInside)
457 {
458 int written;
459 size_t k, rem, stride, j;
460 10 size_t name_length = strlen(name);
461
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 const int isDerivative = derivativeSubscriptInside && name_length > 5 && strncmp(name, "der(", 4) == 0 && name[name_length - 1] == ')';
462
463
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (dimension_info == NULL || dimension_info->numberOfDimensions == 0)
464 {
465 ✗ return snprintf(buffer, buffer_size, "%s", name);
466 }
467
468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 written = snprintf(buffer, buffer_size, "%.*s", (int)(isDerivative ? name_length - 1 : name_length), name);
469
470 rem = linear_address;
471
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (k = 0; k < dimension_info->numberOfDimensions; k++)
472 {
473 stride = 1;
474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 for (j = k + 1; j < dimension_info->numberOfDimensions; j++)
475 {
476 ✗ stride *= (size_t)dimension_info->dimensions[j].start;
477 }
478
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 written += snprintf(buffer + written, written < (int)buffer_size ? buffer_size - written : 0,
479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 (k == 0) ? "[%zu" : ",%zu", rem / stride + 1);
480 10 rem = rem % stride;
481 }
482
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 written += snprintf(buffer + written, written < (int)buffer_size ? buffer_size - written : 0, isDerivative ? "])" : "]");
483
484 10 return written;
485 }
486
487 /**
488 * @brief Convert index from lexicographical access order to linear.
489 *
490 * The linear storage assumes row-major-order representation, see
491 * https://en.wikipedia.org/wiki/Row-_and_column-major_order.
492 * Linear version of an array is also called flattened or scalarized version.
493 *
494 * #### Example:
495 *
496 * For a 2x3 Matrix A =
497 * ```txt
498 * a_{1,1} a_{1,2} a_{1,3}
499 * a_{2,1} a_{2,2} a_{2,3}
500 * ```
501 *
502 * convert `Access` to `Address` according to
503 *
504 * ```txt
505 * Address | Access | Value
506 * --------|---------|--------
507 * 0 | A[0][0] | a_{1,1}
508 * 1 | A[0][1] | a_{1,2}
509 * 2 | A[0][2] | a_{1,3}
510 * 3 | A[1][0] | a_{2,1}
511 * 4 | A[1][1] | a_{2,2}
512 * 5 | A[1][2] | a_{2,3}
513 * ```
514 *
515 * @param dimension_info Dimensions of multi-dimensional array.
516 * @param array_index Array of indices (zero-based)
517 * @return size_t Linear array address.
518 */
519 ✗ size_t multiDimArrayToLinearIndex(DIMENSION_INFO* dimension_info,
520 size_t* array_index)
521 {
522 size_t linear_address = 0;
523
524 ✗ assertStreamPrint(NULL, dimension_info != NULL && dimension_info->numberOfDimensions > 0 && dimension_info->dimensions != NULL, "Invalid dimension info.");
525 ✗ assertStreamPrint(NULL, array_index != NULL, "Array index pointer is NULL.");
526
527 ✗ for (size_t k = 0; k < dimension_info->numberOfDimensions; ++k) {
528 ✗ assertStreamPrint(NULL, array_index[k] < dimension_info->dimensions[k].start,
529 "Index out of bounds: array_index[%zu] = %zu >= %zu",
530 k, array_index[k], (size_t)dimension_info->dimensions[k].start);
531
532 ✗ linear_address = linear_address * dimension_info->dimensions[k].start + array_index[k];
533 }
534
535 ✗ return linear_address;
536 }
537
538 /**
539 * @brief Calculate scalar length of all array variables.
540 *
541 * Needs all start values of structural parameters to be set.
542 *
543 * @param modelData Model data containing variable data with array variables to
544 * update.
545 */
546 1 void calculateAllScalarLength(MODEL_DATA *modelData)
547 {
548 long i;
549
550 // Update variables
551
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for (i = 0; i < modelData->nVariablesRealArray; i++)
552 {
553 2 modelData->realVarsData[i].dimension.scalar_length = calculateLength(&modelData->realVarsData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
554 }
555
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for (i = 0; i < modelData->nVariablesIntegerArray; i++)
556 {
557 1 modelData->integerVarsData[i].dimension.scalar_length = calculateLength(&modelData->integerVarsData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
558 }
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nVariablesBooleanArray; i++)
560 {
561 ✗ modelData->booleanVarsData[i].dimension.scalar_length = calculateLength(&modelData->booleanVarsData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
562 }
563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nVariablesStringArray; i++)
564 {
565 ✗ modelData->stringVarsData[i].dimension.scalar_length = calculateLength(&modelData->stringVarsData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
566 }
567
568 // Update parameters
569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nParametersRealArray; i++)
570 {
571 ✗ modelData->realParameterData[i].dimension.scalar_length = calculateLength(&modelData->realParameterData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
572 }
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nParametersIntegerArray; i++)
574 {
575 ✗ modelData->integerParameterData[i].dimension.scalar_length = calculateLength(&modelData->integerParameterData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
576 }
577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nParametersBooleanArray; i++)
578 {
579 ✗ modelData->booleanParameterData[i].dimension.scalar_length = calculateLength(&modelData->booleanParameterData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
580 }
581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for (i = 0; i < modelData->nParametersStringArray; i++)
582 {
583 ✗ modelData->stringParameterData[i].dimension.scalar_length = calculateLength(&modelData->stringParameterData[i].dimension, modelData->integerParameterData, modelData->nParametersIntegerArray);
584 }
585 1 }
586
587 /**
588 * @brief Compute variable index of one type.
589 *
590 * Compute where in `SIMULATION_DATA-><TYPE>Vars` a variable starts.
591 *
592 * Assumes order of array `variableData` is identical to order in `varsIndex`
593 * and SIMULATION_DATA arrays.
594 *
595 * #### Example
596 *
597 * We have variables `x[3]`, `y`, `z[2]` where `x` is an array of length 3, `y`
598 * a scalar and `z` an array of length 3. Then: `varsIndex = [0, 3, 4, 6]`.
599 *
600 * @param variableData Model variable data. Is of type `STATIC_REAL_DATA*`,
601 * `STATIC_INTEGER_DATA*`, `STATIC_BOOLEAN_DATA*` or
602 * `STATIC_STRING_DATA*`.
603 * @param type Specifies type of model variable `variableData`.
604 * @param num_variables Number of variables in array `variableData`.
605 * @param varsIndex Variable index to compute. Will be set on return.
606 */
607 8 void computeVarsIndex(void *variableData,
608 enum var_type type,
609 size_t num_variables,
610 size_t *varsIndex)
611 {
612 size_t i;
613 int id;
614 int previous_id = -1;
615 DIMENSION_INFO *dimensionInfo;
616 size_t scalar_length;
617
618 8 varsIndex[0] = 0;
619
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 for (i = 0; i < num_variables; i++)
620 {
621
2/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 switch (type)
622 {
623 2 case VAR_TYPE_REAL:
624 2 dimensionInfo = &((STATIC_REAL_DATA *)variableData)[i].dimension;
625 2 id = ((STATIC_REAL_DATA *)variableData)[i].info.id;
626 2 break;
627 1 case VAR_TYPE_INTEGER:
628 1 dimensionInfo = &((STATIC_INTEGER_DATA *)variableData)[i].dimension;
629 1 id = ((STATIC_INTEGER_DATA *)variableData)[i].info.id;
630 1 break;
631 ✗ case VAR_TYPE_BOOLEAN:
632 ✗ dimensionInfo = &((STATIC_BOOLEAN_DATA *)variableData)[i].dimension;
633 ✗ id = ((STATIC_BOOLEAN_DATA *)variableData)[i].info.id;
634 ✗ break;
635 ✗ case VAR_TYPE_STRING:
636 ✗ dimensionInfo = &((STATIC_STRING_DATA *)variableData)[i].dimension;
637 ✗ id = ((STATIC_STRING_DATA *)variableData)[i].info.id;
638 ✗ break;
639 ✗ default:
640 ✗ throwStreamPrint(NULL, "computeVarsIndex: Illegal variable type %d.", (int) type);
641 }
642
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 assertStreamPrint(NULL, id == 0 || id > previous_id, // TODO: FMUs don't set id
644 "Value reference not increasing. "
645 "`realVarsData` isn't sorted correctly!");
646 previous_id = id;
647
648
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 scalar_length = dimensionInfo != NULL ? dimensionInfo->scalar_length : 1;
649 3 varsIndex[i + 1] = varsIndex[i] + scalar_length;
650 }
651 8 }
652
653 /**
654 * @brief Compute alias index for array variables.
655 *
656 * Returns identity array mapping.
657 *
658 * This assumes we only create alias variables for scalar variables.
659 *
660 * @param varsIndex Alias index to set.
661 * @param num_variables Number of variables.
662 */
663 4 void computeAliasIndex(size_t *varsIndex,
664 size_t num_variables)
665 {
666 unsigned int i;
667
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i < num_variables + 1; i++)
668 {
669 4 varsIndex[i] = i;
670 }
671 4 }
672
673 /**
674 * @brief Compute all array mappings for scalarized variables.
675 *
676 * TODO: Handle sensitivity parameters.
677 *
678 * @param simulationInfo Simulation info with index maps to set.
679 * @param modelData Model data with number of variables.
680 */
681 1 void computeVarIndices(SIMULATION_INFO *simulationInfo,
682 MODEL_DATA *modelData)
683 {
684 // Variables
685 1 computeVarsIndex(modelData->realVarsData, VAR_TYPE_REAL, modelData->nVariablesRealArray, simulationInfo->realVarsIndex);
686 // TODO: Are states, state derivatives, algebraic variables and discrete algebraic variables handled with this?
687 1 computeVarsIndex(modelData->integerVarsData, VAR_TYPE_INTEGER, modelData->nVariablesIntegerArray, simulationInfo->integerVarsIndex);
688 1 computeVarsIndex(modelData->booleanVarsData, VAR_TYPE_BOOLEAN, modelData->nVariablesBooleanArray, simulationInfo->booleanVarsIndex);
689 1 computeVarsIndex(modelData->stringVarsData, VAR_TYPE_STRING, modelData->nVariablesStringArray, simulationInfo->stringVarsIndex);
690
691 // Parameters
692 1 computeVarsIndex(modelData->realParameterData, VAR_TYPE_REAL, modelData->nParametersRealArray, simulationInfo->realParamsIndex);
693 1 computeVarsIndex(modelData->integerParameterData, VAR_TYPE_INTEGER, modelData->nParametersIntegerArray, simulationInfo->integerParamsIndex);
694 1 computeVarsIndex(modelData->booleanParameterData, VAR_TYPE_BOOLEAN, modelData->nParametersBooleanArray, simulationInfo->booleanParamsIndex);
695 1 computeVarsIndex(modelData->stringParameterData, VAR_TYPE_STRING, modelData->nParametersStringArray, simulationInfo->stringParamsIndex);
696
697 // TODO: Sensitivity parameter array + index
698
699 // Alias
700 1 computeAliasIndex(simulationInfo->realAliasIndex, modelData->nAliasRealArray);
701 1 computeAliasIndex(simulationInfo->integerAliasIndex, modelData->nAliasIntegerArray);
702 1 computeAliasIndex(simulationInfo->booleanAliasIndex, modelData->nAliasBooleanArray);
703 1 computeAliasIndex(simulationInfo->stringAliasIndex, modelData->nAliasStringArray);
704 1 }
705
706 /**
707 * @brief Compute variable reverse index map of one type.
708 *
709 * Compute where a variable `SIMULATION_DATA-><TYPE>Vars` originates from in
710 * `MODEL_DATA-><TYPE>VarsData`. So for every scalarized index this functions
711 * computes a look up to get the index of the corresponding scalar/ array
712 * varible and the index inside the array variable.
713 *
714 * @param variableData Model variable data. Is of type `STATIC_REAL_DATA*`,
715 * `STATIC_INTEGER_DATA*`, `STATIC_BOOLEAN_DATA*` or
716 * `STATIC_STRING_DATA*`.
717 * @param type Specifies type of model variable `variableData`.
718 * @param num_variables Number of scalar + array variables (before flattening).
719 * @param reverseIndex Variable reverse index to compute.
720 */
721 8 void computeVarsReverseIndex(void *variableData,
722 enum var_type type,
723 size_t num_variables,
724 array_index_t* reverseIndex)
725 {
726 size_t scalar_length;
727 size_t i = 0;
728
729
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 for (size_t var_count = 0; var_count < num_variables; var_count++)
730 {
731
2/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 switch (type)
732 {
733 2 case VAR_TYPE_REAL:
734 2 scalar_length = ((STATIC_REAL_DATA *)variableData)[var_count].dimension.scalar_length;
735 2 break;
736 1 case VAR_TYPE_INTEGER:
737 1 scalar_length = ((STATIC_INTEGER_DATA *)variableData)[var_count].dimension.scalar_length;
738 1 break;
739 ✗ case VAR_TYPE_BOOLEAN:
740 ✗ scalar_length = ((STATIC_BOOLEAN_DATA *)variableData)[var_count].dimension.scalar_length;
741 ✗ break;
742 ✗ case VAR_TYPE_STRING:
743 ✗ scalar_length = ((STATIC_STRING_DATA *)variableData)[var_count].dimension.scalar_length;
744 ✗ break;
745 ✗ default:
746 ✗ throwStreamPrint(NULL, "computeVarsReverseIndex: Illegal variable type case.");
747 }
748
749
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (size_t dim = 0; dim < scalar_length; dim++, i++) {
750 6 reverseIndex[i].array_idx = var_count;
751 6 reverseIndex[i].dim_idx = dim;
752 }
753 }
754 8 }
755 /**
756 * @brief Compute all mappings for scalarized variables to array variables.
757 *
758 * TODO: Add rest
759 *
760 * @param simulationInfo Simulation info with index maps to set.
761 * @param modelData Model data with number of variables.
762 */
763 1 void computeVarReverseIndices(SIMULATION_INFO *simulationInfo,
764 MODEL_DATA *modelData)
765 {
766 // Variables
767 1 computeVarsReverseIndex(modelData->realVarsData, VAR_TYPE_REAL, modelData->nVariablesRealArray, simulationInfo->realVarsReverseIndex);
768 1 computeVarsReverseIndex(modelData->integerVarsData, VAR_TYPE_INTEGER, modelData->nVariablesIntegerArray, simulationInfo->integerVarsReverseIndex);
769 1 computeVarsReverseIndex(modelData->booleanVarsData, VAR_TYPE_BOOLEAN, modelData->nVariablesBooleanArray, simulationInfo->booleanVarsReverseIndex);
770 1 computeVarsReverseIndex(modelData->stringVarsData, VAR_TYPE_STRING, modelData->nVariablesStringArray, simulationInfo->stringVarsReverseIndex);
771
772 // Parameters
773 1 computeVarsReverseIndex(modelData->realParameterData, VAR_TYPE_REAL, modelData->nParametersRealArray, simulationInfo->realParamsReverseIndex);
774 1 computeVarsReverseIndex(modelData->integerParameterData, VAR_TYPE_INTEGER, modelData->nParametersIntegerArray, simulationInfo->integerParamsReverseIndex);
775 1 computeVarsReverseIndex(modelData->booleanParameterData, VAR_TYPE_BOOLEAN, modelData->nParametersBooleanArray, simulationInfo->booleanParamsReverseIndex);
776 1 computeVarsReverseIndex(modelData->stringParameterData, VAR_TYPE_STRING, modelData->nParametersStringArray, simulationInfo->stringParamsReverseIndex);
777 1 }
778
779 /**
780 * @brief Index of the attribute element that holds element `dim_idx` of an
781 * array variable.
782 *
783 * An attribute with a single element (`each` or no attribute given in the
784 * init XML) holds the value for all elements of the array variable.
785 *
786 * @param attribute Attribute array of any element type.
787 * @param dim_idx Index inside array variable as 1D representation.
788 * @return size_t Index into the data of `attribute`.
789 */
790 4 size_t attributeElementIndex(const base_array_t *attribute, size_t dim_idx)
791 {
792 4 const size_t n = (size_t) base_array_nr_of_elements(*attribute);
793
794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (n == 1) {
795 return 0;
796 }
797 ✗ assertStreamPrint(NULL, dim_idx < n,
798 "attributeElementIndex: dim_idx %zu out of bounds [0, %zu)", dim_idx, n);
799 return dim_idx;
800 }
801
802 /**
803 * @brief Get element `dim_idx` of a real attribute, see attributeElementIndex.
804 *
805 * @param attribute Attribute array.
806 * @param dim_idx Index inside array variable as 1D representation.
807 * @return modelica_real Attribute value of element `dim_idx`.
808 */
809 4 static modelica_real real_attribute_get(const real_array *attribute, size_t dim_idx)
810 {
811 4 return real_get(*attribute, attributeElementIndex(attribute, dim_idx));
812 }
813
814 /**
815 * @brief Get start attribute by scalar (flattened) index.
816 *
817 * Look up array index and dimension from reverse index map based on variable
818 * kind.
819 * Performs simple out of bounds check.
820 *
821 * TODO: Implement for integers, booleans and strings.
822 *
823 * @param simulationInfo Simulation info with reverse map.
824 * @param modelData Model data containing start.
825 * @param type Variable data type.
826 * @param kind Kind of variable to get start for.
827 * If it's not known if it is a state or algebraic variable use `VAR_KIND_VARIABLE`.
828 * @param scalar_idx Scalar index.
829 * @return modelica_real start attribute value
830 */
831 ✗ modelica_real getStartFromScalarIdx(const SIMULATION_INFO *simulationInfo,
832 const MODEL_DATA *modelData,
833 enum var_type type,
834 enum var_kind kind,
835 size_t scalar_idx)
836 {
837 array_index_t* revIndex;
838
839 ✗ switch (type) {
840 ✗ case VAR_TYPE_REAL:
841 ✗ switch(kind)
842 {
843 ✗ case VAR_KIND_STATE:
844 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nStates,
845 "getStartFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
846 scalar_idx, (size_t)modelData->nStates);
847 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
848 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.start, revIndex->dim_idx);
849
850 ✗ case VAR_KIND_VARIABLE:
851 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nVariablesReal,
852 "getStartFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
853 scalar_idx, (size_t)modelData->nVariablesReal);
854 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
855 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.start, revIndex->dim_idx);
856
857 ✗ case VAR_KIND_PARAMETER:
858 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nParametersReal,
859 "getStartFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
860 scalar_idx, (size_t)modelData->nParametersReal);
861 ✗ revIndex = &simulationInfo->realParamsReverseIndex[scalar_idx];
862 ✗ return real_attribute_get(&modelData->realParameterData[revIndex->array_idx].attribute.start, revIndex->dim_idx);
863
864 ✗ default:
865 ✗ throwStreamPrint(NULL,
866 "getStartFromScalarIdx not implemented for variables of kind %s.",
867 var_kind_names[kind]);
868 }
869 break;
870
871 ✗ default:
872 ✗ throwStreamPrint(NULL, "getStartFromScalarIdx only implemented for VAR_TYPE_REAL.");
873 }
874 }
875
876 /**
877 * @brief Get nominal attribute by scalar (flattened) index.
878 *
879 * Look up array index and dimension from reverse index map based on variable
880 * kind.
881 * Performs simple out of bounds check.
882 *
883 * @param simulationInfo Simulation info with reverse map.
884 * @param modelData Model data containing nominal.
885 * @param kind Kind of variable to get nominal for.
886 * If it's not known if it is a state or algebraic variable use `VAR_KIND_VARIABLE`.
887 * @param scalar_idx Scalar index of real variable.
888 * @return modelica_real Nominal value
889 */
890 4 modelica_real getNominalFromScalarIdx(const SIMULATION_INFO *simulationInfo,
891 const MODEL_DATA *modelData,
892 enum var_kind kind,
893 size_t scalar_idx)
894 {
895 array_index_t* revIndex;
896
897
1/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 switch(kind)
898 {
899 4 case VAR_KIND_STATE:
900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assertStreamPrint(NULL, scalar_idx < modelData->nStates,
901 "getNominalFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
902 scalar_idx, (size_t)modelData->nStates);
903 4 revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
904 4 return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.nominal, revIndex->dim_idx);
905
906 ✗ case VAR_KIND_VARIABLE:
907 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nVariablesReal,
908 "getNominalFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
909 scalar_idx, (size_t)modelData->nVariablesReal);
910 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
911 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.nominal, revIndex->dim_idx);
912
913 ✗ case VAR_KIND_PARAMETER:
914 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nParametersReal,
915 "getNominalFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
916 scalar_idx, (size_t)modelData->nParametersReal);
917 ✗ revIndex = &simulationInfo->realParamsReverseIndex[scalar_idx];
918 ✗ return real_attribute_get(&modelData->realParameterData[revIndex->array_idx].attribute.nominal, revIndex->dim_idx);
919
920 ✗ default:
921 ✗ throwStreamPrint(NULL,
922 "getNominalFromScalarIdx not implemented for variables of kind %s.",
923 var_kind_names[kind]);
924 }
925 }
926
927 /**
928 * @brief Get min attribute by scalar (flattened) index.
929 *
930 * Look up array index and dimension from reverse index map based on variable
931 * kind.
932 * Performs simple out of bounds check.
933 *
934 * TODO: Implement for integers, booleans and strings.
935 *
936 * @param simulationInfo Simulation info with reverse map.
937 * @param modelData Model data containing min.
938 * @param type Variable data type.
939 * @param kind Kind of variable to get min for.
940 * If it's not known if it is a state or algebraic variable use `VAR_KIND_VARIABLE`.
941 * @param scalar_idx Scalar index.
942 * @return modelica_real min attribute value
943 */
944 ✗ modelica_real getMinFromScalarIdx(const SIMULATION_INFO *simulationInfo,
945 const MODEL_DATA *modelData,
946 enum var_type type,
947 enum var_kind kind,
948 size_t scalar_idx)
949 {
950 array_index_t* revIndex;
951
952 ✗ switch (type) {
953 ✗ case VAR_TYPE_REAL:
954 ✗ switch(kind)
955 {
956 ✗ case VAR_KIND_STATE:
957 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nStates,
958 "getMinFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
959 scalar_idx, (size_t)modelData->nStates);
960 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
961 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.min, revIndex->dim_idx);
962
963 ✗ case VAR_KIND_VARIABLE:
964 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nVariablesReal,
965 "getMinFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
966 scalar_idx, (size_t)modelData->nVariablesReal);
967 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
968 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.min, revIndex->dim_idx);
969
970 ✗ case VAR_KIND_PARAMETER:
971 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nParametersReal,
972 "getMinFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
973 scalar_idx, (size_t)modelData->nParametersReal);
974 ✗ revIndex = &simulationInfo->realParamsReverseIndex[scalar_idx];
975 ✗ return real_attribute_get(&modelData->realParameterData[revIndex->array_idx].attribute.min, revIndex->dim_idx);
976
977 ✗ default:
978 ✗ throwStreamPrint(NULL,
979 "getMinFromScalarIdx not implemented for variables of kind %s.",
980 var_kind_names[kind]);
981 }
982 break;
983
984 ✗ default:
985 ✗ throwStreamPrint(NULL, "getMinFromScalarIdx only implemented for VAR_TYPE_REAL.");
986 }
987 }
988
989 /**
990 * @brief Get max attribute by scalar (flattened) index.
991 *
992 * Look up array index and dimension from reverse index map based on variable
993 * kind.
994 * Performs simple out of bounds check.
995 *
996 * TODO: Implement for integers, booleans and strings.
997 *
998 * @param simulationInfo Simulation info with reverse map.
999 * @param modelData Model data containing max.
1000 * @param type Variable data type.
1001 * @param kind Kind of variable to get max for.
1002 * If it's not known if it is a state or algebraic variable use `VAR_KIND_VARIABLE`.
1003 * @param scalar_idx Scalar index.
1004 * @return modelica_real max attribute value
1005 */
1006 ✗ modelica_real getMaxFromScalarIdx(const SIMULATION_INFO *simulationInfo,
1007 const MODEL_DATA *modelData,
1008 enum var_type type,
1009 enum var_kind kind,
1010 size_t scalar_idx)
1011 {
1012 array_index_t* revIndex;
1013
1014 ✗ switch (type) {
1015 ✗ case VAR_TYPE_REAL:
1016 ✗ switch(kind)
1017 {
1018 ✗ case VAR_KIND_STATE:
1019 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nStates,
1020 "getMaxFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
1021 scalar_idx, (size_t)modelData->nStates);
1022 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
1023 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.max, revIndex->dim_idx);
1024
1025 ✗ case VAR_KIND_VARIABLE:
1026 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nVariablesReal,
1027 "getMaxFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
1028 scalar_idx, (size_t)modelData->nVariablesReal);
1029 ✗ revIndex = &simulationInfo->realVarsReverseIndex[scalar_idx];
1030 ✗ return real_attribute_get(&modelData->realVarsData[revIndex->array_idx].attribute.max, revIndex->dim_idx);
1031
1032 ✗ case VAR_KIND_PARAMETER:
1033 ✗ assertStreamPrint(NULL, scalar_idx < modelData->nParametersReal,
1034 "getMaxFromScalarIdx: scalar_idx %zu out of bounds [0, %zu)",
1035 scalar_idx, (size_t)modelData->nParametersReal);
1036 ✗ revIndex = &simulationInfo->realParamsReverseIndex[scalar_idx];
1037 ✗ return real_attribute_get(&modelData->realParameterData[revIndex->array_idx].attribute.max, revIndex->dim_idx);
1038
1039 ✗ default:
1040 ✗ throwStreamPrint(NULL,
1041 "getMaxFromScalarIdx not implemented for variables of kind %s.",
1042 var_kind_names[kind]);
1043 }
1044 break;
1045
1046 ✗ default:
1047 ✗ throwStreamPrint(NULL, "getMaxFromScalarIdx only implemented for VAR_TYPE_REAL.");
1048 }
1049 }
1050