OMCompiler/SimulationRuntime/c/simulation/solver/nonlinearSystem.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 nonlinearSystem.c | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <math.h> | ||
| 32 | #include <string.h> | ||
| 33 | |||
| 34 | #include "../jacobian_util.h" | ||
| 35 | #include "../../util/simulation_options.h" | ||
| 36 | #include "../../util/omc_error.h" | ||
| 37 | #include "../../util/omc_file.h" | ||
| 38 | #include "nonlinearSystem.h" | ||
| 39 | #include "nonlinearValuesList.h" | ||
| 40 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 41 | #include "kinsolSolver.h" | ||
| 42 | #include "kinsol_b.h" | ||
| 43 | #include "nonlinearSolverHybrd.h" | ||
| 44 | #include "nonlinearSolverNewton.h" | ||
| 45 | #include "newtonIteration.h" | ||
| 46 | #include "newton_diagnostics.h" | ||
| 47 | #endif | ||
| 48 | #include "nonlinearSolverHomotopy.h" | ||
| 49 | #include "../options.h" | ||
| 50 | #include "../simulation_info_json.h" | ||
| 51 | #include "../simulation_runtime.h" | ||
| 52 | #include "model_help.h" | ||
| 53 | |||
| 54 | int check_nonlinear_solution(DATA *data, int printFailingSystems, int sysNumber); | ||
| 55 | |||
| 56 | extern int init_lambda_steps; | ||
| 57 | |||
| 58 | struct dataMixedSolver | ||
| 59 | { | ||
| 60 | void* newtonHomotopyData; | ||
| 61 | void* hybridData; | ||
| 62 | }; | ||
| 63 | |||
| 64 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 65 | #include "../../util/write_csv.h" | ||
| 66 | |||
| 67 | /*! \fn int initializeNLScsvData(DATA* data, NONLINEAR_SYSTEM_DATA* systemData) | ||
| 68 | * | ||
| 69 | * This function initializes csv files for analysis propose. | ||
| 70 | * | ||
| 71 | * \param [ref] [data] | ||
| 72 | * \param [ref] [systemData] | ||
| 73 | */ | ||
| 74 | ✗ | int initializeNLScsvData(DATA* data, NONLINEAR_SYSTEM_DATA* systemData) | |
| 75 | { | ||
| 76 | ✗ | struct csvStats* stats = (struct csvStats*) malloc(sizeof(struct csvStats)); | |
| 77 | char buffer[100]; | ||
| 78 | ✗ | sprintf(buffer, "%s_NLS%dStatsCall.csv", data->modelData->modelFilePrefix, (int)systemData->equationIndex); | |
| 79 | ✗ | stats->callStats = omc_write_csv_init(buffer, ',', '"'); | |
| 80 | |||
| 81 | ✗ | sprintf(buffer, "%s_NLS%dStatsIter.csv", data->modelData->modelFilePrefix, (int)systemData->equationIndex); | |
| 82 | ✗ | stats->iterStats = omc_write_csv_init(buffer, ',', '"'); | |
| 83 | |||
| 84 | ✗ | systemData->csvData = stats; | |
| 85 | |||
| 86 | ✗ | return 0; | |
| 87 | } | ||
| 88 | #else | ||
| 89 | ✗ | int initializeNLScsvData(DATA* data, NONLINEAR_SYSTEM_DATA* systemData) | |
| 90 | { | ||
| 91 | ✗ | fprintf(stderr, "initializeNLScsvData not implemented for OMC_MINIMAL_RUNTIME"); | |
| 92 | ✗ | abort(); | |
| 93 | } | ||
| 94 | #endif | ||
| 95 | |||
| 96 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 97 | /*! \fn int print_csvLineCallStatsHeader(OMC_WRITE_CSV* csvData) | ||
| 98 | * | ||
| 99 | * This function initializes csv files for analysis propose. | ||
| 100 | * | ||
| 101 | * \param [ref] [data] | ||
| 102 | * \param [ref] [systemData] | ||
| 103 | */ | ||
| 104 | ✗ | int print_csvLineCallStatsHeader(OMC_WRITE_CSV* csvData) | |
| 105 | { | ||
| 106 | char buffer[1024]; | ||
| 107 | ✗ | buffer[0] = 0; | |
| 108 | |||
| 109 | /* number of call */ | ||
| 110 | sprintf(buffer,"numberOfCall"); | ||
| 111 | ✗ | omc_write_csv(csvData, buffer); | |
| 112 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 113 | |||
| 114 | /* simulation time */ | ||
| 115 | sprintf(buffer,"simulationTime"); | ||
| 116 | ✗ | omc_write_csv(csvData, buffer); | |
| 117 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 118 | |||
| 119 | /* solving iterations */ | ||
| 120 | sprintf(buffer,"iterations"); | ||
| 121 | ✗ | omc_write_csv(csvData, buffer); | |
| 122 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 123 | |||
| 124 | /* solving fCalls */ | ||
| 125 | sprintf(buffer,"numberOfFunctionCall"); | ||
| 126 | ✗ | omc_write_csv(csvData, buffer); | |
| 127 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 128 | |||
| 129 | /* solving Time */ | ||
| 130 | sprintf(buffer,"solvingTime"); | ||
| 131 | ✗ | omc_write_csv(csvData, buffer); | |
| 132 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 133 | |||
| 134 | /* solving Time */ | ||
| 135 | sprintf(buffer,"solvedSystem"); | ||
| 136 | ✗ | omc_write_csv(csvData, buffer); | |
| 137 | |||
| 138 | /* finish line */ | ||
| 139 | ✗ | fputc('\n',csvData->handle); | |
| 140 | |||
| 141 | ✗ | return 0; | |
| 142 | } | ||
| 143 | |||
| 144 | /*! \fn int print_csvLineCallStats(OMC_WRITE_CSV* csvData) | ||
| 145 | * | ||
| 146 | * This function initializes csv files for analysis propose. | ||
| 147 | * | ||
| 148 | * \param [ref] [csvData] | ||
| 149 | * \param [in] [number of calls] | ||
| 150 | * \param [in] [simulation time] | ||
| 151 | * \param [in] [iterations] | ||
| 152 | * \param [in] [number of function call] | ||
| 153 | * \param [in] [solving time] | ||
| 154 | * \param [in] [solved system] | ||
| 155 | */ | ||
| 156 | ✗ | int print_csvLineCallStats(OMC_WRITE_CSV* csvData, int num, double time, | |
| 157 | int iterations, int fCalls, double solvingTime, | ||
| 158 | NLS_SOLVER_STATUS solved) | ||
| 159 | { | ||
| 160 | char buffer[1024]; | ||
| 161 | |||
| 162 | /* number of call */ | ||
| 163 | sprintf(buffer, "%d", num); | ||
| 164 | ✗ | omc_write_csv(csvData, buffer); | |
| 165 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 166 | |||
| 167 | /* simulation time */ | ||
| 168 | sprintf(buffer, "%g", time); | ||
| 169 | ✗ | omc_write_csv(csvData, buffer); | |
| 170 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 171 | |||
| 172 | /* solving iterations */ | ||
| 173 | sprintf(buffer, "%d", iterations); | ||
| 174 | ✗ | omc_write_csv(csvData, buffer); | |
| 175 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 176 | |||
| 177 | /* solving fCalls */ | ||
| 178 | sprintf(buffer, "%d", fCalls); | ||
| 179 | ✗ | omc_write_csv(csvData, buffer); | |
| 180 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 181 | |||
| 182 | /* solving Time */ | ||
| 183 | sprintf(buffer, "%f", solvingTime); | ||
| 184 | ✗ | omc_write_csv(csvData, buffer); | |
| 185 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 186 | |||
| 187 | /* solved system */ | ||
| 188 | ✗ | sprintf(buffer, "%s", (solved == NLS_SOLVED || solved == NLS_SOLVED_LESS_ACCURACY)?"TRUE":"FALSE"); | |
| 189 | ✗ | omc_write_csv(csvData, buffer); | |
| 190 | |||
| 191 | /* finish line */ | ||
| 192 | ✗ | fputc('\n',csvData->handle); | |
| 193 | |||
| 194 | ✗ | return 0; | |
| 195 | } | ||
| 196 | |||
| 197 | /*! \fn int print_csvLineIterStatsHeader(OMC_WRITE_CSV* csvData) | ||
| 198 | * | ||
| 199 | * This function initializes csv files for analysis propose. | ||
| 200 | * | ||
| 201 | * \param [ref] [data] | ||
| 202 | * \param [ref] [systemData] | ||
| 203 | */ | ||
| 204 | ✗ | int print_csvLineIterStatsHeader(DATA* data, NONLINEAR_SYSTEM_DATA* systemData, OMC_WRITE_CSV* csvData) | |
| 205 | { | ||
| 206 | char buffer[1024]; | ||
| 207 | int j; | ||
| 208 | ✗ | int size = modelInfoGetEquation(&data->modelData->modelDataXml, systemData->equationIndex).numVar; | |
| 209 | |||
| 210 | /* number of call */ | ||
| 211 | sprintf(buffer,"numberOfCall"); | ||
| 212 | ✗ | omc_write_csv(csvData, buffer); | |
| 213 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 214 | |||
| 215 | /* solving iterations */ | ||
| 216 | sprintf(buffer,"iteration"); | ||
| 217 | ✗ | omc_write_csv(csvData, buffer); | |
| 218 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 219 | |||
| 220 | /* variables x */ | ||
| 221 | ✗ | for(j=0; j<size; ++j) { | |
| 222 | ✗ | sprintf(buffer, "%s", modelInfoGetEquation(&data->modelData->modelDataXml, systemData->equationIndex).vars[j]); | |
| 223 | ✗ | omc_write_csv(csvData, buffer); | |
| 224 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 225 | } | ||
| 226 | |||
| 227 | /* residuals */ | ||
| 228 | ✗ | for(j=0; j<size; ++j) { | |
| 229 | ✗ | sprintf(buffer, "r%d", j+1); | |
| 230 | ✗ | omc_write_csv(csvData, buffer); | |
| 231 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 232 | } | ||
| 233 | |||
| 234 | /* delta x */ | ||
| 235 | sprintf(buffer,"delta_x"); | ||
| 236 | ✗ | omc_write_csv(csvData, buffer); | |
| 237 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 238 | |||
| 239 | /* delta x scaled */ | ||
| 240 | sprintf(buffer,"delta_x_scaled"); | ||
| 241 | ✗ | omc_write_csv(csvData, buffer); | |
| 242 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 243 | |||
| 244 | /* error in f */ | ||
| 245 | sprintf(buffer,"error_f"); | ||
| 246 | ✗ | omc_write_csv(csvData, buffer); | |
| 247 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 248 | |||
| 249 | /* error in f scaled */ | ||
| 250 | sprintf(buffer,"error_f_scaled"); | ||
| 251 | ✗ | omc_write_csv(csvData, buffer); | |
| 252 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 253 | |||
| 254 | /* damping lambda */ | ||
| 255 | sprintf(buffer,"lambda"); | ||
| 256 | ✗ | omc_write_csv(csvData, buffer); | |
| 257 | |||
| 258 | /* finish line */ | ||
| 259 | ✗ | fputc('\n',csvData->handle); | |
| 260 | |||
| 261 | ✗ | return 0; | |
| 262 | } | ||
| 263 | |||
| 264 | /*! \fn int print_csvLineIterStatsHeader(OMC_WRITE_CSV* csvData) | ||
| 265 | * | ||
| 266 | * This function initializes csv files for analysis propose. | ||
| 267 | * | ||
| 268 | * \param [ref] [csvData] | ||
| 269 | * \param [in] [size, num, ...] | ||
| 270 | */ | ||
| 271 | ✗ | int print_csvLineIterStats(void* voidCsvData, int size, int num, | |
| 272 | int iteration, double* x, double* f, double error_f, | ||
| 273 | double error_fs, double delta_x, double delta_xs, | ||
| 274 | double lambda) | ||
| 275 | { | ||
| 276 | OMC_WRITE_CSV* csvData = voidCsvData; | ||
| 277 | char buffer[1024]; | ||
| 278 | int j; | ||
| 279 | |||
| 280 | /* number of call */ | ||
| 281 | sprintf(buffer, "%d", num); | ||
| 282 | ✗ | omc_write_csv(csvData, buffer); | |
| 283 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 284 | |||
| 285 | /* simulation time */ | ||
| 286 | sprintf(buffer, "%d", iteration); | ||
| 287 | ✗ | omc_write_csv(csvData, buffer); | |
| 288 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 289 | |||
| 290 | /* x */ | ||
| 291 | ✗ | for(j=0; j<size; ++j) { | |
| 292 | ✗ | sprintf(buffer, "%g", x[j]); | |
| 293 | ✗ | omc_write_csv(csvData, buffer); | |
| 294 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 295 | } | ||
| 296 | |||
| 297 | /* r */ | ||
| 298 | ✗ | for(j=0; j<size; ++j) { | |
| 299 | ✗ | sprintf(buffer, "%g", f[j]); | |
| 300 | ✗ | omc_write_csv(csvData, buffer); | |
| 301 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 302 | } | ||
| 303 | |||
| 304 | /* error_f */ | ||
| 305 | sprintf(buffer, "%g", error_f); | ||
| 306 | ✗ | omc_write_csv(csvData, buffer); | |
| 307 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 308 | |||
| 309 | /* error_f */ | ||
| 310 | sprintf(buffer, "%g", error_fs); | ||
| 311 | ✗ | omc_write_csv(csvData, buffer); | |
| 312 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 313 | |||
| 314 | /* delta_x */ | ||
| 315 | sprintf(buffer, "%g", delta_x); | ||
| 316 | ✗ | omc_write_csv(csvData, buffer); | |
| 317 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 318 | |||
| 319 | /* delta_xs */ | ||
| 320 | sprintf(buffer, "%g", delta_xs); | ||
| 321 | ✗ | omc_write_csv(csvData, buffer); | |
| 322 | ✗ | fputc(csvData->seperator,csvData->handle); | |
| 323 | |||
| 324 | /* lambda */ | ||
| 325 | sprintf(buffer, "%g", lambda); | ||
| 326 | ✗ | omc_write_csv(csvData, buffer); | |
| 327 | |||
| 328 | /* finish line */ | ||
| 329 | ✗ | fputc('\n',csvData->handle); | |
| 330 | |||
| 331 | ✗ | return 0; | |
| 332 | } | ||
| 333 | #endif | ||
| 334 | |||
| 335 | /** | ||
| 336 | * @brief Allocate and initialize NLS user data. | ||
| 337 | * | ||
| 338 | * NLS user data is passed to 3rdParty non-linear solvers, to be used | ||
| 339 | * in e.g. residual and Jacobian functions provided by C runtime. | ||
| 340 | * | ||
| 341 | * @param data Pointer to data. | ||
| 342 | * @param threadData Pointer to thread data. | ||
| 343 | * @param sysNumber Index of non-linear system. | ||
| 344 | * A non-negative index indicates that nlsData is a pointer to | ||
| 345 | * data->simulationInfo->nonlinearSystemData[sysNumber] | ||
| 346 | * @param nlsData Pointer to non-linear system data corresponding to sysNumber. | ||
| 347 | * @param analyticJacobian Pointer to analytic Jacobian. Can be NULL. | ||
| 348 | * @return NLS_USERDATA* Newly allocated struct with NLS user data. | ||
| 349 | */ | ||
| 350 | ✗ | NLS_USERDATA* initNlsUserData(DATA* data, threadData_t* threadData, int sysNumber, NONLINEAR_SYSTEM_DATA* nlsData, JACOBIAN* analyticJacobian) { | |
| 351 | ✗ | NLS_USERDATA* userData = (NLS_USERDATA*) malloc(sizeof(NLS_USERDATA)); | |
| 352 | ✗ | assertStreamPrint(threadData, userData != NULL, "setNlsUserData failed: userData is NULL"); | |
| 353 | |||
| 354 | ✗ | userData->data = data; | |
| 355 | ✗ | userData->threadData = threadData; | |
| 356 | ✗ | userData->sysNumber = sysNumber; | |
| 357 | ✗ | userData->nlsData = nlsData; | |
| 358 | ✗ | userData->analyticJacobian = analyticJacobian; | |
| 359 | ✗ | userData->solverData = NULL; | |
| 360 | |||
| 361 | ✗ | return userData; | |
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * @brief Free NLS user data struct. | ||
| 366 | * | ||
| 367 | * Only frees memory of NLS data struct, not of its members. | ||
| 368 | * | ||
| 369 | * @param userData Pointer to NLS user data. | ||
| 370 | */ | ||
| 371 | ✗ | void freeNlsUserData(NLS_USERDATA* userData) { | |
| 372 | ✗ | free(userData); | |
| 373 | ✗ | } | |
| 374 | |||
| 375 | /* The adaptive homotopy methods solve for lambda alongside the unknowns, so | ||
| 376 | * they take one unknown off the system and add it back as a column. */ | ||
| 377 | static inline modelica_boolean adaptiveHomotopy(DATA *data, NONLINEAR_SYSTEM_DATA *nonlinsys) | ||
| 378 | { | ||
| 379 | ✗ | return nonlinsys->homotopySupport | |
| 380 | ✗ | && (data->callback->homotopyMethod == GLOBAL_ADAPTIVE_HOMOTOPY | |
| 381 | ✗ | || data->callback->homotopyMethod == LOCAL_ADAPTIVE_HOMOTOPY); | |
| 382 | } | ||
| 383 | |||
| 384 | /** | ||
| 385 | * @brief Initialize internal structure of non-linear system. | ||
| 386 | * | ||
| 387 | * @param data Runtime data struct. | ||
| 388 | * @param threadData Thread data for error handling. | ||
| 389 | * @param nonlinsys Pointer to non-linear system. | ||
| 390 | * @param sysNum Number of non-linear system. | ||
| 391 | */ | ||
| 392 | ✗ | void initializeNonlinearSystemData(DATA *data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA *nonlinsys, int sysNum) { | |
| 393 | modelica_integer size; | ||
| 394 | struct dataSolver *solverData; | ||
| 395 | struct dataMixedSolver *mixedSolverData; | ||
| 396 | JACOBIAN* jacobian; | ||
| 397 | |||
| 398 | ✗ | size = nonlinsys->size; | |
| 399 | ✗ | nonlinsys->numberOfFEval = 0; | |
| 400 | ✗ | nonlinsys->numberOfIterations = 0; | |
| 401 | |||
| 402 | /* check if residual function pointer are valid */ | ||
| 403 | ✗ | assertStreamPrint(threadData, (nonlinsys->residualFunc != NULL) || (nonlinsys->strictTearingFunctionCall != NULL), "residual function pointer is invalid"); | |
| 404 | |||
| 405 | /* check if analytical jacobian is created */ | ||
| 406 | ✗ | if(nonlinsys->jacobianIndex != -1) | |
| 407 | { | ||
| 408 | ✗ | jacobian = &(data->simulationInfo->analyticJacobians[nonlinsys->jacobianIndex]); | |
| 409 | ✗ | assertStreamPrint(threadData, 0 != nonlinsys->analyticalJacobianColumn, "jacobian function pointer is invalid" ); | |
| 410 | ✗ | if(nonlinsys->initialAnalyticalJacobian(data, threadData, jacobian)) | |
| 411 | { | ||
| 412 | ✗ | nonlinsys->jacobianIndex = -1; | |
| 413 | /* simulation_data.h documents analyticalJacobianColumn==NULL as THE signal | ||
| 414 | * that no analytic Jacobian is available; clear it here too, not just | ||
| 415 | * jacobianIndex, so every consumer agrees (e.g. kinsolSolver.c's | ||
| 416 | * initKinsolMemory only checks analyticalJacobianColumn, not jacobianIndex, | ||
| 417 | * to decide whether to wire up the symbolic-Jacobian KINSOL callback -- left | ||
| 418 | * dangling non-NULL here, it would still select that callback, which then | ||
| 419 | * fails an assertion pulling a JACOBIAN* through the now -1 jacobianIndex). */ | ||
| 420 | ✗ | nonlinsys->analyticalJacobianColumn = NULL; | |
| 421 | jacobian = NULL; | ||
| 422 | } | ||
| 423 | /* evalJacobian() fills sizeRows*sizeCols entries, the solvers hand it a | ||
| 424 | * rows x (rows+1) buffer. A wider Jacobian would run over it, and its | ||
| 425 | * columns would not be the iteration variables either. */ | ||
| 426 | ✗ | else if(jacobian->sizeRows != (adaptiveHomotopy(data, nonlinsys) ? size - 1 : size) || jacobian->sizeCols != size) | |
| 427 | { | ||
| 428 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Analytic Jacobian of non-linear system %d is %ux%u, but the system has " OMC_INT_FORMAT " iteration variables. " | |
| 429 | "This indicates that something went wrong during Jacobian generation. " | ||
| 430 | "Using a numeric Jacobian instead.", | ||
| 431 | sysNum, jacobian->sizeRows, jacobian->sizeCols, size); | ||
| 432 | ✗ | nonlinsys->jacobianIndex = -1; | |
| 433 | ✗ | nonlinsys->analyticalJacobianColumn = NULL; | |
| 434 | jacobian = NULL; | ||
| 435 | } | ||
| 436 | } else { | ||
| 437 | jacobian = NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | /* allocate system data; zeroed because the "last solving is too long ago" branch | ||
| 441 | * of solve_nonlinear_system leaves nlsxExtrapolation -- which solveHomotopy and | ||
| 442 | * solveHybrd start a non-discrete call from -- unwritten. */ | ||
| 443 | ✗ | nonlinsys->nlsx = (double*) calloc(size, sizeof(double)); | |
| 444 | ✗ | nonlinsys->nlsxExtrapolation = (double*) calloc(size, sizeof(double)); | |
| 445 | ✗ | nonlinsys->nlsxOld = (double*) calloc(size, sizeof(double)); | |
| 446 | ✗ | nonlinsys->resValues = (double*) calloc(size, sizeof(double)); | |
| 447 | |||
| 448 | /* allocate value list*/ | ||
| 449 | ✗ | nonlinsys->oldValueList = allocValueList(1, nonlinsys->size); | |
| 450 | |||
| 451 | ✗ | nonlinsys->lastTimeSolved = 0.0; | |
| 452 | |||
| 453 | /* Allocate nomianl, min and max */ | ||
| 454 | ✗ | nonlinsys->nominal = (double*) malloc(size*sizeof(double)); | |
| 455 | ✗ | nonlinsys->min = (double*) malloc(size*sizeof(double)); | |
| 456 | ✗ | nonlinsys->max = (double*) malloc(size*sizeof(double)); | |
| 457 | /* Init sparsitiy pattern */ | ||
| 458 | ✗ | nonlinsys->initializeStaticNLSData(data, threadData, nonlinsys, 1 /* true */, 1 /* true */); | |
| 459 | |||
| 460 | ✗ | if(nonlinsys->sparsePattern) { | |
| 461 | /* only test for singularity if sparsity pattern is supposed to be there */ | ||
| 462 | ✗ | modelica_boolean useSparsityPattern = sparsitySanityCheck(nonlinsys->sparsePattern, nonlinsys->size, OMC_LOG_NLS); | |
| 463 | ✗ | if (!useSparsityPattern) { | |
| 464 | // free sparsity pattern and don't use scaling | ||
| 465 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Sparsity pattern for non-linear system %d is not regular. " | |
| 466 | "This indicates that something went wrong during sparsity pattern generation. " | ||
| 467 | "Removing sparsity pattern and disabling NLS scaling.", sysNum); | ||
| 468 | /* DEBUG */ | ||
| 469 | //printSparseStructure(nonlinsys->sparsePattern, nonlinsys->size, nonlinsys->size, OMC_LOG_NLS, "NLS sparse pattern"); | ||
| 470 | ✗ | freeSparsePattern(nonlinsys->sparsePattern); | |
| 471 | ✗ | nonlinsys->sparsePattern = NULL; | |
| 472 | ✗ | omc_flag[FLAG_NO_SCALING] = TRUE; | |
| 473 | } | ||
| 474 | } | ||
| 475 | |||
| 476 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 477 | /* csv data call stats*/ | ||
| 478 | ✗ | if (data->simulationInfo->nlsCsvInfomation) | |
| 479 | { | ||
| 480 | ✗ | if (initializeNLScsvData(data, nonlinsys)) | |
| 481 | { | ||
| 482 | ✗ | throwStreamPrint(threadData, "csvData initialization failed"); | |
| 483 | } | ||
| 484 | else | ||
| 485 | { | ||
| 486 | ✗ | print_csvLineCallStatsHeader(((struct csvStats*) nonlinsys->csvData)->callStats); | |
| 487 | ✗ | print_csvLineIterStatsHeader(data, nonlinsys, ((struct csvStats*) nonlinsys->csvData)->iterStats); | |
| 488 | } | ||
| 489 | } | ||
| 490 | #endif | ||
| 491 | |||
| 492 | ✗ | nonlinsys->nlsMethod = data->simulationInfo->nlsMethod; | |
| 493 | ✗ | nonlinsys->nlsLinearSolver = data->simulationInfo->nlsLinearSolver; | |
| 494 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 495 | ✗ | if (nonlinsys->matrixFormat == OMC_MATRIX_SPARSE && nonlinsys->sparsePattern | |
| 496 | ✗ | && !(data->simulationInfo->nlsMethod == NLS_KINSOL || data->simulationInfo->nlsMethod == NLS_KINSOL_B)) | |
| 497 | { | ||
| 498 | ✗ | nonlinsys->nlsMethod = NLS_KINSOL; | |
| 499 | ✗ | nonlinsys->nlsLinearSolver = NLS_LS_KLU; | |
| 500 | } | ||
| 501 | #endif | ||
| 502 | |||
| 503 | /* Set NLS user data */ | ||
| 504 | ✗ | NLS_USERDATA* nlsUserData = initNlsUserData(data, threadData, sysNum, nonlinsys, jacobian); | |
| 505 | |||
| 506 | // FIXME: add generation of scalar system (total system size = 1) to codegen | ||
| 507 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 508 | /* check for trivial sparsity pattern (is not always generated) */ | ||
| 509 | ✗ | if (nonlinsys->size == 1 && !nonlinsys->sparsePattern && (nonlinsys->nlsMethod == NLS_KINSOL || nonlinsys->nlsMethod == NLS_KINSOL_B)) { | |
| 510 | ✗ | nonlinsys->nlsMethod = NLS_HYBRID; | |
| 511 | ✗ | nonlinsys->nlsLinearSolver = NLS_LS_DEFAULT; | |
| 512 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Sparsity pattern for non-linear system %d with size 1x1 (nnz = 1) does not exist. " | |
| 513 | "Can not use the set sparse NLS solver - changing the method to Hybrid.", sysNum); | ||
| 514 | } | ||
| 515 | #endif | ||
| 516 | |||
| 517 | /* allocate stuff depending on the chosen method */ | ||
| 518 | ✗ | switch(nonlinsys->nlsMethod) | |
| 519 | { | ||
| 520 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 521 | ✗ | case NLS_HYBRID: | |
| 522 | ✗ | solverData = (struct dataSolver*) malloc(sizeof(struct dataSolver)); | |
| 523 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 524 | ✗ | solverData->ordinaryData = allocateHybrdData(size-1, nlsUserData); | |
| 525 | ✗ | nlsUserData = initNlsUserData(data, threadData, sysNum, nonlinsys, jacobian); /* Seperate userData for homotopy solver */ | |
| 526 | ✗ | solverData->initHomotopyData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 527 | } else { | ||
| 528 | ✗ | solverData->ordinaryData = allocateHybrdData(size, nlsUserData); | |
| 529 | } | ||
| 530 | ✗ | nonlinsys->solverData = (void*) solverData; | |
| 531 | ✗ | break; | |
| 532 | ✗ | case NLS_KINSOL: | |
| 533 | ✗ | solverData = (struct dataSolver*) malloc(sizeof(struct dataSolver)); | |
| 534 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 535 | ✗ | solverData->initHomotopyData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 536 | } else { | ||
| 537 | ✗ | nonlinsys->solverData = (void*) nlsKinsolAllocate(size, nlsUserData, TRUE, !!nonlinsys->sparsePattern); | |
| 538 | ✗ | solverData->ordinaryData = nonlinsys->solverData; | |
| 539 | } | ||
| 540 | ✗ | nonlinsys->solverData = (void*) solverData; | |
| 541 | ✗ | break; | |
| 542 | ✗ | case NLS_KINSOL_B: | |
| 543 | ✗ | solverData = (struct dataSolver*) malloc(sizeof(struct dataSolver)); | |
| 544 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 545 | ✗ | solverData->initHomotopyData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 546 | } else { | ||
| 547 | ✗ | nonlinsys->solverData = (void*) B_nlsKinsolAllocate(size, nlsUserData, TRUE, !!nonlinsys->sparsePattern); | |
| 548 | ✗ | solverData->ordinaryData = nonlinsys->solverData; | |
| 549 | } | ||
| 550 | ✗ | nonlinsys->solverData = (void*) solverData; | |
| 551 | ✗ | break; | |
| 552 | ✗ | case NLS_NEWTON: | |
| 553 | ✗ | solverData = (struct dataSolver*) malloc(sizeof(struct dataSolver)); | |
| 554 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 555 | ✗ | solverData->ordinaryData = (void*) allocateNewtonData(size-1, nlsUserData); | |
| 556 | ✗ | nlsUserData = initNlsUserData(data, threadData, sysNum, nonlinsys, jacobian); /* Seperate userData for homotopy solver */ | |
| 557 | ✗ | solverData->initHomotopyData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 558 | } else { | ||
| 559 | ✗ | solverData->ordinaryData = (void*) allocateNewtonData(size, nlsUserData); | |
| 560 | } | ||
| 561 | ✗ | nonlinsys->solverData = (void*) solverData; | |
| 562 | ✗ | break; | |
| 563 | ✗ | case NLS_MIXED: | |
| 564 | ✗ | mixedSolverData = (struct dataMixedSolver*) malloc(sizeof(struct dataMixedSolver)); | |
| 565 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 566 | ✗ | mixedSolverData->newtonHomotopyData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 567 | ✗ | nlsUserData = initNlsUserData(data, threadData, sysNum, nonlinsys, jacobian); /* Seperate userData for hybrid solver */ | |
| 568 | ✗ | mixedSolverData->hybridData = (void*) allocateHybrdData(size-1, nlsUserData); | |
| 569 | } else { | ||
| 570 | ✗ | mixedSolverData->newtonHomotopyData = (void*) allocateHomotopyData(size, nlsUserData); | |
| 571 | ✗ | nlsUserData = initNlsUserData(data, threadData, sysNum, nonlinsys, jacobian); /* Seperate userData for hybrid solver */ | |
| 572 | ✗ | mixedSolverData->hybridData = (void*) allocateHybrdData(size, nlsUserData); | |
| 573 | } | ||
| 574 | ✗ | nonlinsys->solverData = (void*) mixedSolverData; | |
| 575 | ✗ | break; | |
| 576 | #endif | ||
| 577 | case NLS_HOMOTOPY: | ||
| 578 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 579 | ✗ | nonlinsys->solverData = (void*) allocateHomotopyData(size-1, nlsUserData); | |
| 580 | } else { | ||
| 581 | ✗ | nonlinsys->solverData = (void*) allocateHomotopyData(size, nlsUserData); | |
| 582 | } | ||
| 583 | break; | ||
| 584 | ✗ | default: | |
| 585 | ✗ | throwStreamPrint(threadData, "unrecognized nonlinear solver"); | |
| 586 | } | ||
| 587 | |||
| 588 | ✗ | return; | |
| 589 | } | ||
| 590 | |||
| 591 | /** | ||
| 592 | * @brief Initialize all non-linear systems. | ||
| 593 | * | ||
| 594 | * Loop over all non-linear systems and call initializeNonlinearSystemData. | ||
| 595 | * Memory for data->simulationInfo->nonlinearSystemData is already allocated. | ||
| 596 | * | ||
| 597 | * @param data Runtime data struct. | ||
| 598 | * @param threadData Thread data for error handling. | ||
| 599 | * @return int Return 0 on success. | ||
| 600 | */ | ||
| 601 | 1 | int initializeNonlinearSystems(DATA *data, threadData_t *threadData) | |
| 602 | { | ||
| 603 | int i; | ||
| 604 | 1 | NONLINEAR_SYSTEM_DATA *nonlinsys = data->simulationInfo->nonlinearSystemData; | |
| 605 | |||
| 606 | 1 | infoStreamPrint(OMC_LOG_NLS, 1, "initialize non-linear system solvers"); | |
| 607 | 1 | infoStreamPrint(OMC_LOG_NLS, 0, "%ld non-linear systems", data->modelData->nNonLinearSystems); | |
| 608 | |||
| 609 | /* set the default nls linear solver depending on the default nls method */ | ||
| 610 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (data->simulationInfo->nlsLinearSolver == NLS_LS_DEFAULT) { |
| 611 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 612 | /* kinsol works best with KLU, | ||
| 613 | they are both sparse so it makes sense to use them together */ | ||
| 614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (data->simulationInfo->nlsMethod == NLS_KINSOL || data->simulationInfo->nlsMethod == NLS_KINSOL_B) { |
| 615 | ✗ | data->simulationInfo->nlsLinearSolver = NLS_LS_KLU; | |
| 616 | } else { | ||
| 617 | 1 | data->simulationInfo->nlsLinearSolver = NLS_LS_LAPACK; | |
| 618 | } | ||
| 619 | #else | ||
| 620 | ✗ | data->simulationInfo->nlsLinearSolver = NLS_LS_LAPACK; | |
| 621 | #endif | ||
| 622 | } | ||
| 623 | |||
| 624 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (i=0; i<data->modelData->nNonLinearSystems; ++i) { |
| 625 | ✗ | initializeNonlinearSystemData(data, threadData, &nonlinsys[i], i); | |
| 626 | } | ||
| 627 | |||
| 628 | 1 | messageClose(OMC_LOG_NLS); | |
| 629 | |||
| 630 | 1 | return 0; | |
| 631 | } | ||
| 632 | |||
| 633 | /** | ||
| 634 | * @brief Initialize min, max, nominal for non-linear systems. | ||
| 635 | * | ||
| 636 | * This function allocates memory for sparsity pattern and | ||
| 637 | * initialized nominal, min, max and spsarsity pattern. | ||
| 638 | * | ||
| 639 | * @param data Pointer to data. | ||
| 640 | * @param threadData Thread data for error handling. | ||
| 641 | * @return int Return 0. | ||
| 642 | */ | ||
| 643 | 1 | int updateStaticDataOfNonlinearSystems(DATA *data, threadData_t *threadData) | |
| 644 | { | ||
| 645 | int i; | ||
| 646 | int size; | ||
| 647 | 1 | NONLINEAR_SYSTEM_DATA *nonlinsys = data->simulationInfo->nonlinearSystemData; | |
| 648 | |||
| 649 | 1 | infoStreamPrint(OMC_LOG_NLS, 1, "update static data of non-linear system solvers"); | |
| 650 | |||
| 651 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for(i=0; i<data->modelData->nNonLinearSystems; ++i) |
| 652 | { | ||
| 653 | ✗ | nonlinsys[i].initializeStaticNLSData(data, threadData, &nonlinsys[i], FALSE, FALSE); | |
| 654 | } | ||
| 655 | |||
| 656 | 1 | messageClose(OMC_LOG_NLS); | |
| 657 | |||
| 658 | 1 | return 0; | |
| 659 | } | ||
| 660 | |||
| 661 | /** | ||
| 662 | * @brief Free non-linear system data. | ||
| 663 | * | ||
| 664 | * Freeing non-linear solver data as well. | ||
| 665 | * | ||
| 666 | * @param data Pointer to data struct. | ||
| 667 | * @param threadData Pointer to thread data. Used for error handling. | ||
| 668 | * @param nonlinsys Pointer to non-linear system data. | ||
| 669 | */ | ||
| 670 | ✗ | void freeNonlinearSyst(DATA* data, threadData_t* threadData, NONLINEAR_SYSTEM_DATA* nonlinsys) | |
| 671 | { | ||
| 672 | struct csvStats* stats; | ||
| 673 | NLS_USERDATA* userData; | ||
| 674 | |||
| 675 | ✗ | free(nonlinsys->nlsx); | |
| 676 | ✗ | free(nonlinsys->nlsxExtrapolation); | |
| 677 | ✗ | free(nonlinsys->nlsxOld); | |
| 678 | ✗ | free(nonlinsys->resValues); | |
| 679 | ✗ | free(nonlinsys->nominal); | |
| 680 | ✗ | free(nonlinsys->min); | |
| 681 | ✗ | free(nonlinsys->max); | |
| 682 | ✗ | free(nonlinsys->eqn_simcode_indices); | |
| 683 | ✗ | nonlinsys->eqn_simcode_indices = NULL; | |
| 684 | ✗ | nonlinsys->freeStaticNLSData(data, threadData, nonlinsys); | |
| 685 | |||
| 686 | ✗ | freeValueList(nonlinsys->oldValueList, 1); | |
| 687 | ✗ | freeNonlinearPattern(nonlinsys->nonlinearPattern); | |
| 688 | ✗ | nonlinsys->nonlinearPattern = NULL; | |
| 689 | |||
| 690 | /* Free CSV data */ | ||
| 691 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 692 | ✗ | if (data->simulationInfo->nlsCsvInfomation) | |
| 693 | { | ||
| 694 | ✗ | stats = nonlinsys->csvData; | |
| 695 | ✗ | omc_write_csv_free(stats->callStats); | |
| 696 | ✗ | omc_write_csv_free(stats->iterStats); | |
| 697 | ✗ | free(nonlinsys->csvData); | |
| 698 | // TODO: Make a function freeNLScsvData | ||
| 699 | } | ||
| 700 | #endif | ||
| 701 | |||
| 702 | /* free solver data */ | ||
| 703 | // TODO: Make this simpler. Don't cast nonlinsys->solverData back and forth. | ||
| 704 | // Always have a structure accepting two solver methods (primary and backup) and make the missing one NULL. | ||
| 705 | // Also just set nonlinsys->solverData->ordinaryData to NULL, if no hybrid solver is available | ||
| 706 | // and make freeHybrdData(NULL) work. | ||
| 707 | ✗ | switch(nonlinsys->nlsMethod) | |
| 708 | { | ||
| 709 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 710 | ✗ | case NLS_HYBRID: | |
| 711 | ✗ | freeHybrdData(((struct dataSolver*) nonlinsys->solverData)->ordinaryData); | |
| 712 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 713 | ✗ | freeHomotopyData(((struct dataSolver*) nonlinsys->solverData)->initHomotopyData); | |
| 714 | } | ||
| 715 | ✗ | free(nonlinsys->solverData); | |
| 716 | ✗ | break; | |
| 717 | case NLS_KINSOL: | ||
| 718 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 719 | ✗ | freeHomotopyData(((struct dataSolver*) nonlinsys->solverData)->initHomotopyData); | |
| 720 | } else { | ||
| 721 | ✗ | nlsKinsolFree(((struct dataSolver*) nonlinsys->solverData)->ordinaryData); | |
| 722 | } | ||
| 723 | ✗ | free(nonlinsys->solverData); | |
| 724 | ✗ | break; | |
| 725 | case NLS_KINSOL_B: | ||
| 726 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 727 | ✗ | freeHomotopyData(((struct dataSolver*) nonlinsys->solverData)->initHomotopyData); | |
| 728 | } else { | ||
| 729 | ✗ | B_nlsKinsolFree(((struct dataSolver*) nonlinsys->solverData)->ordinaryData); | |
| 730 | } | ||
| 731 | ✗ | free(nonlinsys->solverData); | |
| 732 | ✗ | break; | |
| 733 | ✗ | case NLS_NEWTON: | |
| 734 | ✗ | freeNewtonData(((struct dataSolver*) nonlinsys->solverData)->ordinaryData); | |
| 735 | if (adaptiveHomotopy(data, nonlinsys)) { | ||
| 736 | ✗ | freeHomotopyData(((struct dataSolver*) nonlinsys->solverData)->initHomotopyData); | |
| 737 | } | ||
| 738 | ✗ | free(nonlinsys->solverData); | |
| 739 | ✗ | break; | |
| 740 | #endif | ||
| 741 | ✗ | case NLS_HOMOTOPY: | |
| 742 | ✗ | freeHomotopyData(nonlinsys->solverData); | |
| 743 | ✗ | break; | |
| 744 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 745 | ✗ | case NLS_MIXED: | |
| 746 | ✗ | freeHomotopyData(((struct dataMixedSolver*) nonlinsys->solverData)->newtonHomotopyData); | |
| 747 | ✗ | freeHybrdData(((struct dataMixedSolver*) nonlinsys->solverData)->hybridData); | |
| 748 | ✗ | free(nonlinsys->solverData); | |
| 749 | ✗ | break; | |
| 750 | #endif | ||
| 751 | ✗ | default: | |
| 752 | ✗ | throwStreamPrint(threadData, "freeNonlinearSyst: Unrecognized non-linear solver method"); | |
| 753 | } | ||
| 754 | |||
| 755 | ✗ | return; | |
| 756 | } | ||
| 757 | |||
| 758 | /** | ||
| 759 | * @brief Free memory for all non-linear systems in simulationInfo. | ||
| 760 | * | ||
| 761 | * Free all non-linear systems from array data->simulationInfo->nonlinearSystemData. | ||
| 762 | * | ||
| 763 | * @param data Pointer to data struct. | ||
| 764 | * @param threadData Pointer to thread data. Used for error handling. | ||
| 765 | */ | ||
| 766 | 1 | void freeNonlinearSystems(DATA *data, threadData_t *threadData) | |
| 767 | { | ||
| 768 | int i; | ||
| 769 | 1 | NONLINEAR_SYSTEM_DATA* nonlinsys = data->simulationInfo->nonlinearSystemData; | |
| 770 | |||
| 771 | 1 | infoStreamPrint(OMC_LOG_NLS, 1, "free non-linear system solvers"); | |
| 772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for(i=0; i<data->modelData->nNonLinearSystems; ++i) |
| 773 | { | ||
| 774 | ✗ | freeNonlinearSyst(data, threadData, &nonlinsys[i]); | |
| 775 | } | ||
| 776 | |||
| 777 | 1 | messageClose(OMC_LOG_NLS); | |
| 778 | |||
| 779 | 1 | return; | |
| 780 | } | ||
| 781 | |||
| 782 | /** | ||
| 783 | * @brief Print non-linear system statistics to stream. | ||
| 784 | * | ||
| 785 | * @param nonlinsys Non-linear system data to print. | ||
| 786 | * @param stream Log stream to use for logging. | ||
| 787 | */ | ||
| 788 | ✗ | void printNonLinearSystemSolvingStatistics(NONLINEAR_SYSTEM_DATA* nonlinsys, enum OMC_LOG_STREAM stream) | |
| 789 | { | ||
| 790 | ✗ | if (!OMC_ACTIVE_STREAM(stream)) return; | |
| 791 | ✗ | infoStreamPrint(stream, 1, "Non-linear system %d of size %d solver statistics:", (int)nonlinsys->equationIndex, (int)nonlinsys->size); | |
| 792 | ✗ | infoStreamPrint(stream, 0, " number of calls : %ld", nonlinsys->numberOfCall); | |
| 793 | ✗ | infoStreamPrint(stream, 0, " number of iterations : %ld", nonlinsys->numberOfIterations); | |
| 794 | ✗ | infoStreamPrint(stream, 0, " number of function evaluations : %ld", nonlinsys->numberOfFEval); | |
| 795 | ✗ | infoStreamPrint(stream, 0, " number of jacobian evaluations : %ld", nonlinsys->numberOfJEval); | |
| 796 | ✗ | infoStreamPrint(stream, 0, " time of jacobian evaluations : %f", nonlinsys->jacobianTime); | |
| 797 | ✗ | infoStreamPrint(stream, 0, " average time per call : %f", nonlinsys->totalTime/nonlinsys->numberOfCall); | |
| 798 | ✗ | infoStreamPrint(stream, 0, " total time : %f", nonlinsys->totalTime); | |
| 799 | ✗ | messageClose(stream); | |
| 800 | } | ||
| 801 | |||
| 802 | /*! \fn printNonLinearInitialInfo | ||
| 803 | * | ||
| 804 | * This function prints information of an non-linear systems before an solving step. | ||
| 805 | * | ||
| 806 | * \param [in] [logName] log level in general OMC_LOG_NLS | ||
| 807 | * [ref] [data] | ||
| 808 | * [ref] [nonlinsys] index of corresponding non-linear system | ||
| 809 | */ | ||
| 810 | ✗ | void printNonLinearInitialInfo(int logName, DATA* data, NONLINEAR_SYSTEM_DATA *nonlinsys) | |
| 811 | { | ||
| 812 | long i; | ||
| 813 | |||
| 814 | ✗ | if (!OMC_ACTIVE_STREAM(logName)) return; | |
| 815 | ✗ | infoStreamPrint(logName, 1, "initial variable values:"); | |
| 816 | |||
| 817 | ✗ | for(i=0; i<nonlinsys->size; i++) | |
| 818 | ✗ | infoStreamPrint(logName, 0, "[%2ld] %30s = %16.8g\t\t nom = %16.8g", i+1, | |
| 819 | ✗ | modelInfoGetEquation(&data->modelData->modelDataXml,nonlinsys->equationIndex).vars[i], | |
| 820 | ✗ | nonlinsys->nlsx[i], nonlinsys->nominal[i]); | |
| 821 | ✗ | messageClose(logName); | |
| 822 | } | ||
| 823 | |||
| 824 | /*! \fn printNonLinearFinishInfo | ||
| 825 | * | ||
| 826 | * This function prints information of an non-linear systems after a solving step. | ||
| 827 | * | ||
| 828 | * \param [in] [logName] log level in general OMC_LOG_NLS | ||
| 829 | * [ref] [data] | ||
| 830 | * [ref] [nonlinsys] index of corresponding non-linear system | ||
| 831 | */ | ||
| 832 | ✗ | void printNonLinearFinishInfo(int logName, DATA* data, NONLINEAR_SYSTEM_DATA *nonlinsys) | |
| 833 | { | ||
| 834 | long i; | ||
| 835 | |||
| 836 | ✗ | if (!OMC_ACTIVE_STREAM(logName)) return; | |
| 837 | |||
| 838 | ✗ | switch (nonlinsys->solved) | |
| 839 | { | ||
| 840 | ✗ | case NLS_SOLVED: | |
| 841 | ✗ | infoStreamPrint(logName, 1, "Solution status: SOLVED"); | |
| 842 | ✗ | break; | |
| 843 | ✗ | case NLS_SOLVED_LESS_ACCURACY: | |
| 844 | ✗ | infoStreamPrint(logName, 1, "Solution status: SOLVED with less accuracy"); | |
| 845 | ✗ | break; | |
| 846 | ✗ | case NLS_FAILED: | |
| 847 | ✗ | infoStreamPrint(logName, 1, "Solution status: FAILED"); | |
| 848 | ✗ | break; | |
| 849 | ✗ | default: | |
| 850 | ✗ | throwStreamPrint(NULL, "Unhandled case in printNonLinearFinishInfo"); | |
| 851 | break; | ||
| 852 | } | ||
| 853 | ✗ | infoStreamPrint(logName, 0, " number of iterations : %ld", nonlinsys->numberOfIterations); | |
| 854 | ✗ | infoStreamPrint(logName, 0, " number of function evaluations : %ld", nonlinsys->numberOfFEval); | |
| 855 | ✗ | infoStreamPrint(logName, 0, " number of jacobian evaluations : %ld", nonlinsys->numberOfJEval); | |
| 856 | ✗ | infoStreamPrint(logName, 0, "solution values:"); | |
| 857 | ✗ | for(i=0; i<nonlinsys->size; i++) | |
| 858 | ✗ | infoStreamPrint(logName, 0, "[%2ld] %30s = %16.8g", i+1, | |
| 859 | ✗ | modelInfoGetEquation(&data->modelData->modelDataXml,nonlinsys->equationIndex).vars[i], | |
| 860 | ✗ | nonlinsys->nlsx[i]); | |
| 861 | |||
| 862 | ✗ | messageClose(logName); | |
| 863 | } | ||
| 864 | |||
| 865 | /*! \fn getInitialGuess | ||
| 866 | * | ||
| 867 | * This function writes initial guess to nonlinsys->nlsx and nonlinsys->nlsOld. | ||
| 868 | * | ||
| 869 | * \param [in] [nonlinsys] | ||
| 870 | * \param [in] [time] time for extrapolation | ||
| 871 | * | ||
| 872 | */ | ||
| 873 | ✗ | int getInitialGuess(NONLINEAR_SYSTEM_DATA *nonlinsys, double time) | |
| 874 | { | ||
| 875 | /* value extrapolation */ | ||
| 876 | ✗ | printValuesListTimes(nonlinsys->oldValueList->valueList); | |
| 877 | /* if list is empty use current start values */ | ||
| 878 | ✗ | if (listLen(nonlinsys->oldValueList->valueList)==0) | |
| 879 | { | ||
| 880 | /* use old value if no values are stored in the list; the extrapolation too, | ||
| 881 | which `solveHomotopy` starts a non-discrete call from and which is a zeroed | ||
| 882 | allocation until then */ | ||
| 883 | ✗ | memcpy(nonlinsys->nlsx, nonlinsys->nlsxOld, nonlinsys->size*(sizeof(double))); | |
| 884 | ✗ | memcpy(nonlinsys->nlsxExtrapolation, nonlinsys->nlsxOld, nonlinsys->size*(sizeof(double))); | |
| 885 | } | ||
| 886 | else | ||
| 887 | { | ||
| 888 | /* get extrapolated values */ | ||
| 889 | ✗ | getValues(nonlinsys->oldValueList->valueList, time, nonlinsys->nlsxExtrapolation, nonlinsys->nlsxOld); | |
| 890 | ✗ | memcpy(nonlinsys->nlsx, nonlinsys->nlsxOld, nonlinsys->size*(sizeof(double))); | |
| 891 | } | ||
| 892 | |||
| 893 | ✗ | return 0; | |
| 894 | } | ||
| 895 | |||
| 896 | /*! \fn updateInitialGuessDB | ||
| 897 | * | ||
| 898 | * This function writes new values to solution list. | ||
| 899 | * | ||
| 900 | * \param [in] [nonlinsys] | ||
| 901 | * \param [in] [time] time for extrapolation | ||
| 902 | * \param [in] [context] current context of evaluation | ||
| 903 | * | ||
| 904 | */ | ||
| 905 | ✗ | int updateInitialGuessDB(NONLINEAR_SYSTEM_DATA *nonlinsys, double time, EVAL_CONTEXT context) | |
| 906 | { | ||
| 907 | /* Variables */ | ||
| 908 | VALUE* tmpNode; | ||
| 909 | |||
| 910 | /* write solution to oldValue list for extrapolation */ | ||
| 911 | ✗ | if (nonlinsys->solved == NLS_SOLVED) | |
| 912 | { | ||
| 913 | /* do not use solution of jacobian for next extrapolation */ | ||
| 914 | ✗ | if (context == CONTEXT_ODE || context == CONTEXT_ALGEBRAIC || context == CONTEXT_EVENTS) | |
| 915 | { | ||
| 916 | ✗ | tmpNode = createValueElement(nonlinsys->size, time, nonlinsys->nlsx); | |
| 917 | ✗ | addListElement(nonlinsys->oldValueList->valueList, | |
| 918 | tmpNode); | ||
| 919 | ✗ | freeValue(tmpNode); | |
| 920 | } | ||
| 921 | } | ||
| 922 | ✗ | else if (nonlinsys->solved == NLS_SOLVED_LESS_ACCURACY) | |
| 923 | { | ||
| 924 | ✗ | if (listLen((nonlinsys->oldValueList)->valueList)>0) | |
| 925 | { | ||
| 926 | ✗ | cleanValueList(nonlinsys->oldValueList->valueList, NULL); | |
| 927 | } | ||
| 928 | /* do not use solution of jacobian for next extrapolation */ | ||
| 929 | ✗ | if (context == CONTEXT_ODE || context == CONTEXT_ALGEBRAIC || context == CONTEXT_EVENTS) | |
| 930 | { | ||
| 931 | ✗ | tmpNode = createValueElement(nonlinsys->size, time, nonlinsys->nlsx); | |
| 932 | ✗ | addListElement(nonlinsys->oldValueList->valueList, | |
| 933 | tmpNode); | ||
| 934 | ✗ | freeValue(tmpNode); | |
| 935 | } | ||
| 936 | } | ||
| 937 | ✗ | return 0; | |
| 938 | } | ||
| 939 | |||
| 940 | /*! \fn updateInnerEquation | ||
| 941 | * | ||
| 942 | * This function updates inner equation with the current x. | ||
| 943 | * | ||
| 944 | * \param [ref] [data] | ||
| 945 | * [in] [sysNumber] index of corresponding non-linear system | ||
| 946 | */ | ||
| 947 | ✗ | int updateInnerEquation(RESIDUAL_USERDATA* resUserData, int sysNumber, int discrete) | |
| 948 | { | ||
| 949 | ✗ | DATA *data = resUserData->data; | |
| 950 | ✗ | threadData_t *threadData = resUserData->threadData; | |
| 951 | |||
| 952 | ✗ | NONLINEAR_SYSTEM_DATA* nonlinsys = &(data->simulationInfo->nonlinearSystemData[sysNumber]); | |
| 953 | int success = 0; | ||
| 954 | int constraintViolated = 0; | ||
| 955 | |||
| 956 | /* solve non continuous at discrete points*/ | ||
| 957 | ✗ | if(discrete) | |
| 958 | { | ||
| 959 | ✗ | data->simulationInfo->solveContinuous = 0; | |
| 960 | } | ||
| 961 | |||
| 962 | /* try */ | ||
| 963 | #ifndef OMC_EMCC | ||
| 964 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 965 | #endif | ||
| 966 | |||
| 967 | /* call residual function */ | ||
| 968 | ✗ | if (nonlinsys->strictTearingFunctionCall != NULL) | |
| 969 | ✗ | constraintViolated = nonlinsys->residualFuncConstraints(resUserData, nonlinsys->nlsx, nonlinsys->resValues, (int*)&nonlinsys->size); | |
| 970 | else | ||
| 971 | ✗ | nonlinsys->residualFunc(resUserData, nonlinsys->nlsx, nonlinsys->resValues, (int*)&nonlinsys->size); | |
| 972 | |||
| 973 | /* replace extrapolated values by current x for discrete step */ | ||
| 974 | ✗ | memcpy(nonlinsys->nlsxExtrapolation, nonlinsys->nlsx, nonlinsys->size*(sizeof(double))); | |
| 975 | |||
| 976 | ✗ | if (!constraintViolated && !OMC_ERROR_RAISED()) | |
| 977 | success = 1; | ||
| 978 | /*catch */ | ||
| 979 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } | |
| 980 | #ifndef OMC_EMCC | ||
| 981 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 982 | #endif | ||
| 983 | |||
| 984 | ✗ | if (!success && !constraintViolated) | |
| 985 | { | ||
| 986 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Non-Linear Solver try to handle a problem with a called assert."); | |
| 987 | } | ||
| 988 | |||
| 989 | ✗ | if(discrete) | |
| 990 | { | ||
| 991 | ✗ | data->simulationInfo->solveContinuous = 1; | |
| 992 | } | ||
| 993 | |||
| 994 | ✗ | return success; | |
| 995 | } | ||
| 996 | |||
| 997 | /** | ||
| 998 | * @brief Solve given non-linear system. | ||
| 999 | * | ||
| 1000 | * @param data Runtime data struct. | ||
| 1001 | * @param threadData Thread data for error handling. | ||
| 1002 | * @param nonlinsys Pointer to non-linear system. | ||
| 1003 | * @return NLS_SOLVER_STATUS Return NLS_SOLVED on success, | ||
| 1004 | * NLS_SOLVED_LESS_ACCURACY if a less accurate solution was found and | ||
| 1005 | * NLS_FAILED otherwise. | ||
| 1006 | */ | ||
| 1007 | ✗ | NLS_SOLVER_STATUS solveNLS(DATA *data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA* nonlinsys) | |
| 1008 | { | ||
| 1009 | ✗ | NLS_SOLVER_STATUS solver_status = NLS_FAILED; | |
| 1010 | ✗ | int casualTearingSet = nonlinsys->strictTearingFunctionCall != NULL; | |
| 1011 | struct dataSolver *solverData; | ||
| 1012 | struct dataMixedSolver *mixedSolverData; | ||
| 1013 | |||
| 1014 | /* use the selected solver for solving nonlinear system */ | ||
| 1015 | ✗ | switch(nonlinsys->nlsMethod) | |
| 1016 | { | ||
| 1017 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1018 | ✗ | case NLS_HYBRID: | |
| 1019 | ✗ | solverData = nonlinsys->solverData; | |
| 1020 | ✗ | nonlinsys->solverData = solverData->ordinaryData; | |
| 1021 | /* try */ | ||
| 1022 | #ifndef OMC_EMCC | ||
| 1023 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1024 | #endif | ||
| 1025 | ✗ | solver_status = solveHybrd(data, threadData, nonlinsys); | |
| 1026 | /*catch */ | ||
| 1027 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); solver_status = NLS_FAILED; } | |
| 1028 | #ifndef OMC_EMCC | ||
| 1029 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1030 | #endif | ||
| 1031 | ✗ | nonlinsys->solverData = solverData; | |
| 1032 | ✗ | break; | |
| 1033 | ✗ | case NLS_KINSOL: | |
| 1034 | ✗ | solverData = nonlinsys->solverData; | |
| 1035 | ✗ | nonlinsys->solverData = solverData->ordinaryData; | |
| 1036 | /* try */ | ||
| 1037 | #ifndef OMC_EMCC | ||
| 1038 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1039 | #endif | ||
| 1040 | ✗ | solver_status = nlsKinsolSolve(data, threadData, nonlinsys); | |
| 1041 | /*catch */ | ||
| 1042 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); solver_status = NLS_FAILED; } | |
| 1043 | #ifndef OMC_EMCC | ||
| 1044 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1045 | #endif | ||
| 1046 | ✗ | nonlinsys->solverData = solverData; | |
| 1047 | ✗ | break; | |
| 1048 | ✗ | case NLS_KINSOL_B: | |
| 1049 | ✗ | solverData = nonlinsys->solverData; | |
| 1050 | ✗ | nonlinsys->solverData = solverData->ordinaryData; | |
| 1051 | /* try */ | ||
| 1052 | #ifndef OMC_EMCC | ||
| 1053 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1054 | #endif | ||
| 1055 | ✗ | solver_status = B_nlsKinsolSolve(data, threadData, nonlinsys); | |
| 1056 | /*catch */ | ||
| 1057 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); solver_status = NLS_FAILED; } | |
| 1058 | #ifndef OMC_EMCC | ||
| 1059 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1060 | #endif | ||
| 1061 | ✗ | nonlinsys->solverData = solverData; | |
| 1062 | ✗ | break; | |
| 1063 | ✗ | case NLS_NEWTON: | |
| 1064 | ✗ | solverData = nonlinsys->solverData; | |
| 1065 | ✗ | nonlinsys->solverData = solverData->ordinaryData; | |
| 1066 | /* try */ | ||
| 1067 | #ifndef OMC_EMCC | ||
| 1068 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1069 | #endif | ||
| 1070 | ✗ | solver_status = solveNewton(data, threadData, nonlinsys); | |
| 1071 | /*catch */ | ||
| 1072 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); solver_status = NLS_FAILED; } | |
| 1073 | #ifndef OMC_EMCC | ||
| 1074 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1075 | #endif | ||
| 1076 | /* check if solution process was successful, if not use alternative tearing set if available (dynamic tearing)*/ | ||
| 1077 | ✗ | if (solver_status != NLS_SOLVED && casualTearingSet){ | |
| 1078 | debugString(OMC_LOG_DT, "Solving the casual tearing set failed! Now the strict tearing set is used."); | ||
| 1079 | ✗ | if(nonlinsys->strictTearingFunctionCall(data, threadData)) { | |
| 1080 | solver_status = NLS_SOLVED; | ||
| 1081 | } else { | ||
| 1082 | solver_status = NLS_FAILED; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | ✗ | nonlinsys->solverData = solverData; | |
| 1086 | ✗ | break; | |
| 1087 | #endif | ||
| 1088 | ✗ | case NLS_HOMOTOPY: | |
| 1089 | ✗ | solver_status = solveHomotopy(data, threadData, nonlinsys); | |
| 1090 | break; | ||
| 1091 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1092 | ✗ | case NLS_MIXED: | |
| 1093 | ✗ | mixedSolverData = nonlinsys->solverData; | |
| 1094 | ✗ | nonlinsys->solverData = mixedSolverData->newtonHomotopyData; | |
| 1095 | |||
| 1096 | /* try */ | ||
| 1097 | #ifndef OMC_EMCC | ||
| 1098 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1099 | #endif | ||
| 1100 | ✗ | solver_status = solveHomotopy(data, threadData, nonlinsys); | |
| 1101 | |||
| 1102 | /* check if solution process was successful, if not use alternative tearing set if available (dynamic tearing)*/ | ||
| 1103 | ✗ | if (solver_status != NLS_SOLVED && casualTearingSet){ | |
| 1104 | debugString(OMC_LOG_DT, "Solving the casual tearing set failed! Now the strict tearing set is used."); | ||
| 1105 | ✗ | if(nonlinsys->strictTearingFunctionCall(data, threadData)) { | |
| 1106 | solver_status = NLS_SOLVED; | ||
| 1107 | } else { | ||
| 1108 | solver_status = NLS_FAILED; | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | ✗ | if (solver_status != NLS_SOLVED ) { | |
| 1113 | ✗ | nonlinsys->solverData = mixedSolverData->hybridData; | |
| 1114 | ✗ | solver_status = solveHybrd(data, threadData, nonlinsys); | |
| 1115 | } | ||
| 1116 | |||
| 1117 | /* update iteration variables of nonlinsys->nlsx */ | ||
| 1118 | ✗ | if (solver_status == NLS_SOLVED){ | |
| 1119 | ✗ | nonlinsys->getIterationVars(data, nonlinsys->nlsx); | |
| 1120 | } | ||
| 1121 | |||
| 1122 | /*catch */ | ||
| 1123 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); solver_status = NLS_FAILED; } | |
| 1124 | #ifndef OMC_EMCC | ||
| 1125 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1126 | #endif | ||
| 1127 | ✗ | nonlinsys->solverData = mixedSolverData; | |
| 1128 | ✗ | break; | |
| 1129 | #endif | ||
| 1130 | ✗ | default: | |
| 1131 | ✗ | throwStreamPrint(threadData, "unrecognized nonlinear solver"); | |
| 1132 | } | ||
| 1133 | |||
| 1134 | ✗ | return solver_status; | |
| 1135 | } | ||
| 1136 | |||
| 1137 | /** | ||
| 1138 | * @brief Solve initial non-linear system with homotopy solver | ||
| 1139 | * | ||
| 1140 | * @param data Runtime data struct. | ||
| 1141 | * @param threadData Thread data for error handling. | ||
| 1142 | * @param nonlinsys Pointer to non-linear system data. | ||
| 1143 | * @return NLS_SOLVER_STATUS Return solver status of homotopy solver. | ||
| 1144 | */ | ||
| 1145 | ✗ | NLS_SOLVER_STATUS solveWithInitHomotopy(DATA *data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA* nonlinsys) | |
| 1146 | { | ||
| 1147 | NLS_SOLVER_STATUS success = NLS_FAILED; | ||
| 1148 | struct dataSolver *solverData; | ||
| 1149 | struct dataMixedSolver *mixedSolverData; | ||
| 1150 | |||
| 1151 | /* use the homotopy solver for solving the initial system */ | ||
| 1152 | ✗ | switch(nonlinsys->nlsMethod) | |
| 1153 | { | ||
| 1154 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1155 | ✗ | case NLS_HYBRID: | |
| 1156 | case NLS_KINSOL: | ||
| 1157 | case NLS_KINSOL_B: | ||
| 1158 | case NLS_NEWTON: | ||
| 1159 | ✗ | solverData = nonlinsys->solverData; | |
| 1160 | ✗ | nonlinsys->solverData = solverData->initHomotopyData; | |
| 1161 | ✗ | success = solveHomotopy(data, threadData, nonlinsys); | |
| 1162 | ✗ | nonlinsys->solverData = solverData; | |
| 1163 | ✗ | break; | |
| 1164 | #endif | ||
| 1165 | ✗ | case NLS_HOMOTOPY: | |
| 1166 | ✗ | success = solveHomotopy(data, threadData, nonlinsys); | |
| 1167 | ✗ | break; | |
| 1168 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1169 | ✗ | case NLS_MIXED: | |
| 1170 | ✗ | mixedSolverData = nonlinsys->solverData; | |
| 1171 | ✗ | nonlinsys->solverData = mixedSolverData->newtonHomotopyData; | |
| 1172 | ✗ | success = solveHomotopy(data, threadData, nonlinsys); | |
| 1173 | ✗ | nonlinsys->solverData = mixedSolverData; | |
| 1174 | ✗ | break; | |
| 1175 | #endif | ||
| 1176 | ✗ | default: | |
| 1177 | ✗ | throwStreamPrint(threadData, "unrecognized nonlinear solver"); | |
| 1178 | } | ||
| 1179 | |||
| 1180 | ✗ | return success; | |
| 1181 | } | ||
| 1182 | |||
| 1183 | /*! \fn Solve all non-linear systems in data->simulationInfo->nonlinearSystemData. | ||
| 1184 | * | ||
| 1185 | * @param data Runtime data struct. | ||
| 1186 | * @param threadData Thread data for error handling. | ||
| 1187 | * @param sysNumber Index of corresponding non-linear system | ||
| 1188 | * | ||
| 1189 | * @author ptaeuber | ||
| 1190 | */ | ||
| 1191 | ✗ | int solve_nonlinear_system(DATA *data, threadData_t *threadData, int sysNumber) | |
| 1192 | { | ||
| 1193 | ✗ | assertStreamPrint(NULL, NULL != threadData, "threadData is NULL. Something went horribly wrong!"); | |
| 1194 | ✗ | assertStreamPrint(threadData, NULL != data, "data is NULL. Something went horribly wrong!"); | |
| 1195 | |||
| 1196 | ✗ | RESIDUAL_USERDATA resUserData = {.data=data, .threadData=threadData, .solverData=NULL}; | |
| 1197 | int saveJumpState, constraintsSatisfied; | ||
| 1198 | ✗ | NONLINEAR_SYSTEM_DATA* nonlinsys = &(data->simulationInfo->nonlinearSystemData[sysNumber]); | |
| 1199 | ✗ | int casualTearingSet = nonlinsys->strictTearingFunctionCall != NULL; | |
| 1200 | int step; | ||
| 1201 | int equidistantHomotopy = 0; | ||
| 1202 | int solveWithHomotopySolver = 0; | ||
| 1203 | int homotopyDeactivated = 0; | ||
| 1204 | int j; | ||
| 1205 | int nlsLs; | ||
| 1206 | ✗ | modelica_boolean kinsol = FALSE; | |
| 1207 | int res; | ||
| 1208 | struct dataSolver *solverData; | ||
| 1209 | struct dataMixedSolver *mixedSolverData; | ||
| 1210 | char buffer[4096]; | ||
| 1211 | ✗ | FILE *pFile = NULL; | |
| 1212 | ✗ | double originalLambda = data->simulationInfo->lambda; | |
| 1213 | |||
| 1214 | ✗ | if (!nonlinsys->logActive) { | |
| 1215 | ✗ | deactivateLogging(); | |
| 1216 | } | ||
| 1217 | |||
| 1218 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1219 | ✗ | kinsol = (nonlinsys->nlsMethod == NLS_KINSOL) || (nonlinsys->nlsMethod == NLS_KINSOL_B); | |
| 1220 | #endif | ||
| 1221 | |||
| 1222 | /* enable to avoid division by zero */ | ||
| 1223 | ✗ | data->simulationInfo->noThrowDivZero = 1; | |
| 1224 | ✗ | data->simulationInfo->solveContinuous = 1; | |
| 1225 | |||
| 1226 | /* performance measurement */ | ||
| 1227 | ✗ | rt_ext_tp_tick(&nonlinsys->totalTimeClock); | |
| 1228 | |||
| 1229 | ✗ | infoStreamPrint(OMC_LOG_NLS_EXTRAPOLATE, 1, "Nonlinear system " OMC_INT_FORMAT " dump OMC_LOG_NLS_EXTRAPOLATE", nonlinsys->equationIndex); | |
| 1230 | /* grab the initial guess */ | ||
| 1231 | /* if last solving is too long ago use just old values */ | ||
| 1232 | ✗ | if (fabs(data->localData[0]->timeValue - nonlinsys->lastTimeSolved) < 5*data->simulationInfo->stepSize || casualTearingSet) | |
| 1233 | { | ||
| 1234 | ✗ | getInitialGuess(nonlinsys, data->localData[0]->timeValue); | |
| 1235 | } | ||
| 1236 | else | ||
| 1237 | { | ||
| 1238 | ✗ | nonlinsys->getIterationVars(data, nonlinsys->nlsx); | |
| 1239 | ✗ | memcpy(nonlinsys->nlsx, nonlinsys->nlsxOld, nonlinsys->size*(sizeof(double))); | |
| 1240 | } | ||
| 1241 | /* update non continuous */ | ||
| 1242 | ✗ | if (data->simulationInfo->discreteCall) | |
| 1243 | { | ||
| 1244 | // TODO: constraintsSatisfied never used | ||
| 1245 | ✗ | constraintsSatisfied = updateInnerEquation(&resUserData, sysNumber, 1); | |
| 1246 | } | ||
| 1247 | |||
| 1248 | /* print debug initial information */ | ||
| 1249 | ✗ | infoStreamPrint(OMC_LOG_NLS, 1, "############ Solve nonlinear system " OMC_INT_FORMAT " at time %g ############", nonlinsys->equationIndex, data->localData[0]->timeValue); | |
| 1250 | ✗ | printNonLinearInitialInfo(OMC_LOG_NLS, data, nonlinsys); | |
| 1251 | |||
| 1252 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1253 | |||
| 1254 | /* try */ | ||
| 1255 | #ifndef OMC_EMCC | ||
| 1256 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1257 | #endif | ||
| 1258 | |||
| 1259 | /* Improve start values with newton diagnostics method */ | ||
| 1260 | ✗ | if(omc_useStream[OMC_LOG_NLS_NEWTON_DIAGNOSTICS] && data->simulationInfo->initial) { | |
| 1261 | ✗ | EQUATION_INFO eqInfo = modelInfoGetEquation(&data->modelData->modelDataXml, nonlinsys->equationIndex); | |
| 1262 | ✗ | if (eqInfo.section == EQUATION_SECTION_INIT_LAMBDA0 || (eqInfo.section == EQUATION_SECTION_INITIAL && data->callback->functionInitialEquations_lambda0 == NULL)) { | |
| 1263 | ✗ | newtonDiagnostics(data, threadData, sysNumber); | |
| 1264 | } | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | /*catch */ | ||
| 1268 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } | |
| 1269 | #ifndef OMC_EMCC | ||
| 1270 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1271 | #endif | ||
| 1272 | |||
| 1273 | #endif | ||
| 1274 | |||
| 1275 | |||
| 1276 | /* try */ | ||
| 1277 | #ifndef OMC_EMCC | ||
| 1278 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 1279 | #endif | ||
| 1280 | |||
| 1281 | // TODO: refactor this logic | ||
| 1282 | |||
| 1283 | /* handle asserts */ | ||
| 1284 | ✗ | saveJumpState = threadData->currentErrorStage; | |
| 1285 | ✗ | threadData->currentErrorStage = ERROR_NONLINEARSOLVER; | |
| 1286 | |||
| 1287 | ✗ | equidistantHomotopy = data->simulationInfo->initial | |
| 1288 | ✗ | && nonlinsys->homotopySupport | |
| 1289 | ✗ | && (data->callback->homotopyMethod == LOCAL_EQUIDISTANT_HOMOTOPY && init_lambda_steps >= 1); | |
| 1290 | |||
| 1291 | solveWithHomotopySolver = data->simulationInfo->initial | ||
| 1292 | ✗ | && nonlinsys->homotopySupport | |
| 1293 | ✗ | && (data->callback->homotopyMethod == GLOBAL_ADAPTIVE_HOMOTOPY || data->callback->homotopyMethod == LOCAL_ADAPTIVE_HOMOTOPY ); | |
| 1294 | |||
| 1295 | homotopyDeactivated = (!data->simulationInfo->initial // Not an initialization system | ||
| 1296 | ✗ | || !nonlinsys->homotopySupport // There is no homotopy in this component | |
| 1297 | ✗ | || (data->callback->homotopyMethod == GLOBAL_EQUIDISTANT_HOMOTOPY) // Equidistant homotopy is performed globally in symbolic_initialization() | |
| 1298 | ✗ | || (data->callback->homotopyMethod == LOCAL_EQUIDISTANT_HOMOTOPY // Equidistant local homotopy is selected but homotopy is deactivated ... | |
| 1299 | ✗ | && init_lambda_steps <= 0)) | |
| 1300 | ✗ | || data->callback->homotopyMethod == NO_HOMOTOPY ; // No Homotopy present | |
| 1301 | |||
| 1302 | ✗ | nonlinsys->solved = NLS_FAILED; | |
| 1303 | ✗ | nonlinsys->initHomotopy = 0; | |
| 1304 | |||
| 1305 | /* If homotopy is deactivated in this place or flag homotopyOnFirstTry is not set, | ||
| 1306 | solve the system with the selected solver */ | ||
| 1307 | ✗ | if (homotopyDeactivated || !omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY]) { | |
| 1308 | ✗ | if (solveWithHomotopySolver && kinsol) { | |
| 1309 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Automatically set -homotopyOnFirstTry, because trying without homotopy first is not supported for the local global approach in combination with KINSOL."); | |
| 1310 | } else { | ||
| 1311 | ✗ | if (!homotopyDeactivated && !omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY]) | |
| 1312 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Try to solve nonlinear initial system %d without homotopy first.", sysNumber); | |
| 1313 | |||
| 1314 | /* SOLVE! */ | ||
| 1315 | ✗ | nonlinsys->solved = solveNLS(data, threadData, nonlinsys); | |
| 1316 | } | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /* The following cases are only valid for initial systems with homotopy */ | ||
| 1320 | /* **********************************************************************/ | ||
| 1321 | |||
| 1322 | /* If the adaptive local/global homotopy approach is activated and trying without homotopy failed or is not wanted, | ||
| 1323 | use the HOMOTOPY SOLVER */ | ||
| 1324 | ✗ | if (solveWithHomotopySolver && nonlinsys->solved != NLS_SOLVED) { | |
| 1325 | ✗ | if (!omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY] && !kinsol) | |
| 1326 | ✗ | warningStreamPrint(OMC_LOG_ASSERT, 0, "Failed to solve the initial system %d without homotopy method.", sysNumber); | |
| 1327 | ✗ | data->simulationInfo->lambda = 0.0; | |
| 1328 | ✗ | if (data->callback->homotopyMethod == LOCAL_ADAPTIVE_HOMOTOPY ) { | |
| 1329 | // First solve the lambda0-system separately | ||
| 1330 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Local homotopy with adaptive step size started for nonlinear system %d.", sysNumber); | |
| 1331 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 1, "homotopy process\n---------------------------"); | |
| 1332 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "solve lambda0-system"); | |
| 1333 | ✗ | nonlinsys->homotopySupport = 0; | |
| 1334 | ✗ | if (!kinsol) { | |
| 1335 | ✗ | nonlinsys->solved = solveNLS(data, threadData, nonlinsys); | |
| 1336 | } else { | ||
| 1337 | ✗ | nlsLs = data->simulationInfo->nlsLinearSolver; | |
| 1338 | ✗ | data->simulationInfo->nlsLinearSolver = NLS_LS_LAPACK; | |
| 1339 | ✗ | nonlinsys->solved = solveWithInitHomotopy(data, threadData, nonlinsys); | |
| 1340 | ✗ | data->simulationInfo->nlsLinearSolver = nlsLs; | |
| 1341 | } | ||
| 1342 | ✗ | nonlinsys->homotopySupport = 1; | |
| 1343 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "solving lambda0-system done with%s success\n---------------------------", nonlinsys->solved==NLS_SOLVED ? "" : " no"); | |
| 1344 | ✗ | messageClose(OMC_LOG_INIT_HOMOTOPY); | |
| 1345 | } | ||
| 1346 | /* SOLVE! */ | ||
| 1347 | ✗ | if (data->callback->homotopyMethod == GLOBAL_ADAPTIVE_HOMOTOPY || nonlinsys->solved == NLS_SOLVED) { | |
| 1348 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "run along the homotopy path and solve the actual system"); | |
| 1349 | ✗ | nonlinsys->initHomotopy = 1; | |
| 1350 | ✗ | nonlinsys->solved = solveWithInitHomotopy(data, threadData, nonlinsys); | |
| 1351 | } | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | /* If equidistant local homotopy is activated and trying without homotopy failed or is not wanted, | ||
| 1355 | use EQUIDISTANT LOCAL HOMOTOPY */ | ||
| 1356 | ✗ | if (equidistantHomotopy && nonlinsys->solved != NLS_SOLVED) { | |
| 1357 | ✗ | if (!omc_flag[FLAG_HOMOTOPY_ON_FIRST_TRY]) | |
| 1358 | ✗ | warningStreamPrint(OMC_LOG_ASSERT, 0, "Failed to solve the initial system %d without homotopy method. The local homotopy method with equidistant step size is used now.", sysNumber); | |
| 1359 | else | ||
| 1360 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "Local homotopy with equidistant step size started for nonlinear system %d.", sysNumber); | |
| 1361 | #if !defined(OMC_NO_FILESYSTEM) | ||
| 1362 | ✗ | const char sep[] = ","; | |
| 1363 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_INIT_HOMOTOPY)) | |
| 1364 | { | ||
| 1365 | ✗ | sprintf(buffer, "%s_nonlinsys%d_equidistant_local_homotopy.csv", data->modelData->modelFilePrefix, sysNumber); | |
| 1366 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "The homotopy path of system %d will be exported to %s.", sysNumber, buffer); | |
| 1367 | ✗ | pFile = omc_fopen(buffer, "wt"); | |
| 1368 | ✗ | if (pFile) { | |
| 1369 | fprintf(pFile, "\"sep=%s\"\n%s", sep, "\"lambda\""); | ||
| 1370 | ✗ | for(j=0; j<nonlinsys->size; ++j) | |
| 1371 | ✗ | fprintf(pFile, "%s\"%s\"", sep, modelInfoGetEquation(&data->modelData->modelDataXml, nonlinsys->equationIndex).vars[j]); | |
| 1372 | fprintf(pFile, "\n"); | ||
| 1373 | } | ||
| 1374 | } | ||
| 1375 | #endif | ||
| 1376 | |||
| 1377 | ✗ | for(step=0; step<=init_lambda_steps; ++step) | |
| 1378 | { | ||
| 1379 | ✗ | data->simulationInfo->lambda = ((double)step)/(init_lambda_steps); | |
| 1380 | |||
| 1381 | ✗ | if (data->simulationInfo->lambda > 1.0) { | |
| 1382 | ✗ | data->simulationInfo->lambda = 1.0; | |
| 1383 | } | ||
| 1384 | |||
| 1385 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "[system %d] homotopy parameter lambda = %g", sysNumber, data->simulationInfo->lambda); | |
| 1386 | /* SOLVE! */ | ||
| 1387 | ✗ | nonlinsys->solved = solveNLS(data, threadData, nonlinsys); | |
| 1388 | ✗ | if (nonlinsys->solved != NLS_SOLVED) break; | |
| 1389 | |||
| 1390 | #if !defined(OMC_NO_FILESYSTEM) | ||
| 1391 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_INIT_HOMOTOPY)) | |
| 1392 | { | ||
| 1393 | ✗ | infoStreamPrint(OMC_LOG_INIT_HOMOTOPY, 0, "[system %d] homotopy parameter lambda = %g done\n---------------------------", sysNumber, data->simulationInfo->lambda); | |
| 1394 | ✗ | if (pFile) { | |
| 1395 | ✗ | fprintf(pFile, "%.16g", data->simulationInfo->lambda); | |
| 1396 | ✗ | for(j=0; j<nonlinsys->size; ++j) | |
| 1397 | ✗ | fprintf(pFile, "%s%.16g", sep, nonlinsys->nlsx[j]); | |
| 1398 | fprintf(pFile, "\n"); | ||
| 1399 | } | ||
| 1400 | } | ||
| 1401 | #endif | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | #if !defined(OMC_NO_FILESYSTEM) | ||
| 1405 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_INIT_HOMOTOPY)) | |
| 1406 | { | ||
| 1407 | ✗ | if (pFile) fclose(pFile); | |
| 1408 | } | ||
| 1409 | #endif | ||
| 1410 | ✗ | data->simulationInfo->homotopySteps += init_lambda_steps; | |
| 1411 | } | ||
| 1412 | |||
| 1413 | /* handle asserts */ | ||
| 1414 | ✗ | threadData->currentErrorStage = saveJumpState; | |
| 1415 | |||
| 1416 | /*catch */ | ||
| 1417 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } | |
| 1418 | #ifndef OMC_EMCC | ||
| 1419 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 1420 | #endif | ||
| 1421 | |||
| 1422 | ✗ | messageClose(OMC_LOG_NLS_EXTRAPOLATE); | |
| 1423 | /* update value list database */ | ||
| 1424 | ✗ | updateInitialGuessDB(nonlinsys, data->localData[0]->timeValue, data->simulationInfo->currentContext); | |
| 1425 | ✗ | if (nonlinsys->solved == NLS_SOLVED) | |
| 1426 | { | ||
| 1427 | ✗ | nonlinsys->lastTimeSolved = data->localData[0]->timeValue; | |
| 1428 | } | ||
| 1429 | ✗ | printNonLinearFinishInfo(OMC_LOG_NLS, data, nonlinsys); | |
| 1430 | ✗ | messageClose(OMC_LOG_NLS); | |
| 1431 | |||
| 1432 | |||
| 1433 | /* enable to avoid division by zero */ | ||
| 1434 | ✗ | data->simulationInfo->noThrowDivZero = 0; | |
| 1435 | ✗ | data->simulationInfo->solveContinuous = 0; | |
| 1436 | |||
| 1437 | /* performance measurement and statistics */ | ||
| 1438 | ✗ | nonlinsys->totalTime += rt_ext_tp_tock(&(nonlinsys->totalTimeClock)); | |
| 1439 | ✗ | nonlinsys->numberOfCall++; | |
| 1440 | |||
| 1441 | /* write csv file for debugging */ | ||
| 1442 | #if !defined(OMC_MINIMAL_RUNTIME) | ||
| 1443 | ✗ | if (data->simulationInfo->nlsCsvInfomation) | |
| 1444 | { | ||
| 1445 | ✗ | print_csvLineCallStats(((struct csvStats*) nonlinsys->csvData)->callStats, | |
| 1446 | nonlinsys->numberOfCall, | ||
| 1447 | ✗ | data->localData[0]->timeValue, | |
| 1448 | ✗ | nonlinsys->numberOfIterations, | |
| 1449 | ✗ | nonlinsys->numberOfFEval, | |
| 1450 | nonlinsys->totalTime, | ||
| 1451 | nonlinsys->solved | ||
| 1452 | ); | ||
| 1453 | } | ||
| 1454 | #endif | ||
| 1455 | ✗ | res = check_nonlinear_solution(data, 1, sysNumber); | |
| 1456 | ✗ | data->simulationInfo->lambda = originalLambda; | |
| 1457 | |||
| 1458 | ✗ | if (!nonlinsys->logActive) { | |
| 1459 | ✗ | reactivateLogging(); | |
| 1460 | } | ||
| 1461 | |||
| 1462 | ✗ | return res; | |
| 1463 | } | ||
| 1464 | |||
| 1465 | /*! \fn check_nonlinear_solutions | ||
| 1466 | * | ||
| 1467 | * This function check whether some of non-linear systems | ||
| 1468 | * are failed to solve. If one is failed it returns 1 otherwise 0. | ||
| 1469 | * | ||
| 1470 | * \param [in] [data] | ||
| 1471 | * \param [in] [printFailingSystems] | ||
| 1472 | * \param [out] [returnValue] It returns >0 if fail otherwise 0. | ||
| 1473 | * | ||
| 1474 | * \author wbraun | ||
| 1475 | */ | ||
| 1476 | 2 | int check_nonlinear_solutions(DATA *data, int printFailingSystems) | |
| 1477 | { | ||
| 1478 | long i; | ||
| 1479 | |||
| 1480 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | for(i=0; i<data->modelData->nNonLinearSystems; ++i) { |
| 1481 | ✗ | if(check_nonlinear_solution(data, printFailingSystems, i)) | |
| 1482 | return 1; | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | return 0; | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | /*! \fn check_nonlinear_solution | ||
| 1489 | * | ||
| 1490 | * This function checks if a non-linear system | ||
| 1491 | * is solved. Returns a warning and 1 in case it's not | ||
| 1492 | * solved otherwise 0. | ||
| 1493 | * | ||
| 1494 | * \param [in] [data] | ||
| 1495 | * \param [in] [printFailingSystems] | ||
| 1496 | * \param [in] [sysNumber] index of corresponding non-linear System | ||
| 1497 | * \param [out] [returnValue] Returns 1 if fail otherwise 0. | ||
| 1498 | * | ||
| 1499 | * \author wbraun | ||
| 1500 | */ | ||
| 1501 | ✗ | int check_nonlinear_solution(DATA *data, int printFailingSystems, int sysNumber) | |
| 1502 | { | ||
| 1503 | ✗ | NONLINEAR_SYSTEM_DATA* nonlinsys = data->simulationInfo->nonlinearSystemData; | |
| 1504 | long j; | ||
| 1505 | int i = sysNumber; | ||
| 1506 | |||
| 1507 | const size_t buff_size = 2048; | ||
| 1508 | char *start_buffer; | ||
| 1509 | char *nominal_buffer; | ||
| 1510 | |||
| 1511 | ✗ | if(nonlinsys[i].solved == NLS_FAILED) | |
| 1512 | { | ||
| 1513 | ✗ | int index = nonlinsys[i].equationIndex, indexes[2] = {1,index}; | |
| 1514 | ✗ | if (!printFailingSystems) return 1; | |
| 1515 | ✗ | warningStreamPrintWithEquationIndexes(OMC_LOG_NLS, omc_dummyFileInfo, 0, indexes, "nonlinear system %d fails: at t=%g", index, data->localData[0]->timeValue); | |
| 1516 | ✗ | if(data->simulationInfo->initial) | |
| 1517 | { | ||
| 1518 | ✗ | warningStreamPrint(OMC_LOG_INIT, 1, "The system might not be able to initialize because the iteration variables listed below have no suitable start values. The model was probably developed with another tool that selects different iteration (tearing) variables, so its start values may apply to other variables than the ones OpenModelica iterates on here. Try providing start values for the iteration variables below, or a different tearing method (e.g. --tearingMethod=omcTearing)."); | |
| 1519 | } | ||
| 1520 | |||
| 1521 | ✗ | start_buffer = (char*) malloc(buff_size * sizeof(char)); | |
| 1522 | ✗ | assertStreamPrint(NULL, start_buffer != NULL, "Out of memory."); | |
| 1523 | ✗ | nominal_buffer = (char*) malloc(buff_size * sizeof(char)); | |
| 1524 | ✗ | assertStreamPrint(NULL, nominal_buffer != NULL, "Out of memory."); | |
| 1525 | ✗ | for(j=0; j<modelInfoGetEquation(&data->modelData->modelDataXml, (nonlinsys[i]).equationIndex).numVar; ++j) | |
| 1526 | { | ||
| 1527 | int done=0; | ||
| 1528 | long k; | ||
| 1529 | ✗ | const MODEL_DATA *mData = data->modelData; | |
| 1530 | ✗ | for(k=0; k<mData->nVariablesRealArray && !done; ++k) | |
| 1531 | { | ||
| 1532 | ✗ | if (!strcmp(mData->realVarsData[k].info.name, modelInfoGetEquation(&data->modelData->modelDataXml, (nonlinsys[i]).equationIndex).vars[j])) | |
| 1533 | { | ||
| 1534 | done = 1; | ||
| 1535 | ✗ | real_vector_to_string(&mData->realVarsData[k].attribute.start, mData->realVarsData[k].dimension.numberOfDimensions == 0, start_buffer, buff_size); | |
| 1536 | ✗ | real_vector_to_string(&mData->realVarsData[k].attribute.nominal, mData->realVarsData[k].dimension.numberOfDimensions == 0, nominal_buffer, buff_size); | |
| 1537 | ✗ | warningStreamPrint(OMC_LOG_INIT, 0, "[%ld] Real %s(start=%s, nominal=%s)", | |
| 1538 | j+1, | ||
| 1539 | ✗ | mData->realVarsData[k].info.name, | |
| 1540 | start_buffer, | ||
| 1541 | nominal_buffer); | ||
| 1542 | } | ||
| 1543 | } | ||
| 1544 | ✗ | if (!done) | |
| 1545 | { | ||
| 1546 | ✗ | warningStreamPrint(OMC_LOG_INIT, 0, "[%ld] Real %s(start=?, nominal=?)", | |
| 1547 | j+1, | ||
| 1548 | ✗ | modelInfoGetEquation(&data->modelData->modelDataXml, | |
| 1549 | ✗ | (nonlinsys[i]).equationIndex).vars[j]); | |
| 1550 | } | ||
| 1551 | } | ||
| 1552 | ✗ | free(start_buffer); | |
| 1553 | ✗ | free(nominal_buffer); | |
| 1554 | |||
| 1555 | ✗ | if(data->simulationInfo->initial) | |
| 1556 | { | ||
| 1557 | ✗ | messageCloseWarning(OMC_LOG_INIT); | |
| 1558 | } | ||
| 1559 | ✗ | return 1; | |
| 1560 | } | ||
| 1561 | ✗ | if(nonlinsys[i].solved == NLS_SOLVED_LESS_ACCURACY) | |
| 1562 | { | ||
| 1563 | ✗ | nonlinsys[i].solved = NLS_SOLVED; | |
| 1564 | ✗ | return 2; | |
| 1565 | } | ||
| 1566 | |||
| 1567 | |||
| 1568 | return 0; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | /*! \fn cleanUpOldValueListAfterEvent | ||
| 1572 | * | ||
| 1573 | * This function clean old value list up to parameter time for all | ||
| 1574 | * non-linear systems. | ||
| 1575 | * | ||
| 1576 | * \param [in] [data] | ||
| 1577 | * \param [in] [time] | ||
| 1578 | * | ||
| 1579 | * \author wbraun | ||
| 1580 | */ | ||
| 1581 | ✗ | void cleanUpOldValueListAfterEvent(DATA *data, double time) | |
| 1582 | { | ||
| 1583 | long i; | ||
| 1584 | ✗ | NONLINEAR_SYSTEM_DATA* nonlinsys = data->simulationInfo->nonlinearSystemData; | |
| 1585 | |||
| 1586 | ✗ | for(i=0; i<data->modelData->nNonLinearSystems; ++i) { | |
| 1587 | ✗ | cleanValueListbyTime(nonlinsys[i].oldValueList->valueList, time); | |
| 1588 | } | ||
| 1589 | ✗ | } | |
| 1590 |