OMCompiler/SimulationRuntime/c/simulation/solver/solver_main.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 solver_main.c | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include "omc_config.h" | ||
| 32 | #include "simulation/simulation_runtime.h" | ||
| 33 | #include "simulation/results/simulation_result.h" | ||
| 34 | #include "solver_main.h" | ||
| 35 | #include "openmodelica_func.h" | ||
| 36 | #include "initialization/initialization.h" | ||
| 37 | #include "nonlinearSystem.h" | ||
| 38 | #include "newtonIteration.h" | ||
| 39 | #include "cvode_solver.h" | ||
| 40 | #include "dassl.h" | ||
| 41 | #include "ida_solver.h" | ||
| 42 | #include "delay.h" | ||
| 43 | #include "events.h" | ||
| 44 | #include "util/varinfo.h" | ||
| 45 | #include "util/omc_strdup.h" | ||
| 46 | #include "model_help.h" | ||
| 47 | #include "simulation/solver/epsilon.h" | ||
| 48 | #include "simulation/solver/external_input.h" | ||
| 49 | #include "synchronous.h" | ||
| 50 | #include "linearSystem.h" | ||
| 51 | #include "sym_solver_ssc.h" | ||
| 52 | #include "gbode_main.h" | ||
| 53 | #include "gbode_util.h" | ||
| 54 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 55 | #include "simulation/solver/embedded_server.h" | ||
| 56 | #include "simulation/solver/real_time_sync.h" | ||
| 57 | #endif | ||
| 58 | #include "simulation/simulation_input_xml.h" | ||
| 59 | |||
| 60 | #include "optimization/OptimizerInterface.h" | ||
| 61 | |||
| 62 | /* | ||
| 63 | * #include "dopri45.h" | ||
| 64 | */ | ||
| 65 | #include "util/rtclock.h" | ||
| 66 | #include "util/omc_error.h" | ||
| 67 | #include "simulation/options.h" | ||
| 68 | #include <math.h> | ||
| 69 | #include <string.h> | ||
| 70 | #include <errno.h> | ||
| 71 | #include <float.h> | ||
| 72 | |||
| 73 | double** work_states; | ||
| 74 | |||
| 75 | typedef struct RK4_DATA | ||
| 76 | { | ||
| 77 | double** work_states; | ||
| 78 | int work_states_ndims; | ||
| 79 | const double *b; | ||
| 80 | const double *c; | ||
| 81 | double h; | ||
| 82 | }RK4_DATA; | ||
| 83 | |||
| 84 | |||
| 85 | static int euler_ex_step(DATA* data, SOLVER_INFO* solverInfo); | ||
| 86 | static int rungekutta_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo); | ||
| 87 | static int sym_solver_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo); | ||
| 88 | |||
| 89 | #ifdef OMC_HAVE_IPOPT | ||
| 90 | static int ipopt_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo); | ||
| 91 | #endif | ||
| 92 | |||
| 93 | static void writeOutputVars(char* names, DATA* data); | ||
| 94 | |||
| 95 | 1 | int solver_main_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | |
| 96 | { | ||
| 97 | int retVal; | ||
| 98 | |||
| 99 |
1/10✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
1 | switch(solverInfo->solverMethod) |
| 100 | { | ||
| 101 | ✗ | case S_EULER: | |
| 102 | ✗ | retVal = euler_ex_step(data, solverInfo); | |
| 103 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 104 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 105 | return retVal; | ||
| 106 | ✗ | case S_RUNGEKUTTA: | |
| 107 | ✗ | retVal = rungekutta_step(data, threadData, solverInfo); | |
| 108 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 109 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 110 | return retVal; | ||
| 111 | |||
| 112 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 113 | 1 | case S_DASSL: | |
| 114 | 1 | retVal = dassl_step(data, threadData, solverInfo); | |
| 115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if(omc_flag[FLAG_SOLVER_STEPS]) |
| 116 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 117 | return retVal; | ||
| 118 | #endif | ||
| 119 | |||
| 120 | #ifdef OMC_HAVE_IPOPT | ||
| 121 | ✗ | case S_OPTIMIZATION: | |
| 122 | ✗ | if ((int)(data->modelData->nStates + data->modelData->nInputVars) > 0){ | |
| 123 | retVal = ipopt_step(data, threadData, solverInfo); | ||
| 124 | } else { | ||
| 125 | ✗ | solverInfo->solverMethod = S_EULER; | |
| 126 | ✗ | retVal = euler_ex_step(data, solverInfo); | |
| 127 | } | ||
| 128 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 129 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 130 | return retVal; | ||
| 131 | #endif | ||
| 132 | #ifdef WITH_SUNDIALS | ||
| 133 | ✗ | case S_IDA: | |
| 134 | ✗ | retVal = ida_solver_step(data, threadData, solverInfo); | |
| 135 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 136 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 137 | return retVal; | ||
| 138 | ✗ | case S_CVODE: | |
| 139 | ✗ | retVal = cvode_solver_step(data, threadData, solverInfo); | |
| 140 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 141 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 142 | return retVal; | ||
| 143 | #endif | ||
| 144 | ✗ | case S_SYM_SOLVER: | |
| 145 | ✗ | retVal = sym_solver_step(data, threadData, solverInfo); | |
| 146 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 147 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 148 | return retVal; | ||
| 149 | ✗ | case S_SYM_SOLVER_SSC: | |
| 150 | ✗ | retVal = sym_solver_ssc_step(data, threadData, solverInfo); | |
| 151 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 152 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 153 | return retVal; | ||
| 154 | ✗ | case S_GBODE: | |
| 155 | ✗ | retVal = gbode_main(data, threadData, solverInfo); | |
| 156 | ✗ | if(omc_flag[FLAG_SOLVER_STEPS]) | |
| 157 | ✗ | data->simulationInfo->solverSteps = solverInfo->solverStats.nStepsTaken + solverInfo->solverStatsTmp.nStepsTaken; | |
| 158 | return retVal; | ||
| 159 | ✗ | default: | |
| 160 | ✗ | throwStreamPrint(threadData, "Unhandled case in solver_main_step."); | |
| 161 | } | ||
| 162 | return 1; | ||
| 163 | } | ||
| 164 | |||
| 165 | /*! \fn initializeSolverData(DATA* data, SOLVER_INFO* solverInfo) | ||
| 166 | * | ||
| 167 | * \param [ref] [data] | ||
| 168 | * \param [ref] [solverInfo] | ||
| 169 | * | ||
| 170 | * This function initializes solverInfo. | ||
| 171 | */ | ||
| 172 | 1 | int initializeSolverData(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | |
| 173 | { | ||
| 174 | int retValue = 0; | ||
| 175 | int i; | ||
| 176 | |||
| 177 | 1 | SIMULATION_INFO *simInfo = data->simulationInfo; | |
| 178 | |||
| 179 | /* initial solverInfo */ | ||
| 180 | 1 | solverInfo->currentTime = simInfo->startTime; | |
| 181 | 1 | solverInfo->currentStepSize = simInfo->stepSize; | |
| 182 | 1 | solverInfo->laststep = 0; | |
| 183 | 1 | solverInfo->solverRootFinding = 0; | |
| 184 | 1 | solverInfo->solverNoEquidistantGrid = omc_flag[FLAG_NOEQUIDISTANT_GRID]; | |
| 185 | 1 | solverInfo->lastdesiredStep = solverInfo->currentTime + solverInfo->currentStepSize; | |
| 186 | 1 | solverInfo->eventLst = allocList(eventListAlloc, eventListFree, eventListCopy); | |
| 187 | 1 | solverInfo->didEventStep = 0; | |
| 188 | 1 | solverInfo->stateEvents = 0; | |
| 189 | 1 | solverInfo->sampleEvents = 0; | |
| 190 | 1 | resetSolverStats(&solverInfo->solverStats); | |
| 191 | 1 | resetSolverStats(&solverInfo->solverStatsTmp); | |
| 192 | |||
| 193 |
1/9✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1 | switch (solverInfo->solverMethod) |
| 194 | { | ||
| 195 | case S_SYM_SOLVER: | ||
| 196 | case S_EULER: | ||
| 197 | case S_QSS: break; | ||
| 198 | ✗ | case S_SYM_SOLVER_SSC: | |
| 199 | { | ||
| 200 | ✗ | allocateSymSolverSsc(solverInfo, data->modelData->nStates); | |
| 201 | ✗ | break; | |
| 202 | } | ||
| 203 | ✗ | case S_GBODE: | |
| 204 | { | ||
| 205 | ✗ | if (gbode_allocateData(data, threadData, solverInfo) != 0) { | |
| 206 | ✗ | throwStreamPrint(threadData, "Failed to allocate memory for generic multigrid solver."); | |
| 207 | } | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | ✗ | case S_RUNGEKUTTA: | |
| 211 | { | ||
| 212 | /* Allocate RK work arrays */ | ||
| 213 | |||
| 214 | static const int rungekutta_s = 4; | ||
| 215 | static const double rungekutta_b[4] = { 1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0 }; | ||
| 216 | static const double rungekutta_c[4] = { 0.0, 0.5, 0.5, 1.0 }; | ||
| 217 | |||
| 218 | static const int heun_s = 2; | ||
| 219 | static const double heun_b[2] = { 1.0 / 2.0, 1.0 / 2.0 }; | ||
| 220 | static const double heun_c[2] = { 0.0, 1.0 }; | ||
| 221 | |||
| 222 | ✗ | RK4_DATA* rungeData = (RK4_DATA*) malloc(sizeof(RK4_DATA)); | |
| 223 | |||
| 224 | ✗ | rungeData->work_states_ndims = rungekutta_s; | |
| 225 | ✗ | rungeData->b = rungekutta_b; | |
| 226 | ✗ | rungeData->c = rungekutta_c; | |
| 227 | |||
| 228 | ✗ | rungeData->work_states = (double**) malloc((rungeData->work_states_ndims + 1) * sizeof(double*)); | |
| 229 | ✗ | for (i = 0; i < rungeData->work_states_ndims + 1; i++) { | |
| 230 | ✗ | rungeData->work_states[i] = (double*) calloc(data->modelData->nStates, sizeof(double)); | |
| 231 | } | ||
| 232 | ✗ | solverInfo->solverData = rungeData; | |
| 233 | ✗ | break; | |
| 234 | } | ||
| 235 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 236 | 1 | case S_DASSL: | |
| 237 | { | ||
| 238 | /* Initial DASSL solver */ | ||
| 239 | 1 | DASSL_DATA* dasslData = (DASSL_DATA*) malloc(sizeof(DASSL_DATA)); | |
| 240 | 1 | retValue = dassl_initial(data, threadData, solverInfo, dasslData); | |
| 241 | 1 | solverInfo->solverData = dasslData; | |
| 242 | 1 | break; | |
| 243 | } | ||
| 244 | #endif | ||
| 245 | #ifdef OMC_HAVE_IPOPT | ||
| 246 | ✗ | case S_OPTIMIZATION: | |
| 247 | { | ||
| 248 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Initializing optimizer"); | |
| 249 | /* solverInfo->solverData = malloc(sizeof(OptData)); */ | ||
| 250 | ✗ | break; | |
| 251 | } | ||
| 252 | #endif | ||
| 253 | #ifdef WITH_SUNDIALS | ||
| 254 | ✗ | case S_IDA: | |
| 255 | { | ||
| 256 | IDA_SOLVER* idaData = NULL; | ||
| 257 | /* Allocate ida working data */ | ||
| 258 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Initializing IDA DAE Solver"); | |
| 259 | ✗ | idaData = (IDA_SOLVER*) malloc(sizeof(IDA_SOLVER)); | |
| 260 | ✗ | retValue = ida_solver_initial(data, threadData, solverInfo, idaData); | |
| 261 | ✗ | solverInfo->solverData = idaData; | |
| 262 | ✗ | break; | |
| 263 | } | ||
| 264 | ✗ | case S_CVODE: | |
| 265 | { | ||
| 266 | CVODE_SOLVER* cvodeData = NULL; | ||
| 267 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Initializing CVODE ODE Solver"); | |
| 268 | ✗ | cvodeData = (CVODE_SOLVER*) calloc(1, sizeof(CVODE_SOLVER)); | |
| 269 | ✗ | assertStreamPrint(threadData, cvodeData != NULL, "Out of memory"); | |
| 270 | ✗ | retValue = cvode_solver_initial(data, threadData, solverInfo, cvodeData, 0 /* not FMI */); | |
| 271 | ✗ | solverInfo->solverData = cvodeData; | |
| 272 | ✗ | break; | |
| 273 | } | ||
| 274 | #endif | ||
| 275 | ✗ | default: | |
| 276 | ✗ | errorStreamPrint(OMC_LOG_SOLVER, 0, "Solver %s disabled on this configuration", SOLVER_METHOD_NAME[solverInfo->solverMethod]); | |
| 277 | ✗ | return 1; | |
| 278 | } | ||
| 279 | |||
| 280 | return retValue; | ||
| 281 | } | ||
| 282 | |||
| 283 | /*! \fn updateSolverNominals(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | ||
| 284 | * | ||
| 285 | * \param [ref] [data] | ||
| 286 | * \param [ref] [threadData] | ||
| 287 | * \param [ref] [solverInfo] | ||
| 288 | * | ||
| 289 | * Re-read the states' nominal (and, for gbode, min and max) attributes. A | ||
| 290 | * nominal that is a parameter expression is only computed by | ||
| 291 | * updateBoundVariableAttributes, inside initializeModel, which runs after | ||
| 292 | * initializeSolverData because DAE mode needs the solver during initialization; | ||
| 293 | * until then the solver holds the modelDescription default of 1.0. | ||
| 294 | */ | ||
| 295 | 1 | int updateSolverNominals(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | |
| 296 | { | ||
| 297 |
1/5✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1 | switch (solverInfo->solverMethod) |
| 298 | { | ||
| 299 | ✗ | case S_GBODE: | |
| 300 | ✗ | gbode_setVarAttributes(data, solverInfo->solverData); | |
| 301 | ✗ | break; | |
| 302 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 303 | 1 | case S_DASSL: | |
| 304 | 1 | dassl_setNominals(data, solverInfo->solverData); | |
| 305 | 1 | break; | |
| 306 | #endif | ||
| 307 | #ifdef WITH_SUNDIALS | ||
| 308 | ✗ | case S_IDA: | |
| 309 | ✗ | return ida_solver_setNominals(data, threadData, solverInfo->solverData); | |
| 310 | ✗ | case S_CVODE: | |
| 311 | ✗ | return cvode_solver_setNominals(data, threadData, solverInfo->solverData); | |
| 312 | #endif | ||
| 313 | default: | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | |||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | /*! \fn freeSolver(DATA* data, SOLVER_INFO* solverInfo) | ||
| 321 | * | ||
| 322 | * \param [ref] [data] | ||
| 323 | * \param [ref] [solverInfo] | ||
| 324 | * | ||
| 325 | * This function frees solverInfo. | ||
| 326 | */ | ||
| 327 | 1 | int freeSolverData(DATA* data, SOLVER_INFO* solverInfo) | |
| 328 | { | ||
| 329 | int retValue = 0; | ||
| 330 | int i; | ||
| 331 | |||
| 332 | 1 | freeList(solverInfo->eventLst); | |
| 333 | /* deintialize solver related workspace */ | ||
| 334 |
1/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1 | switch (solverInfo->solverMethod) |
| 335 | { | ||
| 336 | case S_EULER: | ||
| 337 | case S_SYM_SOLVER: | ||
| 338 | case S_QSS: break; | ||
| 339 | ✗ | case S_SYM_SOLVER_SSC: | |
| 340 | ✗ | freeSymSolverSsc(solverInfo); | |
| 341 | ✗ | break; | |
| 342 | case S_RUNGEKUTTA: | ||
| 343 | /* free RK work arrays */ | ||
| 344 | ✗ | for(i = 0; i < ((RK4_DATA*)(solverInfo->solverData))->work_states_ndims + 1; i++) { | |
| 345 | ✗ | free(((RK4_DATA*)(solverInfo->solverData))->work_states[i]); | |
| 346 | } | ||
| 347 | ✗ | free(((RK4_DATA*)(solverInfo->solverData))->work_states); | |
| 348 | ✗ | free((RK4_DATA*)solverInfo->solverData); | |
| 349 | ✗ | break; | |
| 350 | ✗ | case S_GBODE: | |
| 351 | ✗ | gbode_freeData(data, solverInfo->solverData); | |
| 352 | ✗ | solverInfo->solverData = NULL; | |
| 353 | ✗ | break; | |
| 354 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 355 | 1 | case S_DASSL: | |
| 356 | /* De-Initial DASSL solver */ | ||
| 357 | 1 | dassl_deinitial(data, solverInfo->solverData); | |
| 358 | 1 | break; | |
| 359 | #endif | ||
| 360 | #ifdef OMC_HAVE_IPOPT | ||
| 361 | case S_OPTIMIZATION: | ||
| 362 | /* free work arrays */ | ||
| 363 | /*destroyIpopt(solverInfo);*/ | ||
| 364 | break; | ||
| 365 | #endif | ||
| 366 | #ifdef WITH_SUNDIALS | ||
| 367 | ✗ | case S_IDA: | |
| 368 | /* free work arrays */ | ||
| 369 | ✗ | ida_solver_deinitial(solverInfo->solverData); | |
| 370 | ✗ | break; | |
| 371 | ✗ | case S_CVODE: | |
| 372 | /* free work arrays */ | ||
| 373 | ✗ | cvode_solver_deinitial(solverInfo->solverData); | |
| 374 | ✗ | break; | |
| 375 | #endif | ||
| 376 | ✗ | default: | |
| 377 | ✗ | throwStreamPrint(NULL, "Unknown solver %u encountered. Possibly leaking memory!", solverInfo->solverMethod); | |
| 378 | } | ||
| 379 | |||
| 380 | 1 | return retValue; | |
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | /*! \fn initializeModel(DATA* data, const char* init_initMethod, | ||
| 385 | * const char* init_file, double init_time) | ||
| 386 | * | ||
| 387 | * \param [ref] [data] | ||
| 388 | * \param [in] [pInitMethod] user defined initialization method | ||
| 389 | * \param [in] [pInitFile] extra argument for initialization-method "file" | ||
| 390 | * \param [in] [initTime] extra argument for initialization-method "file" | ||
| 391 | * | ||
| 392 | * This function starts the initialization process of the model. | ||
| 393 | */ | ||
| 394 | 1 | int initializeModel(DATA* data, threadData_t *threadData, const char* init_initMethod, | |
| 395 | const char* init_file, double init_time) | ||
| 396 | { | ||
| 397 | 1 | int retValue = 0; | |
| 398 | int usedLocal = 0; | ||
| 399 | |||
| 400 | 1 | SIMULATION_INFO *simInfo = data->simulationInfo; | |
| 401 | |||
| 402 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if(measure_time_flag) |
| 403 | { | ||
| 404 | 1 | rt_accumulate(SIM_TIMER_PREINIT); | |
| 405 | 1 | rt_tick(SIM_TIMER_INIT); | |
| 406 | } | ||
| 407 | |||
| 408 | 1 | copyStartValuestoInitValues(data); | |
| 409 | |||
| 410 | 1 | data->localData[0]->timeValue = simInfo->startTime; | |
| 411 | |||
| 412 | /* read input vars */ | ||
| 413 | 1 | data->callback->input_function_init(data, threadData); | |
| 414 | 1 | externalInputUpdate(data); | |
| 415 | 1 | data->callback->input_function_updateStartValues(data, threadData); | |
| 416 | 1 | data->callback->input_function(data, threadData); | |
| 417 | |||
| 418 | 1 | threadData->currentErrorStage = ERROR_SIMULATION; | |
| 419 | /* try */ | ||
| 420 | { | ||
| 421 | int success = 0; | ||
| 422 | #if !defined(OMC_EMCC) | ||
| 423 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | OMC_TRY_INTERNAL(simulationJumpBuffer) |
| 424 | #endif | ||
| 425 | /* A raised error is reported by the catch below. */ | ||
| 426 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1 | if (initialization(data, threadData, init_initMethod, init_file, init_time) && !OMC_ERROR_RAISED()) |
| 427 | { | ||
| 428 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Error in initialization. Storing results and exiting.\nUse -lv=LOG_INIT -w for more information."); | |
| 429 | ✗ | simInfo->stopTime = simInfo->startTime; | |
| 430 | retValue = -1; | ||
| 431 | } | ||
| 432 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
|
1 | if (!retValue && !OMC_ERROR_RAISED()) |
| 433 | { | ||
| 434 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (data->simulationInfo->homotopySteps == 0) { |
| 435 | 1 | infoStreamPrint(OMC_LOG_SUCCESS, 0, "The initialization finished successfully without homotopy method."); | |
| 436 | } | ||
| 437 | else { | ||
| 438 | ✗ | usedLocal = data->callback->homotopyMethod == LOCAL_EQUIDISTANT_HOMOTOPY || data->callback->homotopyMethod == LOCAL_ADAPTIVE_HOMOTOPY ; | |
| 439 | ✗ | infoStreamPrint(OMC_LOG_SUCCESS, 0, "The initialization finished successfully with %d %shomotopy steps.", data->simulationInfo->homotopySteps, usedLocal? "local ":""); | |
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } else { success = 1; } |
| 444 | #if !defined(OMC_EMCC) | ||
| 445 | 1 | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 446 | #endif | ||
| 447 | |||
| 448 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (!success) |
| 449 | { | ||
| 450 | ✗ | retValue = -1; | |
| 451 | ✗ | infoStreamPrint(OMC_LOG_ASSERT, 0, "simulation terminated by an assertion at initialization"); | |
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | /* adrpo: write the parameter data in the file once again after bound parameters and initialization! */ | ||
| 456 | 1 | sim_result.writeParameterData(&sim_result,data,threadData); | |
| 457 | 1 | infoStreamPrint(OMC_LOG_SOLVER, 0, "Wrote parameters to the file after initialization (for output formats that support this)"); | |
| 458 | |||
| 459 | /* Initialization complete */ | ||
| 460 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (measure_time_flag) { |
| 461 | 1 | rt_accumulate(SIM_TIMER_INIT); | |
| 462 | } | ||
| 463 | |||
| 464 | 1 | return retValue; | |
| 465 | } | ||
| 466 | |||
| 467 | |||
| 468 | /*! \fn finishSimulation(DATA* data, SOLVER_INFO* solverInfo) | ||
| 469 | * | ||
| 470 | * \param [ref] [data] | ||
| 471 | * \param [ref] [solverInfo] | ||
| 472 | * | ||
| 473 | * This function performs the last step | ||
| 474 | * and outputs some statistics, this this simulation terminal step. | ||
| 475 | */ | ||
| 476 | 1 | int finishSimulation(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo, const char* outputVariablesAtEnd) | |
| 477 | { | ||
| 478 | int retValue = 0; | ||
| 479 | int ui; | ||
| 480 | double t, total100; | ||
| 481 | |||
| 482 | 1 | SIMULATION_INFO *simInfo = data->simulationInfo; | |
| 483 | |||
| 484 | /* Last step with terminal()=true */ | ||
| 485 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
|
1 | if (solverInfo->currentTime >= simInfo->stopTime && solverInfo->solverMethod != S_OPTIMIZATION) { |
| 486 | 1 | infoStreamPrint(OMC_LOG_EVENTS_V, 0, "terminal event at stop time %g", solverInfo->currentTime); | |
| 487 | 1 | data->simulationInfo->terminal = 1; | |
| 488 | 1 | updateDiscreteSystem(data, threadData); | |
| 489 | |||
| 490 | /* prevent emit if noeventemit flag is used */ | ||
| 491 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (!(omc_flag[FLAG_NOEVENTEMIT])) { |
| 492 | 1 | sim_result.emit(&sim_result, data, threadData); | |
| 493 | } | ||
| 494 | |||
| 495 | 1 | data->simulationInfo->terminal = 0; | |
| 496 | } | ||
| 497 | |||
| 498 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (0 != strcmp("ia", data->simulationInfo->outputFormat)) { |
| 499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (simInfo->simulationSuccess) { |
| 500 | ✗ | communicateStatus("Finished", 1, solverInfo->currentTime, solverInfo->currentStepSize); | |
| 501 | } else { | ||
| 502 | 1 | communicateStatus("Simulation aborted", (solverInfo->currentTime-simInfo->startTime)/(simInfo->stopTime-simInfo->startTime), solverInfo->currentTime, 0.0); | |
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | /* we have output variables in the command line -output a,b,c */ | ||
| 507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if(outputVariablesAtEnd) |
| 508 | { | ||
| 509 | ✗ | writeOutputVars(omc_strdup(outputVariablesAtEnd), data); | |
| 510 | } | ||
| 511 | |||
| 512 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if(OMC_ACTIVE_STREAM(OMC_LOG_STATS)) |
| 513 | { | ||
| 514 | 1 | rt_accumulate(SIM_TIMER_TOTAL); | |
| 515 | |||
| 516 | 1 | infoStreamPrint(OMC_LOG_STATS, 1, "### STATISTICS ###"); | |
| 517 | |||
| 518 | 1 | total100 = rt_accumulated(SIM_TIMER_TOTAL)/100.0; | |
| 519 | |||
| 520 | 1 | infoStreamPrint(OMC_LOG_STATS, 1, "timer"); | |
| 521 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs reading init.xml", rt_accumulated(SIM_TIMER_INIT_XML)); | |
| 522 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs reading info.xml", rt_accumulated(SIM_TIMER_INFO_XML)); | |
| 523 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] pre-initialization", rt_accumulated(SIM_TIMER_PREINIT), rt_accumulated(SIM_TIMER_PREINIT)/total100); | |
| 524 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] initialization", rt_accumulated(SIM_TIMER_INIT), rt_accumulated(SIM_TIMER_INIT)/total100); | |
| 525 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] steps", rt_accumulated(SIM_TIMER_STEP), rt_accumulated(SIM_TIMER_STEP)/total100); | |
| 526 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] solver (excl. callbacks)", rt_accumulated(SIM_TIMER_SOLVER), rt_accumulated(SIM_TIMER_SOLVER)/total100); | |
| 527 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] creating output-file", rt_accumulated(SIM_TIMER_OUTPUT), rt_accumulated(SIM_TIMER_OUTPUT)/total100); | |
| 528 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] event-handling", rt_accumulated(SIM_TIMER_EVENT), rt_accumulated(SIM_TIMER_EVENT)/total100); | |
| 529 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] overhead", rt_accumulated(SIM_TIMER_OVERHEAD), rt_accumulated(SIM_TIMER_OVERHEAD)/total100); | |
| 530 | |||
| 531 | 1 | t = rt_accumulated(SIM_TIMER_TOTAL)-rt_accumulated(SIM_TIMER_OVERHEAD)-rt_accumulated(SIM_TIMER_EVENT)-rt_accumulated(SIM_TIMER_OUTPUT)-rt_accumulated(SIM_TIMER_STEP)-rt_accumulated(SIM_TIMER_INIT)-rt_accumulated(SIM_TIMER_PREINIT)-rt_accumulated(SIM_TIMER_SOLVER); | |
| 532 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
2 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [%5.1f%%] %s", t, t/total100, S_OPTIMIZATION == solverInfo->solverMethod ? "optimization" : "simulation"); |
| 533 | |||
| 534 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%12gs [100.0%%] total", rt_accumulated(SIM_TIMER_TOTAL)); | |
| 535 | 1 | messageClose(OMC_LOG_STATS); | |
| 536 | |||
| 537 | 1 | infoStreamPrint(OMC_LOG_STATS, 1, "events"); | |
| 538 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5ld state events", solverInfo->stateEvents); | |
| 539 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5ld time events", solverInfo->sampleEvents); | |
| 540 | 1 | messageClose(OMC_LOG_STATS); | |
| 541 | |||
| 542 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if(S_OPTIMIZATION == solverInfo->solverMethod || /* skip solver statistics for optimization */ |
| 543 | S_QSS == solverInfo->solverMethod) /* skip also for qss, since not available*/ | ||
| 544 | { | ||
| 545 | } | ||
| 546 | else | ||
| 547 | { | ||
| 548 | /* save stats before print */ | ||
| 549 | 1 | addSolverStats(&(solverInfo->solverStats), &(solverInfo->solverStatsTmp)); | |
| 550 | |||
| 551 | 1 | infoStreamPrint(OMC_LOG_STATS, 1, "solver: %s", SOLVER_METHOD_NAME[solverInfo->solverMethod]); | |
| 552 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5d steps taken", solverInfo->solverStats.nStepsTaken); | |
| 553 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5d calls of functionODE", solverInfo->solverStats.nCallsODE); | |
| 554 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5d evaluations of jacobian", solverInfo->solverStats.nCallsJacobian); | |
| 555 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5d error test failures", solverInfo->solverStats.nErrorTestFailures); | |
| 556 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%5d convergence test failures", solverInfo->solverStats.nConvergenceTestFailures); | |
| 557 | 1 | infoStreamPrint(OMC_LOG_STATS, 0, "%gs time of jacobian evaluation", rt_accumulated(SIM_TIMER_JACOBIAN)); | |
| 558 | |||
| 559 | 1 | messageClose(OMC_LOG_STATS); | |
| 560 | } | ||
| 561 | |||
| 562 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "function calls"); | |
| 563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (compiledInDAEMode) |
| 564 | { | ||
| 565 | ✗ | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5u calls of functionDAE", rt_ncall(SIM_TIMER_DAE)); | |
| 566 | ✗ | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_DAE), rt_accumulated(SIM_TIMER_DAE)/total100); | |
| 567 | ✗ | messageClose(OMC_LOG_STATS_V); | |
| 568 | } | ||
| 569 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (data->simulationInfo->callStatistics.functionODE) { |
| 570 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5ld calls of functionODE", data->simulationInfo->callStatistics.functionODE); | |
| 571 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_FUNCTION_ODE), rt_accumulated(SIM_TIMER_FUNCTION_ODE)/total100); | |
| 572 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 573 | } | ||
| 574 | |||
| 575 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if (rt_ncall(SIM_TIMER_RESIDUALS)) { |
| 576 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5d calls of functionODE_residual", rt_ncall(SIM_TIMER_RESIDUALS)); | |
| 577 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_RESIDUALS), rt_accumulated(SIM_TIMER_RESIDUALS)/total100); | |
| 578 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 579 | } | ||
| 580 | |||
| 581 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (data->simulationInfo->callStatistics.functionAlgebraics) { |
| 582 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5ld calls of functionAlgebraics", data->simulationInfo->callStatistics.functionAlgebraics); | |
| 583 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_ALGEBRAICS), rt_accumulated(SIM_TIMER_ALGEBRAICS)/total100); | |
| 584 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 585 | } | ||
| 586 | |||
| 587 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5d evaluations of jacobian", rt_ncall(SIM_TIMER_JACOBIAN)); | |
| 588 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_JACOBIAN), rt_accumulated(SIM_TIMER_JACOBIAN)/total100); | |
| 589 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 590 | |||
| 591 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%5ld calls of updateDiscreteSystem", data->simulationInfo->callStatistics.updateDiscreteSystem); | |
| 592 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%5ld calls of functionZeroCrossingsEquations", data->simulationInfo->callStatistics.functionZeroCrossingsEquations); | |
| 593 | |||
| 594 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "%5ld calls of functionZeroCrossings", data->simulationInfo->callStatistics.functionZeroCrossings); | |
| 595 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 0, "%12gs [%5.1f%%]", rt_accumulated(SIM_TIMER_ZC), rt_accumulated(SIM_TIMER_ZC)/total100); | |
| 596 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 597 | |||
| 598 | 1 | messageClose(OMC_LOG_STATS_V); // closes section "function calls" | |
| 599 | |||
| 600 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "linear systems"); | |
| 601 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for(ui=0; ui<data->modelData->nLinearSystems; ui++) |
| 602 | ✗ | printLinearSystemSolvingStatistics(data, ui, OMC_LOG_STATS_V); | |
| 603 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 604 | |||
| 605 | 1 | infoStreamPrint(OMC_LOG_STATS_V, 1, "non-linear systems"); | |
| 606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for(ui=0; ui<data->modelData->nNonLinearSystems; ui++) |
| 607 | ✗ | printNonLinearSystemSolvingStatistics(&data->simulationInfo->nonlinearSystemData[ui], OMC_LOG_STATS_V); | |
| 608 | 1 | messageClose(OMC_LOG_STATS_V); | |
| 609 | |||
| 610 | 1 | messageClose(OMC_LOG_STATS); // closes section "### STATISTICS ###" | |
| 611 | 1 | rt_tick(SIM_TIMER_TOTAL); | |
| 612 | } | ||
| 613 | |||
| 614 | 1 | return retValue; | |
| 615 | } | ||
| 616 | |||
| 617 | /*! \fn solver_main | ||
| 618 | * | ||
| 619 | * \param [ref] [data] | ||
| 620 | * \param [in] [pInitMethod] user defined initialization method | ||
| 621 | * \param [in] [pOptiMethod] user defined optimization method | ||
| 622 | * \param [in] [pInitFile] extra argument for initialization-method "file" | ||
| 623 | * \param [in] [initTime] extra argument for initialization-method "file" | ||
| 624 | * \param [in] [solverID] selects the ode solver | ||
| 625 | * \param [in] [outputVariablesAtEnd] ??? | ||
| 626 | * | ||
| 627 | * This is the main function of the solver, it performs the simulation. | ||
| 628 | */ | ||
| 629 | 1 | int solver_main(DATA* data, threadData_t *threadData, const char* init_initMethod, const char* init_file, | |
| 630 | double init_time, int solverID, const char* outputVariablesAtEnd, const char *argv_0) | ||
| 631 | { | ||
| 632 | int i; | ||
| 633 | /* Read after a longjmp into the catch below. */ | ||
| 634 | 1 | volatile int retVal = 1, initSolverInfo = 0; | |
| 635 | unsigned int ui; | ||
| 636 | SOLVER_INFO solverInfo; | ||
| 637 | 1 | SIMULATION_INFO *simInfo = data->simulationInfo; | |
| 638 | void *dllHandle=NULL; | ||
| 639 | |||
| 640 | 1 | solverInfo.solverMethod = solverID; | |
| 641 | |||
| 642 | /* do some solver specific checks */ | ||
| 643 | switch(solverInfo.solverMethod) | ||
| 644 | { | ||
| 645 | #ifndef OMC_HAVE_IPOPT | ||
| 646 | case S_OPTIMIZATION: | ||
| 647 | warningStreamPrint(OMC_LOG_STDOUT, 0, "Ipopt is needed but not available."); | ||
| 648 | return 1; | ||
| 649 | #endif | ||
| 650 | default: | ||
| 651 | break; | ||
| 652 | } | ||
| 653 | |||
| 654 | /* first initialize the model then allocate SolverData memory | ||
| 655 | * due to be able to use the initialized values for the integrator | ||
| 656 | */ | ||
| 657 | 1 | simInfo->useStopTime = 1; | |
| 658 | |||
| 659 | /* Use minStepSize if stepSize is getting too small, but | ||
| 660 | * allow stepSize to be zero if startTime == stopTime. | ||
| 661 | */ | ||
| 662 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if ((simInfo->stepSize < simInfo->minStepSize) && (simInfo->stopTime > simInfo->startTime)){ |
| 663 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "The step-size %g is too small. Adjust the step-size to %g.", simInfo->stepSize, simInfo->minStepSize); | |
| 664 | ✗ | simInfo->stepSize = simInfo->minStepSize; | |
| 665 | ✗ | simInfo->numSteps = round((simInfo->stopTime - simInfo->startTime)/simInfo->stepSize); | |
| 666 | } | ||
| 667 | /* Check step size is not larger then stopTime-startTime, up to 6 decimals | ||
| 668 | * Ignored when linearizing model */ | ||
| 669 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1 | if (!data->modelData->create_linearmodel && simInfo->stepSize > (simInfo->stopTime - simInfo->startTime + 1e-7)) { |
| 670 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 1, "Integrator step size greater than length of experiment"); | |
| 671 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "start time: %f, stop time: %f, integrator step size: %f",simInfo->startTime, simInfo->stopTime, simInfo->stepSize); | |
| 672 | ✗ | messageCloseWarning(OMC_LOG_STDOUT); | |
| 673 | } | ||
| 674 | #if !defined(OMC_EMCC) | ||
| 675 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | OMC_TRY_INTERNAL(simulationJumpBuffer) |
| 676 | #endif | ||
| 677 | |||
| 678 | /* initialize external input structure */ | ||
| 679 | 1 | externalInputallocate(data); | |
| 680 | /* set tolerance for ZeroCrossings */ | ||
| 681 | 1 | setZCtol(fmin(data->simulationInfo->stepSize, data->simulationInfo->tolerance)); | |
| 682 | 1 | omc_alloc_interface.collect_a_little(); | |
| 683 | |||
| 684 | /* initialize solver data */ | ||
| 685 | /* For the DAEmode we need to initialize solverData before the initialization, | ||
| 686 | * since the solver is used to obtain consistent values also via updateDiscreteSystem | ||
| 687 | */ | ||
| 688 | 1 | retVal = initializeSolverData(data, threadData, &solverInfo); | |
| 689 | 1 | initSolverInfo = 1; | |
| 690 | |||
| 691 | /* initialize all parts of the model */ | ||
| 692 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (0 == retVal){ |
| 693 | 1 | retVal = initializeModel(data, threadData, init_initMethod, init_file, init_time); | |
| 694 | 1 | omc_alloc_interface.collect_a_little(); | |
| 695 | } | ||
| 696 | |||
| 697 | /* the nominal values are only final now */ | ||
| 698 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (0 == retVal){ |
| 699 | 1 | retVal = updateSolverNominals(data, threadData, &solverInfo); | |
| 700 | } | ||
| 701 | |||
| 702 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 703 | 1 | dllHandle = embedded_server_load_functions(omc_flagValue[FLAG_EMBEDDED_SERVER]); | |
| 704 | 1 | omc_real_time_sync_init(threadData, data); | |
| 705 | int port = 4841; | ||
| 706 | /* If an embedded server is specified */ | ||
| 707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (dllHandle != NULL) { |
| 708 | ✗ | if (omc_flag[FLAG_EMBEDDED_SERVER_PORT]) { | |
| 709 | ✗ | port = atoi(omc_flagValue[FLAG_EMBEDDED_SERVER_PORT]); | |
| 710 | /* In case of a bad conversion, don't spawn a server on port 0...*/ | ||
| 711 | ✗ | if (port == 0) { | |
| 712 | port = 4841; | ||
| 713 | } | ||
| 714 | } | ||
| 715 | } | ||
| 716 | 1 | data->embeddedServerState = embedded_server_init(data, data->localData[0]->timeValue, solverInfo.currentStepSize, argv_0, omc_real_time_sync_update, port); | |
| 717 | /* If an embedded server is specified */ | ||
| 718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (dllHandle != NULL) { |
| 719 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "The embedded server is initialized."); | |
| 720 | } | ||
| 721 | 1 | wait_for_step(data->embeddedServerState); | |
| 722 | #endif | ||
| 723 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if(0 == retVal) { |
| 724 | 1 | retVal = -1; | |
| 725 | /* if the model has no time changing variables skip the main loop*/ | ||
| 726 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if(data->modelData->nVariablesReal == 0 && |
| 727 | ✗ | data->modelData->nVariablesInteger == 0 && | |
| 728 | ✗ | data->modelData->nVariablesBoolean == 0 && | |
| 729 | ✗ | data->modelData->nVariablesString == 0 ) { | |
| 730 | /* prevent emit if noeventemit flag is used */ | ||
| 731 | ✗ | if (!(omc_flag[FLAG_NOEVENTEMIT])) { | |
| 732 | ✗ | sim_result.emit(&sim_result, data, threadData); | |
| 733 | } | ||
| 734 | |||
| 735 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "The model has no time changing variables, no integration will be performed."); | |
| 736 | ✗ | solverInfo.currentTime = simInfo->stopTime; | |
| 737 | ✗ | data->localData[0]->timeValue = simInfo->stopTime; | |
| 738 | ✗ | overwriteOldSimulationData(data); | |
| 739 | ✗ | retVal = finishSimulation(data, threadData, &solverInfo, outputVariablesAtEnd); | |
| 740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | } else if(S_QSS == solverInfo.solverMethod) { |
| 741 | /* starts the simulation main loop - special solvers */ | ||
| 742 | ✗ | sim_result.emit(&sim_result,data,threadData); | |
| 743 | |||
| 744 | /* overwrite the whole ring-buffer with initialized values */ | ||
| 745 | ✗ | overwriteOldSimulationData(data); | |
| 746 | |||
| 747 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Start numerical integration (startTime: %g, stopTime: %g)", simInfo->startTime, simInfo->stopTime); | |
| 748 | ✗ | retVal = data->callback->performQSSSimulation(data, threadData, &solverInfo); | |
| 749 | ✗ | omc_alloc_interface.collect_a_little(); | |
| 750 | |||
| 751 | /* terminate the simulation */ | ||
| 752 | ✗ | finishSimulation(data, threadData, &solverInfo, outputVariablesAtEnd); | |
| 753 | ✗ | omc_alloc_interface.collect_a_little(); | |
| 754 | } else { | ||
| 755 | /* starts the simulation main loop - standard solver interface */ | ||
| 756 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if(omc_flag[FLAG_SOLVER_STEPS]) |
| 757 | ✗ | data->simulationInfo->solverSteps = 0; | |
| 758 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if(solverInfo.solverMethod != S_OPTIMIZATION) { |
| 759 | 1 | sim_result.emit(&sim_result,data,threadData); | |
| 760 | } | ||
| 761 | |||
| 762 | /* overwrite the whole ring-buffer with initialized values */ | ||
| 763 | 1 | overwriteOldSimulationData(data); | |
| 764 | |||
| 765 | /* store all values for non-dassl event search */ | ||
| 766 | 1 | storeOldValues(data); | |
| 767 | |||
| 768 | 1 | infoStreamPrint(OMC_LOG_SOLVER, 0, "Start numerical solver from %g to %g", simInfo->startTime, simInfo->stopTime); | |
| 769 | 1 | retVal = data->callback->performSimulation(data, threadData, &solverInfo); | |
| 770 | 1 | omc_alloc_interface.collect_a_little(); | |
| 771 | /* terminate the simulation */ | ||
| 772 | //if (solverInfo.solverMethod == S_SYM_SOLVER_SSC) data->callback->symbolicInlineSystems(data, threadData, 0, 2); | ||
| 773 | 1 | finishSimulation(data, threadData, &solverInfo, outputVariablesAtEnd); | |
| 774 | 1 | omc_alloc_interface.collect_a_little(); | |
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (data->real_time_sync.enabled) { |
| 779 | ✗ | int tMaxLate=0; | |
| 780 | ✗ | const char *unit = prettyPrintNanoSec(data->real_time_sync.maxLate, &tMaxLate); | |
| 781 | ✗ | infoStreamPrint(OMC_LOG_RT, 0, "Maximum real-time latency was (positive=missed dealine, negative is slack): %d %s", tMaxLate, unit); | |
| 782 | } | ||
| 783 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 784 | 1 | embedded_server_deinit(data->embeddedServerState); | |
| 785 | 1 | embedded_server_unload_functions(dllHandle); | |
| 786 | #endif | ||
| 787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } |
| 788 | |||
| 789 | #if !defined(OMC_EMCC) | ||
| 790 | 1 | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 791 | #endif | ||
| 792 | |||
| 793 | /* free external input data */ | ||
| 794 | 1 | externalInputFree(data); | |
| 795 | |||
| 796 | /* free SolverInfo memory */ | ||
| 797 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (initSolverInfo) |
| 798 | { | ||
| 799 | 1 | freeSolverData(data, &solverInfo); | |
| 800 | } | ||
| 801 | |||
| 802 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (!retVal) |
| 803 | 1 | infoStreamPrint(OMC_LOG_SUCCESS, 0, "The simulation finished successfully."); | |
| 804 | |||
| 805 | 1 | return retVal; | |
| 806 | } | ||
| 807 | |||
| 808 | /*************************************** EULER_EXP *********************************/ | ||
| 809 | ✗ | static int euler_ex_step(DATA* data, SOLVER_INFO* solverInfo) | |
| 810 | { | ||
| 811 | int i; | ||
| 812 | ✗ | SIMULATION_DATA *sData = (SIMULATION_DATA*)data->localData[0]; | |
| 813 | ✗ | SIMULATION_DATA *sDataOld = (SIMULATION_DATA*)data->localData[1]; | |
| 814 | ✗ | modelica_real* stateDer = sDataOld->realVars + data->modelData->nStates; | |
| 815 | |||
| 816 | ✗ | if (measure_time_flag) rt_tick(SIM_TIMER_SOLVER); | |
| 817 | |||
| 818 | ✗ | solverInfo->currentTime = sDataOld->timeValue + solverInfo->currentStepSize; | |
| 819 | |||
| 820 | ✗ | for(i = 0; i < data->modelData->nStates; i++) | |
| 821 | { | ||
| 822 | ✗ | sData->realVars[i] = sDataOld->realVars[i] + stateDer[i] * solverInfo->currentStepSize; | |
| 823 | } | ||
| 824 | ✗ | sData->timeValue = solverInfo->currentTime; | |
| 825 | |||
| 826 | /* save stats */ | ||
| 827 | /* steps */ | ||
| 828 | ✗ | solverInfo->solverStatsTmp.nStepsTaken += 1; | |
| 829 | /* function ODE evaluation is done directly after this function */ | ||
| 830 | ✗ | solverInfo->solverStatsTmp.nCallsODE += 1; | |
| 831 | |||
| 832 | ✗ | if (measure_time_flag) rt_accumulate(SIM_TIMER_SOLVER); | |
| 833 | |||
| 834 | ✗ | return 0; | |
| 835 | } | ||
| 836 | |||
| 837 | /*************************************** SYM_SOLVER *********************************/ | ||
| 838 | ✗ | static int sym_solver_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo){ | |
| 839 | int retVal = 0, i; | ||
| 840 | |||
| 841 | ✗ | modelica_integer nStates = data->modelData->nStates; | |
| 842 | ✗ | SIMULATION_DATA *sData = data->localData[0]; | |
| 843 | ✗ | SIMULATION_DATA *sDataOld = data->localData[1]; | |
| 844 | ✗ | modelica_real* stateDer = sDataOld->realVars + data->modelData->nStates; | |
| 845 | |||
| 846 | ✗ | if (solverInfo->currentStepSize >= DASSL_STEP_EPS){ | |
| 847 | /* time */ | ||
| 848 | ✗ | solverInfo->currentTime = sDataOld->timeValue + solverInfo->currentStepSize; | |
| 849 | ✗ | sData->timeValue = solverInfo->currentTime; | |
| 850 | /* update dt */ | ||
| 851 | ✗ | data->simulationInfo->inlineData->dt = solverInfo->currentStepSize; | |
| 852 | /* copy old states to workspace */ | ||
| 853 | ✗ | memcpy(data->simulationInfo->inlineData->algOldVars, sDataOld->realVars, nStates * sizeof(double)); | |
| 854 | ✗ | memcpy(sData->realVars, sDataOld->realVars, nStates * sizeof(double)); | |
| 855 | |||
| 856 | /* read input vars */ | ||
| 857 | ✗ | externalInputUpdate(data); | |
| 858 | ✗ | data->callback->input_function(data, threadData); | |
| 859 | ✗ | retVal = data->callback->symbolicInlineSystems(data, threadData); | |
| 860 | |||
| 861 | ✗ | if(retVal != 0){ | |
| 862 | return -1; | ||
| 863 | } | ||
| 864 | |||
| 865 | |||
| 866 | /* update der(x) */ | ||
| 867 | ✗ | for(i=0; i<nStates; ++i) | |
| 868 | { | ||
| 869 | ✗ | stateDer[i] = (sData->realVars[i]-data->simulationInfo->inlineData->algOldVars[i])/solverInfo->currentStepSize; | |
| 870 | } | ||
| 871 | |||
| 872 | /* save stats */ | ||
| 873 | /* steps */ | ||
| 874 | ✗ | solverInfo->solverStatsTmp.nStepsTaken += 1; | |
| 875 | /* function ODE evaluation is done directly after this */ | ||
| 876 | ✗ | solverInfo->solverStatsTmp.nCallsODE += 1; | |
| 877 | } | ||
| 878 | else | ||
| 879 | /* in case desired step size is too small */ | ||
| 880 | { | ||
| 881 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Desired step to small try next one"); | |
| 882 | ✗ | infoStreamPrint(OMC_LOG_SOLVER, 0, "Interpolate linear"); | |
| 883 | |||
| 884 | /* explicit euler step*/ | ||
| 885 | ✗ | for(i = 0; i < nStates; i++) | |
| 886 | { | ||
| 887 | ✗ | sData->realVars[i] = sDataOld->realVars[i] + stateDer[i] * solverInfo->currentStepSize; | |
| 888 | } | ||
| 889 | ✗ | sData->timeValue = solverInfo->currentTime + solverInfo->currentStepSize; | |
| 890 | ✗ | solverInfo->currentTime = sData->timeValue; | |
| 891 | } | ||
| 892 | return retVal; | ||
| 893 | } | ||
| 894 | |||
| 895 | /*************************************** RK4 ***********************************/ | ||
| 896 | ✗ | static int rungekutta_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | |
| 897 | { | ||
| 898 | ✗ | RK4_DATA *rk = ((RK4_DATA*)(solverInfo->solverData)); | |
| 899 | ✗ | double** k = rk->work_states; | |
| 900 | double sum; | ||
| 901 | int i,j; | ||
| 902 | ✗ | SIMULATION_DATA *sData = (SIMULATION_DATA*)data->localData[0]; | |
| 903 | ✗ | SIMULATION_DATA *sDataOld = (SIMULATION_DATA*)data->localData[1]; | |
| 904 | ✗ | modelica_real* stateDer = sData->realVars + data->modelData->nStates; | |
| 905 | ✗ | modelica_real* stateDerOld = sDataOld->realVars + data->modelData->nStates; | |
| 906 | |||
| 907 | ✗ | if (measure_time_flag) rt_tick(SIM_TIMER_SOLVER); | |
| 908 | |||
| 909 | ✗ | solverInfo->currentTime = sDataOld->timeValue + solverInfo->currentStepSize; | |
| 910 | |||
| 911 | /* We calculate k[0] before returning from this function. | ||
| 912 | * We only want to calculate f() 4 times per call */ | ||
| 913 | ✗ | memcpy(k[0], stateDerOld, data->modelData->nStates*sizeof(modelica_real)); | |
| 914 | |||
| 915 | ✗ | for (j = 1; j < rk->work_states_ndims; j++) | |
| 916 | { | ||
| 917 | ✗ | for(i = 0; i < data->modelData->nStates; i++) | |
| 918 | { | ||
| 919 | ✗ | sData->realVars[i] = sDataOld->realVars[i] + solverInfo->currentStepSize * rk->c[j] * k[j - 1][i]; | |
| 920 | } | ||
| 921 | ✗ | sData->timeValue = sDataOld->timeValue + rk->c[j] * solverInfo->currentStepSize; | |
| 922 | ✗ | if (measure_time_flag) rt_accumulate(SIM_TIMER_SOLVER); | |
| 923 | /* read input vars */ | ||
| 924 | ✗ | externalInputUpdate(data); | |
| 925 | ✗ | data->callback->input_function(data, threadData); | |
| 926 | /* eval ode equations */ | ||
| 927 | ✗ | data->callback->functionODE(data, threadData); | |
| 928 | ✗ | if (measure_time_flag) rt_tick(SIM_TIMER_SOLVER); | |
| 929 | ✗ | memcpy(k[j], stateDer, data->modelData->nStates*sizeof(modelica_real)); | |
| 930 | |||
| 931 | } | ||
| 932 | |||
| 933 | ✗ | for(i = 0; i < data->modelData->nStates; i++) | |
| 934 | { | ||
| 935 | sum = 0; | ||
| 936 | ✗ | for(j = 0; j < rk->work_states_ndims; j++) | |
| 937 | { | ||
| 938 | ✗ | sum = sum + rk->b[j] * k[j][i]; | |
| 939 | } | ||
| 940 | ✗ | sData->realVars[i] = sDataOld->realVars[i] + solverInfo->currentStepSize * sum; | |
| 941 | } | ||
| 942 | ✗ | sData->timeValue = solverInfo->currentTime; | |
| 943 | |||
| 944 | /* save stats */ | ||
| 945 | /* steps */ | ||
| 946 | ✗ | solverInfo->solverStatsTmp.nStepsTaken += 1; | |
| 947 | /* function ODE evaluation is done directly after this */ | ||
| 948 | ✗ | solverInfo->solverStatsTmp.nCallsODE += rk->work_states_ndims+1; | |
| 949 | ✗ | if (measure_time_flag) rt_accumulate(SIM_TIMER_SOLVER); | |
| 950 | |||
| 951 | ✗ | return 0; | |
| 952 | } | ||
| 953 | |||
| 954 | /*************************************** Run Ipopt for optimization ***********************************/ | ||
| 955 | #if defined(OMC_HAVE_IPOPT) | ||
| 956 | static int ipopt_step(DATA* data, threadData_t *threadData, SOLVER_INFO* solverInfo) | ||
| 957 | { | ||
| 958 | int cJ, res; | ||
| 959 | |||
| 960 | ✗ | cJ = threadData->currentErrorStage; | |
| 961 | ✗ | threadData->currentErrorStage = ERROR_OPTIMIZE; | |
| 962 | ✗ | res = runOptimizer(data, threadData, solverInfo); | |
| 963 | ✗ | threadData->currentErrorStage = cJ; | |
| 964 | return res; | ||
| 965 | } | ||
| 966 | #endif | ||
| 967 | |||
| 968 | ✗ | static void writeOutputVars(char* names, DATA* data) | |
| 969 | { | ||
| 970 | int i = 0; | ||
| 971 | char *p = NULL; | ||
| 972 | /* fix names to contain | instead of , for splitting */ | ||
| 973 | ✗ | parseVariableStr(names); | |
| 974 | ✗ | p = strtok(names, "!"); | |
| 975 | |||
| 976 | ✗ | fprintf(stdout, "time=%.20g", data->localData[0]->timeValue); | |
| 977 | |||
| 978 | ✗ | while(p) | |
| 979 | { | ||
| 980 | ✗ | for(i = 0; i < data->modelData->nVariablesReal; i++) | |
| 981 | ✗ | if(!strcmp(p, data->modelData->realVarsData[i].info.name)) | |
| 982 | ✗ | fprintf(stdout, ",%s=%.20g", p, (data->localData[0])->realVars[i]); | |
| 983 | ✗ | for(i = 0; i < data->modelData->nVariablesInteger; i++) | |
| 984 | ✗ | if(!strcmp(p, data->modelData->integerVarsData[i].info.name)) | |
| 985 | ✗ | fprintf(stdout, ",%s=" OMC_INT_FORMAT, p, (data->localData[0])->integerVars[i]); | |
| 986 | ✗ | for(i = 0; i < data->modelData->nVariablesBoolean; i++) | |
| 987 | ✗ | if(!strcmp(p, data->modelData->booleanVarsData[i].info.name)) | |
| 988 | ✗ | fprintf(stdout, ",%s=%i", p, (data->localData[0])->booleanVars[i]); | |
| 989 | ✗ | for(i = 0; i < data->modelData->nVariablesString; i++) | |
| 990 | ✗ | if(!strcmp(p, data->modelData->stringVarsData[i].info.name)) | |
| 991 | ✗ | fprintf(stdout, ",%s=\"%s\"", p, omc_string_data((data->localData[0])->stringVars[i])); | |
| 992 | |||
| 993 | ✗ | for(i = 0; i < data->modelData->nAliasReal; i++) | |
| 994 | ✗ | if(!strcmp(p, data->modelData->realAlias[i].info.name)) | |
| 995 | { | ||
| 996 | ✗ | if(data->modelData->realAlias[i].negate) | |
| 997 | ✗ | fprintf(stdout, ",%s=%.20g", p, -(data->localData[0])->realVars[data->modelData->realAlias[i].nameID]); | |
| 998 | else | ||
| 999 | ✗ | fprintf(stdout, ",%s=%.20g", p, (data->localData[0])->realVars[data->modelData->realAlias[i].nameID]); | |
| 1000 | } | ||
| 1001 | ✗ | for(i = 0; i < data->modelData->nAliasInteger; i++) | |
| 1002 | ✗ | if(!strcmp(p, data->modelData->integerAlias[i].info.name)) | |
| 1003 | { | ||
| 1004 | ✗ | if(data->modelData->integerAlias[i].negate) | |
| 1005 | ✗ | fprintf(stdout, ",%s=" OMC_INT_FORMAT, p, -(data->localData[0])->integerVars[data->modelData->integerAlias[i].nameID]); | |
| 1006 | else | ||
| 1007 | ✗ | fprintf(stdout, ",%s=" OMC_INT_FORMAT, p, (data->localData[0])->integerVars[data->modelData->integerAlias[i].nameID]); | |
| 1008 | } | ||
| 1009 | ✗ | for(i = 0; i < data->modelData->nAliasBoolean; i++) | |
| 1010 | ✗ | if(!strcmp(p, data->modelData->booleanAlias[i].info.name)) | |
| 1011 | { | ||
| 1012 | ✗ | if(data->modelData->booleanAlias[i].negate) | |
| 1013 | ✗ | fprintf(stdout, ",%s=%i", p, -(data->localData[0])->booleanVars[data->modelData->booleanAlias[i].nameID]); | |
| 1014 | else | ||
| 1015 | ✗ | fprintf(stdout, ",%s=%i", p, (data->localData[0])->booleanVars[data->modelData->booleanAlias[i].nameID]); | |
| 1016 | } | ||
| 1017 | ✗ | for(i = 0; i < data->modelData->nAliasString; i++) | |
| 1018 | ✗ | if(!strcmp(p, data->modelData->stringAlias[i].info.name)) | |
| 1019 | ✗ | fprintf(stdout, ",%s=\"%s\"", p, omc_string_data((data->localData[0])->stringVars[data->modelData->stringAlias[i].nameID])); | |
| 1020 | |||
| 1021 | /* parameters */ | ||
| 1022 | ✗ | for(i = 0; i < data->modelData->nParametersReal; i++) | |
| 1023 | ✗ | if(!strcmp(p, data->modelData->realParameterData[i].info.name)) | |
| 1024 | ✗ | fprintf(stdout, ",%s=%.20g", p, data->simulationInfo->realParameter[i]); | |
| 1025 | |||
| 1026 | ✗ | for(i = 0; i < data->modelData->nParametersInteger; i++) | |
| 1027 | ✗ | if(!strcmp(p, data->modelData->integerParameterData[i].info.name)) | |
| 1028 | ✗ | fprintf(stdout, ",%s=" OMC_INT_FORMAT, p, data->simulationInfo->integerParameter[i]); | |
| 1029 | |||
| 1030 | ✗ | for(i = 0; i < data->modelData->nParametersBoolean; i++) | |
| 1031 | ✗ | if(!strcmp(p, data->modelData->booleanParameterData[i].info.name)) | |
| 1032 | ✗ | fprintf(stdout, ",%s=%i", p, data->simulationInfo->booleanParameter[i]); | |
| 1033 | |||
| 1034 | ✗ | for(i = 0; i < data->modelData->nParametersString; i++) | |
| 1035 | ✗ | if(!strcmp(p, data->modelData->stringParameterData[i].info.name)) | |
| 1036 | ✗ | fprintf(stdout, ",%s=\"%s\"", p, omc_string_data(data->simulationInfo->stringParameter[i])); | |
| 1037 | |||
| 1038 | /* move to next */ | ||
| 1039 | ✗ | p = strtok(NULL, "!"); | |
| 1040 | } | ||
| 1041 | ✗ | fprintf(stdout, "\n"); fflush(stdout); | |
| 1042 | ✗ | } | |
| 1043 | |||
| 1044 | /** | ||
| 1045 | * @brief Set all solver stats to zero. | ||
| 1046 | * | ||
| 1047 | * @param stats Pointer to solver stats. | ||
| 1048 | */ | ||
| 1049 | 2 | void resetSolverStats(SOLVERSTATS* stats) { | |
| 1050 | 2 | stats->nStepsTaken = 0; | |
| 1051 | 2 | stats->nCallsODE = 0; | |
| 1052 | 2 | stats->nCallsJacobian = 0; | |
| 1053 | 2 | stats->nErrorTestFailures = 0; | |
| 1054 | 2 | stats->nConvergenceTestFailures = 0; | |
| 1055 | 2 | } | |
| 1056 | |||
| 1057 | /** | ||
| 1058 | * @brief Add two solver statistics. | ||
| 1059 | * | ||
| 1060 | * destStats += addStats | ||
| 1061 | * | ||
| 1062 | * @param destStats Pointer to solver stats to add stats to. | ||
| 1063 | * On return has result of addition. | ||
| 1064 | * @param addStats Pointer to solver stats to add. | ||
| 1065 | */ | ||
| 1066 | 1 | void addSolverStats(SOLVERSTATS* destStats, SOLVERSTATS* addStats) { | |
| 1067 | 1 | destStats->nStepsTaken += addStats->nStepsTaken; | |
| 1068 | 1 | destStats->nCallsODE += addStats->nCallsODE; | |
| 1069 | 1 | destStats->nCallsJacobian += addStats->nCallsJacobian; | |
| 1070 | 1 | destStats->nErrorTestFailures += addStats->nErrorTestFailures; | |
| 1071 | 1 | destStats->nConvergenceTestFailures += addStats->nConvergenceTestFailures; | |
| 1072 | 1 | } | |
| 1073 |