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 / 79
Functions: 0.0% 0 / 0 / 3
Branches: 0.0% 0 / 0 / 28

OMCompiler/SimulationRuntime/c/simulation/solver/gbode_events.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 gbode_events.c
29 */
30
31 #include "../../simulation/options.h"
32 #include "epsilon.h"
33 #include "events.h"
34 #include "external_input.h"
35 #include "gbode_main.h"
36 #include "gbode_util.h"
37 #include "model_help.h"
38
39 /*! \fn bisection_gb
40 *
41 * \param [ref] [data]
42 * \param [ref] [a]
43 * \param [ref] [b]
44 * \param [ref] [states_a]
45 * \param [ref] [states_b]
46 * \param [ref] [eventListTmp]
47 * \param [in] [eventList]
48 *
49 * Method to find root in interval [oldTime, timeValue]
50 */
51 ✗ void bisection_gb(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo, double* a, double* b, double* states_a, double* states_b, LIST *tmpEventList, LIST *eventList, modelica_boolean isInnerIntegration)
52 {
53 ✗ DATA_GBODE *gbData = (DATA_GBODE *)solverInfo->solverData;
54 DATA_GBODEF *gbfData;
55
56 int gb_step_info;
57 double timeValue, *y;
58
59 ✗ double TTOL = MINIMAL_STEP_SIZE + MINIMAL_STEP_SIZE*fabs(*b-*a); /* absTol + relTol*abs(b-a) */
60 double c;
61 long i=0;
62 /* n >= log(2)/log(2) + log(|b-a|/TOL)/log(2)*/
63 ✗ unsigned int n = maxBisectionIterations > 0 ? maxBisectionIterations : 1 + ceil(log(fabs(*b - *a)/TTOL)/log(2));
64
65 ✗ memcpy(data->simulationInfo->zeroCrossingsBackup, data->simulationInfo->zeroCrossings, data->modelData->nZeroCrossings * sizeof(modelica_real));
66
67 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "bisection method starts in interval [%e, %e]", *a, *b);
68 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "TTOL is set to %e and maximum number of intersections %d.", TTOL, n);
69
70 ✗ while(fabs(*b - *a) > MINIMAL_STEP_SIZE && n-- > 0)
71 {
72 ✗ c = 0.5 * (*a + *b);
73 ✗ data->localData[0]->timeValue = c;
74
75 /*calculates states at time c using interpolation */
76 ✗ if (isInnerIntegration) {
77 ✗ gbfData = gbData->gbfData;
78 ✗ gb_interpolation(gbfData->interpolation,
79 gbfData->timeLeft, gbfData->yLeft, gbfData->kLeft,
80 gbfData->timeRight, gbfData->yRight, gbfData->kRight,
81 ✗ c, data->localData[0]->realVars,
82 gbData->nStates, NULL, gbData->nStates, gbfData->tableau, gbfData->x, gbfData->k);
83 } else {
84 ✗ gb_interpolation(gbData->interpolation,
85 gbData->timeLeft, gbData->yLeft, gbData->kLeft,
86 gbData->timeRight, gbData->yRight, gbData->kRight,
87 ✗ c, data->localData[0]->realVars,
88 gbData->nStates, NULL, gbData->nStates, gbData->tableau, gbData->x, gbData->k);
89 }
90
91 /*calculates Values dependents on new states*/
92 /* read input vars */
93 ✗ externalInputUpdate(data);
94 ✗ data->callback->input_function(data, threadData);
95 /* eval needed equations*/
96 ✗ data->callback->function_ZeroCrossingsEquations(data, threadData);
97
98 ✗ data->callback->function_ZeroCrossings(data, threadData, data->simulationInfo->zeroCrossings);
99
100 ✗ if(checkZeroCrossings(data, tmpEventList, eventList)) /* If Zerocrossing in left Section */
101 {
102 ✗ memcpy(states_b, data->localData[0]->realVars, data->modelData->nStates * sizeof(modelica_real));
103 ✗ *b = c;
104 ✗ memcpy(data->simulationInfo->zeroCrossingsBackup, data->simulationInfo->zeroCrossings, data->modelData->nZeroCrossings * sizeof(modelica_real));
105 }
106 else /*else Zerocrossing in right Section */
107 {
108 ✗ memcpy(states_a, data->localData[0]->realVars, data->modelData->nStates * sizeof(modelica_real));
109 ✗ *a = c;
110 ✗ memcpy(data->simulationInfo->zeroCrossingsPre, data->simulationInfo->zeroCrossings, data->modelData->nZeroCrossings * sizeof(modelica_real));
111 ✗ memcpy(data->simulationInfo->zeroCrossings, data->simulationInfo->zeroCrossingsBackup, data->modelData->nZeroCrossings * sizeof(modelica_real));
112 }
113 }
114 ✗ }
115
116 /*! \fn findRoot
117 *
118 * \param [ref] [data]
119 * \param [ref] [threadData]
120 * \param [ref] [eventList]
121 * \param [in] [time_left]
122 * \param [in] [values_left]
123 * \param [in] [time_right]
124 * \param [in] [values_right]
125 * \return: first event of interval [time_left, time_right]
126 */
127 ✗ double findRoot_gb(DATA* data, threadData_t* threadData, SOLVER_INFO* solverInfo, LIST* eventList, double time_left, double* values_left, double time_right, double* values_right, modelica_boolean isInnerIntegration)
128 {
129 LIST_NODE* it;
130 fortran_integer i=0;
131 ✗ LIST *tmpEventList = allocList(eventListAlloc, eventListFree, eventListCopy);
132
133 /* static work arrays */
134 ✗ double *states_left = data->simulationInfo->states_left;
135 ✗ double *states_right = data->simulationInfo->states_right;
136
137 /* write states to work arrays */
138 ✗ memcpy(states_left, values_left, data->modelData->nStates * sizeof(double));
139 ✗ memcpy(states_right, values_right, data->modelData->nStates * sizeof(double));
140
141 ✗ for(it=listFirstNode(eventList); it; it=listNextNode(it))
142 {
143 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "search for current event. Events in list: %ld", *((long*)listNodeData(it)));
144 }
145
146 /* Search for event time and event_id with bisection method */
147 ✗ bisection_gb(data, threadData, solverInfo, &time_left, &time_right, states_left, states_right, tmpEventList, eventList, isInnerIntegration);
148
149 /* what happens here? */
150 ✗ if(listLen(tmpEventList) == 0)
151 {
152 ✗ double value = fabs(data->simulationInfo->zeroCrossings[*((long*) listFirstData(eventList))]);
153 ✗ for(it = listFirstNode(eventList); it; it = listNextNode(it))
154 {
155 ✗ double fvalue = fabs(data->simulationInfo->zeroCrossings[*((long*) listNodeData(it))]);
156 ✗ if(value > fvalue)
157 {
158 value = fvalue;
159 }
160 }
161 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "Minimum value: %e", value);
162 ✗ for(it = listFirstNode(eventList); it; it = listNextNode(it))
163 {
164 ✗ if(value == fabs(data->simulationInfo->zeroCrossings[*((long*) listNodeData(it))]))
165 {
166 ✗ listPushBack(tmpEventList, listNodeData(it));
167 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "added tmp event : %ld", *((long*) listNodeData(it)));
168 }
169 }
170 }
171
172 ✗ listClear(eventList);
173
174 ✗ while(listLen(tmpEventList) > 0)
175 {
176 ✗ long event_id = *((long*)listFirstData(tmpEventList));
177 ✗ listPushFrontNodeNoCopy(eventList, listPopFrontNode(tmpEventList));
178 ✗ infoStreamPrint(OMC_LOG_ZEROCROSSINGS, 0, "Event id: %ld", event_id);
179 }
180
181 ✗ data->localData[0]->timeValue = time_left;
182 ✗ memcpy(data->localData[0]->realVars, states_left, data->modelData->nStates * sizeof(double));
183
184 /* determined continuous system */
185 ✗ data->callback->updateContinuousSystem(data, threadData);
186 ✗ updateRelationsPre(data);
187 /*sim_result_emit(data);*/
188
189 ✗ data->localData[0]->timeValue = time_right;
190 ✗ memcpy(data->localData[0]->realVars, states_right, data->modelData->nStates * sizeof(double));
191
192 ✗ freeList(tmpEventList);
193
194 ✗ return time_right;
195 }
196
197 /**
198 * @brief Check if an event has happend between timeLeft and timeRight by comparing the
199 * values of the zero crossing functions with the pre values
200 *
201 * @param data Runtime data struct.
202 * @param threadData Thread data for error handling.
203 * @param solverInfo Information about main solver.
204 * @param timeLeft Time value at the left hand side of the interval
205 * @param leftValues State values at the left hand side of the time interval
206 * @param timeRight Time value at the right hand side of the interval
207 * @param rightValues State values at the right hand side of the time interval
208 * @param isInnerIntegration Specifying if inner or outer step function should be used.
209 * @param eventTime On return is set to event time if an event was found.
210 * @return modelica_boolean Return if an event was found.
211 */
212 ✗ modelica_boolean checkForEvents(DATA* data, threadData_t* threadData, SOLVER_INFO* solverInfo, double timeLeft, double* leftValues, double timeRight, double* rightValues, modelica_boolean isInnerIntegration, modelica_real* eventTime)
213 {
214 modelica_boolean foundEvent;
215 ✗ SIMULATION_DATA *sData = (SIMULATION_DATA*)data->localData[0];
216
217 // store the pre values of the zeroCrossings for comparison
218 ✗ memcpy(data->simulationInfo->zeroCrossingsPre, data->simulationInfo->zeroCrossings, data->modelData->nZeroCrossings * sizeof(modelica_real));
219
220 // set simulation data to the current time
221 ✗ sData->timeValue = timeRight;
222 ✗ memcpy(sData->realVars, rightValues, data->modelData->nStates*sizeof(double));
223 /*calculates Values dependents on new states*/
224 /* read input vars */
225 ✗ externalInputUpdate(data);
226 ✗ data->callback->input_function(data, threadData);
227 /* eval needed equations*/
228 ✗ data->callback->function_ZeroCrossingsEquations(data, threadData);
229 ✗ data->callback->function_ZeroCrossings(data, threadData, data->simulationInfo->zeroCrossings);
230
231 ✗ foundEvent = checkForStateEvent(data, solverInfo->eventLst);
232
233 ✗ if (foundEvent) {
234 ✗ if (omc_flag[FLAG_NO_ROOTFINDING]) {
235 ✗ *eventTime = timeRight;
236 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "gbode detected an event at time: %20.16g (rootfinding is disabled)", *eventTime);
237 } else {
238 ✗ *eventTime = findRoot_gb(data, threadData, solverInfo, solverInfo->eventLst, timeLeft, leftValues, timeRight, rightValues, isInnerIntegration);
239 ✗ infoStreamPrint(OMC_LOG_SOLVER, 0, "gbode detected an event at time: %20.16g", *eventTime);
240 }
241 }
242 // re-store the pre values of the zeroCrossings for comparison
243 ✗ memcpy(data->simulationInfo->zeroCrossings, data->simulationInfo->zeroCrossingsPre, data->modelData->nZeroCrossings * sizeof(modelica_real));
244
245 ✗ return foundEvent;
246 }
247