Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 51.0% 372 / 0 / 729
Functions: 50.0% 54 / 1 / 109
Branches: 37.0% 153 / 0 / 414

OMCompiler/SimulationRuntime/c/util/real_array.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 #include "real_array.h"
29 #include "index_spec.h"
30 #include "../gc/omc_gc.h"
31 #include "division.h"
32 #include "integer_array.h"
33 #include "omc_error.h"
34 #include "generic_array.h"
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <math.h>
40 #include <float.h>
41
42 static inline modelica_real *real_ptrget(const real_array *a, size_t i)
43 {
44 ✗ return ((modelica_real *)a->data) + i;
45 }
46
47 static inline void real_set(real_array *a, size_t i, modelica_real r)
48 {
49 102425548 ((modelica_real *)a->data)[i] = r;
50 }
51
52 /**
53 * @brief Get a single element from a real array by 1D index (row-major order).
54 *
55 * @param a The real array to access (0-based indexing in memory).
56 * @param i The flat index of the element to retrieve.
57 *
58 * @return The value at index i.
59 */
60 28210175 modelica_real real_get(const real_array a, size_t i)
61 {
62 28210175 return ((modelica_real *)a.data)[i];
63 }
64
65 /**
66 * @brief Get a single element from a 2D real array.
67 *
68 * @param a The 2D real array (stored in row-major order).
69 * @param i The row index (0-based).
70 * @param j The column index (0-based).
71 *
72 * @return The value at position (i, j).
73 */
74 ✗ modelica_real real_get_2D(const real_array a, size_t i, size_t j)
75 {
76 ✗ return real_get(a, getIndex_2D(a.dim_size, i, j));
77 }
78
79 /**
80 * @brief Get a single element from a 3D real array.
81 *
82 * @param a The 3D real array (stored in row-major order).
83 * @param i The first dimension index (0-based).
84 * @param j The second dimension index (0-based).
85 * @param k The third dimension index (0-based).
86 *
87 * @return The value at position (i, j, k).
88 */
89 ✗ modelica_real real_get_3D(const real_array a, size_t i, size_t j, size_t k)
90 {
91 ✗ return real_get(a, getIndex_3D(a.dim_size, i, j, k));
92 }
93
94 /**
95 * @brief Get a single element from a 4D real array.
96 *
97 * @param a The 4D real array (stored in row-major order).
98 * @param i The first dimension index (0-based).
99 * @param j The second dimension index (0-based).
100 * @param k The third dimension index (0-based).
101 * @param l The fourth dimension index (0-based).
102 *
103 * @return The value at position (i, j, k, l).
104 */
105 ✗ modelica_real real_get_4D(const real_array a, size_t i, size_t j, size_t k, size_t l)
106 {
107 ✗ return real_get(a, getIndex_4D(a.dim_size, i, j, k, l));
108 }
109
110 /**
111 * @brief Get a single element from a 5D real array.
112 *
113 * @param a The 5D real array (stored in row-major order).
114 * @param i The first dimension index (0-based).
115 * @param j The second dimension index (0-based).
116 * @param k The third dimension index (0-based).
117 * @param l The fourth dimension index (0-based).
118 * @param m The fifth dimension index (0-based).
119 *
120 * @return The value at position (i, j, k, l, m).
121 */
122 ✗ modelica_real real_get_5D(const real_array a, size_t i, size_t j, size_t k, size_t l, size_t m)
123 {
124 ✗ return real_get(a, getIndex_5D(a.dim_size, i, j, k, l, m));
125 }
126
127 /**
128 * @brief Create a real array from existing data and dimension information.
129 *
130 * This function initializes a real_array structure by setting all its fields:
131 * data pointer, number of dimensions (ndims), and dimension sizes. The
132 * dimension sizes are passed as variable arguments and must match the ndims
133 * parameter.
134 *
135 * @param[out] dest Pointer to the real_array structure to be initialized.
136 * @param[in] data Pointer to the array data (modelica_real values). Must
137 * be allocated and large enough to hold all elements.
138 * @param[in] ndims Number of dimensions for the array.
139 * @param[in] ... Variable arguments specifying the size of each
140 * dimension. Must provide exactly ndims values, one for
141 * each dimension.
142 *
143 * @note The function does not allocate memory for the data; it only wraps
144 * existing data with dimension information. The caller is responsible for
145 * allocating the data buffer and ensuring it has sufficient size.
146 *
147 * @warning The number and order of dimension size arguments must exactly match
148 * ndims.
149 *
150 * See `alloc_real_array()` for allocation combined with initialization. See
151 * `real_array_create()` for alternative creation methods.
152 *
153 * #### Vector Example (1D array)
154 *
155 * Create a vector with 5 elements:
156 *
157 * ```c
158 * modelica_real data[5] = {1.0, 2.0, 3.0, 4.0, 5.0};
159 * real_array vec;
160 * real_array_create(&vec, data, 1, 5);
161 * ```
162 *
163 * #### Matrix Example (2D array)
164 *
165 * Create a 3x4 matrix in row-major order:
166 *
167 * ```c
168 * modelica_real matrix_data[12] = {
169 * 1.0, 2.0, 3.0, 4.0,
170 * 5.0, 6.0, 7.0, 8.0,
171 * 9.0, 10.0, 11.0, 12.0
172 * };
173 * real_array mat;
174 * real_array_create(&mat, matrix_data, 2, 3, 4);
175 * ```
176 */
177 19602853 void real_array_create(real_array *dest, modelica_real *data, int ndims, ...)
178 {
179 va_list ap;
180 19602853 va_start(ap, ndims);
181 19602853 base_array_create(dest, data, ndims, ap);
182 19602853 va_end(ap);
183 19602853 }
184
185 /**
186 * @brief Allocate a 1D real array (vector) of size n with uninitialized values.
187 *
188 * @param dest Pointer to the real_array structure to initialize.
189 * @param n Number of elements for the vector.
190 *
191 * @attention Memory is allocated from the garbage-collected heap; no explicit
192 * free() is needed.
193 */
194 23807458 void simple_alloc_1d_real_array(real_array *dest, int n)
195 {
196 23807458 simple_alloc_1d_base_array(dest, n, real_alloc(n));
197 23807458 }
198
199 /**
200 * @brief Allocate a 2D real array (matrix) of size r×c with uninitialized values.
201 *
202 * @param dest Pointer to the real_array structure to initialize.
203 * @param r Number of rows in the matrix.
204 * @param c Number of columns in the matrix.
205 *
206 * @attention Memory is allocated from the garbage-collected heap; no explicit
207 * free() is needed.
208 */
209 3557 void simple_alloc_2d_real_array(real_array *dest, int r, int c)
210 {
211 3557 simple_alloc_2d_base_array(dest, r, c, real_alloc(r * c));
212 3557 }
213
214 /**
215 * @brief Allocate a real array with specified dimensions using variable arguments.
216 *
217 * Allocates memory for a real array with the specified number of dimensions.
218 * All dimension sizes must be provided as variable arguments.
219 *
220 * @param dest Pointer to the real_array structure to initialize.
221 * @param ndims Number of dimensions.
222 * @param ... Variable arguments specifying the size of each dimension.
223 *
224 * @attention Memory is allocated from the garbage-collected heap; no explicit
225 * free() is needed.
226 */
227 4993629 void alloc_real_array(real_array *dest, int ndims, ...)
228 {
229 size_t elements = 0;
230 va_list ap;
231 4993629 va_start(ap, ndims);
232 4993629 elements = alloc_base_array(dest, ndims, ap);
233 4993629 va_end(ap);
234 4993629 dest->data = real_alloc(elements);
235 4993629 }
236
237 /**
238 * @brief Allocate data memory for a real array with pre-configured dimensions.
239 *
240 * Allocates the data buffer for an array whose dimensions have already been set.
241 * Useful when dimension information is already configured in the array structure.
242 *
243 * @param a The real_array structure with dimensions already initialized.
244 *
245 * @pre a->ndims and a->dim_size must be properly initialized.
246 * @attention Memory is allocated from the garbage-collected heap; no explicit
247 * free() is needed.
248 */
249 1082540 void alloc_real_array_data(real_array *a)
250 {
251 1082540 a->data = real_alloc(base_array_nr_of_elements(*a));
252 1082540 }
253
254 /**
255 * @brief Copy all elements from a real array into a pre-allocated memory buffer.
256 *
257 * Copies all elements from a real_array structure into a flat memory buffer.
258 * The destination buffer must be pre-allocated with sufficient space to hold
259 * all array elements (num_elements * sizeof(modelica_real)).
260 *
261 * @param[in] source The source real array to copy from.
262 * @param[out] dest Pointer to pre-allocated memory buffer where elements will be copied.
263 *
264 * @pre source must be a valid real_array structure (checked via base_array_ok).
265 * @pre dest must point to valid memory large enough to hold all elements of source.
266 * @pre The memory pointed to by dest must not overlap with source.data.
267 *
268 * @note This function performs element-by-element copying. For large arrays,
269 * consider the performance implications. The function is safe for arrays
270 * of any dimensionality as it copies all elements sequentially.
271 *
272 * @attention The caller is responsible for allocating and managing the dest buffer.
273 * This function does not allocate or free memory for dest.
274 *
275 * #### Example: Copy vector elements to buffer
276 *
277 * ```c
278 * real_array vec;
279 * simple_alloc_1d_real_array(&vec, 5);
280 * // ... populate vec with data ...
281 *
282 * modelica_real buffer[5];
283 * copy_real_array_data_mem(vec, buffer);
284 * // buffer now contains all elements from vec
285 * ```
286 *
287 * #### Example: Copy matrix elements to buffer
288 *
289 * ```c
290 * real_array mat;
291 * alloc_real_array(&mat, 2, 3, 4); // 3x4 matrix
292 * // ... populate mat with data ...
293 *
294 * modelica_real *buffer = (modelica_real *)malloc(12 * sizeof(modelica_real));
295 * copy_real_array_data_mem(mat, buffer);
296 * // buffer now contains all 12 elements from the 3x4 matrix
297 * free(buffer);
298 * ```
299 */
300 683 void copy_real_array_data_mem(const real_array source, modelica_real *dest)
301 {
302 size_t i, nr_of_elements;
303
304
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 683 times.
683 omc_assert_macro(base_array_ok(&source));
305
306 683 nr_of_elements = base_array_nr_of_elements(source);
307
308
2/2
✓ Branch 0 taken 1369 times.
✓ Branch 1 taken 683 times.
2052 for (i = 0; i < nr_of_elements; ++i)
309 {
310 1369 dest[i] = real_get(source, i);
311 }
312 683 }
313
314 /**
315 * @brief Create a deep copy of a real array.
316 *
317 * Allocates new memory for the destination array and copies all elements
318 * from the source array. Both the structure and data are duplicated.
319 *
320 * @param source The source real array to copy from.
321 * @param dest Pointer to the destination real_array structure to be initialized.
322 *
323 * @attention Memory for dest->data is allocated from the garbage-collected heap;
324 * no explicit free() is needed.
325 */
326 78689 void copy_real_array(const real_array source, real_array *dest)
327 {
328 78689 real_array_alloc_copy(source, *dest);
329 78689 }
330
331 46399 static modelica_real real_le(modelica_real x, modelica_real y)
332 {
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46399 times.
46399 return (x <= y);
334 }
335
336 ✗ static modelica_real real_ge(modelica_real x, modelica_real y)
337 {
338 ✗ return (x >= y);
339 }
340
341 /**
342 * @brief Fill a real array with values from a range with start, step, and stop values.
343 *
344 * Fills the destination array with evenly-spaced values. If step > 0, values are
345 * generated from start to stop (inclusive if step divides evenly). If step < 0,
346 * values are generated from start down to stop.
347 *
348 * @param dest Pointer to the pre-allocated real_array to fill.
349 * @param start The first value in the range.
350 * @param step The increment between consecutive values (must not be zero).
351 * @param stop The end value of the range (inclusive if reachable with step size).
352 *
353 * @pre dest must be pre-allocated with sufficient space to hold all generated values.
354 * @attention The number of elements generated is calculated from the range;
355 * caller must ensure dest has adequate capacity.
356 *
357 * #### Example
358 *
359 * ```c
360 * real_array arr;
361 * alloc_real_array(&arr, 1, 10); // Allocate 10 elements
362 * fill_real_array_from_range(&arr, 1.0, 0.5, 5.5);
363 * // arr now contains: 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5
364 * ```
365 */
366 ✗ void fill_real_array_from_range(real_array *dest,
367 modelica_real start,
368 modelica_real step,
369 modelica_real stop)
370 {
371 size_t elements;
372 size_t i;
373 modelica_real value = start;
374 modelica_real (*comp_func)(modelica_real, modelica_real);
375 ✗ omc_assert_macro(step != 0);
376
377 ✗ comp_func = (step > 0) ? &real_le : &real_ge;
378 ✗ elements = comp_func(start, stop) ? (((stop - start) / step) + 1) : 0;
379
380 ✗ for (i = 0; i < elements; value += step, ++i)
381 {
382 real_set(dest, i, value);
383 }
384 ✗ }
385
386 /**
387 * @brief Get pointer to a real array element using an index specification.
388 *
389 * Internal helper function (static inline) for accessing array elements with
390 * index specifications that handle slicing and dimension selection.
391 */
392 static inline modelica_real *calc_real_index_spec(int ndims, const _index_t *idx_vec,
393 const real_array *arr,
394 const index_spec_t *spec)
395 {
396 return real_ptrget(arr, calc_base_index_spec(ndims, idx_vec, arr, spec));
397 }
398
399 /**
400 * @brief Get pointer to a real array element using 0-based multi-dimensional indices.
401 *
402 * Calculates the flat memory address of an element given its coordinates in
403 * a multi-dimensional array using 0-based indexing.
404 *
405 * @param ndims Number of dimensions.
406 * @param idx_vec Array of 0-based indices, one for each dimension.
407 * @param arr The real array.
408 *
409 * @return Pointer to the element at the specified indices.
410 *
411 * @pre ndims must match arr->ndims.
412 * @pre idx_vec must contain exactly ndims valid indices.
413 */
414 ✗ modelica_real *calc_real_index(int ndims, const _index_t *idx_vec, const real_array *arr)
415 {
416 ✗ return real_ptrget(arr, calc_base_index(ndims, idx_vec, arr));
417 }
418
419 /**
420 * @brief Get pointer to a real array element using 1-based indices from variable arguments.
421 *
422 * Calculates the flat memory address of an element given its 1-based coordinates
423 * as variable arguments. Provides bounds checking.
424 *
425 * @param source The real array.
426 * @param ndims Number of dimensions.
427 * @param ap Variable argument list of 1-based indices.
428 *
429 * @return Pointer to the element at the specified indices.
430 *
431 * @pre source must be a valid array with ndims dimensions.
432 * @pre ap must contain exactly ndims valid 1-based indices within bounds.
433 * @attention Asserts on out-of-bounds indices.
434 */
435 ✗ modelica_real *calc_real_index_va(const real_array *source, int ndims, va_list ap)
436 {
437 ✗ return real_ptrget(source, calc_base_index_va(source, ndims, ap));
438 }
439
440 /**
441 * @brief Print a 2D real array (matrix) to standard output.
442 *
443 * Prints the matrix in a formatted grid showing all rows and columns.
444 * Elements are displayed in scientific notation separated by tabs.
445 * For non-2D arrays, prints an informational message.
446 *
447 * @param source The real array to print. Should be 2D for proper formatting.
448 */
449 ✗ void print_real_matrix(const real_array *source)
450 {
451 _index_t i, j;
452 modelica_real value;
453
454 ✗ if (source->ndims == 2)
455 {
456 ✗ printf("%d X %d matrix:\n", (int)source->dim_size[0], (int)source->dim_size[1]);
457 ✗ for (i = 0; i < source->dim_size[0]; ++i)
458 {
459 ✗ for (j = 0; j < source->dim_size[1]; ++j)
460 {
461 ✗ value = real_get(*source, (i * source->dim_size[1]) + j);
462 printf("%e\t", value);
463 }
464 printf("\n");
465 }
466 }
467 else
468 {
469 printf("array with %d dimensions\n", source->ndims);
470 }
471 ✗ }
472
473 /**
474 * @brief Print a real array to standard output in a formatted manner.
475 *
476 * For 1D arrays (vectors), prints comma-separated values in a row.
477 * For multi-dimensional arrays, prints in a grid format with row breaks.
478 *
479 * @param source The real array to print.
480 *
481 * @pre source must be a valid base_array structure.
482 */
483 ✗ void print_real_array(const real_array *source)
484 {
485 _index_t i, j;
486 modelica_real *data;
487 ✗ omc_assert_macro(base_array_ok(source));
488
489 ✗ data = (modelica_real *)source->data;
490 ✗ if (source->ndims == 1)
491 {
492 ✗ for (i = 1; i < source->dim_size[0]; ++i)
493 {
494 ✗ printf("%e, ", *data);
495 ✗ ++data;
496 }
497 ✗ if (0 < source->dim_size[0])
498 {
499 ✗ printf("%e", *data);
500 }
501 }
502 ✗ else if (source->ndims > 1)
503 {
504 size_t k, n;
505
506 ✗ n = base_array_nr_of_elements(*source) /
507 ✗ (source->dim_size[0] * source->dim_size[1]);
508 ✗ for (k = 0; k < n; ++k)
509 {
510 ✗ for (i = 0; i < source->dim_size[1]; ++i)
511 {
512 ✗ for (j = 0; j < source->dim_size[0]; ++j)
513 {
514 ✗ printf("%e, ", *data);
515 ✗ ++data;
516 }
517 ✗ if (0 < source->dim_size[0])
518 {
519 ✗ printf("%e", *data);
520 }
521 printf("\n");
522 }
523 ✗ if ((k + 1) < n)
524 {
525 printf("\n =================\n");
526 }
527 }
528 }
529 ✗ }
530
531 20 static int real_element_to_string(char *buffer, size_t bufsize, const void *data, _index_t i)
532 {
533 20 return snprintf(buffer, bufsize, "%g", ((const modelica_real *)data)[i]);
534 }
535
536 /**
537 * @brief Write real vector into null-terminated string.
538 *
539 * @param source Real vector to write to `buffer`.
540 * @param isScalar Treat vector as scalar.
541 * @param buffer Buffer to write into.
542 * @param bufsize Length of `buffer`.
543 */
544 14 void real_vector_to_string(const real_array *source, modelica_boolean isScalar, char *buffer, size_t bufsize)
545 {
546 14 base_vector_to_string(source, isScalar, real_element_to_string, buffer, bufsize);
547 14 }
548
549 /**
550 * @brief Set a single element in a real array by flat index (0-based).
551 *
552 * @param value Value to store.
553 * @param i1 Flat (0-based) index into the array data.
554 * @param dest Destination array where the value will be stored.
555 *
556 * @pre dest must be a valid real_array and i1 must be in bounds.
557 * @attention This function writes directly into the array's data buffer.
558 */
559 87135742 void put_real_element(modelica_real value, int i1, real_array *dest)
560 {
561 87135742 real_set(dest, i1, value);
562 87135742 }
563
564 /**
565 * @brief Set a single element in a 2D real matrix by row and column (0-based).
566 *
567 * @param value Value to store.
568 * @param r Row index (0-based).
569 * @param c Column index (0-based).
570 * @param dest Destination matrix.
571 *
572 * @pre dest->ndims must be >= 2 and r,c must be within the matrix bounds.
573 */
574 356579 void put_real_matrix_element(modelica_real value, int r, int c, real_array *dest)
575 {
576 /* Assert that dest hast correct dimension */
577 /* Assert that r and c are valid indices */
578 356579 real_set(dest, (r * dest->dim_size[1]) + c, value);
579 356579 }
580
581 /**
582 * @brief Simple indexed assignment for 1D arrays: dest[i1] := source[i1].
583 *
584 * Copies a single element from the source vector into the destination at
585 * the same flat index.
586 *
587 * @param source Source real array (vector).
588 * @param i1 Index to copy (0-based).
589 * @param dest Destination real array.
590 *
591 * @pre source and dest must be valid and have compatible dimensions.
592 */
593 ✗ void simple_indexed_assign_real_array1(const real_array *source,
594 int i1,
595 real_array *dest)
596 {
597 /* Assert that source has the correct dimension */
598 /* Assert that dest has the correct dimension */
599 ✗ real_set(dest, i1, real_get(*source, i1));
600 ✗ }
601
602 /**
603 * @brief Simple indexed assignment for 2D arrays: dest[i1,i2] := source[i1,i2].
604 *
605 * Copies a single element from the source 2D array into the destination at
606 * the computed flat index.
607 *
608 * @param source Source real array (2D).
609 * @param i1 First index (0-based).
610 * @param i2 Second index (0-based).
611 * @param dest Destination real array.
612 *
613 * @pre source and dest must be valid and have compatible dimensions.
614 */
615 ✗ void simple_indexed_assign_real_array2(const real_array *source,
616 int i1,
617 int i2,
618 real_array *dest)
619 {
620 size_t index;
621 /* Assert that source has correct dimension */
622 /* Assert that dest has correct dimension */
623 ✗ index = (i1 * source->dim_size[1]) + i2;
624 ✗ real_set(dest, index, real_get(*source, index));
625 ✗ }
626
627 /**
628 * @brief Perform indexed assignment from a source vector into a destination array
629 * according to an index specification.
630 *
631 * The function iterates over the index specification and assigns elements from
632 * the source (flattened) into the positions in dest defined by dest_spec.
633 *
634 * @param source Source real array (flattened view expected).
635 * @param dest Destination real array to receive values.
636 * @param dest_spec Index specification describing target positions in dest.
637 *
638 * @pre dest_spec must be valid and fit the destination array.
639 */
640 24016 void indexed_assign_real_array(const real_array source, real_array *dest,
641 const index_spec_t *dest_spec)
642 {
643 _index_t *idx_vec1, *idx_size;
644 _index_t j, n;
645 24016 indexed_assign_base_array_size_alloc(&source, dest, dest_spec, &idx_vec1, &idx_size);
646
647 24016 n = base_array_nr_of_elements(source);
648
2/2
✓ Branch 0 taken 95830 times.
✓ Branch 1 taken 24016 times.
119846 for (j = 0; j < n; j++) {
649 95830 real_set(dest,
650 calc_base_index_spec(dest->ndims, idx_vec1, dest, dest_spec),
651 real_get(source, j));
652 95830 next_index(dest_spec->ndims, idx_vec1, idx_size);
653 }
654
655 24016 omc_rc_release_inline(idx_vec1);
656 24016 omc_rc_release_inline(idx_size);
657 24016 }
658
659 /**
660 * @brief Extract elements from a source array according to an index specification.
661 *
662 * Copies elements from `source` into `dest` as defined by `source_spec`.
663 * Both arrays must be properly allocated and the index specification must
664 * fit the source array.
665 *
666 * @param source The source real array.
667 * @param source_spec Index specification describing which elements to extract.
668 * @param dest Destination real array to receive extracted elements.
669 *
670 * @pre `source_spec` must be valid and fit `source`.
671 */
672 125684 void index_real_array(const real_array *source,
673 const index_spec_t *source_spec,
674 real_array *dest)
675 {
676 _index_t *idx_vec1;
677 _index_t *idx_size;
678 int j;
679 int i;
680
681
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
125684 omc_assert_macro(base_array_ok(source));
682
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
125684 omc_assert_macro(base_array_ok(dest));
683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
125684 omc_assert_macro(index_spec_ok(source_spec));
684
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
125684 omc_assert_macro(index_spec_fit_base_array(source_spec, source));
685
686
2/2
✓ Branch 0 taken 183367 times.
✓ Branch 1 taken 125684 times.
309051 for (i = 0, j = 0; i < source_spec->ndims; ++i)
687 {
688
2/2
✓ Branch 0 taken 125684 times.
✓ Branch 1 taken 57683 times.
183367 if (source_spec->index_type[i] != 'S')
689 {
690 125684 ++j;
691 }
692 }
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125684 times.
125684 omc_assert_macro(imax(j, 1) == dest->ndims);
694
1/2
✓ Branch 1 taken 125684 times.
✗ Branch 2 not taken.
125684 if (base_array_nr_of_elements(*dest) == 0)
695 {
696 return;
697 }
698
699 125684 idx_vec1 = size_alloc(source->ndims);
700 125684 idx_size = size_alloc(source_spec->ndims);
701
702
2/2
✓ Branch 0 taken 183367 times.
✓ Branch 1 taken 125684 times.
309051 for (i = 0; i < source->ndims; ++i)
703 {
704 183367 idx_vec1[i] = 0;
705 }
706
2/2
✓ Branch 0 taken 183367 times.
✓ Branch 1 taken 125684 times.
309051 for (i = 0; i < source_spec->ndims; ++i)
707 {
708
2/2
✓ Branch 0 taken 117224 times.
✓ Branch 1 taken 66143 times.
183367 if (source_spec->index_type[i] != 'W')
709 { /* is 'S' or 'A' */
710 117224 idx_size[i] = imax(source_spec->dim_size[i], 1); /* the imax() is not needed, because there is (idx[d] >= size[d]) in the next_index(), but ... */
711 }
712 else
713 { /* is 'W' */
714 66143 idx_size[i] = source->dim_size[i];
715 }
716 }
717
718 j = 0;
719 do
720 {
721 4323759 real_set(dest, j,
722 real_get(*source,
723 4323759 calc_base_index_spec(source->ndims, idx_vec1,
724 source, source_spec)));
725 4323759 j++;
726
727
2/2
✓ Branch 1 taken 4198075 times.
✓ Branch 2 taken 125684 times.
4323759 } while (0 == next_index(source->ndims, idx_vec1, idx_size));
728
729
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125684 times.
125684 omc_assert_macro(j == base_array_nr_of_elements(*dest));
730 125684 omc_rc_release_inline(idx_vec1);
731 125684 omc_rc_release_inline(idx_size);
732 }
733
734 /**
735 * @brief Allocate destination array and extract a subarray defined by an index spec.
736 *
737 * Computes the required destination dimensions (using `index_alloc_base_array_size`),
738 * allocates the data buffer, and performs the extraction via `index_real_array`.
739 *
740 * @param source The source real array.
741 * @param source_spec Index specification describing which elements to extract.
742 * @param dest Destination real array to initialize and fill.
743 */
744 125684 void index_alloc_real_array(const real_array *source,
745 const index_spec_t *source_spec,
746 real_array *dest)
747 {
748 125684 index_alloc_base_array_size(source, source_spec, dest);
749 125684 alloc_real_array_data(dest);
750 125684 index_real_array(source, source_spec, dest);
751 125684 }
752
753 /**
754 * @brief Allocate a (n-1)-dimensional destination array for simple indexing on the first axis.
755 *
756 * Prepares `dest` to receive `source[i1,:,:...]` by setting its dimension sizes
757 * and allocating the data buffer.
758 */
759 ✗ void simple_index_alloc_real_array1(const real_array *source, int i1,
760 real_array *dest)
761 {
762 int i;
763 ✗ omc_assert_macro(base_array_ok(source));
764
765 ✗ dest->ndims = source->ndims - 1;
766 ✗ dest->dim_size = size_alloc(dest->ndims);
767 ✗ dest->owns_data = 1;
768 ✗ omc_assert_macro(dest->dim_size);
769
770 ✗ for (i = 0; i < dest->ndims; ++i)
771 {
772 ✗ dest->dim_size[i] = source->dim_size[i + 1];
773 }
774 ✗ alloc_real_array_data(dest);
775
776 ✗ simple_index_real_array1(source, i1, dest);
777 ✗ }
778
779 /**
780 * @brief Extract a subarray for a fixed first index: dest := source[i1,:,:...].
781 *
782 * Copies the contiguous block corresponding to the selected first index.
783 */
784 ✗ void simple_index_real_array1(const real_array *source,
785 int i1,
786 real_array *dest)
787 {
788 size_t i;
789 ✗ size_t nr_of_elements = base_array_nr_of_elements(*dest);
790 ✗ size_t off = nr_of_elements * i1;
791
792 ✗ for (i = 0; i < nr_of_elements; off++, i++)
793 {
794 ✗ real_set(dest, i, real_get(*source, off));
795 }
796 ✗ }
797
798 /**
799 * @brief Extract a subarray for fixed two first indices: dest := source[i1,i2,:,:...].
800 */
801 ✗ void simple_index_real_array2(const real_array *source,
802 int i1, int i2,
803 real_array *dest)
804 {
805 size_t i;
806 ✗ size_t nr_of_elements = base_array_nr_of_elements(*dest);
807 ✗ size_t off = nr_of_elements * ((source->dim_size[1] * i1) + i2);
808
809 ✗ for (i = 0; i < nr_of_elements; i++, off++)
810 {
811 ✗ real_set(dest, i, real_get(*source, off));
812 }
813 ✗ }
814
815 /**
816 * @brief Concatenate multiple real arrays into a pre-allocated destination.
817 *
818 * Appends the flattened contents of `n` input arrays (`first`, followed by
819 * the variable arguments) into `dest`. The destination must already be
820 * allocated with sufficient space.
821 *
822 * @param dest Destination array where concatenated elements are stored.
823 * @param n Number of input arrays to concatenate.
824 * @param first First input array; remaining arrays are provided as varargs.
825 */
826 ✗ void array_real_array(real_array *dest, int n, real_array first, ...)
827 {
828 int i, j, c;
829 va_list ap;
830
831 ✗ real_array *elts = (real_array *)malloc(sizeof(real_array) * n);
832 ✗ omc_assert_macro(elts);
833 /* collect all array ptrs to simplify traversal.*/
834 ✗ va_start(ap, first);
835 ✗ elts[0] = first;
836 ✗ for (i = 1; i < n; ++i)
837 {
838 ✗ elts[i] = va_arg(ap, real_array);
839 }
840 ✗ va_end(ap);
841
842 ✗ check_base_array_dim_sizes(elts, n);
843
844 ✗ for (i = 0, c = 0; i < n; ++i)
845 {
846 ✗ int m = base_array_nr_of_elements(elts[i]);
847 ✗ for (j = 0; j < m; ++j)
848 {
849 ✗ real_set(dest, c, real_get(elts[i], j));
850 ✗ c++;
851 }
852 }
853 ✗ free(elts);
854 ✗ }
855
856 /**
857 * @brief Allocate and concatenate multiple real arrays into `dest`.
858 *
859 * Computes the required destination dimensions, allocates `dest->data`, and
860 * fills `dest` with the flattened contents of the provided arrays.
861 *
862 * @param dest Destination array to allocate and initialize.
863 * @param n Number of input arrays.
864 * @param first First input array; remaining arrays provided as varargs.
865 */
866 170189 void array_alloc_real_array(real_array *dest, int n, real_array first, ...)
867 {
868 int i, j, c;
869 va_list ap;
870
871 170189 real_array *elts = (real_array *)malloc(sizeof(real_array) * n);
872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170189 times.
170189 omc_assert_macro(elts);
873 /* collect all array ptrs to simplify traversal.*/
874 170189 va_start(ap, first);
875 170189 elts[0] = first;
876
2/2
✓ Branch 0 taken 274004 times.
✓ Branch 1 taken 170189 times.
444193 for (i = 1; i < n; ++i)
877 {
878 274004 elts[i] = va_arg(ap, real_array);
879 }
880 170189 va_end(ap);
881
882 170189 check_base_array_dim_sizes(elts, n);
883
884
1/2
✓ Branch 0 taken 170189 times.
✗ Branch 1 not taken.
170189 if (first.ndims == 1)
885 {
886 170189 alloc_real_array(dest, 2, n, first.dim_size[0]);
887 }
888 ✗ else if (first.ndims == 2)
889 {
890 ✗ alloc_real_array(dest, 3, n, first.dim_size[0], first.dim_size[1]);
891 }
892 ✗ else if (first.ndims == 3)
893 {
894 ✗ alloc_real_array(dest, 4, n, first.dim_size[0], first.dim_size[1], first.dim_size[2]);
895 }
896 ✗ else if (first.ndims == 4)
897 {
898 ✗ alloc_real_array(dest, 5, n, first.dim_size[0], first.dim_size[1], first.dim_size[2], first.dim_size[3]);
899 }
900 else
901 {
902 ✗ omc_assert_macro(0 && "Dimension size > 4 not impl. yet");
903 }
904
905
2/2
✓ Branch 0 taken 444193 times.
✓ Branch 1 taken 170189 times.
614382 for (i = 0, c = 0; i < n; ++i)
906 {
907 444193 int m = base_array_nr_of_elements(elts[i]);
908
2/2
✓ Branch 0 taken 1331971 times.
✓ Branch 1 taken 444193 times.
1776164 for (j = 0; j < m; ++j)
909 {
910 1331971 real_set(dest, c, real_get(elts[i], j));
911 1331971 c++;
912 }
913 }
914 170189 free(elts);
915 170189 }
916
917 /**
918 * @brief Create (allocate) a 1D real array from scalar arguments.
919 *
920 * Allocates a vector of length `n` and fills it with the scalar arguments
921 * provided (first followed by varargs).
922 *
923 * @param dest Destination vector to allocate and fill.
924 * @param n Number of scalar elements.
925 * @param first First scalar element; remaining elements provided as varargs.
926 */
927 21929680 void array_alloc_scalar_real_array(real_array *dest, int n, modelica_real first, ...)
928 {
929 int i;
930 va_list ap;
931 21929680 simple_alloc_1d_real_array(dest, n);
932 21929680 va_start(ap, first);
933 21929680 put_real_element(first, 0, dest);
934
2/2
✓ Branch 0 taken 65205874 times.
✓ Branch 1 taken 21929680 times.
87135554 for (i = 1; i < n; ++i)
935 {
936 65205874 put_real_element(va_arg(ap, modelica_real), i, dest);
937 }
938 21929680 va_end(ap);
939 21929680 }
940
941 /**
942 * @brief Concatenate multiple real arrays along the k-th dimension (k is 1-based).
943 *
944 * Appends the input arrays along the specified dimension into a pre-allocated
945 * destination array `dest`.
946 *
947 * @param k Dimension index (1-based) along which to concatenate.
948 * @param dest Pre-allocated destination array.
949 * @param n Number of input arrays.
950 * @param first First input array; remaining arrays provided as varargs.
951 */
952 ✗ void cat_real_array(int k, real_array *dest, int n,
953 const real_array *first, ...)
954 {
955 va_list ap;
956 int i, j, r, c;
957 int n_sub = 1, n_super = 1;
958 int new_k_dim_size = 0;
959 ✗ const real_array **elts = (const real_array **)malloc(sizeof(real_array *) * n);
960
961 ✗ omc_assert_macro(elts);
962 /* collect all array ptrs to simplify traversal.*/
963 ✗ va_start(ap, first);
964 ✗ elts[0] = first;
965
966 ✗ for (i = 1; i < n; i++)
967 {
968 ✗ elts[i] = va_arg(ap, const real_array *);
969 }
970 ✗ va_end(ap);
971
972 /* check dim sizes of all inputs and dest */
973 ✗ omc_assert_macro(elts[0]->ndims >= k);
974 ✗ for (i = 0; i < n; i++)
975 {
976 ✗ omc_assert_macro(dest->ndims == elts[i]->ndims);
977 ✗ for (j = 0; j < (k - 1); j++)
978 {
979 ✗ omc_assert_macro(dest->dim_size[j] == elts[i]->dim_size[j]);
980 }
981 ✗ new_k_dim_size += elts[i]->dim_size[k - 1];
982 ✗ for (j = k; j < elts[0]->ndims; j++)
983 {
984 ✗ omc_assert_macro(dest->dim_size[j] == elts[i]->dim_size[j]);
985 }
986 }
987 ✗ omc_assert_macro(dest->dim_size[k - 1] == new_k_dim_size);
988
989 /* calculate size of sub and super structure in 1-dim data representation */
990 ✗ for (i = 0; i < (k - 1); i++)
991 {
992 ✗ n_super *= elts[0]->dim_size[i];
993 }
994 ✗ for (i = k; i < elts[0]->ndims; i++)
995 {
996 ✗ n_sub *= elts[0]->dim_size[i];
997 }
998
999 /* concatenation along k-th dimension */
1000 j = 0;
1001 ✗ for (i = 0; i < n_super; i++)
1002 {
1003 ✗ for (c = 0; c < n; c++)
1004 {
1005 ✗ int n_sub_k = n_sub * elts[c]->dim_size[k - 1];
1006 ✗ for (r = 0; r < n_sub_k; r++)
1007 {
1008 ✗ real_set(dest, j,
1009 ✗ real_get(*elts[c], r + (i * n_sub_k)));
1010 ✗ j++;
1011 }
1012 }
1013 }
1014 ✗ free(elts);
1015 ✗ }
1016
1017 /**
1018 * @brief Allocate and concatenate multiple real arrays along the k-th dimension.
1019 *
1020 * Computes the required `dest` dimensions and fills the allocated destination
1021 * with concatenated inputs.
1022 *
1023 * @param k Dimension index (1-based) along which to concatenate.
1024 * @param dest Destination array to allocate and fill.
1025 * @param n Number of input arrays.
1026 * @param first First input array; remaining arrays provided as varargs.
1027 */
1028 234038 void cat_alloc_real_array(int k,
1029 real_array *dest,
1030 int n,
1031 const real_array *first, ...)
1032 {
1033 va_list ap;
1034 int i, j, r, c;
1035 int n_sub = 1, n_super = 1;
1036 int new_k_dim_size = 0;
1037 234038 const real_array **elts = (const real_array **)malloc(sizeof(real_array *) * n);
1038
1039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234038 times.
234038 omc_assert_macro(elts);
1040 /* collect all array ptrs to simplify traversal.*/
1041 234038 va_start(ap, first);
1042 234038 elts[0] = first;
1043
1044
2/2
✓ Branch 0 taken 234128 times.
✓ Branch 1 taken 234038 times.
468166 for (i = 1; i < n; i++)
1045 {
1046 234128 elts[i] = va_arg(ap, const real_array *);
1047 }
1048 234038 va_end(ap);
1049
1050 /* check dim sizes of all inputs */
1051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234038 times.
234038 omc_assert_macro(elts[0]->ndims >= k);
1052 234038 new_k_dim_size = elts[0]->dim_size[k - 1];
1053
2/2
✓ Branch 0 taken 234128 times.
✓ Branch 1 taken 234038 times.
468166 for (i = 1; i < n; i++)
1054 {
1055
1/2
✓ Branch 0 taken 234128 times.
✗ Branch 1 not taken.
234128 omc_assert_macro(elts[0]->ndims == elts[i]->ndims);
1056
2/2
✓ Branch 0 taken 1126 times.
✓ Branch 1 taken 234128 times.
235254 for (j = 0; j < (k - 1); j++)
1057 {
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1126 times.
1126 omc_assert_macro(elts[0]->dim_size[j] == elts[i]->dim_size[j]);
1059 }
1060 234128 new_k_dim_size += elts[i]->dim_size[k - 1];
1061
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 234128 times.
234188 for (j = k; j < elts[0]->ndims; j++)
1062 {
1063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 omc_assert_macro(elts[0]->dim_size[j] == elts[i]->dim_size[j]);
1064 }
1065 }
1066
1067 /* calculate size of sub and super structure in 1-dim data representation */
1068
2/2
✓ Branch 0 taken 1066 times.
✓ Branch 1 taken 234038 times.
235104 for (i = 0; i < (k - 1); i++)
1069 {
1070 1066 n_super *= elts[0]->dim_size[i];
1071 }
1072
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 234038 times.
234068 for (i = k; i < elts[0]->ndims; i++)
1073 {
1074 30 n_sub *= elts[0]->dim_size[i];
1075 }
1076 /* allocate dest structure */
1077 234038 dest->data = real_alloc(n_super * new_k_dim_size * n_sub);
1078 234038 dest->ndims = elts[0]->ndims;
1079 234038 dest->dim_size = size_alloc(dest->ndims);
1080 234038 dest->owns_data = 1;
1081
2/2
✓ Branch 0 taken 235134 times.
✓ Branch 1 taken 234038 times.
469172 for (j = 0; j < dest->ndims; j++)
1082 {
1083 235134 dest->dim_size[j] = elts[0]->dim_size[j];
1084 }
1085 234038 dest->dim_size[k - 1] = new_k_dim_size;
1086 /* concatenation along k-th dimension */
1087 j = 0;
1088
2/2
✓ Branch 0 taken 236553 times.
✓ Branch 1 taken 234038 times.
470591 for (i = 0; i < n_super; i++)
1089 {
1090
2/2
✓ Branch 0 taken 473196 times.
✓ Branch 1 taken 236553 times.
709749 for (c = 0; c < n; c++)
1091 {
1092 473196 int n_sub_k = n_sub * elts[c]->dim_size[k - 1];
1093
2/2
✓ Branch 0 taken 503677 times.
✓ Branch 1 taken 473196 times.
976873 for (r = 0; r < n_sub_k; r++)
1094 {
1095 1007354 real_set(dest, j,
1096 503677 real_get(*elts[c], r + (i * n_sub_k)));
1097 503677 j++;
1098 }
1099 }
1100 }
1101 234038 free(elts);
1102 234038 }
1103
1104 /**
1105 * @brief Allocate a 1D real array and fill it with a numeric range.
1106 *
1107 * Allocates a vector of values starting at `start`, incrementing by `inc`,
1108 * and ending at or before `stop` (depending on step alignment).
1109 *
1110 * @param start Start value.
1111 * @param stop Stop value.
1112 * @param inc Increment (step).
1113 * @param dest Destination vector to allocate and fill.
1114 */
1115 ✗ void range_alloc_real_array(modelica_real start, modelica_real stop, modelica_real inc, real_array *dest)
1116 {
1117 int n;
1118
1119 ✗ n = (int)floor((stop - start) / inc) + 1;
1120 ✗ simple_alloc_1d_real_array(dest, n);
1121 ✗ range_real_array(start, stop, inc, dest);
1122 ✗ }
1123
1124 /**
1125 * @brief Fill an existing 1D array with a numeric range.
1126 *
1127 * Populates `dest` with values starting at `start` and incremented by `inc`.
1128 * `dest` must already be allocated with sufficient length.
1129 *
1130 * @param start Start value.
1131 * @param stop Stop value (unused by this function; kept for API symmetry).
1132 * @param inc Increment (step).
1133 * @param dest Destination vector to fill.
1134 */
1135 ✗ void range_real_array(modelica_real start, modelica_real stop, modelica_real inc, real_array *dest)
1136 {
1137 int i;
1138 modelica_real v = start;
1139 /* Assert that dest has correct size */
1140 ✗ for (i = 0; i < dest->dim_size[0]; ++i, v += inc)
1141 {
1142 ✗ real_set(dest, i, v);
1143 }
1144 ✗ }
1145
1146 /**
1147 * @brief Element-wise addition of two real arrays: dest := a + b.
1148 *
1149 * Adds corresponding elements of `a` and `b` and stores the result in `dest`.
1150 * Arrays must have the same shape.
1151 */
1152 15937 void add_real_array(const real_array *a, const real_array *b, real_array *dest)
1153 {
1154 size_t nr_of_elements;
1155 size_t i;
1156
1157 /* Assert a and b are of the same size */
1158 /* Assert that dest are of correct size */
1159 15937 nr_of_elements = base_array_nr_of_elements(*a);
1160
2/2
✓ Branch 0 taken 71308 times.
✓ Branch 1 taken 15937 times.
87245 for (i = 0; i < nr_of_elements; ++i)
1161 {
1162 71308 real_set(dest, i, real_get(*a, i) + real_get(*b, i));
1163 }
1164 15937 }
1165
1166 /**
1167 * @brief Allocate and return the element-wise sum of two real arrays.
1168 *
1169 * Clones the shape of `a`, allocates storage for the result, and returns
1170 * a new array containing `a + b`.
1171 */
1172 15937 real_array add_alloc_real_array(const real_array a, const real_array b)
1173 {
1174 real_array dest;
1175 clone_real_array_spec(&a, &dest);
1176 15937 alloc_real_array_data(&dest);
1177 15937 add_real_array(&a, &b, &dest);
1178 15937 return dest;
1179 }
1180
1181 /**
1182 * @brief Allocate and return array resulting from adding a scalar to each element.
1183 *
1184 * Returns `sc + arr` with the same shape as `arr`.
1185 */
1186 ✗ real_array add_alloc_real_array_scalar(const real_array arr, const modelica_real sc)
1187 {
1188 size_t nr_of_elements, i;
1189 real_array dest;
1190 clone_real_array_spec(&arr, &dest);
1191 ✗ alloc_real_array_data(&dest);
1192 ✗ nr_of_elements = base_array_nr_of_elements(arr);
1193 ✗ for (i = 0; i < nr_of_elements; ++i)
1194 {
1195 ✗ real_set(&dest, i, sc + real_get(arr, i));
1196 }
1197 ✗ return dest;
1198 }
1199
1200 ✗ real_array sub_alloc_scalar_real_array(modelica_real sc, const real_array arr)
1201 {
1202 size_t nr_of_elements, i;
1203 real_array dest;
1204 clone_real_array_spec(&arr, &dest);
1205 ✗ alloc_real_array_data(&dest);
1206 ✗ nr_of_elements = base_array_nr_of_elements(arr);
1207 ✗ for (i = 0; i < nr_of_elements; ++i)
1208 {
1209 ✗ real_set(&dest, i, sc - real_get(arr, i));
1210 }
1211 ✗ return dest;
1212 }
1213
1214 /**
1215 * @brief In-place unary negation of a real array (a := -a).
1216 */
1217 ✗ void usub_real_array(real_array *a)
1218 {
1219 size_t nr_of_elements, i;
1220
1221 ✗ nr_of_elements = base_array_nr_of_elements(*a);
1222 ✗ for (i = 0; i < nr_of_elements; ++i)
1223 {
1224 ✗ real_set(a, i, -real_get(*a, i));
1225 }
1226 ✗ }
1227
1228 /**
1229 * @brief Allocate and return the unary negation of a real array.
1230 */
1231 93440 void usub_alloc_real_array(const real_array a, real_array *dest)
1232 {
1233 size_t nr_of_elements, i;
1234 clone_real_array_spec(&a, dest);
1235 93440 alloc_real_array_data(dest);
1236
1237 93440 nr_of_elements = base_array_nr_of_elements(*dest);
1238
2/2
✓ Branch 0 taken 319486 times.
✓ Branch 1 taken 93440 times.
412926 for (i = 0; i < nr_of_elements; ++i)
1239 {
1240 319486 real_set(dest, i, -real_get(a, i));
1241 }
1242 93440 }
1243
1244 /**
1245 * @brief Element-wise subtraction: dest := a - b.
1246 */
1247 130643 void sub_real_array(const real_array *a, const real_array *b, real_array *dest)
1248 {
1249 size_t nr_of_elements;
1250 size_t i;
1251
1252 /* Assert a and b are of the same size */
1253 /* Assert that dest are of correct size */
1254 130643 nr_of_elements = base_array_nr_of_elements(*a);
1255
2/2
✓ Branch 0 taken 805640 times.
✓ Branch 1 taken 130643 times.
936283 for (i = 0; i < nr_of_elements; ++i)
1256 {
1257 805640 real_set(dest, i, real_get(*a, i) - real_get(*b, i));
1258 }
1259 130643 }
1260
1261 /**
1262 * @brief Element-wise subtraction writing into a pre-allocated C buffer.
1263 *
1264 * Writes (a - b) into `dest` (C array of modelica_real).
1265 */
1266 ✗ void sub_real_array_data_mem(const real_array *a,
1267 const real_array *b,
1268 modelica_real *dest)
1269 {
1270 size_t nr_of_elements;
1271 size_t i;
1272
1273 /* Assert a and b are of the same size */
1274 /* Assert that dest are of correct size */
1275 ✗ nr_of_elements = base_array_nr_of_elements(*a);
1276 ✗ for (i = 0; i < nr_of_elements; ++i)
1277 {
1278 ✗ dest[i] = real_get(*a, i) - real_get(*b, i);
1279 }
1280 ✗ }
1281
1282 /**
1283 * @brief Allocate and return dest := a - b.
1284 */
1285 130643 real_array sub_alloc_real_array(const real_array a, const real_array b)
1286 {
1287 real_array dest;
1288 clone_real_array_spec(&a, &dest);
1289 130643 alloc_real_array_data(&dest);
1290 130643 sub_real_array(&a, &b, &dest);
1291 130643 return dest;
1292 }
1293
1294 /**
1295 * @brief Multiply every element of `b` by scalar `a` and store in `dest`.
1296 */
1297 ✗ void mul_scalar_real_array(modelica_real a,
1298 const real_array *b,
1299 real_array *dest)
1300 {
1301 size_t nr_of_elements;
1302 size_t i;
1303 /* Assert that dest has correct size*/
1304 ✗ nr_of_elements = base_array_nr_of_elements(*b);
1305 ✗ for (i = 0; i < nr_of_elements; ++i)
1306 {
1307 ✗ real_set(dest, i, a * real_get(*b, i));
1308 }
1309 ✗ }
1310
1311 /**
1312 * @brief Allocate and return the result of scalar * array.
1313 *
1314 * TODO: Remove me
1315 */
1316 ✗ real_array mul_alloc_scalar_real_array(modelica_real a, const real_array b)
1317 {
1318 real_array dest;
1319 clone_real_array_spec(&b, &dest);
1320 ✗ alloc_real_array_data(&dest);
1321 ✗ mul_scalar_real_array(a, &b, &dest);
1322 ✗ return dest;
1323 }
1324
1325 /**
1326 * @brief Multiply every element of `a` by scalar `b` and store in `dest`.
1327 */
1328 118848 void mul_real_array_scalar(const real_array *a,
1329 modelica_real b,
1330 real_array *dest)
1331 {
1332 size_t nr_of_elements;
1333 size_t i;
1334 /* Assert that dest has correct size*/
1335 118848 nr_of_elements = base_array_nr_of_elements(*a);
1336
2/2
✓ Branch 0 taken 601452 times.
✓ Branch 1 taken 118848 times.
720300 for (i = 0; i < nr_of_elements; ++i)
1337 {
1338 601452 real_set(dest, i, real_get(*a, i) * b);
1339 }
1340 118848 }
1341
1342 /**
1343 * @brief Allocate and return the result of array * scalar.
1344 */
1345 118848 real_array mul_alloc_real_array_scalar(const real_array a,
1346 const modelica_real b)
1347 {
1348 real_array dest;
1349 clone_real_array_spec(&a, &dest);
1350 118848 alloc_real_array_data(&dest);
1351 118848 mul_real_array_scalar(&a, b, &dest);
1352 118848 return dest;
1353 }
1354
1355 /**
1356 * @brief Element-wise multiplication of two real arrays: dest := a * b.
1357 */
1358 163179 void mul_real_array(const real_array *a, const real_array *b, real_array *dest)
1359 {
1360 size_t nr_of_elements;
1361 size_t i;
1362 /* Assert that a,b have same sizes? */
1363 163179 nr_of_elements = base_array_nr_of_elements(*a);
1364
2/2
✓ Branch 0 taken 673993 times.
✓ Branch 1 taken 163179 times.
837172 for (i = 0; i < nr_of_elements; ++i)
1365 {
1366 673993 real_set(dest, i, real_get(*a, i) * real_get(*b, i));
1367 }
1368 163179 }
1369
1370 /**
1371 * @brief Allocate and return the element-wise product of two arrays.
1372 */
1373 163179 real_array mul_alloc_real_array(const real_array a, const real_array b)
1374 {
1375 real_array dest;
1376 clone_real_array_spec(&a, &dest);
1377 163179 alloc_real_array_data(&dest);
1378 163179 mul_real_array(&a, &b, &dest);
1379 163179 return dest;
1380 }
1381
1382 /**
1383 * @brief Compute the scalar (dot) product of two vectors.
1384 */
1385 1007285 modelica_real mul_real_scalar_product(const real_array a, const real_array b)
1386 {
1387 size_t nr_of_elements;
1388 size_t i;
1389 modelica_real res;
1390 /* Assert that a and b are vectors */
1391 /* Assert that vectors are of matching size */
1392
1393 1007285 nr_of_elements = real_array_nr_of_elements(a);
1394 res = 0.0;
1395
2/2
✓ Branch 0 taken 2589840 times.
✓ Branch 1 taken 1007285 times.
3597125 for (i = 0; i < nr_of_elements; ++i)
1396 {
1397 2589840 res += real_get(a, i) * real_get(b, i);
1398 }
1399 1007285 return res;
1400 }
1401
1402 /**
1403 * @brief Matrix-matrix multiplication: dest := a * b.
1404 *
1405 * Computes the matrix product of `a` and `b` storing the result in `dest`.
1406 * All arrays are in row-major order.
1407 */
1408 3557 void mul_real_matrix_product(const real_array *a, const real_array *b, real_array *dest)
1409 {
1410 modelica_real tmp;
1411 size_t i_size;
1412 size_t j_size;
1413 size_t k_size;
1414 size_t i;
1415 size_t j;
1416 size_t k;
1417
1418 /* Assert that dest has correct size */
1419 3557 i_size = dest->dim_size[0];
1420 3557 j_size = dest->dim_size[1];
1421 3557 k_size = a->dim_size[1];
1422
1423
2/2
✓ Branch 0 taken 10671 times.
✓ Branch 1 taken 3557 times.
14228 for (i = 0; i < i_size; ++i)
1424 {
1425
2/2
✓ Branch 0 taken 32013 times.
✓ Branch 1 taken 10671 times.
42684 for (j = 0; j < j_size; ++j)
1426 {
1427 tmp = 0;
1428
2/2
✓ Branch 0 taken 59823 times.
✓ Branch 1 taken 32013 times.
91836 for (k = 0; k < k_size; ++k)
1429 {
1430 59823 tmp += real_get(*a, (i * k_size) + k) * real_get(*b, (k * j_size) + j);
1431 }
1432 32013 real_set(dest, (i * j_size) + j, tmp);
1433 }
1434 }
1435 3557 }
1436
1437 /**
1438 * @brief Matrix-vector multiplication: dest := a * b (b is a vector).
1439 */
1440 91726 void mul_real_matrix_vector(const real_array *a, const real_array *b, real_array *dest)
1441 {
1442 size_t i;
1443 size_t j;
1444 size_t i_size;
1445 size_t j_size;
1446 modelica_real tmp;
1447
1448 /* Assert a matrix */
1449 /* Assert b vector */
1450 /* Assert dest correct size (a vector)*/
1451
1452 91726 i_size = a->dim_size[0];
1453 91726 j_size = a->dim_size[1];
1454
1455
2/2
✓ Branch 0 taken 207615 times.
✓ Branch 1 taken 91726 times.
299341 for (i = 0; i < i_size; ++i)
1456 {
1457 tmp = 0;
1458
2/2
✓ Branch 0 taken 619783 times.
✓ Branch 1 taken 207615 times.
827398 for (j = 0; j < j_size; ++j)
1459 {
1460 619783 tmp += real_get(*a, (i * j_size) + j) * real_get(*b, j);
1461 }
1462 real_set(dest, i, tmp);
1463 }
1464 91726 }
1465
1466 /**
1467 * @brief Vector-matrix multiplication: dest := a * b (a is a vector).
1468 */
1469 ✗ void mul_real_vector_matrix(const real_array *a, const real_array *b, real_array *dest)
1470 {
1471 size_t i;
1472 size_t j;
1473 size_t i_size;
1474 size_t j_size;
1475 modelica_real tmp;
1476
1477 /* Assert a vector */
1478 /* Assert b matrix */
1479 /* Assert dest vector of correct size */
1480
1481 ✗ i_size = b->dim_size[1];
1482 ✗ j_size = b->dim_size[0];
1483
1484 ✗ for (i = 0; i < i_size; ++i)
1485 {
1486 tmp = 0;
1487 ✗ for (j = 0; j < j_size; ++j)
1488 {
1489 ✗ tmp += real_get(*a, j) * real_get(*b, (j * i_size) + i);
1490 }
1491 real_set(dest, i, tmp);
1492 }
1493 ✗ }
1494
1495 /**
1496 * @brief Smart allocator for matrix/vector multiplication.
1497 *
1498 * Chooses the appropriate result shape for combinations of vector/matrix
1499 * and performs the multiplication, allocating the result.
1500 */
1501 95283 real_array mul_alloc_real_matrix_product_smart(const real_array a, const real_array b)
1502 {
1503 real_array dest;
1504
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 95283 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
95283 if ((a.ndims == 1) && (b.ndims == 2))
1505 {
1506 ✗ simple_alloc_1d_real_array(&dest, b.dim_size[1]);
1507 ✗ mul_real_vector_matrix(&a, &b, &dest);
1508 }
1509
3/4
✓ Branch 0 taken 95283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91726 times.
✓ Branch 3 taken 3557 times.
95283 else if ((a.ndims == 2) && (b.ndims == 1))
1510 {
1511 91726 simple_alloc_1d_real_array(&dest, a.dim_size[0]);
1512 91726 mul_real_matrix_vector(&a, &b, &dest);
1513 }
1514
2/4
✓ Branch 0 taken 3557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3557 times.
✗ Branch 3 not taken.
3557 else if ((a.ndims == 2) && (b.ndims == 2))
1515 {
1516 3557 simple_alloc_2d_real_array(&dest, a.dim_size[0], b.dim_size[1]);
1517 3557 mul_real_matrix_product(&a, &b, &dest);
1518 }
1519 else
1520 {
1521 ✗ omc_assert_macro(0 == "Invalid size of matrix");
1522 }
1523 95283 return dest;
1524 }
1525
1526 /**
1527 * @brief Divide every element of array `a` by scalar `b` and store in `dest`.
1528 */
1529 163879 void div_real_array_scalar(const real_array *a, modelica_real b, real_array *dest)
1530 {
1531 size_t nr_of_elements;
1532 size_t i;
1533 /* Assert that dest has correct size*/
1534 /* Do we need to check for b=0? */
1535 163879 nr_of_elements = base_array_nr_of_elements(*a);
1536
2/2
✓ Branch 0 taken 492145 times.
✓ Branch 1 taken 163879 times.
656024 for (i = 0; i < nr_of_elements; ++i)
1537 {
1538 492145 real_set(dest, i, real_get(*a, i) / b);
1539 }
1540 163879 }
1541
1542 /**
1543 * @brief Allocate and return array := a / b (scalar division).
1544 */
1545 163879 real_array div_alloc_real_array_scalar(const real_array a, const modelica_real b)
1546 {
1547 real_array dest;
1548 clone_real_array_spec(&a, &dest);
1549 163879 alloc_real_array_data(&dest);
1550 163879 div_real_array_scalar(&a, b, &dest);
1551 163879 return dest;
1552 }
1553
1554 /**
1555 * @brief Division with runtime check wrapper; uses DIVISIONNOTIME macro.
1556 */
1557 ✗ void division_real_array_scalar(threadData_t *threadData, const real_array *a, modelica_real b, real_array *dest, const char *division_str)
1558 {
1559 size_t nr_of_elements;
1560 size_t i;
1561 /* Assert that dest has correct size*/
1562 ✗ nr_of_elements = base_array_nr_of_elements(*a);
1563 ✗ for (i = 0; i < nr_of_elements; ++i)
1564 {
1565 ✗ real_set(dest, i, DIVISIONNOTIME(real_get(*a, i), b, division_str));
1566 }
1567 ✗ }
1568
1569 /**
1570 * @brief Allocate and perform division with runtime checks.
1571 */
1572 ✗ real_array division_alloc_real_array_scalar(threadData_t *threadData, const real_array a, modelica_real b, const char *division_str)
1573 {
1574 real_array dest;
1575 clone_real_array_spec(&a, &dest);
1576 ✗ alloc_real_array_data(&dest);
1577 ✗ division_real_array_scalar(threadData, &a, b, &dest, division_str);
1578 ✗ return dest;
1579 }
1580
1581 /**
1582 * @brief Allocate and perform division with the checks of DIVISION_SIM (0/0 is 0 during initialization).
1583 */
1584 17176 real_array division_alloc_real_array_scalar_sim(threadData_t *threadData, const real_array a, modelica_real b, const char *division_str, const int *equationIndexes, modelica_boolean noThrowDivZero, modelica_real time, modelica_boolean initial)
1585 {
1586 real_array dest;
1587 size_t nr_of_elements, i;
1588 clone_real_array_spec(&a, &dest);
1589 17176 alloc_real_array_data(&dest);
1590 17176 nr_of_elements = base_array_nr_of_elements(a);
1591
2/2
✓ Branch 0 taken 162156 times.
✓ Branch 1 taken 17176 times.
179332 for (i = 0; i < nr_of_elements; ++i) {
1592 162156 real_set(&dest, i, __OMC_DIV_SIM(threadData, real_get(a, i), b, division_str, equationIndexes, noThrowDivZero, time, initial));
1593
1/2
✓ Branch 0 taken 162156 times.
✗ Branch 1 not taken.
162156 if (OMC_ERROR_RAISED()) break;
1594 }
1595 17176 return dest;
1596 }
1597
1598 /**
1599 * @brief Divide scalar `a` by every element of array `b` and store in `dest`.
1600 */
1601 ✗ void div_scalar_real_array(modelica_real a, const real_array *b, real_array *dest)
1602 {
1603 size_t nr_of_elements;
1604 size_t i;
1605 /* Assert that dest has correct size*/
1606 /* Do we need to check for b=0? */
1607 ✗ nr_of_elements = base_array_nr_of_elements(*b);
1608 ✗ for (i = 0; i < nr_of_elements; ++i)
1609 {
1610 ✗ real_set(dest, i, a / real_get(*b, i));
1611 }
1612 ✗ }
1613
1614 /**
1615 * @brief Allocate and return scalar / array.
1616 */
1617 ✗ real_array div_alloc_scalar_real_array(modelica_real a, const real_array b)
1618 {
1619 real_array dest;
1620 clone_real_array_spec(&b, &dest);
1621 ✗ alloc_real_array_data(&dest);
1622 ✗ div_scalar_real_array(a, &b, &dest);
1623 ✗ return dest;
1624 }
1625
1626 /**
1627 * @brief Element-wise division of two arrays: dest := a / b.
1628 */
1629 507 void div_real_array(const real_array *a, const real_array *b, real_array *dest)
1630 {
1631 size_t nr_of_elements;
1632 size_t i;
1633 /* Assert that a,b have same sizes? */
1634 507 nr_of_elements = base_array_nr_of_elements(*a);
1635
2/2
✓ Branch 0 taken 1521 times.
✓ Branch 1 taken 507 times.
2028 for (i = 0; i < nr_of_elements; ++i)
1636 {
1637 1521 real_set(dest, i, real_get(*a, i) / real_get(*b, i));
1638 }
1639 507 }
1640
1641 /**
1642 * @brief Allocate and return element-wise division of two arrays.
1643 */
1644 507 real_array div_alloc_real_array(const real_array a, const real_array b)
1645 {
1646 real_array dest;
1647 clone_real_array_spec(&a, &dest);
1648 507 alloc_real_array_data(&dest);
1649 507 div_real_array(&a, &b, &dest);
1650 507 return dest;
1651 }
1652
1653 /**
1654 * @brief Raise each element of array `a` to the power `b` and store in `dest`.
1655 */
1656 1043 void pow_real_array_scalar(const real_array *a, modelica_real b, real_array *dest)
1657 {
1658 1043 size_t nr_of_elements = base_array_nr_of_elements(*a);
1659 size_t i;
1660
1661
1/2
✓ Branch 1 taken 1043 times.
✗ Branch 2 not taken.
1043 omc_assert_macro(nr_of_elements == base_array_nr_of_elements(*dest));
1662
1663
2/2
✓ Branch 0 taken 298006 times.
✓ Branch 1 taken 1043 times.
299049 for (i = 0; i < nr_of_elements; ++i)
1664 {
1665 298006 real_set(dest, i, pow(real_get(*a, i), b));
1666 }
1667 1043 }
1668
1669 /**
1670 * @brief Allocate and return array where each element is `a[i]^b`.
1671 */
1672 1043 real_array pow_alloc_real_array_scalar(const real_array a, const modelica_real b)
1673 {
1674 real_array dest;
1675 clone_real_array_spec(&a, &dest);
1676 1043 alloc_real_array_data(&dest);
1677 1043 pow_real_array_scalar(&a, b, &dest);
1678 1043 return dest;
1679 }
1680
1681 /**
1682 * @brief Compute integer power of a square matrix: dest := a^n.
1683 *
1684 * Supports n >= 0. The operation requires `a` (and `dest`) to be square 2D arrays.
1685 */
1686 ✗ void exp_real_array(const real_array *a, modelica_integer n, real_array *dest)
1687 {
1688 /* Assert n>=0 */
1689 ✗ omc_assert_macro(n >= 0);
1690 /* Assert that a is a two dimensional square array */
1691 ✗ omc_assert_macro((a->ndims == 2) && (a->dim_size[0] == a->dim_size[1]));
1692 /* Assert that dest is a two dimensional square array with the same size as a */
1693 ✗ omc_assert_macro((dest->ndims == 2) && (dest->dim_size[0] == dest->dim_size[1]) && (a->dim_size[0] == dest->dim_size[0]));
1694
1695 ✗ if (n == 0)
1696 {
1697 ✗ identity_real_array(a->dim_size[0], dest);
1698 }
1699 else
1700 {
1701 ✗ if (n == 1)
1702 {
1703 clone_real_array_spec(a, dest);
1704 ✗ real_array_copy_data(*a, *dest);
1705 }
1706 ✗ else if (n == 2)
1707 {
1708 clone_real_array_spec(a, dest);
1709 ✗ mul_real_matrix_product(a, a, dest);
1710 }
1711 else
1712 {
1713 modelica_integer i;
1714
1715 real_array tmp;
1716 real_array *b;
1717 real_array *c;
1718
1719 /* prepare temporary array */
1720 clone_real_array_spec(a, &tmp);
1721 clone_real_array_spec(a, dest);
1722
1723 ✗ if ((n & 1) != 0)
1724 {
1725 b = &tmp;
1726 c = dest;
1727 }
1728 else
1729 {
1730 b = dest;
1731 c = &tmp;
1732 }
1733 ✗ mul_real_matrix_product(a, a, b);
1734 ✗ for (i = 2; i < n; ++i)
1735 {
1736 real_array *x;
1737
1738 ✗ mul_real_matrix_product(a, b, c);
1739
1740 /* exchange b and c */
1741 x = b;
1742 b = c;
1743 c = x;
1744 }
1745 /* result is already in dest */
1746 }
1747 }
1748 ✗ }
1749
1750 /**
1751 * @brief Allocate and return matrix power result a^b.
1752 */
1753 ✗ real_array exp_alloc_real_array(const real_array a, modelica_integer b)
1754 {
1755 real_array dest;
1756 clone_real_array_spec(&a, &dest);
1757 ✗ alloc_real_array_data(&dest);
1758 ✗ exp_real_array(&a, b, &dest);
1759 ✗ return dest;
1760 }
1761
1762 /**
1763 * @brief Allocate and promote array by adding `n` singleton dimensions.
1764 *
1765 * Equivalent to `promote_real_array` but also allocates the destination
1766 * array data buffer.
1767 */
1768 5030 void promote_alloc_real_array(const real_array *a, int n, real_array *dest)
1769 {
1770 5030 dest->flexible = a->flexible;
1771 5030 promote_real_array(a, n, dest);
1772 5030 }
1773
1774 /**
1775 * @brief Promote an array by adding `n` trailing singleton dimensions.
1776 *
1777 * For example, promoting a vector `{1,2}` by 1 yields `{{1},{2}}`.
1778 * For example, promoting a vector `{1,2}` by 2 yields `{{{1},{2}}}`.
1779 */
1780 5030 void promote_real_array(const real_array *a, int n, real_array *dest)
1781 {
1782 int i;
1783
1784 5030 dest->dim_size = size_alloc(n + a->ndims);
1785 5030 dest->data = a->data;
1786 5030 dest->owns_data = a->owns_data;
1787
2/2
✓ Branch 0 taken 1006 times.
✓ Branch 1 taken 4024 times.
5030 if (dest->owns_data) {
1788 omc_rc_retain_inline(dest->data);
1789 }
1790 /* Assert a->ndims>=n */
1791
2/2
✓ Branch 0 taken 5030 times.
✓ Branch 1 taken 5030 times.
10060 for (i = 0; i < a->ndims; ++i)
1792 {
1793 5030 dest->dim_size[i] = a->dim_size[i];
1794 }
1795
2/2
✓ Branch 0 taken 5030 times.
✓ Branch 1 taken 5030 times.
10060 for (i = a->ndims; i < (n + a->ndims); ++i)
1796 {
1797 5030 dest->dim_size[i] = 1;
1798 }
1799
1800 5030 dest->ndims = n + a->ndims;
1801 5030 }
1802
1803 /**
1804 * @brief Promote a scalar value `s` to an `n`-dimensional array of ones.
1805 *
1806 * The resulting array has shape [1,1,...] (n times) with the single element `s`.
1807 */
1808 ✗ void promote_scalar_real_array(modelica_real s, int n, real_array *dest)
1809 {
1810 int i;
1811
1812 /* Assert that dest is of correct dimension */
1813
1814 /* Alloc size */
1815 ✗ dest->dim_size = size_alloc(n);
1816 ✗ dest->owns_data = 1;
1817
1818 /* Alloc data */
1819 ✗ dest->data = real_alloc(1);
1820
1821 ✗ dest->ndims = n;
1822 real_set(dest, 0, s);
1823
1824 ✗ for (i = 0; i < n; ++i)
1825 {
1826 ✗ dest->dim_size[i] = 1;
1827 }
1828 ✗ }
1829
1830 /**
1831 * @brief Write the dimension sizes of a real array into an integer array.
1832 *
1833 * Copies the length of each dimension from `a` into `dest->data` as
1834 * integers. `dest` must be a 1-D integer array with length equal to
1835 * `ndims(a)`.
1836 *
1837 * @param a Source real array whose sizes are read.
1838 * @param dest Destination integer array to receive the sizes (must be 1-D).
1839 * @pre `dest->ndims == 1` and `dest->dim_size[0] == a->ndims`.
1840 */
1841 ✗ void size_real_array(const real_array *a, integer_array *dest)
1842 {
1843 /* This should be an integer array dest instead */
1844 int i;
1845
1846 ✗ omc_assert_macro(dest->ndims == 1);
1847 ✗ omc_assert_macro(dest->dim_size[0] == a->ndims);
1848
1849 ✗ for (i = 0; i < a->ndims; i++)
1850 {
1851 ✗ ((modelica_integer *)dest->data)[i] = a->dim_size[i];
1852 }
1853 ✗ }
1854
1855 /**
1856 * @brief Return the single scalar value of a one-element real array.
1857 *
1858 * This function asserts that `a` contains exactly one element and
1859 * returns that element as a scalar `modelica_real`.
1860 *
1861 * @param a Source real array (must contain one element).
1862 * @return The scalar element value from `a`.
1863 */
1864 ✗ modelica_real scalar_real_array(const real_array *a)
1865 {
1866 ✗ omc_assert_macro(base_array_ok(a));
1867 ✗ omc_assert_macro(base_array_one_element_ok(a));
1868
1869 ✗ return real_get(*a, 0);
1870 }
1871
1872 /**
1873 * @brief Flatten or copy `a` into a 1-D real vector `dest`.
1874 *
1875 * Copies the elements of `a` into `dest` in row-major order. Useful when
1876 * converting a higher-dimensional array into a vector view.
1877 *
1878 * @param a Source real array to be flattened.
1879 * @param dest Destination 1-D real array (vector) to receive elements.
1880 */
1881 ✗ void vector_real_array(const real_array *a, real_array *dest)
1882 {
1883 size_t i, nr_of_elements;
1884
1885 /* Assert that a has at most one dimension with dim_size>1*/
1886
1887 ✗ nr_of_elements = base_array_nr_of_elements(*a);
1888 ✗ for (i = 0; i < nr_of_elements; ++i)
1889 {
1890 ✗ real_set(dest, i, real_get(*a, i));
1891 }
1892 ✗ }
1893
1894 /**
1895 * @brief Place a scalar into a 1-D real vector at index 0.
1896 *
1897 * Writes the scalar `a` into `dest[0]`. `dest` is expected to be a
1898 * 1-element vector.
1899 *
1900 * @param a Scalar value to write.
1901 * @param dest Destination real array (1-vector).
1902 */
1903 ✗ void vector_real_scalar(modelica_real a, real_array *dest)
1904 {
1905 /* Assert that dest is a 1-vector */
1906 real_set(dest, 0, a);
1907 ✗ }
1908
1909 /**
1910 * @brief Convert `a` to a 2-D matrix stored in `dest`.
1911 *
1912 * Sets `dest` to be a 2-D array with the first two dimensions taken from
1913 * `a`. Higher dimensions of `a` are asserted to be 1. Elements are copied
1914 * in row-major order.
1915 *
1916 * @param a Source real array.
1917 * @param dest Destination real array (2-D matrix) to receive elements.
1918 */
1919 ✗ void matrix_real_array(const real_array *a, real_array *dest)
1920 {
1921 size_t i, cnt;
1922 /* Assert that size(A,i)=1 for 2 <i<=ndims(A)*/
1923 ✗ dest->dim_size[0] = a->dim_size[0];
1924 ✗ dest->dim_size[1] = (a->ndims < 2) ? 1 : a->dim_size[1];
1925
1926 ✗ cnt = dest->dim_size[0] * dest->dim_size[1];
1927
1928 ✗ for (i = 0; i < cnt; ++i)
1929 {
1930 ✗ real_set(dest, i, real_get(*a, i));
1931 }
1932 ✗ }
1933
1934 /**
1935 * @brief Place scalar `a` into a 1x1 matrix `dest`.
1936 *
1937 * Sets `dest` to a 2-D array of size 1x1 and stores `a` as its single
1938 * element.
1939 *
1940 * @param a Scalar value to write.
1941 * @param dest Destination real array (1x1 matrix).
1942 */
1943 ✗ void matrix_real_scalar(modelica_real a, real_array *dest)
1944 {
1945 ✗ dest->ndims = 2;
1946 ✗ dest->dim_size[0] = 1;
1947 ✗ dest->dim_size[1] = 1;
1948 real_set(dest, 0, a);
1949 ✗ }
1950
1951 /**
1952 * @brief Allocate and produce the transpose of matrix `a` into `dest`.
1953 *
1954 * Allocates `dest` with the transposed shape and copies the transposed
1955 * elements. Only valid for 2-D arrays (matrices).
1956 *
1957 * @param a Source matrix to transpose (must be 2-D).
1958 * @param dest Destination real array; will be allocated to the transposed shape.
1959 * @pre `a->ndims == 2`.
1960 */
1961 6036 void transpose_alloc_real_array(const real_array *a, real_array *dest)
1962 {
1963 clone_real_array_spec(a, dest); /* allocation*/
1964
1965 /* transpose only valid for matrices.*/
1966
1967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6036 times.
6036 omc_assert_macro(a->ndims == 2);
1968 6036 dest->dim_size[0] = a->dim_size[1];
1969 6036 dest->dim_size[1] = a->dim_size[0];
1970 6036 dest->ndims = 2;
1971
1972 6036 alloc_real_array_data(dest);
1973 6036 transpose_real_array(a, dest);
1974 6036 }
1975
1976 /**
1977 * @brief Compute the transpose of matrix `a` into pre-allocated `dest`.
1978 *
1979 * If `a` is a 1-D vector it is copied into `dest`. For 2-D inputs both
1980 * `a` and `dest` must be 2-D and have matched transposed dimensions.
1981 *
1982 * @param a Source array to transpose.
1983 * @param dest Destination array (pre-allocated) to receive the transpose.
1984 */
1985 247170 void transpose_real_array(const real_array *a, real_array *dest)
1986 {
1987 size_t i;
1988 size_t j;
1989 /* size_t k;*/
1990 size_t n, m;
1991
1992
2/2
✓ Branch 0 taken 160403 times.
✓ Branch 1 taken 86767 times.
247170 if (a->ndims == 1)
1993 {
1994 160403 real_array_copy_data(*a, *dest);
1995 160403 return;
1996 }
1997
1998
2/4
✓ Branch 0 taken 86767 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 86767 times.
86767 omc_assert_macro(a->ndims == 2 && dest->ndims == 2);
1999
2000 86767 n = a->dim_size[0];
2001 86767 m = a->dim_size[1];
2002
2003
2/4
✓ Branch 0 taken 86767 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 86767 times.
86767 omc_assert_macro(dest->dim_size[0] == m && dest->dim_size[1] == n);
2004
2005
2/2
✓ Branch 0 taken 262308 times.
✓ Branch 1 taken 86767 times.
349075 for (i = 0; i < n; ++i)
2006 {
2007
2/2
✓ Branch 0 taken 782900 times.
✓ Branch 1 taken 262308 times.
1045208 for (j = 0; j < m; ++j)
2008 {
2009 782900 real_set(dest, (j * n) + i, real_get(*a, (i * m) + j));
2010 }
2011 }
2012 }
2013
2014 /**
2015 * @brief Compute the outer product of two vectors `v1` and `v2` into `dest`.
2016 *
2017 * The result is a matrix with shape `(len(v1), len(v2))` where
2018 * `dest[i,j] = v1[i] * v2[j]`.
2019 *
2020 * @param v1 Left vector operand.
2021 * @param v2 Right vector operand.
2022 * @param dest Destination matrix to receive the outer product.
2023 */
2024 ✗ void outer_product_real_array(const real_array *v1, const real_array *v2,
2025 real_array *dest)
2026 {
2027 size_t i;
2028 size_t j;
2029 size_t number_of_elements_a;
2030 size_t number_of_elements_b;
2031
2032 ✗ number_of_elements_a = base_array_nr_of_elements(*v1);
2033 ✗ number_of_elements_b = base_array_nr_of_elements(*v2);
2034
2035 /* Assert a is a vector */
2036 /* Assert b is a vector */
2037
2038 ✗ for (i = 0; i < number_of_elements_a; ++i)
2039 {
2040 ✗ for (j = 0; j < number_of_elements_b; ++j)
2041 {
2042 ✗ real_set(dest, (i * number_of_elements_b) + j,
2043 ✗ real_get(*v1, i) * real_get(*v2, j));
2044 }
2045 }
2046 ✗ }
2047
2048 ✗ void outer_product_alloc_real_array(real_array *v1, real_array *v2, real_array *dest)
2049 {
2050 size_t dim1, dim2;
2051 ✗ omc_assert_macro(base_array_ok(v1));
2052 ✗ dim1 = base_array_nr_of_elements(*v1);
2053 ✗ dim2 = base_array_nr_of_elements(*v2);
2054 ✗ alloc_real_array(dest, dim1, dim2);
2055 ✗ outer_product_real_array(v1, v2, dest);
2056 ✗ }
2057
2058 /**
2059 * @brief Allocate and compute the outer product of two vectors.
2060 *
2061 * Allocates `dest` with shape `(len(v1), len(v2))` and fills it with
2062 * the outer product of `v1` and `v2`.
2063 *
2064 * @param v1 Left vector operand.
2065 * @param v2 Right vector operand.
2066 * @param dest Destination matrix (will be allocated).
2067 */
2068
2069 ✗ void identity_real_array(int n, real_array *dest)
2070 {
2071 int i;
2072 int j;
2073
2074 ✗ omc_assert_macro(base_array_ok(dest));
2075
2076 /* Check that dest size is ok */
2077 ✗ omc_assert_macro(dest->ndims == 2);
2078 ✗ omc_assert_macro((dest->dim_size[0] == n) && (dest->dim_size[1] == n));
2079
2080 ✗ for (i = 0; i < (n * n); ++i)
2081 {
2082 ✗ real_set(dest, i, 0);
2083 }
2084 j = 0;
2085 ✗ for (i = 0; i < n; ++i)
2086 {
2087 ✗ real_set(dest, j, 1);
2088 ✗ j += n + 1;
2089 }
2090 ✗ }
2091
2092 /**
2093 * @brief Fill `dest` with the identity matrix of size `n`.
2094 *
2095 * Sets `dest` to an `n x n` matrix with ones on the diagonal and zeros
2096 * elsewhere. `dest` must be pre-allocated with the correct shape.
2097 *
2098 * @param n Size of the identity matrix.
2099 * @param dest Destination real array (n x n).
2100 */
2101
2102 2 static void diagonal_real_array_impl(const real_array *v, real_array *dest)
2103 {
2104 size_t i;
2105 size_t j;
2106 size_t n;
2107
2108 2 n = v->dim_size[0];
2109
2110
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < (n * n); ++i)
2111 {
2112 real_set(dest, i, 0);
2113 }
2114 j = 0;
2115
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (i = 0; i < n; ++i)
2116 {
2117 6 real_set(dest, j, real_get(*v, i));
2118 6 j += n + 1;
2119 }
2120 2 }
2121
2122 ✗ void diagonal_real_array(const real_array *v, real_array *dest)
2123 {
2124 size_t i;
2125 size_t j;
2126 size_t n;
2127
2128 /* Assert that v is a vector */
2129 ✗ omc_assert_macro(v->ndims == 1);
2130
2131 /* Assert that dest is a nxn matrix */
2132 ✗ n = v->dim_size[0];
2133 ✗ omc_assert_macro(dest->ndims == 2);
2134 ✗ omc_assert_macro((dest->dim_size[0] == n) && (dest->dim_size[1] == n));
2135
2136 ✗ diagonal_real_array_impl(v, dest);
2137 ✗ }
2138
2139 /**
2140 * @brief Create a diagonal matrix from vector `v` into `dest`.
2141 *
2142 * `dest` must be an `n x n` matrix where `n = len(v)`. The diagonal
2143 * entries are taken from `v` and off-diagonal entries set to zero.
2144 *
2145 * @param v Source vector.
2146 * @param dest Destination square matrix (pre-allocated).
2147 */
2148
2149 2 void diagonal_alloc_real_array(const real_array *v, real_array *dest)
2150 {
2151 size_t n;
2152
2153 /* Assert that v is a vector */
2154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 omc_assert_macro(v->ndims == 1);
2155
2156 /* Allocate a n*n matrix and fill it. */
2157 2 n = v->dim_size[0];
2158 2 alloc_real_array(dest, 2, n, n);
2159 2 diagonal_real_array_impl(v, dest);
2160 2 }
2161
2162 /**
2163 * @brief Allocate and fill a diagonal matrix from vector `v`.
2164 *
2165 * Allocates `dest` as `n x n` and fills it with the diagonal entries from
2166 * `v`.
2167 *
2168 * @param v Source vector.
2169 * @param dest Destination real array (will be allocated to n x n).
2170 */
2171
2172 ✗ void fill_real_array(real_array *dest, modelica_real s)
2173 {
2174 size_t nr_of_elements;
2175 size_t i;
2176
2177 ✗ nr_of_elements = base_array_nr_of_elements(*dest);
2178 ✗ for (i = 0; i < nr_of_elements; ++i)
2179 {
2180 real_set(dest, i, s);
2181 }
2182 ✗ }
2183
2184 /**
2185 * @brief Fill every element of `dest` with scalar `s`.
2186 *
2187 * @param dest Destination real array to be filled.
2188 * @param s Scalar value to set for every element.
2189 */
2190
2191 ✗ void linspace_real_array(modelica_real x1, modelica_real x2, int n,
2192 real_array *dest)
2193 {
2194 int i;
2195
2196 /* Assert n>=2 */
2197
2198 ✗ for (i = 0; i < (n - 1); ++i)
2199 {
2200 ✗ real_set(dest, i, x1 + (((x2 - x1) * (i - 1)) / (n - 1)));
2201 }
2202 ✗ }
2203
2204 /**
2205 * @brief Fill `dest` with `n` linearly spaced values from `x1` to `x2`.
2206 *
2207 * Writes `n` values into `dest`, forming a linearly spaced vector.
2208 *
2209 * @param x1 Start value.
2210 * @param x2 End value.
2211 * @param n Number of points (must be >= 2).
2212 * @param dest Destination real array (length `n`).
2213 */
2214
2215 /**
2216 * @brief Return the maximum element of `a`.
2217 *
2218 * Scans all elements of `a` and returns the largest value. If `a` is
2219 * empty, returns DBL_MIN.
2220 *
2221 * @param a Source real array.
2222 * @return Maximum element or DBL_MIN if empty.
2223 */
2224 170778 modelica_real max_real_array(const real_array a)
2225 {
2226 size_t nr_of_elements;
2227 modelica_real max_element = DBL_MIN;
2228
2229
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 170778 times.
170778 omc_assert_macro(base_array_ok(&a));
2230
2231 170778 nr_of_elements = base_array_nr_of_elements(a);
2232
2233
1/2
✓ Branch 0 taken 170778 times.
✗ Branch 1 not taken.
170778 if (nr_of_elements > 0)
2234 {
2235 size_t i;
2236 170778 max_element = real_get(a, 0);
2237
2/2
✓ Branch 0 taken 511050 times.
✓ Branch 1 taken 170778 times.
681828 for (i = 1; i < nr_of_elements; ++i)
2238 {
2239
2/2
✓ Branch 1 taken 185695 times.
✓ Branch 2 taken 325355 times.
511050 if (max_element < real_get(a, i))
2240 {
2241 185695 max_element = real_get(a, i);
2242 }
2243 }
2244 }
2245
2246 170778 return max_element;
2247 }
2248
2249 /**
2250 * @brief Return the minimum element of `a`.
2251 *
2252 * Scans all elements of `a` and returns the smallest value. If `a` is
2253 * empty, returns DBL_MAX.
2254 *
2255 * @param a Source real array.
2256 * @return Minimum element or DBL_MAX if empty.
2257 */
2258 91176 modelica_real min_real_array(const real_array a)
2259 {
2260 size_t nr_of_elements;
2261 modelica_real min_element = DBL_MAX;
2262
2263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 91176 times.
91176 omc_assert_macro(base_array_ok(&a));
2264
2265 91176 nr_of_elements = base_array_nr_of_elements(a);
2266
2267
1/2
✓ Branch 0 taken 91176 times.
✗ Branch 1 not taken.
91176 if (nr_of_elements > 0)
2268 {
2269 size_t i;
2270 91176 min_element = real_get(a, 0);
2271
2/2
✓ Branch 0 taken 351836 times.
✓ Branch 1 taken 91176 times.
443012 for (i = 1; i < nr_of_elements; ++i)
2272 {
2273
2/2
✓ Branch 1 taken 20159 times.
✓ Branch 2 taken 331677 times.
351836 if (min_element > real_get(a, i))
2274 {
2275 20159 min_element = real_get(a, i);
2276 }
2277 }
2278 }
2279
2280 91176 return min_element;
2281 }
2282
2283 /**
2284 * @brief Index of the first minimal element in `a`, needed for the derivative of min(a).
2285 *
2286 * @param a Source real array.
2287 * @return One-based index of the minimum, 0 if empty.
2288 */
2289 ✗ modelica_integer argmin_real_array(const real_array a)
2290 {
2291 size_t i, nr_of_elements;
2292 modelica_integer arg = 0;
2293
2294 ✗ omc_assert_macro(base_array_ok(&a));
2295
2296 ✗ nr_of_elements = base_array_nr_of_elements(a);
2297 ✗ for (i = 0; i < nr_of_elements; ++i)
2298 {
2299 ✗ if (arg == 0 || real_get(a, i) < real_get(a, arg - 1))
2300 {
2301 ✗ arg = (modelica_integer)i + 1;
2302 }
2303 }
2304 ✗ return arg;
2305 }
2306
2307 /**
2308 * @brief Index of the first maximal element in `a`, needed for the derivative of max(a).
2309 *
2310 * @param a Source real array.
2311 * @return One-based index of the maximum, 0 if empty.
2312 */
2313 ✗ modelica_integer argmax_real_array(const real_array a)
2314 {
2315 size_t i, nr_of_elements;
2316 modelica_integer arg = 0;
2317
2318 ✗ omc_assert_macro(base_array_ok(&a));
2319
2320 ✗ nr_of_elements = base_array_nr_of_elements(a);
2321 ✗ for (i = 0; i < nr_of_elements; ++i)
2322 {
2323 ✗ if (arg == 0 || real_get(a, i) > real_get(a, arg - 1))
2324 {
2325 ✗ arg = (modelica_integer)i + 1;
2326 }
2327 }
2328 ✗ return arg;
2329 }
2330
2331 /**
2332 * @brief Compute the sum of all elements in `a`.
2333 *
2334 * @param a Source real array.
2335 * @return Sum of all elements (0 for empty array).
2336 */
2337 1659411 modelica_real sum_real_array(const real_array a)
2338 {
2339 size_t i;
2340 size_t nr_of_elements;
2341 modelica_real sum = 0;
2342
2343
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1659411 times.
1659411 omc_assert_macro(base_array_ok(&a));
2344
2345 1659411 nr_of_elements = base_array_nr_of_elements(a);
2346
2347
2/2
✓ Branch 0 taken 2804139 times.
✓ Branch 1 taken 1659411 times.
4463550 for (i = 0; i < nr_of_elements; ++i)
2348 {
2349 2804139 sum += real_get(a, i);
2350 }
2351
2352 1659411 return sum;
2353 }
2354
2355 /**
2356 * @brief Compute the product of all elements in `a`.
2357 *
2358 * @param a Source real array.
2359 * @return Product of all elements (1 for empty array).
2360 */
2361 ✗ modelica_real product_real_array(const real_array a)
2362 {
2363 size_t i;
2364 size_t nr_of_elements;
2365 modelica_real product = 1;
2366
2367 ✗ omc_assert_macro(base_array_ok(&a));
2368
2369 ✗ nr_of_elements = base_array_nr_of_elements(a);
2370
2371 ✗ for (i = 0; i < nr_of_elements; ++i)
2372 {
2373 ✗ product *= real_get(a, i);
2374 }
2375
2376 ✗ return product;
2377 }
2378
2379 ✗ void symmetric_real_array(const real_array *a, real_array *dest)
2380 {
2381 size_t i;
2382 size_t j;
2383 size_t nr_of_elements;
2384
2385 ✗ nr_of_elements = base_array_nr_of_elements(*a);
2386
2387 /* Assert that a is a two dimensional square array */
2388 /* Assert that dest is a two dimensional square array */
2389 ✗ for (i = 0; i < nr_of_elements; ++i)
2390 {
2391 ✗ for (j = 0; j < i; ++j)
2392 {
2393 ✗ real_set(dest, (i * nr_of_elements) + j,
2394 ✗ real_get(*a, (j * nr_of_elements) + i));
2395 }
2396 ✗ for (; j < nr_of_elements; ++j)
2397 {
2398 ✗ real_set(dest, (i * nr_of_elements) + j,
2399 ✗ real_get(*a, (i * nr_of_elements) + j));
2400 }
2401 }
2402 ✗ }
2403
2404 /**
2405 * @brief Produce a symmetric version of square matrix `a` into `dest`.
2406 *
2407 * Copies elements so that `dest[i,j] = a[i,j]` for `j>=i` and
2408 * `dest[i,j] = a[j,i]` for `j<i`.
2409 *
2410 * @param a Source square matrix.
2411 * @param dest Destination square matrix (pre-allocated).
2412 */
2413
2414 ✗ void cross_real_array(const real_array *x, const real_array *y, real_array *dest)
2415 {
2416 /* Assert x and y are vectors */
2417 ✗ omc_assert_macro((x->ndims == 1) && (x->dim_size[0] == 3));
2418 /* Assert y is vector of size 3 */
2419 ✗ omc_assert_macro((y->ndims == 1) && (y->dim_size[0] == 3));
2420 /* Assert dest is vector of size 3 */
2421 ✗ omc_assert_macro((dest->ndims == 1) && (dest->dim_size[0] == 3));
2422
2423 ✗ real_set(dest, 0, (real_get(*x, 1) * real_get(*y, 2)) - (real_get(*x, 2) * real_get(*y, 1)));
2424 ✗ real_set(dest, 1, (real_get(*x, 2) * real_get(*y, 0)) - (real_get(*x, 0) * real_get(*y, 2)));
2425 ✗ real_set(dest, 2, (real_get(*x, 0) * real_get(*y, 1)) - (real_get(*x, 1) * real_get(*y, 0)));
2426 ✗ }
2427
2428 /**
2429 * @brief Compute the 3D cross product of vectors `x` and `y`.
2430 *
2431 * Both `x` and `y` must be length-3 vectors. The result is written into
2432 * `dest` (also a length-3 vector).
2433 *
2434 * @param x Left vector (length 3).
2435 * @param y Right vector (length 3).
2436 * @param dest Destination vector (length 3).
2437 */
2438
2439 ✗ void cross_alloc_real_array(const real_array *x, const real_array *y, real_array *dest)
2440 {
2441 ✗ alloc_real_array(dest, 1, 3);
2442 ✗ cross_real_array(x, y, dest);
2443 ✗ }
2444
2445 /**
2446 * @brief Allocate and compute the cross product of two 3-vectors.
2447 *
2448 * Allocates `dest` as a length-3 vector and computes `dest = cross(x, y)`.
2449 *
2450 * @param x Left vector (length 3).
2451 * @param y Right vector (length 3).
2452 * @param dest Destination vector (will be allocated).
2453 */
2454
2455 ✗ void skew_real_array(const real_array *x, real_array *dest)
2456 {
2457 /* Assert x vector*/
2458 /* Assert x has size 3*/
2459 /* Assert dest is 3x3*/
2460 real_set(dest, 0, 0);
2461 ✗ real_set(dest, 1, -real_get(*x, 2));
2462 ✗ real_set(dest, 2, real_get(*x, 1));
2463 ✗ real_set(dest, 3, real_get(*x, 2));
2464 real_set(dest, 4, 0);
2465 ✗ real_set(dest, 5, -real_get(*x, 0));
2466 ✗ real_set(dest, 6, -real_get(*x, 1));
2467 ✗ real_set(dest, 7, real_get(*x, 0));
2468 real_set(dest, 8, 0);
2469 ✗ }
2470
2471 /**
2472 * @brief Build the skew-symmetric matrix of a length-3 vector `x`.
2473 *
2474 * Fills `dest` (3x3) with the skew symmetric matrix such that
2475 * `skew(x)*y = cross(x,y)`.
2476 *
2477 * @param x Source length-3 vector.
2478 * @param dest Destination 3x3 matrix (pre-allocated).
2479 */
2480
2481 159917 void convert_alloc_real_array_to_f77(const real_array *a, real_array *dest)
2482 {
2483 int i;
2484 159917 clone_reverse_base_array_spec(a, dest);
2485 159917 alloc_real_array_data(dest);
2486 159917 transpose_real_array(a, dest);
2487
2/2
✓ Branch 0 taken 239626 times.
✓ Branch 1 taken 159917 times.
399543 for (i = 0; i < dest->ndims; ++i)
2488 {
2489 239626 dest->dim_size[i] = a->dim_size[i];
2490 }
2491 159917 }
2492
2493 /**
2494 * @brief Convert `a` to Fortran (column-major) layout into an allocated `dest`.
2495 *
2496 * Allocates `dest` with reversed base-array spec, transposes the data and
2497 * adjusts dimension sizes so that the result is suitable for Fortran-style
2498 * libraries expecting column-major order.
2499 *
2500 * @param a Source array in C row-major layout.
2501 * @param dest Destination array that will be allocated in F77 layout.
2502 */
2503
2504 81217 void convert_alloc_real_array_from_f77(const real_array *a, real_array *dest)
2505 {
2506 int i;
2507 81217 clone_reverse_base_array_spec(a, dest);
2508 81217 alloc_real_array_data(dest);
2509
2/2
✓ Branch 0 taken 82239 times.
✓ Branch 1 taken 81217 times.
163456 for (i = 0; i < dest->ndims; ++i)
2510 {
2511 82239 int tmp = dest->dim_size[i];
2512 82239 dest->dim_size[i] = a->dim_size[i];
2513 82239 a->dim_size[i] = tmp;
2514 }
2515 81217 transpose_real_array(a, dest);
2516 81217 }
2517
2518 /**
2519 * @brief Convert from Fortran (column-major) layout into an allocated C array.
2520 *
2521 * Allocates `dest` and transposes the Fortran-ordered data into C row-major
2522 * layout.
2523 *
2524 * @param a Source array in F77 layout.
2525 * @param dest Destination array that will be allocated in C layout.
2526 */
2527
2528 5030 void cast_integer_array_to_real(const integer_array *a, real_array *dest)
2529 {
2530 5030 int els = base_array_nr_of_elements(*a);
2531 int i;
2532 5030 clone_base_array_spec(a, dest);
2533 5030 alloc_real_array_data(dest);
2534
2/2
✓ Branch 0 taken 18156 times.
✓ Branch 1 taken 5030 times.
23186 for (i = 0; i < els; i++)
2535 {
2536 18156 real_set(dest, i, (modelica_real)integer_get(*a, i));
2537 }
2538 5030 }
2539
2540 /**
2541 * @brief Cast an integer array to a real array element-wise.
2542 *
2543 * Allocates `dest` data and converts each integer element to `modelica_real`.
2544 *
2545 * @param a Source integer array.
2546 * @param dest Destination real array (shape cloned from `a`).
2547 */
2548
2549 ✗ void cast_real_array_to_integer(const real_array *a, integer_array *dest)
2550 {
2551 ✗ int els = base_array_nr_of_elements(*a);
2552 int i;
2553 ✗ clone_base_array_spec(a, dest);
2554 ✗ alloc_integer_array_data(dest);
2555 ✗ for (i = 0; i < els; i++)
2556 {
2557 ✗ put_integer_element((modelica_integer)real_get(*a, i), i, dest);
2558 }
2559 ✗ }
2560
2561 /**
2562 * @brief Cast a real array to an integer array element-wise.
2563 *
2564 * Allocates `dest` data and converts each real element to `modelica_integer`.
2565 *
2566 * @param a Source real array.
2567 * @param dest Destination integer array (shape cloned from `a`).
2568 */
2569
2570 /* Fills an array with a value. */
2571 75431 void fill_alloc_real_array(real_array *dest, modelica_real value, int ndims, ...)
2572 {
2573 size_t i;
2574 size_t elements = 0;
2575 va_list ap;
2576 75431 va_start(ap, ndims);
2577 75431 elements = alloc_base_array(dest, ndims, ap);
2578 75431 va_end(ap);
2579 75431 dest->data = real_alloc(elements);
2580
2581
2/2
✓ Branch 0 taken 82064 times.
✓ Branch 1 taken 75431 times.
157495 for (i = 0; i < elements; ++i)
2582 {
2583 real_set(dest, i, value);
2584 }
2585 75431 }
2586
2587 /**
2588 * @brief Allocate an array with given dimensions and fill it with `value`.
2589 *
2590 * The function takes a variable argument list of dimension sizes after
2591 * `ndims`, allocates `dest` and fills every element with `value`.
2592 *
2593 * @param dest Destination real array (will be allocated).
2594 * @param value Value to fill the array with.
2595 * @param ndims Number of dimensions to allocate, followed by their sizes.
2596 */
2597
2598 ✗ void identity_alloc_real_array(int n, real_array *dest)
2599 {
2600 ✗ alloc_real_array(dest, 2, n, n);
2601 ✗ identity_real_array(n, dest);
2602 ✗ }
2603
2604 /**
2605 * @brief Create a 1-D real array from a range `start:step:stop`.
2606 *
2607 * Example: `1.0:2.0:6.0` => `{1.0, 3.0, 5.0}`. The function computes the
2608 * number of elements and allocates a 1-D array containing the arithmetic
2609 * progression.
2610 *
2611 * @param dest Destination 1-D real array (will be allocated).
2612 * @param start Range start value.
2613 * @param step Range step value (must be non-zero).
2614 * @param stop Range end value.
2615 * @pre `step != 0`.
2616 */
2617 46399 void create_real_array_from_range(real_array *dest, modelica_real start, modelica_real step, modelica_real stop)
2618 {
2619 size_t elements;
2620 size_t i;
2621 modelica_real (*comp_func)(modelica_real, modelica_real);
2622
2623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46399 times.
46399 omc_assert_macro(step != 0);
2624
2625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46399 times.
46399 comp_func = (step > 0) ? &real_le : &real_ge;
2626
1/2
✓ Branch 1 taken 46399 times.
✗ Branch 2 not taken.
46399 elements = comp_func(start, stop) ? (((stop - start) / step) + 1) : 0;
2627 /* fprintf(stderr, "start %g step %g stop %g elements %d\n", start, step, stop, elements); */
2628
2629 46399 simple_alloc_1d_real_array(dest, elements);
2630
2631
2/2
✓ Branch 0 taken 4129511 times.
✓ Branch 1 taken 46399 times.
4175910 for (i = 0; i < elements; start += step, ++i)
2632 {
2633 real_set(dest, i, start);
2634 }
2635 46399 }
2636
2637 /**
2638 * @brief Resize a start attribute array to n elements, repeating its values.
2639 *
2640 * The start attribute of an array variable can hold a single broadcast value
2641 * or the values of an inner dimension only. Writing the start values of the
2642 * whole array needs one element per array element. If the array has more than
2643 * n elements, the first n are kept. Nothing is reallocated if the array
2644 * already has n elements.
2645 */
2646 8 void real_array_ensure_size(real_array *a, int n)
2647 {
2648 8 int m = (int) base_array_nr_of_elements(*a);
2649 real_array tmp;
2650 int i;
2651
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 if (m == n) {
2652 5 return;
2653 }
2654 3 simple_alloc_1d_real_array(&tmp, n);
2655
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 3 times.
22 for (i = 0; i < n; ++i) {
2656
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 ((modelica_real*) tmp.data)[i] = m > 0 ? ((modelica_real*) a->data)[i % m] : 0.0;
2657 }
2658 3 omc_array_release(a);
2659 3 *a = tmp;
2660 }
2661