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