OMCompiler/SimulationRuntime/c/simulation/results/simulation_result_rust.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 "simulation_result_rust.h" | ||
| 29 | |||
| 30 | #include "omc_result.h" | ||
| 31 | #include "util/omc_error.h" | ||
| 32 | #include "util/rtclock.h" | ||
| 33 | #include "simulation/options.h" | ||
| 34 | |||
| 35 | #include <cstring> | ||
| 36 | #include <string> | ||
| 37 | #include <vector> | ||
| 38 | |||
| 39 | extern "C" { | ||
| 40 | |||
| 41 | /* A kept array variable: where its scalars start in the runtime's value array | ||
| 42 | * and how many there are. Rows are filled from these in signal order. */ | ||
| 43 | struct block { size_t start; size_t len; }; | ||
| 44 | |||
| 45 | struct rust_result_data | ||
| 46 | { | ||
| 47 | omc_result_writer *writer; | ||
| 48 | std::vector<std::string> strings; /* owns every name/description/unit the signals point at */ | ||
| 49 | std::vector<omc_result_signal> signals; | ||
| 50 | std::vector<int> columnTypes; | ||
| 51 | std::vector<block> reals, ints, bools, strs; | ||
| 52 | size_t nSensitivities; | ||
| 53 | std::vector<double> row; | ||
| 54 | std::vector<double> params; | ||
| 55 | }; | ||
| 56 | |||
| 57 | 7 | static std::string arrayName(const char *name, const DIMENSION_INFO *dimension, size_t linear, modelica_boolean isStateDerivative) | |
| 58 | { | ||
| 59 | 7 | std::string out = name; | |
| 60 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
7 | if (dimension == NULL || dimension->numberOfDimensions == 0) { |
| 61 | return out; | ||
| 62 | } | ||
| 63 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (isStateDerivative) { |
| 64 | out.pop_back(); /* the ")" of der(x): the subscripts go inside it */ | ||
| 65 | } | ||
| 66 | size_t rem = linear; | ||
| 67 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | for (size_t k = 0; k < dimension->numberOfDimensions; k++) { |
| 68 | size_t stride = 1; | ||
| 69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | for (size_t j = k + 1; j < dimension->numberOfDimensions; j++) { |
| 70 | ✗ | stride *= (size_t)dimension->dimensions[j].start; | |
| 71 | } | ||
| 72 |
4/10✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 6 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
12 | out += (k == 0 ? "[" : ",") + std::to_string(rem / stride + 1); |
| 73 | 6 | rem = rem % stride; | |
| 74 | } | ||
| 75 | out += "]"; | ||
| 76 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (isStateDerivative) { |
| 77 | out += ")"; | ||
| 78 | } | ||
| 79 | return out; | ||
| 80 | } | ||
| 81 | |||
| 82 | static const char *mmcString(const modelica_string *s) | ||
| 83 | { | ||
| 84 |
1/10✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
2 | if (s == NULL || *s == NULL) { |
| 85 | return ""; | ||
| 86 | } | ||
| 87 | const char *str = omc_string_data(*s); | ||
| 88 | 4 | return str ? str : ""; | |
| 89 | } | ||
| 90 | |||
| 91 | /* A String value travels in the row (or params) as its interned id. */ | ||
| 92 | static double internString(modelica_string s) | ||
| 93 | { | ||
| 94 | ✗ | return omc_result_intern(mmcString(&s)); | |
| 95 | } | ||
| 96 | |||
| 97 | /* Adds the signals of one (array) variable: scalar_length of them. `column` is | ||
| 98 | * the row column of the first scalar for a column signal, -1 for the others. */ | ||
| 99 | 4 | static void addSignals(rust_result_data *d, const char *name, const char *comment, const char *unit, const char *displayUnit, | |
| 100 | int type, int kind, long column, int negate, int unvarying, | ||
| 101 | const DIMENSION_INFO *dimension, modelica_boolean isStateDerivative, | ||
| 102 | modelica_boolean relativeQuantity = FALSE) | ||
| 103 | { | ||
| 104 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
|
4 | size_t n = dimension ? dimension->scalar_length : 1; |
| 105 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
|
11 | for (size_t i = 0; i < n; i++) { |
| 106 | /* Pointers into `strings` are taken only after every push_back (open()). */ | ||
| 107 | 7 | d->strings.push_back(arrayName(name, dimension, i, isStateDerivative)); | |
| 108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | d->strings.push_back(comment ? comment : ""); |
| 109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | d->strings.push_back(unit ? unit : ""); |
| 110 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1 time.
|
14 | d->strings.push_back(displayUnit ? displayUnit : ""); |
| 111 | omc_result_signal s; | ||
| 112 | memset(&s, 0, sizeof(s)); | ||
| 113 | 7 | s.type = type; | |
| 114 | 7 | s.discrete = type != OMC_RESULT_TYPE_REAL; | |
| 115 | 7 | s.kind = kind; | |
| 116 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 time.
|
7 | s.column = kind == OMC_RESULT_KIND_COLUMN ? (unsigned)(column + i) : 0; |
| 117 | 7 | s.negate = negate; | |
| 118 | 7 | s.unvarying = unvarying; | |
| 119 | 7 | s.relative_quantity = relativeQuantity; | |
| 120 | 7 | d->signals.push_back(s); | |
| 121 | } | ||
| 122 | 4 | } | |
| 123 | |||
| 124 | 1 | void rust_result_init(simulation_result *self, DATA *data, threadData_t *threadData) | |
| 125 | { | ||
| 126 | 1 | const MODEL_DATA *mData = data->modelData; | |
| 127 | 1 | const SIMULATION_INFO *sInfo = data->simulationInfo; | |
| 128 | 1 | rust_result_data *d = new rust_result_data(); | |
| 129 | d->writer = NULL; | ||
| 130 | d->nSensitivities = 0; | ||
| 131 | 1 | self->storage = d; | |
| 132 | |||
| 133 | /* Row layout: time, $cpuTime, $solverSteps, kept reals, sensitivities, kept | ||
| 134 | * integers, kept booleans, kept strings (as interned ids). */ | ||
| 135 | long column = 0; | ||
| 136 | 1 | addSignals(d, "time", "Simulation time", "s", "", OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_TIME, column++, 0, 0, NULL, FALSE); | |
| 137 | 1 | d->columnTypes.push_back(OMC_RESULT_TYPE_REAL); | |
| 138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (self->cpuTime) { |
| 139 | ✗ | addSignals(d, "$cpuTime", "cpu time", "s", "", OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_COLUMN, column++, 0, 0, NULL, FALSE); | |
| 140 | ✗ | d->columnTypes.push_back(OMC_RESULT_TYPE_REAL); | |
| 141 | } | ||
| 142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (omc_flag[FLAG_SOLVER_STEPS]) { |
| 143 | ✗ | addSignals(d, "$solverSteps", "number of steps taken by the integrator", "", "", OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_COLUMN, column++, 0, 0, NULL, FALSE); | |
| 144 | ✗ | d->columnTypes.push_back(OMC_RESULT_TYPE_REAL); | |
| 145 | } | ||
| 146 | /* Row column of each kept scalar variable, by its index in the value arrays; | ||
| 147 | * the aliases look their targets up here. */ | ||
| 148 |
2/6✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
1 | std::vector<long> realColumn(mData->nVariablesReal, -1), intColumn(mData->nVariablesInteger, -1), boolColumn(mData->nVariablesBoolean, -1); |
| 149 | /* The discrete Reals are the tail of realVarsData. */ | ||
| 150 | 1 | const long firstDiscreteReal = mData->nVariablesRealArray - mData->nDiscreteRealArray; | |
| 151 | auto markDiscrete = [d](size_t from) { | ||
| 152 | ✗ | for (size_t j = from; j < d->signals.size(); j++) d->signals[j].discrete = 1; | |
| 153 | }; | ||
| 154 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3 | for (int i = 0; i < mData->nVariablesRealArray; i++) { |
| 155 | 2 | const STATIC_REAL_DATA *v = &mData->realVarsData[i]; | |
| 156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (v->filterOutput) continue; |
| 157 |
3/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
2 | modelica_boolean isStateDerivative = mData->nStatesArray <= i && i < 2 * mData->nStatesArray; |
| 158 | 2 | size_t start = sInfo->realVarsIndex[i]; | |
| 159 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (size_t k = 0; k < v->dimension.scalar_length; k++) { |
| 160 |
1/1✓ Branch 1 taken 4 times.
|
4 | realColumn[start + k] = column + k; |
| 161 |
1/1✓ Branch 1 taken 4 times.
|
4 | d->columnTypes.push_back(OMC_RESULT_TYPE_REAL); |
| 162 | } | ||
| 163 | size_t first = d->signals.size(); | ||
| 164 |
1/1✓ Branch 1 taken 2 times.
|
2 | addSignals(d, v->info.name, v->info.comment, mmcString(&v->attribute.unit), mmcString(&v->attribute.displayUnit), |
| 165 | 2 | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_COLUMN, column, 0, v->time_unvarying, &v->dimension, isStateDerivative, | |
| 166 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | v->attribute.relativeQuantity); |
| 167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (i >= firstDiscreteReal) markDiscrete(first); |
| 168 |
1/1✓ Branch 1 taken 2 times.
|
2 | d->reals.push_back({start, v->dimension.scalar_length}); |
| 169 | 2 | column += v->dimension.scalar_length; | |
| 170 | } | ||
| 171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (omc_flag[FLAG_IDAS]) { |
| 172 | ✗ | for (int i = mData->nSensitivityParamVars; i < mData->nSensitivityVars; i++) { | |
| 173 | ✗ | addSignals(d, mData->realSensitivityData[i].info.name, mData->realSensitivityData[i].info.comment, "", "", | |
| 174 | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_COLUMN, column++, 0, 0, NULL, FALSE); | ||
| 175 | ✗ | d->columnTypes.push_back(OMC_RESULT_TYPE_REAL); | |
| 176 | ✗ | d->nSensitivities++; | |
| 177 | } | ||
| 178 | } | ||
| 179 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for (int i = 0; i < mData->nVariablesIntegerArray; i++) { |
| 180 | 1 | const STATIC_INTEGER_DATA *v = &mData->integerVarsData[i]; | |
| 181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (v->filterOutput) continue; |
| 182 | 1 | size_t start = sInfo->integerVarsIndex[i]; | |
| 183 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3 | for (size_t k = 0; k < v->dimension.scalar_length; k++) { |
| 184 |
1/1✓ Branch 1 taken 2 times.
|
2 | intColumn[start + k] = column + k; |
| 185 |
1/1✓ Branch 1 taken 2 times.
|
2 | d->columnTypes.push_back(OMC_RESULT_TYPE_INTEGER); |
| 186 | } | ||
| 187 |
1/1✓ Branch 1 taken 1 time.
|
1 | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_INTEGER, OMC_RESULT_KIND_COLUMN, column, 0, v->time_unvarying, &v->dimension, FALSE); |
| 188 |
1/1✓ Branch 1 taken 1 time.
|
1 | d->ints.push_back({start, v->dimension.scalar_length}); |
| 189 | 1 | column += v->dimension.scalar_length; | |
| 190 | } | ||
| 191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nVariablesBooleanArray; i++) { |
| 192 | ✗ | const STATIC_BOOLEAN_DATA *v = &mData->booleanVarsData[i]; | |
| 193 | ✗ | if (v->filterOutput) continue; | |
| 194 | ✗ | size_t start = sInfo->booleanVarsIndex[i]; | |
| 195 | ✗ | for (size_t k = 0; k < v->dimension.scalar_length; k++) { | |
| 196 | ✗ | boolColumn[start + k] = column + k; | |
| 197 | ✗ | d->columnTypes.push_back(OMC_RESULT_TYPE_BOOLEAN); | |
| 198 | } | ||
| 199 | ✗ | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_BOOLEAN, OMC_RESULT_KIND_COLUMN, column, 0, v->time_unvarying, &v->dimension, FALSE); | |
| 200 | ✗ | d->bools.push_back({start, v->dimension.scalar_length}); | |
| 201 | ✗ | column += v->dimension.scalar_length; | |
| 202 | } | ||
| 203 |
1/3✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1 | std::vector<long> stringColumn(mData->nVariablesString, -1); |
| 204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nVariablesStringArray; i++) { |
| 205 | ✗ | const STATIC_STRING_DATA *v = &mData->stringVarsData[i]; | |
| 206 | ✗ | if (v->filterOutput) continue; | |
| 207 | ✗ | size_t start = sInfo->stringVarsIndex[i]; | |
| 208 | ✗ | for (size_t k = 0; k < v->dimension.scalar_length; k++) { | |
| 209 | ✗ | stringColumn[start + k] = column + k; | |
| 210 | ✗ | d->columnTypes.push_back(OMC_RESULT_TYPE_STRING); | |
| 211 | } | ||
| 212 | ✗ | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_STRING, OMC_RESULT_KIND_COLUMN, column, 0, v->time_unvarying, &v->dimension, FALSE); | |
| 213 | ✗ | d->strs.push_back({start, v->dimension.scalar_length}); | |
| 214 | ✗ | column += v->dimension.scalar_length; | |
| 215 | } | ||
| 216 |
1/3✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1 | d->row.assign(column, 0.0); |
| 217 | |||
| 218 | /* Parameter values are read when the file is opened, after initialization. */ | ||
| 219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersRealArray; i++) { |
| 220 | ✗ | const STATIC_REAL_DATA *v = &mData->realParameterData[i]; | |
| 221 | ✗ | if (v->filterOutput) continue; | |
| 222 | ✗ | addSignals(d, v->info.name, v->info.comment, mmcString(&v->attribute.unit), mmcString(&v->attribute.displayUnit), | |
| 223 | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_PARAMETER, -1, 0, 0, &v->dimension, FALSE, | ||
| 224 | ✗ | v->attribute.relativeQuantity); | |
| 225 | } | ||
| 226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersIntegerArray; i++) { |
| 227 | ✗ | const STATIC_INTEGER_DATA *v = &mData->integerParameterData[i]; | |
| 228 | ✗ | if (v->filterOutput) continue; | |
| 229 | ✗ | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_INTEGER, OMC_RESULT_KIND_PARAMETER, -1, 0, 0, &v->dimension, FALSE); | |
| 230 | } | ||
| 231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersBooleanArray; i++) { |
| 232 | ✗ | const STATIC_BOOLEAN_DATA *v = &mData->booleanParameterData[i]; | |
| 233 | ✗ | if (v->filterOutput) continue; | |
| 234 | ✗ | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_BOOLEAN, OMC_RESULT_KIND_PARAMETER, -1, 0, 0, &v->dimension, FALSE); | |
| 235 | } | ||
| 236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersStringArray; i++) { |
| 237 | ✗ | const STATIC_STRING_DATA *v = &mData->stringParameterData[i]; | |
| 238 | ✗ | if (v->filterOutput) continue; | |
| 239 | ✗ | addSignals(d, v->info.name, v->info.comment, "", "", OMC_RESULT_TYPE_STRING, OMC_RESULT_KIND_PARAMETER, -1, 0, 0, &v->dimension, FALSE); | |
| 240 | } | ||
| 241 | |||
| 242 | /* Aliases share their target's column (or repeat its parameter value). */ | ||
| 243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasRealArray; i++) { |
| 244 | ✗ | const DATA_REAL_ALIAS *a = &mData->realAlias[i]; | |
| 245 | ✗ | if (a->filterOutput) continue; | |
| 246 | ✗ | int negate = a->negate ? OMC_RESULT_NEGATE_ARITHMETIC : OMC_RESULT_NEGATE_NONE; | |
| 247 | ✗ | switch (a->aliasType) { | |
| 248 | ✗ | case ALIAS_TYPE_VARIABLE: { | |
| 249 | ✗ | const STATIC_REAL_DATA *v = &mData->realVarsData[a->nameID]; | |
| 250 | ✗ | modelica_boolean isStateDerivative = mData->nStatesArray <= a->nameID && a->nameID < 2 * mData->nStatesArray; | |
| 251 | size_t first = d->signals.size(); | ||
| 252 | ✗ | addSignals(d, a->info.name, a->info.comment, mmcString(&a->unit), mmcString(&a->displayUnit), | |
| 253 | ✗ | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_COLUMN, realColumn[sInfo->realVarsIndex[a->nameID]], negate, v->time_unvarying, &v->dimension, isStateDerivative, | |
| 254 | ✗ | a->relativeQuantity); | |
| 255 | ✗ | if (a->nameID >= firstDiscreteReal) markDiscrete(first); | |
| 256 | break; | ||
| 257 | } | ||
| 258 | ✗ | case ALIAS_TYPE_PARAMETER: { | |
| 259 | ✗ | const STATIC_REAL_DATA *v = &mData->realParameterData[a->nameID]; | |
| 260 | ✗ | addSignals(d, a->info.name, a->info.comment, mmcString(&a->unit), mmcString(&a->displayUnit), | |
| 261 | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_PARAMETER, -1, negate, 0, &v->dimension, FALSE, | ||
| 262 | ✗ | a->relativeQuantity); | |
| 263 | break; | ||
| 264 | } | ||
| 265 | ✗ | case ALIAS_TYPE_TIME: { | |
| 266 | const char *unit = mmcString(&a->unit); | ||
| 267 | ✗ | addSignals(d, a->info.name, a->info.comment, unit[0] ? unit : "s", mmcString(&a->displayUnit), | |
| 268 | OMC_RESULT_TYPE_REAL, OMC_RESULT_KIND_TIME, 0, negate, 0, NULL, FALSE, | ||
| 269 | ✗ | a->relativeQuantity); | |
| 270 | break; | ||
| 271 | } | ||
| 272 | ✗ | default: | |
| 273 | ✗ | throwStreamPrint(threadData, "rust_result_init: Unknown alias type for real alias."); | |
| 274 | } | ||
| 275 | } | ||
| 276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasIntegerArray; i++) { |
| 277 | ✗ | const DATA_INTEGER_ALIAS *a = &mData->integerAlias[i]; | |
| 278 | ✗ | if (a->filterOutput) continue; | |
| 279 | ✗ | int negate = a->negate ? OMC_RESULT_NEGATE_ARITHMETIC : OMC_RESULT_NEGATE_NONE; | |
| 280 | ✗ | switch (a->aliasType) { | |
| 281 | ✗ | case ALIAS_TYPE_VARIABLE: { | |
| 282 | ✗ | const STATIC_INTEGER_DATA *v = &mData->integerVarsData[a->nameID]; | |
| 283 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_INTEGER, OMC_RESULT_KIND_COLUMN, | |
| 284 | ✗ | intColumn[sInfo->integerVarsIndex[a->nameID]], negate, v->time_unvarying, &v->dimension, FALSE); | |
| 285 | break; | ||
| 286 | } | ||
| 287 | ✗ | case ALIAS_TYPE_PARAMETER: | |
| 288 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_INTEGER, OMC_RESULT_KIND_PARAMETER, -1, negate, 0, | |
| 289 | ✗ | &mData->integerParameterData[a->nameID].dimension, FALSE); | |
| 290 | break; | ||
| 291 | ✗ | default: | |
| 292 | ✗ | throwStreamPrint(threadData, "rust_result_init: Unknown alias type for integer alias."); | |
| 293 | } | ||
| 294 | } | ||
| 295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasBooleanArray; i++) { |
| 296 | ✗ | const DATA_BOOLEAN_ALIAS *a = &mData->booleanAlias[i]; | |
| 297 | ✗ | if (a->filterOutput) continue; | |
| 298 | ✗ | int negate = a->negate ? OMC_RESULT_NEGATE_LOGICAL : OMC_RESULT_NEGATE_NONE; | |
| 299 | ✗ | switch (a->aliasType) { | |
| 300 | ✗ | case ALIAS_TYPE_VARIABLE: { | |
| 301 | ✗ | const STATIC_BOOLEAN_DATA *v = &mData->booleanVarsData[a->nameID]; | |
| 302 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_BOOLEAN, OMC_RESULT_KIND_COLUMN, | |
| 303 | ✗ | boolColumn[sInfo->booleanVarsIndex[a->nameID]], negate, v->time_unvarying, &v->dimension, FALSE); | |
| 304 | break; | ||
| 305 | } | ||
| 306 | ✗ | case ALIAS_TYPE_PARAMETER: | |
| 307 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_BOOLEAN, OMC_RESULT_KIND_PARAMETER, -1, negate, 0, | |
| 308 | ✗ | &mData->booleanParameterData[a->nameID].dimension, FALSE); | |
| 309 | break; | ||
| 310 | ✗ | default: | |
| 311 | ✗ | throwStreamPrint(threadData, "rust_result_init: Unknown alias type for boolean alias."); | |
| 312 | } | ||
| 313 | } | ||
| 314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasStringArray; i++) { |
| 315 | ✗ | const DATA_STRING_ALIAS *a = &mData->stringAlias[i]; | |
| 316 | ✗ | if (a->filterOutput) continue; | |
| 317 | ✗ | switch (a->aliasType) { | |
| 318 | ✗ | case ALIAS_TYPE_VARIABLE: { | |
| 319 | ✗ | const STATIC_STRING_DATA *v = &mData->stringVarsData[a->nameID]; | |
| 320 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_STRING, OMC_RESULT_KIND_COLUMN, | |
| 321 | ✗ | stringColumn[sInfo->stringVarsIndex[a->nameID]], 0, v->time_unvarying, &v->dimension, FALSE); | |
| 322 | break; | ||
| 323 | } | ||
| 324 | ✗ | case ALIAS_TYPE_PARAMETER: | |
| 325 | ✗ | addSignals(d, a->info.name, a->info.comment, "", "", OMC_RESULT_TYPE_STRING, OMC_RESULT_KIND_PARAMETER, -1, 0, 0, | |
| 326 | ✗ | &mData->stringParameterData[a->nameID].dimension, FALSE); | |
| 327 | break; | ||
| 328 | ✗ | default: | |
| 329 | ✗ | throwStreamPrint(threadData, "rust_result_init: Unknown alias type for string alias."); | |
| 330 | } | ||
| 331 | } | ||
| 332 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
|
8 | for (size_t i = 0; i < d->signals.size(); i++) { |
| 333 | 7 | d->signals[i].name = d->strings[4 * i].c_str(); | |
| 334 | 7 | d->signals[i].description = d->strings[4 * i + 1].c_str(); | |
| 335 | 7 | d->signals[i].unit = d->strings[4 * i + 2].c_str(); | |
| 336 | 7 | d->signals[i].display_unit = d->strings[4 * i + 3].c_str(); | |
| 337 | } | ||
| 338 | 1 | } | |
| 339 | |||
| 340 | 4 | static void fillRow(rust_result_data *d, simulation_result *self, DATA *data) | |
| 341 | { | ||
| 342 | 4 | const SIMULATION_INFO *sInfo = data->simulationInfo; | |
| 343 | 4 | const SIMULATION_DATA *local = data->localData[0]; | |
| 344 | size_t cur = 0; | ||
| 345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | d->row[cur++] = local->timeValue; |
| 346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (self->cpuTime) { |
| 347 | ✗ | rt_accumulate(SIM_TIMER_TOTAL); | |
| 348 | ✗ | d->row[cur++] = rt_accumulated(SIM_TIMER_TOTAL); | |
| 349 | ✗ | rt_tick(SIM_TIMER_TOTAL); | |
| 350 | } | ||
| 351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (omc_flag[FLAG_SOLVER_STEPS]) { |
| 352 | ✗ | d->row[cur++] = sInfo->solverSteps; | |
| 353 | } | ||
| 354 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
|
12 | for (const block &b : d->reals) { |
| 355 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
|
24 | for (size_t k = 0; k < b.len; k++) d->row[cur++] = local->realVars[b.start + k]; |
| 356 | } | ||
| 357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | for (size_t i = 0; i < d->nSensitivities; i++) { |
| 358 | ✗ | d->row[cur++] = sInfo->sensitivityMatrix[i]; | |
| 359 | } | ||
| 360 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | for (const block &b : d->ints) { |
| 361 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
|
12 | for (size_t k = 0; k < b.len; k++) d->row[cur++] = local->integerVars[b.start + k]; |
| 362 | } | ||
| 363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | for (const block &b : d->bools) { |
| 364 | ✗ | for (size_t k = 0; k < b.len; k++) d->row[cur++] = local->booleanVars[b.start + k]; | |
| 365 | } | ||
| 366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | for (const block &b : d->strs) { |
| 367 | ✗ | for (size_t k = 0; k < b.len; k++) d->row[cur++] = internString(local->stringVars[b.start + k]); | |
| 368 | } | ||
| 369 | 4 | } | |
| 370 | |||
| 371 | /* The parameter values in signal order (an alias of a parameter repeats it). */ | ||
| 372 | 1 | static void fillParams(rust_result_data *d, DATA *data) | |
| 373 | { | ||
| 374 | 1 | const MODEL_DATA *mData = data->modelData; | |
| 375 | 1 | const SIMULATION_INFO *sInfo = data->simulationInfo; | |
| 376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | d->params.clear(); |
| 377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersRealArray; i++) { |
| 378 | ✗ | if (mData->realParameterData[i].filterOutput) continue; | |
| 379 | ✗ | for (size_t k = 0; k < mData->realParameterData[i].dimension.scalar_length; k++) | |
| 380 | ✗ | d->params.push_back(sInfo->realParameter[sInfo->realParamsIndex[i] + k]); | |
| 381 | } | ||
| 382 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersIntegerArray; i++) { |
| 383 | ✗ | if (mData->integerParameterData[i].filterOutput) continue; | |
| 384 | ✗ | for (size_t k = 0; k < mData->integerParameterData[i].dimension.scalar_length; k++) | |
| 385 | ✗ | d->params.push_back(sInfo->integerParameter[sInfo->integerParamsIndex[i] + k]); | |
| 386 | } | ||
| 387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersBooleanArray; i++) { |
| 388 | ✗ | if (mData->booleanParameterData[i].filterOutput) continue; | |
| 389 | ✗ | for (size_t k = 0; k < mData->booleanParameterData[i].dimension.scalar_length; k++) | |
| 390 | ✗ | d->params.push_back(sInfo->booleanParameter[sInfo->booleanParamsIndex[i] + k]); | |
| 391 | } | ||
| 392 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nParametersStringArray; i++) { |
| 393 | ✗ | if (mData->stringParameterData[i].filterOutput) continue; | |
| 394 | ✗ | for (size_t k = 0; k < mData->stringParameterData[i].dimension.scalar_length; k++) | |
| 395 | ✗ | d->params.push_back(internString(sInfo->stringParameter[sInfo->stringParamsIndex[i] + k])); | |
| 396 | } | ||
| 397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasRealArray; i++) { |
| 398 | ✗ | const DATA_REAL_ALIAS *a = &mData->realAlias[i]; | |
| 399 | ✗ | if (a->filterOutput || a->aliasType != ALIAS_TYPE_PARAMETER) continue; | |
| 400 | ✗ | for (size_t k = 0; k < mData->realParameterData[a->nameID].dimension.scalar_length; k++) | |
| 401 | ✗ | d->params.push_back(sInfo->realParameter[sInfo->realParamsIndex[a->nameID] + k]); | |
| 402 | } | ||
| 403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasIntegerArray; i++) { |
| 404 | ✗ | const DATA_INTEGER_ALIAS *a = &mData->integerAlias[i]; | |
| 405 | ✗ | if (a->filterOutput || a->aliasType != ALIAS_TYPE_PARAMETER) continue; | |
| 406 | ✗ | for (size_t k = 0; k < mData->integerParameterData[a->nameID].dimension.scalar_length; k++) | |
| 407 | ✗ | d->params.push_back(sInfo->integerParameter[sInfo->integerParamsIndex[a->nameID] + k]); | |
| 408 | } | ||
| 409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasBooleanArray; i++) { |
| 410 | ✗ | const DATA_BOOLEAN_ALIAS *a = &mData->booleanAlias[i]; | |
| 411 | ✗ | if (a->filterOutput || a->aliasType != ALIAS_TYPE_PARAMETER) continue; | |
| 412 | ✗ | for (size_t k = 0; k < mData->booleanParameterData[a->nameID].dimension.scalar_length; k++) | |
| 413 | ✗ | d->params.push_back(sInfo->booleanParameter[sInfo->booleanParamsIndex[a->nameID] + k]); | |
| 414 | } | ||
| 415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | for (int i = 0; i < mData->nAliasStringArray; i++) { |
| 416 | ✗ | const DATA_STRING_ALIAS *a = &mData->stringAlias[i]; | |
| 417 | ✗ | if (a->filterOutput || a->aliasType != ALIAS_TYPE_PARAMETER) continue; | |
| 418 | ✗ | for (size_t k = 0; k < mData->stringParameterData[a->nameID].dimension.scalar_length; k++) | |
| 419 | ✗ | d->params.push_back(internString(sInfo->stringParameter[sInfo->stringParamsIndex[a->nameID] + k])); | |
| 420 | } | ||
| 421 | 1 | } | |
| 422 | |||
| 423 | 1 | static void openWriter(rust_result_data *d, simulation_result *self, DATA *data, threadData_t *threadData) | |
| 424 | { | ||
| 425 | 1 | fillParams(d, data); | |
| 426 | 1 | fillRow(d, self, data); | |
| 427 | 1 | char *error = NULL; | |
| 428 | 4 | d->writer = omc_result_writer_open(self->filename, data->simulationInfo->outputFormat, | |
| 429 | d->signals.data(), d->signals.size(), | ||
| 430 | d->columnTypes.data(), d->columnTypes.size(), | ||
| 431 | d->params.data(), d->params.size(), | ||
| 432 | 1 | d->row.data(), data->simulationInfo->startTime, data->simulationInfo->stopTime, | |
| 433 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | omc_flag[FLAG_SINGLE_PRECISION] ? 1 : 0, |
| 434 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | omc_flag[FLAG_MAT_SYNC] ? atoi(omc_flagValue[FLAG_MAT_SYNC]) : 0, &error); |
| 435 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if (!d->writer) { |
| 436 | ✗ | std::string msg = error ? error : "unknown error"; | |
| 437 | ✗ | omc_result_free_string(error); | |
| 438 | ✗ | throwStreamPrint(threadData, "Error opening result file %s: %s", self->filename, msg.c_str()); | |
| 439 | } | ||
| 440 | 1 | } | |
| 441 | |||
| 442 | /* Called once initialization is done: parameters and the time-invariant | ||
| 443 | * variables have their final values, so the file is opened here. */ | ||
| 444 | 1 | void rust_result_writeParameterData(simulation_result *self, DATA *data, threadData_t *threadData) | |
| 445 | { | ||
| 446 | 1 | rust_result_data *d = (rust_result_data *)self->storage; | |
| 447 | 1 | rt_tick(SIM_TIMER_OUTPUT); | |
| 448 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (!d->writer) { |
| 449 | 1 | openWriter(d, self, data, threadData); | |
| 450 | } | ||
| 451 | 1 | rt_accumulate(SIM_TIMER_OUTPUT); | |
| 452 | 1 | } | |
| 453 | |||
| 454 | 3 | void rust_result_emit(simulation_result *self, DATA *data, threadData_t *threadData) | |
| 455 | { | ||
| 456 | 3 | rust_result_data *d = (rust_result_data *)self->storage; | |
| 457 | 3 | rt_tick(SIM_TIMER_OUTPUT); | |
| 458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!d->writer) { |
| 459 | ✗ | openWriter(d, self, data, threadData); | |
| 460 | } | ||
| 461 | 3 | fillRow(d, self, data); | |
| 462 | 3 | omc_result_writer_emit(d->writer, d->row.data()); | |
| 463 | 3 | rt_accumulate(SIM_TIMER_OUTPUT); | |
| 464 | 3 | } | |
| 465 | |||
| 466 | 1 | void rust_result_free(simulation_result *self, DATA *data, threadData_t *threadData) | |
| 467 | { | ||
| 468 | 1 | rust_result_data *d = (rust_result_data *)self->storage; | |
| 469 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if (!d) { |
| 470 | return; | ||
| 471 | } | ||
| 472 | 1 | rt_tick(SIM_TIMER_OUTPUT); | |
| 473 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
|
1 | if (d->writer && !omc_result_writer_close(d->writer)) { |
| 474 | ✗ | warningStreamPrint(OMC_LOG_STDOUT, 0, "Writing the result file %s failed.", self->filename); | |
| 475 | } | ||
| 476 | 1 | delete d; | |
| 477 | 1 | self->storage = NULL; | |
| 478 | 1 | rt_accumulate(SIM_TIMER_OUTPUT); | |
| 479 | } | ||
| 480 | |||
| 481 | } /* extern "C" */ | ||
| 482 |