OMCompiler/SimulationRuntime/c/simulation/solver/nonlinearSolverHybrd.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 nonlinearSolverHybrd.c | ||
| 29 | * | ||
| 30 | * | ||
| 31 | */ | ||
| 32 | |||
| 33 | #ifdef __cplusplus | ||
| 34 | extern "C" { | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #include <math.h> | ||
| 38 | #include <stdlib.h> | ||
| 39 | #include <string.h> /* memcpy */ | ||
| 40 | |||
| 41 | #include "../simulation_info_json.h" | ||
| 42 | #include "../jacobian_util.h" | ||
| 43 | #include "../../util/omc_error.h" | ||
| 44 | #include "../../util/varinfo.h" | ||
| 45 | #include "model_help.h" | ||
| 46 | #include "../../gc/omc_gc.h" | ||
| 47 | |||
| 48 | #include "nonlinearSystem.h" | ||
| 49 | #include "nonlinearSolverHybrd.h" | ||
| 50 | |||
| 51 | extern double enorm_(integer *n, double *x); | ||
| 52 | |||
| 53 | static void wrapper_fvec_hybrj(const integer *n_p, const double* x, double* f, double* fjac, const integer* ldjac, integer* iflag, void* userData); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * @brief Allocate memory for non-linear hybrid solver. | ||
| 57 | * | ||
| 58 | * @param size Size of non-linear system. | ||
| 59 | * @param userData Information about the non-linear system (number, Jacobian, data, threadData, ...) | ||
| 60 | * @return DATA_HYBRD* Pointer to allocated hybrid data. | ||
| 61 | */ | ||
| 62 | ✗ | DATA_HYBRD* allocateHybrdData(size_t size, NLS_USERDATA* userData) | |
| 63 | { | ||
| 64 | ✗ | DATA_HYBRD* hybrdData = (DATA_HYBRD*) malloc(sizeof(DATA_HYBRD)); | |
| 65 | ✗ | assertStreamPrint(NULL, hybrdData != NULL, "allocationHybrdData() failed!"); | |
| 66 | |||
| 67 | /* fjac/fjacobian receive evalJacobian's dense output (strided by the | ||
| 68 | * analytic Jacobian's own sizeCols) and getAnalyticalJacobian's memcpy uses | ||
| 69 | * sizeRows*sizeCols directly -- both can exceed size*(size+1) for a | ||
| 70 | * partial-slice Jacobian with extra addressable-but-not-genuinely-unknown | ||
| 71 | * seed columns (see allocateHomotopyData's identical fix and | ||
| 72 | * NBJacobian.mo's partialSliceSeedCandidates whole-array fallback). Size | ||
| 73 | * those two buffers off the larger of the two; `size`/`n`, r__ (MINPACK's | ||
| 74 | * own internal packed triangular factor, sized purely off the genuine | ||
| 75 | * unknown count), and everything else below stays genuine (the solver | ||
| 76 | * itself must never see phantom unknowns). */ | ||
| 77 | ✗ | size_t jacCols = size + 1; | |
| 78 | ✗ | if (userData != NULL && userData->analyticJacobian != NULL && | |
| 79 | ✗ | (size_t)userData->analyticJacobian->sizeCols > jacCols) { | |
| 80 | jacCols = (size_t)userData->analyticJacobian->sizeCols; | ||
| 81 | } | ||
| 82 | |||
| 83 | ✗ | hybrdData->initialized = FALSE; | |
| 84 | ✗ | hybrdData->resScaling = (double*) malloc(size*sizeof(double)); | |
| 85 | ✗ | hybrdData->fvecScaled = (double*) malloc(size*sizeof(double)); | |
| 86 | ✗ | hybrdData->useXScaling = 1; | |
| 87 | ✗ | hybrdData->xScalefactors = (double*) malloc(size*sizeof(double)); | |
| 88 | |||
| 89 | ✗ | hybrdData->n = size; | |
| 90 | ✗ | hybrdData->x = (double*) malloc((size+1)*sizeof(double)); | |
| 91 | ✗ | hybrdData->xSave = (double*) malloc((size+1)*sizeof(double)); | |
| 92 | ✗ | hybrdData->xScaled = (double*) malloc((size+1)*sizeof(double)); | |
| 93 | ✗ | hybrdData->fvec = (double*) calloc(size, sizeof(double)); | |
| 94 | ✗ | hybrdData->fvecSave = (double*) calloc(size, sizeof(double)); | |
| 95 | ✗ | hybrdData->xtol = 1e-12; | |
| 96 | ✗ | hybrdData->maxfev = size*10000; | |
| 97 | ✗ | hybrdData->ml = size - 1; | |
| 98 | ✗ | hybrdData->mu = size - 1; | |
| 99 | ✗ | hybrdData->epsfcn = 1e-12; | |
| 100 | ✗ | hybrdData->diag = (double*) malloc(size*sizeof(double)); | |
| 101 | ✗ | hybrdData->diagres = (double*) malloc(size*sizeof(double)); | |
| 102 | ✗ | hybrdData->mode = 1; | |
| 103 | ✗ | hybrdData->factor = 100.0; | |
| 104 | ✗ | hybrdData->nprint = -1; | |
| 105 | ✗ | hybrdData->info = 0; | |
| 106 | ✗ | hybrdData->nfev = 0; | |
| 107 | ✗ | hybrdData->njev = 0; | |
| 108 | ✗ | hybrdData->fjac = (double*) calloc((size*jacCols), sizeof(double)); | |
| 109 | ✗ | hybrdData->fjacobian = (double*) calloc((size*jacCols), sizeof(double)); | |
| 110 | ✗ | hybrdData->ldfjac = size; | |
| 111 | ✗ | hybrdData->r__ = (double*) malloc(((size*(size+1))/2)*sizeof(double)); | |
| 112 | ✗ | hybrdData->lr = (size*(size + 1)) / 2; | |
| 113 | ✗ | hybrdData->qtf = (double*) malloc(size*sizeof(double)); | |
| 114 | ✗ | hybrdData->wa1 = (double*) malloc(size*sizeof(double)); | |
| 115 | ✗ | hybrdData->wa2 = (double*) malloc(size*sizeof(double)); | |
| 116 | ✗ | hybrdData->wa3 = (double*) malloc(size*sizeof(double)); | |
| 117 | ✗ | hybrdData->wa4 = (double*) malloc(size*sizeof(double)); | |
| 118 | |||
| 119 | ✗ | hybrdData->numberOfIterations = 0; | |
| 120 | ✗ | hybrdData->numberOfFunctionEvaluations = 0; | |
| 121 | |||
| 122 | ✗ | hybrdData->userData = userData; | |
| 123 | |||
| 124 | ✗ | return hybrdData; | |
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * @brief Free hybrid solver data. | ||
| 129 | * | ||
| 130 | * @param hybrdData Pointer to hybrid data. | ||
| 131 | */ | ||
| 132 | ✗ | void freeHybrdData(DATA_HYBRD* hybrdData) | |
| 133 | { | ||
| 134 | ✗ | free(hybrdData->resScaling); | |
| 135 | ✗ | free(hybrdData->fvecScaled); | |
| 136 | ✗ | free(hybrdData->xScalefactors); | |
| 137 | ✗ | free(hybrdData->x); | |
| 138 | ✗ | free(hybrdData->xSave); | |
| 139 | ✗ | free(hybrdData->xScaled); | |
| 140 | ✗ | free(hybrdData->fvec); | |
| 141 | ✗ | free(hybrdData->fvecSave); | |
| 142 | ✗ | free(hybrdData->diag); | |
| 143 | ✗ | free(hybrdData->diagres); | |
| 144 | ✗ | free(hybrdData->fjac); | |
| 145 | ✗ | free(hybrdData->fjacobian); | |
| 146 | ✗ | free(hybrdData->r__); | |
| 147 | ✗ | free(hybrdData->qtf); | |
| 148 | ✗ | free(hybrdData->wa1); | |
| 149 | ✗ | free(hybrdData->wa2); | |
| 150 | ✗ | free(hybrdData->wa3); | |
| 151 | ✗ | free(hybrdData->wa4); | |
| 152 | |||
| 153 | ✗ | freeNlsUserData(hybrdData->userData); | |
| 154 | |||
| 155 | ✗ | free(hybrdData); | |
| 156 | ✗ | return; | |
| 157 | } | ||
| 158 | |||
| 159 | /*! \fn printVector | ||
| 160 | * | ||
| 161 | * \param [in] [vector] | ||
| 162 | * \param [in] [size] | ||
| 163 | * \param [in] [logLevel] | ||
| 164 | * \param [in] [name] | ||
| 165 | * | ||
| 166 | * \author wbraun | ||
| 167 | */ | ||
| 168 | ✗ | static void printVector(const double *vector, const integer size, const int logLevel, const char *name) | |
| 169 | { | ||
| 170 | int i; | ||
| 171 | ✗ | if (!OMC_ACTIVE_STREAM(logLevel)) return; | |
| 172 | ✗ | infoStreamPrint(logLevel, 1, "%s", name); | |
| 173 | ✗ | for(i=0; i<size; i++) | |
| 174 | ✗ | infoStreamPrint(logLevel, 0, "[%2d] %20.12g", i, vector[i]); | |
| 175 | ✗ | messageClose(logLevel); | |
| 176 | } | ||
| 177 | |||
| 178 | /*! \fn printStatus | ||
| 179 | * | ||
| 180 | * \param [in] [solverData] | ||
| 181 | * \param [in] [nfunc_evals] | ||
| 182 | * \param [in] [xerror] | ||
| 183 | * \param [in] [xerror_scaled] | ||
| 184 | * \param [in] [logLevel] | ||
| 185 | * | ||
| 186 | * \author wbraun | ||
| 187 | */ | ||
| 188 | ✗ | static void printStatus(DATA *data, DATA_HYBRD *solverData, int eqSystemNumber, const int *nfunc_evals, const double *xerror, const double *xerror_scaled, const int logLevel) | |
| 189 | { | ||
| 190 | long i; | ||
| 191 | |||
| 192 | ✗ | if (!OMC_ACTIVE_STREAM(logLevel)) return; | |
| 193 | ✗ | infoStreamPrint(logLevel, 1, "nls status"); | |
| 194 | |||
| 195 | ✗ | infoStreamPrint(logLevel, 1, "variables"); | |
| 196 | ✗ | for(i=0; i<solverData->n; i++) | |
| 197 | ✗ | infoStreamPrint(logLevel, 0, "[%ld] %s = %.20e\n - scaling factor internal = %.16e\n" | |
| 198 | " - scaling factor external = %.16e", i+1, | ||
| 199 | ✗ | modelInfoGetEquation(&data->modelData->modelDataXml,eqSystemNumber).vars[i], | |
| 200 | ✗ | solverData->x[i], solverData->diag[i], solverData->xScalefactors[i]); | |
| 201 | ✗ | messageClose(logLevel); | |
| 202 | |||
| 203 | ✗ | infoStreamPrint(logLevel, 1, "functions"); | |
| 204 | ✗ | for(i=0; i<solverData->n; i++) | |
| 205 | ✗ | infoStreamPrint(logLevel, 0, "res[%ld] = %.20e [scaling factor = %.16e]", i+1, solverData->fvec[i], solverData->resScaling[i]); | |
| 206 | ✗ | messageClose(logLevel); | |
| 207 | |||
| 208 | ✗ | infoStreamPrint(logLevel, 1, "statistics"); | |
| 209 | ✗ | infoStreamPrint(logLevel, 0, "nfunc = %d\nerror = %.20e\nerror_scaled = %.20e", *nfunc_evals, *xerror, *xerror_scaled); | |
| 210 | ✗ | messageClose(logLevel); | |
| 211 | |||
| 212 | ✗ | messageClose(logLevel); | |
| 213 | |||
| 214 | } | ||
| 215 | |||
| 216 | /** | ||
| 217 | * @brief Calculate numeric Jacobian matrix J(x). | ||
| 218 | * | ||
| 219 | * Using finite differences method. | ||
| 220 | * | ||
| 221 | * @param hybrdUserData Pointer to hybrid solver user data. | ||
| 222 | * @param jac Contains values of Jacobian J(x) on exit. | ||
| 223 | * @param x Vector x. | ||
| 224 | * @param f Residual values f(x). | ||
| 225 | * @return int Return 0 on success. | ||
| 226 | */ | ||
| 227 | ✗ | static int getNumericalJacobian(NLS_USERDATA* hybrdUserData, double* jac, const double* x, double* f) | |
| 228 | { | ||
| 229 | ✗ | NONLINEAR_SYSTEM_DATA* systemData = hybrdUserData->nlsData; | |
| 230 | ✗ | DATA_HYBRD* solverData = (DATA_HYBRD*) systemData->solverData; | |
| 231 | |||
| 232 | ✗ | double delta_h = sqrt(solverData->epsfcn); | |
| 233 | double delta_hh, delta_hhh, deltaInv; | ||
| 234 | ✗ | integer iflag = 1; | |
| 235 | int i, j, l; | ||
| 236 | |||
| 237 | ✗ | memcpy(solverData->xSave, x, solverData->n*sizeof(double)); | |
| 238 | |||
| 239 | ✗ | for(i = 0; i < solverData->n ; ++i) | |
| 240 | { | ||
| 241 | ✗ | delta_hhh = solverData->epsfcn * f[i]; | |
| 242 | ✗ | delta_hh = fmax(delta_h * fmax(fabs(x[i]), fabs(delta_hhh)), delta_h); | |
| 243 | ✗ | delta_hh = ((f[i] >= 0) ? delta_hh : -delta_hh); | |
| 244 | ✗ | delta_hh = x[i] + delta_hh - x[i]; | |
| 245 | ✗ | deltaInv = 1. / delta_hh; | |
| 246 | ✗ | solverData->xSave[i] = x[i] + delta_hh; | |
| 247 | |||
| 248 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_JAC)) | |
| 249 | { | ||
| 250 | ✗ | infoStreamPrint(OMC_LOG_NLS_JAC, 0, "%d. %s = %f (delta_hh = %f)", i+1, modelInfoGetEquation(&hybrdUserData->data->modelData->modelDataXml, systemData->equationIndex).vars[i], solverData->xSave[i], delta_hh); | |
| 251 | } | ||
| 252 | ✗ | wrapper_fvec_hybrj(&solverData->n, (const double*) solverData->xSave, solverData->fvecSave, solverData->fjacobian, &solverData->ldfjac, &iflag, hybrdUserData); | |
| 253 | |||
| 254 | ✗ | for(j = 0; j < solverData->n; ++j) | |
| 255 | { | ||
| 256 | ✗ | l = i*solverData->n+j; | |
| 257 | ✗ | solverData->fjacobian[l] = jac[l] = (solverData->fvecSave[j] - f[j]) * deltaInv; | |
| 258 | } | ||
| 259 | ✗ | solverData->xSave[i] = x[i]; | |
| 260 | } | ||
| 261 | |||
| 262 | ✗ | return 0; | |
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * @brief Calculate analytic Jacobian J(x). | ||
| 267 | * | ||
| 268 | * Using symbolic Jacobian and sparsity + coloring. | ||
| 269 | * x has to be set before calling this function. | ||
| 270 | * | ||
| 271 | * @param hybrdUserData Pointer to hybrid solver user data. | ||
| 272 | * @param jac Contains values of Jacobian J(x) on exit. | ||
| 273 | * @return int Return 0 on success. | ||
| 274 | */ | ||
| 275 | ✗ | static int getAnalyticalJacobian(NLS_USERDATA* hybrdUserData, double* jac) | |
| 276 | { | ||
| 277 | ✗ | DATA *data = hybrdUserData->data; | |
| 278 | ✗ | threadData_t *threadData = hybrdUserData->threadData; | |
| 279 | ✗ | NONLINEAR_SYSTEM_DATA* systemData = hybrdUserData->nlsData; | |
| 280 | ✗ | DATA_HYBRD* solverData = (DATA_HYBRD*)(systemData->solverData); | |
| 281 | ✗ | JACOBIAN* jacobian = hybrdUserData->analyticJacobian; | |
| 282 | |||
| 283 | /* call generic dense Jacobian */ | ||
| 284 | ✗ | evalJacobian(data, threadData, jacobian, NULL, jac, TRUE); | |
| 285 | |||
| 286 | ✗ | memcpy(solverData->fjacobian, jac, (jacobian->sizeRows) * (jacobian->sizeCols) * sizeof(modelica_real)); | |
| 287 | |||
| 288 | ✗ | return 0; | |
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * @brief Residual and Jacobian function. | ||
| 293 | * | ||
| 294 | * @param n Size of arrays x and f. | ||
| 295 | * @param x Vector x. | ||
| 296 | * @param f Residual vector f(x). | ||
| 297 | * Set to residual vector on exit, if iflag=1. | ||
| 298 | * Needs to be set as input, if iflag=2. | ||
| 299 | * @param fjac Array for Jacobian J(x) | ||
| 300 | * @param ldjac Leading dimension of Jacobian. | ||
| 301 | * @param iflag Flag signaling if residual or Jacobian should be evaluated. | ||
| 302 | * iflag = 1 ==> Residual evaluation | ||
| 303 | * iflag = 2 ==> Jacobian evaluation | ||
| 304 | * @param userDataIn User data. Get's typecasted to NLS_USERDATA | ||
| 305 | */ | ||
| 306 | ✗ | static void wrapper_fvec_hybrj(const integer *n_p, const double* x, double* f, double* fjac, const integer* ldjac, integer* iflag, void* userDataIn) | |
| 307 | { | ||
| 308 | int i,j; | ||
| 309 | ✗ | int n = *n_p; | |
| 310 | NLS_USERDATA* userData = (NLS_USERDATA*) userDataIn; | ||
| 311 | ✗ | DATA* data = userData->data; | |
| 312 | ✗ | threadData_t* threadData = userData->threadData; | |
| 313 | ✗ | NONLINEAR_SYSTEM_DATA* systemData = userData->nlsData; | |
| 314 | ✗ | DATA_HYBRD* hybrdData = (DATA_HYBRD*)(systemData->solverData); | |
| 315 | ✗ | modelica_boolean continuous = data->simulationInfo->solveContinuous; | |
| 316 | ✗ | RESIDUAL_USERDATA resUserData = {.data=data, .threadData=threadData, .solverData=userData->solverData}; | |
| 317 | |||
| 318 | ✗ | switch(*iflag) | |
| 319 | { | ||
| 320 | ✗ | case 1: | |
| 321 | /* re-scaling x vector */ | ||
| 322 | ✗ | if(hybrdData->useXScaling) | |
| 323 | ✗ | for(i=0; i<n; i++) | |
| 324 | ✗ | hybrdData->xScaled[i] = x[i]*hybrdData->xScalefactors[i]; | |
| 325 | |||
| 326 | /* debug output */ | ||
| 327 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_RES)) { | |
| 328 | ✗ | infoStreamPrint(OMC_LOG_NLS_RES, 0, "-- residual function call %d -- scaling = %d", (int)hybrdData->nfev, hybrdData->useXScaling); | |
| 329 | ✗ | printVector(x, n, OMC_LOG_NLS_RES, "x vector (scaled)"); | |
| 330 | ✗ | printVector(hybrdData->xScaled, n, OMC_LOG_NLS_RES, "x vector"); | |
| 331 | } | ||
| 332 | |||
| 333 | /* call residual function */ | ||
| 334 | ✗ | if(hybrdData->useXScaling){ | |
| 335 | ✗ | (systemData->residualFunc)(&resUserData, (const double*) hybrdData->xScaled, f, (const int*)iflag); | |
| 336 | } else { | ||
| 337 | ✗ | (systemData->residualFunc)(&resUserData, x, f, (const int*)iflag); | |
| 338 | } | ||
| 339 | /* A negative iflag makes MINPACK stop. */ | ||
| 340 | ✗ | if (OMC_ERROR_RAISED()) { | |
| 341 | ✗ | *iflag = -1; | |
| 342 | ✗ | return; | |
| 343 | } | ||
| 344 | |||
| 345 | /* debug output */ | ||
| 346 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_RES)) { | |
| 347 | ✗ | printVector(f, n, OMC_LOG_NLS_RES, "residuals"); | |
| 348 | ✗ | infoStreamPrint(OMC_LOG_NLS_RES, 0, "-- end of residual function call %d --", (int)hybrdData->nfev); | |
| 349 | } | ||
| 350 | |||
| 351 | ✗ | hybrdData->numberOfFunctionEvaluations++; | |
| 352 | ✗ | break; | |
| 353 | ✗ | case 2: | |
| 354 | /* set residual function continuous for jacobian calculation */ | ||
| 355 | ✗ | if(continuous) | |
| 356 | ✗ | data->simulationInfo->solveContinuous = FALSE; | |
| 357 | |||
| 358 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_RES)) | |
| 359 | ✗ | infoStreamPrint(OMC_LOG_NLS_RES, 0, "-- begin calculating jacobian --"); | |
| 360 | |||
| 361 | /* performance measurement */ | ||
| 362 | ✗ | rt_ext_tp_tick(&systemData->jacobianTimeClock); | |
| 363 | |||
| 364 | /* call apropreated jacobian function */ | ||
| 365 | ✗ | if(systemData->jacobianIndex != -1){ | |
| 366 | ✗ | integer iflagtmp = 1; | |
| 367 | ✗ | wrapper_fvec_hybrj(n_p, x, f, fjac, ldjac, &iflagtmp, userData); | |
| 368 | |||
| 369 | ✗ | getAnalyticalJacobian(userData, fjac); | |
| 370 | } | ||
| 371 | else{ | ||
| 372 | ✗ | getNumericalJacobian(userData, fjac, x, f); | |
| 373 | } | ||
| 374 | |||
| 375 | /* debug output */ | ||
| 376 | ✗ | if (OMC_ACTIVE_STREAM(OMC_LOG_NLS_RES)) { | |
| 377 | ✗ | infoStreamPrint(OMC_LOG_NLS_RES, 0, "-- end calculating jacobian --"); | |
| 378 | |||
| 379 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_JAC)) | |
| 380 | { | ||
| 381 | ✗ | char *buffer = (char*)malloc(sizeof(char)*n*25); | |
| 382 | ✗ | infoStreamPrint(OMC_LOG_NLS_JAC, 1, "jacobian matrix [%dx%d]", n, n); | |
| 383 | ✗ | for(i=0; i<n; i++) | |
| 384 | { | ||
| 385 | char *p = buffer; | ||
| 386 | ✗ | for(j=0; j<n; j++) | |
| 387 | ✗ | p += sprintf(p, "%20.12g ", fjac[i*hybrdData->n+j]); | |
| 388 | ✗ | infoStreamPrint(OMC_LOG_NLS_JAC, 0, "%s", buffer); | |
| 389 | } | ||
| 390 | ✗ | messageClose(OMC_LOG_NLS_JAC); | |
| 391 | ✗ | free(buffer); | |
| 392 | } | ||
| 393 | } | ||
| 394 | /* reset residual function again */ | ||
| 395 | ✗ | if(continuous) | |
| 396 | ✗ | data->simulationInfo->solveContinuous = TRUE; | |
| 397 | |||
| 398 | /* performance measurement and statistics */ | ||
| 399 | ✗ | systemData->jacobianTime += rt_ext_tp_tock(&(systemData->jacobianTimeClock)); | |
| 400 | ✗ | systemData->numberOfJEval++; | |
| 401 | |||
| 402 | ✗ | break; | |
| 403 | |||
| 404 | ✗ | default: | |
| 405 | ✗ | throwStreamPrint(NULL, "Well, this is embarrasing. The non-linear solver should never call this case.%d", (int)*iflag); | |
| 406 | break; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | /** | ||
| 411 | * @brief Solve non-linear system with hybrid method. | ||
| 412 | * | ||
| 413 | * @param data Runtime data struct. | ||
| 414 | * @param threadData Thread data for error handling. | ||
| 415 | * @param nlsData Pointer to non-linear system data. | ||
| 416 | * @return NLS_SOLVER_STATUS Return NLS_SOLVED on success and NLS_FAILED otherwise. | ||
| 417 | */ | ||
| 418 | ✗ | NLS_SOLVER_STATUS solveHybrd(DATA *data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA* nlsData) | |
| 419 | { | ||
| 420 | ✗ | DATA_HYBRD* hybrdData = (DATA_HYBRD*)nlsData->solverData; | |
| 421 | ✗ | int eqSystemNumber = nlsData->equationIndex; | |
| 422 | |||
| 423 | int i, j; | ||
| 424 | ✗ | integer iflag = 1; | |
| 425 | double xerror, xerror_scaled; | ||
| 426 | ✗ | NLS_SOLVER_STATUS success = NLS_FAILED; | |
| 427 | modelica_boolean catchedError; | ||
| 428 | ✗ | double local_tol = 1e-12; | |
| 429 | ✗ | double initial_factor = hybrdData->factor; | |
| 430 | ✗ | int nfunc_evals = 0; | |
| 431 | ✗ | modelica_boolean continuous = TRUE; | |
| 432 | ✗ | int nonContinuousCase = 0; | |
| 433 | |||
| 434 | ✗ | int giveUp = 0; | |
| 435 | ✗ | int retries = 0; | |
| 436 | ✗ | int retries2 = 0; | |
| 437 | ✗ | int retries3 = 0; | |
| 438 | ✗ | int assertCalled = 0; | |
| 439 | ✗ | int assertRetries = 0; | |
| 440 | ✗ | int assertMessage = 0; | |
| 441 | |||
| 442 | modelica_boolean* relationsPreBackup; | ||
| 443 | |||
| 444 | ✗ | relationsPreBackup = (modelica_boolean*) malloc(data->modelData->nRelations*sizeof(modelica_boolean)); | |
| 445 | |||
| 446 | ✗ | hybrdData->numberOfFunctionEvaluations = 0; | |
| 447 | |||
| 448 | // Initialize lambda variable | ||
| 449 | ✗ | if (nlsData->homotopySupport) { | |
| 450 | ✗ | hybrdData->x[hybrdData->n] = 1.0; | |
| 451 | ✗ | hybrdData->xSave[hybrdData->n] = 1.0; | |
| 452 | ✗ | hybrdData->xScaled[hybrdData->n] = 1.0; | |
| 453 | } | ||
| 454 | else { | ||
| 455 | ✗ | hybrdData->x[hybrdData->n] = 0.0; | |
| 456 | ✗ | hybrdData->xSave[hybrdData->n] = 0.0; | |
| 457 | ✗ | hybrdData->xScaled[hybrdData->n] = 0.0; | |
| 458 | } | ||
| 459 | |||
| 460 | /* debug output */ | ||
| 461 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 462 | { | ||
| 463 | ✗ | int indexes[2] = {1,eqSystemNumber}; | |
| 464 | ✗ | infoStreamPrintWithEquationIndexes(OMC_LOG_NLS_V, omc_dummyFileInfo, 1, indexes, | |
| 465 | "Start solving Non-Linear System %d (size %d) at time %g with Hybrd Solver", | ||
| 466 | ✗ | eqSystemNumber, (int) nlsData->size, data->localData[0]->timeValue); | |
| 467 | |||
| 468 | ✗ | for(i = 0; i < hybrdData->n; i++) { | |
| 469 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 1, "%d. %s = %f", i+1, modelInfoGetEquation(&data->modelData->modelDataXml,eqSystemNumber).vars[i], nlsData->nlsx[i]); | |
| 470 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " nominal = %f\nold = %f\nextrapolated = %f", | |
| 471 | ✗ | nlsData->nominal[i], nlsData->nlsxOld[i], nlsData->nlsxExtrapolation[i]); | |
| 472 | ✗ | messageClose(OMC_LOG_NLS_V); | |
| 473 | } | ||
| 474 | ✗ | messageClose(OMC_LOG_NLS_V); | |
| 475 | } | ||
| 476 | |||
| 477 | /* set x vector */ | ||
| 478 | ✗ | if(data->simulationInfo->discreteCall) | |
| 479 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 480 | else | ||
| 481 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 482 | |||
| 483 | ✗ | for(i=0; i<hybrdData->n; i++){ | |
| 484 | ✗ | hybrdData->xScalefactors[i] = fmax(fabs(hybrdData->x[i]), nlsData->nominal[i]); | |
| 485 | } | ||
| 486 | |||
| 487 | /* start solving loop */ | ||
| 488 | ✗ | while(!giveUp && !success) | |
| 489 | { | ||
| 490 | /* constrain x */ | ||
| 491 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 492 | ✗ | hybrdData->x[i] = fmax(nlsData->min[i], fmin(hybrdData->x[i], nlsData->max[i])); | |
| 493 | |||
| 494 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 495 | ✗ | hybrdData->xScalefactors[i] = fmax(fabs(hybrdData->x[i]), nlsData->nominal[i]); | |
| 496 | |||
| 497 | /* debug output */ | ||
| 498 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 499 | ✗ | printVector(hybrdData->xScalefactors, (hybrdData->n), OMC_LOG_NLS_V, "scaling factors x vector"); | |
| 500 | ✗ | printVector(hybrdData->x, (hybrdData->n), OMC_LOG_NLS_V, "Iteration variable values"); | |
| 501 | } | ||
| 502 | |||
| 503 | /* Scaling x vector */ | ||
| 504 | ✗ | if(hybrdData->useXScaling) { | |
| 505 | ✗ | for(i=0; i<hybrdData->n; i++) { | |
| 506 | ✗ | hybrdData->x[i] = (1.0/hybrdData->xScalefactors[i]) * hybrdData->x[i]; | |
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 510 | /* debug output */ | ||
| 511 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 512 | { | ||
| 513 | ✗ | printVector(hybrdData->x, hybrdData->n, OMC_LOG_NLS_V, "Iteration variable values (scaled)"); | |
| 514 | } | ||
| 515 | |||
| 516 | /* set residual function continuous */ | ||
| 517 | ✗ | data->simulationInfo->solveContinuous = continuous; | |
| 518 | |||
| 519 | giveUp = 1; | ||
| 520 | |||
| 521 | /* try */ | ||
| 522 | { | ||
| 523 | catchedError = TRUE; | ||
| 524 | #ifndef OMC_EMCC | ||
| 525 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 526 | #endif | ||
| 527 | ✗ | hybrj_(wrapper_fvec_hybrj, &hybrdData->n, hybrdData->x, | |
| 528 | ✗ | hybrdData->fvec, hybrdData->fjac, &hybrdData->ldfjac, &hybrdData->xtol, | |
| 529 | ✗ | &hybrdData->maxfev, hybrdData->diag, &hybrdData->mode, &hybrdData->factor, | |
| 530 | ✗ | &hybrdData->nprint, &hybrdData->info, &hybrdData->nfev, &hybrdData->njev, hybrdData->r__, | |
| 531 | &hybrdData->lr, hybrdData->qtf, hybrdData->wa1, hybrdData->wa2, | ||
| 532 | ✗ | hybrdData->wa3, hybrdData->wa4, hybrdData->userData); | |
| 533 | |||
| 534 | /* The residual raised: skip the success tail, so the retry counter | ||
| 535 | below keeps counting. */ | ||
| 536 | ✗ | if (OMC_ERROR_RAISED()) { | |
| 537 | ✗ | OMC_ERROR_CLEAR(); | |
| 538 | } else { | ||
| 539 | ✗ | if(assertCalled) | |
| 540 | { | ||
| 541 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "After assertions failed, found a solution for which assertions did not fail."); | |
| 542 | /* re-scaling x vector */ | ||
| 543 | ✗ | for(i=0; i<hybrdData->n; i++){ | |
| 544 | ✗ | if(hybrdData->useXScaling) | |
| 545 | ✗ | nlsData->nlsxOld[i] = hybrdData->x[i]*hybrdData->xScalefactors[i]; | |
| 546 | else | ||
| 547 | ✗ | nlsData->nlsxOld[i] = hybrdData->x[i]; | |
| 548 | } | ||
| 549 | } | ||
| 550 | assertRetries = 0; | ||
| 551 | assertCalled = 0; | ||
| 552 | catchedError = FALSE; | ||
| 553 | } | ||
| 554 | #ifndef OMC_EMCC | ||
| 555 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 556 | #endif | ||
| 557 | /* catch */ | ||
| 558 | ✗ | if (catchedError) | |
| 559 | { | ||
| 560 | ✗ | if (!assertMessage) | |
| 561 | { | ||
| 562 | ✗ | if (OMC_ACTIVE_WARNING_STREAM(OMC_LOG_STDOUT)) | |
| 563 | { | ||
| 564 | ✗ | if(data->simulationInfo->initial) | |
| 565 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 1, "While solving non-linear system an assertion failed during initialization."); | |
| 566 | else | ||
| 567 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 1, "While solving non-linear system an assertion failed at time %g.", data->localData[0]->timeValue); | |
| 568 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "The non-linear solver tries to solve the problem that could take some time."); | |
| 569 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "It could help to provide better start-values for the iteration variables."); | |
| 570 | ✗ | if (!OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 571 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "For more information simulate with -lv LOG_NLS_V"); | |
| 572 | ✗ | messageCloseWarning(OMC_LOG_STDOUT); | |
| 573 | } | ||
| 574 | assertMessage = 1; | ||
| 575 | } | ||
| 576 | |||
| 577 | ✗ | hybrdData->info = -1; | |
| 578 | ✗ | xerror_scaled = 1; | |
| 579 | ✗ | xerror = 1; | |
| 580 | assertCalled = 1; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | /* reset residual function continuous */ | ||
| 585 | ✗ | data->simulationInfo->solveContinuous = !continuous; | |
| 586 | |||
| 587 | /* re-scaling x vector */ | ||
| 588 | ✗ | if(hybrdData->useXScaling) | |
| 589 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 590 | ✗ | hybrdData->x[i] = hybrdData->x[i]*hybrdData->xScalefactors[i]; | |
| 591 | |||
| 592 | /* check for proper inputs */ | ||
| 593 | ✗ | if(hybrdData->info == 0) { | |
| 594 | ✗ | printErrorEqSyst(IMPROPER_INPUT, modelInfoGetEquation(&data->modelData->modelDataXml, eqSystemNumber), | |
| 595 | ✗ | data->localData[0]->timeValue); | |
| 596 | } | ||
| 597 | |||
| 598 | ✗ | if(hybrdData->info != -1) | |
| 599 | { | ||
| 600 | /* evaluate with discontinuities */ | ||
| 601 | ✗ | if(data->simulationInfo->discreteCall){ | |
| 602 | ✗ | int scaling = hybrdData->useXScaling; | |
| 603 | catchedError = TRUE; | ||
| 604 | ✗ | if(scaling) | |
| 605 | ✗ | hybrdData->useXScaling = 0; | |
| 606 | |||
| 607 | ✗ | data->simulationInfo->solveContinuous = FALSE; | |
| 608 | |||
| 609 | /* try */ | ||
| 610 | #ifndef OMC_EMCC | ||
| 611 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 612 | #endif | ||
| 613 | ✗ | wrapper_fvec_hybrj(&hybrdData->n, hybrdData->x, hybrdData->fvec, hybrdData->fjac, &hybrdData->ldfjac, &iflag, hybrdData->userData); | |
| 614 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } else { catchedError = FALSE; } | |
| 615 | #ifndef OMC_EMCC | ||
| 616 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 617 | #endif | ||
| 618 | /* catch */ | ||
| 619 | ✗ | if (catchedError) | |
| 620 | { | ||
| 621 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Non-Linear Solver try to handle a problem with a called assert."); | |
| 622 | |||
| 623 | ✗ | hybrdData->info = -1; | |
| 624 | ✗ | xerror_scaled = 1; | |
| 625 | ✗ | xerror = 1; | |
| 626 | assertCalled = 1; | ||
| 627 | } | ||
| 628 | |||
| 629 | ✗ | if(scaling) | |
| 630 | ✗ | hybrdData->useXScaling = 1; | |
| 631 | |||
| 632 | ✗ | updateRelationsPre(data); | |
| 633 | } | ||
| 634 | } | ||
| 635 | |||
| 636 | ✗ | if(hybrdData->info != -1) | |
| 637 | { | ||
| 638 | /* scaling residual vector */ | ||
| 639 | { | ||
| 640 | int l=0; | ||
| 641 | ✗ | for(i=0; i<hybrdData->n; i++){ | |
| 642 | ✗ | hybrdData->resScaling[i] = 1e-16; | |
| 643 | ✗ | for(j=0; j<hybrdData->n; j++){ | |
| 644 | ✗ | hybrdData->resScaling[i] = (fabs(hybrdData->fjacobian[l]) > hybrdData->resScaling[i]) | |
| 645 | ✗ | ? fabs(hybrdData->fjacobian[l]) : hybrdData->resScaling[i]; | |
| 646 | ✗ | l++; | |
| 647 | } | ||
| 648 | ✗ | hybrdData->fvecScaled[i] = hybrdData->fvec[i] * (1 / hybrdData->resScaling[i]); | |
| 649 | } | ||
| 650 | /* debug output */ | ||
| 651 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 652 | { | ||
| 653 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 1, "scaling factors for residual vector"); | |
| 654 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 655 | { | ||
| 656 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 1, "scaled residual [%d] : %.20e", i, hybrdData->fvecScaled[i]); | |
| 657 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "scaling factor [%d] : %.20e", i, hybrdData->resScaling[i]); | |
| 658 | ✗ | messageClose(OMC_LOG_NLS_V); | |
| 659 | } | ||
| 660 | ✗ | messageClose(OMC_LOG_NLS_V); | |
| 661 | } | ||
| 662 | |||
| 663 | /* debug output */ | ||
| 664 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_JAC)) | |
| 665 | { | ||
| 666 | ✗ | char *buffer = (char*)malloc(sizeof(char)*hybrdData->n*15); | |
| 667 | |||
| 668 | ✗ | infoStreamPrint(OMC_LOG_NLS_JAC, 1, "jacobian matrix [%dx%d]", (int)hybrdData->n, (int)hybrdData->n); | |
| 669 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 670 | { | ||
| 671 | char *p = buffer; | ||
| 672 | ✗ | for(j=0; j<hybrdData->n; j++) | |
| 673 | ✗ | p += sprintf(p, "%10g ", hybrdData->fjacobian[i*hybrdData->n+j]); | |
| 674 | ✗ | infoStreamPrint(OMC_LOG_NLS_JAC, 0, "%s", buffer); | |
| 675 | } | ||
| 676 | ✗ | messageClose(OMC_LOG_NLS_JAC); | |
| 677 | ✗ | free(buffer); | |
| 678 | } | ||
| 679 | |||
| 680 | /* check for error */ | ||
| 681 | ✗ | xerror_scaled = enorm_(&hybrdData->n, hybrdData->fvecScaled); | |
| 682 | ✗ | xerror = enorm_(&hybrdData->n, hybrdData->fvec); | |
| 683 | } | ||
| 684 | } | ||
| 685 | |||
| 686 | /* reset non-contunuousCase */ | ||
| 687 | ✗ | if(nonContinuousCase && xerror > local_tol && xerror_scaled > local_tol) | |
| 688 | { | ||
| 689 | ✗ | memcpy(data->simulationInfo->relationsPre, relationsPreBackup, sizeof(modelica_boolean)*data->modelData->nRelations); | |
| 690 | nonContinuousCase = 0; | ||
| 691 | } | ||
| 692 | |||
| 693 | ✗ | if(hybrdData->info < 4 && xerror > local_tol && xerror_scaled > local_tol) | |
| 694 | ✗ | hybrdData->info = 4; | |
| 695 | |||
| 696 | /* solution found */ | ||
| 697 | ✗ | if(hybrdData->info == 1 || xerror <= local_tol || xerror_scaled <= local_tol) | |
| 698 | { | ||
| 699 | int scaling; | ||
| 700 | |||
| 701 | ✗ | success = NLS_SOLVED; | |
| 702 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 703 | ✗ | if (OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)){ | |
| 704 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 1, "System solved"); | |
| 705 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "%d retries\n%d restarts", retries, retries2+retries3); | |
| 706 | ✗ | messageClose(OMC_LOG_NLS_V); | |
| 707 | } | ||
| 708 | ✗ | scaling = hybrdData->useXScaling; | |
| 709 | ✗ | if(scaling) | |
| 710 | ✗ | hybrdData->useXScaling = 0; | |
| 711 | |||
| 712 | /* take the solution */ | ||
| 713 | ✗ | memcpy(nlsData->nlsx, hybrdData->x, hybrdData->n*(sizeof(double))); | |
| 714 | |||
| 715 | /* try */ | ||
| 716 | { | ||
| 717 | catchedError = TRUE; | ||
| 718 | #ifndef OMC_EMCC | ||
| 719 | ✗ | OMC_TRY_INTERNAL(simulationJumpBuffer) | |
| 720 | #endif | ||
| 721 | ✗ | wrapper_fvec_hybrj(&hybrdData->n, hybrdData->x, hybrdData->fvec, hybrdData->fjac, &hybrdData->ldfjac, &iflag, hybrdData->userData); | |
| 722 | ✗ | if (OMC_ERROR_RAISED()) { OMC_ERROR_CLEAR(); } else { catchedError = FALSE; } | |
| 723 | #ifndef OMC_EMCC | ||
| 724 | ✗ | OMC_CATCH_INTERNAL(simulationJumpBuffer) | |
| 725 | #endif | ||
| 726 | /* catch */ | ||
| 727 | ✗ | if (catchedError) { | |
| 728 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Non-Linear Solver try to handle a problem with a called assert."); | |
| 729 | |||
| 730 | ✗ | hybrdData->info = 4; | |
| 731 | ✗ | xerror_scaled = 1; | |
| 732 | ✗ | xerror = 1; | |
| 733 | assertCalled = 1; | ||
| 734 | success = NLS_FAILED; | ||
| 735 | giveUp = 0; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | ✗ | if(scaling) | |
| 739 | ✗ | hybrdData->useXScaling = 1; | |
| 740 | } | ||
| 741 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && assertRetries < 1+hybrdData->n && assertCalled) | |
| 742 | { | ||
| 743 | /* case only used, when the Modelica code called an assert | ||
| 744 | * then, we try to modify start values to avoid the assert call.*/ | ||
| 745 | int i; | ||
| 746 | |||
| 747 | ✗ | memcpy(hybrdData->x, nlsData->nlsxOld, hybrdData->n*(sizeof(double))); | |
| 748 | |||
| 749 | /* set all zero values to nominal values */ | ||
| 750 | ✗ | if(assertRetries < 1) | |
| 751 | { | ||
| 752 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 753 | { | ||
| 754 | ✗ | if(nlsData->nlsx[i] == 0) | |
| 755 | { | ||
| 756 | ✗ | nlsData->nlsx[i] = nlsData->nominal[i]; | |
| 757 | ✗ | hybrdData->x[i] = nlsData->nominal[i]; | |
| 758 | } | ||
| 759 | } | ||
| 760 | } | ||
| 761 | /* change initial guess values one by one */ | ||
| 762 | ✗ | else if(assertRetries < hybrdData->n+1) | |
| 763 | { | ||
| 764 | ✗ | i = assertRetries-1; | |
| 765 | ✗ | hybrdData->x[i] += 0.01*nlsData->nominal[i]; | |
| 766 | } | ||
| 767 | |||
| 768 | ✗ | giveUp = 0; | |
| 769 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 770 | ✗ | assertRetries++; | |
| 771 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 772 | { | ||
| 773 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - try to handle a problem with a called assert vary initial value a bit. (Retry: %d)",assertRetries); | |
| 774 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 775 | } | ||
| 776 | } | ||
| 777 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && retries < 3) | |
| 778 | { | ||
| 779 | /* first try to decrease factor */ | ||
| 780 | |||
| 781 | /* set x vector */ | ||
| 782 | ✗ | if(data->simulationInfo->discreteCall) | |
| 783 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 784 | else | ||
| 785 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 786 | |||
| 787 | ✗ | hybrdData->factor = hybrdData->factor / 10.0; | |
| 788 | |||
| 789 | ✗ | retries++; | |
| 790 | ✗ | giveUp = 0; | |
| 791 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 792 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 793 | { | ||
| 794 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t decreasing initial step bound to %f.", hybrdData->factor); | |
| 795 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 796 | } | ||
| 797 | } | ||
| 798 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && retries < 4) | |
| 799 | { | ||
| 800 | /* try to vary the initial values */ | ||
| 801 | |||
| 802 | ✗ | for(i = 0; i < hybrdData->n; i++) | |
| 803 | ✗ | hybrdData->x[i] += nlsData->nominal[i] * 0.1; | |
| 804 | |||
| 805 | ✗ | hybrdData->factor = initial_factor; | |
| 806 | ✗ | retries++; | |
| 807 | ✗ | giveUp = 0; | |
| 808 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 809 | |||
| 810 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 811 | { | ||
| 812 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "iteration making no progress:\t vary solution point by 1%%."); | |
| 813 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 814 | } | ||
| 815 | } | ||
| 816 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && retries < 5) | |
| 817 | { | ||
| 818 | /* try old values as x-Scaling factors */ | ||
| 819 | |||
| 820 | /* set x vector */ | ||
| 821 | ✗ | if(data->simulationInfo->discreteCall) | |
| 822 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 823 | else | ||
| 824 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 825 | |||
| 826 | |||
| 827 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 828 | ✗ | hybrdData->xScalefactors[i] = fmax(fabs(nlsData->nlsxOld[i]), nlsData->nominal[i]); | |
| 829 | |||
| 830 | ✗ | retries++; | |
| 831 | ✗ | giveUp = 0; | |
| 832 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 833 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 834 | { | ||
| 835 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "iteration making no progress:\t try old values as scaling factors."); | |
| 836 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 837 | } | ||
| 838 | } | ||
| 839 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && retries < 6) | |
| 840 | { | ||
| 841 | int scaling = 0; | ||
| 842 | /* try to disable x-Scaling */ | ||
| 843 | |||
| 844 | /* set x vector */ | ||
| 845 | ✗ | if(data->simulationInfo->discreteCall) | |
| 846 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 847 | else | ||
| 848 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 849 | |||
| 850 | ✗ | scaling = hybrdData->useXScaling; | |
| 851 | ✗ | if(scaling) | |
| 852 | ✗ | hybrdData->useXScaling = 0; | |
| 853 | |||
| 854 | /* reset x-scaling factors */ | ||
| 855 | ✗ | for(i=0; i<hybrdData->n; i++) | |
| 856 | ✗ | hybrdData->xScalefactors[i] = fmax(fabs(hybrdData->x[i]), nlsData->nominal[i]); | |
| 857 | |||
| 858 | ✗ | retries++; | |
| 859 | ✗ | giveUp = 0; | |
| 860 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 861 | |||
| 862 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) | |
| 863 | { | ||
| 864 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "iteration making no progress:\t try without scaling at all."); | |
| 865 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 866 | } | ||
| 867 | } | ||
| 868 | ✗ | else if((hybrdData->info == 4 || hybrdData->info == 5) && retries < 7 && data->simulationInfo->discreteCall) | |
| 869 | { | ||
| 870 | /* try to solve non-continuous | ||
| 871 | * work-a-round: since other wise some model does | ||
| 872 | * stuck in event iteration. e.g.: Modelica.Mechanics.Rotational.Examples.HeatLosses | ||
| 873 | */ | ||
| 874 | |||
| 875 | ✗ | memcpy(hybrdData->x, nlsData->nlsxOld, hybrdData->n*(sizeof(double))); | |
| 876 | ✗ | retries++; | |
| 877 | |||
| 878 | /* try to solve a discontinuous system */ | ||
| 879 | ✗ | continuous = FALSE; | |
| 880 | |||
| 881 | ✗ | nonContinuousCase = 1; | |
| 882 | ✗ | memcpy(relationsPreBackup, data->simulationInfo->relationsPre, sizeof(modelica_boolean)*data->modelData->nRelations); | |
| 883 | |||
| 884 | ✗ | giveUp = 0; | |
| 885 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 886 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 887 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t try to solve a discontinuous system."); | |
| 888 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 889 | } | ||
| 890 | /* Then try with old values (instead of extrapolating )*/ | ||
| 891 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries2 < 1) { | |
| 892 | int scaling = 0; | ||
| 893 | /* set x vector */ | ||
| 894 | ✗ | memcpy(hybrdData->x, nlsData->nlsxOld, hybrdData->n*(sizeof(double))); | |
| 895 | |||
| 896 | ✗ | scaling = hybrdData->useXScaling; | |
| 897 | ✗ | if(!scaling) | |
| 898 | ✗ | hybrdData->useXScaling = 1; | |
| 899 | |||
| 900 | ✗ | continuous = TRUE; | |
| 901 | ✗ | hybrdData->factor = initial_factor; | |
| 902 | |||
| 903 | ✗ | retries = 0; | |
| 904 | ✗ | retries2++; | |
| 905 | ✗ | giveUp = 0; | |
| 906 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 907 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 908 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t use old values instead extrapolated."); | |
| 909 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 910 | } | ||
| 911 | /* try to vary the initial values */ | ||
| 912 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries2 < 2) { | |
| 913 | /* set x vector */ | ||
| 914 | ✗ | if(data->simulationInfo->discreteCall) | |
| 915 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 916 | else | ||
| 917 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 918 | ✗ | for(i = 0; i < hybrdData->n; i++) { | |
| 919 | ✗ | hybrdData->x[i] *= 1.01; | |
| 920 | }; | ||
| 921 | |||
| 922 | ✗ | retries = 0; | |
| 923 | ✗ | retries2++; | |
| 924 | ✗ | giveUp = 0; | |
| 925 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 926 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 927 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, | |
| 928 | " - iteration making no progress:\t vary initial point by adding 1%%."); | ||
| 929 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 930 | } | ||
| 931 | /* try to vary the initial values */ | ||
| 932 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries2 < 3) { | |
| 933 | /* set x vector */ | ||
| 934 | ✗ | if(data->simulationInfo->discreteCall) | |
| 935 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 936 | else | ||
| 937 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 938 | ✗ | for(i = 0; i < hybrdData->n; i++) { | |
| 939 | ✗ | hybrdData->x[i] *= 0.99; | |
| 940 | }; | ||
| 941 | |||
| 942 | ✗ | retries = 0; | |
| 943 | ✗ | retries2++; | |
| 944 | ✗ | giveUp = 0; | |
| 945 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 946 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 947 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t vary initial point by -1%%."); | |
| 948 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 949 | } | ||
| 950 | /* try to vary the initial values */ | ||
| 951 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries2 < 4) { | |
| 952 | /* set x vector */ | ||
| 953 | ✗ | memcpy(hybrdData->x, nlsData->nominal, hybrdData->n*(sizeof(double))); | |
| 954 | ✗ | retries = 0; | |
| 955 | ✗ | retries2++; | |
| 956 | ✗ | giveUp = 0; | |
| 957 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 958 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 959 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t try scaling factor as initial point."); | |
| 960 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 961 | } | ||
| 962 | /* try own scaling factors */ | ||
| 963 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries2 < 5 && !assertCalled) { | |
| 964 | /* set x vector */ | ||
| 965 | ✗ | if(data->simulationInfo->discreteCall) | |
| 966 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 967 | else | ||
| 968 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 969 | |||
| 970 | ✗ | for(i = 0; i < hybrdData->n; i++) { | |
| 971 | ✗ | hybrdData->diag[i] = fabs(hybrdData->resScaling[i]); | |
| 972 | ✗ | if(hybrdData->diag[i] <= 1e-16) | |
| 973 | ✗ | hybrdData->diag[i] = 1e-16; | |
| 974 | } | ||
| 975 | ✗ | retries = 0; | |
| 976 | ✗ | retries2++; | |
| 977 | ✗ | giveUp = 0; | |
| 978 | ✗ | hybrdData->mode = 2; | |
| 979 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 980 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 981 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t try with own scaling factors."); | |
| 982 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 983 | } | ||
| 984 | /* try without internal scaling */ | ||
| 985 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries3 < 1) { | |
| 986 | /* set x vector */ | ||
| 987 | ✗ | if(data->simulationInfo->discreteCall) | |
| 988 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 989 | else | ||
| 990 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 991 | |||
| 992 | ✗ | for(i = 0; i < hybrdData->n; i++) | |
| 993 | ✗ | hybrdData->diag[i] = 1.0; | |
| 994 | |||
| 995 | ✗ | hybrdData->useXScaling = 1; | |
| 996 | ✗ | retries = 0; | |
| 997 | ✗ | retries2 = 0; | |
| 998 | ✗ | retries3++; | |
| 999 | ✗ | hybrdData->mode = 2; | |
| 1000 | ✗ | giveUp = 0; | |
| 1001 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 1002 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 1003 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t disable solver internal scaling."); | |
| 1004 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 1005 | } | ||
| 1006 | /* try to reduce the tolerance a bit */ | ||
| 1007 | ✗ | } else if((hybrdData->info == 4 || hybrdData->info == 5) && retries3 < 6) { | |
| 1008 | /* set x vector */ | ||
| 1009 | ✗ | if(data->simulationInfo->discreteCall) | |
| 1010 | ✗ | memcpy(hybrdData->x, nlsData->nlsx, hybrdData->n*(sizeof(double))); | |
| 1011 | else | ||
| 1012 | ✗ | memcpy(hybrdData->x, nlsData->nlsxExtrapolation, hybrdData->n*(sizeof(double))); | |
| 1013 | |||
| 1014 | /* reduce tolarance */ | ||
| 1015 | ✗ | local_tol = local_tol*10; | |
| 1016 | |||
| 1017 | ✗ | hybrdData->factor = initial_factor; | |
| 1018 | ✗ | hybrdData->mode = 1; | |
| 1019 | |||
| 1020 | ✗ | retries = 0; | |
| 1021 | ✗ | retries2 = 0; | |
| 1022 | ✗ | retries3++; | |
| 1023 | |||
| 1024 | ✗ | giveUp = 0; | |
| 1025 | ✗ | nfunc_evals += hybrdData->nfev; | |
| 1026 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 1027 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, " - iteration making no progress:\t reduce the tolerance slightly to %e.", local_tol); | |
| 1028 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 1029 | } | ||
| 1030 | ✗ | } else if(hybrdData->info >= 2 && hybrdData->info <= 5) { | |
| 1031 | |||
| 1032 | /* while the initialization it's ok to every time a solution */ | ||
| 1033 | ✗ | if(!data->simulationInfo->initial){ | |
| 1034 | ✗ | printErrorEqSyst(ERROR_AT_TIME, modelInfoGetEquation(&data->modelData->modelDataXml, eqSystemNumber), data->localData[0]->timeValue); | |
| 1035 | } | ||
| 1036 | ✗ | if (OMC_ACTIVE_STREAM(OMC_LOG_NLS_V)) { | |
| 1037 | ✗ | infoStreamPrint(OMC_LOG_NLS_V, 0, "### No Solution! ###\n after %d restarts", retries*retries2*retries3); | |
| 1038 | ✗ | printStatus(data, hybrdData, eqSystemNumber, &nfunc_evals, &xerror, &xerror_scaled, OMC_LOG_NLS_V); | |
| 1039 | } | ||
| 1040 | /* take the best approximation */ | ||
| 1041 | ✗ | memcpy(nlsData->nlsx, hybrdData->x, hybrdData->n*(sizeof(double))); | |
| 1042 | |||
| 1043 | giveUp = 1; | ||
| 1044 | success = NLS_FAILED; | ||
| 1045 | ✗ | break; | |
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /* reset some solving data */ | ||
| 1050 | ✗ | hybrdData->factor = initial_factor; | |
| 1051 | ✗ | hybrdData->mode = 1; | |
| 1052 | |||
| 1053 | /* write statistics */ | ||
| 1054 | ✗ | nlsData->numberOfFEval += hybrdData->numberOfFunctionEvaluations; | |
| 1055 | /* iteration in hybrid are equal to the nfev numbers */ | ||
| 1056 | ✗ | nlsData->numberOfIterations += nfunc_evals; | |
| 1057 | |||
| 1058 | ✗ | free(relationsPreBackup); | |
| 1059 | |||
| 1060 | ✗ | return success; | |
| 1061 | } | ||
| 1062 | |||
| 1063 | #ifdef __cplusplus | ||
| 1064 | } | ||
| 1065 | #endif | ||
| 1066 |