Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 21.8% 79 / 0 / 363
Functions: 36.4% 4 / 0 / 11
Branches: 11.5% 31 / 0 / 270

OMCompiler/SimulationRuntime/c/simulation/solver/initialization/initialization.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 initialization.c
29 */
30
31 #include "initialization.h"
32
33 #include "../../../util/omc_error.h"
34 #include "../../../util/omc_file.h"
35 #include "../../../openmodelica.h"
36 #include "../../../openmodelica_func.h"
37 #include "../../../simulation/options.h"
38 #include "../../simulation_input_xml.h"
39 #include "../../arrayIndex.h"
40 #include "../model_help.h"
41 #if !defined(OMC_MINIMAL_RUNTIME)
42 #include "../../../util/read_matlab4.h"
43 #endif
44 #include "../events.h"
45 #include "../stateset.h"
46
47 #if defined(OMC_NUM_MIXED_SYSTEMS) && OMC_NUM_MIXED_SYSTEMS==0
48 #define check_mixed_solutions(X,Y) 0
49 #else
50 #include "../mixedSystem.h"
51 #endif
52
53 #if defined(OMC_NUM_LINEAR_SYSTEMS) && OMC_NUM_LINEAR_SYSTEMS==0
54 #define check_linear_solutions(X,Y) 0
55 #define updateStaticDataOfLinearSystems(X,Y)
56 #else
57 #include "../linearSystem.h"
58 #endif
59
60 #if defined(OMC_NUM_NONLINEAR_SYSTEMS) && OMC_NUM_NONLINEAR_SYSTEMS==0
61 #define check_nonlinear_solutions(X,Y) 0
62 #define updateStaticDataOfNonlinearSystems(X,Y)
63 #else
64 #include "../nonlinearSystem.h"
65 #endif
66
67 #include "../delay.h"
68 #include "../synchronous.h"
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <math.h>
73 #include <string.h>
74
75 int init_lambda_steps = 3;
76
77 /**
78 * @brief Print the real variables with array index in [from, to), one line per
79 * scalar element.
80 *
81 * @param simData Simulation data.
82 * @param from First array index.
83 * @param to Array index after the last one.
84 * @param withAttributes Print the start and nominal attribute.
85 */
86 ✗ static void dumpRealVars(DATA *simData, long from, long to, modelica_boolean withAttributes)
87 {
88 ✗ const MODEL_DATA *mData = simData->modelData;
89 ✗ const SIMULATION_INFO *sInfo = simData->simulationInfo;
90 char name[2048];
91 long i;
92 size_t k, idx;
93
94 ✗ for (i = from; i < to; ++i) {
95 ✗ STATIC_REAL_DATA *var = &mData->realVarsData[i];
96 ✗ for (k = 0; k < var->dimension.scalar_length; ++k) {
97 ✗ idx = sInfo->realVarsIndex[i] + k;
98 ✗ printArrayElementName(name, sizeof(name), var->info.name, &var->dimension, k, FALSE);
99 ✗ if (withAttributes) {
100 ✗ infoStreamPrint(OMC_LOG_SOTI, 0, "[%zu] Real %s(start=%g, nominal=%g) = %g (pre: %g)", idx+1, name,
101 ✗ real_get(var->attribute.start, attributeElementIndex(&var->attribute.start, k)),
102 ✗ real_get(var->attribute.nominal, attributeElementIndex(&var->attribute.nominal, k)),
103 ✗ simData->localData[0]->realVars[idx],
104 ✗ sInfo->realVarsPre[idx]);
105 } else {
106 ✗ infoStreamPrint(OMC_LOG_SOTI, 0, "[%zu] Real %s = %g (pre: %g)", idx+1, name,
107 ✗ simData->localData[0]->realVars[idx],
108 ✗ sInfo->realVarsPre[idx]);
109 }
110 }
111 }
112 ✗ }
113
114 /*! \fn void dumpInitializationStatus(DATA *data)
115 *
116 * \param [in] [data]
117 *
118 * \author lochel
119 */
120 1 void dumpInitialSolution(DATA *simData)
121 {
122 long i;
123 size_t k, idx;
124
125 1 const MODEL_DATA *mData = simData->modelData;
126 1 const SIMULATION_INFO *sInfo = simData->simulationInfo;
127
128 char name[2048];
129
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (OMC_ACTIVE_STREAM(OMC_LOG_INIT_V))
131 ✗ printParameters(simData, OMC_LOG_INIT_V);
132
133
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (!OMC_ACTIVE_STREAM(OMC_LOG_SOTI)) {
134 1 return;
135 }
136
137 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "### SOLUTION OF THE INITIALIZATION ###");
138
139 ✗ if (0 < mData->nStatesArray)
140 {
141 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "states variables");
142 ✗ dumpRealVars(simData, 0, mData->nStatesArray, TRUE);
143 ✗ messageClose(OMC_LOG_SOTI);
144
145 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "derivatives variables");
146 ✗ dumpRealVars(simData, mData->nStatesArray, 2*mData->nStatesArray, FALSE);
147 ✗ messageClose(OMC_LOG_SOTI);
148 }
149
150 ✗ if (2*mData->nStatesArray < mData->nVariablesRealArray)
151 {
152 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "other real variables");
153 ✗ dumpRealVars(simData, 2*mData->nStatesArray, mData->nVariablesRealArray, TRUE);
154 ✗ messageClose(OMC_LOG_SOTI);
155 }
156
157 ✗ if (0 < mData->nVariablesIntegerArray)
158 {
159 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "integer variables");
160 ✗ for(i=0; i<mData->nVariablesIntegerArray; ++i) {
161 ✗ STATIC_INTEGER_DATA *var = &mData->integerVarsData[i];
162 ✗ for (k = 0; k < var->dimension.scalar_length; ++k) {
163 ✗ idx = sInfo->integerVarsIndex[i] + k;
164 ✗ printArrayElementName(name, sizeof(name), var->info.name, &var->dimension, k, FALSE);
165 ✗ infoStreamPrint(OMC_LOG_SOTI, 0, "[%zu] Integer %s(start=" OMC_INT_FORMAT ") = " OMC_INT_FORMAT " (pre: " OMC_INT_FORMAT ")", idx+1, name,
166 ✗ integer_get(var->attribute.start, attributeElementIndex(&var->attribute.start, k)),
167 ✗ simData->localData[0]->integerVars[idx],
168 ✗ sInfo->integerVarsPre[idx]);
169 }
170 }
171 ✗ messageClose(OMC_LOG_SOTI);
172 }
173
174 ✗ if (0 < mData->nVariablesBooleanArray)
175 {
176 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "boolean variables");
177 ✗ for(i=0; i<mData->nVariablesBooleanArray; ++i) {
178 ✗ STATIC_BOOLEAN_DATA *var = &mData->booleanVarsData[i];
179 ✗ for (k = 0; k < var->dimension.scalar_length; ++k) {
180 ✗ idx = sInfo->booleanVarsIndex[i] + k;
181 ✗ printArrayElementName(name, sizeof(name), var->info.name, &var->dimension, k, FALSE);
182 ✗ infoStreamPrint(OMC_LOG_SOTI, 0, "[%zu] Boolean %s(start=%s) = %s (pre: %s)", idx+1, name,
183 ✗ boolean_get(var->attribute.start, attributeElementIndex(&var->attribute.start, k)) ? "true" : "false",
184 ✗ simData->localData[0]->booleanVars[idx] ? "true" : "false",
185 ✗ sInfo->booleanVarsPre[idx] ? "true" : "false");
186 }
187 }
188 ✗ messageClose(OMC_LOG_SOTI);
189 }
190
191 ✗ if (0 < mData->nVariablesStringArray)
192 {
193 ✗ infoStreamPrint(OMC_LOG_SOTI, 1, "string variables");
194 ✗ for(i=0; i<mData->nVariablesStringArray; ++i) {
195 ✗ STATIC_STRING_DATA *var = &mData->stringVarsData[i];
196 ✗ for (k = 0; k < var->dimension.scalar_length; ++k) {
197 ✗ modelica_string start = string_get(var->attribute.start, attributeElementIndex(&var->attribute.start, k));
198 ✗ idx = sInfo->stringVarsIndex[i] + k;
199 ✗ printArrayElementName(name, sizeof(name), var->info.name, &var->dimension, k, FALSE);
200 ✗ infoStreamPrint(OMC_LOG_SOTI, 0, "[%zu] String %s(start=\"%s\") = \"%s\" (pre: \"%s\")", idx+1, name,
201 start ? omc_string_data(start) : "",
202 ✗ omc_string_data(simData->localData[0]->stringVars[idx]),
203 ✗ omc_string_data(sInfo->stringVarsPre[idx]));
204 }
205 }
206 ✗ messageClose(OMC_LOG_SOTI);
207 }
208
209 ✗ messageClose(OMC_LOG_SOTI);
210 }
211
212
213 /**
214 * @brief Write fileName into buffer.
215 *
216 * If FLAG_OUTPUT_PATH is used add output path to file name.
217 *
218 * @param buffer FileName on output.
219 * @param fileName Name for CSV file.
220 * @param mData Pointer to model data.
221 */
222 ✗ void homotopy_log_file_path(char* buffer, const char* fileName, MODEL_DATA *mData)
223 {
224 ✗ if (omc_flag[FLAG_OUTPUT_PATH]) { /* Add output path to file name */
225 ✗ sprintf(buffer, "%s/%s_%s", omc_flagValue[FLAG_OUTPUT_PATH], mData->modelFilePrefix, fileName);
226 }
227 else
228 {
229 ✗ sprintf(buffer, "%s_%s", mData->modelFilePrefix, fileName);
230 }
231 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "The homotopy path will be exported to %s.", buffer);
232 ✗ return;
233 }
234
235 /**
236 * @brief Log lambda and all real variables in homotopy CSV file
237 *
238 * @param data Pointer to DATA.
239 * @param threadData Pointer to threadData.
240 * @param fileName Name of CSV file to write to.
241 * @param sep CSV Seperator (usually ",").
242 * @param lambda Value of lambda.
243 * @param firstLine Boolean specifying if header of CSV should be written.
244 */
245 ✗ void log_homotopy_lambda_vars(DATA *data, threadData_t *threadData, const char* fileName, const char* sep, double lambda, int firstLine)
246 {
247 int i;
248 FILE* pFile;
249
250 /* Open file */
251 ✗ if (firstLine) {
252 ✗ pFile = omc_fopen(fileName, "wt");
253 }
254 else {
255 ✗ pFile = omc_fopen(fileName, "at");
256 }
257 ✗ if (pFile == NULL)
258 {
259 ✗ throwStreamPrint(threadData, "Could not write to `%s`.", fileName);
260 }
261
262 /* Write to file */
263 ✗ if (firstLine) {
264 fprintf(pFile, "\"lambda\"");
265 ✗ for(i=0; i<data->modelData->nVariablesRealArray; ++i)
266 {
267 ✗ const char* name = data->modelData->realVarsData[i].info.name;
268
269 ✗ if (data->modelData->realVarsData[i].dimension.numberOfDimensions == 0) {
270 fprintf(pFile, "%s\"%s\"", sep, name);
271 } else {
272 ✗ printFlattenedNames(pFile, sep, name, &data->modelData->realVarsData[i].dimension);
273 }
274 }
275 fprintf(pFile, "\n");
276 } else {
277 fprintf(pFile, "%.16g", lambda);
278 ✗ for(i=0; i<data->modelData->nVariablesReal; ++i)
279 {
280 ✗ fprintf(pFile, "%s%.16g", sep, data->localData[0]->realVars[i]);
281 }
282 fprintf(pFile, "\n");
283 }
284
285 ✗ fclose(pFile);
286 ✗ return;
287 }
288
289 /*! \fn static int symbolic_initialization(DATA *data, threadData_t *threadData)
290 *
291 * \param [ref] [data]
292 * \param [ref] [threadData]
293 *
294 * \author lochel
295 * \author ptaeuber
296 */
297 1 static int symbolic_initialization(DATA *data, threadData_t *threadData)
298 {
299 int retVal;
300 FILE *pFile = NULL;
301 char fileName[4096];
302 const char* sep = ",";
303 long i;
304 1 MODEL_DATA *mData = data->modelData;
305 modelica_boolean homotopySupport = FALSE;
306 int solveWithGlobalHomotopy;
307 1 int triedWithoutHomotopy = 0;
308 int adaptiveGlobal;
309 int kinsol = 0;
310
311 #if !defined(OMC_MINIMAL_RUNTIME)
312 1 kinsol = (data->simulationInfo->nlsMethod == NLS_KINSOL);
313 #endif
314
315 #if !defined(OMC_NUM_NONLINEAR_SYSTEMS) || OMC_NUM_NONLINEAR_SYSTEMS>0
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<mData->nNonLinearSystems; i++) {
317 ✗ if (data->simulationInfo->nonlinearSystemData[i].homotopySupport) {
318 homotopySupport = TRUE;
319 break;
320 }
321 }
322 #endif
323
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (homotopySupport && omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY] != 1 && omc_flag[FLAG_NO_HOMOTOPY_ON_FIRST_TRY] != 1) {
324 ✗ omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY] = 1;
325 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Model contains homotopy operator: Use adaptive homotopy method to solve initialization problem. "
326 "To disable initialization with homotopy operator use \"-noHomotopyOnFirstTry\".");
327 }
328
329 1 adaptiveGlobal = data->callback->homotopyMethod == GLOBAL_ADAPTIVE_HOMOTOPY; /* new global homotopy approach (adaptive lambda) */
330 1 solveWithGlobalHomotopy = homotopySupport
331
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 && ((data->callback->homotopyMethod == GLOBAL_EQUIDISTANT_HOMOTOPY && init_lambda_steps >= 1) || adaptiveGlobal);
332
333 /* initialize all relations that are ZeroCrossings */
334 1 storePreValues(data);
335 1 overwriteOldSimulationData(data);
336
337 /* If there is no homotopy in the model or local homotopy is activated
338 or homotopy is disabled by runtime flag '-ils=<lambda_steps>',
339 solve WITHOUT HOMOTOPY or LOCAL HOMOTOPY. */
340
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (!solveWithGlobalHomotopy){
341 1 data->simulationInfo->lambda = 1.0;
342 1 data->callback->functionInitialEquations(data, threadData);
343
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 OMC_ERROR_CHECK_RETURN(-1);
344
345 /* If there is homotopy in the model and global homotopy is activated
346 and homotopy on first try is deactivated,
347 TRY TO SOLVE WITHOUT HOMOTOPY FIRST.
348 TO-DO: For the adaptive global approach, provide a separate DAE with
349 the original unmanipulated systems for trying without homotopy */
350 ✗ } else if (!omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY]) {
351 /* try */
352 #ifndef OMC_EMCC
353 ✗ OMC_TRY_INTERNAL(simulationJumpBuffer)
354 #endif
355 ✗ if (adaptiveGlobal && kinsol) {
356 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Automatically set -homotopyOnFirstTry, because trying without homotopy first is not supported for the adaptive global approach in combination with KINSOL.");
357 } else {
358 ✗ if (adaptiveGlobal)
359 ✗ data->callback->homotopyMethod = GLOBAL_EQUIDISTANT_HOMOTOPY; /* global homotopy (equidistant lambda) */
360 ✗ data->simulationInfo->lambda = 1.0;
361 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Try to solve the initialization problem without homotopy first.");
362 ✗ data->callback->functionInitialEquations(data, threadData);
363 triedWithoutHomotopy = 1;
364 }
365
366 /* catch */
367 ✗ if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } else if (triedWithoutHomotopy) { solveWithGlobalHomotopy = 0; }
368 #ifndef OMC_EMCC
369 ✗ OMC_CATCH_INTERNAL(simulationJumpBuffer)
370 #endif
371 ✗ if (adaptiveGlobal)
372 ✗ data->callback->homotopyMethod = GLOBAL_ADAPTIVE_HOMOTOPY; /* new global homotopy approach (adaptive lambda) */
373 ✗ if(solveWithGlobalHomotopy) {
374 ✗ if (!kinsol)
375 ✗ warningStreamPrint(OMC_LOG_ASSERT, 0, "Failed to solve the initialization problem without homotopy method. If homotopy is available the homotopy method is used now.");
376 ✗ omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY] = 1;
377 ✗ setAllParamsToStart(data->simulationInfo, data->modelData);
378 ✗ setAllVarsToStart(data->localData[0], data->simulationInfo, data->modelData);
379 ✗ data->callback->updateBoundParameters(data, threadData);
380 ✗ data->callback->updateBoundVariableAttributes(data, threadData);
381 }
382 }
383
384 /* If there is homotopy in the model and the equidistant global homotopy approach is activated
385 and solving without homotopy failed or is not wanted,
386 use EQUIDISTANT GLOBAL HOMOTOPY METHOD. */
387
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if (data->callback->homotopyMethod == GLOBAL_EQUIDISTANT_HOMOTOPY && solveWithGlobalHomotopy)
388 {
389 long step;
390 double lambda = -1;
391 ✗ int success = 0;
392
393 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Global homotopy with equidistant step size started.");
394
395 #if !defined(OMC_NO_FILESYSTEM)
396 ✗ if(OMC_ACTIVE_STREAM(OMC_LOG_INIT_HOMOTOPY))
397 {
398 ✗ homotopy_log_file_path(fileName, "equidistant_global_homotopy.csv", mData);
399 ✗ log_homotopy_lambda_vars(data, threadData, fileName, sep, lambda, 1 /*TRUE*/);
400 }
401 #endif
402
403 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 1, "homotopy process\n---------------------------");
404 /* try */
405 #ifndef OMC_EMCC
406 ✗ OMC_TRY_INTERNAL(simulationJumpBuffer)
407 #endif
408 ✗ for(step=0; step<=init_lambda_steps; ++step)
409 {
410 ✗ data->simulationInfo->lambda = ((double)step)/(init_lambda_steps);
411 lambda = data->simulationInfo->lambda;
412 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "homotopy parameter lambda = %g", lambda);
413
414 ✗ if(data->simulationInfo->lambda > 1.0)
415 {
416 ✗ data->simulationInfo->lambda = 1.0;
417 lambda = 1.0;
418 }
419
420 ✗ if(0 == step)
421 {
422 ✗ if(data->callback->functionInitialEquations_lambda0 != NULL)
423 {
424 ✗ data->callback->functionInitialEquations_lambda0(data, threadData);
425 }
426 else
427 {
428 ✗ warningStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "No initialEquation_lambda0 was generated. Using normal initial equation system with lambda=0 instead.");
429 ✗ data->callback->functionInitialEquations(data, threadData);
430 }
431 }
432 else
433 {
434 ✗ data->callback->functionInitialEquations(data, threadData);
435 }
436
437 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "homotopy parameter lambda = %g done\n---------------------------", lambda);
438
439 #if !defined(OMC_NO_FILESYSTEM)
440 ✗ if(OMC_ACTIVE_STREAM(OMC_LOG_INIT_HOMOTOPY))
441 {
442 ✗ log_homotopy_lambda_vars(data, threadData, fileName, sep, lambda, 0 /*FALSE*/);
443 }
444 #endif
445 }
446 /* catch */
447 ✗ if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } else { success = 1; }
448 #ifndef OMC_EMCC
449 ✗ OMC_CATCH_INTERNAL(simulationJumpBuffer)
450 #endif
451
452 ✗ messageClose(OMC_LOG_INIT_HOMOTOPY);
453
454 /* Error handling in case an assert was thrown */
455 ✗ if (!success)
456 {
457 ✗ errorStreamPrint(OMC_LOG_ASSERT, 0, "Failed to solve the initialization problem with global homotopy with equidistant step size.");
458 ✗ throwStreamPrint(threadData, "Unable to solve initialization problem.");
459 }
460
461 ✗ data->simulationInfo->homotopySteps += init_lambda_steps;
462 }
463
464 /* If there is homotopy in the model and the adaptive global homotopy approach is activated
465 and solving without homotopy failed or is not wanted,
466 use ADAPTIVE GLOBAL HOMOTOPY APPROACH. */
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (adaptiveGlobal && solveWithGlobalHomotopy)
468 {
469 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Global homotopy with adaptive step size started.");
470 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 1, "homotopy process\n---------------------------");
471
472 // Solve lambda0-DAE
473 ✗ data->simulationInfo->lambda = 0;
474 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "solve simplified lambda0-DAE");
475 ✗ if(data->callback->functionInitialEquations_lambda0 != NULL)
476 {
477 ✗ data->callback->functionInitialEquations_lambda0(data, threadData);
478 }
479 else
480 {
481 ✗ warningStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "No initialEquation_lambda0 was generated. Using normal initial equation system with lambda=0 instead.");
482 ✗ data->callback->functionInitialEquations(data, threadData);
483 }
484 ✗ OMC_ERROR_CHECK_RETURN(-1);
485 ✗ infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "solving simplified lambda0-DAE done\n---------------------------");
486
487 // Run along the homotopy path and solve the actual system
488 ✗ data->callback->functionInitialEquations(data, threadData);
489 ✗ OMC_ERROR_CHECK_RETURN(-1);
490
491 ✗ messageClose(OMC_LOG_INIT_HOMOTOPY);
492 }
493
494 1 storeRelations(data);
495
496 /* check for over-determined systems */
497 1 retVal = data->callback->functionRemovedInitialEquations(data, threadData);
498
499 return retVal;
500 }
501
502 /*! \fn static char *mapToDymolaVars(const char *varname)
503 *
504 * \param [in] [varname]
505 *
506 * converts a given variable name into dymola style
507 * ** der(foo.foo2) -> foo.der(foo2)
508 * ** foo.foo2[1,2,3] -> foo.foo2[1, 2, 3]
509 *
510 * \author lochel
511 */
512 ✗ static char *mapToDymolaVars(const char *varname)
513 {
514 ✗ unsigned int varnameSize = strlen(varname);
515 unsigned int level = 0;
516 unsigned int i=0, j=0, pos=0;
517 char* newVarname = NULL;
518 unsigned int newVarnameSize = 0;
519
520 newVarnameSize = varnameSize;
521 ✗ for(i=0; i<varnameSize; i++)
522 {
523 ✗ if(varname[i] == '[')
524 ✗ level++;
525 ✗ else if(varname[i] == ']')
526 ✗ level--;
527
528 ✗ if(level > 0 && varname[i] == ',' && varname[i+1] != ' ')
529 ✗ newVarnameSize++;
530 }
531
532 ✗ newVarname = (char*)malloc((newVarnameSize+1) * sizeof(char));
533 ✗ for(i=0,j=0; i<newVarnameSize; i++,j++)
534 {
535 ✗ if(varname[j] == '[')
536 ✗ level++;
537 ✗ else if(varname[j] == ']')
538 ✗ level--;
539
540 ✗ newVarname[i] = varname[j];
541 ✗ if(level > 0 && varname[j] == ',' && varname[j+1] != ' ')
542 {
543 ✗ i++;
544 ✗ newVarname[i] = ' ';
545 }
546 }
547 ✗ newVarname[newVarnameSize] = '\0';
548
549 ✗ while(!memcmp((const void*)newVarname, (const void*)"der(", 4*sizeof(char)))
550 {
551 ✗ for(pos=newVarnameSize; pos>=4; pos--)
552 ✗ if(newVarname[pos] == '.')
553 break;
554
555 ✗ if(pos == 3)
556 break;
557
558 ✗ memcpy((void*)newVarname, (const void*)(newVarname+4), (pos-3)*sizeof(char));
559 ✗ memcpy((void*)(newVarname+pos-3), (const void*)"der(", 4*sizeof(char));
560 }
561
562 ✗ return newVarname;
563 }
564
565 #if !defined(OMC_MINIMAL_RUNTIME)
566 enum import_type { IMPORT_REAL, IMPORT_INTEGER, IMPORT_BOOLEAN };
567
568 /* Longest name of an array element to import. */
569 #define IMPORT_NAME_LENGTH 4096
570
571 /**
572 * @brief Find variable in initialization file.
573 *
574 * Also tries the Dymola naming of derivatives.
575 *
576 * @param reader Reader of initialization file.
577 * @param name Name of scalar variable.
578 * @return ModelicaMatVariable_t* Variable or NULL if not found.
579 */
580 ✗ static ModelicaMatVariable_t* findImportVariable(ModelicaMatReader *reader, const char *name)
581 {
582 ✗ ModelicaMatVariable_t *pVar = omc_matlab4_find_var(reader, name);
583 char *newVarname;
584
585 ✗ if (!pVar) {
586 ✗ newVarname = mapToDymolaVars(name);
587 ✗ pVar = omc_matlab4_find_var(reader, newVarname);
588 ✗ free(newVarname);
589 }
590 ✗ return pVar;
591 }
592
593 /**
594 * @brief Import start value of a scalar or array variable or parameter.
595 *
596 * Array elements are looked up by their structured name `name[i,j,...]`, as
597 * written in the result files.
598 *
599 * @param reader Reader of initialization file.
600 * @param initTime Time to read values at.
601 * @param info Variable info.
602 * @param dimension Dimension of variable.
603 * @param start Start attribute to update.
604 * @param type Type of variable.
605 * @param parameterValues Parameter values starting at the first element of
606 * the parameter to update as well, NULL for variables.
607 * @param kind "variable" or "parameter", for messages.
608 */
609 ✗ static void importStartValue(ModelicaMatReader *reader,
610 double initTime,
611 const VAR_INFO *info,
612 const DIMENSION_INFO *dimension,
613 base_array_t *start,
614 enum import_type type,
615 void *parameterValues,
616 const char *kind)
617 {
618 static const char *type_names[] = {"real", "integer", "boolean"};
619 ✗ const size_t n = dimension->numberOfDimensions > 0 ? dimension->scalar_length : 1;
620 char name[IMPORT_NAME_LENGTH];
621 ModelicaMatVariable_t *pVar;
622 double value;
623 size_t k;
624
625 ✗ if (isQuantityOverridden(info->name)) {
626 ✗ infoStreamPrint(OMC_LOG_INIT_V, 0, "| skip import of %s %s %s: overridden on command line", type_names[type], kind, info->name);
627 ✗ return;
628 }
629
630 /* one start value per element, e.g. start attributes given with `each` hold a single value */
631 ✗ switch (type) {
632 ✗ case IMPORT_REAL: real_array_ensure_size(start, (int) n); break;
633 ✗ case IMPORT_INTEGER: integer_array_ensure_size(start, (int) n); break;
634 ✗ case IMPORT_BOOLEAN: boolean_array_ensure_size(start, (int) n); break;
635 }
636
637 ✗ for (k = 0; k < n; k++) {
638 ✗ printArrayElementName(name, IMPORT_NAME_LENGTH, info->name, dimension, k, TRUE);
639 ✗ pVar = findImportVariable(reader, name);
640
641 ✗ if (!pVar) {
642 /* skip warnings about self-generated variables */
643 ✗ if (parameterValues != NULL ||
644 ✗ (strlen(name) > 0 && name[0] != '$' && strncmp(name, "der($", 5) != 0)) {
645 ✗ warningStreamPrint(OMC_LOG_INIT, 0, "unable to import %s %s %s from given file", type_names[type], kind, name);
646 }
647 ✗ continue;
648 }
649
650 ✗ omc_matlab4_val(&value, reader, pVar, initTime);
651 ✗ switch (type) {
652 ✗ case IMPORT_REAL:
653 ✗ put_real_element(value, k, start);
654 ✗ if (parameterValues) ((modelica_real*) parameterValues)[k] = value;
655 ✗ infoStreamPrint(OMC_LOG_INIT_V, 0, "| %s(start=%g)", name, value);
656 ✗ break;
657 ✗ case IMPORT_INTEGER:
658 ✗ put_integer_element((modelica_integer) value, k, start);
659 ✗ if (parameterValues) ((modelica_integer*) parameterValues)[k] = (modelica_integer) value;
660 ✗ infoStreamPrint(OMC_LOG_INIT_V, 0, "| %s(start=" OMC_INT_FORMAT ")", name, (modelica_integer) value);
661 ✗ break;
662 ✗ case IMPORT_BOOLEAN:
663 ✗ put_boolean_element((modelica_boolean) value, k, start);
664 ✗ if (parameterValues) ((modelica_boolean*) parameterValues)[k] = (modelica_boolean) value;
665 ✗ infoStreamPrint(OMC_LOG_INIT_V, 0, "| %s(start=%s)", name, value ? "true" : "false");
666 ✗ break;
667 }
668 }
669 }
670
671 /**
672 * @brief Import start values from initialization file.
673 *
674 * Imports real, integer and boolean variables and parameters. Elements of
675 * array variables are looked up by their structured name `name[i,j,...]`.
676 *
677 * @param data Pointer to data struct to fill member `modelData` with start values.
678 * @param threadData Thread data for error handling.
679 * @param pInitFile Initialization file (MATv4 format).
680 * @param initTime Initialization time (simulation start time).
681 * @return int 0 on success, 1 otherwise.
682 */
683 ✗ int importStartValues(DATA *data, threadData_t *threadData, const char *pInitFile, const double initTime)
684 {
685 ModelicaMatReader reader;
686 const char *pError = NULL;
687
688 ✗ MODEL_DATA *mData = data->modelData;
689 ✗ SIMULATION_INFO *sInfo = data->simulationInfo;
690 long i;
691
692 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import start values\nfile: %s\ntime: %g", pInitFile, initTime);
693
694 ✗ if(!strcmp(mData->resultFileName, pInitFile))
695 {
696 ✗ errorStreamPrint(OMC_LOG_INIT, 0, "Cannot import a result file for initialization that is also the current output file <%s>.\nConsider redirecting the output result file (-r=<new_res.mat>) or renaming the result file that is used for initialization import.", pInitFile);
697 ✗ return 1;
698 }
699
700 ✗ pError = omc_new_matlab4_reader(pInitFile, &reader);
701 ✗ if(pError) {
702 ✗ throwStreamPrint(threadData, "unable to read input-file <%s> [%s]", pInitFile, pError);
703 return 1;
704 }
705
706 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import real variables");
707 ✗ for(i=0; i<mData->nVariablesRealArray; ++i) {
708 ✗ importStartValue(&reader, initTime, &mData->realVarsData[i].info, &mData->realVarsData[i].dimension,
709 ✗ &mData->realVarsData[i].attribute.start, IMPORT_REAL, NULL, "variable");
710 }
711
712 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import integer variables");
713 ✗ for(i=0; i<mData->nVariablesIntegerArray; ++i) {
714 ✗ importStartValue(&reader, initTime, &mData->integerVarsData[i].info, &mData->integerVarsData[i].dimension,
715 ✗ &mData->integerVarsData[i].attribute.start, IMPORT_INTEGER, NULL, "variable");
716 }
717
718 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import boolean variables");
719 ✗ for(i=0; i<mData->nVariablesBooleanArray; ++i) {
720 ✗ importStartValue(&reader, initTime, &mData->booleanVarsData[i].info, &mData->booleanVarsData[i].dimension,
721 ✗ &mData->booleanVarsData[i].attribute.start, IMPORT_BOOLEAN, NULL, "variable");
722 }
723
724 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import real parameters");
725 ✗ for(i=0; i<mData->nParametersRealArray; ++i) {
726 ✗ importStartValue(&reader, initTime, &mData->realParameterData[i].info, &mData->realParameterData[i].dimension,
727 ✗ &mData->realParameterData[i].attribute.start, IMPORT_REAL,
728 ✗ &sInfo->realParameter[sInfo->realParamsIndex[i]], "parameter");
729 }
730
731 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import integer parameters");
732 ✗ for(i=0; i<mData->nParametersIntegerArray; ++i) {
733 ✗ importStartValue(&reader, initTime, &mData->integerParameterData[i].info, &mData->integerParameterData[i].dimension,
734 ✗ &mData->integerParameterData[i].attribute.start, IMPORT_INTEGER,
735 ✗ &sInfo->integerParameter[sInfo->integerParamsIndex[i]], "parameter");
736 }
737
738 ✗ infoStreamPrint(OMC_LOG_INIT, 0, "import boolean parameters");
739 ✗ for(i=0; i<mData->nParametersBooleanArray; ++i) {
740 ✗ importStartValue(&reader, initTime, &mData->booleanParameterData[i].info, &mData->booleanParameterData[i].dimension,
741 ✗ &mData->booleanParameterData[i].attribute.start, IMPORT_BOOLEAN,
742 ✗ &sInfo->booleanParameter[sInfo->booleanParamsIndex[i]], "parameter");
743 }
744
745 ✗ omc_free_matlab4_reader(&reader);
746
747 ✗ return 0;
748 }
749 #endif
750
751 /*! \fn initSample
752 *
753 * \param [ref] [data]
754 * \param [in] [startTime]
755 * \param [in] [stopTime]
756 *
757 * This function initializes sample-events.
758 */
759 1 void initSample(DATA* data, threadData_t *threadData, double startTime, double stopTime)
760 {
761 long i;
762
763 1 data->callback->function_initSample(data, threadData); /* set-up sample */
764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nSamples; ++i) {
765 ✗ if(startTime < data->modelData->samplesInfo[i].start) {
766 ✗ data->simulationInfo->nextSampleTimes[i] = data->modelData->samplesInfo[i].start;
767 } else {
768 ✗ data->simulationInfo->nextSampleTimes[i] = data->modelData->samplesInfo[i].start + ceil((startTime-data->modelData->samplesInfo[i].start) / data->modelData->samplesInfo[i].interval) * data->modelData->samplesInfo[i].interval;
769 }
770 }
771 1 updateNextSampleEvent(data, threadData);
772 1 }
773
774 /*! \fn int initialization(DATA *data, const char* pInitMethod, const char* pOptiMethod, const char* pInitFile, double initTime)
775 *
776 * \param [ref] [data]
777 * \param [in] [pInitMethod] user defined initialization method
778 * \param [in] [pInitFile] extra argument for initialization-method "file"
779 * \param [in] [initTime] extra argument for initialization-method "file"
780 *
781 * \author lochel
782 */
783 1 int initialization(DATA *data, threadData_t *threadData, const char* pInitMethod, const char* pInitFile, double initTime)
784 {
785 int initMethod = IIM_SYMBOLIC; /* default method */
786 int retVal = -1;
787 int i;
788
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 modelica_boolean read_init_from_file = (pInitFile && strcmp(pInitFile, ""));
789 1 modelica_boolean fmi_init_method = !strcmp(pInitMethod, "fmi");
790
791 1 data->simulationInfo->homotopySteps = 0;
792
793 1 infoStreamPrint(OMC_LOG_INIT, 0, "### START INITIALIZATION ###");
794
795
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (!fmi_init_method) {
796 1 setAllParamsToStart(data->simulationInfo, data->modelData);
797 }
798
799 #if !defined(OMC_MINIMAL_RUNTIME)
800 /* import start values from extern mat-file */
801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if(read_init_from_file)
802 {
803 ✗ data->callback->updateBoundParameters(data, threadData);
804 ✗ data->callback->updateBoundVariableAttributes(data, threadData);
805 ✗ OMC_ERROR_CHECK_RETURN(1);
806
807 ✗ if(importStartValues(data, threadData, pInitFile, initTime)) {
808 return 1;
809 }
810 }
811 #endif
812 /* set up all variables with their start-values */
813
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (!fmi_init_method) {
814 1 setAllVarsToStart(data->localData[0], data->simulationInfo, data->modelData);
815 }
816
817
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(!read_init_from_file) {
818 1 data->callback->updateBoundParameters(data, threadData);
819 1 data->callback->updateBoundVariableAttributes(data, threadData);
820 }
821
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 OMC_ERROR_CHECK_RETURN(1);
822
823 1 data->callback->function_initSpatialDistribution(data, threadData);
824
825 /* Update nominal, min and max values of linear/non-linear system solvers */
826 1 updateStaticDataOfLinearSystems(data, threadData);
827 1 updateStaticDataOfNonlinearSystems(data, threadData);
828
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 OMC_ERROR_CHECK_RETURN(1);
829
830 /* if there are user-specified options, use them! */
831
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (pInitMethod && (strcmp(pInitMethod, "") && !fmi_init_method)) {
832 initMethod = IIM_UNKNOWN;
833
834 ✗ for (i=1; i<IIM_MAX; ++i) {
835 ✗ if(!strcmp(pInitMethod, INIT_METHOD_NAME[i])) {
836 initMethod = i;
837 }
838 }
839
840 ✗ if(initMethod == IIM_UNKNOWN) {
841 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "unrecognized option -iim %s", pInitMethod);
842 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "current options are:");
843 ✗ for (i=1; i<IIM_MAX; ++i) {
844 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "| %-15s [%s]", INIT_METHOD_NAME[i], INIT_METHOD_DESC[i]);
845 }
846 ✗ throwStreamPrint(threadData, "see last warning");
847 }
848 }
849
850 1 infoStreamPrint(OMC_LOG_INIT, 0, "initialization method: %-15s [%s]", INIT_METHOD_NAME[initMethod], INIT_METHOD_DESC[initMethod]);
851
852 /* start with the real initialization */
853 1 data->simulationInfo->initial = 1; /* to evaluate when-equations with initial()-conditions */
854
855 /* initialize all (nonlinear|linear|mixed) systems
856 * This is a workaround and should be removed as soon as possible.
857 */
858 #if !defined(OMC_NUM_NONLINEAR_SYSTEMS) || OMC_NUM_NONLINEAR_SYSTEMS>0
859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nNonLinearSystems; ++i) {
860 ✗ data->simulationInfo->nonlinearSystemData[i].solved = 1;
861 }
862 #endif
863 #if !defined(OMC_NUM_LINEAR_SYSTEMS) || OMC_NUM_LINEAR_SYSTEMS>0
864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nLinearSystems; ++i) {
865 ✗ data->simulationInfo->linearSystemData[i].solved = 1;
866 }
867 #endif
868 #if !defined(OMC_NUM_MIXED_SYSTEMS) || OMC_NUM_MIXED_SYSTEMS>0
869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(i=0; i<data->modelData->nMixedSystems; ++i) {
870 ✗ data->simulationInfo->mixedSystemData[i].solved = 1;
871 }
872 #endif
873 /* end workaround */
874
875 /* select the right initialization-method */
876
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if(IIM_NONE == initMethod) {
877 retVal = 0;
878
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 } else if(IIM_SYMBOLIC == initMethod) {
879 1 retVal = symbolic_initialization(data, threadData);
880
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 OMC_ERROR_CHECK_RETURN(retVal);
881 } else {
882 ✗ throwStreamPrint(threadData, "unsupported option -iim");
883 }
884
885 /* External object sanity check
886 * At this point all external objects should be initialized (bound parameters or initial system) */
887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 for(int i=0; i<data->modelData->nExtObjs; i++) {
888 ✗ if (data->simulationInfo->extObjs[i] == NULL) {
889 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "External object %i is NULL, did a external constructor fail?", i);
890 }
891 }
892
893 /* check for unsolved (nonlinear|linear|mixed) systems
894 * This is a workaround and should be removed as soon as possible.
895 */
896
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if(check_nonlinear_solutions(data, 1)) {
897 retVal = -2;
898
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 } else if(check_linear_solutions(data, 1)) {
899 retVal = -3;
900
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 } else if(check_mixed_solutions(data, 1)) {
901 retVal = -4;
902 }
903 /* end workaround */
904
905 #if !defined(OMC_MINIMAL_LOGGING)
906 1 dumpInitialSolution(data);
907 1 infoStreamPrint(OMC_LOG_INIT, 0, "### END INITIALIZATION ###");
908 #endif
909
910 1 overwriteOldSimulationData(data); /* overwrite the whole ring-buffer with initialized values */
911 1 storePreValues(data); /* save pre-values */
912 1 updateDiscreteSystem(data, threadData); /* evaluate discrete variables (event iteration) */
913 1 saveZeroCrossings(data, threadData);
914
915 /* do pivoting for dynamic state selection if selection changed try again */
916 #if !defined(OMC_NO_STATESELECTION)
917
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if(stateSelection(data, threadData, 0, 1) == 1) {
918 ✗ if(stateSelection(data, threadData, 1, 1) == 1) {
919 /* report a warning about strange start values */
920 ✗ warningStreamPrint(OMC_LOG_STDOUT, 0, "Cannot initialize the dynamic state selection in an unique way. Use -lv LOG_DSS to see the switching state set.");
921 }
922 }
923 #endif
924
925 1 data->simulationInfo->initial = 0;
926 /* initialization is done */
927
928 1 initSample(data, threadData, data->simulationInfo->startTime, data->simulationInfo->stopTime);
929 1 data->callback->function_storeDelayed(data, threadData);
930 1 data->callback->function_storeSpatialDistribution(data, threadData);
931 1 data->callback->function_updateRelations(data, threadData, 1);
932 1 initSynchronous(data, threadData, data->simulationInfo->startTime);
933
934 #if !defined(OMC_MINIMAL_LOGGING)
935 1 printRelations(data, OMC_LOG_EVENTS);
936 1 printZeroCrossings(data, OMC_LOG_EVENTS);
937 #endif
938
939 /* Check for warning of variables out of range assert(min<x || x>xmax, ...)*/
940 1 data->callback->checkForAsserts(data, threadData);
941
942 /* valid system for the first time! */
943 1 return retVal;
944 }
945