Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 10.0% 13 / 0 / 130
Functions: 44.4% 4 / 0 / 9
Branches: 6.2% 4 / 0 / 64

OMCompiler/SimulationRuntime/c/simulation/solver/stateset.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 #if !defined(OMC_NO_STATESELECTION)
29
30 #include "stateset.h"
31 #include "../../util/omc_error.h"
32 #include "../jacobian_util.h"
33
34 #include <string.h>
35
36 /*! \fn printStateSelectionInfo
37 *
38 * function prints actually information about current state selection
39 *
40 * \param [in] [data]
41 * \param [in] [set]
42 *
43 * \author wbraun
44 */
45 ✗ void printStateSelectionInfo(DATA *data, STATE_SET_DATA *set)
46 {
47 long k, l;
48
49 ✗ infoStreamPrint(OMC_LOG_DSS, 0, "Select " OMC_INT_FORMAT " state%s from " OMC_INT_FORMAT " candidates.", set->nStates, set->nStates == 1 ? "" : "s", set->nCandidates);
50 ✗ infoStreamPrint(OMC_LOG_DSS, 1, "State candidates:");
51 ✗ for(k=0; k < set->nCandidates; k++)
52 {
53 ✗ infoStreamPrint(OMC_LOG_DSS, 0, "[%ld] %s", k+1, set->statescandidates[k]->name);
54 }
55 ✗ messageClose(OMC_LOG_DSS);
56
57 ✗ infoStreamPrint(OMC_LOG_DSS, 1, "Selected state%s", set->nStates == 1 ? "" : "s");
58 {
59 ✗ unsigned int aid = set->A->id - data->modelData->integerVarsData[0].info.id;
60 ✗ modelica_integer *Adump = &(data->localData[0]->integerVars[aid]);
61 ✗ for(k=0; k < set->nStates; k++)
62 {
63 ✗ for(l=0; l < set->nCandidates; l++)
64 {
65 ✗ if (Adump[k*set->nCandidates+l] == 1)
66 {
67 ✗ infoStreamPrint(OMC_LOG_DSS, 0, "[%ld] %s", l+1, set->statescandidates[l]->name);
68 ✗ break;
69 }
70 }
71 }
72 }
73 ✗ messageClose(OMC_LOG_DSS);
74 ✗ }
75
76 /*! \fn initializeStateSetJacobians
77 *
78 * initialize jacobians for state selection
79 *
80 * \param [ref] [data] ???
81 *
82 * \author ???
83 */
84 1 void initializeStateSetJacobians(DATA *data, threadData_t *threadData)
85 {
86 long i = 0;
87 STATE_SET_DATA *set = NULL;
88 JACOBIAN* jacobian;
89
90 /* go troug all state sets*/
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nStateSets; i++)
92 {
93 ✗ set = &(data->simulationInfo->stateSetData[i]);
94 ✗ jacobian = &(data->simulationInfo->analyticJacobians[set->jacobianIndex]);
95
96 ✗ if(set->initialAnalyticalJacobian(data, threadData, jacobian))
97 {
98 ✗ throwStreamPrint(threadData, "can not initialze Jacobians for dynamic state selection");
99 }
100 }
101 1 initializeStateSetPivoting(data);
102 1 }
103
104 /*! \fn initializeStateSetPivoting
105 *
106 * initialize pivoting data for state selection
107 *
108 * \param [ref] [data] ???
109 *
110 * \author ???
111 */
112 1 void initializeStateSetPivoting(DATA *data)
113 {
114 long i = 0;
115 long n = 0;
116 STATE_SET_DATA *set = NULL;
117 unsigned int aid = 0;
118 modelica_integer *A = NULL;
119
120 /* go trough all state sets */
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nStateSets; i++)
122 {
123 ✗ set = &(data->simulationInfo->stateSetData[i]);
124 ✗ aid = set->A->id - data->modelData->integerVarsData[0].info.id;
125 ✗ A = &(data->localData[0]->integerVars[aid]);
126
127 ✗ memset(A, 0, set->nCandidates*set->nStates*sizeof(modelica_integer));
128
129 /* initialize row and col indices */
130 ✗ for(n=0; n<set->nDummyStates; n++)
131 ✗ set->rowPivot[n] = n;
132
133 ✗ for(n=0; n<set->nCandidates; n++)
134 ✗ set->colPivot[n] = set->nCandidates-n-1;
135
136 ✗ for(n=0; n<set->nStates; n++)
137 ✗ A[n*set->nCandidates + n] = 1; /* set A[row, col] */
138 }
139 1 }
140
141 /*! \fn freeStateSetData
142 *
143 * free jacobians for state selection
144 *
145 * \param [ref] [data] ???
146 *
147 * \author ???
148 */
149 1 void freeStateSetData(DATA *data)
150 {
151 long i=0;
152
153 /* go through all state sets */
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nStateSets; i++)
155 {
156 ✗ STATE_SET_DATA *set = &(data->simulationInfo->stateSetData[i]);
157 ✗ free(set->states);
158 ✗ free(set->statescandidates);
159 ✗ free(set->rowPivot);
160 ✗ free(set->colPivot);
161 ✗ free(set->J);
162 }
163 1 }
164
165 /*! \fn getAnalyticalJacobianSet
166 *
167 * function calculates analytical jacobian
168 *
169 * \param [ref] [data] ???
170 * \param [out] [index] ???
171 *
172 * \author wbraun
173 */
174 ✗ static void getAnalyticalJacobianSet(DATA* data, threadData_t *threadData, unsigned int index)
175 {
176 unsigned int i, j, k, l, ii;
177 ✗ const unsigned int jacIndex = data->simulationInfo->stateSetData[index].jacobianIndex;
178 ✗ JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[jacIndex]);
179 const SPARSE_PATTERN* sp = jacobian->sparsePattern;
180
181 ✗ modelica_real* jac = data->simulationInfo->stateSetData[index].J;
182
183 /* call generic dense Jacobian */
184 ✗ evalJacobian(data, threadData, jacobian, NULL, jac, TRUE);
185
186 ✗ if(OMC_ACTIVE_STREAM(OMC_LOG_DSS_JAC))
187 {
188 ✗ char *buffer = (char*)malloc(sizeof(char)*jacobian->sizeCols*20);
189
190 ✗ infoStreamPrint(OMC_LOG_DSS_JAC, 1, "jacobian %zux%zu [id: %d]", jacobian->sizeRows, jacobian->sizeCols, jacIndex);
191
192 ✗ for(i=0; i<jacobian->sizeRows; i++)
193 {
194 char *p = buffer;
195 ✗ for(j=0; j < jacobian->sizeCols; j++)
196 ✗ p += sprintf(p, "%.5e ", jac[i*jacobian->sizeCols+j]);
197 ✗ infoStreamPrint(OMC_LOG_DSS_JAC, 0, "%s", buffer);
198 }
199 ✗ messageClose(OMC_LOG_DSS_JAC);
200 ✗ free(buffer);
201 }
202 ✗ }
203
204 /*! \fn setAMatrix
205 *
206 * ??? desc ???
207 *
208 * \param [ref] [newEnable]
209 * \param [ref] [nCandidates]
210 * \param [ref] [nStates]
211 * \param [ref] [Ainfo]
212 * \param [ref] [states]
213 * \param [ref] [statecandidates]
214 * \param [ref] [data]
215 */
216 ✗ static void setAMatrix(modelica_integer* newEnable, modelica_integer nCandidates, modelica_integer nStates, VAR_INFO* Ainfo, VAR_INFO** states, VAR_INFO** statecandidates, DATA *data)
217 {
218 modelica_integer col;
219 modelica_integer row=0;
220 /* clear old values */
221 ✗ unsigned int aid = Ainfo->id - data->modelData->integerVarsData[0].info.id;
222 ✗ modelica_integer *A = &(data->localData[0]->integerVars[aid]);
223 ✗ memset(A, 0, nCandidates*nStates*sizeof(modelica_integer));
224
225 ✗ for(col=0; col<nCandidates; col++)
226 {
227 ✗ if(newEnable[col]==2)
228 {
229 ✗ unsigned int firstrealid = data->modelData->realVarsData[0].info.id;
230 ✗ unsigned int id = statecandidates[col]->id-firstrealid;
231 ✗ unsigned int sid = states[row]->id-firstrealid;
232 /* set A[row, col] */
233 ✗ A[row*nCandidates + col] = 1;
234 /* reinit state */
235 ✗ data->localData[0]->realVars[sid] = data->localData[0]->realVars[id];
236 ✗ row++;
237 }
238 }
239 ✗ }
240
241 /*! \fn comparePivot
242 *
243 * ??? desc ???
244 *
245 * \param [ref] [oldPivot]
246 * \param [ref] [set]
247 * \param [ref] [setIndex]
248 * \param [ref] [data]
249 * \param [ref] [switchStates]
250 * \return ???
251 */
252 ✗ static int comparePivot(modelica_integer *oldPivot, STATE_SET_DATA *set, long setIndex, DATA *data, int switchStates)
253 {
254 modelica_integer i;
255 int ret = 0;
256 ✗ modelica_integer *newPivot = set->colPivot;
257 ✗ modelica_integer nCandidates = set->nCandidates;
258 ✗ modelica_integer nDummyStates = set->nDummyStates;
259 ✗ modelica_integer nStates = set->nStates;
260 ✗ VAR_INFO* A = set->A;
261 ✗ VAR_INFO** states = set->states;
262 ✗ VAR_INFO** statecandidates = set->statescandidates;
263 ✗ modelica_integer* oldEnable = (modelica_integer*) calloc(nCandidates, sizeof(modelica_integer));
264 ✗ modelica_integer* newEnable = (modelica_integer*) calloc(nCandidates, sizeof(modelica_integer));
265
266 ✗ for(i=0; i<nCandidates; i++)
267 {
268 ✗ modelica_integer entry = (i < nDummyStates) ? 1: 2;
269 ✗ newEnable[ newPivot[i] ] = entry;
270 ✗ oldEnable[ oldPivot[i] ] = entry;
271 }
272
273 ✗ for(i=0; i<nCandidates; i++)
274 {
275 ✗ if(newEnable[i] != oldEnable[i])
276 {
277 ✗ if(switchStates)
278 {
279 ✗ setAMatrix(newEnable, nCandidates, nStates, A, states, statecandidates, data);
280 /* debug */
281 ✗ if(OMC_ACTIVE_STREAM(OMC_LOG_DSS)){
282 ✗ infoStreamPrint(OMC_LOG_DSS, 1, "StateSelection Set %ld at time = %f", setIndex, data->localData[0]->timeValue);
283 ✗ printStateSelectionInfo(data, set);
284 ✗ messageClose(OMC_LOG_DSS);
285 }
286 }
287 ret = -1;
288 break;
289 }
290 }
291
292 ✗ free(oldEnable);
293 ✗ free(newEnable);
294
295 ✗ return ret;
296 }
297
298 /*! \fn stateSelectionSet
299 *
300 * function to select the actual states for an individual stateSet
301 *
302 * \param [ref] [data]
303 * \param [ref] [threadData]
304 * \param [in] [reportError]
305 * \param [in] [switchStates] flag for switch states, function does switch only if this switchStates = 1
306 * \param [in] [setIndex] unique index of the stateSet
307 * \param [in] [globalres] flag for discontinuous timestep in the case of a state switch for all sets before
308 * \return [globalres] flag for discontinuous timestep in the case of a state switch for at least one set
309 *
310 * \author Abdelhak / Frenkel TUD
311 */
312 ✗ int stateSelectionSet(DATA *data, threadData_t *threadData, char reportError, int switchStates, long setIndex, int globalres)
313 {
314 long j=0;
315 long k=0;
316 long l=0;
317 long m=0;
318 int res=0;
319 ✗ STATE_SET_DATA *set = &(data->simulationInfo->stateSetData[setIndex]);
320 ✗ modelica_integer* oldColPivot = (modelica_integer*) malloc(set->nCandidates * sizeof(modelica_integer));
321 ✗ modelica_integer* oldRowPivot = (modelica_integer*) malloc(set->nDummyStates * sizeof(modelica_integer));
322
323 /* generate jacobian, stored in set->J */
324 ✗ getAnalyticalJacobianSet(data, threadData, setIndex);
325
326 /* call pivoting function to select the states */
327 ✗ memcpy(oldColPivot, set->colPivot, set->nCandidates*sizeof(modelica_integer));
328 ✗ memcpy(oldRowPivot, set->rowPivot, set->nDummyStates*sizeof(modelica_integer));
329 ✗ if((pivot(set->J, set->nDummyStates, set->nCandidates, set->rowPivot, set->colPivot) != 0) && reportError)
330 {
331 /* error, report the matrix and the time */
332
333 ✗ char *buffer = (char*)malloc(sizeof(char)*data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeCols*100+5);
334 ✗ warningStreamPrint(OMC_LOG_DSS, 1, "jacobian %zux%zu [id: " OMC_INT_FORMAT "]", data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeRows, data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeCols, set->jacobianIndex);
335
336 ✗ for(m=0; m < data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeRows; m++)
337 {
338 char *p = buffer;
339 ✗ for(j=0; j < data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeCols; j++)
340 ✗ p += sprintf(p, "%.5e ", set->J[m*data->simulationInfo->analyticJacobians[set->jacobianIndex].sizeCols+j]);
341 ✗ warningStreamPrint(OMC_LOG_DSS, 0, "%s", buffer);
342 }
343
344 ✗ free(buffer);
345
346 ✗ for(m=0; m<set->nCandidates; m++)
347 ✗ warningStreamPrint(OMC_LOG_DSS, 0, "%s", set->statescandidates[m]->name);
348 ✗ messageCloseWarning(OMC_LOG_DSS);
349
350 ✗ throwStreamPrint(threadData, "Error, singular Jacobian for dynamic state selection at time %f\nUse -lv LOG_DSS_JAC to get the Jacobian", data->localData[0]->timeValue);
351 }
352 /* if we have a new set throw event for reinitialization
353 and set the A matrix for set.x=A*(states) */
354 ✗ res = comparePivot(oldColPivot, set, setIndex, data, switchStates);
355 ✗ if(!switchStates)
356 {
357 ✗ memcpy(set->colPivot, oldColPivot, set->nCandidates*sizeof(modelica_integer));
358 ✗ memcpy(set->rowPivot, oldRowPivot, set->nDummyStates*sizeof(modelica_integer));
359 }
360 ✗ if(res)
361 globalres = 1;
362
363 ✗ free(oldColPivot);
364 ✗ free(oldRowPivot);
365 ✗ return globalres;
366 }
367
368 /*! \fn stateSelection
369 *
370 * function to select the actual states
371 *
372 * \param [ref] [data]
373 * \param [ref] [threadData]
374 * \param [in] [reportError]
375 * \param [in] [switchStates] flag for switch states, function does switch only if this switchStates = 1
376 * \return [globalres] flag for discontinuous timestep in the case of a state switch for at least one set
377 *
378 * \author Frenkel TUD
379 */
380 2 int stateSelection(DATA *data, threadData_t *threadData, char reportError, int switchStates)
381 {
382 long i=0;
383 int globalres=0;
384
385 /* go through all the state sets */
386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for(i=0; i<data->modelData->nStateSets; i++)
387 {
388 ✗ globalres = stateSelectionSet(data, threadData, reportError, switchStates, i, globalres);
389 }
390
391 2 return globalres;
392 }
393
394 #endif /* OMC_NO_STATESELECTION */
395