OMCompiler/SimulationRuntime/c/optimization/eval_all/EvalL.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 | /*! EvalL.c | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include "../OptimizerData.h" | ||
| 32 | #include "../OptimizerLocalFunction.h" | ||
| 33 | #include "../../simulation/solver/model_help.h" | ||
| 34 | |||
| 35 | static inline void calculate_hessian_matrix_numerical(double * v, const double * const lambda, const double objFactor , OptData *optData, const int i, const int j); | ||
| 36 | static inline void calculate_weighted_sum_with_lagrange_multiplicator_from_tensor(const int i, const int j, double * res, const modelica_boolean upC, OptData *optData); | ||
| 37 | static inline void calculate_hessian_matrix_numerical_last_time_intervall(double * v, const double * const lambda, const double objFactor, OptData *optData, const int i, const int j); | ||
| 38 | static inline void calculate_weighted_sum_with_lagrange_multiplicator_from_tensor_last_time_intervall(const int i, const int j, double * res, const modelica_boolean upC, const modelica_boolean upC2, OptData *optData); | ||
| 39 | |||
| 40 | |||
| 41 | static inline long double guess_step_size_for_numerical_differentiation(const long double v) | ||
| 42 | { | ||
| 43 | ✗ | return 1e-5*fabsl(v) + 1e-8; | |
| 44 | } | ||
| 45 | |||
| 46 | |||
| 47 | ✗ | static void init_hessian_structure(int *iRow, int *iCol, OptData *optData){ | |
| 48 | int i, j, k, p, l, r, c; | ||
| 49 | ✗ | const int nsi = optData->dim.nsi; | |
| 50 | ✗ | const int np = optData->dim.np; | |
| 51 | ✗ | const int np1 = np + 1; | |
| 52 | ✗ | const int nv = optData->dim.nv; | |
| 53 | |||
| 54 | ✗ | for(i = 0, r = 0, c = 0, k = 0; i + 1 < nsi; ++i){ | |
| 55 | ✗ | for(p = 1; p < np1; ++p, r += nv, c += nv){ | |
| 56 | ✗ | for(j = 0; j < nv; ++j){ | |
| 57 | ✗ | for(l = 0; l < j+1; ++l){ | |
| 58 | ✗ | if(optData->s.H0[j][l]){ | |
| 59 | ✗ | iRow[k] = r + j; | |
| 60 | ✗ | iCol[k++] = c + l; | |
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /* init_hessian_structure_last_time_intervall */ | ||
| 68 | ✗ | for(p = 1; p < np1; ++p, r += nv, c += nv){ | |
| 69 | ✗ | for(j = 0; j< nv; ++j){ | |
| 70 | ✗ | for(l = 0; l< j+1; ++l){ | |
| 71 | ✗ | if(optData->s.H1[j][l] && np == p){ | |
| 72 | ✗ | iRow[k] = r + j; | |
| 73 | ✗ | iCol[k++] = c + l; | |
| 74 | ✗ | }else if(optData->s.H0[j][l]){ | |
| 75 | ✗ | iRow[k] = r + j; | |
| 76 | ✗ | iCol[k++] = c + l; | |
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | ✗ | } | |
| 82 | |||
| 83 | ✗ | static void fill_hessian_values(double *vopt, double *lambda, double obj_factor, OptData *optData, double *values){ | |
| 84 | ✗ | const int nJ = optData->dim.nJ; | |
| 85 | const modelica_boolean do_update_cost_function = obj_factor != 0; | ||
| 86 | ✗ | const modelica_boolean do_update_mayer_cost_function = do_update_cost_function && optData->s.mayer; | |
| 87 | ✗ | const modelica_boolean do_update_lagrange_cost_function = do_update_cost_function && optData->s.lagrange; | |
| 88 | ✗ | const int np = optData->dim.np; | |
| 89 | ✗ | const int np1 = np + 1; | |
| 90 | ✗ | const int nv = optData->dim.nv; | |
| 91 | ✗ | const int nsi = optData->dim.nsi; | |
| 92 | |||
| 93 | int ii, p, i, j, k; | ||
| 94 | double * v; | ||
| 95 | double * la; | ||
| 96 | |||
| 97 | ✗ | DATA * data = optData->data; | |
| 98 | |||
| 99 | ✗ | ++optData->dim.iter; | |
| 100 | ✗ | optData->dim.iter_updateHessian = 0; | |
| 101 | ✗ | copy_initial_values(optData, data); | |
| 102 | |||
| 103 | ✗ | for(ii = 0, k = 0, v = vopt, la = lambda; ii + 1 < nsi; ++ii){ | |
| 104 | ✗ | for(p = 1; p < np1; ++p, v += nv, la += nJ){ | |
| 105 | ✗ | calculate_hessian_matrix_numerical(v, la, obj_factor, optData, ii, p-1); | |
| 106 | /*******************/ | ||
| 107 | ✗ | for(i = 0; i < nv; ++i){ | |
| 108 | ✗ | for(j = 0; j < i + 1; ++j){ | |
| 109 | ✗ | if(optData->s.H0[i][j]){ | |
| 110 | ✗ | calculate_weighted_sum_with_lagrange_multiplicator_from_tensor(i, j, values + (k++), do_update_lagrange_cost_function, optData); | |
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | /*******************/ | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /* fill_hessian_values last time intervall */ | ||
| 119 | ✗ | for(p = 1; p < np1; ++p, v += nv, la += nJ){ | |
| 120 | ✗ | calculate_hessian_matrix_numerical_last_time_intervall(v, la, obj_factor, optData, ii, p-1); | |
| 121 | ✗ | for(i = 0; i < nv; ++i){ | |
| 122 | ✗ | for(j = 0; j < i + 1; ++j){ | |
| 123 | ✗ | if(optData->s.H1[i][j] && np == p){ | |
| 124 | ✗ | calculate_weighted_sum_with_lagrange_multiplicator_from_tensor_last_time_intervall(i, j, values + (k++), do_update_lagrange_cost_function, do_update_mayer_cost_function, optData); | |
| 125 | ✗ | }else if(optData->s.H0[i][j]){ | |
| 126 | ✗ | calculate_weighted_sum_with_lagrange_multiplicator_from_tensor(i, j, values + (k++),do_update_lagrange_cost_function, optData); | |
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | ✗ | } | |
| 133 | |||
| 134 | /* eval hessian | ||
| 135 | */ | ||
| 136 | ✗ | Bool ipopt_h(int n, double *vopt, Bool new_x, double obj_factor, int m, double *lambda, Bool new_lambda, | |
| 137 | int nele_hess, int *iRow, int *iCol, double *values, void* useData){ | ||
| 138 | |||
| 139 | OptData *optData = (OptData*)useData; | ||
| 140 | ✗ | modelica_boolean keepH = optData->dim.updateHessian > optData->dim.iter_updateHessian++; | |
| 141 | |||
| 142 | ✗ | if(values == NULL){ | |
| 143 | ✗ | init_hessian_structure(iRow, iCol, optData); | |
| 144 | ✗ | }else if(keepH){ | |
| 145 | ✗ | memcpy(values,optData->oldH,nele_hess*sizeof(double)); | |
| 146 | }else{ | ||
| 147 | ✗ | if(optData->ipop.csvOstep) | |
| 148 | ✗ | debugeSteps(optData, vopt, lambda); | |
| 149 | ✗ | fill_hessian_values(vopt,lambda, obj_factor, optData, values); | |
| 150 | ✗ | if(optData->dim.updateHessian > 0) | |
| 151 | ✗ | memcpy(optData->oldH, values, nele_hess*sizeof(double)); | |
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | ✗ | return TRUE; | |
| 156 | } | ||
| 157 | |||
| 158 | /* numerical approximation | ||
| 159 | * hessian | ||
| 160 | */ | ||
| 161 | ✗ | static inline void calculate_hessian_matrix_numerical(double * v, const double * const lambda, | |
| 162 | const double objFactor , OptData *optData, const int i, const int j){ | ||
| 163 | |||
| 164 | ✗ | const modelica_boolean la = optData->s.lagrange; | |
| 165 | ✗ | const modelica_boolean upCost = la && objFactor != 0; | |
| 166 | ✗ | DATA * data = optData->data; | |
| 167 | ✗ | threadData_t *threadData = optData->threadData; | |
| 168 | |||
| 169 | ✗ | const int nv = optData->dim.nv; | |
| 170 | ✗ | const int nx = optData->dim.nx; | |
| 171 | ✗ | const int nJ = optData->dim.nJ; | |
| 172 | ✗ | const modelica_real * const vmax = optData->bounds.vmax; | |
| 173 | ✗ | const modelica_real * const vnom = optData->bounds.vnom; | |
| 174 | |||
| 175 | int ii,jj, l; | ||
| 176 | long double v_save, h; | ||
| 177 | modelica_real * realV[3]; | ||
| 178 | |||
| 179 | |||
| 180 | ✗ | for(l = 1; l<3; ++l){ | |
| 181 | ✗ | realV[l] = data->localData[l]->realVars; | |
| 182 | ✗ | data->localData[l]->realVars = optData->v[i][j]; | |
| 183 | ✗ | data->localData[l]->timeValue = (modelica_real) optData->time.t[i][j]; | |
| 184 | } | ||
| 185 | ✗ | data->localData[0]->timeValue = (modelica_real) optData->time.t[i][j]; | |
| 186 | |||
| 187 | ✗ | for(ii = 0; ii < nv; ++ii){ | |
| 188 | /********************/ | ||
| 189 | ✗ | v_save = (long double) v[ii]; | |
| 190 | h = (long double)guess_step_size_for_numerical_differentiation(v_save); | ||
| 191 | ✗ | v[ii] += h; | |
| 192 | ✗ | if( v[ii] >= vmax[ii]){ | |
| 193 | ✗ | h *= -1.0; | |
| 194 | ✗ | v[ii] = v_save + h; | |
| 195 | } | ||
| 196 | /********************/ | ||
| 197 | ✗ | for(l = 0; l < nx; ++l) | |
| 198 | ✗ | data->localData[0]->realVars[l] = v[l]*vnom[l]; | |
| 199 | ✗ | for(; l <nv; ++l) | |
| 200 | ✗ | data->simulationInfo->inputVars[l-nx] = (modelica_real) v[l]*vnom[l]; | |
| 201 | ✗ | data->callback->input_function(data, threadData); | |
| 202 | /*data->callback->functionDAE(data);*/ | ||
| 203 | ✗ | updateDiscreteSystem(data, threadData); | |
| 204 | /********************/ | ||
| 205 | ✗ | diffSynColoredOptimizerSystem(optData, optData->tmpJ, i,j,2); | |
| 206 | /********************/ | ||
| 207 | ✗ | v[ii] = (double)v_save; | |
| 208 | /********************/ | ||
| 209 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 210 | ✗ | if(optData->s.H0[ii][jj]){ | |
| 211 | ✗ | for(l = 0; l < nJ; ++l){ | |
| 212 | ✗ | if(optData->s.Hg[l][ii][jj] && lambda[l] != 0) | |
| 213 | ✗ | optData->H[l][ii][jj] = (long double)(optData->tmpJ[l][jj] - optData->J[i][j][l][jj])*lambda[l]/h; | |
| 214 | } | ||
| 215 | } | ||
| 216 | } | ||
| 217 | /********************/ | ||
| 218 | ✗ | if(upCost){ | |
| 219 | ✗ | h = objFactor/h; | |
| 220 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 221 | ✗ | if(optData->s.Hl[ii][jj]){ | |
| 222 | ✗ | optData->Hl[ii][jj] = (long double)(optData->tmpJ[nJ][jj] - optData->J[i][j][nJ][jj])*h; | |
| 223 | }else{ | ||
| 224 | ✗ | optData->Hl[ii][jj] = 0.0; | |
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | /********************/ | ||
| 229 | } | ||
| 230 | |||
| 231 | ✗ | for(l = 1; l<3; ++l){ | |
| 232 | ✗ | data->localData[l]->realVars = realV[l]; | |
| 233 | } | ||
| 234 | |||
| 235 | ✗ | } | |
| 236 | |||
| 237 | |||
| 238 | /* numerical approximation | ||
| 239 | * hessian | ||
| 240 | */ | ||
| 241 | ✗ | static inline void calculate_hessian_matrix_numerical_last_time_intervall(double * v, const double * const lambda, | |
| 242 | const double objFactor, OptData *optData, const int i, const int j){ | ||
| 243 | |||
| 244 | ✗ | const modelica_boolean la = optData->s.lagrange; | |
| 245 | ✗ | const modelica_boolean ma = optData->s.mayer; | |
| 246 | ✗ | const modelica_boolean upCost = la && objFactor != 0; | |
| 247 | |||
| 248 | ✗ | const int nv = optData->dim.nv; | |
| 249 | ✗ | const int nx = optData->dim.nx; | |
| 250 | ✗ | const int np = optData->dim.np; | |
| 251 | ✗ | const int nJ = optData->dim.nJ; | |
| 252 | ✗ | const int nJ1 = optData->dim.nJ + 1; | |
| 253 | ✗ | const int nsi = optData->dim.nsi; | |
| 254 | ✗ | const int ncf = optData->dim.ncf; | |
| 255 | ✗ | const modelica_real * const vmax = optData->bounds.vmax; | |
| 256 | ✗ | const modelica_real * const vnom = optData->bounds.vnom; | |
| 257 | ✗ | const modelica_boolean upFinalCon = np == j + 1 && nsi == i +1; | |
| 258 | ✗ | const modelica_boolean upCost2 = upFinalCon && ma && objFactor != 0; | |
| 259 | const short indexJ = (upCost2) ? 3 : 2; | ||
| 260 | int ii,jj, l,k; | ||
| 261 | long double v_save, h; | ||
| 262 | ✗ | DATA * data = optData->data; | |
| 263 | ✗ | threadData_t *threadData = optData->threadData; | |
| 264 | |||
| 265 | modelica_real * realV[3]; | ||
| 266 | |||
| 267 | ✗ | data->localData[0]->timeValue = (modelica_real) optData->time.t[i][j]; | |
| 268 | ✗ | for(l = 1; l<3; ++l){ | |
| 269 | ✗ | realV[l] = data->localData[l]->realVars; | |
| 270 | ✗ | data->localData[l]->realVars = optData->v[i][j]; | |
| 271 | ✗ | data->localData[l]->timeValue = (modelica_real) optData->time.t[i][j]; | |
| 272 | } | ||
| 273 | |||
| 274 | ✗ | for(ii = 0; ii < nv; ++ii){ | |
| 275 | /********************/ | ||
| 276 | ✗ | v_save = (long double) v[ii]; | |
| 277 | h = (long double)guess_step_size_for_numerical_differentiation(v_save); | ||
| 278 | ✗ | v[ii] += h; | |
| 279 | ✗ | if(v[ii] > vmax[ii]){ | |
| 280 | ✗ | h *= -1.0; | |
| 281 | ✗ | v[ii] = v_save + h; | |
| 282 | } | ||
| 283 | /********************/ | ||
| 284 | ✗ | for(l = 0; l < nx; ++l) | |
| 285 | ✗ | data->localData[0]->realVars[l] = v[l]*vnom[l]; | |
| 286 | ✗ | for(; l <nv; ++l) | |
| 287 | ✗ | data->simulationInfo->inputVars[l-nx] = (modelica_real) v[l]*vnom[l]; | |
| 288 | |||
| 289 | ✗ | data->callback->input_function(data, threadData); | |
| 290 | /*data->callback->functionDAE(data);*/ | ||
| 291 | ✗ | updateDiscreteSystem(data, threadData); | |
| 292 | /********************/ | ||
| 293 | ✗ | diffSynColoredOptimizerSystem(optData, optData->tmpJ, i,j,indexJ); | |
| 294 | /********************/ | ||
| 295 | ✗ | v[ii] = (double)v_save; | |
| 296 | /********************/ | ||
| 297 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 298 | ✗ | if(optData->s.H0[ii][jj]){ | |
| 299 | ✗ | for(l = 0; l < nJ; ++l){ | |
| 300 | ✗ | if(optData->s.Hg[l][ii][jj]) | |
| 301 | ✗ | optData->H[l][ii][jj] = (long double)(optData->tmpJ[l][jj] - optData->J[i][j][l][jj])*lambda[l]/h; | |
| 302 | } | ||
| 303 | } | ||
| 304 | } | ||
| 305 | /********************/ | ||
| 306 | ✗ | if(upCost){ | |
| 307 | long double hh; | ||
| 308 | ✗ | hh = objFactor/h; | |
| 309 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 310 | ✗ | if(optData->s.Hl[ii][jj]){ | |
| 311 | ✗ | optData->Hl[ii][jj] = (long double)(optData->tmpJ[nJ][jj] - optData->J[i][j][nJ][jj])*hh; | |
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | /********************/ | ||
| 316 | ✗ | if(upCost2){ | |
| 317 | long double hh; | ||
| 318 | ✗ | hh = objFactor/h; | |
| 319 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 320 | ✗ | if(optData->s.Hm[ii][jj]){ | |
| 321 | ✗ | optData->Hm[ii][jj] = (long double)(optData->tmpJ[nJ1][jj] - optData->J[i][j][nJ1][jj])*hh; | |
| 322 | } | ||
| 323 | } | ||
| 324 | } | ||
| 325 | /********************/ | ||
| 326 | ✗ | if(upFinalCon && ncf > 0){ | |
| 327 | ✗ | diffSynColoredOptimizerSystemF(optData, optData->tmpJf); | |
| 328 | ✗ | for(jj = 0; jj <ii+1; ++jj){ | |
| 329 | ✗ | if(optData->s.H0[ii][jj]){ | |
| 330 | ✗ | for(l = 0; l < ncf; ++l){ | |
| 331 | ✗ | if(optData->s.Hcf[l][ii][jj]){ | |
| 332 | ✗ | optData->Hcf[l][ii][jj] = (long double)(optData->tmpJf[l][jj] - optData->Jf[l][jj])*lambda[nJ+l]/h; | |
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | /********************/ | ||
| 339 | } | ||
| 340 | |||
| 341 | ✗ | for(l = 1; l<3; ++l){ | |
| 342 | ✗ | data->localData[l]->realVars = realV[l]; | |
| 343 | } | ||
| 344 | |||
| 345 | ✗ | } | |
| 346 | |||
| 347 | |||
| 348 | /* eval hessian for lagrange | ||
| 349 | */ | ||
| 350 | ✗ | static inline void calculate_weighted_sum_with_lagrange_multiplicator_from_tensor(const int i, const int j, double * res, | |
| 351 | const modelica_boolean upC, OptData *optData){ | ||
| 352 | ✗ | const int nJ = optData->dim.nJ; | |
| 353 | |||
| 354 | long double sum = 0.0; | ||
| 355 | int l; | ||
| 356 | |||
| 357 | ✗ | for(l = 0; l< nJ; ++l){ | |
| 358 | ✗ | if(optData->s.Hg[l][i][j]) | |
| 359 | ✗ | sum += optData->H[l][i][j]; | |
| 360 | } | ||
| 361 | |||
| 362 | ✗ | if(upC && optData->s.Hl[i][j]) | |
| 363 | ✗ | sum += optData->Hl[i][j]; | |
| 364 | |||
| 365 | ✗ | *res = (double) sum; | |
| 366 | |||
| 367 | ✗ | } | |
| 368 | |||
| 369 | /* eval hessian for lagrange | ||
| 370 | */ | ||
| 371 | ✗ | static inline void calculate_weighted_sum_with_lagrange_multiplicator_from_tensor_last_time_intervall(const int i, const int j, double * res, | |
| 372 | const modelica_boolean upC, const modelica_boolean upC2, OptData *optData){ | ||
| 373 | ✗ | const int nJ = optData->dim.nJ; | |
| 374 | ✗ | const int ncf = optData->dim.ncf; | |
| 375 | |||
| 376 | long double sum = 0.0; | ||
| 377 | int l; | ||
| 378 | |||
| 379 | ✗ | if(optData->s.H0[i][j]){ | |
| 380 | ✗ | for(l = 0; l< nJ; ++l){ | |
| 381 | ✗ | if(optData->s.Hg[l][i][j]) | |
| 382 | ✗ | sum += optData->H[l][i][j]; | |
| 383 | } | ||
| 384 | |||
| 385 | ✗ | if(upC && optData->s.Hl[i][j]) | |
| 386 | ✗ | sum += optData->Hl[i][j]; | |
| 387 | } | ||
| 388 | ✗ | for(l = 0; l< ncf; ++l){ | |
| 389 | ✗ | if(optData->s.Hcf[l][i][j]) | |
| 390 | ✗ | sum += optData->Hcf[l][i][j]; | |
| 391 | } | ||
| 392 | ✗ | if(upC2 && optData->s.Hm[i][j]) | |
| 393 | ✗ | sum += optData->Hm[i][j]; | |
| 394 | |||
| 395 | ✗ | *res = (double) sum; | |
| 396 | |||
| 397 | ✗ | } | |
| 398 | |||
| 399 |