OMCompiler/SimulationRuntime/c/simulation/solver/gbode_sparse.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 gbode_sparse.c | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include "gbode_main.h" | ||
| 32 | #include "gbode_util.h" | ||
| 33 | |||
| 34 | #include "model_help.h" | ||
| 35 | #include "simulation_data.h" | ||
| 36 | #include "solver_main.h" | ||
| 37 | |||
| 38 | #include <limits.h> | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Greedily pack structurally independent columns into colors. | ||
| 42 | * | ||
| 43 | * This works directly on CSC data in O(colors * (nnz + columns)) time and | ||
| 44 | * O(rows) workspace. | ||
| 45 | */ | ||
| 46 | ✗ | static void colorSparsePattern(SPARSE_PATTERN *pattern, int sizeRows, int sizeCols, int nStages, unsigned int *work) | |
| 47 | { | ||
| 48 | ✗ | assertStreamPrint(NULL, sizeRows >= 0 && sizeCols >= 0 && nStages > 0 && sizeCols % nStages == 0, | |
| 49 | "Invalid GBODE sparse coloring dimensions %d x %d with %d stages.", sizeRows, sizeCols, nStages); | ||
| 50 | ✗ | if (sizeCols == 0) | |
| 51 | { | ||
| 52 | ✗ | pattern->maxColors = 0; | |
| 53 | ✗ | return; | |
| 54 | } | ||
| 55 | modelica_boolean ownsWork = work == NULL; | ||
| 56 | ✗ | if (ownsWork) | |
| 57 | { | ||
| 58 | ✗ | work = malloc(sizeRows * sizeof(unsigned int)); | |
| 59 | } | ||
| 60 | |||
| 61 | unsigned int color = 0; | ||
| 62 | ✗ | const int stageSize = sizeCols / nStages; | |
| 63 | ✗ | memset(pattern->colorCols, 0, sizeCols * sizeof(unsigned int)); | |
| 64 | ✗ | memset(work, 0, sizeRows * sizeof(unsigned int)); | |
| 65 | ✗ | for (int stage = 0; stage < nStages; stage++) | |
| 66 | { | ||
| 67 | ✗ | const int firstCol = stage * stageSize; | |
| 68 | ✗ | const int endCol = firstCol + stageSize; | |
| 69 | int remaining = stageSize; | ||
| 70 | ✗ | while (remaining > 0) | |
| 71 | { | ||
| 72 | ✗ | color++; | |
| 73 | |||
| 74 | ✗ | for (int col = firstCol; col < endCol; col++) | |
| 75 | { | ||
| 76 | ✗ | if (pattern->colorCols[col]) | |
| 77 | { | ||
| 78 | ✗ | continue; | |
| 79 | } | ||
| 80 | |||
| 81 | modelica_boolean conflict = FALSE; | ||
| 82 | ✗ | for (unsigned int nz = pattern->leadindex[col]; nz < pattern->leadindex[col + 1]; nz++) | |
| 83 | { | ||
| 84 | ✗ | if (work[pattern->index[nz]] == color) | |
| 85 | { | ||
| 86 | conflict = TRUE; | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | ✗ | if (conflict) | |
| 91 | { | ||
| 92 | ✗ | continue; | |
| 93 | } | ||
| 94 | |||
| 95 | ✗ | pattern->colorCols[col] = color; | |
| 96 | ✗ | remaining--; | |
| 97 | ✗ | for (unsigned int nz = pattern->leadindex[col]; nz < pattern->leadindex[col + 1]; nz++) | |
| 98 | { | ||
| 99 | ✗ | work[pattern->index[nz]] = color; | |
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | ✗ | pattern->maxColors = color; | |
| 106 | ✗ | if (ownsWork) | |
| 107 | { | ||
| 108 | ✗ | free(work); | |
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | ✗ | static SPARSE_PATTERN *copySparsePattern(const SPARSE_PATTERN *source, int size, modelica_boolean copyColoring) | |
| 113 | { | ||
| 114 | ✗ | SPARSE_PATTERN *copy = allocSparsePattern(size, source->nnz, size); | |
| 115 | ✗ | memcpy(copy->leadindex, source->leadindex, (size + 1) * sizeof(unsigned int)); | |
| 116 | ✗ | memcpy(copy->index, source->index, source->nnz * sizeof(unsigned int)); | |
| 117 | ✗ | if (copyColoring) | |
| 118 | { | ||
| 119 | ✗ | memcpy(copy->colorCols, source->colorCols, size * sizeof(unsigned int)); | |
| 120 | ✗ | copy->maxColors = source->maxColors; | |
| 121 | } | ||
| 122 | else | ||
| 123 | { | ||
| 124 | ✗ | memset(copy->colorCols, 0, size * sizeof(unsigned int)); | |
| 125 | ✗ | copy->maxColors = 0; | |
| 126 | } | ||
| 127 | ✗ | return copy; | |
| 128 | } | ||
| 129 | |||
| 130 | // Build struct(I + J), optionally coloring it, allocating a pattern when target is NULL | ||
| 131 | ✗ | static SPARSE_PATTERN *sparsePatternWithDiagonal(const SPARSE_PATTERN *source, int size, SPARSE_PATTERN *target, unsigned int *work, | |
| 132 | modelica_boolean colorPattern, modelica_boolean reuseSourceColoring) | ||
| 133 | { | ||
| 134 | int diagonalCount = 0; | ||
| 135 | |||
| 136 | ✗ | if (target == NULL) | |
| 137 | { | ||
| 138 | ✗ | for (int col = 0; col < size; col++) | |
| 139 | { | ||
| 140 | ✗ | for (unsigned int nz = source->leadindex[col]; nz < source->leadindex[col + 1]; nz++) | |
| 141 | { | ||
| 142 | ✗ | if (source->index[nz] == col) | |
| 143 | { | ||
| 144 | ✗ | diagonalCount++; | |
| 145 | ✗ | break; | |
| 146 | } | ||
| 147 | } | ||
| 148 | } | ||
| 149 | ✗ | target = allocSparsePattern(size, source->nnz + size - diagonalCount, size); | |
| 150 | } | ||
| 151 | |||
| 152 | unsigned int targetNz = 0; | ||
| 153 | diagonalCount = 0; | ||
| 154 | ✗ | target->leadindex[0] = 0; | |
| 155 | ✗ | for (int col = 0; col < size; col++) | |
| 156 | { | ||
| 157 | modelica_boolean diagonalPresent = FALSE; | ||
| 158 | ✗ | for (unsigned int nz = source->leadindex[col]; nz < source->leadindex[col + 1]; nz++) | |
| 159 | { | ||
| 160 | ✗ | unsigned int row = source->index[nz]; | |
| 161 | ✗ | if (!diagonalPresent && row > col) | |
| 162 | { | ||
| 163 | ✗ | target->index[targetNz++] = col; | |
| 164 | diagonalPresent = TRUE; | ||
| 165 | } | ||
| 166 | ✗ | if (row == col) | |
| 167 | { | ||
| 168 | diagonalPresent = TRUE; | ||
| 169 | ✗ | diagonalCount++; | |
| 170 | } | ||
| 171 | ✗ | target->index[targetNz++] = row; | |
| 172 | } | ||
| 173 | ✗ | if (!diagonalPresent) | |
| 174 | { | ||
| 175 | ✗ | target->index[targetNz++] = col; | |
| 176 | } | ||
| 177 | ✗ | target->leadindex[col + 1] = targetNz; | |
| 178 | } | ||
| 179 | ✗ | target->nnz = targetNz; | |
| 180 | |||
| 181 | ✗ | if (!colorPattern) | |
| 182 | { | ||
| 183 | ✗ | memset(target->colorCols, 0, size * sizeof(unsigned int)); | |
| 184 | ✗ | target->maxColors = 0; | |
| 185 | } | ||
| 186 | ✗ | else if (reuseSourceColoring && diagonalCount == size && source->maxColors > 0) | |
| 187 | { | ||
| 188 | ✗ | memcpy(target->colorCols, source->colorCols, size * sizeof(unsigned int)); | |
| 189 | ✗ | target->maxColors = source->maxColors; | |
| 190 | } | ||
| 191 | else | ||
| 192 | { | ||
| 193 | ✗ | colorSparsePattern(target, size, size, 1, work); | |
| 194 | } | ||
| 195 | |||
| 196 | ✗ | return target; | |
| 197 | } | ||
| 198 | |||
| 199 | // Reduce a square CSC pattern to the principal submatrix selected by indices | ||
| 200 | ✗ | static void reduceSparsePattern(const SPARSE_PATTERN *source, int sourceSize, SPARSE_PATTERN *target, | |
| 201 | const int *indices, int targetSize, unsigned int *work) | ||
| 202 | { | ||
| 203 | ✗ | for (int i = 0; i < sourceSize; i++) | |
| 204 | { | ||
| 205 | ✗ | work[i] = UINT_MAX; | |
| 206 | } | ||
| 207 | ✗ | for (int i = 0; i < targetSize; i++) | |
| 208 | { | ||
| 209 | ✗ | work[indices[i]] = i; | |
| 210 | } | ||
| 211 | |||
| 212 | unsigned int targetNz = 0; | ||
| 213 | ✗ | target->leadindex[0] = 0; | |
| 214 | ✗ | for (int col = 0; col < targetSize; col++) | |
| 215 | { | ||
| 216 | ✗ | int sourceCol = indices[col]; | |
| 217 | ✗ | for (unsigned int nz = source->leadindex[sourceCol]; nz < source->leadindex[sourceCol + 1]; nz++) | |
| 218 | { | ||
| 219 | ✗ | unsigned int row = work[source->index[nz]]; | |
| 220 | ✗ | if (row != UINT_MAX) | |
| 221 | { | ||
| 222 | ✗ | target->index[targetNz++] = row; | |
| 223 | } | ||
| 224 | } | ||
| 225 | ✗ | target->leadindex[col + 1] = targetNz; | |
| 226 | } | ||
| 227 | ✗ | target->nnz = targetNz; | |
| 228 | ✗ | memset(target->colorCols, 0, targetSize * sizeof(unsigned int)); | |
| 229 | ✗ | target->maxColors = 0; | |
| 230 | ✗ | } | |
| 231 | |||
| 232 | ✗ | void gbodeMapSparsePattern(const SPARSE_PATTERN *source, const SPARSE_PATTERN *target, | |
| 233 | int size, int *sourceToTarget, int *targetDiagonal) | ||
| 234 | { | ||
| 235 | ✗ | for (int col = 0; col < size; col++) | |
| 236 | { | ||
| 237 | ✗ | unsigned int sourceNz = source->leadindex[col]; | |
| 238 | ✗ | unsigned int sourceEnd = source->leadindex[col + 1]; | |
| 239 | ✗ | targetDiagonal[col] = -1; | |
| 240 | |||
| 241 | ✗ | for (unsigned int targetNz = target->leadindex[col]; targetNz < target->leadindex[col + 1]; targetNz++) | |
| 242 | { | ||
| 243 | ✗ | unsigned int targetRow = target->index[targetNz]; | |
| 244 | ✗ | if (targetRow == col) | |
| 245 | { | ||
| 246 | ✗ | targetDiagonal[col] = targetNz; | |
| 247 | } | ||
| 248 | ✗ | if (sourceNz < sourceEnd && source->index[sourceNz] == targetRow) | |
| 249 | { | ||
| 250 | ✗ | sourceToTarget[sourceNz++] = targetNz; | |
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | ✗ | assertStreamPrint(NULL, targetDiagonal[col] >= 0 && sourceNz == sourceEnd, "GBODE sparse pattern mapping failed in column %d.", col); | |
| 255 | } | ||
| 256 | ✗ | } | |
| 257 | |||
| 258 | // Create the struct(I + J) pattern used by block solves | ||
| 259 | ✗ | static SPARSE_PATTERN* initializeSparsePatternBlock(DATA* data, modelica_boolean colorPattern) | |
| 260 | { | ||
| 261 | ✗ | JACOBIAN *jacobian = &data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A]; | |
| 262 | ✗ | return sparsePatternWithDiagonal(jacobian->sparsePattern, jacobian->sizeRows, NULL, NULL, colorPattern, TRUE); | |
| 263 | } | ||
| 264 | |||
| 265 | static SPARSE_PATTERN* initializeSparsePattern_IRK(DATA* data); | ||
| 266 | |||
| 267 | ✗ | void initializeSparsePattern_GBODE(DATA* data, DATA_GBODE* gbData) | |
| 268 | { | ||
| 269 | ✗ | assertStreamPrint(NULL, !gbData->isExplicit, | |
| 270 | "Cannot initialize GBODE sparsity for an explicit method."); | ||
| 271 | ✗ | if (gbData->type == GM_TYPE_IMPLICIT && gbData->nlsSolverMethod != GB_NLS_INTERNAL) | |
| 272 | { | ||
| 273 | ✗ | gbData->sparsePattern_NLS = initializeSparsePattern_IRK(data); | |
| 274 | } | ||
| 275 | else | ||
| 276 | { | ||
| 277 | ✗ | gbData->sparsePattern_NLS = initializeSparsePatternBlock(data, gbData->nlsSolverMethod != GB_NLS_INTERNAL); | |
| 278 | } | ||
| 279 | ✗ | } | |
| 280 | |||
| 281 | ✗ | void initializeSparsePattern_GBODEF(DATA* data, DATA_GBODEF* gbfData) | |
| 282 | { | ||
| 283 | ✗ | assertStreamPrint(NULL, !gbfData->isExplicit, | |
| 284 | "Cannot initialize GBODEF sparsity for an explicit method."); | ||
| 285 | ✗ | JACOBIAN *jacobian = &data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A]; | |
| 286 | ✗ | const modelica_boolean useInternal = gbfData->nlsSolverMethod == GB_NLS_INTERNAL; | |
| 287 | ✗ | gbfData->sparseWork = malloc(jacobian->sizeRows * sizeof(unsigned int)); | |
| 288 | ✗ | gbfData->sparsePattern_ODE = copySparsePattern(jacobian->sparsePattern, jacobian->sizeRows, useInternal); | |
| 289 | ✗ | gbfData->sparsePattern_NLS = sparsePatternWithDiagonal(jacobian->sparsePattern, jacobian->sizeRows, | |
| 290 | NULL, gbfData->sparseWork, !useInternal, TRUE); | ||
| 291 | ✗ | } | |
| 292 | |||
| 293 | ✗ | void updateSparsePattern_GBODEF(DATA* data, DATA_GBODE* gbData) | |
| 294 | { | ||
| 295 | ✗ | DATA_GBODEF *gbfData = gbData->gbfData; | |
| 296 | ✗ | SPARSE_PATTERN *fullPattern = data->simulationInfo->analyticJacobians[data->callback->INDEX_JAC_A].sparsePattern; | |
| 297 | |||
| 298 | ✗ | reduceSparsePattern(fullPattern, gbData->nStates, gbfData->sparsePattern_ODE, gbData->fastStatesIdx, gbData->nFastStates, gbfData->sparseWork); | |
| 299 | ✗ | if (gbfData->nlsSolverMethod == GB_NLS_INTERNAL) | |
| 300 | { | ||
| 301 | ✗ | colorSparsePattern(gbfData->sparsePattern_ODE, gbData->nFastStates, gbData->nFastStates, 1, gbfData->sparseWork); | |
| 302 | } | ||
| 303 | |||
| 304 | ✗ | sparsePatternWithDiagonal(gbfData->sparsePattern_ODE, gbData->nFastStates, gbfData->sparsePattern_NLS, | |
| 305 | ✗ | gbfData->sparseWork, gbfData->nlsSolverMethod != GB_NLS_INTERNAL, FALSE); | |
| 306 | |||
| 307 | ✗ | printSparseStructure(gbfData->sparsePattern_NLS, gbData->nFastStates, gbData->nFastStates, OMC_LOG_GBODE_V, "sparsePattern_MR"); | |
| 308 | ✗ | } | |
| 309 | |||
| 310 | /** | ||
| 311 | * @brief Initialize sparsity pattern for non-linear system of full implicit Runge-Kutta methods. | ||
| 312 | * | ||
| 313 | * Get sparsity pattern of ODE Jacobian and map it on the different stages taking into account | ||
| 314 | * the non-zero elements of the A matrix in the Butcher-tableau | ||
| 315 | * Coloring will be calculated, whereby different stages will have different colors, due to the | ||
| 316 | * column-wise calculation of the Jacobian | ||
| 317 | * | ||
| 318 | * @param data Runtime data struct. | ||
| 319 | * @return SPARSE_PATTERN* Pointer to sparsity pattern of non-linear system. | ||
| 320 | */ | ||
| 321 | ✗ | static SPARSE_PATTERN* initializeSparsePattern_IRK(DATA* data) | |
| 322 | { | ||
| 323 | unsigned int i,j,k,l; | ||
| 324 | unsigned int row, col; | ||
| 325 | unsigned int missingZeros = 0; | ||
| 326 | unsigned int nDiags = 0, nDiags_A, nnz_A; | ||
| 327 | unsigned int shift = 0; | ||
| 328 | modelica_boolean diagElemNonZero; | ||
| 329 | SPARSE_PATTERN* sparsePattern_IRK; | ||
| 330 | ✗ | DATA_GBODE* gbData = (DATA_GBODE*) data->simulationInfo->backupSolverData; | |
| 331 | |||
| 332 | /* Get Sparsity of ODE Jacobian */ | ||
| 333 | ✗ | JACOBIAN* jacobian = getSymbolicOdeJacobian(data); | |
| 334 | ✗ | SPARSE_PATTERN* sparsePattern_ODE = getJacobianCscPattern(jacobian); | |
| 335 | |||
| 336 | ✗ | int sizeRows = jacobian->sizeRows; | |
| 337 | ✗ | int sizeCols = jacobian->sizeCols; | |
| 338 | ✗ | int nStages = gbData->tableau->nStages; | |
| 339 | ✗ | int nStates = gbData->nStates; | |
| 340 | ✗ | double* A = gbData->tableau->A; | |
| 341 | |||
| 342 | ✗ | printSparseStructure(sparsePattern_ODE, | |
| 343 | sizeRows, | ||
| 344 | sizeCols, | ||
| 345 | OMC_LOG_GBODE_V, | ||
| 346 | "sparsePatternODE"); | ||
| 347 | |||
| 348 | nnz_A = 0; | ||
| 349 | nDiags_A = 0; | ||
| 350 | ✗ | for (i=0; i<nStages; i++) { | |
| 351 | ✗ | if (A[i*nStages + i] != 0) nDiags_A++; | |
| 352 | ✗ | for (j=0; j<nStages; j++) { | |
| 353 | ✗ | if (A[i*nStages + j] != 0) nnz_A++; | |
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | i = 0; | ||
| 358 | ✗ | for(col=0; col < sizeRows; col++) { | |
| 359 | ✗ | for(; i < sparsePattern_ODE->leadindex[col+1];) { | |
| 360 | ✗ | if(sparsePattern_ODE->index[i++] == col) { | |
| 361 | ✗ | nDiags++; | |
| 362 | } | ||
| 363 | } | ||
| 364 | } | ||
| 365 | ✗ | int missingDiags = jacobian->sizeRows - nDiags; | |
| 366 | ✗ | int nnz = nnz_A*sparsePattern_ODE->nnz + nDiags_A*missingDiags + (nStages-nDiags_A)*nStates; | |
| 367 | |||
| 368 | // first generated a coordinate format and transform this later to Column pressed format | ||
| 369 | ✗ | int *coo_col = (int*) malloc(nnz*sizeof(int)); | |
| 370 | ✗ | int *coo_row = (int*) malloc(nnz*sizeof(int)); | |
| 371 | |||
| 372 | i = 0; | ||
| 373 | ✗ | for (k=0; k<nStages; k++) | |
| 374 | { | ||
| 375 | ✗ | for (col=0; col < nStates; col++) | |
| 376 | { | ||
| 377 | diagElemNonZero = FALSE; | ||
| 378 | ✗ | for (l=0; l<nStages; l++) | |
| 379 | { | ||
| 380 | ✗ | for (j=sparsePattern_ODE->leadindex[col]; j<sparsePattern_ODE->leadindex[col+1]; j++) | |
| 381 | { | ||
| 382 | ✗ | if (((col + k*nStates) < (sparsePattern_ODE->index[j] + l*nStates)) && !diagElemNonZero) | |
| 383 | { | ||
| 384 | ✗ | coo_col[i] = col + k*nStates; | |
| 385 | ✗ | coo_row[i] = col + k*nStates; | |
| 386 | ✗ | i++; | |
| 387 | diagElemNonZero = TRUE; | ||
| 388 | } | ||
| 389 | // if the entry in A is non-zero, the sparsity pattern of the ODE-Jacobian will be inserted, | ||
| 390 | // respectively | ||
| 391 | ✗ | if (A[l*nStages + k] != 0) | |
| 392 | { | ||
| 393 | ✗ | if ((col + k*nStates) == (sparsePattern_ODE->index[j] + l*nStates)) | |
| 394 | diagElemNonZero = TRUE; | ||
| 395 | ✗ | coo_col[i] = col + k*nStates; | |
| 396 | ✗ | coo_row[i] = sparsePattern_ODE->index[j] + l*nStates; | |
| 397 | ✗ | i++; | |
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | ✗ | if (!diagElemNonZero) { | |
| 402 | ✗ | coo_col[i] = col + k*nStates; | |
| 403 | ✗ | coo_row[i] = col + k*nStates; | |
| 404 | ✗ | i++; | |
| 405 | diagElemNonZero = TRUE; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | ✗ | nnz = i; | |
| 411 | |||
| 412 | ✗ | if (OMC_ACTIVE_STREAM(OMC_LOG_GBODE_V)){ | |
| 413 | ✗ | printIntVector_gb(OMC_LOG_GBODE_V, "rows", coo_row, nnz, 0.0); | |
| 414 | ✗ | printIntVector_gb(OMC_LOG_GBODE_V, "cols", coo_col, nnz, 0.0); | |
| 415 | } | ||
| 416 | |||
| 417 | ✗ | int length_row_indices = jacobian->sizeCols*nStages+1; | |
| 418 | |||
| 419 | // Allocate memory for new sparsity pattern | ||
| 420 | ✗ | sparsePattern_IRK = allocSparsePattern(jacobian->sizeCols*nStages, nnz, jacobian->sizeCols*nStages); | |
| 421 | |||
| 422 | /* Set diagonal elements of sparsitiy pattern to non-zero */ | ||
| 423 | ✗ | for (i=0; i<length_row_indices; i++) | |
| 424 | ✗ | sparsePattern_IRK->leadindex[i] = 0; | |
| 425 | |||
| 426 | ✗ | for (int i = 0; i < nnz; i++) | |
| 427 | { | ||
| 428 | ✗ | sparsePattern_IRK->index[i] = coo_row[i]; | |
| 429 | ✗ | sparsePattern_IRK->leadindex[coo_col[i] + 1]++; | |
| 430 | } | ||
| 431 | ✗ | for (int i = 0; i < sizeCols*nStages; i++) | |
| 432 | { | ||
| 433 | ✗ | sparsePattern_IRK->leadindex[i + 1] += sparsePattern_IRK->leadindex[i]; | |
| 434 | } | ||
| 435 | |||
| 436 | ✗ | free(coo_col); | |
| 437 | ✗ | free(coo_row); | |
| 438 | |||
| 439 | ✗ | colorSparsePattern(sparsePattern_IRK, sizeRows*nStages, sizeCols*nStages, nStages, NULL); | |
| 440 | |||
| 441 | ✗ | return sparsePattern_IRK; | |
| 442 | } | ||
| 443 |