@sdeverywhere/runtime 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2440 +1,2248 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
- var __hasOwnProp = Object.prototype.hasOwnProperty;
4
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __spreadValues = (a, b) => {
7
- for (var prop in b || (b = {}))
8
- if (__hasOwnProp.call(b, prop))
9
- __defNormalProp(a, prop, b[prop]);
10
- if (__getOwnPropSymbols)
11
- for (var prop of __getOwnPropSymbols(b)) {
12
- if (__propIsEnum.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- }
15
- return a;
16
- };
17
- var __async = (__this, __arguments, generator) => {
18
- return new Promise((resolve, reject) => {
19
- var fulfilled = (value) => {
20
- try {
21
- step(generator.next(value));
22
- } catch (e) {
23
- reject(e);
24
- }
25
- };
26
- var rejected = (value) => {
27
- try {
28
- step(generator.throw(value));
29
- } catch (e) {
30
- reject(e);
31
- }
32
- };
33
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
34
- step((generator = generator.apply(__this, __arguments)).next());
35
- });
36
- };
37
-
38
- // src/_shared/inputs.ts
1
+ import { err, ok } from "neverthrow";
2
+ //#region src/_shared/inputs.ts
3
+ /**
4
+ * Create a basic `InputValue` instance that notifies when a new value is set.
5
+ *
6
+ * @param varId The input variable ID, as used in SDEverywhere.
7
+ * @param defaultValue The default value of the input.
8
+ * @param initialValue The inital value of the input; if undefined, will use `defaultValue`.
9
+ */
39
10
  function createInputValue(varId, defaultValue, initialValue) {
40
- let currentValue = initialValue !== void 0 ? initialValue : defaultValue;
41
- const callbacks = {};
42
- const get = () => {
43
- return currentValue;
44
- };
45
- const set = (newValue) => {
46
- var _a;
47
- if (newValue !== currentValue) {
48
- currentValue = newValue;
49
- (_a = callbacks.onSet) == null ? void 0 : _a.call(callbacks);
50
- }
51
- };
52
- const reset = () => {
53
- set(defaultValue);
54
- };
55
- return { varId, get, set, reset, callbacks };
11
+ let currentValue = initialValue !== void 0 ? initialValue : defaultValue;
12
+ const callbacks = {};
13
+ const get = () => {
14
+ return currentValue;
15
+ };
16
+ const set = (newValue) => {
17
+ if (newValue !== currentValue) {
18
+ currentValue = newValue;
19
+ callbacks.onSet?.();
20
+ }
21
+ };
22
+ const reset = () => {
23
+ set(defaultValue);
24
+ };
25
+ return {
26
+ varId,
27
+ get,
28
+ set,
29
+ reset,
30
+ callbacks
31
+ };
56
32
  }
57
-
58
- // src/_shared/outputs.ts
59
- import { ok, err } from "neverthrow";
60
- var Series = class _Series {
61
- /**
62
- * @param varId The ID for the output variable (as used by SDEverywhere).
63
- * @param points The data points for the variable, one point per time increment.
64
- */
65
- constructor(varId, points) {
66
- this.varId = varId;
67
- this.points = points;
68
- }
69
- /**
70
- * Return the Y value at the given time. Note that this does not attempt to interpolate
71
- * if there is no data point defined for the given time and will return undefined in
72
- * that case.
73
- *
74
- * @param time The x (time) value.
75
- * @return The y value for the given time, or undefined if there is no data point defined
76
- * for the given time.
77
- */
78
- getValueAtTime(time) {
79
- var _a;
80
- return (_a = this.points.find((p) => p.x === time)) == null ? void 0 : _a.y;
81
- }
82
- /**
83
- * Create a new `Series` instance that is a copy of this one.
84
- */
85
- copy() {
86
- const pointsCopy = this.points.map((p) => __spreadValues({}, p));
87
- return new _Series(this.varId, pointsCopy);
88
- }
33
+ //#endregion
34
+ //#region src/_shared/outputs.ts
35
+ /**
36
+ * A time series of data points for an output variable.
37
+ */
38
+ var Series = class Series {
39
+ /**
40
+ * @param varId The ID for the output variable (as used by SDEverywhere).
41
+ * @param points The data points for the variable, one point per time increment.
42
+ */
43
+ constructor(varId, points) {
44
+ this.varId = varId;
45
+ this.points = points;
46
+ }
47
+ /**
48
+ * Return the Y value at the given time. Note that this does not attempt to interpolate
49
+ * if there is no data point defined for the given time and will return undefined in
50
+ * that case.
51
+ *
52
+ * @param time The x (time) value.
53
+ * @return The y value for the given time, or undefined if there is no data point defined
54
+ * for the given time.
55
+ */
56
+ getValueAtTime(time) {
57
+ return this.points.find((p) => p.x === time)?.y;
58
+ }
59
+ /**
60
+ * Create a new `Series` instance that is a copy of this one.
61
+ */
62
+ copy() {
63
+ const pointsCopy = this.points.map((p) => ({ ...p }));
64
+ return new Series(this.varId, pointsCopy);
65
+ }
89
66
  };
67
+ /** Represents the outputs from a model run. */
90
68
  var Outputs = class {
91
- /**
92
- * @param varIds The output variable identifiers.
93
- * @param startTime The start time for the model.
94
- * @param endTime The end time for the model.
95
- * @param saveFreq The frequency with which output values are saved (aka `SAVEPER`).
96
- */
97
- constructor(varIds, startTime, endTime, saveFreq = 1) {
98
- this.varIds = varIds;
99
- this.startTime = startTime;
100
- this.endTime = endTime;
101
- this.saveFreq = saveFreq;
102
- this.seriesLength = Math.round((endTime - startTime) / saveFreq) + 1;
103
- this.varSeries = new Array(varIds.length);
104
- for (let i = 0; i < varIds.length; i++) {
105
- const points = new Array(this.seriesLength);
106
- for (let j = 0; j < this.seriesLength; j++) {
107
- points[j] = { x: startTime + j * saveFreq, y: 0 };
108
- }
109
- const varId = varIds[i];
110
- this.varSeries[i] = new Series(varId, points);
111
- }
112
- }
113
- /**
114
- * The optional set of specs that dictate which variables from the model will be
115
- * stored in this `Outputs` instance. If undefined, the default set of outputs
116
- * will be stored (as configured in `varIds`).
117
- * @hidden This is not yet part of the public API; it is exposed here for use
118
- * in experimental testing tools.
119
- */
120
- setVarSpecs(varSpecs) {
121
- if (varSpecs.length !== this.varIds.length) {
122
- throw new Error("Length of output varSpecs must match that of varIds");
123
- }
124
- this.varSpecs = varSpecs;
125
- }
126
- /**
127
- * Parse the given raw float buffer (produced by the model) and store the values
128
- * into this `Outputs` instance.
129
- *
130
- * Note that the length of `outputsBuffer` must be greater than or equal to
131
- * the capacity of this `Outputs` instance. The `Outputs` instance is allowed
132
- * to be smaller to support the case where you want to extract a subset of
133
- * the time range in the buffer produced by the model.
134
- *
135
- * @param outputsBuffer The raw outputs buffer produced by the model.
136
- * @param rowLength The number of elements per row (one element per save point).
137
- * @return An `ok` result if the buffer is valid, otherwise an `err` result.
138
- */
139
- updateFromBuffer(outputsBuffer, rowLength) {
140
- const result = parseOutputsBuffer(outputsBuffer, rowLength, this);
141
- if (result.isOk()) {
142
- return ok(void 0);
143
- } else {
144
- return err(result.error);
145
- }
146
- }
147
- /**
148
- * Return the series for the given output variable.
149
- *
150
- * @param varId The ID of the output variable (as used by SDEverywhere).
151
- */
152
- getSeriesForVar(varId) {
153
- const seriesIndex = this.varIds.indexOf(varId);
154
- if (seriesIndex >= 0) {
155
- return this.varSeries[seriesIndex];
156
- } else {
157
- return void 0;
158
- }
159
- }
69
+ /**
70
+ * @param varIds The output variable identifiers.
71
+ * @param startTime The start time for the model.
72
+ * @param endTime The end time for the model.
73
+ * @param saveFreq The frequency with which output values are saved (aka `SAVEPER`).
74
+ */
75
+ constructor(varIds, startTime, endTime, saveFreq = 1) {
76
+ this.varIds = varIds;
77
+ this.startTime = startTime;
78
+ this.endTime = endTime;
79
+ this.saveFreq = saveFreq;
80
+ this.seriesLength = Math.round((endTime - startTime) / saveFreq) + 1;
81
+ this.varSeries = new Array(varIds.length);
82
+ for (let i = 0; i < varIds.length; i++) {
83
+ const points = new Array(this.seriesLength);
84
+ for (let j = 0; j < this.seriesLength; j++) points[j] = {
85
+ x: startTime + j * saveFreq,
86
+ y: 0
87
+ };
88
+ const varId = varIds[i];
89
+ this.varSeries[i] = new Series(varId, points);
90
+ }
91
+ }
92
+ /**
93
+ * The optional set of specs that dictate which variables from the model will be
94
+ * stored in this `Outputs` instance. If undefined, the default set of outputs
95
+ * will be stored (as configured in `varIds`).
96
+ * @hidden This is not yet part of the public API; it is exposed here for use
97
+ * in experimental testing tools.
98
+ */
99
+ setVarSpecs(varSpecs) {
100
+ if (varSpecs.length !== this.varIds.length) throw new Error("Length of output varSpecs must match that of varIds");
101
+ this.varSpecs = varSpecs;
102
+ }
103
+ /**
104
+ * Parse the given raw float buffer (produced by the model) and store the values
105
+ * into this `Outputs` instance.
106
+ *
107
+ * Note that the length of `outputsBuffer` must be greater than or equal to
108
+ * the capacity of this `Outputs` instance. The `Outputs` instance is allowed
109
+ * to be smaller to support the case where you want to extract a subset of
110
+ * the time range in the buffer produced by the model.
111
+ *
112
+ * @param outputsBuffer The raw outputs buffer produced by the model.
113
+ * @param rowLength The number of elements per row (one element per save point).
114
+ * @return An `ok` result if the buffer is valid, otherwise an `err` result.
115
+ */
116
+ updateFromBuffer(outputsBuffer, rowLength) {
117
+ const result = parseOutputsBuffer(outputsBuffer, rowLength, this);
118
+ if (result.isOk()) return ok(void 0);
119
+ else return err(result.error);
120
+ }
121
+ /**
122
+ * Return the series for the given output variable.
123
+ *
124
+ * @param varId The ID of the output variable (as used by SDEverywhere).
125
+ */
126
+ getSeriesForVar(varId) {
127
+ const seriesIndex = this.varIds.indexOf(varId);
128
+ if (seriesIndex >= 0) return this.varSeries[seriesIndex];
129
+ else return;
130
+ }
160
131
  };
132
+ /**
133
+ * Parse the raw buffer produced by the model and store the values in the
134
+ * given (reused) `Outputs` object.
135
+ *
136
+ * @param outputsBuffer The raw outputs buffer produced by the model.
137
+ * @param rowLength The number of elements per row (one element per year or save point).
138
+ * @return An `ok` result if the buffer is valid, otherwise an `err` result.
139
+ * @hidden
140
+ */
161
141
  function parseOutputsBuffer(outputsBuffer, rowLength, outputs) {
162
- const varCount = outputs.varIds.length;
163
- const seriesLength = outputs.seriesLength;
164
- if (rowLength < seriesLength || outputsBuffer.length < varCount * seriesLength) {
165
- return err("invalid-point-count");
166
- }
167
- for (let outputVarIndex = 0; outputVarIndex < varCount; outputVarIndex++) {
168
- const series = outputs.varSeries[outputVarIndex];
169
- let sourceIndex = rowLength * outputVarIndex;
170
- for (let valueIndex = 0; valueIndex < seriesLength; valueIndex++) {
171
- series.points[valueIndex].y = validateNumber(outputsBuffer[sourceIndex]);
172
- sourceIndex++;
173
- }
174
- }
175
- return ok(outputs);
142
+ const varCount = outputs.varIds.length;
143
+ const seriesLength = outputs.seriesLength;
144
+ if (rowLength < seriesLength || outputsBuffer.length < varCount * seriesLength) return err("invalid-point-count");
145
+ for (let outputVarIndex = 0; outputVarIndex < varCount; outputVarIndex++) {
146
+ const series = outputs.varSeries[outputVarIndex];
147
+ let sourceIndex = rowLength * outputVarIndex;
148
+ for (let valueIndex = 0; valueIndex < seriesLength; valueIndex++) {
149
+ series.points[valueIndex].y = validateNumber(outputsBuffer[sourceIndex]);
150
+ sourceIndex++;
151
+ }
152
+ }
153
+ return ok(outputs);
176
154
  }
155
+ /**
156
+ * Return the given number if it is valid, or undefined if it is invalid.
157
+ *
158
+ * SDE converts Vensim's `:NA:` values to `-DBL_MAX`, so if we see a very large negative
159
+ * value, convert it to `undefined`. This is preferable to including extreme values
160
+ * because some charting libraries (e.g. Chart.js) appear to choke on these large values
161
+ * in certain browsers (e.g. Safari), but `undefined` appears to be handled better and
162
+ * does a better job of signaling that the data point is undefined.
163
+ *
164
+ * @hidden
165
+ */
177
166
  function validateNumber(x) {
178
- if (!isNaN(x) && x > -1e32) {
179
- return x;
180
- } else {
181
- return void 0;
182
- }
167
+ if (!isNaN(x) && x > -1e32) return x;
168
+ else return;
183
169
  }
184
-
185
- // src/_shared/var-indices.ts
170
+ //#endregion
171
+ //#region src/_shared/var-indices.ts
172
+ /**
173
+ * Return the length of the array that is required to store the variable
174
+ * indices for the given `VarSpec` instances.
175
+ *
176
+ * @hidden This is not part of the public API; it is exposed here for use by
177
+ * the synchronous and asynchronous model runner implementations.
178
+ *
179
+ * @param varSpecs The `VarSpec` instances to encode.
180
+ */
186
181
  function getEncodedVarIndicesLength(varSpecs) {
187
- var _a;
188
- let length = 1;
189
- for (const varSpec of varSpecs) {
190
- length += 2;
191
- const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
192
- length += subCount;
193
- }
194
- return length;
182
+ let length = 1;
183
+ for (const varSpec of varSpecs) {
184
+ length += 2;
185
+ const subCount = varSpec.subscriptIndices?.length || 0;
186
+ length += subCount;
187
+ }
188
+ return length;
195
189
  }
190
+ /**
191
+ * Encode variable indices to the given array.
192
+ *
193
+ * @hidden This is not part of the public API; it is exposed here for use by
194
+ * the synchronous and asynchronous model runner implementations.
195
+ *
196
+ * @param varSpecs The `VarSpec` instances to encode.
197
+ */
196
198
  function encodeVarIndices(varSpecs, indicesArray) {
197
- let offset = 0;
198
- indicesArray[offset++] = varSpecs.length;
199
- for (const varSpec of varSpecs) {
200
- indicesArray[offset++] = varSpec.varIndex;
201
- const subs = varSpec.subscriptIndices;
202
- const subCount = (subs == null ? void 0 : subs.length) || 0;
203
- indicesArray[offset++] = subCount;
204
- for (let i = 0; i < subCount; i++) {
205
- indicesArray[offset++] = subs[i];
206
- }
207
- }
199
+ let offset = 0;
200
+ indicesArray[offset++] = varSpecs.length;
201
+ for (const varSpec of varSpecs) {
202
+ indicesArray[offset++] = varSpec.varIndex;
203
+ const subs = varSpec.subscriptIndices;
204
+ const subCount = subs?.length || 0;
205
+ indicesArray[offset++] = subCount;
206
+ for (let i = 0; i < subCount; i++) indicesArray[offset++] = subs[i];
207
+ }
208
208
  }
209
+ /**
210
+ * Return the lengths of the arrays that are required to store the constant values
211
+ * and indices for the given `ConstantDef` instances.
212
+ *
213
+ * @hidden This is not part of the public API; it is exposed here for use by
214
+ * the synchronous and asynchronous model runner implementations.
215
+ *
216
+ * @param constantDefs The `ConstantDef` instances to encode.
217
+ */
209
218
  function getEncodedConstantBufferLengths(constantDefs) {
210
- var _a;
211
- let constantIndicesLength = 1;
212
- let constantsLength = 0;
213
- for (const constantDef of constantDefs) {
214
- const varSpec = constantDef.varRef.varSpec;
215
- if (varSpec === void 0) {
216
- throw new Error("Cannot compute constant buffer lengths until all constant var specs are defined");
217
- }
218
- constantIndicesLength += 2;
219
- const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
220
- constantIndicesLength += subCount;
221
- constantsLength += 1;
222
- }
223
- return {
224
- constantIndicesLength,
225
- constantsLength
226
- };
219
+ let constantIndicesLength = 1;
220
+ let constantsLength = 0;
221
+ for (const constantDef of constantDefs) {
222
+ const varSpec = constantDef.varRef.varSpec;
223
+ if (varSpec === void 0) throw new Error("Cannot compute constant buffer lengths until all constant var specs are defined");
224
+ constantIndicesLength += 2;
225
+ const subCount = varSpec.subscriptIndices?.length || 0;
226
+ constantIndicesLength += subCount;
227
+ constantsLength += 1;
228
+ }
229
+ return {
230
+ constantIndicesLength,
231
+ constantsLength
232
+ };
227
233
  }
234
+ /**
235
+ * Encode constant values and indices to the given arrays.
236
+ *
237
+ * @hidden This is not part of the public API; it is exposed here for use by
238
+ * the synchronous and asynchronous model runner implementations.
239
+ *
240
+ * @param constantDefs The `ConstantDef` instances to encode.
241
+ * @param constantIndicesArray The view on the constant indices buffer.
242
+ * @param constantsArray The view on the constant values buffer.
243
+ */
228
244
  function encodeConstants(constantDefs, constantIndicesArray, constantsArray) {
229
- let ci = 0;
230
- constantIndicesArray[ci++] = constantDefs.length;
231
- let constantDataOffset = 0;
232
- for (const constantDef of constantDefs) {
233
- const varSpec = constantDef.varRef.varSpec;
234
- constantIndicesArray[ci++] = varSpec.varIndex;
235
- const subs = varSpec.subscriptIndices;
236
- const subCount = (subs == null ? void 0 : subs.length) || 0;
237
- constantIndicesArray[ci++] = subCount;
238
- for (let i = 0; i < subCount; i++) {
239
- constantIndicesArray[ci++] = subs[i];
240
- }
241
- constantsArray[constantDataOffset++] = constantDef.value;
242
- }
245
+ let ci = 0;
246
+ constantIndicesArray[ci++] = constantDefs.length;
247
+ let constantDataOffset = 0;
248
+ for (const constantDef of constantDefs) {
249
+ const varSpec = constantDef.varRef.varSpec;
250
+ constantIndicesArray[ci++] = varSpec.varIndex;
251
+ const subs = varSpec.subscriptIndices;
252
+ const subCount = subs?.length || 0;
253
+ constantIndicesArray[ci++] = subCount;
254
+ for (let i = 0; i < subCount; i++) constantIndicesArray[ci++] = subs[i];
255
+ constantsArray[constantDataOffset++] = constantDef.value;
256
+ }
243
257
  }
258
+ /**
259
+ * Decode constant values and indices from the given buffer views and return the
260
+ * reconstructed `ConstantDef` instances.
261
+ *
262
+ * @hidden This is not part of the public API; it is exposed here for use by
263
+ * the synchronous and asynchronous model runner implementations.
264
+ *
265
+ * @param constantIndicesArray The view on the constant indices buffer.
266
+ * @param constantsArray The view on the constant values buffer.
267
+ */
244
268
  function decodeConstants(constantIndicesArray, constantsArray) {
245
- const constantDefs = [];
246
- let ci = 0;
247
- const constantCount = constantIndicesArray[ci++];
248
- for (let i = 0; i < constantCount; i++) {
249
- const varIndex = constantIndicesArray[ci++];
250
- const subCount = constantIndicesArray[ci++];
251
- const subscriptIndices = subCount > 0 ? Array(subCount) : void 0;
252
- for (let subIndex = 0; subIndex < subCount; subIndex++) {
253
- subscriptIndices[subIndex] = constantIndicesArray[ci++];
254
- }
255
- const varSpec = {
256
- varIndex,
257
- subscriptIndices
258
- };
259
- const value = constantsArray[i];
260
- constantDefs.push({
261
- varRef: {
262
- varSpec
263
- },
264
- value
265
- });
266
- }
267
- return constantDefs;
269
+ const constantDefs = [];
270
+ let ci = 0;
271
+ const constantCount = constantIndicesArray[ci++];
272
+ for (let i = 0; i < constantCount; i++) {
273
+ const varIndex = constantIndicesArray[ci++];
274
+ const subCount = constantIndicesArray[ci++];
275
+ const subscriptIndices = subCount > 0 ? Array(subCount) : void 0;
276
+ for (let subIndex = 0; subIndex < subCount; subIndex++) subscriptIndices[subIndex] = constantIndicesArray[ci++];
277
+ const varSpec = {
278
+ varIndex,
279
+ subscriptIndices
280
+ };
281
+ const value = constantsArray[i];
282
+ constantDefs.push({
283
+ varRef: { varSpec },
284
+ value
285
+ });
286
+ }
287
+ return constantDefs;
268
288
  }
289
+ /**
290
+ * Return the lengths of the arrays that are required to store the lookup data
291
+ * and indices for the given `LookupDef` instances.
292
+ *
293
+ * @hidden This is not part of the public API; it is exposed here for use by
294
+ * the synchronous and asynchronous model runner implementations.
295
+ *
296
+ * @param lookupDefs The `LookupDef` instances to encode.
297
+ */
269
298
  function getEncodedLookupBufferLengths(lookupDefs) {
270
- var _a, _b;
271
- let lookupIndicesLength = 1;
272
- let lookupsLength = 0;
273
- for (const lookupDef of lookupDefs) {
274
- const varSpec = lookupDef.varRef.varSpec;
275
- if (varSpec === void 0) {
276
- throw new Error("Cannot compute lookup buffer lengths until all lookup var specs are defined");
277
- }
278
- lookupIndicesLength += 2;
279
- const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
280
- lookupIndicesLength += subCount;
281
- lookupIndicesLength += 2;
282
- lookupsLength += ((_b = lookupDef.points) == null ? void 0 : _b.length) || 0;
283
- }
284
- return {
285
- lookupIndicesLength,
286
- lookupsLength
287
- };
299
+ let lookupIndicesLength = 1;
300
+ let lookupsLength = 0;
301
+ for (const lookupDef of lookupDefs) {
302
+ const varSpec = lookupDef.varRef.varSpec;
303
+ if (varSpec === void 0) throw new Error("Cannot compute lookup buffer lengths until all lookup var specs are defined");
304
+ lookupIndicesLength += 2;
305
+ const subCount = varSpec.subscriptIndices?.length || 0;
306
+ lookupIndicesLength += subCount;
307
+ lookupIndicesLength += 2;
308
+ lookupsLength += lookupDef.points?.length || 0;
309
+ }
310
+ return {
311
+ lookupIndicesLength,
312
+ lookupsLength
313
+ };
288
314
  }
315
+ /**
316
+ * Encode lookup data and indices to the given arrays.
317
+ *
318
+ * @hidden This is not part of the public API; it is exposed here for use by
319
+ * the synchronous and asynchronous model runner implementations.
320
+ *
321
+ * @param lookupDefs The `LookupDef` instances to encode.
322
+ * @param lookupIndicesArray The view on the lookup indices buffer.
323
+ * @param lookupsArray The view on the lookup data buffer. This can be undefined in
324
+ * the case where the data for the lookup(s) is empty.
325
+ */
289
326
  function encodeLookups(lookupDefs, lookupIndicesArray, lookupsArray) {
290
- let li = 0;
291
- lookupIndicesArray[li++] = lookupDefs.length;
292
- let lookupDataOffset = 0;
293
- for (const lookupDef of lookupDefs) {
294
- const varSpec = lookupDef.varRef.varSpec;
295
- lookupIndicesArray[li++] = varSpec.varIndex;
296
- const subs = varSpec.subscriptIndices;
297
- const subCount = (subs == null ? void 0 : subs.length) || 0;
298
- lookupIndicesArray[li++] = subCount;
299
- for (let i = 0; i < subCount; i++) {
300
- lookupIndicesArray[li++] = subs[i];
301
- }
302
- if (lookupDef.points !== void 0) {
303
- lookupIndicesArray[li++] = lookupDataOffset;
304
- lookupIndicesArray[li++] = lookupDef.points.length;
305
- lookupsArray == null ? void 0 : lookupsArray.set(lookupDef.points, lookupDataOffset);
306
- lookupDataOffset += lookupDef.points.length;
307
- } else {
308
- lookupIndicesArray[li++] = -1;
309
- lookupIndicesArray[li++] = 0;
310
- }
311
- }
327
+ let li = 0;
328
+ lookupIndicesArray[li++] = lookupDefs.length;
329
+ let lookupDataOffset = 0;
330
+ for (const lookupDef of lookupDefs) {
331
+ const varSpec = lookupDef.varRef.varSpec;
332
+ lookupIndicesArray[li++] = varSpec.varIndex;
333
+ const subs = varSpec.subscriptIndices;
334
+ const subCount = subs?.length || 0;
335
+ lookupIndicesArray[li++] = subCount;
336
+ for (let i = 0; i < subCount; i++) lookupIndicesArray[li++] = subs[i];
337
+ if (lookupDef.points !== void 0) {
338
+ lookupIndicesArray[li++] = lookupDataOffset;
339
+ lookupIndicesArray[li++] = lookupDef.points.length;
340
+ lookupsArray?.set(lookupDef.points, lookupDataOffset);
341
+ lookupDataOffset += lookupDef.points.length;
342
+ } else {
343
+ lookupIndicesArray[li++] = -1;
344
+ lookupIndicesArray[li++] = 0;
345
+ }
346
+ }
312
347
  }
348
+ /**
349
+ * Decode lookup data and indices from the given buffer views and return the
350
+ * reconstructed `LookupDef` instances.
351
+ *
352
+ * @hidden This is not part of the public API; it is exposed here for use by
353
+ * the synchronous and asynchronous model runner implementations.
354
+ *
355
+ * @param lookupIndicesArray The view on the lookup indices buffer.
356
+ * @param lookupsArray The view on the lookup data buffer. This can be undefined in
357
+ * the case where the data for the lookup(s) is empty.
358
+ */
313
359
  function decodeLookups(lookupIndicesArray, lookupsArray) {
314
- const lookupDefs = [];
315
- let li = 0;
316
- const lookupCount = lookupIndicesArray[li++];
317
- for (let i = 0; i < lookupCount; i++) {
318
- const varIndex = lookupIndicesArray[li++];
319
- const subCount = lookupIndicesArray[li++];
320
- const subscriptIndices = subCount > 0 ? Array(subCount) : void 0;
321
- for (let subIndex = 0; subIndex < subCount; subIndex++) {
322
- subscriptIndices[subIndex] = lookupIndicesArray[li++];
323
- }
324
- const lookupDataOffset = lookupIndicesArray[li++];
325
- const lookupDataLength = lookupIndicesArray[li++];
326
- const varSpec = {
327
- varIndex,
328
- subscriptIndices
329
- };
330
- let points;
331
- if (lookupDataOffset >= 0) {
332
- if (lookupsArray) {
333
- points = lookupsArray.slice(lookupDataOffset, lookupDataOffset + lookupDataLength);
334
- } else {
335
- points = new Float64Array(0);
336
- }
337
- } else {
338
- points = void 0;
339
- }
340
- lookupDefs.push({
341
- varRef: {
342
- varSpec
343
- },
344
- points
345
- });
346
- }
347
- return lookupDefs;
360
+ const lookupDefs = [];
361
+ let li = 0;
362
+ const lookupCount = lookupIndicesArray[li++];
363
+ for (let i = 0; i < lookupCount; i++) {
364
+ const varIndex = lookupIndicesArray[li++];
365
+ const subCount = lookupIndicesArray[li++];
366
+ const subscriptIndices = subCount > 0 ? Array(subCount) : void 0;
367
+ for (let subIndex = 0; subIndex < subCount; subIndex++) subscriptIndices[subIndex] = lookupIndicesArray[li++];
368
+ const lookupDataOffset = lookupIndicesArray[li++];
369
+ const lookupDataLength = lookupIndicesArray[li++];
370
+ const varSpec = {
371
+ varIndex,
372
+ subscriptIndices
373
+ };
374
+ let points;
375
+ if (lookupDataOffset >= 0) {
376
+ if (lookupsArray) points = lookupsArray.slice(lookupDataOffset, lookupDataOffset + lookupDataLength);
377
+ else points = /* @__PURE__ */ new Float64Array(0);
378
+ } else points = void 0;
379
+ lookupDefs.push({
380
+ varRef: { varSpec },
381
+ points
382
+ });
383
+ }
384
+ return lookupDefs;
348
385
  }
349
-
350
- // src/_shared/constant-def.ts
386
+ //#endregion
387
+ //#region src/_shared/constant-def.ts
388
+ /**
389
+ * Create a `ConstantDef` instance.
390
+ *
391
+ * @param varRef The reference to the constant variable to be modified.
392
+ * @param value The new constant value.
393
+ */
351
394
  function createConstantDef(varRef, value) {
352
- return {
353
- varRef,
354
- value
355
- };
395
+ return {
396
+ varRef,
397
+ value
398
+ };
356
399
  }
357
-
358
- // src/_shared/lookup-def.ts
400
+ //#endregion
401
+ //#region src/_shared/lookup-def.ts
402
+ /**
403
+ * Create a `LookupDef` instance from the given array of `Point` objects.
404
+ *
405
+ * @param varRef The reference to the lookup or data variable to be modified.
406
+ * @param points The lookup data as an array of `Point` objects. This can be
407
+ * undefined, in which case the lookup data will be reset to the original data.
408
+ */
359
409
  function createLookupDef(varRef, points) {
360
- let flatPoints;
361
- if (points) {
362
- flatPoints = new Float64Array(points.length * 2);
363
- let i = 0;
364
- for (const p of points) {
365
- flatPoints[i++] = p.x;
366
- flatPoints[i++] = p.y;
367
- }
368
- }
369
- return {
370
- varRef,
371
- points: flatPoints
372
- };
410
+ let flatPoints;
411
+ if (points) {
412
+ flatPoints = new Float64Array(points.length * 2);
413
+ let i = 0;
414
+ for (const p of points) {
415
+ flatPoints[i++] = p.x;
416
+ flatPoints[i++] = p.y;
417
+ }
418
+ }
419
+ return {
420
+ varRef,
421
+ points: flatPoints
422
+ };
373
423
  }
374
-
375
- // src/model-listing/model-listing.ts
424
+ //#endregion
425
+ //#region src/model-listing/model-listing.ts
426
+ /**
427
+ * @hidden This is not yet part of the public API; it is exposed here for use
428
+ * in experimental testing tools.
429
+ */
376
430
  var ModelListing = class {
377
- constructor(listingObj) {
378
- this.varSpecs = /* @__PURE__ */ new Map();
379
- const dimensions = /* @__PURE__ */ new Map();
380
- for (const dimInfo of listingObj.dimensions) {
381
- const dimId = dimInfo.id;
382
- const subscripts = [];
383
- for (let i = 0; i < dimInfo.subIds.length; i++) {
384
- subscripts.push({
385
- id: dimInfo.subIds[i],
386
- index: i
387
- });
388
- }
389
- dimensions.set(dimId, {
390
- id: dimId,
391
- subscripts
392
- });
393
- }
394
- function dimensionForId(dimId) {
395
- const dim = dimensions.get(dimId);
396
- if (dim === void 0) {
397
- throw new Error(`No dimension info found for id=${dimId}`);
398
- }
399
- return dim;
400
- }
401
- const baseVarIds = /* @__PURE__ */ new Set();
402
- for (const v of listingObj.variables) {
403
- const baseVarId = varIdWithoutSubscripts(v.id);
404
- if (!baseVarIds.has(baseVarId)) {
405
- const dimIds = v.dimIds || [];
406
- const dimensions2 = dimIds.map(dimensionForId);
407
- if (dimensions2.length > 0) {
408
- const dimSubs = [];
409
- for (const dim of dimensions2) {
410
- dimSubs.push(dim.subscripts);
411
- }
412
- const combos = cartesianProductOf(dimSubs);
413
- for (const combo of combos) {
414
- const subs = combo.map((sub) => sub.id).join(",");
415
- const subIndices = combo.map((sub) => sub.index);
416
- const fullVarId = `${baseVarId}[${subs}]`;
417
- this.varSpecs.set(fullVarId, {
418
- varIndex: v.index,
419
- subscriptIndices: subIndices
420
- });
421
- }
422
- } else {
423
- this.varSpecs.set(baseVarId, {
424
- varIndex: v.index
425
- });
426
- }
427
- baseVarIds.add(baseVarId);
428
- }
429
- }
430
- }
431
- /**
432
- * Return the `VarSpec` for the given variable ID, or undefined if there is no spec defined
433
- * in the listing for that variable.
434
- */
435
- getSpecForVarId(varId) {
436
- return this.varSpecs.get(varId);
437
- }
438
- /**
439
- * Return the `VarSpec` for the given variable name, or undefined if there is no spec defined
440
- * in the listing for that variable.
441
- */
442
- getSpecForVarName(varName) {
443
- const varId = sdeVarIdForVensimVarName(varName);
444
- return this.varSpecs.get(varId);
445
- }
446
- /**
447
- * Create a new `Outputs` instance that uses the same start/end years as the given "normal"
448
- * `Outputs` instance but is prepared for reading the specified internal variables from the model.
449
- *
450
- * @param normalOutputs The `Outputs` that is used to access normal output variables from the model.
451
- * @param varIds The variable IDs to include with the new `Outputs` instance.
452
- */
453
- deriveOutputs(normalOutputs, varIds) {
454
- const varSpecs = [];
455
- for (const varId of varIds) {
456
- const varSpec = this.varSpecs.get(varId);
457
- if (varSpec !== void 0) {
458
- varSpecs.push(varSpec);
459
- } else {
460
- console.warn(`WARNING: No output var spec found for id=${varId}`);
461
- }
462
- }
463
- const newOutputs = new Outputs(varIds, normalOutputs.startTime, normalOutputs.endTime, normalOutputs.saveFreq);
464
- newOutputs.varSpecs = varSpecs;
465
- return newOutputs;
466
- }
431
+ constructor(listingObj) {
432
+ this.varSpecs = /* @__PURE__ */ new Map();
433
+ const dimensions = /* @__PURE__ */ new Map();
434
+ for (const dimInfo of listingObj.dimensions) {
435
+ const dimId = dimInfo.id;
436
+ const subscripts = [];
437
+ for (let i = 0; i < dimInfo.subIds.length; i++) subscripts.push({
438
+ id: dimInfo.subIds[i],
439
+ index: i
440
+ });
441
+ dimensions.set(dimId, {
442
+ id: dimId,
443
+ subscripts
444
+ });
445
+ }
446
+ function dimensionForId(dimId) {
447
+ const dim = dimensions.get(dimId);
448
+ if (dim === void 0) throw new Error(`No dimension info found for id=${dimId}`);
449
+ return dim;
450
+ }
451
+ const baseVarIds = /* @__PURE__ */ new Set();
452
+ for (const v of listingObj.variables) {
453
+ const baseVarId = varIdWithoutSubscripts(v.id);
454
+ if (!baseVarIds.has(baseVarId)) {
455
+ const dimensions = (v.dimIds || []).map(dimensionForId);
456
+ if (dimensions.length > 0) {
457
+ const dimSubs = [];
458
+ for (const dim of dimensions) dimSubs.push(dim.subscripts);
459
+ const combos = cartesianProductOf(dimSubs);
460
+ for (const combo of combos) {
461
+ const subs = combo.map((sub) => sub.id).join(",");
462
+ const subIndices = combo.map((sub) => sub.index);
463
+ const fullVarId = `${baseVarId}[${subs}]`;
464
+ this.varSpecs.set(fullVarId, {
465
+ varIndex: v.index,
466
+ subscriptIndices: subIndices
467
+ });
468
+ }
469
+ } else this.varSpecs.set(baseVarId, { varIndex: v.index });
470
+ baseVarIds.add(baseVarId);
471
+ }
472
+ }
473
+ }
474
+ /**
475
+ * Return the `VarSpec` for the given variable ID, or undefined if there is no spec defined
476
+ * in the listing for that variable.
477
+ */
478
+ getSpecForVarId(varId) {
479
+ return this.varSpecs.get(varId);
480
+ }
481
+ /**
482
+ * Return the `VarSpec` for the given variable name, or undefined if there is no spec defined
483
+ * in the listing for that variable.
484
+ */
485
+ getSpecForVarName(varName) {
486
+ const varId = sdeVarIdForVensimVarName(varName);
487
+ return this.varSpecs.get(varId);
488
+ }
489
+ /**
490
+ * Create a new `Outputs` instance that uses the same start/end years as the given "normal"
491
+ * `Outputs` instance but is prepared for reading the specified internal variables from the model.
492
+ *
493
+ * @param normalOutputs The `Outputs` that is used to access normal output variables from the model.
494
+ * @param varIds The variable IDs to include with the new `Outputs` instance.
495
+ */
496
+ deriveOutputs(normalOutputs, varIds) {
497
+ const varSpecs = [];
498
+ for (const varId of varIds) {
499
+ const varSpec = this.varSpecs.get(varId);
500
+ if (varSpec !== void 0) varSpecs.push(varSpec);
501
+ else console.warn(`WARNING: No output var spec found for id=${varId}`);
502
+ }
503
+ const newOutputs = new Outputs(varIds, normalOutputs.startTime, normalOutputs.endTime, normalOutputs.saveFreq);
504
+ newOutputs.varSpecs = varSpecs;
505
+ return newOutputs;
506
+ }
467
507
  };
508
+ /**
509
+ * Helper function that returns the base name of a variable without the subscripts.
510
+ */
468
511
  function varIdWithoutSubscripts(fullVarId) {
469
- const bracketIndex = fullVarId.indexOf("[");
470
- if (bracketIndex >= 0) {
471
- return fullVarId.substring(0, bracketIndex);
472
- } else {
473
- return fullVarId;
474
- }
512
+ const bracketIndex = fullVarId.indexOf("[");
513
+ if (bracketIndex >= 0) return fullVarId.substring(0, bracketIndex);
514
+ else return fullVarId;
475
515
  }
516
+ /**
517
+ * Return the cartesian product of the given array of arrays.
518
+ *
519
+ * For example, if we have an array that lists out two dimensions:
520
+ * [ ['a1','a2'], ['b1','b2','b3'] ]
521
+ * this function will return all the combinations, e.g.:
522
+ * [ ['a1', 'b1'], ['a1', 'b2'], ['a1', 'b3'], ['a2', 'b1'], ... ]
523
+ *
524
+ * This can be used in place of nested for loops and has the benefit of working
525
+ * for multi-dimensional inputs.
526
+ */
476
527
  function cartesianProductOf(arr) {
477
- return arr.reduce(
478
- (a, b) => {
479
- return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
480
- },
481
- [[]]
482
- );
528
+ return arr.reduce((a, b) => {
529
+ return a.map((x) => b.map((y) => x.concat([y]))).reduce((v, w) => v.concat(w), []);
530
+ }, [[]]);
483
531
  }
532
+ /**
533
+ * Helper function that converts a Vensim variable or subscript name
534
+ * into a valid C identifier as used by SDE.
535
+ * TODO: Import helper function from `compile` package instead
536
+ */
484
537
  function sdeVarIdForVensimName(name) {
485
- return "_" + name.trim().replace(/"/g, "_").replace(/\s+!$/g, "!").replace(/\s/g, "_").replace(/,/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/\$/g, "_").replace(/'/g, "_").replace(/&/g, "_").replace(/%/g, "_").replace(/\//g, "_").replace(/\|/g, "_").toLowerCase();
538
+ return "_" + name.trim().replace(/"/g, "_").replace(/\s+!$/g, "!").replace(/\s/g, "_").replace(/,/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/\$/g, "_").replace(/'/g, "_").replace(/&/g, "_").replace(/%/g, "_").replace(/\//g, "_").replace(/\|/g, "_").toLowerCase();
486
539
  }
540
+ /**
541
+ * Helper function that converts a Vensim variable name (possibly containing
542
+ * subscripts) into a valid C identifier as used by SDE.
543
+ * TODO: Import helper function from `compile` package instead
544
+ */
487
545
  function sdeVarIdForVensimVarName(varName) {
488
- const m = varName.match(/([^[]+)(?:\[([^\]]+)\])?/);
489
- if (!m) {
490
- throw new Error(`Invalid Vensim name: ${varName}`);
491
- }
492
- let id = sdeVarIdForVensimName(m[1]);
493
- if (m[2]) {
494
- const subscripts = m[2].split(",").map((x) => sdeVarIdForVensimName(x));
495
- id += `[${subscripts.join(",")}]`;
496
- }
497
- return id;
546
+ const m = varName.match(/([^[]+)(?:\[([^\]]+)\])?/);
547
+ if (!m) throw new Error(`Invalid Vensim name: ${varName}`);
548
+ let id = sdeVarIdForVensimName(m[1]);
549
+ if (m[2]) {
550
+ const subscripts = m[2].split(",").map((x) => sdeVarIdForVensimName(x));
551
+ id += `[${subscripts.join(",")}]`;
552
+ }
553
+ return id;
498
554
  }
499
-
500
- // src/runnable-model/resolve-var-ref.ts
555
+ //#endregion
556
+ //#region src/runnable-model/resolve-var-ref.ts
557
+ /**
558
+ * Resolve the provided variable reference using the `ModelListing` and variable name
559
+ * or identifier.
560
+ *
561
+ * - If `varRef` has a defined `varSpec`, it is assumed to be valid.
562
+ * - Otherwise, if `varRef` has a defined `varId`, it will be used to locate the
563
+ * corresponding `varSpec` in the provided listing.
564
+ * - Otherwise, if `varRef` has a defined `varName`, it will be used to locate the
565
+ * corresponding `varSpec` in the provided listing.
566
+ *
567
+ * If the `varSpec` is found, this will set the `varSpec` property on the provided `varRef`.
568
+ * Otherwise, this will throw an error.
569
+ *
570
+ * @hidden This is not part of the public API; it is exposed here for internal
571
+ * use only.
572
+ *
573
+ * @param listing The model listing.
574
+ * @param varRef The variable reference.
575
+ * @param varKind The kind of variable (e.g., "lookup"), used to build an error message.
576
+ */
501
577
  function resolveVarRef(listing, varRef, varKind) {
502
- if (varRef.varSpec) {
503
- return;
504
- }
505
- if (listing === void 0) {
506
- throw new Error(
507
- `Unable to resolve ${varKind} variable references by name or identifier when model listing is unavailable`
508
- );
509
- }
510
- if (varRef.varId) {
511
- const varSpec = listing == null ? void 0 : listing.getSpecForVarId(varRef.varId);
512
- if (varSpec) {
513
- varRef.varSpec = varSpec;
514
- } else {
515
- throw new Error(`Failed to resolve ${varKind} variable reference for varId=${varRef.varId}`);
516
- }
517
- } else {
518
- const varSpec = listing == null ? void 0 : listing.getSpecForVarName(varRef.varName);
519
- if (varSpec) {
520
- varRef.varSpec = varSpec;
521
- } else {
522
- throw new Error(`Failed to resolve ${varKind} variable reference for varName='${varRef.varId}'`);
523
- }
524
- }
578
+ if (varRef.varSpec) return;
579
+ if (listing === void 0) throw new Error(`Unable to resolve ${varKind} variable references by name or identifier when model listing is unavailable`);
580
+ if (varRef.varId) {
581
+ const varSpec = listing?.getSpecForVarId(varRef.varId);
582
+ if (varSpec) varRef.varSpec = varSpec;
583
+ else throw new Error(`Failed to resolve ${varKind} variable reference for varId=${varRef.varId}`);
584
+ } else {
585
+ const varSpec = listing?.getSpecForVarName(varRef.varName);
586
+ if (varSpec) varRef.varSpec = varSpec;
587
+ else throw new Error(`Failed to resolve ${varKind} variable reference for varName='${varRef.varId}'`);
588
+ }
525
589
  }
526
-
527
- // src/runnable-model/buffered-run-model-params.ts
528
- var headerLengthInElements = 20;
529
- var extrasLengthInElements = 1;
590
+ //#endregion
591
+ //#region src/runnable-model/buffered-run-model-params.ts
592
+ const headerLengthInElements = 20;
593
+ const extrasLengthInElements = 1;
530
594
  var Int32Section = class {
531
- constructor() {
532
- this.offsetInBytes = 0;
533
- this.lengthInElements = 0;
534
- }
535
- update(encoded, offsetInBytes, lengthInElements) {
536
- this.view = lengthInElements > 0 ? new Int32Array(encoded, offsetInBytes, lengthInElements) : void 0;
537
- this.offsetInBytes = offsetInBytes;
538
- this.lengthInElements = lengthInElements;
539
- }
595
+ constructor() {
596
+ this.offsetInBytes = 0;
597
+ this.lengthInElements = 0;
598
+ }
599
+ update(encoded, offsetInBytes, lengthInElements) {
600
+ this.view = lengthInElements > 0 ? new Int32Array(encoded, offsetInBytes, lengthInElements) : void 0;
601
+ this.offsetInBytes = offsetInBytes;
602
+ this.lengthInElements = lengthInElements;
603
+ }
540
604
  };
541
605
  var Float64Section = class {
542
- constructor() {
543
- this.offsetInBytes = 0;
544
- this.lengthInElements = 0;
545
- }
546
- update(encoded, offsetInBytes, lengthInElements) {
547
- this.view = lengthInElements > 0 ? new Float64Array(encoded, offsetInBytes, lengthInElements) : void 0;
548
- this.offsetInBytes = offsetInBytes;
549
- this.lengthInElements = lengthInElements;
550
- }
606
+ constructor() {
607
+ this.offsetInBytes = 0;
608
+ this.lengthInElements = 0;
609
+ }
610
+ update(encoded, offsetInBytes, lengthInElements) {
611
+ this.view = lengthInElements > 0 ? new Float64Array(encoded, offsetInBytes, lengthInElements) : void 0;
612
+ this.offsetInBytes = offsetInBytes;
613
+ this.lengthInElements = lengthInElements;
614
+ }
551
615
  };
616
+ /**
617
+ * An implementation of `RunModelParams` that copies the input and output arrays into a single,
618
+ * combined buffer. This implementation is designed to work with an asynchronous `ModelRunner`
619
+ * implementation because the buffer can be transferred to/from a Web Worker or Node.js worker
620
+ * thread without copying (if it is marked `Transferable`).
621
+ *
622
+ * @hidden This is not yet exposed in the public API; it is currently only used by
623
+ * the implementations of the `RunnableModel` interface.
624
+ */
552
625
  var BufferedRunModelParams = class {
553
- /**
554
- * @param listing The model listing that is used to locate a variable that is referenced by
555
- * name or identifier. If undefined, variables cannot be referenced by name or identifier,
556
- * and can only be referenced using a valid `VarSpec`.
557
- */
558
- constructor(listing) {
559
- this.listing = listing;
560
- /**
561
- * The header section of the `encoded` buffer. The header declares the byte offset and length
562
- * (in elements) of each section of the buffer.
563
- */
564
- this.header = new Int32Section();
565
- /** The extras section of the `encoded` buffer (holds elapsed time, etc). */
566
- this.extras = new Float64Section();
567
- /** The inputs section of the `encoded` buffer. */
568
- this.inputs = new Float64Section();
569
- /** The outputs section of the `encoded` buffer. */
570
- this.outputs = new Float64Section();
571
- /** The output indices section of the `encoded` buffer. */
572
- this.outputIndices = new Int32Section();
573
- /** The constant values section of the `encoded` buffer. */
574
- this.constants = new Float64Section();
575
- /** The constant indices section of the `encoded` buffer. */
576
- this.constantIndices = new Int32Section();
577
- /** The lookup data section of the `encoded` buffer. */
578
- this.lookups = new Float64Section();
579
- /** The lookup indices section of the `encoded` buffer. */
580
- this.lookupIndices = new Int32Section();
581
- }
582
- /**
583
- * Return the encoded buffer from this instance, which can be passed to `updateFromEncodedBuffer`.
584
- */
585
- getEncodedBuffer() {
586
- return this.encoded;
587
- }
588
- // from RunModelParams interface
589
- getInputs() {
590
- return this.inputs.view;
591
- }
592
- // from RunModelParams interface
593
- copyInputs(array, create) {
594
- if (this.inputs.lengthInElements === 0) {
595
- return;
596
- }
597
- if (array === void 0 || array.length < this.inputs.lengthInElements) {
598
- array = create(this.inputs.lengthInElements);
599
- }
600
- array.set(this.inputs.view);
601
- }
602
- // from RunModelParams interface
603
- getOutputIndicesLength() {
604
- return this.outputIndices.lengthInElements;
605
- }
606
- // from RunModelParams interface
607
- getOutputIndices() {
608
- return this.outputIndices.view;
609
- }
610
- // from RunModelParams interface
611
- copyOutputIndices(array, create) {
612
- if (this.outputIndices.lengthInElements === 0) {
613
- return;
614
- }
615
- if (array === void 0 || array.length < this.outputIndices.lengthInElements) {
616
- array = create(this.outputIndices.lengthInElements);
617
- }
618
- array.set(this.outputIndices.view);
619
- }
620
- // from RunModelParams interface
621
- getOutputsLength() {
622
- return this.outputs.lengthInElements;
623
- }
624
- // from RunModelParams interface
625
- getOutputs() {
626
- return this.outputs.view;
627
- }
628
- // from RunModelParams interface
629
- getOutputsObject() {
630
- return void 0;
631
- }
632
- // from RunModelParams interface
633
- storeOutputs(array) {
634
- if (this.outputs.view === void 0) {
635
- return;
636
- }
637
- if (array.length > this.outputs.view.length) {
638
- this.outputs.view.set(array.subarray(0, this.outputs.view.length));
639
- } else {
640
- this.outputs.view.set(array);
641
- }
642
- }
643
- // from RunModelParams interface
644
- getConstants() {
645
- if (this.constantIndices.lengthInElements === 0) {
646
- return void 0;
647
- }
648
- return decodeConstants(this.constantIndices.view, this.constants.view);
649
- }
650
- // from RunModelParams interface
651
- getLookups() {
652
- if (this.lookupIndices.lengthInElements === 0) {
653
- return void 0;
654
- }
655
- return decodeLookups(this.lookupIndices.view, this.lookups.view);
656
- }
657
- // from RunModelParams interface
658
- getElapsedTime() {
659
- return this.extras.view[0];
660
- }
661
- // from RunModelParams interface
662
- storeElapsedTime(elapsed) {
663
- this.extras.view[0] = elapsed;
664
- }
665
- /**
666
- * Copy the outputs buffer to the given `Outputs` instance. This should be called
667
- * after the `runModel` call has completed so that the output values are copied from
668
- * the internal buffer to the `Outputs` instance that was passed to `runModel`.
669
- *
670
- * @param outputs The `Outputs` instance into which the output values will be copied.
671
- */
672
- finalizeOutputs(outputs) {
673
- if (this.outputs.view) {
674
- outputs.updateFromBuffer(this.outputs.view, outputs.seriesLength);
675
- }
676
- outputs.runTimeInMillis = this.getElapsedTime();
677
- }
678
- /**
679
- * Update this instance using the parameters that are passed to a `runModel` call.
680
- *
681
- * @param inputs The model input values (must be in the same order as in the spec file).
682
- * @param outputs The structure into which the model outputs will be stored.
683
- * @param options Additional options that influence the model run.
684
- */
685
- updateFromParams(inputs, outputs, options) {
686
- const inputsLengthInElements = inputs.length;
687
- const outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
688
- let outputIndicesLengthInElements;
689
- const outputVarSpecs = outputs.varSpecs;
690
- if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) {
691
- outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
692
- } else {
693
- outputIndicesLengthInElements = 0;
694
- }
695
- let constantsLengthInElements;
696
- let constantIndicesLengthInElements;
697
- if ((options == null ? void 0 : options.constants) !== void 0 && options.constants.length > 0) {
698
- for (const constantDef of options.constants) {
699
- resolveVarRef(this.listing, constantDef.varRef, "constant");
700
- }
701
- const encodedLengths = getEncodedConstantBufferLengths(options.constants);
702
- constantsLengthInElements = encodedLengths.constantsLength;
703
- constantIndicesLengthInElements = encodedLengths.constantIndicesLength;
704
- } else {
705
- constantsLengthInElements = 0;
706
- constantIndicesLengthInElements = 0;
707
- }
708
- let lookupsLengthInElements;
709
- let lookupIndicesLengthInElements;
710
- if ((options == null ? void 0 : options.lookups) !== void 0 && options.lookups.length > 0) {
711
- for (const lookupDef of options.lookups) {
712
- resolveVarRef(this.listing, lookupDef.varRef, "lookup");
713
- }
714
- const encodedLengths = getEncodedLookupBufferLengths(options.lookups);
715
- lookupsLengthInElements = encodedLengths.lookupsLength;
716
- lookupIndicesLengthInElements = encodedLengths.lookupIndicesLength;
717
- } else {
718
- lookupsLengthInElements = 0;
719
- lookupIndicesLengthInElements = 0;
720
- }
721
- let byteOffset = 0;
722
- function section(kind, lengthInElements) {
723
- const sectionOffsetInBytes = byteOffset;
724
- const bytesPerElement = kind === "float64" ? Float64Array.BYTES_PER_ELEMENT : Int32Array.BYTES_PER_ELEMENT;
725
- const requiredSectionLengthInBytes = Math.round(lengthInElements * bytesPerElement);
726
- const alignedSectionLengthInBytes = Math.ceil(requiredSectionLengthInBytes / 8) * 8;
727
- byteOffset += alignedSectionLengthInBytes;
728
- return sectionOffsetInBytes;
729
- }
730
- const headerOffsetInBytes = section("int32", headerLengthInElements);
731
- const extrasOffsetInBytes = section("float64", extrasLengthInElements);
732
- const inputsOffsetInBytes = section("float64", inputsLengthInElements);
733
- const outputsOffsetInBytes = section("float64", outputsLengthInElements);
734
- const outputIndicesOffsetInBytes = section("int32", outputIndicesLengthInElements);
735
- const constantsOffsetInBytes = section("float64", constantsLengthInElements);
736
- const constantIndicesOffsetInBytes = section("int32", constantIndicesLengthInElements);
737
- const lookupsOffsetInBytes = section("float64", lookupsLengthInElements);
738
- const lookupIndicesOffsetInBytes = section("int32", lookupIndicesLengthInElements);
739
- const requiredLengthInBytes = byteOffset;
740
- if (this.encoded === void 0 || this.encoded.byteLength < requiredLengthInBytes) {
741
- const totalLengthInBytes = Math.ceil(requiredLengthInBytes * 1.2);
742
- this.encoded = new ArrayBuffer(totalLengthInBytes);
743
- this.header.update(this.encoded, headerOffsetInBytes, headerLengthInElements);
744
- }
745
- const headerView = this.header.view;
746
- let headerIndex = 0;
747
- headerView[headerIndex++] = extrasOffsetInBytes;
748
- headerView[headerIndex++] = extrasLengthInElements;
749
- headerView[headerIndex++] = inputsOffsetInBytes;
750
- headerView[headerIndex++] = inputsLengthInElements;
751
- headerView[headerIndex++] = outputsOffsetInBytes;
752
- headerView[headerIndex++] = outputsLengthInElements;
753
- headerView[headerIndex++] = outputIndicesOffsetInBytes;
754
- headerView[headerIndex++] = outputIndicesLengthInElements;
755
- headerView[headerIndex++] = constantsOffsetInBytes;
756
- headerView[headerIndex++] = constantsLengthInElements;
757
- headerView[headerIndex++] = constantIndicesOffsetInBytes;
758
- headerView[headerIndex++] = constantIndicesLengthInElements;
759
- headerView[headerIndex++] = lookupsOffsetInBytes;
760
- headerView[headerIndex++] = lookupsLengthInElements;
761
- headerView[headerIndex++] = lookupIndicesOffsetInBytes;
762
- headerView[headerIndex++] = lookupIndicesLengthInElements;
763
- this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
764
- this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements);
765
- this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
766
- this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
767
- this.constants.update(this.encoded, constantsOffsetInBytes, constantsLengthInElements);
768
- this.constantIndices.update(this.encoded, constantIndicesOffsetInBytes, constantIndicesLengthInElements);
769
- this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
770
- this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
771
- const inputsView = this.inputs.view;
772
- for (let i = 0; i < inputs.length; i++) {
773
- const input = inputs[i];
774
- if (typeof input === "number") {
775
- inputsView[i] = input;
776
- } else {
777
- inputsView[i] = input.get();
778
- }
779
- }
780
- if (this.outputIndices.view) {
781
- encodeVarIndices(outputVarSpecs, this.outputIndices.view);
782
- }
783
- if (constantIndicesLengthInElements > 0) {
784
- encodeConstants(options.constants, this.constantIndices.view, this.constants.view);
785
- }
786
- if (lookupIndicesLengthInElements > 0) {
787
- encodeLookups(options.lookups, this.lookupIndices.view, this.lookups.view);
788
- }
789
- }
790
- /**
791
- * Update this instance using the values contained in the encoded buffer from another
792
- * `BufferedRunModelParams` instance.
793
- *
794
- * @param buffer An encoded buffer returned by `getEncodedBuffer`.
795
- */
796
- updateFromEncodedBuffer(buffer) {
797
- const headerLengthInBytes = headerLengthInElements * Int32Array.BYTES_PER_ELEMENT;
798
- if (buffer.byteLength < headerLengthInBytes) {
799
- throw new Error("Buffer must be long enough to contain header section");
800
- }
801
- this.encoded = buffer;
802
- const headerOffsetInBytes = 0;
803
- this.header.update(this.encoded, headerOffsetInBytes, headerLengthInElements);
804
- const headerView = this.header.view;
805
- let headerIndex = 0;
806
- const extrasOffsetInBytes = headerView[headerIndex++];
807
- const extrasLengthInElements2 = headerView[headerIndex++];
808
- const inputsOffsetInBytes = headerView[headerIndex++];
809
- const inputsLengthInElements = headerView[headerIndex++];
810
- const outputsOffsetInBytes = headerView[headerIndex++];
811
- const outputsLengthInElements = headerView[headerIndex++];
812
- const outputIndicesOffsetInBytes = headerView[headerIndex++];
813
- const outputIndicesLengthInElements = headerView[headerIndex++];
814
- const constantsOffsetInBytes = headerView[headerIndex++];
815
- const constantsLengthInElements = headerView[headerIndex++];
816
- const constantIndicesOffsetInBytes = headerView[headerIndex++];
817
- const constantIndicesLengthInElements = headerView[headerIndex++];
818
- const lookupsOffsetInBytes = headerView[headerIndex++];
819
- const lookupsLengthInElements = headerView[headerIndex++];
820
- const lookupIndicesOffsetInBytes = headerView[headerIndex++];
821
- const lookupIndicesLengthInElements = headerView[headerIndex++];
822
- const extrasLengthInBytes = extrasLengthInElements2 * Float64Array.BYTES_PER_ELEMENT;
823
- const inputsLengthInBytes = inputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
824
- const outputsLengthInBytes = outputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
825
- const outputIndicesLengthInBytes = outputIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
826
- const constantsLengthInBytes = constantsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
827
- const constantIndicesLengthInBytes = constantIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
828
- const lookupsLengthInBytes = lookupsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
829
- const lookupIndicesLengthInBytes = lookupIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
830
- const requiredLengthInBytes = headerLengthInBytes + extrasLengthInBytes + inputsLengthInBytes + outputsLengthInBytes + outputIndicesLengthInBytes + constantsLengthInBytes + constantIndicesLengthInBytes + lookupsLengthInBytes + lookupIndicesLengthInBytes;
831
- if (buffer.byteLength < requiredLengthInBytes) {
832
- throw new Error("Buffer must be long enough to contain sections declared in header");
833
- }
834
- this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements2);
835
- this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
836
- this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
837
- this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
838
- this.constants.update(this.encoded, constantsOffsetInBytes, constantsLengthInElements);
839
- this.constantIndices.update(this.encoded, constantIndicesOffsetInBytes, constantIndicesLengthInElements);
840
- this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
841
- this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
842
- }
626
+ /**
627
+ * @param listing The model listing that is used to locate a variable that is referenced by
628
+ * name or identifier. If undefined, variables cannot be referenced by name or identifier,
629
+ * and can only be referenced using a valid `VarSpec`.
630
+ */
631
+ constructor(listing) {
632
+ this.listing = listing;
633
+ this.header = new Int32Section();
634
+ this.extras = new Float64Section();
635
+ this.inputs = new Float64Section();
636
+ this.outputs = new Float64Section();
637
+ this.outputIndices = new Int32Section();
638
+ this.constants = new Float64Section();
639
+ this.constantIndices = new Int32Section();
640
+ this.lookups = new Float64Section();
641
+ this.lookupIndices = new Int32Section();
642
+ }
643
+ /**
644
+ * Return the encoded buffer from this instance, which can be passed to `updateFromEncodedBuffer`.
645
+ */
646
+ getEncodedBuffer() {
647
+ return this.encoded;
648
+ }
649
+ getInputs() {
650
+ return this.inputs.view;
651
+ }
652
+ copyInputs(array, create) {
653
+ if (this.inputs.lengthInElements === 0) return;
654
+ if (array === void 0 || array.length < this.inputs.lengthInElements) array = create(this.inputs.lengthInElements);
655
+ array.set(this.inputs.view);
656
+ }
657
+ getOutputIndicesLength() {
658
+ return this.outputIndices.lengthInElements;
659
+ }
660
+ getOutputIndices() {
661
+ return this.outputIndices.view;
662
+ }
663
+ copyOutputIndices(array, create) {
664
+ if (this.outputIndices.lengthInElements === 0) return;
665
+ if (array === void 0 || array.length < this.outputIndices.lengthInElements) array = create(this.outputIndices.lengthInElements);
666
+ array.set(this.outputIndices.view);
667
+ }
668
+ getOutputsLength() {
669
+ return this.outputs.lengthInElements;
670
+ }
671
+ getOutputs() {
672
+ return this.outputs.view;
673
+ }
674
+ getOutputsObject() {}
675
+ storeOutputs(array) {
676
+ if (this.outputs.view === void 0) return;
677
+ if (array.length > this.outputs.view.length) this.outputs.view.set(array.subarray(0, this.outputs.view.length));
678
+ else this.outputs.view.set(array);
679
+ }
680
+ getConstants() {
681
+ if (this.constantIndices.lengthInElements === 0) return;
682
+ return decodeConstants(this.constantIndices.view, this.constants.view);
683
+ }
684
+ getLookups() {
685
+ if (this.lookupIndices.lengthInElements === 0) return;
686
+ return decodeLookups(this.lookupIndices.view, this.lookups.view);
687
+ }
688
+ getElapsedTime() {
689
+ return this.extras.view[0];
690
+ }
691
+ storeElapsedTime(elapsed) {
692
+ this.extras.view[0] = elapsed;
693
+ }
694
+ /**
695
+ * Copy the outputs buffer to the given `Outputs` instance. This should be called
696
+ * after the `runModel` call has completed so that the output values are copied from
697
+ * the internal buffer to the `Outputs` instance that was passed to `runModel`.
698
+ *
699
+ * @param outputs The `Outputs` instance into which the output values will be copied.
700
+ */
701
+ finalizeOutputs(outputs) {
702
+ if (this.outputs.view) outputs.updateFromBuffer(this.outputs.view, outputs.seriesLength);
703
+ outputs.runTimeInMillis = this.getElapsedTime();
704
+ }
705
+ /**
706
+ * Update this instance using the parameters that are passed to a `runModel` call.
707
+ *
708
+ * @param inputs The model input values (must be in the same order as in the spec file).
709
+ * @param outputs The structure into which the model outputs will be stored.
710
+ * @param options Additional options that influence the model run.
711
+ */
712
+ updateFromParams(inputs, outputs, options) {
713
+ const inputsLengthInElements = inputs.length;
714
+ const outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
715
+ let outputIndicesLengthInElements;
716
+ const outputVarSpecs = outputs.varSpecs;
717
+ if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
718
+ else outputIndicesLengthInElements = 0;
719
+ let constantsLengthInElements;
720
+ let constantIndicesLengthInElements;
721
+ if (options?.constants !== void 0 && options.constants.length > 0) {
722
+ for (const constantDef of options.constants) resolveVarRef(this.listing, constantDef.varRef, "constant");
723
+ const encodedLengths = getEncodedConstantBufferLengths(options.constants);
724
+ constantsLengthInElements = encodedLengths.constantsLength;
725
+ constantIndicesLengthInElements = encodedLengths.constantIndicesLength;
726
+ } else {
727
+ constantsLengthInElements = 0;
728
+ constantIndicesLengthInElements = 0;
729
+ }
730
+ let lookupsLengthInElements;
731
+ let lookupIndicesLengthInElements;
732
+ if (options?.lookups !== void 0 && options.lookups.length > 0) {
733
+ for (const lookupDef of options.lookups) resolveVarRef(this.listing, lookupDef.varRef, "lookup");
734
+ const encodedLengths = getEncodedLookupBufferLengths(options.lookups);
735
+ lookupsLengthInElements = encodedLengths.lookupsLength;
736
+ lookupIndicesLengthInElements = encodedLengths.lookupIndicesLength;
737
+ } else {
738
+ lookupsLengthInElements = 0;
739
+ lookupIndicesLengthInElements = 0;
740
+ }
741
+ let byteOffset = 0;
742
+ function section(kind, lengthInElements) {
743
+ const sectionOffsetInBytes = byteOffset;
744
+ const bytesPerElement = kind === "float64" ? Float64Array.BYTES_PER_ELEMENT : Int32Array.BYTES_PER_ELEMENT;
745
+ const requiredSectionLengthInBytes = Math.round(lengthInElements * bytesPerElement);
746
+ const alignedSectionLengthInBytes = Math.ceil(requiredSectionLengthInBytes / 8) * 8;
747
+ byteOffset += alignedSectionLengthInBytes;
748
+ return sectionOffsetInBytes;
749
+ }
750
+ const headerOffsetInBytes = section("int32", headerLengthInElements);
751
+ const extrasOffsetInBytes = section("float64", extrasLengthInElements);
752
+ const inputsOffsetInBytes = section("float64", inputsLengthInElements);
753
+ const outputsOffsetInBytes = section("float64", outputsLengthInElements);
754
+ const outputIndicesOffsetInBytes = section("int32", outputIndicesLengthInElements);
755
+ const constantsOffsetInBytes = section("float64", constantsLengthInElements);
756
+ const constantIndicesOffsetInBytes = section("int32", constantIndicesLengthInElements);
757
+ const lookupsOffsetInBytes = section("float64", lookupsLengthInElements);
758
+ const lookupIndicesOffsetInBytes = section("int32", lookupIndicesLengthInElements);
759
+ const requiredLengthInBytes = byteOffset;
760
+ if (this.encoded === void 0 || this.encoded.byteLength < requiredLengthInBytes) {
761
+ const totalLengthInBytes = Math.ceil(requiredLengthInBytes * 1.2);
762
+ this.encoded = new ArrayBuffer(totalLengthInBytes);
763
+ this.header.update(this.encoded, headerOffsetInBytes, headerLengthInElements);
764
+ }
765
+ const headerView = this.header.view;
766
+ let headerIndex = 0;
767
+ headerView[headerIndex++] = extrasOffsetInBytes;
768
+ headerView[headerIndex++] = extrasLengthInElements;
769
+ headerView[headerIndex++] = inputsOffsetInBytes;
770
+ headerView[headerIndex++] = inputsLengthInElements;
771
+ headerView[headerIndex++] = outputsOffsetInBytes;
772
+ headerView[headerIndex++] = outputsLengthInElements;
773
+ headerView[headerIndex++] = outputIndicesOffsetInBytes;
774
+ headerView[headerIndex++] = outputIndicesLengthInElements;
775
+ headerView[headerIndex++] = constantsOffsetInBytes;
776
+ headerView[headerIndex++] = constantsLengthInElements;
777
+ headerView[headerIndex++] = constantIndicesOffsetInBytes;
778
+ headerView[headerIndex++] = constantIndicesLengthInElements;
779
+ headerView[headerIndex++] = lookupsOffsetInBytes;
780
+ headerView[headerIndex++] = lookupsLengthInElements;
781
+ headerView[headerIndex++] = lookupIndicesOffsetInBytes;
782
+ headerView[headerIndex++] = lookupIndicesLengthInElements;
783
+ this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
784
+ this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements);
785
+ this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
786
+ this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
787
+ this.constants.update(this.encoded, constantsOffsetInBytes, constantsLengthInElements);
788
+ this.constantIndices.update(this.encoded, constantIndicesOffsetInBytes, constantIndicesLengthInElements);
789
+ this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
790
+ this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
791
+ const inputsView = this.inputs.view;
792
+ for (let i = 0; i < inputs.length; i++) {
793
+ const input = inputs[i];
794
+ if (typeof input === "number") inputsView[i] = input;
795
+ else inputsView[i] = input.get();
796
+ }
797
+ if (this.outputIndices.view) encodeVarIndices(outputVarSpecs, this.outputIndices.view);
798
+ if (constantIndicesLengthInElements > 0) encodeConstants(options.constants, this.constantIndices.view, this.constants.view);
799
+ if (lookupIndicesLengthInElements > 0) encodeLookups(options.lookups, this.lookupIndices.view, this.lookups.view);
800
+ }
801
+ /**
802
+ * Update this instance using the values contained in the encoded buffer from another
803
+ * `BufferedRunModelParams` instance.
804
+ *
805
+ * @param buffer An encoded buffer returned by `getEncodedBuffer`.
806
+ */
807
+ updateFromEncodedBuffer(buffer) {
808
+ const headerLengthInBytes = headerLengthInElements * Int32Array.BYTES_PER_ELEMENT;
809
+ if (buffer.byteLength < headerLengthInBytes) throw new Error("Buffer must be long enough to contain header section");
810
+ this.encoded = buffer;
811
+ this.header.update(this.encoded, 0, headerLengthInElements);
812
+ const headerView = this.header.view;
813
+ let headerIndex = 0;
814
+ const extrasOffsetInBytes = headerView[headerIndex++];
815
+ const extrasLengthInElements = headerView[headerIndex++];
816
+ const inputsOffsetInBytes = headerView[headerIndex++];
817
+ const inputsLengthInElements = headerView[headerIndex++];
818
+ const outputsOffsetInBytes = headerView[headerIndex++];
819
+ const outputsLengthInElements = headerView[headerIndex++];
820
+ const outputIndicesOffsetInBytes = headerView[headerIndex++];
821
+ const outputIndicesLengthInElements = headerView[headerIndex++];
822
+ const constantsOffsetInBytes = headerView[headerIndex++];
823
+ const constantsLengthInElements = headerView[headerIndex++];
824
+ const constantIndicesOffsetInBytes = headerView[headerIndex++];
825
+ const constantIndicesLengthInElements = headerView[headerIndex++];
826
+ const lookupsOffsetInBytes = headerView[headerIndex++];
827
+ const lookupsLengthInElements = headerView[headerIndex++];
828
+ const lookupIndicesOffsetInBytes = headerView[headerIndex++];
829
+ const lookupIndicesLengthInElements = headerView[headerIndex++];
830
+ const extrasLengthInBytes = extrasLengthInElements * Float64Array.BYTES_PER_ELEMENT;
831
+ const inputsLengthInBytes = inputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
832
+ const outputsLengthInBytes = outputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
833
+ const outputIndicesLengthInBytes = outputIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
834
+ const constantsLengthInBytes = constantsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
835
+ const constantIndicesLengthInBytes = constantIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
836
+ const lookupsLengthInBytes = lookupsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
837
+ const lookupIndicesLengthInBytes = lookupIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
838
+ const requiredLengthInBytes = headerLengthInBytes + extrasLengthInBytes + inputsLengthInBytes + outputsLengthInBytes + outputIndicesLengthInBytes + constantsLengthInBytes + constantIndicesLengthInBytes + lookupsLengthInBytes + lookupIndicesLengthInBytes;
839
+ if (buffer.byteLength < requiredLengthInBytes) throw new Error("Buffer must be long enough to contain sections declared in header");
840
+ this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements);
841
+ this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
842
+ this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
843
+ this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
844
+ this.constants.update(this.encoded, constantsOffsetInBytes, constantsLengthInElements);
845
+ this.constantIndices.update(this.encoded, constantIndicesOffsetInBytes, constantIndicesLengthInElements);
846
+ this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
847
+ this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
848
+ }
843
849
  };
844
-
845
- // src/runnable-model/referenced-run-model-params.ts
850
+ //#endregion
851
+ //#region src/runnable-model/referenced-run-model-params.ts
852
+ /**
853
+ * An implementation of `RunModelParams` that keeps references to the `inputs` and
854
+ * `outputs` parameters that are passed to the `runModel` function. This implementation
855
+ * is best used with a synchronous `ModelRunner`.
856
+ *
857
+ * @hidden This is not yet exposed in the public API; it is currently only used by
858
+ * the implementations of the `RunnableModel` interface.
859
+ */
846
860
  var ReferencedRunModelParams = class {
847
- /**
848
- * @param listing The model listing that is used to locate a variable that is referenced by
849
- * name or identifier. If undefined, variables cannot be referenced by name or identifier,
850
- * and can only be referenced using a valid `VarSpec`.
851
- */
852
- constructor(listing) {
853
- this.listing = listing;
854
- this.outputsLengthInElements = 0;
855
- this.outputIndicesLengthInElements = 0;
856
- }
857
- // from RunModelParams interface
858
- getInputs() {
859
- return void 0;
860
- }
861
- // from RunModelParams interface
862
- copyInputs(array, create) {
863
- const inputsLengthInElements = this.inputs.length;
864
- if (array === void 0 || array.length < inputsLengthInElements) {
865
- array = create(inputsLengthInElements);
866
- }
867
- for (let i = 0; i < this.inputs.length; i++) {
868
- const input = this.inputs[i];
869
- if (typeof input === "number") {
870
- array[i] = input;
871
- } else {
872
- array[i] = input.get();
873
- }
874
- }
875
- }
876
- // from RunModelParams interface
877
- getOutputIndicesLength() {
878
- return this.outputIndicesLengthInElements;
879
- }
880
- // from RunModelParams interface
881
- getOutputIndices() {
882
- return void 0;
883
- }
884
- // from RunModelParams interface
885
- copyOutputIndices(array, create) {
886
- if (this.outputIndicesLengthInElements === 0) {
887
- return;
888
- }
889
- if (array === void 0 || array.length < this.outputIndicesLengthInElements) {
890
- array = create(this.outputIndicesLengthInElements);
891
- }
892
- encodeVarIndices(this.outputs.varSpecs, array);
893
- }
894
- // from RunModelParams interface
895
- getOutputsLength() {
896
- return this.outputsLengthInElements;
897
- }
898
- // from RunModelParams interface
899
- getOutputs() {
900
- return void 0;
901
- }
902
- // from RunModelParams interface
903
- getOutputsObject() {
904
- return this.outputs;
905
- }
906
- // from RunModelParams interface
907
- storeOutputs(array) {
908
- if (this.outputs) {
909
- const result = this.outputs.updateFromBuffer(array, this.outputs.seriesLength);
910
- if (result.isErr()) {
911
- throw new Error(`Failed to store outputs: ${result.error}`);
912
- }
913
- }
914
- }
915
- // from RunModelParams interface
916
- getConstants() {
917
- if (this.constants !== void 0 && this.constants.length > 0) {
918
- return this.constants;
919
- } else {
920
- return void 0;
921
- }
922
- }
923
- // from RunModelParams interface
924
- getLookups() {
925
- if (this.lookups !== void 0 && this.lookups.length > 0) {
926
- return this.lookups;
927
- } else {
928
- return void 0;
929
- }
930
- }
931
- // from RunModelParams interface
932
- getElapsedTime() {
933
- var _a;
934
- return (_a = this.outputs) == null ? void 0 : _a.runTimeInMillis;
935
- }
936
- // from RunModelParams interface
937
- storeElapsedTime(elapsed) {
938
- if (this.outputs) {
939
- this.outputs.runTimeInMillis = elapsed;
940
- }
941
- }
942
- /**
943
- * Update this instance using the parameters that are passed to a `runModel` call.
944
- *
945
- * @param inputs The model input values (must be in the same order as in the spec file).
946
- * @param outputs The structure into which the model outputs will be stored.
947
- * @param options Additional options that influence the model run.
948
- */
949
- updateFromParams(inputs, outputs, options) {
950
- this.inputs = inputs;
951
- this.outputs = outputs;
952
- this.outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
953
- this.constants = options == null ? void 0 : options.constants;
954
- this.lookups = options == null ? void 0 : options.lookups;
955
- if (this.constants) {
956
- for (const constantDef of this.constants) {
957
- resolveVarRef(this.listing, constantDef.varRef, "constant");
958
- }
959
- }
960
- if (this.lookups) {
961
- for (const lookupDef of this.lookups) {
962
- resolveVarRef(this.listing, lookupDef.varRef, "lookup");
963
- }
964
- }
965
- const outputVarSpecs = outputs.varSpecs;
966
- if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) {
967
- this.outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
968
- } else {
969
- this.outputIndicesLengthInElements = 0;
970
- }
971
- }
861
+ /**
862
+ * @param listing The model listing that is used to locate a variable that is referenced by
863
+ * name or identifier. If undefined, variables cannot be referenced by name or identifier,
864
+ * and can only be referenced using a valid `VarSpec`.
865
+ */
866
+ constructor(listing) {
867
+ this.listing = listing;
868
+ this.outputsLengthInElements = 0;
869
+ this.outputIndicesLengthInElements = 0;
870
+ }
871
+ getInputs() {}
872
+ copyInputs(array, create) {
873
+ const inputsLengthInElements = this.inputs.length;
874
+ if (array === void 0 || array.length < inputsLengthInElements) array = create(inputsLengthInElements);
875
+ for (let i = 0; i < this.inputs.length; i++) {
876
+ const input = this.inputs[i];
877
+ if (typeof input === "number") array[i] = input;
878
+ else array[i] = input.get();
879
+ }
880
+ }
881
+ getOutputIndicesLength() {
882
+ return this.outputIndicesLengthInElements;
883
+ }
884
+ getOutputIndices() {}
885
+ copyOutputIndices(array, create) {
886
+ if (this.outputIndicesLengthInElements === 0) return;
887
+ if (array === void 0 || array.length < this.outputIndicesLengthInElements) array = create(this.outputIndicesLengthInElements);
888
+ encodeVarIndices(this.outputs.varSpecs, array);
889
+ }
890
+ getOutputsLength() {
891
+ return this.outputsLengthInElements;
892
+ }
893
+ getOutputs() {}
894
+ getOutputsObject() {
895
+ return this.outputs;
896
+ }
897
+ storeOutputs(array) {
898
+ if (this.outputs) {
899
+ const result = this.outputs.updateFromBuffer(array, this.outputs.seriesLength);
900
+ if (result.isErr()) throw new Error(`Failed to store outputs: ${result.error}`);
901
+ }
902
+ }
903
+ getConstants() {
904
+ if (this.constants !== void 0 && this.constants.length > 0) return this.constants;
905
+ else return;
906
+ }
907
+ getLookups() {
908
+ if (this.lookups !== void 0 && this.lookups.length > 0) return this.lookups;
909
+ else return;
910
+ }
911
+ getElapsedTime() {
912
+ return this.outputs?.runTimeInMillis;
913
+ }
914
+ storeElapsedTime(elapsed) {
915
+ if (this.outputs) this.outputs.runTimeInMillis = elapsed;
916
+ }
917
+ /**
918
+ * Update this instance using the parameters that are passed to a `runModel` call.
919
+ *
920
+ * @param inputs The model input values (must be in the same order as in the spec file).
921
+ * @param outputs The structure into which the model outputs will be stored.
922
+ * @param options Additional options that influence the model run.
923
+ */
924
+ updateFromParams(inputs, outputs, options) {
925
+ this.inputs = inputs;
926
+ this.outputs = outputs;
927
+ this.outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
928
+ this.constants = options?.constants;
929
+ this.lookups = options?.lookups;
930
+ if (this.constants) for (const constantDef of this.constants) resolveVarRef(this.listing, constantDef.varRef, "constant");
931
+ if (this.lookups) for (const lookupDef of this.lookups) resolveVarRef(this.listing, lookupDef.varRef, "lookup");
932
+ const outputVarSpecs = outputs.varSpecs;
933
+ if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) this.outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
934
+ else this.outputIndicesLengthInElements = 0;
935
+ }
972
936
  };
973
-
974
- // src/js-model/js-model-constants.ts
975
- var _NA_ = -Number.MAX_VALUE;
976
-
977
- // src/js-model/js-model-lookup.ts
937
+ //#endregion
938
+ //#region src/js-model/js-model-constants.ts
939
+ const _NA_ = -Number.MAX_VALUE;
940
+ //#endregion
941
+ //#region src/js-model/js-model-lookup.ts
942
+ /**
943
+ * @hidden This is not yet part of the public API; for internal use only.
944
+ */
978
945
  var JsModelLookup = class {
979
- /**
980
- * @param size The number of (x,y) pairs in the lookup.
981
- * @param data The lookup data, as (x,y) pairs. The length of the array must be
982
- * >= 2*n. Note that the data will be stored by reference, so if there is a chance
983
- * that the array will be reused or modified by other code, be sure to pass in a
984
- * copy of the array.
985
- */
986
- constructor(size, data) {
987
- if (data && data.length < size * 2) {
988
- throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
989
- }
990
- this.originalData = data;
991
- this.originalSize = size;
992
- this.dynamicData = void 0;
993
- this.dynamicSize = 0;
994
- this.activeData = this.originalData;
995
- this.activeSize = this.originalSize;
996
- this.lastInput = Number.MAX_VALUE;
997
- this.lastHitIndex = 0;
998
- }
999
- /**
1000
- * Set new data for this lookup instance, or restore the original data.
1001
- *
1002
- * If `data` is undefined, the original data that was supplied to the constructor will
1003
- * be restored as the "active" data. Otherwise, `data` will be copied to an internal
1004
- * data buffer, which will be the "active" data. If `size` is greater than the size
1005
- * passed to previous calls, the internal data buffer will be grown as needed.
1006
- *
1007
- * @param size The number of (x,y) pairs in the lookup.
1008
- * @param data The lookup data, as (x,y) pairs. The length of the array must be
1009
- * >= 2*n. Note that the data will be copied into an internal data buffer, so it
1010
- * is not necessary to defensively copy data before calling this method.
1011
- */
1012
- setData(size, data) {
1013
- if (data) {
1014
- if (data.length < size * 2) {
1015
- throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
1016
- }
1017
- const dataLengthInElems = size * 2;
1018
- if (this.dynamicData === void 0 || dataLengthInElems > this.dynamicData.length) {
1019
- this.dynamicData = new Float64Array(dataLengthInElems);
1020
- }
1021
- this.dynamicSize = size;
1022
- if (size > 0) {
1023
- const subarray = data.subarray(0, dataLengthInElems);
1024
- this.dynamicData.set(subarray);
1025
- }
1026
- this.activeData = this.dynamicData;
1027
- this.activeSize = this.dynamicSize;
1028
- } else {
1029
- this.activeData = this.originalData;
1030
- this.activeSize = this.originalSize;
1031
- }
1032
- this.invertedData = void 0;
1033
- this.lastInput = Number.MAX_VALUE;
1034
- this.lastHitIndex = 0;
1035
- }
1036
- getValueForX(x, mode) {
1037
- return this.getValue(x, false, mode);
1038
- }
1039
- getValueForY(y) {
1040
- if (this.invertedData === void 0) {
1041
- const numValues = this.activeSize * 2;
1042
- const normalData = this.activeData;
1043
- const invertedData = Array(numValues);
1044
- for (let i = 0; i < numValues; i += 2) {
1045
- invertedData[i] = normalData[i + 1];
1046
- invertedData[i + 1] = normalData[i];
1047
- }
1048
- this.invertedData = invertedData;
1049
- }
1050
- return this.getValue(y, true, "interpolate");
1051
- }
1052
- /**
1053
- * Interpolate the y value from the array of (x,y) pairs.
1054
- * NOTE: The x values are assumed to be monotonically increasing.
1055
- */
1056
- getValue(input, useInvertedData, mode) {
1057
- if (this.activeSize === 0) {
1058
- return _NA_;
1059
- }
1060
- const data = useInvertedData ? this.invertedData : this.activeData;
1061
- const max = this.activeSize * 2;
1062
- const useCachedValues = !useInvertedData;
1063
- let startIndex;
1064
- if (useCachedValues && input >= this.lastInput) {
1065
- startIndex = this.lastHitIndex;
1066
- } else {
1067
- startIndex = 0;
1068
- }
1069
- for (let xi = startIndex; xi < max; xi += 2) {
1070
- const x = data[xi];
1071
- if (x >= input) {
1072
- if (useCachedValues) {
1073
- this.lastInput = input;
1074
- this.lastHitIndex = xi;
1075
- }
1076
- if (xi === 0 || x === input) {
1077
- return data[xi + 1];
1078
- }
1079
- switch (mode) {
1080
- default:
1081
- case "interpolate": {
1082
- const last_x = data[xi - 2];
1083
- const last_y = data[xi - 1];
1084
- const y = data[xi + 1];
1085
- const dx = x - last_x;
1086
- const dy = y - last_y;
1087
- return last_y + dy / dx * (input - last_x);
1088
- }
1089
- case "forward":
1090
- return data[xi + 1];
1091
- case "backward":
1092
- return data[xi - 1];
1093
- }
1094
- }
1095
- }
1096
- if (useCachedValues) {
1097
- this.lastInput = input;
1098
- this.lastHitIndex = max;
1099
- }
1100
- return data[max - 1];
1101
- }
1102
- /**
1103
- * Return the most appropriate y value from the array of (x,y) pairs when
1104
- * this instance is used to provide inputs for the `GAME` function.
1105
- *
1106
- * NOTE: The x values are assumed to be monotonically increasing.
1107
- *
1108
- * This method is similar to `getValueForX` in concept, except that this one
1109
- * returns the provided `defaultValue` if the `time` parameter is earlier than
1110
- * the first data point in the lookup. Also, this method always uses the
1111
- * `backward` interpolation mode, meaning that it holds the "current" value
1112
- * constant instead of interpolating.
1113
- *
1114
- * @param time The time that is used to select the data point that has an
1115
- * `x` value less than or equal to the provided time.
1116
- * @param defaultValue The value that is returned if this lookup is empty (has
1117
- * no points) or if the provided time is earlier than the first data point.
1118
- */
1119
- getValueForGameTime(time, defaultValue) {
1120
- if (this.activeSize <= 0) {
1121
- return defaultValue;
1122
- }
1123
- const x0 = this.activeData[0];
1124
- if (time < x0) {
1125
- return defaultValue;
1126
- }
1127
- return this.getValue(time, false, "backward");
1128
- }
1129
- /**
1130
- * Interpolate the y value from the array of (x,y) pairs.
1131
- * NOTE: The x values are assumed to be monotonically increasing.
1132
- *
1133
- * This method is similar to `getValue` in concept, but Vensim produces results for
1134
- * the `GET DATA BETWEEN TIMES` function that differ in unexpected ways from normal
1135
- * lookup behavior, so we implement it as a separate method here.
1136
- */
1137
- getValueBetweenTimes(input, mode) {
1138
- if (this.activeSize === 0) {
1139
- return _NA_;
1140
- }
1141
- const data = this.activeData;
1142
- const max = this.activeSize * 2;
1143
- switch (mode) {
1144
- case "forward": {
1145
- input = Math.floor(input);
1146
- for (let xi = 0; xi < max; xi += 2) {
1147
- const x = data[xi];
1148
- if (x >= input) {
1149
- return data[xi + 1];
1150
- }
1151
- }
1152
- return data[max - 1];
1153
- }
1154
- case "backward": {
1155
- input = Math.floor(input);
1156
- for (let xi = 2; xi < max; xi += 2) {
1157
- const x = data[xi];
1158
- if (x >= input) {
1159
- return data[xi - 1];
1160
- }
1161
- }
1162
- if (max >= 4) {
1163
- return data[max - 3];
1164
- } else {
1165
- return data[1];
1166
- }
1167
- }
1168
- case "interpolate":
1169
- default: {
1170
- if (input - Math.floor(input) > 0) {
1171
- let msg = `GET DATA BETWEEN TIMES was called with an input value (${input}) that has a fractional part. `;
1172
- msg += "When mode is 0 (interpolate) and the input value is not a whole number, Vensim produces unexpected ";
1173
- msg += "results that may differ from those produced by SDEverywhere.";
1174
- throw new Error(msg);
1175
- }
1176
- for (let xi = 2; xi < max; xi += 2) {
1177
- const x = data[xi];
1178
- if (x >= input) {
1179
- const last_x = data[xi - 2];
1180
- const last_y = data[xi - 1];
1181
- const y = data[xi + 1];
1182
- const dx = x - last_x;
1183
- const dy = y - last_y;
1184
- return last_y + dy / dx * (input - last_x);
1185
- }
1186
- }
1187
- return data[max - 1];
1188
- }
1189
- }
1190
- }
946
+ /**
947
+ * @param size The number of (x,y) pairs in the lookup.
948
+ * @param data The lookup data, as (x,y) pairs. The length of the array must be
949
+ * >= 2*n. Note that the data will be stored by reference, so if there is a chance
950
+ * that the array will be reused or modified by other code, be sure to pass in a
951
+ * copy of the array.
952
+ */
953
+ constructor(size, data) {
954
+ if (data && data.length < size * 2) throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
955
+ this.originalData = data;
956
+ this.originalSize = size;
957
+ this.dynamicData = void 0;
958
+ this.dynamicSize = 0;
959
+ this.activeData = this.originalData;
960
+ this.activeSize = this.originalSize;
961
+ this.lastInput = Number.MAX_VALUE;
962
+ this.lastHitIndex = 0;
963
+ }
964
+ /**
965
+ * Set new data for this lookup instance, or restore the original data.
966
+ *
967
+ * If `data` is undefined, the original data that was supplied to the constructor will
968
+ * be restored as the "active" data. Otherwise, `data` will be copied to an internal
969
+ * data buffer, which will be the "active" data. If `size` is greater than the size
970
+ * passed to previous calls, the internal data buffer will be grown as needed.
971
+ *
972
+ * @param size The number of (x,y) pairs in the lookup.
973
+ * @param data The lookup data, as (x,y) pairs. The length of the array must be
974
+ * >= 2*n. Note that the data will be copied into an internal data buffer, so it
975
+ * is not necessary to defensively copy data before calling this method.
976
+ */
977
+ setData(size, data) {
978
+ if (data) {
979
+ if (data.length < size * 2) throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
980
+ const dataLengthInElems = size * 2;
981
+ if (this.dynamicData === void 0 || dataLengthInElems > this.dynamicData.length) this.dynamicData = new Float64Array(dataLengthInElems);
982
+ this.dynamicSize = size;
983
+ if (size > 0) {
984
+ const subarray = data.subarray(0, dataLengthInElems);
985
+ this.dynamicData.set(subarray);
986
+ }
987
+ this.activeData = this.dynamicData;
988
+ this.activeSize = this.dynamicSize;
989
+ } else {
990
+ this.activeData = this.originalData;
991
+ this.activeSize = this.originalSize;
992
+ }
993
+ this.invertedData = void 0;
994
+ this.lastInput = Number.MAX_VALUE;
995
+ this.lastHitIndex = 0;
996
+ }
997
+ getValueForX(x, mode) {
998
+ return this.getValue(x, false, mode);
999
+ }
1000
+ getValueForY(y) {
1001
+ if (this.invertedData === void 0) {
1002
+ const numValues = this.activeSize * 2;
1003
+ const normalData = this.activeData;
1004
+ const invertedData = Array(numValues);
1005
+ for (let i = 0; i < numValues; i += 2) {
1006
+ invertedData[i] = normalData[i + 1];
1007
+ invertedData[i + 1] = normalData[i];
1008
+ }
1009
+ this.invertedData = invertedData;
1010
+ }
1011
+ return this.getValue(y, true, "interpolate");
1012
+ }
1013
+ /**
1014
+ * Interpolate the y value from the array of (x,y) pairs.
1015
+ * NOTE: The x values are assumed to be monotonically increasing.
1016
+ */
1017
+ getValue(input, useInvertedData, mode) {
1018
+ if (this.activeSize === 0) return _NA_;
1019
+ const data = useInvertedData ? this.invertedData : this.activeData;
1020
+ const max = this.activeSize * 2;
1021
+ const useCachedValues = !useInvertedData;
1022
+ let startIndex;
1023
+ if (useCachedValues && input >= this.lastInput) startIndex = this.lastHitIndex;
1024
+ else startIndex = 0;
1025
+ for (let xi = startIndex; xi < max; xi += 2) {
1026
+ const x = data[xi];
1027
+ if (x >= input) {
1028
+ if (useCachedValues) {
1029
+ this.lastInput = input;
1030
+ this.lastHitIndex = xi;
1031
+ }
1032
+ if (xi === 0 || x === input) return data[xi + 1];
1033
+ switch (mode) {
1034
+ default:
1035
+ case "interpolate": {
1036
+ const last_x = data[xi - 2];
1037
+ const last_y = data[xi - 1];
1038
+ const y = data[xi + 1];
1039
+ const dx = x - last_x;
1040
+ return last_y + (y - last_y) / dx * (input - last_x);
1041
+ }
1042
+ case "forward": return data[xi + 1];
1043
+ case "backward": return data[xi - 1];
1044
+ }
1045
+ }
1046
+ }
1047
+ if (useCachedValues) {
1048
+ this.lastInput = input;
1049
+ this.lastHitIndex = max;
1050
+ }
1051
+ return data[max - 1];
1052
+ }
1053
+ /**
1054
+ * Return the most appropriate y value from the array of (x,y) pairs when
1055
+ * this instance is used to provide inputs for the `GAME` function.
1056
+ *
1057
+ * NOTE: The x values are assumed to be monotonically increasing.
1058
+ *
1059
+ * This method is similar to `getValueForX` in concept, except that this one
1060
+ * returns the provided `defaultValue` if the `time` parameter is earlier than
1061
+ * the first data point in the lookup. Also, this method always uses the
1062
+ * `backward` interpolation mode, meaning that it holds the "current" value
1063
+ * constant instead of interpolating.
1064
+ *
1065
+ * @param time The time that is used to select the data point that has an
1066
+ * `x` value less than or equal to the provided time.
1067
+ * @param defaultValue The value that is returned if this lookup is empty (has
1068
+ * no points) or if the provided time is earlier than the first data point.
1069
+ */
1070
+ getValueForGameTime(time, defaultValue) {
1071
+ if (this.activeSize <= 0) return defaultValue;
1072
+ if (time < this.activeData[0]) return defaultValue;
1073
+ return this.getValue(time, false, "backward");
1074
+ }
1075
+ /**
1076
+ * Interpolate the y value from the array of (x,y) pairs.
1077
+ * NOTE: The x values are assumed to be monotonically increasing.
1078
+ *
1079
+ * This method is similar to `getValue` in concept, but Vensim produces results for
1080
+ * the `GET DATA BETWEEN TIMES` function that differ in unexpected ways from normal
1081
+ * lookup behavior, so we implement it as a separate method here.
1082
+ */
1083
+ getValueBetweenTimes(input, mode) {
1084
+ if (this.activeSize === 0) return _NA_;
1085
+ const data = this.activeData;
1086
+ const max = this.activeSize * 2;
1087
+ switch (mode) {
1088
+ case "forward":
1089
+ input = Math.floor(input);
1090
+ for (let xi = 0; xi < max; xi += 2) if (data[xi] >= input) return data[xi + 1];
1091
+ return data[max - 1];
1092
+ case "backward":
1093
+ input = Math.floor(input);
1094
+ for (let xi = 2; xi < max; xi += 2) if (data[xi] >= input) return data[xi - 1];
1095
+ if (max >= 4) return data[max - 3];
1096
+ else return data[1];
1097
+ default:
1098
+ if (input - Math.floor(input) > 0) {
1099
+ let msg = `GET DATA BETWEEN TIMES was called with an input value (${input}) that has a fractional part. `;
1100
+ msg += "When mode is 0 (interpolate) and the input value is not a whole number, Vensim produces unexpected ";
1101
+ msg += "results that may differ from those produced by SDEverywhere.";
1102
+ throw new Error(msg);
1103
+ }
1104
+ for (let xi = 2; xi < max; xi += 2) {
1105
+ const x = data[xi];
1106
+ if (x >= input) {
1107
+ const last_x = data[xi - 2];
1108
+ const last_y = data[xi - 1];
1109
+ const y = data[xi + 1];
1110
+ const dx = x - last_x;
1111
+ return last_y + (y - last_y) / dx * (input - last_x);
1112
+ }
1113
+ }
1114
+ return data[max - 1];
1115
+ }
1116
+ }
1191
1117
  };
1192
-
1193
- // src/js-model/js-model-functions.ts
1194
- var EPSILON = 1e-6;
1118
+ //#endregion
1119
+ //#region src/js-model/js-model-functions.ts
1120
+ const EPSILON = 1e-6;
1121
+ /**
1122
+ * Returns a default implementation of the `JsModelFunctions` interface. If needed,
1123
+ * you can provide a custom implementation of any exposed function by overriding
1124
+ * (setting) a new function implementation on the returned instance.
1125
+ *
1126
+ * @hidden This is not yet part of the public API; for internal use by generated
1127
+ * `JsModel` implementations.
1128
+ */
1195
1129
  function getJsModelFunctions() {
1196
- let ctx;
1197
- const cachedVectors = /* @__PURE__ */ new Map();
1198
- const cachedSortVectors = /* @__PURE__ */ new Map();
1199
- const cachedInvertWorkMatrices = /* @__PURE__ */ new Map();
1200
- const cachedInvertResultMatrices = /* @__PURE__ */ new Map();
1201
- return {
1202
- setContext(context) {
1203
- ctx = context;
1204
- },
1205
- ABS(x) {
1206
- return Math.abs(x);
1207
- },
1208
- ARCCOS(x) {
1209
- return Math.acos(x);
1210
- },
1211
- ARCSIN(x) {
1212
- return Math.asin(x);
1213
- },
1214
- ARCTAN(x) {
1215
- return Math.atan(x);
1216
- },
1217
- COS(x) {
1218
- return Math.cos(x);
1219
- },
1220
- EXP(x) {
1221
- return Math.exp(x);
1222
- },
1223
- GAME(inputs, x) {
1224
- return inputs ? inputs.getValueForGameTime(ctx.currentTime, x) : x;
1225
- },
1226
- // GAMMA_LN(): number {
1227
- // throw new Error('GAMMA_LN function not yet implemented for JS target')
1228
- // },
1229
- INTEG(value, rate) {
1230
- return value + rate * ctx.timeStep;
1231
- },
1232
- INTEGER(x) {
1233
- return Math.trunc(x);
1234
- },
1235
- INVERT_MATRIX(matrix, n) {
1236
- let work = cachedInvertWorkMatrices.get(n);
1237
- if (work === void 0) {
1238
- work = Array(n);
1239
- for (let i = 0; i < n; i++) {
1240
- work[i] = Array(2 * n);
1241
- }
1242
- cachedInvertWorkMatrices.set(n, work);
1243
- }
1244
- let result = cachedInvertResultMatrices.get(n);
1245
- if (result === void 0) {
1246
- result = Array(n);
1247
- for (let i = 0; i < n; i++) {
1248
- result[i] = Array(n);
1249
- }
1250
- cachedInvertResultMatrices.set(n, result);
1251
- }
1252
- for (let i = 0; i < n; i++) {
1253
- for (let j = 0; j < n; j++) {
1254
- work[i][j] = matrix[i][j];
1255
- work[i][n + j] = i === j ? 1 : 0;
1256
- }
1257
- }
1258
- for (let k = 0; k < n; k++) {
1259
- let pivot = k;
1260
- let max = Math.abs(work[k][k]);
1261
- for (let i = k + 1; i < n; i++) {
1262
- const v = Math.abs(work[i][k]);
1263
- if (v > max) {
1264
- max = v;
1265
- pivot = i;
1266
- }
1267
- }
1268
- if (max === 0) {
1269
- for (let i = 0; i < n; i++) {
1270
- for (let j = 0; j < n; j++) {
1271
- result[i][j] = _NA_;
1272
- }
1273
- }
1274
- return result;
1275
- }
1276
- if (pivot !== k) {
1277
- const tmpRow = work[k];
1278
- work[k] = work[pivot];
1279
- work[pivot] = tmpRow;
1280
- }
1281
- const p = work[k][k];
1282
- for (let j = 0; j < 2 * n; j++) {
1283
- work[k][j] /= p;
1284
- }
1285
- for (let i = 0; i < n; i++) {
1286
- if (i !== k) {
1287
- const f = work[i][k];
1288
- if (f !== 0) {
1289
- for (let j = 0; j < 2 * n; j++) {
1290
- work[i][j] -= f * work[k][j];
1291
- }
1292
- }
1293
- }
1294
- }
1295
- }
1296
- for (let i = 0; i < n; i++) {
1297
- for (let j = 0; j < n; j++) {
1298
- result[i][j] = work[i][n + j];
1299
- }
1300
- }
1301
- return result;
1302
- },
1303
- LN(x) {
1304
- return Math.log(x);
1305
- },
1306
- MAX(x, y) {
1307
- return Math.max(x, y);
1308
- },
1309
- MIN(x, y) {
1310
- return Math.min(x, y);
1311
- },
1312
- MODULO(x, y) {
1313
- return x % y;
1314
- },
1315
- POW(x, y) {
1316
- return Math.pow(x, y);
1317
- },
1318
- POWER(x, y) {
1319
- return Math.pow(x, y);
1320
- },
1321
- PULSE(start, width) {
1322
- return pulse(ctx, start, width);
1323
- },
1324
- PULSE_TRAIN(start, width, interval, end) {
1325
- const n = Math.floor((end - start) / interval);
1326
- for (let k = 0; k <= n; k++) {
1327
- if (ctx.currentTime <= end && pulse(ctx, start + k * interval, width)) {
1328
- return 1;
1329
- }
1330
- }
1331
- return 0;
1332
- },
1333
- QUANTUM(x, y) {
1334
- return y <= 0 ? x : y * Math.trunc(x / y);
1335
- },
1336
- RAMP(slope, startTime, endTime) {
1337
- if (ctx.currentTime > startTime) {
1338
- if (ctx.currentTime < endTime || startTime > endTime) {
1339
- return slope * (ctx.currentTime - startTime);
1340
- } else {
1341
- return slope * (endTime - startTime);
1342
- }
1343
- } else {
1344
- return 0;
1345
- }
1346
- },
1347
- SIN(x) {
1348
- return Math.sin(x);
1349
- },
1350
- SQRT(x) {
1351
- return Math.sqrt(x);
1352
- },
1353
- STEP(height, stepTime) {
1354
- return ctx.currentTime + ctx.timeStep / 2 > stepTime ? height : 0;
1355
- },
1356
- TAN(x) {
1357
- return Math.tan(x);
1358
- },
1359
- VECTOR_SORT_ORDER(vector, size, direction) {
1360
- if (size > vector.length) {
1361
- throw new Error(`VECTOR SORT ORDER input vector length (${vector.length}) must be >= size (${size})`);
1362
- }
1363
- let sortVector = cachedSortVectors.get(size);
1364
- if (sortVector === void 0) {
1365
- sortVector = Array(size);
1366
- for (let i = 0; i < size; i++) {
1367
- sortVector[i] = { x: 0, ind: 0 };
1368
- }
1369
- cachedSortVectors.set(size, sortVector);
1370
- }
1371
- let outArray = cachedVectors.get(size);
1372
- if (outArray === void 0) {
1373
- outArray = Array(size);
1374
- cachedVectors.set(size, outArray);
1375
- }
1376
- for (let i = 0; i < size; i++) {
1377
- sortVector[i].x = vector[i];
1378
- sortVector[i].ind = i;
1379
- }
1380
- const sortOrder = direction > 0 ? 1 : -1;
1381
- sortVector.sort((a, b) => {
1382
- let result;
1383
- if (a.x < b.x) {
1384
- result = -1;
1385
- } else if (a.x > b.x) {
1386
- result = 1;
1387
- } else {
1388
- result = 0;
1389
- }
1390
- return result * sortOrder;
1391
- });
1392
- for (let i = 0; i < size; i++) {
1393
- outArray[i] = sortVector[i].ind;
1394
- }
1395
- return outArray;
1396
- },
1397
- XIDZ(a, b, x) {
1398
- return Math.abs(b) < EPSILON ? x : a / b;
1399
- },
1400
- ZIDZ(a, b) {
1401
- if (Math.abs(b) < EPSILON) {
1402
- return 0;
1403
- } else {
1404
- return a / b;
1405
- }
1406
- },
1407
- //
1408
- // Lookup functions
1409
- //
1410
- createLookup(size, data) {
1411
- return new JsModelLookup(size, data);
1412
- },
1413
- LOOKUP(lookup, x) {
1414
- return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
1415
- },
1416
- LOOKUP_FORWARD(lookup, x) {
1417
- return lookup ? lookup.getValueForX(x, "forward") : _NA_;
1418
- },
1419
- LOOKUP_BACKWARD(lookup, x) {
1420
- return lookup ? lookup.getValueForX(x, "backward") : _NA_;
1421
- },
1422
- LOOKUP_INVERT(lookup, y) {
1423
- return lookup ? lookup.getValueForY(y) : _NA_;
1424
- },
1425
- WITH_LOOKUP(x, lookup) {
1426
- return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
1427
- },
1428
- GET_DATA_BETWEEN_TIMES(lookup, x, mode) {
1429
- let lookupMode;
1430
- if (mode >= 1) {
1431
- lookupMode = "forward";
1432
- } else if (mode <= -1) {
1433
- lookupMode = "backward";
1434
- } else {
1435
- lookupMode = "interpolate";
1436
- }
1437
- return lookup ? lookup.getValueBetweenTimes(x, lookupMode) : _NA_;
1438
- }
1439
- };
1130
+ let ctx;
1131
+ const cachedVectors = /* @__PURE__ */ new Map();
1132
+ const cachedSortVectors = /* @__PURE__ */ new Map();
1133
+ const cachedInvertWorkMatrices = /* @__PURE__ */ new Map();
1134
+ const cachedInvertResultMatrices = /* @__PURE__ */ new Map();
1135
+ return {
1136
+ setContext(context) {
1137
+ ctx = context;
1138
+ },
1139
+ ABS(x) {
1140
+ return Math.abs(x);
1141
+ },
1142
+ ARCCOS(x) {
1143
+ return Math.acos(x);
1144
+ },
1145
+ ARCSIN(x) {
1146
+ return Math.asin(x);
1147
+ },
1148
+ ARCTAN(x) {
1149
+ return Math.atan(x);
1150
+ },
1151
+ COS(x) {
1152
+ return Math.cos(x);
1153
+ },
1154
+ EXP(x) {
1155
+ return Math.exp(x);
1156
+ },
1157
+ GAME(inputs, x) {
1158
+ return inputs ? inputs.getValueForGameTime(ctx.currentTime, x) : x;
1159
+ },
1160
+ INTEG(value, rate) {
1161
+ return value + rate * ctx.timeStep;
1162
+ },
1163
+ INTEGER(x) {
1164
+ return Math.trunc(x);
1165
+ },
1166
+ INVERT_MATRIX(matrix, n) {
1167
+ let work = cachedInvertWorkMatrices.get(n);
1168
+ if (work === void 0) {
1169
+ work = Array(n);
1170
+ for (let i = 0; i < n; i++) work[i] = Array(2 * n);
1171
+ cachedInvertWorkMatrices.set(n, work);
1172
+ }
1173
+ let result = cachedInvertResultMatrices.get(n);
1174
+ if (result === void 0) {
1175
+ result = Array(n);
1176
+ for (let i = 0; i < n; i++) result[i] = Array(n);
1177
+ cachedInvertResultMatrices.set(n, result);
1178
+ }
1179
+ for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) {
1180
+ work[i][j] = matrix[i][j];
1181
+ work[i][n + j] = i === j ? 1 : 0;
1182
+ }
1183
+ for (let k = 0; k < n; k++) {
1184
+ let pivot = k;
1185
+ let max = Math.abs(work[k][k]);
1186
+ for (let i = k + 1; i < n; i++) {
1187
+ const v = Math.abs(work[i][k]);
1188
+ if (v > max) {
1189
+ max = v;
1190
+ pivot = i;
1191
+ }
1192
+ }
1193
+ if (max === 0) {
1194
+ for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) result[i][j] = _NA_;
1195
+ return result;
1196
+ }
1197
+ if (pivot !== k) {
1198
+ const tmpRow = work[k];
1199
+ work[k] = work[pivot];
1200
+ work[pivot] = tmpRow;
1201
+ }
1202
+ const p = work[k][k];
1203
+ for (let j = 0; j < 2 * n; j++) work[k][j] /= p;
1204
+ for (let i = 0; i < n; i++) if (i !== k) {
1205
+ const f = work[i][k];
1206
+ if (f !== 0) for (let j = 0; j < 2 * n; j++) work[i][j] -= f * work[k][j];
1207
+ }
1208
+ }
1209
+ for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) result[i][j] = work[i][n + j];
1210
+ return result;
1211
+ },
1212
+ LN(x) {
1213
+ return Math.log(x);
1214
+ },
1215
+ MAX(x, y) {
1216
+ return Math.max(x, y);
1217
+ },
1218
+ MIN(x, y) {
1219
+ return Math.min(x, y);
1220
+ },
1221
+ MODULO(x, y) {
1222
+ return x % y;
1223
+ },
1224
+ POW(x, y) {
1225
+ return Math.pow(x, y);
1226
+ },
1227
+ POWER(x, y) {
1228
+ return Math.pow(x, y);
1229
+ },
1230
+ PULSE(start, width) {
1231
+ return pulse(ctx, start, width);
1232
+ },
1233
+ PULSE_TRAIN(start, width, interval, end) {
1234
+ const n = Math.floor((end - start) / interval);
1235
+ for (let k = 0; k <= n; k++) if (ctx.currentTime <= end && pulse(ctx, start + k * interval, width)) return 1;
1236
+ return 0;
1237
+ },
1238
+ QUANTUM(x, y) {
1239
+ return y <= 0 ? x : y * Math.trunc(x / y);
1240
+ },
1241
+ RAMP(slope, startTime, endTime) {
1242
+ if (ctx.currentTime > startTime) {
1243
+ if (ctx.currentTime < endTime || startTime > endTime) return slope * (ctx.currentTime - startTime);
1244
+ else return slope * (endTime - startTime);
1245
+ } else return 0;
1246
+ },
1247
+ SIN(x) {
1248
+ return Math.sin(x);
1249
+ },
1250
+ SQRT(x) {
1251
+ return Math.sqrt(x);
1252
+ },
1253
+ STEP(height, stepTime) {
1254
+ return ctx.currentTime + ctx.timeStep / 2 > stepTime ? height : 0;
1255
+ },
1256
+ TAN(x) {
1257
+ return Math.tan(x);
1258
+ },
1259
+ VECTOR_SORT_ORDER(vector, size, direction) {
1260
+ if (size > vector.length) throw new Error(`VECTOR SORT ORDER input vector length (${vector.length}) must be >= size (${size})`);
1261
+ let sortVector = cachedSortVectors.get(size);
1262
+ if (sortVector === void 0) {
1263
+ sortVector = Array(size);
1264
+ for (let i = 0; i < size; i++) sortVector[i] = {
1265
+ x: 0,
1266
+ ind: 0
1267
+ };
1268
+ cachedSortVectors.set(size, sortVector);
1269
+ }
1270
+ let outArray = cachedVectors.get(size);
1271
+ if (outArray === void 0) {
1272
+ outArray = Array(size);
1273
+ cachedVectors.set(size, outArray);
1274
+ }
1275
+ for (let i = 0; i < size; i++) {
1276
+ sortVector[i].x = vector[i];
1277
+ sortVector[i].ind = i;
1278
+ }
1279
+ const sortOrder = direction > 0 ? 1 : -1;
1280
+ sortVector.sort((a, b) => {
1281
+ let result;
1282
+ if (a.x < b.x) result = -1;
1283
+ else if (a.x > b.x) result = 1;
1284
+ else result = 0;
1285
+ return result * sortOrder;
1286
+ });
1287
+ for (let i = 0; i < size; i++) outArray[i] = sortVector[i].ind;
1288
+ return outArray;
1289
+ },
1290
+ XIDZ(a, b, x) {
1291
+ return Math.abs(b) < EPSILON ? x : a / b;
1292
+ },
1293
+ ZIDZ(a, b) {
1294
+ if (Math.abs(b) < EPSILON) return 0;
1295
+ else return a / b;
1296
+ },
1297
+ createLookup(size, data) {
1298
+ return new JsModelLookup(size, data);
1299
+ },
1300
+ LOOKUP(lookup, x) {
1301
+ return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
1302
+ },
1303
+ LOOKUP_FORWARD(lookup, x) {
1304
+ return lookup ? lookup.getValueForX(x, "forward") : _NA_;
1305
+ },
1306
+ LOOKUP_BACKWARD(lookup, x) {
1307
+ return lookup ? lookup.getValueForX(x, "backward") : _NA_;
1308
+ },
1309
+ LOOKUP_INVERT(lookup, y) {
1310
+ return lookup ? lookup.getValueForY(y) : _NA_;
1311
+ },
1312
+ WITH_LOOKUP(x, lookup) {
1313
+ return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
1314
+ },
1315
+ GET_DATA_BETWEEN_TIMES(lookup, x, mode) {
1316
+ let lookupMode;
1317
+ if (mode >= 1) lookupMode = "forward";
1318
+ else if (mode <= -1) lookupMode = "backward";
1319
+ else lookupMode = "interpolate";
1320
+ return lookup ? lookup.getValueBetweenTimes(x, lookupMode) : _NA_;
1321
+ }
1322
+ };
1440
1323
  }
1441
1324
  function pulse(ctx, start, width) {
1442
- const timePlus = ctx.currentTime + ctx.timeStep / 2;
1443
- if (width === 0) {
1444
- width = ctx.timeStep;
1445
- }
1446
- return timePlus > start && timePlus < start + width ? 1 : 0;
1325
+ const timePlus = ctx.currentTime + ctx.timeStep / 2;
1326
+ if (width === 0) width = ctx.timeStep;
1327
+ return timePlus > start && timePlus < start + width ? 1 : 0;
1447
1328
  }
1448
-
1449
- // src/perf/perf.ts
1450
- var isWeb;
1329
+ //#endregion
1330
+ //#region src/perf/perf.ts
1331
+ let isWeb;
1332
+ /**
1333
+ * Return a timestamp that can be passed to `perfElapsed` for calculating the elapsed
1334
+ * time of an operation.
1335
+ *
1336
+ * @hidden This is not part of the public API; exposed only for use in performance testing.
1337
+ */
1451
1338
  function perfNow() {
1452
- if (isWeb === void 0) {
1453
- isWeb = typeof self !== "undefined" && (self == null ? void 0 : self.performance) !== void 0;
1454
- }
1455
- if (isWeb) {
1456
- return self.performance.now();
1457
- } else {
1458
- return process == null ? void 0 : process.hrtime();
1459
- }
1339
+ if (isWeb === void 0) isWeb = typeof self !== "undefined" && self?.performance !== void 0;
1340
+ if (isWeb) return self.performance.now();
1341
+ else return process?.hrtime();
1460
1342
  }
1343
+ /**
1344
+ * Return the elapsed time between the given timestamp (created by `perfNow`) and now.
1345
+ *
1346
+ * @hidden This is not part of the public API; exposed only for use in performance testing.
1347
+ */
1461
1348
  function perfElapsed(t0) {
1462
- if (isWeb) {
1463
- const t1 = self.performance.now();
1464
- return t1 - t0;
1465
- } else {
1466
- const elapsed = process.hrtime(t0);
1467
- return (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
1468
- }
1349
+ if (isWeb) return self.performance.now() - t0;
1350
+ else {
1351
+ const elapsed = process.hrtime(t0);
1352
+ return (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
1353
+ }
1469
1354
  }
1470
-
1471
- // src/runnable-model/base-runnable-model.ts
1355
+ //#endregion
1356
+ //#region src/runnable-model/base-runnable-model.ts
1357
+ /**
1358
+ * A base implementation of the `RunnableModel` interface that takes care
1359
+ * of managing internal buffers and copying values to/from the `RunModelParams`.
1360
+ *
1361
+ * The `onRunModel` function allows an implementation of the core model run loop
1362
+ * to deal with typed arrays only.
1363
+ *
1364
+ * @hidden This is not part of the public API; for internal use only.
1365
+ */
1472
1366
  var BaseRunnableModel = class {
1473
- constructor(options) {
1474
- this.startTime = options.startTime;
1475
- this.endTime = options.endTime;
1476
- this.saveFreq = options.saveFreq;
1477
- this.numSavePoints = options.numSavePoints;
1478
- this.outputVarIds = options.outputVarIds;
1479
- this.modelListing = options.modelListing;
1480
- this.onRunModel = options.onRunModel;
1481
- }
1482
- // from RunnableModel interface
1483
- runModel(params) {
1484
- var _a;
1485
- let inputsArray = params.getInputs();
1486
- if (inputsArray === void 0) {
1487
- params.copyInputs(this.inputs, (numElements) => {
1488
- this.inputs = new Float64Array(numElements);
1489
- return this.inputs;
1490
- });
1491
- inputsArray = this.inputs;
1492
- }
1493
- let outputIndicesArray = params.getOutputIndices();
1494
- if (outputIndicesArray === void 0 && params.getOutputIndicesLength() > 0) {
1495
- params.copyOutputIndices(this.outputIndices, (numElements) => {
1496
- this.outputIndices = new Int32Array(numElements);
1497
- return this.outputIndices;
1498
- });
1499
- outputIndicesArray = this.outputIndices;
1500
- }
1501
- const outputsLengthInElements = params.getOutputsLength();
1502
- if (this.outputs === void 0 || this.outputs.length < outputsLengthInElements) {
1503
- this.outputs = new Float64Array(outputsLengthInElements);
1504
- }
1505
- const outputsArray = this.outputs;
1506
- const t0 = perfNow();
1507
- (_a = this.onRunModel) == null ? void 0 : _a.call(this, inputsArray, outputsArray, {
1508
- outputIndices: outputIndicesArray,
1509
- constants: params.getConstants(),
1510
- lookups: params.getLookups()
1511
- });
1512
- const elapsed = perfElapsed(t0);
1513
- params.storeOutputs(outputsArray);
1514
- params.storeElapsedTime(elapsed);
1515
- }
1516
- // from RunnableModel interface
1517
- terminate() {
1518
- }
1367
+ constructor(options) {
1368
+ this.startTime = options.startTime;
1369
+ this.endTime = options.endTime;
1370
+ this.saveFreq = options.saveFreq;
1371
+ this.numSavePoints = options.numSavePoints;
1372
+ this.outputVarIds = options.outputVarIds;
1373
+ this.modelListing = options.modelListing;
1374
+ this.onRunModel = options.onRunModel;
1375
+ }
1376
+ runModel(params) {
1377
+ let inputsArray = params.getInputs();
1378
+ if (inputsArray === void 0) {
1379
+ params.copyInputs(this.inputs, (numElements) => {
1380
+ this.inputs = new Float64Array(numElements);
1381
+ return this.inputs;
1382
+ });
1383
+ inputsArray = this.inputs;
1384
+ }
1385
+ let outputIndicesArray = params.getOutputIndices();
1386
+ if (outputIndicesArray === void 0 && params.getOutputIndicesLength() > 0) {
1387
+ params.copyOutputIndices(this.outputIndices, (numElements) => {
1388
+ this.outputIndices = new Int32Array(numElements);
1389
+ return this.outputIndices;
1390
+ });
1391
+ outputIndicesArray = this.outputIndices;
1392
+ }
1393
+ const outputsLengthInElements = params.getOutputsLength();
1394
+ if (this.outputs === void 0 || this.outputs.length < outputsLengthInElements) this.outputs = new Float64Array(outputsLengthInElements);
1395
+ const outputsArray = this.outputs;
1396
+ const t0 = perfNow();
1397
+ this.onRunModel?.(inputsArray, outputsArray, {
1398
+ outputIndices: outputIndicesArray,
1399
+ constants: params.getConstants(),
1400
+ lookups: params.getLookups()
1401
+ });
1402
+ const elapsed = perfElapsed(t0);
1403
+ params.storeOutputs(outputsArray);
1404
+ params.storeElapsedTime(elapsed);
1405
+ }
1406
+ terminate() {}
1519
1407
  };
1520
-
1521
- // src/js-model/js-model.ts
1408
+ //#endregion
1409
+ //#region src/js-model/js-model.ts
1410
+ /**
1411
+ * Create a `RunnableModel` from a given `JsModel` that was generated by the
1412
+ * SDEverywhere transpiler.
1413
+ *
1414
+ * @hidden This is not part of the public API; only the top-level `createRunnableModel`
1415
+ * function is exposed in the public API.
1416
+ */
1522
1417
  function initJsModel(model) {
1523
- let fns = model.getModelFunctions();
1524
- if (fns === void 0) {
1525
- fns = getJsModelFunctions();
1526
- model.setModelFunctions(fns);
1527
- }
1528
- const initialTime = model.getInitialTime();
1529
- const finalTime = model.getFinalTime();
1530
- const timeStep = model.getTimeStep();
1531
- const saveFreq = model.getSaveFreq();
1532
- const numSavePoints = Math.round((finalTime - initialTime) / saveFreq) + 1;
1533
- return new BaseRunnableModel({
1534
- startTime: initialTime,
1535
- endTime: finalTime,
1536
- saveFreq,
1537
- numSavePoints,
1538
- outputVarIds: model.outputVarIds,
1539
- modelListing: model.modelListing,
1540
- onRunModel: (inputs, outputs, options) => {
1541
- runJsModel(
1542
- model,
1543
- initialTime,
1544
- finalTime,
1545
- timeStep,
1546
- saveFreq,
1547
- numSavePoints,
1548
- inputs,
1549
- outputs,
1550
- options == null ? void 0 : options.outputIndices,
1551
- options == null ? void 0 : options.constants,
1552
- options == null ? void 0 : options.lookups,
1553
- void 0
1554
- );
1555
- }
1556
- });
1418
+ let fns = model.getModelFunctions();
1419
+ if (fns === void 0) {
1420
+ fns = getJsModelFunctions();
1421
+ model.setModelFunctions(fns);
1422
+ }
1423
+ const initialTime = model.getInitialTime();
1424
+ const finalTime = model.getFinalTime();
1425
+ const timeStep = model.getTimeStep();
1426
+ const saveFreq = model.getSaveFreq();
1427
+ const numSavePoints = Math.round((finalTime - initialTime) / saveFreq) + 1;
1428
+ return new BaseRunnableModel({
1429
+ startTime: initialTime,
1430
+ endTime: finalTime,
1431
+ saveFreq,
1432
+ numSavePoints,
1433
+ outputVarIds: model.outputVarIds,
1434
+ modelListing: model.modelListing,
1435
+ onRunModel: (inputs, outputs, options) => {
1436
+ runJsModel(model, initialTime, finalTime, timeStep, saveFreq, numSavePoints, inputs, outputs, options?.outputIndices, options?.constants, options?.lookups, void 0);
1437
+ }
1438
+ });
1557
1439
  }
1558
1440
  function runJsModel(model, initialTime, finalTime, timeStep, saveFreq, numSavePoints, inputs, outputs, outputIndices, constants, lookups, stopAfterTime) {
1559
- let time = initialTime;
1560
- model.setTime(time);
1561
- const fnContext = {
1562
- timeStep,
1563
- currentTime: time
1564
- };
1565
- model.getModelFunctions().setContext(fnContext);
1566
- model.initConstants();
1567
- if (constants !== void 0) {
1568
- for (const constantDef of constants) {
1569
- model.setConstant(constantDef.varRef.varSpec, constantDef.value);
1570
- }
1571
- }
1572
- if (lookups !== void 0) {
1573
- for (const lookupDef of lookups) {
1574
- model.setLookup(lookupDef.varRef.varSpec, lookupDef.points);
1575
- }
1576
- }
1577
- if ((inputs == null ? void 0 : inputs.length) > 0) {
1578
- model.setInputs((index) => inputs[index]);
1579
- }
1580
- model.initLevels();
1581
- const lastStep = Math.round((finalTime - initialTime) / timeStep);
1582
- const stopTime = stopAfterTime !== void 0 ? stopAfterTime : finalTime;
1583
- let step = 0;
1584
- let savePointIndex = 0;
1585
- let outputVarIndex = 0;
1586
- while (step <= lastStep) {
1587
- model.evalAux();
1588
- if (time % saveFreq < 1e-6) {
1589
- outputVarIndex = 0;
1590
- const storeValue = (value) => {
1591
- const outputBufferIndex = outputVarIndex * numSavePoints + savePointIndex;
1592
- outputs[outputBufferIndex] = time <= stopTime ? value : void 0;
1593
- outputVarIndex++;
1594
- };
1595
- if (outputIndices !== void 0) {
1596
- let indexBufferOffset = 0;
1597
- const outputCount = outputIndices[indexBufferOffset++];
1598
- for (let i = 0; i < outputCount; i++) {
1599
- const varIndex = outputIndices[indexBufferOffset++];
1600
- const subCount = outputIndices[indexBufferOffset++];
1601
- let subscriptIndices;
1602
- if (subCount > 0) {
1603
- subscriptIndices = outputIndices.subarray(indexBufferOffset, indexBufferOffset + subCount);
1604
- indexBufferOffset += subCount;
1605
- }
1606
- const varSpec = {
1607
- varIndex,
1608
- subscriptIndices
1609
- };
1610
- model.storeOutput(varSpec, storeValue);
1611
- }
1612
- } else {
1613
- model.storeOutputs(storeValue);
1614
- }
1615
- savePointIndex++;
1616
- }
1617
- if (step === lastStep) {
1618
- break;
1619
- }
1620
- model.evalLevels();
1621
- time += timeStep;
1622
- model.setTime(time);
1623
- fnContext.currentTime = time;
1624
- step++;
1625
- }
1441
+ let time = initialTime;
1442
+ model.setTime(time);
1443
+ const fnContext = {
1444
+ timeStep,
1445
+ currentTime: time
1446
+ };
1447
+ model.getModelFunctions().setContext(fnContext);
1448
+ model.initConstants();
1449
+ if (constants !== void 0) for (const constantDef of constants) model.setConstant(constantDef.varRef.varSpec, constantDef.value);
1450
+ if (lookups !== void 0) for (const lookupDef of lookups) model.setLookup(lookupDef.varRef.varSpec, lookupDef.points);
1451
+ if (inputs?.length > 0) model.setInputs((index) => inputs[index]);
1452
+ model.initLevels();
1453
+ const lastStep = Math.round((finalTime - initialTime) / timeStep);
1454
+ const stopTime = stopAfterTime !== void 0 ? stopAfterTime : finalTime;
1455
+ let step = 0;
1456
+ let savePointIndex = 0;
1457
+ let outputVarIndex = 0;
1458
+ while (step <= lastStep) {
1459
+ model.evalAux();
1460
+ if (time % saveFreq < 1e-6) {
1461
+ outputVarIndex = 0;
1462
+ const storeValue = (value) => {
1463
+ const outputBufferIndex = outputVarIndex * numSavePoints + savePointIndex;
1464
+ outputs[outputBufferIndex] = time <= stopTime ? value : void 0;
1465
+ outputVarIndex++;
1466
+ };
1467
+ if (outputIndices !== void 0) {
1468
+ let indexBufferOffset = 0;
1469
+ const outputCount = outputIndices[indexBufferOffset++];
1470
+ for (let i = 0; i < outputCount; i++) {
1471
+ const varIndex = outputIndices[indexBufferOffset++];
1472
+ const subCount = outputIndices[indexBufferOffset++];
1473
+ let subscriptIndices;
1474
+ if (subCount > 0) {
1475
+ subscriptIndices = outputIndices.subarray(indexBufferOffset, indexBufferOffset + subCount);
1476
+ indexBufferOffset += subCount;
1477
+ }
1478
+ const varSpec = {
1479
+ varIndex,
1480
+ subscriptIndices
1481
+ };
1482
+ model.storeOutput(varSpec, storeValue);
1483
+ }
1484
+ } else model.storeOutputs(storeValue);
1485
+ savePointIndex++;
1486
+ }
1487
+ if (step === lastStep) break;
1488
+ model.evalLevels();
1489
+ time += timeStep;
1490
+ model.setTime(time);
1491
+ fnContext.currentTime = time;
1492
+ step++;
1493
+ }
1626
1494
  }
1627
-
1628
- // src/js-model/exec-js-model.ts
1495
+ //#endregion
1496
+ //#region src/js-model/exec-js-model.ts
1497
+ /**
1498
+ * Run the given model synchronously and log the output values to the console in
1499
+ * TSV (tab-separated values) format.
1500
+ *
1501
+ * @hidden This is mainly intended for use in implementing the `sde exec` command,
1502
+ * so isn't exposed in the public API at this time.
1503
+ *
1504
+ * @param jsModel A `JsModel` instance.
1505
+ */
1629
1506
  function execJsModel(jsModel) {
1630
- const runnableModel = initJsModel(jsModel);
1631
- const inputs = [];
1632
- const outputVarIds = jsModel.outputVarIds;
1633
- const startTime = jsModel.getInitialTime();
1634
- const endTime = jsModel.getFinalTime();
1635
- const saveFreq = jsModel.getSaveFreq();
1636
- const outputs = new Outputs(outputVarIds, startTime, endTime, saveFreq);
1637
- const params = new ReferencedRunModelParams();
1638
- params.updateFromParams(inputs, outputs);
1639
- runnableModel.runModel(params);
1640
- const outputVarNames = jsModel.outputVarNames.map((name) => name.replace(/"/g, '\\"'));
1641
- const header = outputVarNames.join(" ");
1642
- console.log(header);
1643
- for (let i = 0; i < outputs.seriesLength; i++) {
1644
- const rowValues = [];
1645
- for (const series of outputs.varSeries) {
1646
- rowValues.push(series.points[i].y);
1647
- }
1648
- console.log(rowValues.join(" "));
1649
- }
1507
+ const runnableModel = initJsModel(jsModel);
1508
+ const inputs = [];
1509
+ const outputVarIds = jsModel.outputVarIds;
1510
+ const outputs = new Outputs(outputVarIds, jsModel.getInitialTime(), jsModel.getFinalTime(), jsModel.getSaveFreq());
1511
+ const params = new ReferencedRunModelParams();
1512
+ params.updateFromParams(inputs, outputs);
1513
+ runnableModel.runModel(params);
1514
+ const header = jsModel.outputVarNames.map((name) => name.replace(/"/g, "\\\"")).join(" ");
1515
+ console.log(header);
1516
+ for (let i = 0; i < outputs.seriesLength; i++) {
1517
+ const rowValues = [];
1518
+ for (const series of outputs.varSeries) rowValues.push(series.points[i].y);
1519
+ console.log(rowValues.join(" "));
1520
+ }
1650
1521
  }
1651
-
1652
- // src/js-model/_mocks/mock-js-model.ts
1522
+ //#endregion
1523
+ //#region src/js-model/_mocks/mock-js-model.ts
1524
+ /**
1525
+ * @hidden This type is not part of the public API; it is exposed only for use in
1526
+ * tests in the runtime-async package.
1527
+ */
1653
1528
  var MockJsModel = class {
1654
- constructor(options) {
1655
- // from JsModel interface
1656
- this.kind = "js";
1657
- this.vars = /* @__PURE__ */ new Map();
1658
- this.constants = /* @__PURE__ */ new Map();
1659
- this.lookups = /* @__PURE__ */ new Map();
1660
- this.outputVarIds = options.outputVarIds;
1661
- this.outputVarNames = options.outputVarIds;
1662
- this.initialTime = options.initialTime;
1663
- this.finalTime = options.finalTime;
1664
- this.outputVarIds = options.outputVarIds;
1665
- if (options.listingJson) {
1666
- this.modelListing = JSON.parse(options.listingJson);
1667
- this.internalListing = new ModelListing(this.modelListing);
1668
- }
1669
- this.onEvalAux = options.onEvalAux;
1670
- }
1671
- varIdForSpec(varSpec) {
1672
- for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) {
1673
- if (listingSpec.varIndex === varSpec.varIndex) {
1674
- return listingVarId;
1675
- }
1676
- }
1677
- return void 0;
1678
- }
1679
- // from JsModel interface
1680
- getInitialTime() {
1681
- return this.initialTime;
1682
- }
1683
- // from JsModel interface
1684
- getFinalTime() {
1685
- return this.finalTime;
1686
- }
1687
- // from JsModel interface
1688
- getTimeStep() {
1689
- return 1;
1690
- }
1691
- // from JsModel interface
1692
- getSaveFreq() {
1693
- return 1;
1694
- }
1695
- // from JsModel interface
1696
- getModelFunctions() {
1697
- return this.fns;
1698
- }
1699
- // from JsModel interface
1700
- setModelFunctions(fns) {
1701
- this.fns = fns;
1702
- }
1703
- // from JsModel interface
1704
- setTime(time) {
1705
- this.vars.set("_time", time);
1706
- }
1707
- // from JsModel interface
1708
- setInputs() {
1709
- }
1710
- // from JsModel interface
1711
- setConstant(varSpec, value) {
1712
- const varId = this.varIdForSpec(varSpec);
1713
- if (varId === void 0) {
1714
- throw new Error(`No constant variable found for spec ${varSpec}`);
1715
- }
1716
- this.constants.set(varId, value);
1717
- }
1718
- // from JsModel interface
1719
- setLookup(varSpec, points) {
1720
- const varId = this.varIdForSpec(varSpec);
1721
- if (varId === void 0) {
1722
- throw new Error(`No lookup variable found for spec ${varSpec}`);
1723
- }
1724
- const numPoints = points ? points.length / 2 : 0;
1725
- this.lookups.set(varId, new JsModelLookup(numPoints, points));
1726
- }
1727
- // from JsModel interface
1728
- storeOutputs(storeValue) {
1729
- for (const varId of this.outputVarIds) {
1730
- storeValue(this.vars.get(varId));
1731
- }
1732
- }
1733
- // from JsModel interface
1734
- storeOutput(varSpec, storeValue) {
1735
- const varId = this.varIdForSpec(varSpec);
1736
- if (varId === void 0) {
1737
- throw new Error(`No output variable found for spec ${varSpec}`);
1738
- }
1739
- storeValue(this.vars.get(varId));
1740
- }
1741
- // from JsModel interface
1742
- initConstants() {
1743
- this.constants.clear();
1744
- }
1745
- // from JsModel interface
1746
- initLevels() {
1747
- }
1748
- // from JsModel interface
1749
- evalAux() {
1750
- var _a;
1751
- (_a = this.onEvalAux) == null ? void 0 : _a.call(this, this.vars, this.constants.size > 0 ? this.constants : void 0, this.lookups);
1752
- }
1753
- // from JsModel interface
1754
- evalLevels() {
1755
- }
1529
+ constructor(options) {
1530
+ this.kind = "js";
1531
+ this.vars = /* @__PURE__ */ new Map();
1532
+ this.constants = /* @__PURE__ */ new Map();
1533
+ this.lookups = /* @__PURE__ */ new Map();
1534
+ this.outputVarIds = options.outputVarIds;
1535
+ this.outputVarNames = options.outputVarIds;
1536
+ this.initialTime = options.initialTime;
1537
+ this.finalTime = options.finalTime;
1538
+ this.outputVarIds = options.outputVarIds;
1539
+ if (options.listingJson) {
1540
+ this.modelListing = JSON.parse(options.listingJson);
1541
+ this.internalListing = new ModelListing(this.modelListing);
1542
+ }
1543
+ this.onEvalAux = options.onEvalAux;
1544
+ }
1545
+ varIdForSpec(varSpec) {
1546
+ for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) if (listingSpec.varIndex === varSpec.varIndex) return listingVarId;
1547
+ }
1548
+ getInitialTime() {
1549
+ return this.initialTime;
1550
+ }
1551
+ getFinalTime() {
1552
+ return this.finalTime;
1553
+ }
1554
+ getTimeStep() {
1555
+ return 1;
1556
+ }
1557
+ getSaveFreq() {
1558
+ return 1;
1559
+ }
1560
+ getModelFunctions() {
1561
+ return this.fns;
1562
+ }
1563
+ setModelFunctions(fns) {
1564
+ this.fns = fns;
1565
+ }
1566
+ setTime(time) {
1567
+ this.vars.set("_time", time);
1568
+ }
1569
+ setInputs() {}
1570
+ setConstant(varSpec, value) {
1571
+ const varId = this.varIdForSpec(varSpec);
1572
+ if (varId === void 0) throw new Error(`No constant variable found for spec ${varSpec}`);
1573
+ this.constants.set(varId, value);
1574
+ }
1575
+ setLookup(varSpec, points) {
1576
+ const varId = this.varIdForSpec(varSpec);
1577
+ if (varId === void 0) throw new Error(`No lookup variable found for spec ${varSpec}`);
1578
+ const numPoints = points ? points.length / 2 : 0;
1579
+ this.lookups.set(varId, new JsModelLookup(numPoints, points));
1580
+ }
1581
+ storeOutputs(storeValue) {
1582
+ for (const varId of this.outputVarIds) storeValue(this.vars.get(varId));
1583
+ }
1584
+ storeOutput(varSpec, storeValue) {
1585
+ const varId = this.varIdForSpec(varSpec);
1586
+ if (varId === void 0) throw new Error(`No output variable found for spec ${varSpec}`);
1587
+ storeValue(this.vars.get(varId));
1588
+ }
1589
+ initConstants() {
1590
+ this.constants.clear();
1591
+ }
1592
+ initLevels() {}
1593
+ evalAux() {
1594
+ this.onEvalAux?.(this.vars, this.constants.size > 0 ? this.constants : void 0, this.lookups);
1595
+ }
1596
+ evalLevels() {}
1756
1597
  };
1757
-
1758
- // src/wasm-model/wasm-buffer.ts
1598
+ //#endregion
1599
+ //#region src/wasm-model/wasm-buffer.ts
1600
+ /**
1601
+ * Wraps a `WebAssembly.Memory` buffer allocated on the wasm heap.
1602
+ *
1603
+ * When this is used synchronously (in the browser's normal JavaScript thread),
1604
+ * the client can use `getArrayView` to write directly into the underlying memory.
1605
+ *
1606
+ * Note, however, that `WebAssembly.Memory` buffers cannot be transferred to/from
1607
+ * a Web Worker. When using this class in a worker thread, create a separate
1608
+ * `Float64Array` that can be transferred between the worker and the client running
1609
+ * in the browser's normal JS thread, and then use `getArrayView` to copy into and
1610
+ * out of the wasm buffer.
1611
+ *
1612
+ * @hidden For internal use only.
1613
+ */
1759
1614
  var WasmBuffer = class {
1760
- /**
1761
- * @param wasmModule The `WasmModule` used to initialize the memory.
1762
- * @param numElements The number of elements in the buffer.
1763
- * @param byteOffset The byte offset within the wasm heap.
1764
- * @param heapArray The array view on the underlying heap buffer.
1765
- */
1766
- constructor(wasmModule, numElements, byteOffset, heapArray) {
1767
- this.wasmModule = wasmModule;
1768
- this.numElements = numElements;
1769
- this.byteOffset = byteOffset;
1770
- this.heapArray = heapArray;
1771
- }
1772
- /**
1773
- * @return An `ArrType` view on the underlying heap buffer.
1774
- */
1775
- getArrayView() {
1776
- return this.heapArray;
1777
- }
1778
- /**
1779
- * @return The raw address of the underlying heap buffer.
1780
- * @hidden This is intended for use by `WasmModel` only.
1781
- */
1782
- getAddress() {
1783
- return this.byteOffset;
1784
- }
1785
- /**
1786
- * Dispose the buffer by freeing the allocated heap memory.
1787
- */
1788
- dispose() {
1789
- var _a, _b;
1790
- if (this.heapArray) {
1791
- (_b = (_a = this.wasmModule)._free) == null ? void 0 : _b.call(_a, this.byteOffset);
1792
- this.numElements = void 0;
1793
- this.heapArray = void 0;
1794
- this.byteOffset = void 0;
1795
- }
1796
- }
1615
+ /**
1616
+ * @param wasmModule The `WasmModule` used to initialize the memory.
1617
+ * @param numElements The number of elements in the buffer.
1618
+ * @param byteOffset The byte offset within the wasm heap.
1619
+ * @param heapArray The array view on the underlying heap buffer.
1620
+ */
1621
+ constructor(wasmModule, numElements, byteOffset, heapArray) {
1622
+ this.wasmModule = wasmModule;
1623
+ this.numElements = numElements;
1624
+ this.byteOffset = byteOffset;
1625
+ this.heapArray = heapArray;
1626
+ }
1627
+ /**
1628
+ * @return An `ArrType` view on the underlying heap buffer.
1629
+ */
1630
+ getArrayView() {
1631
+ return this.heapArray;
1632
+ }
1633
+ /**
1634
+ * @return The raw address of the underlying heap buffer.
1635
+ * @hidden This is intended for use by `WasmModel` only.
1636
+ */
1637
+ getAddress() {
1638
+ return this.byteOffset;
1639
+ }
1640
+ /**
1641
+ * Dispose the buffer by freeing the allocated heap memory.
1642
+ */
1643
+ dispose() {
1644
+ if (this.heapArray) {
1645
+ this.wasmModule._free?.(this.byteOffset);
1646
+ this.numElements = void 0;
1647
+ this.heapArray = void 0;
1648
+ this.byteOffset = void 0;
1649
+ }
1650
+ }
1797
1651
  };
1652
+ /**
1653
+ * Return a `WasmBuffer` that holds int32 elements.
1654
+ *
1655
+ * @hidden For internal use only.
1656
+ *
1657
+ * @param wasmModule The `WasmModule` used to initialize the memory.
1658
+ * @param numElements The number of elements in the buffer.
1659
+ */
1798
1660
  function createInt32WasmBuffer(wasmModule, numElements) {
1799
- const elemSizeInBytes = 4;
1800
- const lengthInBytes = numElements * elemSizeInBytes;
1801
- const byteOffset = wasmModule._malloc(lengthInBytes);
1802
- const elemOffset = byteOffset / elemSizeInBytes;
1803
- const heapArray = wasmModule.HEAP32.subarray(elemOffset, elemOffset + numElements);
1804
- return new WasmBuffer(wasmModule, numElements, byteOffset, heapArray);
1661
+ const elemSizeInBytes = 4;
1662
+ const lengthInBytes = numElements * elemSizeInBytes;
1663
+ const byteOffset = wasmModule._malloc(lengthInBytes);
1664
+ const elemOffset = byteOffset / elemSizeInBytes;
1665
+ return new WasmBuffer(wasmModule, numElements, byteOffset, wasmModule.HEAP32.subarray(elemOffset, elemOffset + numElements));
1805
1666
  }
1667
+ /**
1668
+ * Return a `WasmBuffer` that holds float64 elements.
1669
+ *
1670
+ * @hidden For internal use only.
1671
+ *
1672
+ * @param wasmModule The `WasmModule` used to initialize the memory.
1673
+ * @param numElements The number of elements in the buffer.
1674
+ */
1806
1675
  function createFloat64WasmBuffer(wasmModule, numElements) {
1807
- const elemSizeInBytes = 8;
1808
- const lengthInBytes = numElements * elemSizeInBytes;
1809
- const byteOffset = wasmModule._malloc(lengthInBytes);
1810
- const elemOffset = byteOffset / elemSizeInBytes;
1811
- const heapArray = wasmModule.HEAPF64.subarray(elemOffset, elemOffset + numElements);
1812
- return new WasmBuffer(wasmModule, numElements, byteOffset, heapArray);
1676
+ const elemSizeInBytes = 8;
1677
+ const lengthInBytes = numElements * elemSizeInBytes;
1678
+ const byteOffset = wasmModule._malloc(lengthInBytes);
1679
+ const elemOffset = byteOffset / elemSizeInBytes;
1680
+ return new WasmBuffer(wasmModule, numElements, byteOffset, wasmModule.HEAPF64.subarray(elemOffset, elemOffset + numElements));
1813
1681
  }
1814
-
1815
- // src/wasm-model/wasm-model.ts
1682
+ //#endregion
1683
+ //#region src/wasm-model/wasm-model.ts
1684
+ /**
1685
+ * A wrapper around a WebAssembly module generated by the SDEverywhere transpiler,
1686
+ * which allows for running the model with a given set of input values, producing
1687
+ * a set of output values.
1688
+ */
1816
1689
  var WasmModel = class {
1817
- /**
1818
- * @param wasmModule The `WasmModule` that provides access to the native functions.
1819
- * @param outputVarIds The output variable IDs for this model.
1820
- */
1821
- constructor(wasmModule) {
1822
- this.wasmModule = wasmModule;
1823
- function getNumberValue(funcName) {
1824
- const wasmGetValue = wasmModule.cwrap(funcName, "number", []);
1825
- return wasmGetValue();
1826
- }
1827
- this.startTime = getNumberValue("getInitialTime");
1828
- this.endTime = getNumberValue("getFinalTime");
1829
- this.saveFreq = getNumberValue("getSaveper");
1830
- this.numSavePoints = Math.round((this.endTime - this.startTime) / this.saveFreq) + 1;
1831
- this.outputVarIds = wasmModule.outputVarIds;
1832
- this.modelListing = wasmModule.modelListing;
1833
- this.wasmSetLookup = wasmModule.cwrap("setLookup", null, ["number", "number", "number", "number"]);
1834
- this.wasmRunModel = wasmModule.cwrap("runModelWithBuffers", null, [
1835
- "number",
1836
- "number",
1837
- "number",
1838
- "number",
1839
- "number",
1840
- "number"
1841
- ]);
1842
- }
1843
- // from RunnableModel interface
1844
- runModel(params) {
1845
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1846
- const lookups = params.getLookups();
1847
- if (lookups !== void 0) {
1848
- for (const lookupDef of lookups) {
1849
- const varSpec = lookupDef.varRef.varSpec;
1850
- const numSubElements = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
1851
- let subIndicesAddress;
1852
- if (numSubElements > 0) {
1853
- if (this.lookupSubIndicesBuffer === void 0 || this.lookupSubIndicesBuffer.numElements < numSubElements) {
1854
- (_b = this.lookupSubIndicesBuffer) == null ? void 0 : _b.dispose();
1855
- this.lookupSubIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numSubElements);
1856
- }
1857
- this.lookupSubIndicesBuffer.getArrayView().set(varSpec.subscriptIndices);
1858
- subIndicesAddress = this.lookupSubIndicesBuffer.getAddress();
1859
- } else {
1860
- subIndicesAddress = 0;
1861
- }
1862
- let pointsAddress;
1863
- let numPoints;
1864
- if (lookupDef.points) {
1865
- const numLookupElements = lookupDef.points.length;
1866
- if (this.lookupDataBuffer === void 0 || this.lookupDataBuffer.numElements < numLookupElements) {
1867
- (_c = this.lookupDataBuffer) == null ? void 0 : _c.dispose();
1868
- this.lookupDataBuffer = createFloat64WasmBuffer(this.wasmModule, numLookupElements);
1869
- }
1870
- this.lookupDataBuffer.getArrayView().set(lookupDef.points);
1871
- pointsAddress = this.lookupDataBuffer.getAddress();
1872
- numPoints = numLookupElements / 2;
1873
- } else {
1874
- pointsAddress = 0;
1875
- numPoints = 0;
1876
- }
1877
- const varIndex = varSpec.varIndex;
1878
- this.wasmSetLookup(varIndex, subIndicesAddress, pointsAddress, numPoints);
1879
- }
1880
- }
1881
- let constantIndicesBuffer;
1882
- let constantValuesBuffer;
1883
- const constants = params.getConstants();
1884
- if (constants !== void 0 && constants.length > 0) {
1885
- let totalIndicesSize = 1;
1886
- for (const constantDef of constants) {
1887
- const numSubElements = ((_d = constantDef.varRef.varSpec.subscriptIndices) == null ? void 0 : _d.length) || 0;
1888
- totalIndicesSize += 2 + numSubElements;
1889
- }
1890
- if (this.constantIndicesBuffer === void 0 || this.constantIndicesBuffer.numElements < totalIndicesSize) {
1891
- (_e = this.constantIndicesBuffer) == null ? void 0 : _e.dispose();
1892
- this.constantIndicesBuffer = createInt32WasmBuffer(this.wasmModule, totalIndicesSize);
1893
- }
1894
- const numConstants = constants.length;
1895
- if (this.constantValuesBuffer === void 0 || this.constantValuesBuffer.numElements < numConstants) {
1896
- (_f = this.constantValuesBuffer) == null ? void 0 : _f.dispose();
1897
- this.constantValuesBuffer = createFloat64WasmBuffer(this.wasmModule, numConstants);
1898
- }
1899
- const indicesView = this.constantIndicesBuffer.getArrayView();
1900
- const valuesView = this.constantValuesBuffer.getArrayView();
1901
- let indicesOffset = 0;
1902
- let valuesOffset = 0;
1903
- indicesView[indicesOffset++] = numConstants;
1904
- for (const constantDef of constants) {
1905
- const varSpec = constantDef.varRef.varSpec;
1906
- const numSubElements = ((_g = varSpec.subscriptIndices) == null ? void 0 : _g.length) || 0;
1907
- indicesView[indicesOffset++] = varSpec.varIndex;
1908
- indicesView[indicesOffset++] = numSubElements;
1909
- if (numSubElements > 0) {
1910
- for (let i = 0; i < numSubElements; i++) {
1911
- indicesView[indicesOffset++] = varSpec.subscriptIndices[i];
1912
- }
1913
- }
1914
- valuesView[valuesOffset++] = constantDef.value;
1915
- }
1916
- constantIndicesBuffer = this.constantIndicesBuffer;
1917
- constantValuesBuffer = this.constantValuesBuffer;
1918
- } else {
1919
- constantIndicesBuffer = void 0;
1920
- constantValuesBuffer = void 0;
1921
- }
1922
- params.copyInputs((_h = this.inputsBuffer) == null ? void 0 : _h.getArrayView(), (numElements) => {
1923
- var _a2;
1924
- (_a2 = this.inputsBuffer) == null ? void 0 : _a2.dispose();
1925
- this.inputsBuffer = createFloat64WasmBuffer(this.wasmModule, numElements);
1926
- return this.inputsBuffer.getArrayView();
1927
- });
1928
- let outputIndicesBuffer;
1929
- if (params.getOutputIndicesLength() > 0) {
1930
- params.copyOutputIndices((_i = this.outputIndicesBuffer) == null ? void 0 : _i.getArrayView(), (numElements) => {
1931
- var _a2;
1932
- (_a2 = this.outputIndicesBuffer) == null ? void 0 : _a2.dispose();
1933
- this.outputIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numElements);
1934
- return this.outputIndicesBuffer.getArrayView();
1935
- });
1936
- outputIndicesBuffer = this.outputIndicesBuffer;
1937
- } else {
1938
- outputIndicesBuffer = void 0;
1939
- }
1940
- const outputsLengthInElements = params.getOutputsLength();
1941
- if (this.outputsBuffer === void 0 || this.outputsBuffer.numElements < outputsLengthInElements) {
1942
- (_j = this.outputsBuffer) == null ? void 0 : _j.dispose();
1943
- this.outputsBuffer = createFloat64WasmBuffer(this.wasmModule, outputsLengthInElements);
1944
- }
1945
- const t0 = perfNow();
1946
- this.wasmRunModel(
1947
- ((_k = this.inputsBuffer) == null ? void 0 : _k.getAddress()) || 0,
1948
- // Always pass 0 (NULL) for input indices, since we assume that all input values are
1949
- // provided and are in the same order as the input variables defined in the model spec
1950
- 0,
1951
- this.outputsBuffer.getAddress(),
1952
- (outputIndicesBuffer == null ? void 0 : outputIndicesBuffer.getAddress()) || 0,
1953
- (constantValuesBuffer == null ? void 0 : constantValuesBuffer.getAddress()) || 0,
1954
- (constantIndicesBuffer == null ? void 0 : constantIndicesBuffer.getAddress()) || 0
1955
- );
1956
- const elapsed = perfElapsed(t0);
1957
- params.storeOutputs(this.outputsBuffer.getArrayView());
1958
- params.storeElapsedTime(elapsed);
1959
- }
1960
- // from RunnableModel interface
1961
- terminate() {
1962
- var _a, _b, _c, _d, _e;
1963
- (_a = this.inputsBuffer) == null ? void 0 : _a.dispose();
1964
- this.inputsBuffer = void 0;
1965
- (_b = this.outputsBuffer) == null ? void 0 : _b.dispose();
1966
- this.outputsBuffer = void 0;
1967
- (_c = this.outputIndicesBuffer) == null ? void 0 : _c.dispose();
1968
- this.outputIndicesBuffer = void 0;
1969
- (_d = this.constantValuesBuffer) == null ? void 0 : _d.dispose();
1970
- this.constantValuesBuffer = void 0;
1971
- (_e = this.constantIndicesBuffer) == null ? void 0 : _e.dispose();
1972
- this.constantIndicesBuffer = void 0;
1973
- }
1690
+ /**
1691
+ * @param wasmModule The `WasmModule` that provides access to the native functions.
1692
+ * @param outputVarIds The output variable IDs for this model.
1693
+ */
1694
+ constructor(wasmModule) {
1695
+ this.wasmModule = wasmModule;
1696
+ function getNumberValue(funcName) {
1697
+ return wasmModule.cwrap(funcName, "number", [])();
1698
+ }
1699
+ this.startTime = getNumberValue("getInitialTime");
1700
+ this.endTime = getNumberValue("getFinalTime");
1701
+ this.saveFreq = getNumberValue("getSaveper");
1702
+ this.numSavePoints = Math.round((this.endTime - this.startTime) / this.saveFreq) + 1;
1703
+ this.outputVarIds = wasmModule.outputVarIds;
1704
+ this.modelListing = wasmModule.modelListing;
1705
+ this.wasmSetLookup = wasmModule.cwrap("setLookup", null, [
1706
+ "number",
1707
+ "number",
1708
+ "number",
1709
+ "number"
1710
+ ]);
1711
+ this.wasmRunModel = wasmModule.cwrap("runModelWithBuffers", null, [
1712
+ "number",
1713
+ "number",
1714
+ "number",
1715
+ "number",
1716
+ "number",
1717
+ "number"
1718
+ ]);
1719
+ }
1720
+ runModel(params) {
1721
+ const lookups = params.getLookups();
1722
+ if (lookups !== void 0) for (const lookupDef of lookups) {
1723
+ const varSpec = lookupDef.varRef.varSpec;
1724
+ const numSubElements = varSpec.subscriptIndices?.length || 0;
1725
+ let subIndicesAddress;
1726
+ if (numSubElements > 0) {
1727
+ if (this.lookupSubIndicesBuffer === void 0 || this.lookupSubIndicesBuffer.numElements < numSubElements) {
1728
+ this.lookupSubIndicesBuffer?.dispose();
1729
+ this.lookupSubIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numSubElements);
1730
+ }
1731
+ this.lookupSubIndicesBuffer.getArrayView().set(varSpec.subscriptIndices);
1732
+ subIndicesAddress = this.lookupSubIndicesBuffer.getAddress();
1733
+ } else subIndicesAddress = 0;
1734
+ let pointsAddress;
1735
+ let numPoints;
1736
+ if (lookupDef.points) {
1737
+ const numLookupElements = lookupDef.points.length;
1738
+ if (this.lookupDataBuffer === void 0 || this.lookupDataBuffer.numElements < numLookupElements) {
1739
+ this.lookupDataBuffer?.dispose();
1740
+ this.lookupDataBuffer = createFloat64WasmBuffer(this.wasmModule, numLookupElements);
1741
+ }
1742
+ this.lookupDataBuffer.getArrayView().set(lookupDef.points);
1743
+ pointsAddress = this.lookupDataBuffer.getAddress();
1744
+ numPoints = numLookupElements / 2;
1745
+ } else {
1746
+ pointsAddress = 0;
1747
+ numPoints = 0;
1748
+ }
1749
+ const varIndex = varSpec.varIndex;
1750
+ this.wasmSetLookup(varIndex, subIndicesAddress, pointsAddress, numPoints);
1751
+ }
1752
+ let constantIndicesBuffer;
1753
+ let constantValuesBuffer;
1754
+ const constants = params.getConstants();
1755
+ if (constants !== void 0 && constants.length > 0) {
1756
+ let totalIndicesSize = 1;
1757
+ for (const constantDef of constants) {
1758
+ const numSubElements = constantDef.varRef.varSpec.subscriptIndices?.length || 0;
1759
+ totalIndicesSize += 2 + numSubElements;
1760
+ }
1761
+ if (this.constantIndicesBuffer === void 0 || this.constantIndicesBuffer.numElements < totalIndicesSize) {
1762
+ this.constantIndicesBuffer?.dispose();
1763
+ this.constantIndicesBuffer = createInt32WasmBuffer(this.wasmModule, totalIndicesSize);
1764
+ }
1765
+ const numConstants = constants.length;
1766
+ if (this.constantValuesBuffer === void 0 || this.constantValuesBuffer.numElements < numConstants) {
1767
+ this.constantValuesBuffer?.dispose();
1768
+ this.constantValuesBuffer = createFloat64WasmBuffer(this.wasmModule, numConstants);
1769
+ }
1770
+ const indicesView = this.constantIndicesBuffer.getArrayView();
1771
+ const valuesView = this.constantValuesBuffer.getArrayView();
1772
+ let indicesOffset = 0;
1773
+ let valuesOffset = 0;
1774
+ indicesView[indicesOffset++] = numConstants;
1775
+ for (const constantDef of constants) {
1776
+ const varSpec = constantDef.varRef.varSpec;
1777
+ const numSubElements = varSpec.subscriptIndices?.length || 0;
1778
+ indicesView[indicesOffset++] = varSpec.varIndex;
1779
+ indicesView[indicesOffset++] = numSubElements;
1780
+ if (numSubElements > 0) for (let i = 0; i < numSubElements; i++) indicesView[indicesOffset++] = varSpec.subscriptIndices[i];
1781
+ valuesView[valuesOffset++] = constantDef.value;
1782
+ }
1783
+ constantIndicesBuffer = this.constantIndicesBuffer;
1784
+ constantValuesBuffer = this.constantValuesBuffer;
1785
+ } else {
1786
+ constantIndicesBuffer = void 0;
1787
+ constantValuesBuffer = void 0;
1788
+ }
1789
+ params.copyInputs(this.inputsBuffer?.getArrayView(), (numElements) => {
1790
+ this.inputsBuffer?.dispose();
1791
+ this.inputsBuffer = createFloat64WasmBuffer(this.wasmModule, numElements);
1792
+ return this.inputsBuffer.getArrayView();
1793
+ });
1794
+ let outputIndicesBuffer;
1795
+ if (params.getOutputIndicesLength() > 0) {
1796
+ params.copyOutputIndices(this.outputIndicesBuffer?.getArrayView(), (numElements) => {
1797
+ this.outputIndicesBuffer?.dispose();
1798
+ this.outputIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numElements);
1799
+ return this.outputIndicesBuffer.getArrayView();
1800
+ });
1801
+ outputIndicesBuffer = this.outputIndicesBuffer;
1802
+ } else outputIndicesBuffer = void 0;
1803
+ const outputsLengthInElements = params.getOutputsLength();
1804
+ if (this.outputsBuffer === void 0 || this.outputsBuffer.numElements < outputsLengthInElements) {
1805
+ this.outputsBuffer?.dispose();
1806
+ this.outputsBuffer = createFloat64WasmBuffer(this.wasmModule, outputsLengthInElements);
1807
+ }
1808
+ const t0 = perfNow();
1809
+ this.wasmRunModel(this.inputsBuffer?.getAddress() || 0, 0, this.outputsBuffer.getAddress(), outputIndicesBuffer?.getAddress() || 0, constantValuesBuffer?.getAddress() || 0, constantIndicesBuffer?.getAddress() || 0);
1810
+ const elapsed = perfElapsed(t0);
1811
+ params.storeOutputs(this.outputsBuffer.getArrayView());
1812
+ params.storeElapsedTime(elapsed);
1813
+ }
1814
+ terminate() {
1815
+ this.inputsBuffer?.dispose();
1816
+ this.inputsBuffer = void 0;
1817
+ this.outputsBuffer?.dispose();
1818
+ this.outputsBuffer = void 0;
1819
+ this.outputIndicesBuffer?.dispose();
1820
+ this.outputIndicesBuffer = void 0;
1821
+ this.constantValuesBuffer?.dispose();
1822
+ this.constantValuesBuffer = void 0;
1823
+ this.constantIndicesBuffer?.dispose();
1824
+ this.constantIndicesBuffer = void 0;
1825
+ }
1974
1826
  };
1827
+ /**
1828
+ * Initialize the wasm model.
1829
+ *
1830
+ * @hidden This is not part of the public API; only the top-level `createRunnableModel`
1831
+ * function is exposed in the public API.
1832
+ *
1833
+ * @param wasmModule The `WasmModule` that wraps the `wasm` binary.
1834
+ * @return The initialized `WasmModel` instance.
1835
+ */
1975
1836
  function initWasmModel(wasmModule) {
1976
- return new WasmModel(wasmModule);
1837
+ return new WasmModel(wasmModule);
1977
1838
  }
1978
-
1979
- // src/wasm-model/_mocks/mock-wasm-module.ts
1839
+ //#endregion
1840
+ //#region src/wasm-model/_mocks/mock-wasm-module.ts
1841
+ /**
1842
+ * @hidden This type is not part of the public API; it is exposed only for use in
1843
+ * tests in the runtime-async package.
1844
+ */
1980
1845
  var MockWasmModule = class {
1981
- constructor(options) {
1982
- // from WasmModule interface
1983
- this.kind = "wasm";
1984
- // Start at 8 so that we can treat 0 as NULL
1985
- this.mallocOffset = 8;
1986
- this.allocs = /* @__PURE__ */ new Map();
1987
- this.lookups = /* @__PURE__ */ new Map();
1988
- this.constants = /* @__PURE__ */ new Map();
1989
- this.initialTime = options.initialTime;
1990
- this.finalTime = options.finalTime;
1991
- this.outputVarIds = options.outputVarIds;
1992
- if (options.listingJson) {
1993
- this.modelListing = JSON.parse(options.listingJson);
1994
- this.internalListing = new ModelListing(this.modelListing);
1995
- }
1996
- this.onRunModel = options.onRunModel;
1997
- this.heap = new ArrayBuffer(8192);
1998
- this.HEAP32 = new Int32Array(this.heap);
1999
- this.HEAPF64 = new Float64Array(this.heap);
2000
- }
2001
- varIdForSpec(varSpec) {
2002
- for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) {
2003
- if (listingSpec.varIndex === varSpec.varIndex) {
2004
- return listingVarId;
2005
- }
2006
- }
2007
- return void 0;
2008
- }
2009
- // from WasmModule interface
2010
- cwrap(fname) {
2011
- switch (fname) {
2012
- case "getInitialTime":
2013
- return () => this.initialTime;
2014
- case "getFinalTime":
2015
- return () => this.finalTime;
2016
- case "getSaveper":
2017
- return () => 1;
2018
- case "setLookup":
2019
- return (varIndex, _subIndicesAddress, pointsAddress, numPoints) => {
2020
- const varId = this.varIdForSpec({ varIndex });
2021
- if (varId === void 0) {
2022
- throw new Error(`No lookup variable found for var index ${varIndex}`);
2023
- }
2024
- const points = new Float64Array(this.getHeapView("float64", pointsAddress));
2025
- this.lookups.set(varId, new JsModelLookup(numPoints, points));
2026
- };
2027
- case "runModelWithBuffers":
2028
- return (inputsAddress, _inputIndicesAddress, outputsAddress, outputIndicesAddress, constantValuesAddress, constantIndicesAddress) => {
2029
- const inputs = this.getHeapView("float64", inputsAddress);
2030
- const outputs = this.getHeapView("float64", outputsAddress);
2031
- const outputIndices = this.getHeapView("int32", outputIndicesAddress);
2032
- this.constants.clear();
2033
- if (constantValuesAddress !== 0 && constantIndicesAddress !== 0) {
2034
- const constantValues = this.getHeapView("float64", constantValuesAddress);
2035
- const constantIndices = this.getHeapView("int32", constantIndicesAddress);
2036
- const numConstants = constantIndices[0];
2037
- let indicesOffset = 1;
2038
- let valuesOffset = 0;
2039
- for (let i = 0; i < numConstants; i++) {
2040
- const varIndex = constantIndices[indicesOffset++];
2041
- const subCount = constantIndices[indicesOffset++];
2042
- indicesOffset += subCount;
2043
- const varId = this.varIdForSpec({ varIndex });
2044
- if (varId) {
2045
- this.constants.set(varId, constantValues[valuesOffset++]);
2046
- }
2047
- }
2048
- }
2049
- this.onRunModel(
2050
- inputs,
2051
- outputs,
2052
- this.constants.size > 0 ? this.constants : void 0,
2053
- this.lookups,
2054
- outputIndices
2055
- );
2056
- this.constants.clear();
2057
- };
2058
- default:
2059
- throw new Error(`Unhandled call to cwrap with function name '${fname}'`);
2060
- }
2061
- }
2062
- // from WasmModule interface
2063
- _malloc(lengthInBytes) {
2064
- const currentOffset = this.mallocOffset;
2065
- this.allocs.set(currentOffset, lengthInBytes);
2066
- if (lengthInBytes > 0) {
2067
- this.mallocOffset += lengthInBytes;
2068
- } else {
2069
- this.mallocOffset += 8;
2070
- }
2071
- return currentOffset;
2072
- }
2073
- // from WasmModule interface
2074
- _free() {
2075
- }
2076
- getHeapView(kind, address) {
2077
- if (address === 0) {
2078
- return void 0;
2079
- }
2080
- const lengthInBytes = this.allocs.get(address);
2081
- if (lengthInBytes === void 0) {
2082
- throw new Error("Failed to locate heap allocation");
2083
- }
2084
- if (kind === "float64") {
2085
- const offset = address / 8;
2086
- return this.HEAPF64.subarray(offset, offset + lengthInBytes / 8);
2087
- } else {
2088
- const offset = address / 4;
2089
- return this.HEAP32.subarray(offset, offset + lengthInBytes / 4);
2090
- }
2091
- }
1846
+ constructor(options) {
1847
+ this.kind = "wasm";
1848
+ this.mallocOffset = 8;
1849
+ this.allocs = /* @__PURE__ */ new Map();
1850
+ this.lookups = /* @__PURE__ */ new Map();
1851
+ this.constants = /* @__PURE__ */ new Map();
1852
+ this.initialTime = options.initialTime;
1853
+ this.finalTime = options.finalTime;
1854
+ this.outputVarIds = options.outputVarIds;
1855
+ if (options.listingJson) {
1856
+ this.modelListing = JSON.parse(options.listingJson);
1857
+ this.internalListing = new ModelListing(this.modelListing);
1858
+ }
1859
+ this.onRunModel = options.onRunModel;
1860
+ this.heap = /* @__PURE__ */ new ArrayBuffer(8192);
1861
+ this.HEAP32 = new Int32Array(this.heap);
1862
+ this.HEAPF64 = new Float64Array(this.heap);
1863
+ }
1864
+ varIdForSpec(varSpec) {
1865
+ for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) if (listingSpec.varIndex === varSpec.varIndex) return listingVarId;
1866
+ }
1867
+ cwrap(fname) {
1868
+ switch (fname) {
1869
+ case "getInitialTime": return () => this.initialTime;
1870
+ case "getFinalTime": return () => this.finalTime;
1871
+ case "getSaveper": return () => 1;
1872
+ case "setLookup": return (varIndex, _subIndicesAddress, pointsAddress, numPoints) => {
1873
+ const varId = this.varIdForSpec({ varIndex });
1874
+ if (varId === void 0) throw new Error(`No lookup variable found for var index ${varIndex}`);
1875
+ const points = new Float64Array(this.getHeapView("float64", pointsAddress));
1876
+ this.lookups.set(varId, new JsModelLookup(numPoints, points));
1877
+ };
1878
+ case "runModelWithBuffers": return (inputsAddress, _inputIndicesAddress, outputsAddress, outputIndicesAddress, constantValuesAddress, constantIndicesAddress) => {
1879
+ const inputs = this.getHeapView("float64", inputsAddress);
1880
+ const outputs = this.getHeapView("float64", outputsAddress);
1881
+ const outputIndices = this.getHeapView("int32", outputIndicesAddress);
1882
+ this.constants.clear();
1883
+ if (constantValuesAddress !== 0 && constantIndicesAddress !== 0) {
1884
+ const constantValues = this.getHeapView("float64", constantValuesAddress);
1885
+ const constantIndices = this.getHeapView("int32", constantIndicesAddress);
1886
+ const numConstants = constantIndices[0];
1887
+ let indicesOffset = 1;
1888
+ let valuesOffset = 0;
1889
+ for (let i = 0; i < numConstants; i++) {
1890
+ const varIndex = constantIndices[indicesOffset++];
1891
+ const subCount = constantIndices[indicesOffset++];
1892
+ indicesOffset += subCount;
1893
+ const varId = this.varIdForSpec({ varIndex });
1894
+ if (varId) this.constants.set(varId, constantValues[valuesOffset++]);
1895
+ }
1896
+ }
1897
+ this.onRunModel(inputs, outputs, this.constants.size > 0 ? this.constants : void 0, this.lookups, outputIndices);
1898
+ this.constants.clear();
1899
+ };
1900
+ default: throw new Error(`Unhandled call to cwrap with function name '${fname}'`);
1901
+ }
1902
+ }
1903
+ _malloc(lengthInBytes) {
1904
+ const currentOffset = this.mallocOffset;
1905
+ this.allocs.set(currentOffset, lengthInBytes);
1906
+ if (lengthInBytes > 0) this.mallocOffset += lengthInBytes;
1907
+ else this.mallocOffset += 8;
1908
+ return currentOffset;
1909
+ }
1910
+ _free() {}
1911
+ getHeapView(kind, address) {
1912
+ if (address === 0) return;
1913
+ const lengthInBytes = this.allocs.get(address);
1914
+ if (lengthInBytes === void 0) throw new Error("Failed to locate heap allocation");
1915
+ if (kind === "float64") {
1916
+ const offset = address / 8;
1917
+ return this.HEAPF64.subarray(offset, offset + lengthInBytes / 8);
1918
+ } else {
1919
+ const offset = address / 4;
1920
+ return this.HEAP32.subarray(offset, offset + lengthInBytes / 4);
1921
+ }
1922
+ }
2092
1923
  };
2093
-
2094
- // src/model-runner/synchronous-model-runner.ts
1924
+ //#endregion
1925
+ //#region src/model-runner/synchronous-model-runner.ts
1926
+ /**
1927
+ * Create a `RunnableModel` from a given `JsModel` or `WasmModule` that was generated by the
1928
+ * SDEverywhere transpiler/builder.
1929
+ *
1930
+ * @hidden This is not yet part of the public API; it is only exposed for use by
1931
+ * the runtime-async package.
1932
+ */
2095
1933
  function createRunnableModel(generatedModel) {
2096
- switch (generatedModel.kind) {
2097
- case "js":
2098
- return initJsModel(generatedModel);
2099
- case "wasm":
2100
- return initWasmModel(generatedModel);
2101
- default:
2102
- throw new Error(`Unable to identify generated model kind`);
2103
- }
1934
+ switch (generatedModel.kind) {
1935
+ case "js": return initJsModel(generatedModel);
1936
+ case "wasm": return initWasmModel(generatedModel);
1937
+ default: throw new Error(`Unable to identify generated model kind`);
1938
+ }
2104
1939
  }
1940
+ /**
1941
+ * Create a `ModelRunner` that runs a generated model on the JS thread.
1942
+ *
1943
+ * @param generatedModel A `JsModel` or `WasmModule` generated by the SDEverywhere transpiler.
1944
+ */
2105
1945
  function createSynchronousModelRunner(generatedModel) {
2106
- const runnableModel = createRunnableModel(generatedModel);
2107
- return createRunnerFromRunnableModel(runnableModel);
1946
+ return createRunnerFromRunnableModel(createRunnableModel(generatedModel));
2108
1947
  }
1948
+ /**
1949
+ * Create a `ModelRunner` that runs the given model on the JS thread.
1950
+ *
1951
+ * @param model The runnable model instance.
1952
+ */
2109
1953
  function createRunnerFromRunnableModel(model) {
2110
- const listing = model.modelListing ? new ModelListing(model.modelListing) : void 0;
2111
- const params = new ReferencedRunModelParams(listing);
2112
- let terminated = false;
2113
- const runModelSync = (inputs, outputs, options) => {
2114
- params.updateFromParams(inputs, outputs, options);
2115
- model.runModel(params);
2116
- return outputs;
2117
- };
2118
- return {
2119
- createOutputs: () => {
2120
- return new Outputs(model.outputVarIds, model.startTime, model.endTime, model.saveFreq);
2121
- },
2122
- runModel: (inputs, outputs, options) => {
2123
- if (terminated) {
2124
- return Promise.reject(new Error("Model runner has already been terminated"));
2125
- }
2126
- return Promise.resolve(runModelSync(inputs, outputs, options));
2127
- },
2128
- runModelSync: (inputs, outputs, options) => {
2129
- if (terminated) {
2130
- throw new Error("Model runner has already been terminated");
2131
- }
2132
- return runModelSync(inputs, outputs, options);
2133
- },
2134
- terminate: () => __async(null, null, function* () {
2135
- if (!terminated) {
2136
- model.terminate();
2137
- terminated = true;
2138
- }
2139
- })
2140
- };
1954
+ const params = new ReferencedRunModelParams(model.modelListing ? new ModelListing(model.modelListing) : void 0);
1955
+ let terminated = false;
1956
+ const runModelSync = (inputs, outputs, options) => {
1957
+ params.updateFromParams(inputs, outputs, options);
1958
+ model.runModel(params);
1959
+ return outputs;
1960
+ };
1961
+ return {
1962
+ createOutputs: () => {
1963
+ return new Outputs(model.outputVarIds, model.startTime, model.endTime, model.saveFreq);
1964
+ },
1965
+ runModel: (inputs, outputs, options) => {
1966
+ if (terminated) return Promise.reject(/* @__PURE__ */ new Error("Model runner has already been terminated"));
1967
+ return Promise.resolve(runModelSync(inputs, outputs, options));
1968
+ },
1969
+ runModelSync: (inputs, outputs, options) => {
1970
+ if (terminated) throw new Error("Model runner has already been terminated");
1971
+ return runModelSync(inputs, outputs, options);
1972
+ },
1973
+ terminate: async () => {
1974
+ if (!terminated) {
1975
+ model.terminate();
1976
+ terminated = true;
1977
+ }
1978
+ }
1979
+ };
2141
1980
  }
2142
-
2143
- // src/model-scheduler/model-scheduler.ts
1981
+ //#endregion
1982
+ //#region src/model-scheduler/model-scheduler.ts
1983
+ /**
1984
+ * A high-level interface that schedules the underlying `ModelRunner`.
1985
+ *
1986
+ * When one or more input values are changed, this class will schedule a model
1987
+ * run to be completed as soon as possible. When the model run has completed,
1988
+ * `onOutputsChanged` is called to notify that new output data is available.
1989
+ *
1990
+ * The `ModelRunner` is pluggable to allow for running the model synchronously
1991
+ * (on the main JavaScript thread) or asynchronously (in a Web Worker or Node.js
1992
+ * worker thread).
1993
+ */
2144
1994
  var ModelScheduler = class {
2145
- /**
2146
- * @param runner The model runner.
2147
- * @param userInputs The input values, in the same order as in the spec file passed to `sde`.
2148
- * @param outputs The structure into which the model outputs will be stored.
2149
- */
2150
- constructor(runner, userInputs, outputs) {
2151
- this.runner = runner;
2152
- this.userInputs = userInputs;
2153
- this.outputs = outputs;
2154
- /** Whether a model run has been scheduled. */
2155
- this.runNeeded = false;
2156
- /** Whether a model run is in progress. */
2157
- this.runInProgress = false;
2158
- const afterSet = () => {
2159
- this.runModelIfNeeded();
2160
- };
2161
- for (const userInput of userInputs) {
2162
- userInput.callbacks.onSet = afterSet;
2163
- }
2164
- this.currentInputs = [];
2165
- for (const userInput of userInputs) {
2166
- this.currentInputs.push(createSimpleInputValue(userInput.varId));
2167
- }
2168
- }
2169
- /**
2170
- * Schedule a model run (if not already pending). When the run is
2171
- * complete, save the outputs and call the `onOutputsChanged` callback.
2172
- */
2173
- runModelIfNeeded() {
2174
- this.runNeeded = true;
2175
- if (this.runInProgress) {
2176
- return;
2177
- } else {
2178
- this.runInProgress = true;
2179
- setTimeout(() => {
2180
- this.runModelNow();
2181
- }, 0);
2182
- }
2183
- }
2184
- /**
2185
- * Run the model asynchronously using the current set of input values.
2186
- */
2187
- runModelNow() {
2188
- return __async(this, null, function* () {
2189
- var _a;
2190
- for (let i = 0; i < this.userInputs.length; i++) {
2191
- this.currentInputs[i].set(this.userInputs[i].get());
2192
- }
2193
- try {
2194
- this.outputs = yield this.runner.runModel(this.currentInputs, this.outputs);
2195
- (_a = this.onOutputsChanged) == null ? void 0 : _a.call(this, this.outputs);
2196
- } catch (e) {
2197
- console.error(`ERROR: Failed to run model: ${e.message}`);
2198
- }
2199
- if (this.runNeeded) {
2200
- this.runNeeded = false;
2201
- setTimeout(() => {
2202
- this.runModelNow();
2203
- }, 0);
2204
- } else {
2205
- this.runNeeded = false;
2206
- this.runInProgress = false;
2207
- }
2208
- });
2209
- }
1995
+ /**
1996
+ * @param runner The model runner.
1997
+ * @param userInputs The input values, in the same order as in the spec file passed to `sde`.
1998
+ * @param outputs The structure into which the model outputs will be stored.
1999
+ */
2000
+ constructor(runner, userInputs, outputs) {
2001
+ this.runner = runner;
2002
+ this.userInputs = userInputs;
2003
+ this.outputs = outputs;
2004
+ this.runNeeded = false;
2005
+ this.runInProgress = false;
2006
+ const afterSet = () => {
2007
+ this.runModelIfNeeded();
2008
+ };
2009
+ for (const userInput of userInputs) userInput.callbacks.onSet = afterSet;
2010
+ this.currentInputs = [];
2011
+ for (const userInput of userInputs) this.currentInputs.push(createSimpleInputValue(userInput.varId));
2012
+ }
2013
+ /**
2014
+ * Schedule a model run (if not already pending). When the run is
2015
+ * complete, save the outputs and call the `onOutputsChanged` callback.
2016
+ */
2017
+ runModelIfNeeded() {
2018
+ this.runNeeded = true;
2019
+ if (this.runInProgress) return;
2020
+ else {
2021
+ this.runInProgress = true;
2022
+ setTimeout(() => {
2023
+ this.runModelNow();
2024
+ }, 0);
2025
+ }
2026
+ }
2027
+ /**
2028
+ * Run the model asynchronously using the current set of input values.
2029
+ */
2030
+ async runModelNow() {
2031
+ for (let i = 0; i < this.userInputs.length; i++) this.currentInputs[i].set(this.userInputs[i].get());
2032
+ try {
2033
+ this.outputs = await this.runner.runModel(this.currentInputs, this.outputs);
2034
+ this.onOutputsChanged?.(this.outputs);
2035
+ } catch (e) {
2036
+ console.error(`ERROR: Failed to run model: ${e.message}`);
2037
+ }
2038
+ if (this.runNeeded) {
2039
+ this.runNeeded = false;
2040
+ setTimeout(() => {
2041
+ this.runModelNow();
2042
+ }, 0);
2043
+ } else {
2044
+ this.runNeeded = false;
2045
+ this.runInProgress = false;
2046
+ }
2047
+ }
2210
2048
  };
2049
+ /**
2050
+ * Create an `InputValue` that is only used to hold a copy of another input (no callbacks).
2051
+ * @hidden
2052
+ */
2211
2053
  function createSimpleInputValue(varId) {
2212
- let currentValue = 0;
2213
- const get = () => {
2214
- return currentValue;
2215
- };
2216
- const set = (newValue) => {
2217
- currentValue = newValue;
2218
- };
2219
- const reset = () => {
2220
- set(0);
2221
- };
2222
- return { varId, get, set, reset, callbacks: {} };
2054
+ let currentValue = 0;
2055
+ const get = () => {
2056
+ return currentValue;
2057
+ };
2058
+ const set = (newValue) => {
2059
+ currentValue = newValue;
2060
+ };
2061
+ const reset = () => {
2062
+ set(0);
2063
+ };
2064
+ return {
2065
+ varId,
2066
+ get,
2067
+ set,
2068
+ reset,
2069
+ callbacks: {}
2070
+ };
2223
2071
  }
2224
-
2225
- // src/model-scheduler/multi-context-model-scheduler.ts
2072
+ //#endregion
2073
+ //#region src/model-scheduler/multi-context-model-scheduler.ts
2074
+ /**
2075
+ * A high-level interface that schedules running of the underlying `ModelRunner`.
2076
+ *
2077
+ * This class is similar to the (single context) `ModelScheduler` class, except
2078
+ * this one supports multiple contexts, each with its own distinct set of
2079
+ * inputs and outputs. This is useful for running the same underlying model
2080
+ * instance with different sets of inputs and outputs. For example, you can
2081
+ * use this to show the outputs for multiple scenarios in a single graph, or
2082
+ * multiple scenarios across different graphs.
2083
+ *
2084
+ * When input values are changed in one or more contexts, this class will schedule
2085
+ * a model run for each changed context to be completed as soon as possible.
2086
+ * When the model run has completed, the context's `onOutputsChanged` function
2087
+ * is called to notify that new output data is available for that context.
2088
+ *
2089
+ * The `ModelRunner` is pluggable to allow for running the model synchronously
2090
+ * (on the main JavaScript thread) or asynchronously (in a Web Worker or Node.js
2091
+ * worker thread).
2092
+ */
2226
2093
  var MultiContextModelScheduler = class {
2227
- /**
2228
- * @param runner The model runner.
2229
- * @param options Additional options for the scheduler.
2230
- * @param options.initialOutputs An optional `Outputs` instance that will be reused
2231
- * for the initial context. This is useful for saving memory when an `Outputs`
2232
- * instance was already created for, e.g., a initial baseline/reference run.
2233
- */
2234
- constructor(runner, options) {
2235
- this.runner = runner;
2236
- /** The contexts that hold distinct sets of inputs and outputs. */
2237
- this.contexts = [];
2238
- /** Whether a model run has been scheduled. */
2239
- this.runNeeded = false;
2240
- /** Whether a model run is in progress. */
2241
- this.runInProgress = false;
2242
- this.initialOutputs = options == null ? void 0 : options.initialOutputs;
2243
- }
2244
- /**
2245
- * Return true if the scheduler has started any model runs.
2246
- */
2247
- isStarted() {
2248
- return this.initialOutputs === void 0;
2249
- }
2250
- /**
2251
- * Add a new context that holds a distinct set of model inputs and outputs.
2252
- * These inputs and outputs are kept separate from those in other contexts,
2253
- * which allows an application to use the same underlying model to run with
2254
- * multiple I/O contexts.
2255
- *
2256
- * Note that the contexts created before the first scheduled model run
2257
- * will inherit the data from `initialOutputs` passed to the constructor,
2258
- * but contexts created after that will initially have output values set
2259
- * to zero.
2260
- *
2261
- * @param inputs The input values, in the same order as in the spec file passed to `sde`.
2262
- * @param options Additional options for the context.
2263
- * @param options.externalData Additional data that is external to the model outputs.
2264
- * For example, this can contain data that was captured from an initial reference
2265
- * run, or other static data that is displayed in graphs alongside the model
2266
- * output data in graphs.
2267
- */
2268
- addContext(inputs, options) {
2269
- let outputs;
2270
- if (this.initialOutputs !== void 0) {
2271
- if (this.contexts.length === 0) {
2272
- outputs = this.initialOutputs;
2273
- } else {
2274
- outputs = this.runner.createOutputs();
2275
- for (const varId of outputs.varIds) {
2276
- const series0 = this.initialOutputs.getSeriesForVar(varId);
2277
- const series1 = outputs.getSeriesForVar(varId);
2278
- for (let i = 0; i < series0.points.length; i++) {
2279
- series1.points[i].y = series0.points[i].y;
2280
- }
2281
- }
2282
- }
2283
- } else {
2284
- outputs = this.runner.createOutputs();
2285
- }
2286
- const context = new ModelContextImpl(inputs, outputs, options == null ? void 0 : options.externalData);
2287
- const afterSet = () => {
2288
- context.runNeeded = true;
2289
- this.runModelIfNeeded();
2290
- };
2291
- for (const input of inputs) {
2292
- input.callbacks.onSet = afterSet;
2293
- }
2294
- this.contexts.push(context);
2295
- return context;
2296
- }
2297
- /**
2298
- * Remove the given context from the set of contexts managed by the scheduler.
2299
- *
2300
- * @param context The context to remove.
2301
- */
2302
- removeContext(context) {
2303
- const index = this.contexts.findIndex((c) => c === context);
2304
- if (index >= 0) {
2305
- this.contexts.splice(index, 1);
2306
- }
2307
- }
2308
- /**
2309
- * Schedule a model run (if not already pending). When the run is
2310
- * complete, save the outputs and call the `onOutputsChanged` callback.
2311
- */
2312
- runModelIfNeeded() {
2313
- this.runNeeded = true;
2314
- if (this.runInProgress) {
2315
- return;
2316
- } else {
2317
- this.runInProgress = true;
2318
- setTimeout(() => {
2319
- this.runModelNow();
2320
- }, 0);
2321
- }
2322
- }
2323
- /**
2324
- * Run the model asynchronously for all relevant contexts.
2325
- */
2326
- runModelNow() {
2327
- return __async(this, null, function* () {
2328
- this.initialOutputs = void 0;
2329
- for (const context of this.contexts) {
2330
- if (context.runNeeded) {
2331
- context.runNeeded = false;
2332
- yield this.runModelNowForContext(context);
2333
- }
2334
- }
2335
- if (this.runNeeded) {
2336
- this.runNeeded = false;
2337
- setTimeout(() => {
2338
- this.runModelNow();
2339
- }, 0);
2340
- } else {
2341
- this.runNeeded = false;
2342
- this.runInProgress = false;
2343
- }
2344
- });
2345
- }
2346
- /**
2347
- * Run the model asynchronously using the current set of input values in the given context.
2348
- *
2349
- * @param context The context to use for the model run.
2350
- */
2351
- runModelNowForContext(context) {
2352
- return __async(this, null, function* () {
2353
- var _a;
2354
- if (this.currentInputs === void 0) {
2355
- this.currentInputs = Array(context.inputsArray.length);
2356
- }
2357
- for (let i = 0; i < context.inputsArray.length; i++) {
2358
- this.currentInputs[i] = context.inputsArray[i].get();
2359
- }
2360
- try {
2361
- yield this.runner.runModel(this.currentInputs, context.outputs);
2362
- (_a = context.onOutputsChanged) == null ? void 0 : _a.call(context);
2363
- } catch (e) {
2364
- console.error("ERROR: The scheduler encountered an error when running the model:", e);
2365
- }
2366
- });
2367
- }
2094
+ /**
2095
+ * @param runner The model runner.
2096
+ * @param options Additional options for the scheduler.
2097
+ * @param options.initialOutputs An optional `Outputs` instance that will be reused
2098
+ * for the initial context. This is useful for saving memory when an `Outputs`
2099
+ * instance was already created for, e.g., a initial baseline/reference run.
2100
+ */
2101
+ constructor(runner, options) {
2102
+ this.runner = runner;
2103
+ this.contexts = [];
2104
+ this.runNeeded = false;
2105
+ this.runInProgress = false;
2106
+ this.initialOutputs = options?.initialOutputs;
2107
+ }
2108
+ /**
2109
+ * Return true if the scheduler has started any model runs.
2110
+ */
2111
+ isStarted() {
2112
+ return this.initialOutputs === void 0;
2113
+ }
2114
+ /**
2115
+ * Add a new context that holds a distinct set of model inputs and outputs.
2116
+ * These inputs and outputs are kept separate from those in other contexts,
2117
+ * which allows an application to use the same underlying model to run with
2118
+ * multiple I/O contexts.
2119
+ *
2120
+ * Note that the contexts created before the first scheduled model run
2121
+ * will inherit the data from `initialOutputs` passed to the constructor,
2122
+ * but contexts created after that will initially have output values set
2123
+ * to zero.
2124
+ *
2125
+ * @param inputs The input values, in the same order as in the spec file passed to `sde`.
2126
+ * @param options Additional options for the context.
2127
+ * @param options.externalData Additional data that is external to the model outputs.
2128
+ * For example, this can contain data that was captured from an initial reference
2129
+ * run, or other static data that is displayed in graphs alongside the model
2130
+ * output data in graphs.
2131
+ */
2132
+ addContext(inputs, options) {
2133
+ let outputs;
2134
+ if (this.initialOutputs !== void 0) {
2135
+ if (this.contexts.length === 0) outputs = this.initialOutputs;
2136
+ else {
2137
+ outputs = this.runner.createOutputs();
2138
+ for (const varId of outputs.varIds) {
2139
+ const series0 = this.initialOutputs.getSeriesForVar(varId);
2140
+ const series1 = outputs.getSeriesForVar(varId);
2141
+ for (let i = 0; i < series0.points.length; i++) series1.points[i].y = series0.points[i].y;
2142
+ }
2143
+ }
2144
+ } else outputs = this.runner.createOutputs();
2145
+ const context = new ModelContextImpl(inputs, outputs, options?.externalData);
2146
+ const afterSet = () => {
2147
+ context.runNeeded = true;
2148
+ this.runModelIfNeeded();
2149
+ };
2150
+ for (const input of inputs) input.callbacks.onSet = afterSet;
2151
+ this.contexts.push(context);
2152
+ return context;
2153
+ }
2154
+ /**
2155
+ * Remove the given context from the set of contexts managed by the scheduler.
2156
+ *
2157
+ * @param context The context to remove.
2158
+ */
2159
+ removeContext(context) {
2160
+ const index = this.contexts.findIndex((c) => c === context);
2161
+ if (index >= 0) this.contexts.splice(index, 1);
2162
+ }
2163
+ /**
2164
+ * Schedule a model run (if not already pending). When the run is
2165
+ * complete, save the outputs and call the `onOutputsChanged` callback.
2166
+ */
2167
+ runModelIfNeeded() {
2168
+ this.runNeeded = true;
2169
+ if (this.runInProgress) return;
2170
+ else {
2171
+ this.runInProgress = true;
2172
+ setTimeout(() => {
2173
+ this.runModelNow();
2174
+ }, 0);
2175
+ }
2176
+ }
2177
+ /**
2178
+ * Run the model asynchronously for all relevant contexts.
2179
+ */
2180
+ async runModelNow() {
2181
+ this.initialOutputs = void 0;
2182
+ for (const context of this.contexts) if (context.runNeeded) {
2183
+ context.runNeeded = false;
2184
+ await this.runModelNowForContext(context);
2185
+ }
2186
+ if (this.runNeeded) {
2187
+ this.runNeeded = false;
2188
+ setTimeout(() => {
2189
+ this.runModelNow();
2190
+ }, 0);
2191
+ } else {
2192
+ this.runNeeded = false;
2193
+ this.runInProgress = false;
2194
+ }
2195
+ }
2196
+ /**
2197
+ * Run the model asynchronously using the current set of input values in the given context.
2198
+ *
2199
+ * @param context The context to use for the model run.
2200
+ */
2201
+ async runModelNowForContext(context) {
2202
+ if (this.currentInputs === void 0) this.currentInputs = Array(context.inputsArray.length);
2203
+ for (let i = 0; i < context.inputsArray.length; i++) this.currentInputs[i] = context.inputsArray[i].get();
2204
+ try {
2205
+ await this.runner.runModel(this.currentInputs, context.outputs);
2206
+ context.onOutputsChanged?.();
2207
+ } catch (e) {
2208
+ console.error("ERROR: The scheduler encountered an error when running the model:", e);
2209
+ }
2210
+ }
2368
2211
  };
2369
2212
  var ModelContextImpl = class {
2370
- /**
2371
- * @hidden This is intended for use by `MultiContextModelScheduler` only.
2372
- *
2373
- * @param inputs The input values, in the same order as in the spec file passed to `sde`.
2374
- * @param outputs The structure into which the model outputs will be stored.
2375
- * @param externalData Additional data that is external to the model outputs. For example, this can contain
2376
- * data that was captured from an initial reference run, or other static data that is displayed in graphs
2377
- * alongside the model output data in graphs.
2378
- */
2379
- constructor(inputs, outputs, externalData) {
2380
- this.externalData = externalData;
2381
- /**
2382
- * Whether a model run is needed for this context.
2383
- * @hidden This is intended for use by `MultiContextModelScheduler` only.
2384
- */
2385
- this.runNeeded = false;
2386
- this.inputsArray = Array.from(inputs);
2387
- this.outputs = outputs;
2388
- }
2389
- /**
2390
- * Return the series data for the given model output variable or external
2391
- * dataset.
2392
- *
2393
- * @param varId The ID of the output variable associated with the data.
2394
- * @param sourceName The external data source name (e.g. "Ref"), or
2395
- * undefined to use the latest model output data from this context.
2396
- */
2397
- getSeriesForVar(varId, sourceName) {
2398
- if (sourceName === void 0) {
2399
- return this.outputs.getSeriesForVar(varId);
2400
- } else {
2401
- const dataForSource = this.externalData.get(sourceName);
2402
- if (dataForSource !== void 0) {
2403
- return dataForSource.get(varId);
2404
- } else {
2405
- return void 0;
2406
- }
2407
- }
2408
- }
2409
- };
2410
- export {
2411
- BufferedRunModelParams,
2412
- MockJsModel,
2413
- MockWasmModule,
2414
- ModelListing,
2415
- ModelScheduler,
2416
- MultiContextModelScheduler,
2417
- Outputs,
2418
- ReferencedRunModelParams,
2419
- Series,
2420
- createConstantDef,
2421
- createInputValue,
2422
- createLookupDef,
2423
- createRunnableModel,
2424
- createSynchronousModelRunner,
2425
- decodeConstants,
2426
- decodeLookups,
2427
- encodeConstants,
2428
- encodeLookups,
2429
- encodeVarIndices,
2430
- execJsModel,
2431
- getEncodedConstantBufferLengths,
2432
- getEncodedLookupBufferLengths,
2433
- getEncodedVarIndicesLength,
2434
- getJsModelFunctions,
2435
- initJsModel,
2436
- initWasmModel,
2437
- perfElapsed,
2438
- perfNow
2213
+ /**
2214
+ * @hidden This is intended for use by `MultiContextModelScheduler` only.
2215
+ *
2216
+ * @param inputs The input values, in the same order as in the spec file passed to `sde`.
2217
+ * @param outputs The structure into which the model outputs will be stored.
2218
+ * @param externalData Additional data that is external to the model outputs. For example, this can contain
2219
+ * data that was captured from an initial reference run, or other static data that is displayed in graphs
2220
+ * alongside the model output data in graphs.
2221
+ */
2222
+ constructor(inputs, outputs, externalData) {
2223
+ this.externalData = externalData;
2224
+ this.runNeeded = false;
2225
+ this.inputsArray = Array.from(inputs);
2226
+ this.outputs = outputs;
2227
+ }
2228
+ /**
2229
+ * Return the series data for the given model output variable or external
2230
+ * dataset.
2231
+ *
2232
+ * @param varId The ID of the output variable associated with the data.
2233
+ * @param sourceName The external data source name (e.g. "Ref"), or
2234
+ * undefined to use the latest model output data from this context.
2235
+ */
2236
+ getSeriesForVar(varId, sourceName) {
2237
+ if (sourceName === void 0) return this.outputs.getSeriesForVar(varId);
2238
+ else {
2239
+ const dataForSource = this.externalData.get(sourceName);
2240
+ if (dataForSource !== void 0) return dataForSource.get(varId);
2241
+ else return;
2242
+ }
2243
+ }
2439
2244
  };
2245
+ //#endregion
2246
+ export { BufferedRunModelParams, MockJsModel, MockWasmModule, ModelListing, ModelScheduler, MultiContextModelScheduler, Outputs, ReferencedRunModelParams, Series, createConstantDef, createInputValue, createLookupDef, createRunnableModel, createSynchronousModelRunner, decodeConstants, decodeLookups, encodeConstants, encodeLookups, encodeVarIndices, execJsModel, getEncodedConstantBufferLengths, getEncodedLookupBufferLengths, getEncodedVarIndicesLength, getJsModelFunctions, initJsModel, initWasmModel, perfElapsed, perfNow };
2247
+
2440
2248
  //# sourceMappingURL=index.js.map