OMCompiler/SimulationRuntime/c/linearization/linearize.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 | #include "util/omc_error.h" | ||
| 29 | #include "util/omc_file.h" | ||
| 30 | #include "simulation_data.h" | ||
| 31 | #include "openmodelica_func.h" | ||
| 32 | #include "simulation/arrayIndex.h" | ||
| 33 | #include "simulation/solver/external_input.h" | ||
| 34 | #include "simulation/options.h" | ||
| 35 | #include "simulation/solver/model_help.h" | ||
| 36 | #include "linearize.h" | ||
| 37 | #include <iostream> | ||
| 38 | #include <sstream> | ||
| 39 | #include <string> | ||
| 40 | |||
| 41 | using namespace std; | ||
| 42 | |||
| 43 | ✗ | static string array2string(double* array, int row, int col, DATA *data) | |
| 44 | { | ||
| 45 | int i=0; | ||
| 46 | int j=0; | ||
| 47 | ✗ | ostringstream retVal(ostringstream::out); | |
| 48 | retVal.precision(16); | ||
| 49 | ✗ | for(i=0; i<row; i++) | |
| 50 | { | ||
| 51 | int k = i; | ||
| 52 | ✗ | for(j=0; j<col-1; j++) | |
| 53 | { | ||
| 54 | ✗ | if (data->modelData->linearizationDumpLanguage == OMC_LINEARIZE_DUMP_LANGUAGE_JULIA) | |
| 55 | { | ||
| 56 | ✗ | retVal << array[k] << " "; // Julia matrix accepts space as separators | |
| 57 | } | ||
| 58 | else | ||
| 59 | { | ||
| 60 | ✗ | retVal << array[k] << ", "; | |
| 61 | } | ||
| 62 | ✗ | k += row; | |
| 63 | } | ||
| 64 | ✗ | if(col > 0) | |
| 65 | { | ||
| 66 | ✗ | retVal << array[k]; | |
| 67 | } | ||
| 68 | ✗ | if((i+1 != row) && (col != 0)) | |
| 69 | { | ||
| 70 | ✗ | retVal << ";\n\t"; | |
| 71 | } | ||
| 72 | } | ||
| 73 | ✗ | return retVal.str(); | |
| 74 | ✗ | } | |
| 75 | |||
| 76 | ✗ | static string array2PythonString(double* array, int row, int col) | |
| 77 | { | ||
| 78 | int i=0; | ||
| 79 | int j=0; | ||
| 80 | ✗ | ostringstream retVal(ostringstream::out); | |
| 81 | ✗ | if (row == 0 || col == 0) | |
| 82 | { | ||
| 83 | ✗ | retVal << "[]\n"; | |
| 84 | return retVal.str(); | ||
| 85 | } | ||
| 86 | |||
| 87 | retVal.precision(16); | ||
| 88 | ✗ | retVal << "["; | |
| 89 | ✗ | for(i=0; i<row; i++) | |
| 90 | { | ||
| 91 | int k = i; | ||
| 92 | ✗ | retVal << "["; | |
| 93 | ✗ | for(j=0; j<col-1; j++) | |
| 94 | { | ||
| 95 | ✗ | retVal << array[k] << ", "; | |
| 96 | ✗ | k += row; | |
| 97 | } | ||
| 98 | ✗ | if(col > 0) | |
| 99 | { | ||
| 100 | ✗ | retVal << array[k]; | |
| 101 | } | ||
| 102 | ✗ | if((i+1 != row) && (col != 0)) | |
| 103 | { | ||
| 104 | ✗ | retVal << "],\n\t"; | |
| 105 | } | ||
| 106 | } | ||
| 107 | ✗ | retVal << "]]\n"; | |
| 108 | |||
| 109 | return retVal.str(); | ||
| 110 | ✗ | } | |
| 111 | |||
| 112 | extern "C" { | ||
| 113 | |||
| 114 | ✗ | int functionODE_residual(DATA* data, threadData_t *threadData, double *dx, double *dy, double *dz) | |
| 115 | { | ||
| 116 | long i; | ||
| 117 | |||
| 118 | /* debug */ | ||
| 119 | /* printCurrentStatesVector(OMC_LOG_JAC, y, data, data->localData[0]->timeValue); */ | ||
| 120 | |||
| 121 | /* read input vars */ | ||
| 122 | ✗ | externalInputUpdate(data); | |
| 123 | ✗ | data->callback->input_function(data, threadData); | |
| 124 | |||
| 125 | /* eval input vars */ | ||
| 126 | ✗ | data->callback->functionODE(data, threadData); | |
| 127 | |||
| 128 | /* eval algebraic vars */ | ||
| 129 | ✗ | data->callback->functionAlgebraics(data, threadData); | |
| 130 | |||
| 131 | /* eval output vars */ | ||
| 132 | ✗ | data->callback->output_function(data, threadData); | |
| 133 | |||
| 134 | /* get the difference between the temp_xd(=localData->statesDerivatives) | ||
| 135 | and xd(=statesDerivativesBackup) */ | ||
| 136 | ✗ | for(i=0; i < data->modelData->nStates; i++) | |
| 137 | { | ||
| 138 | ✗ | dx[i] = data->localData[0]->realVars[data->modelData->nStates + i]; | |
| 139 | } | ||
| 140 | ✗ | for(i=0; i < data->modelData->nOutputVars; i++) | |
| 141 | { | ||
| 142 | ✗ | dy[i] = data->simulationInfo->outputVars[i]; | |
| 143 | } | ||
| 144 | ✗ | if(dz){ | |
| 145 | ✗ | for(i=0; i < (data->modelData->nVariablesReal - 2*data->modelData->nStates); i++) | |
| 146 | { | ||
| 147 | ✗ | dz[i] = data->localData[0]->realVars[2*data->modelData->nStates + i]; | |
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | ✗ | return 0; | |
| 152 | } | ||
| 153 | |||
| 154 | /* Calculate the jacobian matrix by numerical finite difference */ | ||
| 155 | ✗ | int functionJacAC_num(DATA* data, threadData_t *threadData, double *matrixA, double *matrixC, double *matrixCz) | |
| 156 | { | ||
| 157 | ✗ | const double delta_h = numericalDifferentiationDeltaXlinearize; | |
| 158 | double delta_hh; | ||
| 159 | double xsave; | ||
| 160 | |||
| 161 | double* x; | ||
| 162 | |||
| 163 | int i,j,k; | ||
| 164 | |||
| 165 | int do_data_recovery = 0; | ||
| 166 | |||
| 167 | ✗ | int size_A = data->modelData->nStates; | |
| 168 | ✗ | int size_C = data->modelData->nOutputVars; | |
| 169 | ✗ | int size_z = data->modelData->nVariablesReal - 2*data->modelData->nStates; | |
| 170 | |||
| 171 | ✗ | double* x0 = (double*)calloc(size_A,sizeof(double)); | |
| 172 | ✗ | double* y0 = (double*)calloc(size_C,sizeof(double)); | |
| 173 | ✗ | double* x1 = (double*)calloc(size_A,sizeof(double)); | |
| 174 | ✗ | double* y1 = (double*)calloc(size_C,sizeof(double)); | |
| 175 | double* z0 = 0; | ||
| 176 | double* z1 = 0; | ||
| 177 | ✗ | double *xScaling = (double*)calloc(size_A,sizeof(double)); | |
| 178 | |||
| 179 | ✗ | assertStreamPrint(threadData,0!=x0,"calloc failed"); | |
| 180 | ✗ | assertStreamPrint(threadData,0!=y0,"calloc failed"); | |
| 181 | ✗ | assertStreamPrint(threadData,0!=x1,"calloc failed"); | |
| 182 | ✗ | assertStreamPrint(threadData,0!=y1,"calloc failed"); | |
| 183 | |||
| 184 | ✗ | if(matrixCz){ | |
| 185 | do_data_recovery = 1; | ||
| 186 | } | ||
| 187 | |||
| 188 | if(do_data_recovery > 0){ | ||
| 189 | ✗ | z0 = (double*)calloc(size_z,sizeof(double)); | |
| 190 | ✗ | z1 = (double*)calloc(size_z,sizeof(double)); | |
| 191 | ✗ | assertStreamPrint(threadData,0!=z0,"calloc failed"); | |
| 192 | ✗ | assertStreamPrint(threadData,0!=z1,"calloc failed"); | |
| 193 | } | ||
| 194 | |||
| 195 | ✗ | functionODE_residual(data, threadData, x0, y0, z0); | |
| 196 | |||
| 197 | ✗ | x = data->localData[0]->realVars; | |
| 198 | |||
| 199 | /* use actually value for xScaling */ | ||
| 200 | ✗ | for (i = 0; i < size_A; i++) { | |
| 201 | ✗ | modelica_real nominal = getNominalFromScalarIdx(data->simulationInfo, data->modelData, VAR_KIND_STATE, i); | |
| 202 | ✗ | xScaling[i] = fmax(nominal, fabs(x[i])); | |
| 203 | } | ||
| 204 | |||
| 205 | /* solverData->f1 must be set outside this function based on x */ | ||
| 206 | ✗ | for(i = 0; i < size_A; i++) { | |
| 207 | ✗ | xsave = x[i]; | |
| 208 | ✗ | delta_hh = delta_h * (fabs(xsave) + 1.0); | |
| 209 | ✗ | if (xsave + delta_hh >= getMaxFromScalarIdx(data->simulationInfo, data->modelData, VAR_TYPE_REAL, VAR_KIND_VARIABLE, i)) { | |
| 210 | ✗ | delta_hh *= -1; | |
| 211 | } | ||
| 212 | ✗ | x[i] += delta_hh / xScaling[i]; | |
| 213 | /* Calculate scaled difference quotient */ | ||
| 214 | ✗ | delta_hh = 1. / delta_hh * xScaling[i]; | |
| 215 | |||
| 216 | ✗ | functionODE_residual(data, threadData, x1, y1, z1); | |
| 217 | |||
| 218 | ✗ | for(j = 0; j < size_A; j++) { | |
| 219 | ✗ | k = i * size_A + j; | |
| 220 | ✗ | matrixA[k] = (x1[j] - x0[j]) * delta_hh; | |
| 221 | } | ||
| 222 | ✗ | for(j = 0; j < size_C; j++) { | |
| 223 | ✗ | k = i * size_C + j; | |
| 224 | ✗ | matrixC[k] = (y1[j] - y0[j]) * delta_hh; | |
| 225 | } | ||
| 226 | ✗ | if(do_data_recovery > 0){ | |
| 227 | ✗ | for(j = 0; j < size_z; j++) { | |
| 228 | ✗ | k = i * size_z + j; | |
| 229 | ✗ | matrixCz[k] = (z1[j] - z0[j]) * delta_hh; | |
| 230 | } | ||
| 231 | } | ||
| 232 | ✗ | x[i] = xsave; | |
| 233 | } | ||
| 234 | |||
| 235 | ✗ | free(xScaling); | |
| 236 | ✗ | free(x0); | |
| 237 | ✗ | free(y0); | |
| 238 | ✗ | free(x1); | |
| 239 | ✗ | free(y1); | |
| 240 | ✗ | if(do_data_recovery > 0){ | |
| 241 | ✗ | free(z0); | |
| 242 | ✗ | free(z1); | |
| 243 | } | ||
| 244 | |||
| 245 | ✗ | return 0; | |
| 246 | } | ||
| 247 | |||
| 248 | ✗ | int functionJacBD_num(DATA* data, threadData_t *threadData, double *matrixB, double *matrixD, double *matrixDz) | |
| 249 | { | ||
| 250 | ✗ | const double delta_h = numericalDifferentiationDeltaXlinearize; | |
| 251 | double delta_hh; | ||
| 252 | double usave; | ||
| 253 | double* u; | ||
| 254 | |||
| 255 | int i,j,k; | ||
| 256 | |||
| 257 | int do_data_recovery = 0; | ||
| 258 | ✗ | if(matrixDz){ | |
| 259 | do_data_recovery = 1; | ||
| 260 | } | ||
| 261 | |||
| 262 | ✗ | int size_x = data->modelData->nStates; | |
| 263 | ✗ | int size_u = data->modelData->nInputVars; | |
| 264 | ✗ | int size_y = data->modelData->nOutputVars; | |
| 265 | ✗ | int size_z = data->modelData->nVariablesReal - 2*data->modelData->nStates; | |
| 266 | ✗ | double* x0 = (double*)calloc(size_x,sizeof(double)); | |
| 267 | ✗ | double* y0 = (double*)calloc(size_y,sizeof(double)); | |
| 268 | ✗ | double* x1 = (double*)calloc(size_x,sizeof(double)); | |
| 269 | ✗ | double* y1 = (double*)calloc(size_y,sizeof(double)); | |
| 270 | double* z0 = 0; | ||
| 271 | double* z1 = 0; | ||
| 272 | |||
| 273 | ✗ | assertStreamPrint(threadData,0!=x0,"calloc failed"); | |
| 274 | ✗ | assertStreamPrint(threadData,0!=y0,"calloc failed"); | |
| 275 | ✗ | assertStreamPrint(threadData,0!=x1,"calloc failed"); | |
| 276 | ✗ | assertStreamPrint(threadData,0!=y1,"calloc failed"); | |
| 277 | |||
| 278 | ✗ | if(do_data_recovery > 0){ | |
| 279 | ✗ | z0 = (double*)calloc(size_z,sizeof(double)); | |
| 280 | ✗ | z1 = (double*)calloc(size_z,sizeof(double)); | |
| 281 | ✗ | assertStreamPrint(threadData,0!=z0,"calloc failed"); | |
| 282 | ✗ | assertStreamPrint(threadData,0!=z1,"calloc failed"); | |
| 283 | } | ||
| 284 | |||
| 285 | ✗ | functionODE_residual(data, threadData, x0, y0, z0); | |
| 286 | |||
| 287 | ✗ | u = data->simulationInfo->inputVars; | |
| 288 | |||
| 289 | /* solverData->f1 must be set outside this function based on x */ | ||
| 290 | ✗ | for(i = 0; i < size_u; i++) { | |
| 291 | ✗ | usave = u[i]; | |
| 292 | ✗ | delta_hh = delta_h * (fabs(usave) + 1.0); | |
| 293 | ✗ | u[i] += delta_hh; | |
| 294 | ✗ | delta_hh = 1. / delta_hh; | |
| 295 | |||
| 296 | ✗ | functionODE_residual(data, threadData, x1, y1, z1); | |
| 297 | |||
| 298 | ✗ | for(j = 0; j < size_x; j++) { | |
| 299 | ✗ | k = i * size_x + j; | |
| 300 | ✗ | matrixB[k] = (x1[j] - x0[j]) * delta_hh; | |
| 301 | } | ||
| 302 | ✗ | for(j = 0; j < size_y; j++) { | |
| 303 | ✗ | k = i * size_y + j; | |
| 304 | ✗ | matrixD[k] = (y1[j] - y0[j]) * delta_hh; | |
| 305 | } | ||
| 306 | ✗ | if(do_data_recovery > 0){ | |
| 307 | ✗ | for(j = 0; j < size_z; j++) { | |
| 308 | ✗ | k = i * size_z + j; | |
| 309 | ✗ | matrixDz[k] = (z1[j] - z0[j]) * delta_hh; | |
| 310 | } | ||
| 311 | } | ||
| 312 | ✗ | u[i] = usave; | |
| 313 | } | ||
| 314 | |||
| 315 | ✗ | free(x0); | |
| 316 | ✗ | free(y0); | |
| 317 | ✗ | free(x1); | |
| 318 | ✗ | free(y1); | |
| 319 | ✗ | if(do_data_recovery > 0){ | |
| 320 | ✗ | free(z0); | |
| 321 | ✗ | free(z1); | |
| 322 | } | ||
| 323 | |||
| 324 | ✗ | return 0; | |
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | /* Calculate the jacobian matrix by analytical finite difference */ | ||
| 329 | ✗ | int functionJacA(DATA* data, threadData_t *threadData, double* jac){ | |
| 330 | |||
| 331 | ✗ | const int index = data->callback->INDEX_JAC_A; | |
| 332 | ✗ | JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[index]); | |
| 333 | unsigned int i,j,k; | ||
| 334 | k = 0; | ||
| 335 | ✗ | if (jacobian->constantEqns != NULL) { | |
| 336 | ✗ | jacobian->constantEqns(data, threadData, jacobian, NULL); | |
| 337 | } | ||
| 338 | |||
| 339 | ✗ | for(i=0; i < jacobian->sizeCols; i++) | |
| 340 | { | ||
| 341 | ✗ | jacobian->seedVars[i] = 1.0; | |
| 342 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 343 | { | ||
| 344 | printf("Caluculate one col:\n"); | ||
| 345 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 346 | { | ||
| 347 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"seed: jacobian->seedVars[%d]= %f",j,jacobian->seedVars[j]); | |
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | ✗ | data->callback->functionJacA_column(data, threadData, jacobian, NULL); | |
| 352 | |||
| 353 | ✗ | for(j = 0; j < jacobian->sizeRows; j++) | |
| 354 | { | ||
| 355 | ✗ | jac[k++] = jacobian->resultVars[j]; | |
| 356 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"write in jac[%d]-[%d,%d]=%g from row[%d]=%g",k-1,i,j,jac[k-1],i,jacobian->resultVars[j]); | |
| 357 | } | ||
| 358 | |||
| 359 | ✗ | jacobian->seedVars[i] = 0.0; | |
| 360 | } | ||
| 361 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 362 | { | ||
| 363 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"Print jac:"); | |
| 364 | ✗ | for(i=0; i < jacobian->sizeRows;i++) | |
| 365 | { | ||
| 366 | ✗ | for(j=0; j < jacobian->sizeCols;j++) { | |
| 367 | ✗ | printf("% .5e ",jac[i+j*jacobian->sizeCols]); | |
| 368 | } | ||
| 369 | printf("\n"); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | ✗ | return 0; | |
| 374 | } | ||
| 375 | ✗ | int functionJacB(DATA* data, threadData_t *threadData, double* jac){ | |
| 376 | |||
| 377 | ✗ | const int index = data->callback->INDEX_JAC_B; | |
| 378 | ✗ | JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[index]); | |
| 379 | |||
| 380 | unsigned int i,j,k; | ||
| 381 | k = 0; | ||
| 382 | ✗ | if (jacobian->constantEqns != NULL) { | |
| 383 | ✗ | jacobian->constantEqns(data, threadData, jacobian, NULL); | |
| 384 | } | ||
| 385 | |||
| 386 | ✗ | for(i=0; i < jacobian->sizeCols; i++) | |
| 387 | { | ||
| 388 | ✗ | jacobian->seedVars[i] = 1.0; | |
| 389 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 390 | { | ||
| 391 | printf("Caluculate one col:\n"); | ||
| 392 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 393 | { | ||
| 394 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"seed: jacobian->seedVars[%d]= %f",j,jacobian->seedVars[j]); | |
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | ✗ | data->callback->functionJacB_column(data, threadData, jacobian, NULL); | |
| 399 | |||
| 400 | ✗ | for(j = 0; j < jacobian->sizeRows; j++) | |
| 401 | { | ||
| 402 | ✗ | jac[k++] = jacobian->resultVars[j]; | |
| 403 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"write in jac[%d]-[%d,%d]=%g from row[%d]=%g",k-1,i,j,jac[k-1],i,jacobian->resultVars[j]); | |
| 404 | } | ||
| 405 | |||
| 406 | ✗ | jacobian->seedVars[i] = 0.0; | |
| 407 | } | ||
| 408 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 409 | { | ||
| 410 | ✗ | infoStreamPrint(OMC_LOG_JAC, 0, "Print jac:"); | |
| 411 | ✗ | for(i=0; i < jacobian->sizeRows;i++) | |
| 412 | { | ||
| 413 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 414 | ✗ | printf("% .5e ",jac[i+j*jacobian->sizeCols]); | |
| 415 | printf("\n"); | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | ✗ | return 0; | |
| 420 | } | ||
| 421 | ✗ | int functionJacC(DATA* data, threadData_t *threadData, double* jac){ | |
| 422 | |||
| 423 | ✗ | const int index = data->callback->INDEX_JAC_C; | |
| 424 | ✗ | JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[index]); | |
| 425 | unsigned int i,j,k; | ||
| 426 | k = 0; | ||
| 427 | ✗ | if (jacobian->constantEqns != NULL) { | |
| 428 | ✗ | jacobian->constantEqns(data, threadData, jacobian, NULL); | |
| 429 | } | ||
| 430 | |||
| 431 | ✗ | for(i=0; i < jacobian->sizeCols; i++) | |
| 432 | { | ||
| 433 | ✗ | jacobian->seedVars[i] = 1.0; | |
| 434 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 435 | { | ||
| 436 | printf("Caluculate one col:\n"); | ||
| 437 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 438 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"seed: jacobian->seedVars[%d]= %f",j,jacobian->seedVars[j]); | |
| 439 | } | ||
| 440 | |||
| 441 | ✗ | data->callback->functionJacC_column(data, threadData, jacobian, NULL); | |
| 442 | |||
| 443 | ✗ | for(j = 0; j < jacobian->sizeRows; j++) | |
| 444 | { | ||
| 445 | ✗ | jac[k++] = jacobian->resultVars[j]; | |
| 446 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"write in jac[%d]-[%d,%d]=%g from row[%d]=%g",k-1,i,j,jac[k-1],i,jacobian->resultVars[j]); | |
| 447 | } | ||
| 448 | |||
| 449 | ✗ | jacobian->seedVars[i] = 0.0; | |
| 450 | } | ||
| 451 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 452 | { | ||
| 453 | ✗ | infoStreamPrint(OMC_LOG_JAC, 0, "Print jac:"); | |
| 454 | ✗ | for(i=0; i < jacobian->sizeRows;i++) | |
| 455 | { | ||
| 456 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 457 | ✗ | printf("% .5e ",jac[i+j*jacobian->sizeCols]); | |
| 458 | printf("\n"); | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | ✗ | return 0; | |
| 463 | } | ||
| 464 | ✗ | int functionJacD(DATA* data, threadData_t *threadData, double* jac){ | |
| 465 | |||
| 466 | ✗ | const int index = data->callback->INDEX_JAC_D; | |
| 467 | ✗ | JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[index]); | |
| 468 | unsigned int i,j,k; | ||
| 469 | k = 0; | ||
| 470 | ✗ | if (jacobian->constantEqns != NULL) { | |
| 471 | ✗ | jacobian->constantEqns(data, threadData, jacobian, NULL); | |
| 472 | } | ||
| 473 | |||
| 474 | ✗ | for(i=0; i < jacobian->sizeCols; i++) | |
| 475 | { | ||
| 476 | ✗ | jacobian->seedVars[i] = 1.0; | |
| 477 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 478 | { | ||
| 479 | printf("Caluculate one col:\n"); | ||
| 480 | ✗ | for(j=0; j < jacobian->sizeCols;j++) { | |
| 481 | ✗ | infoStreamPrint(OMC_LOG_JAC,0,"seed: jacobian->seedVars[%d]= %f",j,jacobian->seedVars[j]); | |
| 482 | } | ||
| 483 | } | ||
| 484 | |||
| 485 | ✗ | data->callback->functionJacD_column(data, threadData, jacobian, NULL); | |
| 486 | |||
| 487 | ✗ | for(j = 0; j < jacobian->sizeRows; j++) | |
| 488 | { | ||
| 489 | ✗ | jac[k++] = jacobian->resultVars[j]; | |
| 490 | ✗ | infoStreamPrint(OMC_LOG_JAC,0, "write in jac[%d]-[%d,%d]=%g from row[%d]=%g",k-1,i,j,jac[k-1],i,jacobian->resultVars[j]); | |
| 491 | } | ||
| 492 | |||
| 493 | ✗ | jacobian->seedVars[i] = 0.0; | |
| 494 | } | ||
| 495 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_JAC)) | |
| 496 | { | ||
| 497 | ✗ | infoStreamPrint(OMC_LOG_JAC, 0, "Print jac:"); | |
| 498 | ✗ | for(i=0; i < jacobian->sizeRows;i++) | |
| 499 | { | ||
| 500 | ✗ | for(j=0; j < jacobian->sizeCols;j++) | |
| 501 | ✗ | printf("% .5e ",jac[i+j*jacobian->sizeCols]); | |
| 502 | printf("\n"); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | ✗ | return 0; | |
| 507 | } | ||
| 508 | |||
| 509 | |||
| 510 | |||
| 511 | ✗ | int linearize(DATA* data, threadData_t *threadData) | |
| 512 | { | ||
| 513 | /* Check if data recovery is requested */ | ||
| 514 | ✗ | int do_data_recovery = omc_flag[FLAG_L_DATA_RECOVERY] ? 1 : 0; | |
| 515 | |||
| 516 | /* init linearization sizes */ | ||
| 517 | ✗ | int size_A = data->modelData->nStates; | |
| 518 | ✗ | int size_Inputs = data->modelData->nInputVars; | |
| 519 | ✗ | int size_Outputs = data->modelData->nOutputVars; | |
| 520 | ✗ | int size_z = data->modelData->nVariablesReal - 2*data->modelData->nStates; | |
| 521 | ✗ | double* matrixA = (double*)calloc(size_A*size_A,sizeof(double)); | |
| 522 | ✗ | double* matrixB = (double*)calloc(size_A*size_Inputs,sizeof(double)); | |
| 523 | ✗ | double* matrixC = (double*)calloc(size_Outputs*size_A,sizeof(double)); | |
| 524 | ✗ | double* matrixD = (double*)calloc(size_Outputs*size_Inputs,sizeof(double)); | |
| 525 | double* matrixCz = 0; | ||
| 526 | double* matrixDz = 0; | ||
| 527 | string strA, strB, strC, strD, strCz, strDz, strX, strU, strZ0, filename, ext; | ||
| 528 | |||
| 529 | ✗ | assertStreamPrint(threadData,0!=matrixA,"calloc failed"); | |
| 530 | ✗ | assertStreamPrint(threadData,0!=matrixB,"calloc failed"); | |
| 531 | ✗ | assertStreamPrint(threadData,0!=matrixC,"calloc failed"); | |
| 532 | ✗ | assertStreamPrint(threadData,0!=matrixD,"calloc failed"); | |
| 533 | |||
| 534 | ✗ | if(do_data_recovery > 0){ | |
| 535 | ✗ | matrixCz = (double*)calloc(size_z*size_A,sizeof(double)); | |
| 536 | ✗ | matrixDz = (double*)calloc(size_z*size_Inputs,sizeof(double)); | |
| 537 | ✗ | assertStreamPrint(threadData,0!=matrixCz,"calloc failed"); | |
| 538 | ✗ | assertStreamPrint(threadData,0!=matrixDz,"calloc failed"); | |
| 539 | } | ||
| 540 | |||
| 541 | /* Need to do this before changing anything so that we get a proper z0 */ | ||
| 542 | ✗ | if(do_data_recovery > 0){ | |
| 543 | ✗ | if(size_z){ | |
| 544 | ✗ | strZ0 = "{" + array2string(&data->localData[0]->realVars[2*size_A], 1, size_z, data) + "}"; | |
| 545 | }else{ | ||
| 546 | strZ0 = "zeros(0)"; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | /* Can currently only extract data recovery matrices Cz and Dz numerically, so we do this first if necessary */ | ||
| 551 | ✗ | if(do_data_recovery > 0 || data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A].sizeTmpVars == 0){ | |
| 552 | /* Calculate numeric Jacobian */ | ||
| 553 | ✗ | if(functionJacAC_num(data, threadData, matrixA, matrixC, matrixCz)) | |
| 554 | { | ||
| 555 | ✗ | throwStreamPrint(threadData, "Error, can not get Matrix A or C "); | |
| 556 | return 1; | ||
| 557 | } | ||
| 558 | ✗ | if(functionJacBD_num(data, threadData, matrixB, matrixD, matrixDz)) | |
| 559 | { | ||
| 560 | ✗ | throwStreamPrint(threadData, "Error, can not get Matrix B or D "); | |
| 561 | return 1; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | /* Check if symbolic Jacobian available, if it is then use it (overwriting A,B,C,D if also doing data recovery) */ | ||
| 566 | ✗ | if (data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A].sizeTmpVars > 0){ | |
| 567 | /* Retrieve symbolic Jacobian */ | ||
| 568 | /* Determine Matrix A */ | ||
| 569 | JACOBIAN* jacobian = &(data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A]); | ||
| 570 | ✗ | if(!data->callback->initialAnalyticJacobianA(data, threadData, jacobian)){ | |
| 571 | ✗ | assertStreamPrint(threadData,0==functionJacA(data, threadData, matrixA),"Error, can not get Matrix A "); | |
| 572 | } | ||
| 573 | |||
| 574 | /* Determine Matrix B */ | ||
| 575 | ✗ | jacobian = &(data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_B]); | |
| 576 | ✗ | if(!data->callback->initialAnalyticJacobianB(data, threadData, jacobian)){ | |
| 577 | ✗ | assertStreamPrint(threadData,0==functionJacB(data, threadData, matrixB),"Error, can not get Matrix B "); | |
| 578 | } | ||
| 579 | |||
| 580 | /* Determine Matrix C */ | ||
| 581 | ✗ | jacobian = &(data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_C]); | |
| 582 | ✗ | if(!data->callback->initialAnalyticJacobianC(data, threadData, jacobian)){ | |
| 583 | ✗ | assertStreamPrint(threadData,0==functionJacC(data, threadData, matrixC),"Error, can not get Matrix C "); | |
| 584 | } | ||
| 585 | |||
| 586 | /* Determine Matrix D */ | ||
| 587 | ✗ | jacobian = &(data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_D]); | |
| 588 | ✗ | if(!data->callback->initialAnalyticJacobianD(data, threadData, jacobian)){ | |
| 589 | ✗ | assertStreamPrint(threadData,0==functionJacD(data, threadData, matrixD),"Error, can not get Matrix D "); | |
| 590 | } | ||
| 591 | } | ||
| 592 | ✗ | if (data->modelData->linearizationDumpLanguage != OMC_LINEARIZE_DUMP_LANGUAGE_PYTHON) | |
| 593 | { | ||
| 594 | |||
| 595 | ✗ | strA = array2string(matrixA, size_A, size_A, data); | |
| 596 | ✗ | strB = array2string(matrixB, size_A, size_Inputs, data); | |
| 597 | ✗ | strC = array2string(matrixC, size_Outputs, size_A, data); | |
| 598 | ✗ | strD = array2string(matrixD, size_Outputs, size_Inputs, data); | |
| 599 | ✗ | if (do_data_recovery > 0) | |
| 600 | { | ||
| 601 | ✗ | strCz = array2string(matrixCz, size_z, size_A, data); | |
| 602 | ✗ | strDz = array2string(matrixDz, size_z, size_Inputs, data); | |
| 603 | } | ||
| 604 | |||
| 605 | // The empty array {} is not valid modelica, so we need to put something | ||
| 606 | // inside the curly braces for x0 and u0. {for i in in 1:0} will create an | ||
| 607 | // empty array if needed. | ||
| 608 | ✗ | if (size_A) | |
| 609 | { | ||
| 610 | // fix dummping julia vector braces | ||
| 611 | ✗ | if (data->modelData->linearizationDumpLanguage == OMC_LINEARIZE_DUMP_LANGUAGE_JULIA) | |
| 612 | ✗ | strX = "[" + array2string(data->localData[0]->realVars, 1, size_A, data) + "]"; | |
| 613 | else | ||
| 614 | ✗ | strX = "{" + array2string(data->localData[0]->realVars, 1, size_A, data) + "}"; | |
| 615 | } | ||
| 616 | else | ||
| 617 | { | ||
| 618 | strX = "zeros(0)"; | ||
| 619 | } | ||
| 620 | |||
| 621 | ✗ | if (size_Inputs) | |
| 622 | { | ||
| 623 | // fix dummping julia vector braces | ||
| 624 | ✗ | if (data->modelData->linearizationDumpLanguage == OMC_LINEARIZE_DUMP_LANGUAGE_JULIA) | |
| 625 | ✗ | strU = "[" + array2string(data->simulationInfo->inputVars, 1, size_Inputs, data) + "]"; | |
| 626 | else | ||
| 627 | ✗ | strU = "{" + array2string(data->simulationInfo->inputVars, 1, size_Inputs, data) + "}"; | |
| 628 | } | ||
| 629 | else | ||
| 630 | { | ||
| 631 | strU = "zeros(0)"; | ||
| 632 | } | ||
| 633 | } | ||
| 634 | else | ||
| 635 | { | ||
| 636 | // convert the matrices to Python format | ||
| 637 | //infoStreamPrint(OMC_LOG_STDOUT, 0, "Python selected"); | ||
| 638 | ✗ | strA = array2PythonString(matrixA, size_A, size_A); | |
| 639 | ✗ | strB = array2PythonString(matrixB, size_A, size_Inputs); | |
| 640 | ✗ | strC = array2PythonString(matrixC, size_Outputs, size_A); | |
| 641 | ✗ | strD = array2PythonString(matrixD, size_Outputs, size_Inputs); | |
| 642 | ✗ | if (do_data_recovery > 0) | |
| 643 | { | ||
| 644 | ✗ | strCz = array2PythonString(matrixCz, size_z, size_A); | |
| 645 | ✗ | strDz = array2PythonString(matrixDz, size_z, size_Inputs); | |
| 646 | } | ||
| 647 | // strA = "[[-2.887152375617477, -1.62655852935388], [-2.380918056675567, -2.388394731625707]]"; | ||
| 648 | //infoStreamPrint(OMC_LOG_STDOUT, 0, strA.c_str()); | ||
| 649 | ✗ | if (size_A) | |
| 650 | ✗ | strX = "[" + array2string(data->localData[0]->realVars, 1, size_A, data) + "]"; | |
| 651 | else | ||
| 652 | strX = "[0]"; | ||
| 653 | |||
| 654 | ✗ | if (size_Inputs) | |
| 655 | ✗ | strU = "[" + array2string(data->simulationInfo->inputVars, 1, size_Inputs, data) + "]"; | |
| 656 | else | ||
| 657 | strU = "[0]"; | ||
| 658 | } | ||
| 659 | |||
| 660 | ✗ | free(matrixA); | |
| 661 | ✗ | free(matrixB); | |
| 662 | ✗ | free(matrixC); | |
| 663 | ✗ | free(matrixD); | |
| 664 | ✗ | if(do_data_recovery > 0){ | |
| 665 | ✗ | free(matrixCz); | |
| 666 | ✗ | free(matrixDz); | |
| 667 | } | ||
| 668 | ✗ | switch(data->modelData->linearizationDumpLanguage){ | |
| 669 | case OMC_LINEARIZE_DUMP_LANGUAGE_MODELICA: ext = ".mo"; break; | ||
| 670 | case OMC_LINEARIZE_DUMP_LANGUAGE_MATLAB: ext = ".m"; break; | ||
| 671 | case OMC_LINEARIZE_DUMP_LANGUAGE_JULIA: ext = ".jl"; break; | ||
| 672 | case OMC_LINEARIZE_DUMP_LANGUAGE_PYTHON: ext = ".py"; break; | ||
| 673 | } | ||
| 674 | /* ticket #5927: Don't use the model name to prevent bad names for certain languages. */ | ||
| 675 | ✗ | if (omc_flag[FLAG_OUTPUT_PATH]) { | |
| 676 | ✗ | filename = string(omc_flagValue[FLAG_OUTPUT_PATH]) + "/" + "linearized_model" + string(ext); | |
| 677 | } else { | ||
| 678 | ✗ | filename = "linearized_model" + string(ext); | |
| 679 | } | ||
| 680 | |||
| 681 | ✗ | FILE *fout = omc_fopen(filename.c_str(),"wb"); | |
| 682 | ✗ | assertStreamPrint(threadData,0!=fout,"Cannot open File %s",filename.c_str()); | |
| 683 | |||
| 684 | const char* frame = NULL; | ||
| 685 | ✗ | if(do_data_recovery > 0){ | |
| 686 | ✗ | frame = data->callback->linear_model_datarecovery_frame(); | |
| 687 | fprintf(fout, frame, strX.c_str(), strU.c_str(), strZ0.c_str(), strA.c_str(), strB.c_str(), strC.c_str(), strD.c_str(), strCz.c_str(), strDz.c_str()); | ||
| 688 | }else{ | ||
| 689 | ✗ | frame = data->callback->linear_model_frame(); | |
| 690 | ✗ | fprintf(fout, frame, strX.c_str(), strU.c_str(), strA.c_str(), strB.c_str(), strC.c_str(), strD.c_str(), (double) data->simulationInfo->stopTime); | |
| 691 | } | ||
| 692 | |||
| 693 | ✗ | fflush(fout); | |
| 694 | ✗ | fclose(fout); | |
| 695 | |||
| 696 | ✗ | if (0 == strcmp(frame, "")) { | |
| 697 | ✗ | errorStreamPrint(OMC_LOG_STDOUT, 0, "Linear model could not be created."); | |
| 698 | } else { | ||
| 699 | ✗ | if (data->modelData->runTestsuite) { | |
| 700 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "Linear model is created."); | |
| 701 | } | ||
| 702 | else { | ||
| 703 | ✗ | if (omc_flag[FLAG_OUTPUT_PATH]) { | |
| 704 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "Linear model is created at %s", filename.c_str()); | |
| 705 | } else { | ||
| 706 | char* cwd = getcwd(NULL, 0); /* call with NULL and 0 to allocate the buffer dynamically (no pathmax needed) */ | ||
| 707 | ✗ | if(!cwd) { | |
| 708 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "Linear model %s is created, but getting the full path failed.", filename.c_str()); | |
| 709 | } | ||
| 710 | else { | ||
| 711 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "Linear model is created at %s/%s", cwd, filename.c_str()); | |
| 712 | ✗ | free(cwd); | |
| 713 | } | ||
| 714 | } | ||
| 715 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "The output format can be changed with the command line option --linearizationDumpLanguage."); | |
| 716 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "The options are: --linearizationDumpLanguage=none, modelica, matlab, julia, python."); | |
| 717 | ✗ | infoStreamPrint(OMC_LOG_STDOUT, 0, "In OMEdit Simulation Setup->Linearize->Target language for linearized model."); | |
| 718 | } | ||
| 719 | } | ||
| 720 | return 0; | ||
| 721 | } | ||
| 722 | |||
| 723 | } | ||
| 724 |