Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 143
Functions: 0.0% 0 / 0 / 15
Branches: 0.0% 0 / 0 / 54

OMCompiler/SimulationRuntime/c/simulation/solver/nonlinearValuesList.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 nonlinearValuesList.h
29 * Description: This is a C implementation of a value database
30 * based on a list. It's purpose is to be used by a
31 * a non-linear solver in OpenModelica in order to
32 * guess next value by extrapolation or interpolation.
33 * Assuming time passes forward.
34 *
35 */
36
37 #include "epsilon.h"
38 #include "nonlinearValuesList.h"
39
40 #include "../../util/list.h"
41 #include "../../util/omc_error.h"
42
43 #include <stdlib.h>
44 #include <string.h>
45
46 #define UNUSED(x) (void)(x)
47
48 /* Forward extrapolate function definition */
49 double extrapolateValues(const double, const double, const double, const double, const double);
50 void* valueListAlloc(const void* data);
51 void valueListFree(void* data);
52 void valueListCopy(void* dest, const void* src);
53
54 /**
55 * @brief Allocate value lists.
56 *
57 * @param numberOfList Number of lists to allocate.
58 * @param valueSize Length of array double* values
59 * @return VALUES_LIST* Array of value lists.
60 */
61 ✗ VALUES_LIST* allocValueList(unsigned int numberOfList, unsigned int valueSize)
62 {
63 unsigned int i = 0;
64 ✗ VALUES_LIST* valueList = (VALUES_LIST*) malloc(numberOfList*sizeof(VALUES_LIST));
65
66 ✗ for(i=0; i<numberOfList; i++) {
67 ✗ valueList[i].valueList = allocList(valueListAlloc, valueListFree, valueListCopy);
68 }
69
70 ✗ return valueList;
71 }
72
73 /**
74 * @brief Free array of value lists.
75 *
76 * @param valueList Array of value lists.
77 * @param numberOfList Length of array valueList.
78 */
79 ✗ void freeValueList(VALUES_LIST* valueList, unsigned int numberOfList)
80 {
81 unsigned int i = 0;
82
83 ✗ for(i=0; i<numberOfList; i++) {
84 ✗ freeList(valueList[i].valueList);
85 }
86 ✗ free(valueList);
87 ✗ }
88
89 /**
90 * @brief Removes all nodes after startNode from valueList.
91 * If startNode = NULL then clear the whole list.
92 *
93 * @param valueList Pointer to value list
94 * @param startNode Pointer to list node, following nodes will be deleted
95 */
96 ✗ void cleanValueList(LIST* valueList, LIST_NODE *startNode)
97 {
98 int len;
99 ✗ if(startNode)
100 {
101 ✗ listClearAfterNode(valueList, startNode);
102 }
103 ✗ else listClear(valueList);
104 ✗ }
105
106 /**
107 * @brief Removes all nodes except the one just before or at time.
108 *
109 * @param valueList Pointer to value list
110 * @param time time
111 */
112 ✗ void cleanValueListbyTime(LIST *valueList, double time)
113 {
114 LIST_NODE *next, *it;
115 VALUE* elem;
116
117 ✗ printValuesListTimes(valueList);
118 // need to get first node at each iteration since head is removed
119 ✗ for(it = listFirstNode(valueList); it; it = listFirstNode(valueList))
120 {
121 assert(it != NULL);
122 ✗ elem = (VALUE*)listNodeData(it);
123 ✗ if (elem->time <= time)
124 {
125 ✗ cleanValueList(valueList, it);
126 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "New list length %d: ", listLen(valueList));
127 ✗ printValuesListTimes(valueList);
128 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Done!");
129 ✗ break;
130 }
131 /* debug output */
132 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "cleanValueListbyTime %g check element: ", time);
133 ✗ printValueElement(elem);
134
135 ✗ listRemoveFront(valueList);
136 }
137 ✗ }
138
139 /**
140 * @brief Create new value element for value list.
141 *
142 * @param size Length of values array.
143 * @param time Time
144 * @param values Array of values
145 */
146 ✗ VALUE* createValueElement(unsigned int size, double time, double* values)
147 {
148 ✗ VALUE* elem = calloc(1, sizeof(VALUE));
149 ✗ elem->values = calloc(size, sizeof(double));
150 ✗ elem->time = time;
151 ✗ elem->size = size;
152
153 ✗ memcpy(elem->values, values, size*sizeof(double));
154
155 /* debug output */
156 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Create Element");
157
158 ✗ return elem;
159 }
160
161 /**
162 * @brief Free value element allocated with createValueElement
163 *
164 * @param elem Value element to free.
165 */
166 ✗ void freeValue(VALUE* elem)
167 {
168 ✗ free(elem->values);
169 ✗ free(elem);
170 ✗ }
171
172 /**
173 * @brief Adds copy of new element to list.
174 *
175 * @param valuesList List
176 * @param newElem New element to add to list.
177 */
178 ✗ void addListElement(LIST* valuesList, VALUE* newElem)
179 {
180 LIST_NODE *node, *next;
181 VALUE* elem;
182 int replace = 0, i = 0;
183
184 /* debug output */
185 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 1, "Adding element in a list of size %d", listLen(valuesList));
186 ✗ printValueElement(newElem);
187
188 /* if it's empty, just push it in */
189 ✗ if (listLen(valuesList) == 0)
190 {
191 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "List is empty add new element.");
192 ✗ listPushFront(valuesList, (void*) newElem);
193
194 ✗ messageClose(OMC_LOG_NLS_EXTRAPOLATE);
195 ✗ return;
196 }
197
198 /* if the element at begin is earlier than current
199 * push the element just in front and if the end element
200 * is later than current push it just back.*/
201 ✗ node = listFirstNode(valuesList);
202 ✗ if ( fabs( ((VALUE*)listNodeData(node))->time - newElem->time ) > MINIMAL_STEP_SIZE )
203 {
204 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "First Value list element is:");
205 ✗ printValueElement(((VALUE*)listNodeData(node)));
206 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "so new element is added before.");
207 ✗ listPushFront(valuesList, (void*) newElem);
208
209 ✗ messageClose(OMC_LOG_NLS_EXTRAPOLATE);
210 ✗ return;
211 }
212
213 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Search position of new element");
214 /* search correct position */
215 next = node;
216 do
217 {
218 /* if next node is empty */
219 ✗ if (!next)
220 {
221 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Search finished last element reached");
222 break;
223 }
224
225 ✗ elem = ((VALUE*)listNodeData(next));
226
227 /* debug output */
228 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Next node of list is element:");
229 ✗ printValueElement(elem);
230
231
232 ✗ if (fabs(elem->time - newElem->time)<=MINIMAL_STEP_SIZE)
233 {
234 replace = 1;
235 break;
236 }
237 ✗ else if (elem->time < newElem->time)
238 {
239 break;
240 }
241 node = next;
242 ✗ next = listNextNode(node);
243 ✗ i++; /* count insert or replace place */
244 }while(1);
245
246 /* add element before currect node */
247 ✗ if (!replace){
248 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Insert element before last output element.");
249 ✗ listInsert(valuesList, node, (void*) newElem);
250 }
251 else
252 {
253 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "replace element.");
254 ✗ updateNodeData(valuesList, next, (void*) newElem);
255 }
256 /* clean list if too full */
257 ✗ if (i < 3 && listLen(valuesList)>10)
258 {
259 ✗ while(i < 4)
260 {
261 ✗ next = listNextNode(next);
262 ✗ i++;
263 }
264 ✗ cleanValueList(valuesList, next);
265 }
266
267 ✗ messageClose(OMC_LOG_NLS_EXTRAPOLATE);
268 ✗ return;
269 }
270
271 /**
272 * @brief Gets extrapolated values for time from value list.
273 *
274 * @param valuesList Pointer to value list
275 * @param time time
276 * @param extrapolatedValues values extrapolated (overwritten)
277 * @param oldOutput old values just before time
278 */
279 ✗ void getValues(LIST* valuesList, double time, double* extrapolatedValues, double* oldOutput)
280 {
281 LIST_NODE *it;
282 LIST_NODE *old = NULL;
283 LIST_NODE *old2 = NULL;
284 VALUE *oldValues, *old2Values, *elem;
285
286 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 1, "Get values for time %g in a list of size %d", time, listLen(valuesList));
287
288 /* find corresponding values */
289 ✗ for(it = listFirstNode(valuesList); it; it = listNextNode(it))
290 {
291 ✗ elem = (VALUE*)listNodeData(it);
292 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Searching current element:");
293 ✗ printValueElement(elem);
294
295 old = it;
296 ✗ if(fabs(elem->time - time) <= MINIMAL_STEP_SIZE)
297 {
298 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "take element with the same time.");
299 ✗ break;
300 }
301 ✗ else if(elem->time < time)
302 {
303 ✗ old2 = listNextNode(old);
304 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "found element to use for extrapolation.");
305 ✗ break;
306 }
307 }
308
309 /* if the list is empty old never gets set */
310 ✗ assertStreamPrint(NULL, NULL != old, "getValues failed, no elements!");
311
312 ✗ if(it == NULL)
313 {
314 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "reached end of list.");
315 }
316
317 /* get next values */
318 ✗ if (old2 == NULL)
319 {
320 ✗ oldValues = (VALUE*) listNodeData(old);
321 ✗ memcpy(extrapolatedValues, oldValues->values, oldValues->size*sizeof(double));
322 ✗ memcpy(oldOutput, oldValues->values, oldValues->size*sizeof(double));
323 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "take just old values.");
324 }
325 else
326 {
327 int i;
328 ✗ oldValues = (VALUE*) listNodeData(old);
329 ✗ old2Values = (VALUE*) listNodeData(old2);
330 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, "Use following elements for calculation:");
331 ✗ printValueElement(oldValues);
332 ✗ printValueElement(old2Values);
333 ✗ for(i = 0; i < oldValues->size; ++i)
334 {
335 ✗ extrapolatedValues[i] = extrapolateValues(time, oldValues->values[i], oldValues->time, old2Values->values[i], old2Values->time);
336 }
337 ✗ memcpy(oldOutput, oldValues->values, oldValues->size*sizeof(double));
338 }
339 ✗ messageClose(OMC_LOG_NLS_EXTRAPOLATE);
340 ✗ return;
341 }
342
343 ✗ void printValueElement(VALUE* elem)
344 {
345 /* debug output */
346 ✗ if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_EXTRAPOLATE))
347 {
348 int i;
349 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 1, "Element(size %d) at time %g ", elem->size, elem->time);
350 ✗ for(i = 0; i < elem->size; i++) {
351 ✗ infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 0, " oldValues[%d] = %g",i, elem->values[i]);
352 }
353 ✗ messageClose(OMC_LOG_NLS_EXTRAPOLATE);
354 }
355 ✗ }
356
357 /**
358 * @brief Print function for printValuesListTimes
359 *
360 * @param data Data of node of type VALUE*
361 * @param stream Stream to output to.
362 * @param unused Unused
363 */
364 ✗ static void printElemTimes(void* data, int stream, void* unused) {
365 UNUSED(unused);
366 VALUE* elem = (VALUE*) data;
367
368 unsigned int i;
369 ✗ for(i=0; i<elem->size; i++) {
370 ✗ infoStreamPrint(stream, 0, "Element %d at time %g", i, elem->time);
371 }
372 ✗ }
373
374 /**
375 * @brief Print value times of value list.
376 *
377 * @param list Value list.
378 */
379 ✗ void printValuesListTimes(LIST* list) {
380 ✗ printList(list, OMC_LOG_NLS_EXTRAPOLATE, printElemTimes);
381 ✗ }
382
383 /*! \fn extraPolateValues
384 * This function extrapolates linear values based on old values.
385 *
386 * \param [in] [time] desired time for extrapolation
387 * \param [in] [old1] old value at time1
388 * \param [in] [time1] time for the first value
389 * \param [in] [old2] old value at time2
390 * \param [in] [time2] time for the second value
391 */
392 ✗ double extrapolateValues(const double time, const double old1, const double time1, const double old2, const double time2)
393 {
394 double retValue;
395
396 ✗ if (time1 == time2 || old1 == old2)
397 {
398 retValue = old1;
399 }
400 else
401 {
402 ✗ retValue = old2 + ((time - time2)/(time1 - time2)) * (old1-old2);
403 }
404
405 ✗ return retValue;
406 }
407
408 /**
409 * @brief Allocate memory for valueList elements.
410 *
411 * @param data value list element, containing size of array values
412 * Has to be of type VALUE*;
413 * @return void* Allocated memory for LIST_NODE data.
414 */
415 ✗ void* valueListAlloc(const void* data) {
416 const VALUE* valueElem = (VALUE*) data;
417 ✗ VALUE* newElem = malloc(sizeof(VALUE));
418 ✗ assertStreamPrint(NULL, newElem != NULL, "valueListAlloc: Out of memory");
419 ✗ newElem->values = malloc(valueElem->size*sizeof(double));
420 ✗ assertStreamPrint(NULL, newElem->values != NULL, "valueListAlloc: Out of memory");
421 ✗ return (void*) newElem;
422 }
423
424 /**
425 * @brief Free memory allocated with valueListAlloc.
426 *
427 * @param data Void pointer, representing index for new list element.
428 */
429 ✗ void valueListFree(void* data) {
430 VALUE* valueElem = (VALUE*) data;
431 ✗ free(valueElem->values);
432 ✗ free(valueElem);
433 ✗ }
434
435 /**
436 * @brief Copy data of valueList elements.
437 *
438 * @param dest Void pointer of destination data, representing VALUE.
439 * @param src Void pointer of source data, representing VALUE.
440 */
441 ✗ void valueListCopy(void* dest, const void* src) {
442 VALUE* destValue = (VALUE*) dest;
443 VALUE* srcValue = (VALUE*) src;
444 ✗ destValue->size = srcValue->size;
445 ✗ destValue->time = srcValue->time;
446 ✗ memcpy(destValue->values, srcValue->values, srcValue->size*sizeof(double));
447 ✗ }
448