OMCompiler/SimulationRuntime/cpp/Solver/Newton/Newton.cpp
| 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 | /** @addtogroup solverNewton | ||
| 29 | * | ||
| 30 | * @{ | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <Core/ModelicaDefine.h> | ||
| 34 | #include <Core/Modelica.h> | ||
| 35 | |||
| 36 | #include <Solver/Newton/FactoryExport.h> | ||
| 37 | #include <Core/Utils/extension/logger.hpp> | ||
| 38 | |||
| 39 | #include <Solver/Newton/Newton.h> | ||
| 40 | |||
| 41 | #include <Core/Math/ILapack.h> // needed for solution of linear system with Lapack | ||
| 42 | #include <Core/Math/Constants.h> // definitializeion of constants like uround | ||
| 43 | |||
| 44 | 52 | Newton::Newton(INonLinSolverSettings* settings,shared_ptr<INonLinearAlgLoop> algLoop) | |
| 45 | :AlgLoopSolverDefaultImplementation() | ||
| 46 | ,_algLoop (algLoop) | ||
| 47 | 52 | , _newtonSettings ((INonLinSolverSettings*)settings) | |
| 48 | 52 | , _yNames (NULL) | |
| 49 | 52 | , _yNominal (NULL) | |
| 50 | 52 | , _yMin (NULL) | |
| 51 | 52 | , _yMax (NULL) | |
| 52 | 52 | , _y (NULL) | |
| 53 | 52 | , _yHelp (NULL) | |
| 54 | 52 | , _yTest (NULL) | |
| 55 | 52 | , _fNominal (NULL) | |
| 56 | 52 | , _f (NULL) | |
| 57 | 52 | , _fHelp (NULL) | |
| 58 | 52 | , _fTest (NULL) | |
| 59 | 52 | , _iHelp (NULL) | |
| 60 | 52 | , _jHelp (NULL) | |
| 61 | 52 | , _jac (NULL) | |
| 62 | 52 | , _firstCall (true) | |
| 63 | 52 | , _iterationStatus (CONTINUE) | |
| 64 |
1/2✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
|
52 | , _lc (LC_NLS) |
| 65 | { | ||
| 66 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_algLoop) |
| 67 | { | ||
| 68 |
3/3✓ Branch 1 taken 52 times.
✓ Branch 4 taken 52 times.
✓ Branch 7 taken 52 times.
|
52 | AlgLoopSolverDefaultImplementation::initialize(_algLoop->getDimZeroFunc(),_algLoop->getDimReal()); |
| 69 | } | ||
| 70 | else | ||
| 71 | { | ||
| 72 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "solve for single instance is not supported"); | |
| 73 | } | ||
| 74 | 52 | } | |
| 75 | |||
| 76 | 104 | Newton::~Newton() | |
| 77 | { | ||
| 78 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yNames) delete [] _yNames; |
| 79 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yNominal) delete [] _yNominal; |
| 80 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yMin) delete [] _yMin; |
| 81 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yMax) delete [] _yMax; |
| 82 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_y) delete [] _y; |
| 83 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yHelp) delete [] _yHelp; |
| 84 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_yTest) delete [] _yTest; |
| 85 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_fNominal) delete [] _fNominal; |
| 86 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_f) delete [] _f; |
| 87 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_fHelp) delete [] _fHelp; |
| 88 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_fTest) delete [] _fTest; |
| 89 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_iHelp) delete [] _iHelp; |
| 90 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_jHelp) delete [] _jHelp; |
| 91 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_jac) delete [] _jac; |
| 92 | 104 | } | |
| 93 | |||
| 94 | 52 | void Newton::initialize() | |
| 95 | { | ||
| 96 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _firstCall = false; |
| 97 | |||
| 98 | //(Re-) initializeialization of algebraic loop | ||
| 99 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if(_algLoop) |
| 100 | 52 | _algLoop->initialize(); | |
| 101 | else | ||
| 102 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "algloop system is not initialized"); | |
| 103 | |||
| 104 | |||
| 105 | 52 | _dimSys = _algLoop->getDimReal(); | |
| 106 | |||
| 107 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (_dimSys > 0) { |
| 108 | // initialize of vectors of unknowns and residuals | ||
| 109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yNames) delete [] _yNames; |
| 110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yNominal) delete [] _yNominal; |
| 111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yMin) delete [] _yMin; |
| 112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yMax) delete [] _yMax; |
| 113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_y) delete [] _y; |
| 114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_fNominal) delete [] _fNominal; |
| 115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_f) delete [] _f; |
| 116 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yHelp) delete [] _yHelp; |
| 117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_yTest) delete [] _yTest; |
| 118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_fHelp) delete [] _fHelp; |
| 119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_fTest) delete [] _fTest; |
| 120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_iHelp) delete [] _iHelp; |
| 121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_jHelp) delete [] _jHelp; |
| 122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (_jac) delete [] _jac; |
| 123 | |||
| 124 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yNames = new const char* [_dimSys]; |
| 125 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yNominal = new double[_dimSys]; |
| 126 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yMin = new double[_dimSys]; |
| 127 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yMax = new double[_dimSys]; |
| 128 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _y = new double[_dimSys]; |
| 129 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _fNominal = new double[_dimSys]; |
| 130 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _f = new double[_dimSys]; |
| 131 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yHelp = new double[_dimSys]; |
| 132 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _yTest = new double[_dimSys]; |
| 133 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _fHelp = new double[_dimSys]; |
| 134 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _fTest = new double[_dimSys]; |
| 135 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _iHelp = new long int[_dimSys]; |
| 136 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _jHelp = new long int[_dimSys]; |
| 137 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | _jac = new double[_dimSys*_dimSys]; |
| 138 | |||
| 139 | 52 | _algLoop->getNamesReal(_yNames); | |
| 140 | 52 | _algLoop->getNominalReal(_yNominal); | |
| 141 | 52 | _algLoop->getMinReal(_yMin); | |
| 142 | 52 | _algLoop->getMaxReal(_yMax); | |
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | |||
| 147 |
2/16✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
52 | LOGGER_WRITE_BEGIN("Newton: eq" + to_string(_algLoop->getEquationIndex()) + |
| 148 | " initialized", _lc, LL_DEBUG); | ||
| 149 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2 times.
|
52 | LOGGER_WRITE_VECTOR("yNames", _yNames, _dimSys, _lc, LL_DEBUG); |
| 150 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2 times.
|
52 | LOGGER_WRITE_VECTOR("yNominal", _yNominal, _dimSys, _lc, LL_DEBUG); |
| 151 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2 times.
|
52 | LOGGER_WRITE_END(_lc, LL_DEBUG); |
| 152 | 52 | } | |
| 153 | ✗ | void Newton::solve( shared_ptr<INonLinearAlgLoop> algLoop,bool first_solve) | |
| 154 | { | ||
| 155 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "solve for single instance is not supported"); | |
| 156 | } | ||
| 157 | |||
| 158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 759169 times.
|
759169 | void Newton::solve( ) |
| 159 | { | ||
| 160 | |||
| 161 | |||
| 162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 759169 times.
|
759169 | if(!_algLoop) |
| 163 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "algloop system is not initialized"); | |
| 164 | long int | ||
| 165 | 759169 | dimRHS = 1, // Dimension of right hand side of linear system (=b) | |
| 166 | 759169 | info = 0; // Retrun-flag of Fortran code | |
| 167 | int | ||
| 168 | totSteps = 0; // Total number of steps taken | ||
| 169 | double | ||
| 170 | 759169 | atol = _newtonSettings->getAtol(), | |
| 171 | 759169 | rtol = _newtonSettings->getRtol(); | |
| 172 | |||
| 173 | // If initialize() was not called yet | ||
| 174 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 759117 times.
|
759169 | if (_firstCall) |
| 175 | 52 | initialize(); | |
| 176 | |||
| 177 | // Get current values and residuals from system | ||
| 178 | 759169 | _algLoop->getReal(_y); | |
| 179 | 759169 | _algLoop->evaluate(); | |
| 180 | 759169 | _algLoop->getRHS(_f); | |
| 181 | |||
| 182 | // Reset status flag | ||
| 183 | 759169 | _iterationStatus = CONTINUE; | |
| 184 | |||
| 185 |
2/36✓ Branch 0 taken 758007 times.
✓ Branch 1 taken 1162 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
|
759169 | LOGGER_WRITE_BEGIN("Newton: eq" + to_string(_algLoop->getEquationIndex()) + |
| 186 | " at time " + to_string(_algLoop->getSimTime()) + ":", | ||
| 187 | _lc, LL_DEBUG); | ||
| 188 | |||
| 189 |
2/2✓ Branch 0 taken 768026 times.
✓ Branch 1 taken 759169 times.
|
1527195 | while (_iterationStatus == CONTINUE) { |
| 190 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 768026 times.
|
768026 | if (totSteps >= _newtonSettings->getNewtMax()) { |
| 191 | ✗ | LOGGER_WRITE_END(_lc, LL_DEBUG); | |
| 192 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, | |
| 193 | ✗ | "error solving nonlinear system (iteration limit: " + to_string(totSteps) + ")"); | |
| 194 | } | ||
| 195 | |||
| 196 | // Newton step for non-linear system | ||
| 197 |
2/10✓ Branch 0 taken 766864 times.
✓ Branch 1 taken 1162 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
768026 | LOGGER_WRITE_VECTOR("y" + to_string(totSteps), _y, _dimSys, _lc, LL_DEBUG); |
| 198 |
2/10✓ Branch 0 taken 766864 times.
✓ Branch 1 taken 1162 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
768026 | LOGGER_WRITE_VECTOR("f" + to_string(totSteps), _f, _dimSys, _lc, LL_DEBUG); |
| 199 | |||
| 200 | 768026 | calcJacobian(_jac, _fNominal); | |
| 201 | |||
| 202 | // Initialize line search function | ||
| 203 | double phi = 0.0; | ||
| 204 |
2/2✓ Branch 0 taken 1134857 times.
✓ Branch 1 taken 768026 times.
|
1902883 | for (int i = 0; i < _dimSys; i++) { |
| 205 | 1134857 | _f[i] /= _fNominal[i]; | |
| 206 | 1134857 | phi += _f[i] * _f[i]; | |
| 207 | } | ||
| 208 | |||
| 209 | double det; | ||
| 210 |
3/4✓ Branch 0 taken 405273 times.
✓ Branch 1 taken 362753 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 405273 times.
|
768026 | if (_dimSys == 1 && (det = _jac[0]) != 0.0) { |
| 211 | det = _jac[0]; | ||
| 212 | 405273 | _f[0] /= det; | |
| 213 | 405273 | info = 0; | |
| 214 | } | ||
| 215 |
3/4✓ Branch 0 taken 360927 times.
✓ Branch 1 taken 1826 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 360927 times.
|
362753 | else if (_dimSys == 2 && (det = _jac[0]*_jac[3] - _jac[1]*_jac[2]) != 0.0) { |
| 216 | det = _jac[0]*_jac[3] - _jac[1]*_jac[2]; | ||
| 217 | 360927 | double f0 = (_f[0]*_jac[3] - _f[1]*_jac[2]) / det; | |
| 218 | 360927 | _f[1] = (_jac[0]*_f[1] - _jac[1]*_f[0]) / det; | |
| 219 | 360927 | _f[0] = f0; | |
| 220 | 360927 | info = 0; | |
| 221 | } | ||
| 222 | else { | ||
| 223 | // Solve linear system | ||
| 224 | 1826 | dgesv_(&_dimSys, &dimRHS, _jac, &_dimSys, _iHelp, _f, &_dimSys, &info); | |
| 225 | } | ||
| 226 | |||
| 227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 768026 times.
|
768026 | if (info > 0) { |
| 228 | ✗ | long int info2 = 0; | |
| 229 | ✗ | double scale = 0.0; | |
| 230 | ✗ | dgetc2_(&_dimSys, _jac, &_dimSys, _iHelp, _jHelp, &info2); | |
| 231 | ✗ | dgesc2_(&_dimSys, _jac, &_dimSys, _f, _iHelp, _jHelp, &scale); | |
| 232 | // limit change of y by f to yNominal in case of singular Jacobian | ||
| 233 | ✗ | for (int i = 0; i < _dimSys; i++) { | |
| 234 | ✗ | _f[i] = std::min(_yNominal[i], std::max(-_yNominal[i], _f[i])); | |
| 235 | } | ||
| 236 | ✗ | LOGGER_WRITE("total pivoting: dgesv/dgetc2 infos: " + to_string(info) + "/" + to_string(info2) + | |
| 237 | ", dgesc2 scale: " + to_string(scale), _lc, LL_DEBUG); | ||
| 238 | } | ||
| 239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 768026 times.
|
768026 | else if (info < 0) { |
| 240 | ✗ | LOGGER_WRITE_END(_lc, LL_DEBUG); | |
| 241 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, | |
| 242 | ✗ | "error solving nonlinear system (iteration: " + to_string(totSteps) | |
| 243 | ✗ | + ", dgesv info: " + to_string(info) + ")"); | |
| 244 | } | ||
| 245 | |||
| 246 | // Increase counter | ||
| 247 | 768026 | ++ totSteps; | |
| 248 | |||
| 249 | // New iterate | ||
| 250 | double lambda = 1.0; // step size | ||
| 251 | double alpha = 1e-4; // guard for sufficient decrease | ||
| 252 | // first find a feasible step | ||
| 253 | while (true) { | ||
| 254 |
2/2✓ Branch 0 taken 1134857 times.
✓ Branch 1 taken 768026 times.
|
1902883 | for (int i = 0; i < _dimSys; i++) { |
| 255 | 1134857 | _yHelp[i] = _y[i] - lambda * _f[i] /** _yNominal[i]*/; | |
| 256 |
2/4✓ Branch 0 taken 1134857 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1134857 times.
✗ Branch 3 not taken.
|
3404571 | _yHelp[i] = std::min(_yMax[i], std::max(_yMin[i], _yHelp[i])); |
| 257 | } | ||
| 258 | // evaluate function | ||
| 259 | try { | ||
| 260 |
1/1✓ Branch 1 taken 768026 times.
|
768026 | calcFunction(_yHelp, _fHelp); |
| 261 | } | ||
| 262 | ✗ | catch (ModelicaSimulationError& ex) { | |
| 263 | ✗ | if (lambda < 1e-10) { | |
| 264 | ✗ | LOGGER_WRITE_END(_lc, LL_DEBUG); | |
| 265 | ✗ | throw; | |
| 266 | } | ||
| 267 | // reduce step size | ||
| 268 | ✗ | lambda *= 0.5; | |
| 269 | continue; | ||
| 270 | ✗ | } | |
| 271 | break; | ||
| 272 | } | ||
| 273 | // check stopping criterion | ||
| 274 | 768026 | _iterationStatus = DONE; | |
| 275 |
2/2✓ Branch 0 taken 1134345 times.
✓ Branch 1 taken 759169 times.
|
1893514 | for (int i = 0; i < _dimSys; i++) { |
| 276 |
2/2✓ Branch 0 taken 8857 times.
✓ Branch 1 taken 1125488 times.
|
1134345 | if (std::abs(_fHelp[i]) > atol + rtol * _fNominal[i]) { |
| 277 | 8857 | _iterationStatus = CONTINUE; | |
| 278 | 8857 | break; | |
| 279 | } | ||
| 280 | } | ||
| 281 | // second do line search with quadratic approximation of phi(lambda) | ||
| 282 | // C.T.Kelley: Solving Nonlinear Equations with Newton's Method, | ||
| 283 | // no 1 in Fundamentals of Algorithms, SIAM 2003. ISBN 0-89871-546-6. | ||
| 284 | double phiHelp = 0.0; | ||
| 285 |
2/2✓ Branch 0 taken 1134857 times.
✓ Branch 1 taken 768026 times.
|
1902883 | for (int i = 0; i < _dimSys; i++) { |
| 286 | 1134857 | _fHelp[i] /= _fNominal[i]; | |
| 287 | 1134857 | phiHelp += _fHelp[i] * _fHelp[i]; | |
| 288 | } | ||
| 289 |
2/2✓ Branch 0 taken 8859 times.
✓ Branch 1 taken 759169 times.
|
768028 | while (_iterationStatus == CONTINUE) { |
| 290 | // test half step that also serves as max bound for step reduction | ||
| 291 | 8859 | double lambdaTest = 0.5*lambda; | |
| 292 |
2/2✓ Branch 0 taken 9505 times.
✓ Branch 1 taken 8859 times.
|
18364 | for (int i = 0; i < _dimSys; i++) { |
| 293 | 9505 | _yTest[i] = _y[i] - lambdaTest * _f[i] /** _yNominal[i]*/; | |
| 294 |
2/4✓ Branch 0 taken 9505 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9505 times.
✗ Branch 3 not taken.
|
28515 | _yTest[i] = std::min(_yMax[i], std::max(_yMin[i], _yTest[i])); |
| 295 | } | ||
| 296 | 8859 | calcFunction(_yTest, _fTest); | |
| 297 | double phiTest = 0.0; | ||
| 298 |
2/2✓ Branch 0 taken 9505 times.
✓ Branch 1 taken 8859 times.
|
18364 | for (int i = 0; i < _dimSys; i++) { |
| 299 | 9505 | _fTest[i] /= _fNominal[i]; | |
| 300 | 9505 | phiTest += _fTest[i] * _fTest[i]; | |
| 301 | } | ||
| 302 | // check for sufficient decrease of phiHelp | ||
| 303 | // and no further decrease with phiTest | ||
| 304 | // otherwise minimize quadratic approximation of phi(lambda) | ||
| 305 |
2/2✓ Branch 0 taken 8803 times.
✓ Branch 1 taken 56 times.
|
8859 | if (phiHelp > (1.0 - alpha * lambda) * phi || |
| 306 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8777 times.
|
8803 | phiTest < (1.0 - alpha * lambda) * phiHelp) { |
| 307 | 82 | long int n = 3; | |
| 308 | long int ipiv[3]; | ||
| 309 | 82 | double bx[] = {phi, phiTest, phiHelp}; | |
| 310 | 82 | double A[] = {1.0, 1.0, 1.0, | |
| 311 | 0.0, lambdaTest, lambda, | ||
| 312 | 82 | 0.0, lambdaTest*lambdaTest, lambda*lambda}; | |
| 313 | 82 | dgesv_(&n, &dimRHS, A, &n, ipiv, bx, &n, &info); | |
| 314 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 2 times.
|
82 | lambda = std::max(0.1*lambda, -0.5*bx[1]/bx[2]); |
| 315 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 54 times.
|
82 | if (lambda >= lambdaTest) { |
| 316 | // upper bound 0.5*lambda | ||
| 317 | lambda = lambdaTest; | ||
| 318 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | std::copy(_yTest, _yTest + _dimSys, _yHelp); |
| 319 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | std::copy(_fTest, _fTest + _dimSys, _fHelp); |
| 320 | phiHelp = phiTest; | ||
| 321 | } | ||
| 322 | else { | ||
| 323 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
|
108 | for (int i = 0; i < _dimSys; i++) { |
| 324 | 54 | _yHelp[i] = _y[i] - lambda * _f[i] /** _yNominal[i]*/; | |
| 325 |
2/4✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
|
162 | _yHelp[i] = std::min(_yMax[i], std::max(_yMin[i], _yHelp[i])); |
| 326 | } | ||
| 327 | 54 | calcFunction(_yHelp, _fHelp); | |
| 328 | phiHelp = 0.0; | ||
| 329 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
|
108 | for (int i = 0; i < _dimSys; i++) { |
| 330 | 54 | _fHelp[i] /= _fNominal[i]; | |
| 331 | 54 | phiHelp += _fHelp[i] * _fHelp[i]; | |
| 332 | } | ||
| 333 | } | ||
| 334 |
1/42✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
|
82 | LOGGER_WRITE("lambda = " + to_string(lambda) + |
| 335 | ", phi = " + to_string(phi) + | ||
| 336 | " --> " + to_string(phiHelp), | ||
| 337 | _lc, LL_DEBUG); | ||
| 338 | } | ||
| 339 | // check for stalled step control | ||
| 340 |
2/4✓ Branch 0 taken 8859 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8859 times.
✗ Branch 3 not taken.
|
8859 | if (!(lambda >= 1e-10) || !isfinite(phi)) { |
| 341 | ✗ | LOGGER_WRITE_END(_lc, LL_DEBUG); | |
| 342 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, | |
| 343 | "can't get sufficient decrease of solution" | ||
| 344 | ✗ | ", lambda = " + to_string(lambda) + ", phi = " + to_string(phi)); | |
| 345 | } | ||
| 346 | // check for sufficient decrease | ||
| 347 | // (also break for very small lambda and try a small step instead | ||
| 348 | // -- avoid "sufficient decrease" errors, still have iteration limit) | ||
| 349 |
3/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8857 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
8859 | if (phiHelp <= (1.0 - alpha * lambda) * phi || (lambda < alpha && isfinite(phiHelp))) |
| 350 | break; | ||
| 351 | } | ||
| 352 | // take iterate | ||
| 353 |
1/2✓ Branch 0 taken 768026 times.
✗ Branch 1 not taken.
|
768026 | std::copy(_yHelp, _yHelp + _dimSys, _y); |
| 354 |
2/2✓ Branch 0 taken 1134857 times.
✓ Branch 1 taken 768026 times.
|
1902883 | for (int i = 0; i < _dimSys; i++) |
| 355 | 1134857 | _f[i] = _fHelp[i] * _fNominal[i]; | |
| 356 | phi = phiHelp; | ||
| 357 | } // end while | ||
| 358 | |||
| 359 |
2/2✓ Branch 0 taken 758007 times.
✓ Branch 1 taken 1162 times.
|
759169 | LOGGER_WRITE_VECTOR("y*", _y, _dimSys, _lc, LL_DEBUG); |
| 360 |
2/2✓ Branch 0 taken 758007 times.
✓ Branch 1 taken 1162 times.
|
759169 | LOGGER_WRITE_END(_lc, LL_DEBUG); |
| 361 | 759169 | } | |
| 362 | |||
| 363 | ✗ | INonLinearAlgLoopSolver::ITERATIONSTATUS Newton::getIterationStatus() | |
| 364 | { | ||
| 365 | ✗ | return _iterationStatus; | |
| 366 | } | ||
| 367 | |||
| 368 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1903552 times.
|
1903552 | void Newton::calcFunction(const double *y, double *residual) |
| 369 | { | ||
| 370 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1903552 times.
|
1903552 | if(!_algLoop) |
| 371 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "algloop system is not initialized"); | |
| 372 | 1903552 | _algLoop->setReal(y); | |
| 373 | 1903552 | _algLoop->evaluate(); | |
| 374 | 1903552 | _algLoop->getRHS(residual); | |
| 375 | 1903552 | } | |
| 376 | |||
| 377 | ✗ | void Newton::stepCompleted(double time) | |
| 378 | { | ||
| 379 | |||
| 380 | ✗ | } | |
| 381 | |||
| 382 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 768026 times.
|
768026 | void Newton::calcJacobian(double *jac, double *fNominal) |
| 383 | { | ||
| 384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 768026 times.
|
768026 | if(!_algLoop) |
| 385 | ✗ | throw ModelicaSimulationError(ALGLOOP_SOLVER, "algloop system is not initialized"); | |
| 386 | const double *Adata = NULL; | ||
| 387 | 768026 | std::fill(fNominal, fNominal + _dimSys, 1e2 * _newtonSettings->getAtol()); | |
| 388 | |||
| 389 | // Use analytic Jacobian if available | ||
| 390 | try { | ||
| 391 |
1/1✓ Branch 1 taken 768026 times.
|
768026 | const matrix_t& A = _algLoop->getSystemMatrix(); |
| 392 |
3/4✓ Branch 0 taken 2302 times.
✓ Branch 1 taken 765724 times.
✓ Branch 2 taken 2302 times.
✗ Branch 3 not taken.
|
768026 | if (A.size1() == _dimSys && A.size2() == _dimSys) { |
| 393 | Adata = A.data().begin(); | ||
| 394 |
1/2✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
|
2302 | std::copy(Adata, Adata + _dimSys * _dimSys, jac); |
| 395 |
2/2✓ Branch 0 taken 8244 times.
✓ Branch 1 taken 2302 times.
|
10546 | for (int j = 0, idx = 0; j < _dimSys; j++) |
| 396 |
2/2✓ Branch 0 taken 31048 times.
✓ Branch 1 taken 8244 times.
|
39292 | for (int i = 0; i < _dimSys; i++, idx++) { |
| 397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31048 times.
|
31048 | if (!isfinite(jac[idx])) |
| 398 | ✗ | jac[idx] = 0.0; // remove infinite element in favor of potential singularity | |
| 399 |
2/2✓ Branch 0 taken 22798 times.
✓ Branch 1 taken 8250 times.
|
53846 | fNominal[i] = std::max(std::abs(jac[idx]) /** _yNominal[j]*/, fNominal[i]); |
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | ✗ | catch (ModelicaSimulationError& ex) { | |
| 404 | ✗ | LOGGER_WRITE("Analytic Jacobian failed for eq" + | |
| 405 | to_string(_algLoop->getEquationIndex()) + " at time " + | ||
| 406 | to_string(_algLoop->getSimTime()) + ": " + ex.what(), | ||
| 407 | _lc, LL_WARNING); | ||
| 408 | ✗ | } | |
| 409 | |||
| 410 | // Alternatively apply finite differences | ||
| 411 |
1/2✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
|
2302 | if (Adata == NULL) { |
| 412 |
2/2✓ Branch 0 taken 1126613 times.
✓ Branch 1 taken 765724 times.
|
1892337 | for (int j = 0; j < _dimSys; j++) { |
| 413 | // Reset variables for every column | ||
| 414 |
1/2✓ Branch 0 taken 1126613 times.
✗ Branch 1 not taken.
|
1126613 | std::copy(_y, _y + _dimSys, _yHelp); |
| 415 | 1126613 | double stepsize = 1e2 * _newtonSettings->getRtol() * _yNominal[j]; | |
| 416 | |||
| 417 | // Finite differences | ||
| 418 | 1126613 | _yHelp[j] += stepsize; | |
| 419 | |||
| 420 | 1126613 | calcFunction(_yHelp, _fHelp); | |
| 421 | |||
| 422 | // Build Jacobian in Fortran format | ||
| 423 |
2/2✓ Branch 0 taken 1880803 times.
✓ Branch 1 taken 1126613 times.
|
3007416 | for (int i = 0, idx = j * _dimSys; i < _dimSys; i++, idx++) { |
| 424 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1880803 times.
|
1880803 | jac[idx] = (_fHelp[i] - _f[i]) / stepsize; |
| 425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1880803 times.
|
1880803 | if (!isfinite(jac[idx])) |
| 426 | ✗ | jac[idx] = 0.0; // remove infinite element in favor of potential singularity | |
| 427 |
2/2✓ Branch 0 taken 515458 times.
✓ Branch 1 taken 1365345 times.
|
2396261 | fNominal[i] = std::max(std::abs(jac[idx]) /** _yNominal[j]*/, fNominal[i]); |
| 428 | } | ||
| 429 | |||
| 430 | 1126613 | _yHelp[j] -= stepsize; | |
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | // Scale Jacobian | ||
| 435 |
2/2✓ Branch 0 taken 766864 times.
✓ Branch 1 taken 1162 times.
|
768026 | LOGGER_WRITE_VECTOR("fNominal", fNominal, _dimSys, _lc, LL_DEBUG); |
| 436 |
2/2✓ Branch 0 taken 1134857 times.
✓ Branch 1 taken 768026 times.
|
1902883 | for (int j = 0, idx = 0; j < _dimSys; j++) |
| 437 |
2/2✓ Branch 0 taken 1911851 times.
✓ Branch 1 taken 1134857 times.
|
3046708 | for (int i = 0; i < _dimSys; i++, idx++) |
| 438 | //jac[idx] *= _yNominal[j] / fNominal[i]; | ||
| 439 | 1911851 | jac[idx] /= fNominal[i]; | |
| 440 | 768026 | } | |
| 441 | 759165 | bool* Newton::getConditionsWorkArray() | |
| 442 | { | ||
| 443 | 759165 | return AlgLoopSolverDefaultImplementation::getConditionsWorkArray(); | |
| 444 | |||
| 445 | } | ||
| 446 | 759165 | bool* Newton::getConditions2WorkArray() | |
| 447 | { | ||
| 448 | |||
| 449 | 759165 | return AlgLoopSolverDefaultImplementation::getConditions2WorkArray(); | |
| 450 | } | ||
| 451 | |||
| 452 | |||
| 453 | 759165 | double* Newton::getVariableWorkArray() | |
| 454 | { | ||
| 455 | |||
| 456 | 759165 | return AlgLoopSolverDefaultImplementation::getVariableWorkArray(); | |
| 457 | |||
| 458 | } | ||
| 459 | ✗ | void Newton::restoreOldValues() | |
| 460 | { | ||
| 461 | ✗ | } | |
| 462 | |||
| 463 | ✗ | void Newton::restoreNewValues() | |
| 464 | { | ||
| 465 | ✗ | } | |
| 466 | |||
| 467 | /** @} */ // end of solverNewton | ||
| 468 |