OMCompiler/SimulationRuntime/c/simulation/solver/mixedSearchSolver.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 mixedSearchSolver.c | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <math.h> | ||
| 32 | #include <stdlib.h> | ||
| 33 | #include <string.h> /* memcpy */ | ||
| 34 | |||
| 35 | #include "../simulation_info_json.h" | ||
| 36 | #include "../../util/omc_error.h" | ||
| 37 | #include "../../util/varinfo.h" | ||
| 38 | #include "model_help.h" | ||
| 39 | |||
| 40 | #include "nonlinearSystem.h" | ||
| 41 | #include "nonlinearSolverHybrd.h" | ||
| 42 | |||
| 43 | typedef struct DATA_SEARCHMIXED_SOLVER | ||
| 44 | { | ||
| 45 | modelica_boolean* iterationVars; | ||
| 46 | modelica_boolean* iterationVars2; | ||
| 47 | modelica_boolean* iterationVarsPre; | ||
| 48 | |||
| 49 | long* iterationVarsIndex; | ||
| 50 | |||
| 51 | modelica_boolean* stateofSearch; | ||
| 52 | |||
| 53 | }DATA_SEARCHMIXED_SOLVER; | ||
| 54 | |||
| 55 | |||
| 56 | /*! \fn allocate memory for mixed systems search solver | ||
| 57 | * | ||
| 58 | */ | ||
| 59 | ✗ | int allocateMixedSearchData(int size, void** voiddata) | |
| 60 | { | ||
| 61 | ✗ | DATA_SEARCHMIXED_SOLVER* data = (DATA_SEARCHMIXED_SOLVER*) malloc(sizeof(DATA_SEARCHMIXED_SOLVER)); | |
| 62 | ✗ | *voiddata = (void*)data; | |
| 63 | ✗ | assertStreamPrint(NULL, 0 != data, "allocationHybrdData() failed!"); | |
| 64 | |||
| 65 | ✗ | data->iterationVars = (modelica_boolean*) malloc(size*sizeof(modelica_boolean)); | |
| 66 | ✗ | data->iterationVars2 = (modelica_boolean*) malloc(size*sizeof(modelica_boolean)); | |
| 67 | ✗ | data->iterationVarsPre = (modelica_boolean*) malloc(size*sizeof(modelica_boolean)); | |
| 68 | |||
| 69 | ✗ | data->stateofSearch = (modelica_boolean*) malloc(size*sizeof(modelica_boolean)); | |
| 70 | |||
| 71 | assertStreamPrint(NULL, 0 != *voiddata, "allocateMixedSearchData() voiddata failed!"); | ||
| 72 | ✗ | return 0; | |
| 73 | } | ||
| 74 | |||
| 75 | /*! \fn free memory for mixed systems search solver | ||
| 76 | * | ||
| 77 | */ | ||
| 78 | ✗ | int freeMixedSearchData(void **voiddata) | |
| 79 | { | ||
| 80 | ✗ | DATA_SEARCHMIXED_SOLVER* data = (DATA_SEARCHMIXED_SOLVER*) *voiddata; | |
| 81 | |||
| 82 | ✗ | free(data->iterationVars); | |
| 83 | ✗ | free(data->iterationVars2); | |
| 84 | ✗ | free(data->iterationVarsPre); | |
| 85 | |||
| 86 | ✗ | free(data->stateofSearch); | |
| 87 | |||
| 88 | ✗ | return 0; | |
| 89 | } | ||
| 90 | |||
| 91 | /*! \fn nextVar | ||
| 92 | * | ||
| 93 | * function is used in generated code for mixed equation systems | ||
| 94 | * to generate next combination of boolean variables. | ||
| 95 | * Example: for n = 3 | ||
| 96 | * generates sequence: 000, 100, 010, 001, 110, 101, 011, 111 | ||
| 97 | * | ||
| 98 | * \param [ref] [data] | ||
| 99 | * | ||
| 100 | * \author Jan Silar | ||
| 101 | * | ||
| 102 | * \brief | ||
| 103 | */ | ||
| 104 | ✗ | modelica_boolean nextVar(modelica_boolean *b, int n) { | |
| 105 | /*number of "1" */ | ||
| 106 | int n1 = 0; | ||
| 107 | int i; | ||
| 108 | int last; | ||
| 109 | ✗ | for(i = 0; i < n; i++){ | |
| 110 | ✗ | if(b[i] == 1) | |
| 111 | ✗ | n1++; | |
| 112 | } | ||
| 113 | /*index of last element with "1"*/ | ||
| 114 | ✗ | last = n - 1; | |
| 115 | ✗ | while(last >= 0 && !b[last]) | |
| 116 | ✗ | last--; | |
| 117 | ✗ | if(n1 == n) /*exit - all combination were already generated*/ | |
| 118 | return 0; | ||
| 119 | ✗ | else if(last == -1) { /* 0000 -> 1000 */ | |
| 120 | ✗ | b[0] = 1; | |
| 121 | ✗ | return 1; | |
| 122 | ✗ | } else if(last < n - 1) { /* e.g. 1010 -> 1001 */ | |
| 123 | ✗ | b[last] = 0; | |
| 124 | ✗ | b[last + 1] = 1; | |
| 125 | ✗ | return 1; | |
| 126 | } else { /*at the end of the array is "1"*/ | ||
| 127 | /*detect position of last ocurenc of sequence 10 */ | ||
| 128 | ✗ | int ip = n - 2; /*actual position in array*/ | |
| 129 | int nr1 = 1; /*count of "1"*/ | ||
| 130 | ✗ | while(ip >= 0) { | |
| 131 | ✗ | if(b[ip] && !b[ip + 1]) { /*we found*/ | |
| 132 | ✗ | nr1++; | |
| 133 | ✗ | break; | |
| 134 | ✗ | } else if(b[ip]) { /*we didn't find, but 1 - increase nr1*/ | |
| 135 | ✗ | nr1++; | |
| 136 | ✗ | ip--; | |
| 137 | } else { /*we didnt't find, 0*/ | ||
| 138 | ✗ | ip--; | |
| 139 | } | ||
| 140 | } | ||
| 141 | ✗ | if(ip >= 0) { /*e.g. 1001 -> 0110*/ | |
| 142 | ✗ | int pn = ip + nr1; | |
| 143 | ✗ | b[ip] = 0; | |
| 144 | ✗ | for(i = ip + 1; i <= pn; i++) | |
| 145 | ✗ | b[i] = 1; | |
| 146 | ✗ | for(i = pn + 1; i <= n - 1; i++) | |
| 147 | ✗ | b[i] = 0; | |
| 148 | return 1; | ||
| 149 | } else { | ||
| 150 | ✗ | for(i = 0; i <= n1; i++) | |
| 151 | ✗ | b[i] = 1; | |
| 152 | ✗ | for(i = n1 + 1; i <= n - 1; i++) | |
| 153 | ✗ | b[i] = 0; | |
| 154 | return 1; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /*! \fn solve mixed system with extended search | ||
| 160 | * | ||
| 161 | * \param [in] [data] | ||
| 162 | * [sysNumber] index of the corresponing mixed system | ||
| 163 | * | ||
| 164 | * \author wbraun | ||
| 165 | */ | ||
| 166 | ✗ | int solveMixedSearch(DATA *data, int sysNumber) | |
| 167 | { | ||
| 168 | ✗ | MIXED_SYSTEM_DATA* systemData = &(data->simulationInfo->mixedSystemData[sysNumber]); | |
| 169 | ✗ | DATA_SEARCHMIXED_SOLVER* solverData = (DATA_SEARCHMIXED_SOLVER*)systemData->solverData; | |
| 170 | |||
| 171 | ✗ | int eqSystemNumber = systemData->equationIndex; | |
| 172 | |||
| 173 | int found_solution = 0; | ||
| 174 | /* | ||
| 175 | * We are given the number of the non-linear system. | ||
| 176 | * We want to look it up among all equations. | ||
| 177 | */ | ||
| 178 | int i, ix; | ||
| 179 | |||
| 180 | int mixedIterations = 0; | ||
| 181 | int success = 0; | ||
| 182 | |||
| 183 | // FIXME there is no messageCloseDebug so we use infoStreamPrint here | ||
| 184 | ✗ | infoStreamPrint(OMC_LOG_MIXED, 1, "\n#### Start solver mixed equation system at time %f.", data->localData[0]->timeValue); | |
| 185 | |||
| 186 | ✗ | memset(solverData->stateofSearch, 0, systemData->size); | |
| 187 | |||
| 188 | /* update pre iteration vars */ | ||
| 189 | /* update iteration vars */ | ||
| 190 | ✗ | for(i=0;i<systemData->size;++i) | |
| 191 | ✗ | solverData->iterationVarsPre[i] = *(systemData->iterationVarsPtr[i]); | |
| 192 | |||
| 193 | do | ||
| 194 | { | ||
| 195 | /* update pre iteration vars */ | ||
| 196 | ✗ | for(i=0;i<systemData->size;++i) | |
| 197 | ✗ | solverData->iterationVars[i] = *(systemData->iterationVarsPtr[i]); | |
| 198 | |||
| 199 | /* solve continuous equation part | ||
| 200 | * and update iteration variables in model | ||
| 201 | */ | ||
| 202 | ✗ | systemData->solveContinuousPart(data); | |
| 203 | ✗ | systemData->updateIterationExps(data); | |
| 204 | |||
| 205 | /* set new values of boolean variable */ | ||
| 206 | ✗ | for(i=0;i<systemData->size;++i) { | |
| 207 | ✗ | solverData->iterationVars2[i] = *(systemData->iterationVarsPtr[i]); | |
| 208 | } | ||
| 209 | |||
| 210 | ✗ | found_solution = systemData->continuous_solution; | |
| 211 | |||
| 212 | /* restart if any relation has changed */ | ||
| 213 | ✗ | if(checkRelations(data)) | |
| 214 | { | ||
| 215 | ✗ | updateRelationsPre(data); | |
| 216 | ✗ | systemData->updateIterationExps(data); | |
| 217 | ✗ | if(mixedIterations++ > 200) | |
| 218 | found_solution = -4; /* mixedIterations++ > 200 */ | ||
| 219 | } | ||
| 220 | |||
| 221 | ✗ | if(found_solution == -1) | |
| 222 | { | ||
| 223 | /* system of equations failed */ | ||
| 224 | found_solution = -2; | ||
| 225 | } | ||
| 226 | else | ||
| 227 | { | ||
| 228 | found_solution = 1; | ||
| 229 | ✗ | for(i = 0; i < systemData->size; i++) | |
| 230 | { | ||
| 231 | ✗ | if(solverData->iterationVars[i] != solverData->iterationVars2[i]) | |
| 232 | { | ||
| 233 | found_solution = 0; | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | ✗ | if(!found_solution ) | |
| 240 | { | ||
| 241 | /* try next set of values*/ | ||
| 242 | ✗ | if(nextVar(solverData->stateofSearch, systemData->size)) | |
| 243 | { | ||
| 244 | ✗ | for(i = 0; i < systemData->size; i++) | |
| 245 | ✗ | *(systemData->iterationVarsPtr[i]) = *(systemData->iterationPreVarsPtr[i]) != solverData->stateofSearch[i]; | |
| 246 | |||
| 247 | /* debug output */ | ||
| 248 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_MIXED)) | |
| 249 | { | ||
| 250 | const char * __name; | ||
| 251 | for(i = 0; i < systemData->size; i++) | ||
| 252 | { | ||
| 253 | ix = (systemData->iterationVarsPtr[i]-data->localData[0]->booleanVars); | ||
| 254 | __name = data->modelData->booleanVarsData[ix].info.name; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | else | ||
| 259 | { | ||
| 260 | /* while the initialization it's okay not a solution */ | ||
| 261 | ✗ | if(!data->simulationInfo->initial) | |
| 262 | { | ||
| 263 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, | |
| 264 | "Error solving mixed equation system with index %d at time %e", | ||
| 265 | ✗ | eqSystemNumber, data->localData[0]->timeValue); | |
| 266 | } | ||
| 267 | ✗ | data->simulationInfo->needToIterate = 1; | |
| 268 | found_solution = -1; | ||
| 269 | /*TODO: "break simulation?"*/ | ||
| 270 | } | ||
| 271 | } | ||
| 272 | /* we found a solution*/ | ||
| 273 | ✗ | if(found_solution == 1) | |
| 274 | { | ||
| 275 | success = 1; | ||
| 276 | ✗ | if(OMC_ACTIVE_STREAM(OMC_LOG_MIXED)) | |
| 277 | { | ||
| 278 | const char * __name; | ||
| 279 | for(i = 0; i < systemData->size; i++) | ||
| 280 | { | ||
| 281 | ix = (systemData->iterationVarsPtr[i]-data->localData[0]->booleanVars); | ||
| 282 | __name = data->modelData->booleanVarsData[ix].info.name; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | ✗ | mixedIterations++; | |
| 288 | |||
| 289 | ✗ | }while(!found_solution); | |
| 290 | |||
| 291 | ✗ | messageClose(OMC_LOG_MIXED); | |
| 292 | ✗ | return success; | |
| 293 | } | ||
| 294 |