@sdeverywhere/runtime 0.2.2 → 0.2.3
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 +66 -39
- package/dist/index.cjs +1535 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +746 -179
- package/dist/index.d.ts +746 -179
- package/dist/index.js +1519 -215
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -53,145 +53,31 @@ var __async = (__this, __arguments, generator) => {
|
|
|
53
53
|
// src/index.ts
|
|
54
54
|
var src_exports = {};
|
|
55
55
|
__export(src_exports, {
|
|
56
|
+
BufferedRunModelParams: () => BufferedRunModelParams,
|
|
57
|
+
MockJsModel: () => MockJsModel,
|
|
58
|
+
MockWasmModule: () => MockWasmModule,
|
|
56
59
|
ModelListing: () => ModelListing,
|
|
57
60
|
ModelScheduler: () => ModelScheduler,
|
|
58
61
|
Outputs: () => Outputs,
|
|
62
|
+
ReferencedRunModelParams: () => ReferencedRunModelParams,
|
|
59
63
|
Series: () => Series,
|
|
60
|
-
WasmBuffer: () => WasmBuffer,
|
|
61
|
-
WasmModel: () => WasmModel,
|
|
62
|
-
createFloat64WasmBuffer: () => createFloat64WasmBuffer,
|
|
63
64
|
createInputValue: () => createInputValue,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
createLookupDef: () => createLookupDef,
|
|
66
|
+
createRunnableModel: () => createRunnableModel,
|
|
67
|
+
createSynchronousModelRunner: () => createSynchronousModelRunner,
|
|
68
|
+
decodeLookups: () => decodeLookups,
|
|
69
|
+
encodeLookups: () => encodeLookups,
|
|
70
|
+
encodeVarIndices: () => encodeVarIndices,
|
|
71
|
+
execJsModel: () => execJsModel,
|
|
72
|
+
getEncodedLookupBufferLengths: () => getEncodedLookupBufferLengths,
|
|
73
|
+
getEncodedVarIndicesLength: () => getEncodedVarIndicesLength,
|
|
74
|
+
getJsModelFunctions: () => getJsModelFunctions,
|
|
75
|
+
initJsModel: () => initJsModel,
|
|
76
|
+
initWasmModel: () => initWasmModel
|
|
70
77
|
});
|
|
71
78
|
module.exports = __toCommonJS(src_exports);
|
|
72
79
|
|
|
73
|
-
// src/
|
|
74
|
-
var WasmBuffer = class {
|
|
75
|
-
/**
|
|
76
|
-
* @param wasmModule The `WasmModule` used to initialize the memory.
|
|
77
|
-
* @param byteOffset The byte offset within the wasm heap.
|
|
78
|
-
* @param heapArray The array view on the underlying heap buffer.
|
|
79
|
-
*/
|
|
80
|
-
constructor(wasmModule, byteOffset, heapArray) {
|
|
81
|
-
this.wasmModule = wasmModule;
|
|
82
|
-
this.byteOffset = byteOffset;
|
|
83
|
-
this.heapArray = heapArray;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* @return An `ArrType` view on the underlying heap buffer.
|
|
87
|
-
*/
|
|
88
|
-
getArrayView() {
|
|
89
|
-
return this.heapArray;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* @return The raw address of the underlying heap buffer.
|
|
93
|
-
* @hidden This is intended for use by `WasmModel` only.
|
|
94
|
-
*/
|
|
95
|
-
getAddress() {
|
|
96
|
-
return this.byteOffset;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Dispose the buffer by freeing the allocated heap memory.
|
|
100
|
-
*/
|
|
101
|
-
dispose() {
|
|
102
|
-
if (this.heapArray) {
|
|
103
|
-
this.wasmModule._free(this.byteOffset);
|
|
104
|
-
this.heapArray = void 0;
|
|
105
|
-
this.byteOffset = void 0;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
function createInt32WasmBuffer(wasmModule, numElements) {
|
|
110
|
-
const elemSizeInBytes = 4;
|
|
111
|
-
const lengthInBytes = numElements * elemSizeInBytes;
|
|
112
|
-
const byteOffset = wasmModule._malloc(lengthInBytes);
|
|
113
|
-
const elemOffset = byteOffset / elemSizeInBytes;
|
|
114
|
-
const heapArray = wasmModule.HEAP32.subarray(elemOffset, elemOffset + numElements);
|
|
115
|
-
return new WasmBuffer(wasmModule, byteOffset, heapArray);
|
|
116
|
-
}
|
|
117
|
-
function createFloat64WasmBuffer(wasmModule, numElements) {
|
|
118
|
-
const elemSizeInBytes = 8;
|
|
119
|
-
const lengthInBytes = numElements * elemSizeInBytes;
|
|
120
|
-
const byteOffset = wasmModule._malloc(lengthInBytes);
|
|
121
|
-
const elemOffset = byteOffset / elemSizeInBytes;
|
|
122
|
-
const heapArray = wasmModule.HEAPF64.subarray(elemOffset, elemOffset + numElements);
|
|
123
|
-
return new WasmBuffer(wasmModule, byteOffset, heapArray);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// src/wasm-model/wasm-model.ts
|
|
127
|
-
var indicesPerOutput = 4;
|
|
128
|
-
var WasmModel = class {
|
|
129
|
-
/**
|
|
130
|
-
* @param wasmModule The `WasmModule` that provides access to the native functions.
|
|
131
|
-
*/
|
|
132
|
-
constructor(wasmModule) {
|
|
133
|
-
function getNumberValue(funcName) {
|
|
134
|
-
const wasmGetValue = wasmModule.cwrap(funcName, "number", []);
|
|
135
|
-
return wasmGetValue();
|
|
136
|
-
}
|
|
137
|
-
this.startTime = getNumberValue("getInitialTime");
|
|
138
|
-
this.endTime = getNumberValue("getFinalTime");
|
|
139
|
-
this.saveFreq = getNumberValue("getSaveper");
|
|
140
|
-
try {
|
|
141
|
-
this.maxOutputIndices = getNumberValue("getMaxOutputIndices");
|
|
142
|
-
} catch (e) {
|
|
143
|
-
this.maxOutputIndices = 0;
|
|
144
|
-
}
|
|
145
|
-
this.numSavePoints = Math.round((this.endTime - this.startTime) / this.saveFreq) + 1;
|
|
146
|
-
this.wasmRunModel = wasmModule.cwrap("runModelWithBuffers", null, ["number", "number", "number"]);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Run the model, using inputs from the `inputs` buffer, and writing outputs into
|
|
150
|
-
* the `outputs` buffer.
|
|
151
|
-
*
|
|
152
|
-
* @param inputs The buffer containing inputs in the order expected by the model.
|
|
153
|
-
* @param outputs The buffer into which the model will store output values.
|
|
154
|
-
* @param outputIndices The buffer used to control which variables are written to `outputs`.
|
|
155
|
-
*/
|
|
156
|
-
runModel(inputs, outputs, outputIndices) {
|
|
157
|
-
this.wasmRunModel(inputs.getAddress(), outputs.getAddress(), (outputIndices == null ? void 0 : outputIndices.getAddress()) || 0);
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
function initWasmModelAndBuffers(wasmModule, numInputs, outputVarIds) {
|
|
161
|
-
const model = new WasmModel(wasmModule);
|
|
162
|
-
const inputsBuffer = createFloat64WasmBuffer(wasmModule, numInputs);
|
|
163
|
-
const outputVarCount = Math.max(outputVarIds.length, model.maxOutputIndices);
|
|
164
|
-
const outputsBuffer = createFloat64WasmBuffer(wasmModule, outputVarCount * model.numSavePoints);
|
|
165
|
-
let outputIndicesBuffer;
|
|
166
|
-
if (model.maxOutputIndices > 0) {
|
|
167
|
-
outputIndicesBuffer = createInt32WasmBuffer(wasmModule, model.maxOutputIndices * indicesPerOutput);
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
model,
|
|
171
|
-
inputsBuffer,
|
|
172
|
-
outputsBuffer,
|
|
173
|
-
outputIndicesBuffer,
|
|
174
|
-
outputVarIds
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function updateOutputIndices(indicesArray, outputVarSpecs) {
|
|
178
|
-
var _a;
|
|
179
|
-
if (indicesArray.length < outputVarSpecs.length * indicesPerOutput) {
|
|
180
|
-
throw new Error("Length of indicesArray must be large enough to accommodate the given outputVarSpecs");
|
|
181
|
-
}
|
|
182
|
-
let offset = 0;
|
|
183
|
-
for (const outputVarSpec of outputVarSpecs) {
|
|
184
|
-
const subCount = ((_a = outputVarSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
|
|
185
|
-
indicesArray[offset + 0] = outputVarSpec.varIndex;
|
|
186
|
-
indicesArray[offset + 1] = subCount > 0 ? outputVarSpec.subscriptIndices[0] : 0;
|
|
187
|
-
indicesArray[offset + 2] = subCount > 1 ? outputVarSpec.subscriptIndices[1] : 0;
|
|
188
|
-
indicesArray[offset + 3] = subCount > 2 ? outputVarSpec.subscriptIndices[2] : 0;
|
|
189
|
-
offset += indicesPerOutput;
|
|
190
|
-
}
|
|
191
|
-
indicesArray.fill(0, offset);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// src/model-runner/inputs.ts
|
|
80
|
+
// src/_shared/inputs.ts
|
|
195
81
|
function createInputValue(varId, defaultValue, initialValue) {
|
|
196
82
|
let currentValue = initialValue !== void 0 ? initialValue : defaultValue;
|
|
197
83
|
const callbacks = {};
|
|
@@ -211,7 +97,7 @@ function createInputValue(varId, defaultValue, initialValue) {
|
|
|
211
97
|
return { varId, get, set, reset, callbacks };
|
|
212
98
|
}
|
|
213
99
|
|
|
214
|
-
// src/
|
|
100
|
+
// src/_shared/outputs.ts
|
|
215
101
|
var import_neverthrow = require("neverthrow");
|
|
216
102
|
var Series = class _Series {
|
|
217
103
|
/**
|
|
@@ -338,102 +224,132 @@ function validateNumber(x) {
|
|
|
338
224
|
}
|
|
339
225
|
}
|
|
340
226
|
|
|
341
|
-
// src/
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
227
|
+
// src/_shared/var-indices.ts
|
|
228
|
+
function getEncodedVarIndicesLength(varSpecs) {
|
|
229
|
+
var _a;
|
|
230
|
+
let length = 1;
|
|
231
|
+
for (const varSpec of varSpecs) {
|
|
232
|
+
length += 2;
|
|
233
|
+
const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
|
|
234
|
+
length += subCount;
|
|
346
235
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
236
|
+
return length;
|
|
237
|
+
}
|
|
238
|
+
function encodeVarIndices(varSpecs, indicesArray) {
|
|
239
|
+
let offset = 0;
|
|
240
|
+
indicesArray[offset++] = varSpecs.length;
|
|
241
|
+
for (const varSpec of varSpecs) {
|
|
242
|
+
indicesArray[offset++] = varSpec.varIndex;
|
|
243
|
+
const subs = varSpec.subscriptIndices;
|
|
244
|
+
const subCount = (subs == null ? void 0 : subs.length) || 0;
|
|
245
|
+
indicesArray[offset++] = subCount;
|
|
246
|
+
for (let i = 0; i < subCount; i++) {
|
|
247
|
+
indicesArray[offset++] = subs[i];
|
|
248
|
+
}
|
|
351
249
|
}
|
|
352
250
|
}
|
|
353
|
-
function
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const
|
|
359
|
-
|
|
251
|
+
function getEncodedLookupBufferLengths(lookupDefs) {
|
|
252
|
+
var _a;
|
|
253
|
+
let lookupIndicesLength = 1;
|
|
254
|
+
let lookupsLength = 0;
|
|
255
|
+
for (const lookupDef of lookupDefs) {
|
|
256
|
+
const varSpec = lookupDef.varRef.varSpec;
|
|
257
|
+
if (varSpec === void 0) {
|
|
258
|
+
throw new Error("Cannot compute lookup buffer lengths until all lookup var specs are defined");
|
|
259
|
+
}
|
|
260
|
+
lookupIndicesLength += 2;
|
|
261
|
+
const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
|
|
262
|
+
lookupIndicesLength += subCount;
|
|
263
|
+
lookupIndicesLength += 2;
|
|
264
|
+
lookupsLength += lookupDef.points.length;
|
|
360
265
|
}
|
|
266
|
+
return {
|
|
267
|
+
lookupIndicesLength,
|
|
268
|
+
lookupsLength
|
|
269
|
+
};
|
|
361
270
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
271
|
+
function encodeLookups(lookupDefs, lookupIndicesArray, lookupsArray) {
|
|
272
|
+
let li = 0;
|
|
273
|
+
lookupIndicesArray[li++] = lookupDefs.length;
|
|
274
|
+
let lookupDataOffset = 0;
|
|
275
|
+
for (const lookupDef of lookupDefs) {
|
|
276
|
+
const varSpec = lookupDef.varRef.varSpec;
|
|
277
|
+
lookupIndicesArray[li++] = varSpec.varIndex;
|
|
278
|
+
const subs = varSpec.subscriptIndices;
|
|
279
|
+
const subCount = (subs == null ? void 0 : subs.length) || 0;
|
|
280
|
+
lookupIndicesArray[li++] = subCount;
|
|
281
|
+
for (let i = 0; i < subCount; i++) {
|
|
282
|
+
lookupIndicesArray[li++] = subs[i];
|
|
283
|
+
}
|
|
284
|
+
lookupIndicesArray[li++] = lookupDataOffset;
|
|
285
|
+
lookupIndicesArray[li++] = lookupDef.points.length;
|
|
286
|
+
lookupsArray == null ? void 0 : lookupsArray.set(lookupDef.points, lookupDataOffset);
|
|
287
|
+
lookupDataOffset += lookupDef.points.length;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function decodeLookups(lookupIndicesArray, lookupsArray) {
|
|
291
|
+
const lookupDefs = [];
|
|
292
|
+
let li = 0;
|
|
293
|
+
const lookupCount = lookupIndicesArray[li++];
|
|
294
|
+
for (let i = 0; i < lookupCount; i++) {
|
|
295
|
+
const varIndex = lookupIndicesArray[li++];
|
|
296
|
+
const subCount = lookupIndicesArray[li++];
|
|
297
|
+
const subscriptIndices = subCount > 0 ? Array(subCount) : void 0;
|
|
298
|
+
for (let subIndex = 0; subIndex < subCount; subIndex++) {
|
|
299
|
+
subscriptIndices[subIndex] = lookupIndicesArray[li++];
|
|
300
|
+
}
|
|
301
|
+
const lookupDataOffset = lookupIndicesArray[li++];
|
|
302
|
+
const lookupDataLength = lookupIndicesArray[li++];
|
|
303
|
+
const varSpec = {
|
|
304
|
+
varIndex,
|
|
305
|
+
subscriptIndices
|
|
306
|
+
};
|
|
307
|
+
let points;
|
|
308
|
+
if (lookupsArray) {
|
|
309
|
+
points = lookupsArray.slice(lookupDataOffset, lookupDataOffset + lookupDataLength);
|
|
384
310
|
} else {
|
|
385
|
-
|
|
311
|
+
points = new Float64Array(0);
|
|
386
312
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
313
|
+
lookupDefs.push({
|
|
314
|
+
varRef: {
|
|
315
|
+
varSpec
|
|
316
|
+
},
|
|
317
|
+
points
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return lookupDefs;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/_shared/lookup-def.ts
|
|
324
|
+
function createLookupDef(varRef, points) {
|
|
325
|
+
const flatPoints = new Float64Array(points.length * 2);
|
|
326
|
+
let i = 0;
|
|
327
|
+
for (const p of points) {
|
|
328
|
+
flatPoints[i++] = p.x;
|
|
329
|
+
flatPoints[i++] = p.y;
|
|
330
|
+
}
|
|
393
331
|
return {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
},
|
|
397
|
-
runModel: (inputs, outputs) => {
|
|
398
|
-
if (terminated) {
|
|
399
|
-
return Promise.reject(new Error("Model runner has already been terminated"));
|
|
400
|
-
}
|
|
401
|
-
return Promise.resolve(runModelSync(inputs, outputs));
|
|
402
|
-
},
|
|
403
|
-
runModelSync: (inputs, outputs) => {
|
|
404
|
-
if (terminated) {
|
|
405
|
-
throw new Error("Model runner has already been terminated");
|
|
406
|
-
}
|
|
407
|
-
return runModelSync(inputs, outputs);
|
|
408
|
-
},
|
|
409
|
-
terminate: () => {
|
|
410
|
-
if (!terminated) {
|
|
411
|
-
terminated = true;
|
|
412
|
-
}
|
|
413
|
-
return Promise.resolve();
|
|
414
|
-
}
|
|
332
|
+
varRef,
|
|
333
|
+
points: flatPoints
|
|
415
334
|
};
|
|
416
335
|
}
|
|
417
336
|
|
|
418
|
-
// src/model-
|
|
337
|
+
// src/model-listing/model-listing.ts
|
|
419
338
|
var ModelListing = class {
|
|
420
|
-
constructor(
|
|
339
|
+
constructor(listingObj) {
|
|
421
340
|
this.varSpecs = /* @__PURE__ */ new Map();
|
|
422
|
-
const modelJson = JSON.parse(modelJsonString);
|
|
423
341
|
const dimensions = /* @__PURE__ */ new Map();
|
|
424
|
-
for (const dimInfo of
|
|
425
|
-
const dimId = dimInfo.
|
|
342
|
+
for (const dimInfo of listingObj.dimensions) {
|
|
343
|
+
const dimId = dimInfo.id;
|
|
426
344
|
const subscripts = [];
|
|
427
|
-
for (let i = 0; i < dimInfo.
|
|
345
|
+
for (let i = 0; i < dimInfo.subIds.length; i++) {
|
|
428
346
|
subscripts.push({
|
|
429
|
-
id: dimInfo.
|
|
430
|
-
// name: dimInfo.modelValue[i]
|
|
347
|
+
id: dimInfo.subIds[i],
|
|
431
348
|
index: i
|
|
432
349
|
});
|
|
433
350
|
}
|
|
434
351
|
dimensions.set(dimId, {
|
|
435
352
|
id: dimId,
|
|
436
|
-
// name: dimInfo.modelName,
|
|
437
353
|
subscripts
|
|
438
354
|
});
|
|
439
355
|
}
|
|
@@ -445,15 +361,12 @@ var ModelListing = class {
|
|
|
445
361
|
return dim;
|
|
446
362
|
}
|
|
447
363
|
const baseVarIds = /* @__PURE__ */ new Set();
|
|
448
|
-
for (const v of
|
|
449
|
-
const baseVarId = varIdWithoutSubscripts(v.
|
|
364
|
+
for (const v of listingObj.variables) {
|
|
365
|
+
const baseVarId = varIdWithoutSubscripts(v.id);
|
|
450
366
|
if (!baseVarIds.has(baseVarId)) {
|
|
451
|
-
const dimIds = v.
|
|
367
|
+
const dimIds = v.dimIds || [];
|
|
452
368
|
const dimensions2 = dimIds.map(dimensionForId);
|
|
453
369
|
if (dimensions2.length > 0) {
|
|
454
|
-
if (dimensions2.length > 3) {
|
|
455
|
-
throw new Error("Variables with more than 3 dimensions not currently supported");
|
|
456
|
-
}
|
|
457
370
|
const dimSubs = [];
|
|
458
371
|
for (const dim of dimensions2) {
|
|
459
372
|
dimSubs.push(dim.subscripts);
|
|
@@ -464,19 +377,34 @@ var ModelListing = class {
|
|
|
464
377
|
const subIndices = combo.map((sub) => sub.index);
|
|
465
378
|
const fullVarId = `${baseVarId}[${subs}]`;
|
|
466
379
|
this.varSpecs.set(fullVarId, {
|
|
467
|
-
varIndex: v.
|
|
380
|
+
varIndex: v.index,
|
|
468
381
|
subscriptIndices: subIndices
|
|
469
382
|
});
|
|
470
383
|
}
|
|
471
384
|
} else {
|
|
472
385
|
this.varSpecs.set(baseVarId, {
|
|
473
|
-
varIndex: v.
|
|
386
|
+
varIndex: v.index
|
|
474
387
|
});
|
|
475
388
|
}
|
|
476
389
|
baseVarIds.add(baseVarId);
|
|
477
390
|
}
|
|
478
391
|
}
|
|
479
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Return the `VarSpec` for the given variable ID, or undefined if there is no spec defined
|
|
395
|
+
* in the listing for that variable.
|
|
396
|
+
*/
|
|
397
|
+
getSpecForVarId(varId) {
|
|
398
|
+
return this.varSpecs.get(varId);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Return the `VarSpec` for the given variable name, or undefined if there is no spec defined
|
|
402
|
+
* in the listing for that variable.
|
|
403
|
+
*/
|
|
404
|
+
getSpecForVarName(varName) {
|
|
405
|
+
const varId = sdeVarIdForVensimVarName(varName);
|
|
406
|
+
return this.varSpecs.get(varId);
|
|
407
|
+
}
|
|
480
408
|
/**
|
|
481
409
|
* Create a new `Outputs` instance that uses the same start/end years as the given "normal"
|
|
482
410
|
* `Outputs` instance but is prepared for reading the specified internal variables from the model.
|
|
@@ -515,6 +443,1382 @@ function cartesianProductOf(arr) {
|
|
|
515
443
|
[[]]
|
|
516
444
|
);
|
|
517
445
|
}
|
|
446
|
+
function sdeVarIdForVensimName(name) {
|
|
447
|
+
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();
|
|
448
|
+
}
|
|
449
|
+
function sdeVarIdForVensimVarName(varName) {
|
|
450
|
+
const m = varName.match(/([^[]+)(?:\[([^\]]+)\])?/);
|
|
451
|
+
if (!m) {
|
|
452
|
+
throw new Error(`Invalid Vensim name: ${varName}`);
|
|
453
|
+
}
|
|
454
|
+
let id = sdeVarIdForVensimName(m[1]);
|
|
455
|
+
if (m[2]) {
|
|
456
|
+
const subscripts = m[2].split(",").map((x) => sdeVarIdForVensimName(x));
|
|
457
|
+
id += `[${subscripts.join(",")}]`;
|
|
458
|
+
}
|
|
459
|
+
return id;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// src/runnable-model/resolve-var-ref.ts
|
|
463
|
+
function resolveVarRef(listing, varRef, varKind) {
|
|
464
|
+
if (varRef.varSpec) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (listing === void 0) {
|
|
468
|
+
throw new Error(
|
|
469
|
+
`Unable to resolve ${varKind} variable references by name or identifier when model listing is unavailable`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
if (varRef.varId) {
|
|
473
|
+
const varSpec = listing == null ? void 0 : listing.getSpecForVarId(varRef.varId);
|
|
474
|
+
if (varSpec) {
|
|
475
|
+
varRef.varSpec = varSpec;
|
|
476
|
+
} else {
|
|
477
|
+
throw new Error(`Failed to resolve ${varKind} variable reference for varId=${varRef.varId}`);
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
const varSpec = listing == null ? void 0 : listing.getSpecForVarName(varRef.varName);
|
|
481
|
+
if (varSpec) {
|
|
482
|
+
varRef.varSpec = varSpec;
|
|
483
|
+
} else {
|
|
484
|
+
throw new Error(`Failed to resolve ${varKind} variable reference for varName='${varRef.varId}'`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/runnable-model/buffered-run-model-params.ts
|
|
490
|
+
var headerLengthInElements = 16;
|
|
491
|
+
var extrasLengthInElements = 1;
|
|
492
|
+
var Int32Section = class {
|
|
493
|
+
constructor() {
|
|
494
|
+
this.offsetInBytes = 0;
|
|
495
|
+
this.lengthInElements = 0;
|
|
496
|
+
}
|
|
497
|
+
update(encoded, offsetInBytes, lengthInElements) {
|
|
498
|
+
this.view = lengthInElements > 0 ? new Int32Array(encoded, offsetInBytes, lengthInElements) : void 0;
|
|
499
|
+
this.offsetInBytes = offsetInBytes;
|
|
500
|
+
this.lengthInElements = lengthInElements;
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
var Float64Section = class {
|
|
504
|
+
constructor() {
|
|
505
|
+
this.offsetInBytes = 0;
|
|
506
|
+
this.lengthInElements = 0;
|
|
507
|
+
}
|
|
508
|
+
update(encoded, offsetInBytes, lengthInElements) {
|
|
509
|
+
this.view = lengthInElements > 0 ? new Float64Array(encoded, offsetInBytes, lengthInElements) : void 0;
|
|
510
|
+
this.offsetInBytes = offsetInBytes;
|
|
511
|
+
this.lengthInElements = lengthInElements;
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
var BufferedRunModelParams = class {
|
|
515
|
+
/**
|
|
516
|
+
* @param listing The model listing that is used to locate a variable that is referenced by
|
|
517
|
+
* name or identifier. If undefined, variables cannot be referenced by name or identifier,
|
|
518
|
+
* and can only be referenced using a valid `VarSpec`.
|
|
519
|
+
*/
|
|
520
|
+
constructor(listing) {
|
|
521
|
+
this.listing = listing;
|
|
522
|
+
/**
|
|
523
|
+
* The header section of the `encoded` buffer. The header declares the byte offset and length
|
|
524
|
+
* (in elements) of each section of the buffer.
|
|
525
|
+
*/
|
|
526
|
+
this.header = new Int32Section();
|
|
527
|
+
/** The extras section of the `encoded` buffer (holds elapsed time, etc). */
|
|
528
|
+
this.extras = new Float64Section();
|
|
529
|
+
/** The inputs section of the `encoded` buffer. */
|
|
530
|
+
this.inputs = new Float64Section();
|
|
531
|
+
/** The outputs section of the `encoded` buffer. */
|
|
532
|
+
this.outputs = new Float64Section();
|
|
533
|
+
/** The output indices section of the `encoded` buffer. */
|
|
534
|
+
this.outputIndices = new Int32Section();
|
|
535
|
+
/** The lookup data section of the `encoded` buffer. */
|
|
536
|
+
this.lookups = new Float64Section();
|
|
537
|
+
/** The lookup indices section of the `encoded` buffer. */
|
|
538
|
+
this.lookupIndices = new Int32Section();
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Return the encoded buffer from this instance, which can be passed to `updateFromEncodedBuffer`.
|
|
542
|
+
*/
|
|
543
|
+
getEncodedBuffer() {
|
|
544
|
+
return this.encoded;
|
|
545
|
+
}
|
|
546
|
+
// from RunModelParams interface
|
|
547
|
+
getInputs() {
|
|
548
|
+
return this.inputs.view;
|
|
549
|
+
}
|
|
550
|
+
// from RunModelParams interface
|
|
551
|
+
copyInputs(array, create) {
|
|
552
|
+
if (this.inputs.lengthInElements === 0) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (array === void 0 || array.length < this.inputs.lengthInElements) {
|
|
556
|
+
array = create(this.inputs.lengthInElements);
|
|
557
|
+
}
|
|
558
|
+
array.set(this.inputs.view);
|
|
559
|
+
}
|
|
560
|
+
// from RunModelParams interface
|
|
561
|
+
getOutputIndicesLength() {
|
|
562
|
+
return this.outputIndices.lengthInElements;
|
|
563
|
+
}
|
|
564
|
+
// from RunModelParams interface
|
|
565
|
+
getOutputIndices() {
|
|
566
|
+
return this.outputIndices.view;
|
|
567
|
+
}
|
|
568
|
+
// from RunModelParams interface
|
|
569
|
+
copyOutputIndices(array, create) {
|
|
570
|
+
if (this.outputIndices.lengthInElements === 0) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (array === void 0 || array.length < this.outputIndices.lengthInElements) {
|
|
574
|
+
array = create(this.outputIndices.lengthInElements);
|
|
575
|
+
}
|
|
576
|
+
array.set(this.outputIndices.view);
|
|
577
|
+
}
|
|
578
|
+
// from RunModelParams interface
|
|
579
|
+
getOutputsLength() {
|
|
580
|
+
return this.outputs.lengthInElements;
|
|
581
|
+
}
|
|
582
|
+
// from RunModelParams interface
|
|
583
|
+
getOutputs() {
|
|
584
|
+
return this.outputs.view;
|
|
585
|
+
}
|
|
586
|
+
// from RunModelParams interface
|
|
587
|
+
getOutputsObject() {
|
|
588
|
+
return void 0;
|
|
589
|
+
}
|
|
590
|
+
// from RunModelParams interface
|
|
591
|
+
storeOutputs(array) {
|
|
592
|
+
var _a;
|
|
593
|
+
(_a = this.outputs.view) == null ? void 0 : _a.set(array);
|
|
594
|
+
}
|
|
595
|
+
// from RunModelParams interface
|
|
596
|
+
getLookups() {
|
|
597
|
+
if (this.lookupIndices.lengthInElements === 0) {
|
|
598
|
+
return void 0;
|
|
599
|
+
}
|
|
600
|
+
return decodeLookups(this.lookupIndices.view, this.lookups.view);
|
|
601
|
+
}
|
|
602
|
+
// from RunModelParams interface
|
|
603
|
+
getElapsedTime() {
|
|
604
|
+
return this.extras.view[0];
|
|
605
|
+
}
|
|
606
|
+
// from RunModelParams interface
|
|
607
|
+
storeElapsedTime(elapsed) {
|
|
608
|
+
this.extras.view[0] = elapsed;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Copy the outputs buffer to the given `Outputs` instance. This should be called
|
|
612
|
+
* after the `runModel` call has completed so that the output values are copied from
|
|
613
|
+
* the internal buffer to the `Outputs` instance that was passed to `runModel`.
|
|
614
|
+
*
|
|
615
|
+
* @param outputs The `Outputs` instance into which the output values will be copied.
|
|
616
|
+
*/
|
|
617
|
+
finalizeOutputs(outputs) {
|
|
618
|
+
if (this.outputs.view) {
|
|
619
|
+
outputs.updateFromBuffer(this.outputs.view, outputs.seriesLength);
|
|
620
|
+
}
|
|
621
|
+
outputs.runTimeInMillis = this.getElapsedTime();
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Update this instance using the parameters that are passed to a `runModel` call.
|
|
625
|
+
*
|
|
626
|
+
* @param inputs The model input values (must be in the same order as in the spec file).
|
|
627
|
+
* @param outputs The structure into which the model outputs will be stored.
|
|
628
|
+
* @param options Additional options that influence the model run.
|
|
629
|
+
*/
|
|
630
|
+
updateFromParams(inputs, outputs, options) {
|
|
631
|
+
const inputsLengthInElements = inputs.length;
|
|
632
|
+
const outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
|
|
633
|
+
let outputIndicesLengthInElements;
|
|
634
|
+
const outputVarSpecs = outputs.varSpecs;
|
|
635
|
+
if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) {
|
|
636
|
+
outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
|
|
637
|
+
} else {
|
|
638
|
+
outputIndicesLengthInElements = 0;
|
|
639
|
+
}
|
|
640
|
+
let lookupsLengthInElements;
|
|
641
|
+
let lookupIndicesLengthInElements;
|
|
642
|
+
if ((options == null ? void 0 : options.lookups) !== void 0 && options.lookups.length > 0) {
|
|
643
|
+
for (const lookupDef of options.lookups) {
|
|
644
|
+
resolveVarRef(this.listing, lookupDef.varRef, "lookup");
|
|
645
|
+
}
|
|
646
|
+
const encodedLengths = getEncodedLookupBufferLengths(options.lookups);
|
|
647
|
+
lookupsLengthInElements = encodedLengths.lookupsLength;
|
|
648
|
+
lookupIndicesLengthInElements = encodedLengths.lookupIndicesLength;
|
|
649
|
+
} else {
|
|
650
|
+
lookupsLengthInElements = 0;
|
|
651
|
+
lookupIndicesLengthInElements = 0;
|
|
652
|
+
}
|
|
653
|
+
let byteOffset = 0;
|
|
654
|
+
function section(kind, lengthInElements) {
|
|
655
|
+
const sectionOffsetInBytes = byteOffset;
|
|
656
|
+
const bytesPerElement = kind === "float64" ? Float64Array.BYTES_PER_ELEMENT : Int32Array.BYTES_PER_ELEMENT;
|
|
657
|
+
const requiredSectionLengthInBytes = Math.round(lengthInElements * bytesPerElement);
|
|
658
|
+
const alignedSectionLengthInBytes = Math.ceil(requiredSectionLengthInBytes / 8) * 8;
|
|
659
|
+
byteOffset += alignedSectionLengthInBytes;
|
|
660
|
+
return sectionOffsetInBytes;
|
|
661
|
+
}
|
|
662
|
+
const headerOffsetInBytes = section("int32", headerLengthInElements);
|
|
663
|
+
const extrasOffsetInBytes = section("float64", extrasLengthInElements);
|
|
664
|
+
const inputsOffsetInBytes = section("float64", inputsLengthInElements);
|
|
665
|
+
const outputsOffsetInBytes = section("float64", outputsLengthInElements);
|
|
666
|
+
const outputIndicesOffsetInBytes = section("int32", outputIndicesLengthInElements);
|
|
667
|
+
const lookupsOffsetInBytes = section("float64", lookupsLengthInElements);
|
|
668
|
+
const lookupIndicesOffsetInBytes = section("int32", lookupIndicesLengthInElements);
|
|
669
|
+
const requiredLengthInBytes = byteOffset;
|
|
670
|
+
if (this.encoded === void 0 || this.encoded.byteLength < requiredLengthInBytes) {
|
|
671
|
+
const totalLengthInBytes = Math.ceil(requiredLengthInBytes * 1.2);
|
|
672
|
+
this.encoded = new ArrayBuffer(totalLengthInBytes);
|
|
673
|
+
this.header.update(this.encoded, headerOffsetInBytes, headerLengthInElements);
|
|
674
|
+
}
|
|
675
|
+
const headerView = this.header.view;
|
|
676
|
+
let headerIndex = 0;
|
|
677
|
+
headerView[headerIndex++] = extrasOffsetInBytes;
|
|
678
|
+
headerView[headerIndex++] = extrasLengthInElements;
|
|
679
|
+
headerView[headerIndex++] = inputsOffsetInBytes;
|
|
680
|
+
headerView[headerIndex++] = inputsLengthInElements;
|
|
681
|
+
headerView[headerIndex++] = outputsOffsetInBytes;
|
|
682
|
+
headerView[headerIndex++] = outputsLengthInElements;
|
|
683
|
+
headerView[headerIndex++] = outputIndicesOffsetInBytes;
|
|
684
|
+
headerView[headerIndex++] = outputIndicesLengthInElements;
|
|
685
|
+
headerView[headerIndex++] = lookupsOffsetInBytes;
|
|
686
|
+
headerView[headerIndex++] = lookupsLengthInElements;
|
|
687
|
+
headerView[headerIndex++] = lookupIndicesOffsetInBytes;
|
|
688
|
+
headerView[headerIndex++] = lookupIndicesLengthInElements;
|
|
689
|
+
this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
|
|
690
|
+
this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements);
|
|
691
|
+
this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
|
|
692
|
+
this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
|
|
693
|
+
this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
|
|
694
|
+
this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
|
|
695
|
+
const inputsView = this.inputs.view;
|
|
696
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
697
|
+
const input = inputs[i];
|
|
698
|
+
if (typeof input === "number") {
|
|
699
|
+
inputsView[i] = input;
|
|
700
|
+
} else {
|
|
701
|
+
inputsView[i] = input.get();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (this.outputIndices.view) {
|
|
705
|
+
encodeVarIndices(outputVarSpecs, this.outputIndices.view);
|
|
706
|
+
}
|
|
707
|
+
if (lookupIndicesLengthInElements > 0) {
|
|
708
|
+
encodeLookups(options.lookups, this.lookupIndices.view, this.lookups.view);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Update this instance using the values contained in the encoded buffer from another
|
|
713
|
+
* `BufferedRunModelParams` instance.
|
|
714
|
+
*
|
|
715
|
+
* @param buffer An encoded buffer returned by `getEncodedBuffer`.
|
|
716
|
+
*/
|
|
717
|
+
updateFromEncodedBuffer(buffer) {
|
|
718
|
+
const headerLengthInBytes = headerLengthInElements * Int32Array.BYTES_PER_ELEMENT;
|
|
719
|
+
if (buffer.byteLength < headerLengthInBytes) {
|
|
720
|
+
throw new Error("Buffer must be long enough to contain header section");
|
|
721
|
+
}
|
|
722
|
+
this.encoded = buffer;
|
|
723
|
+
const headerOffsetInBytes = 0;
|
|
724
|
+
this.header.update(this.encoded, headerOffsetInBytes, headerLengthInElements);
|
|
725
|
+
const headerView = this.header.view;
|
|
726
|
+
let headerIndex = 0;
|
|
727
|
+
const extrasOffsetInBytes = headerView[headerIndex++];
|
|
728
|
+
const extrasLengthInElements2 = headerView[headerIndex++];
|
|
729
|
+
const inputsOffsetInBytes = headerView[headerIndex++];
|
|
730
|
+
const inputsLengthInElements = headerView[headerIndex++];
|
|
731
|
+
const outputsOffsetInBytes = headerView[headerIndex++];
|
|
732
|
+
const outputsLengthInElements = headerView[headerIndex++];
|
|
733
|
+
const outputIndicesOffsetInBytes = headerView[headerIndex++];
|
|
734
|
+
const outputIndicesLengthInElements = headerView[headerIndex++];
|
|
735
|
+
const lookupsOffsetInBytes = headerView[headerIndex++];
|
|
736
|
+
const lookupsLengthInElements = headerView[headerIndex++];
|
|
737
|
+
const lookupIndicesOffsetInBytes = headerView[headerIndex++];
|
|
738
|
+
const lookupIndicesLengthInElements = headerView[headerIndex++];
|
|
739
|
+
const extrasLengthInBytes = extrasLengthInElements2 * Float64Array.BYTES_PER_ELEMENT;
|
|
740
|
+
const inputsLengthInBytes = inputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
|
|
741
|
+
const outputsLengthInBytes = outputsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
|
|
742
|
+
const outputIndicesLengthInBytes = outputIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
|
|
743
|
+
const lookupsLengthInBytes = lookupsLengthInElements * Float64Array.BYTES_PER_ELEMENT;
|
|
744
|
+
const lookupIndicesLengthInBytes = lookupIndicesLengthInElements * Int32Array.BYTES_PER_ELEMENT;
|
|
745
|
+
const requiredLengthInBytes = headerLengthInBytes + extrasLengthInBytes + inputsLengthInBytes + outputsLengthInBytes + outputIndicesLengthInBytes + lookupsLengthInBytes + lookupIndicesLengthInBytes;
|
|
746
|
+
if (buffer.byteLength < requiredLengthInBytes) {
|
|
747
|
+
throw new Error("Buffer must be long enough to contain sections declared in header");
|
|
748
|
+
}
|
|
749
|
+
this.extras.update(this.encoded, extrasOffsetInBytes, extrasLengthInElements2);
|
|
750
|
+
this.inputs.update(this.encoded, inputsOffsetInBytes, inputsLengthInElements);
|
|
751
|
+
this.outputs.update(this.encoded, outputsOffsetInBytes, outputsLengthInElements);
|
|
752
|
+
this.outputIndices.update(this.encoded, outputIndicesOffsetInBytes, outputIndicesLengthInElements);
|
|
753
|
+
this.lookups.update(this.encoded, lookupsOffsetInBytes, lookupsLengthInElements);
|
|
754
|
+
this.lookupIndices.update(this.encoded, lookupIndicesOffsetInBytes, lookupIndicesLengthInElements);
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
// src/runnable-model/referenced-run-model-params.ts
|
|
759
|
+
var ReferencedRunModelParams = class {
|
|
760
|
+
/**
|
|
761
|
+
* @param listing The model listing that is used to locate a variable that is referenced by
|
|
762
|
+
* name or identifier. If undefined, variables cannot be referenced by name or identifier,
|
|
763
|
+
* and can only be referenced using a valid `VarSpec`.
|
|
764
|
+
*/
|
|
765
|
+
constructor(listing) {
|
|
766
|
+
this.listing = listing;
|
|
767
|
+
this.outputsLengthInElements = 0;
|
|
768
|
+
this.outputIndicesLengthInElements = 0;
|
|
769
|
+
}
|
|
770
|
+
// from RunModelParams interface
|
|
771
|
+
getInputs() {
|
|
772
|
+
return void 0;
|
|
773
|
+
}
|
|
774
|
+
// from RunModelParams interface
|
|
775
|
+
copyInputs(array, create) {
|
|
776
|
+
const inputsLengthInElements = this.inputs.length;
|
|
777
|
+
if (array === void 0 || array.length < inputsLengthInElements) {
|
|
778
|
+
array = create(inputsLengthInElements);
|
|
779
|
+
}
|
|
780
|
+
for (let i = 0; i < this.inputs.length; i++) {
|
|
781
|
+
const input = this.inputs[i];
|
|
782
|
+
if (typeof input === "number") {
|
|
783
|
+
array[i] = input;
|
|
784
|
+
} else {
|
|
785
|
+
array[i] = input.get();
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
// from RunModelParams interface
|
|
790
|
+
getOutputIndicesLength() {
|
|
791
|
+
return this.outputIndicesLengthInElements;
|
|
792
|
+
}
|
|
793
|
+
// from RunModelParams interface
|
|
794
|
+
getOutputIndices() {
|
|
795
|
+
return void 0;
|
|
796
|
+
}
|
|
797
|
+
// from RunModelParams interface
|
|
798
|
+
copyOutputIndices(array, create) {
|
|
799
|
+
if (this.outputIndicesLengthInElements === 0) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (array === void 0 || array.length < this.outputIndicesLengthInElements) {
|
|
803
|
+
array = create(this.outputIndicesLengthInElements);
|
|
804
|
+
}
|
|
805
|
+
encodeVarIndices(this.outputs.varSpecs, array);
|
|
806
|
+
}
|
|
807
|
+
// from RunModelParams interface
|
|
808
|
+
getOutputsLength() {
|
|
809
|
+
return this.outputsLengthInElements;
|
|
810
|
+
}
|
|
811
|
+
// from RunModelParams interface
|
|
812
|
+
getOutputs() {
|
|
813
|
+
return void 0;
|
|
814
|
+
}
|
|
815
|
+
// from RunModelParams interface
|
|
816
|
+
getOutputsObject() {
|
|
817
|
+
return this.outputs;
|
|
818
|
+
}
|
|
819
|
+
// from RunModelParams interface
|
|
820
|
+
storeOutputs(array) {
|
|
821
|
+
if (this.outputs) {
|
|
822
|
+
const result = this.outputs.updateFromBuffer(array, this.outputs.seriesLength);
|
|
823
|
+
if (result.isErr()) {
|
|
824
|
+
throw new Error(`Failed to store outputs: ${result.error}`);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
// from RunModelParams interface
|
|
829
|
+
getLookups() {
|
|
830
|
+
if (this.lookups !== void 0 && this.lookups.length > 0) {
|
|
831
|
+
return this.lookups;
|
|
832
|
+
} else {
|
|
833
|
+
return void 0;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// from RunModelParams interface
|
|
837
|
+
getElapsedTime() {
|
|
838
|
+
var _a;
|
|
839
|
+
return (_a = this.outputs) == null ? void 0 : _a.runTimeInMillis;
|
|
840
|
+
}
|
|
841
|
+
// from RunModelParams interface
|
|
842
|
+
storeElapsedTime(elapsed) {
|
|
843
|
+
if (this.outputs) {
|
|
844
|
+
this.outputs.runTimeInMillis = elapsed;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Update this instance using the parameters that are passed to a `runModel` call.
|
|
849
|
+
*
|
|
850
|
+
* @param inputs The model input values (must be in the same order as in the spec file).
|
|
851
|
+
* @param outputs The structure into which the model outputs will be stored.
|
|
852
|
+
* @param options Additional options that influence the model run.
|
|
853
|
+
*/
|
|
854
|
+
updateFromParams(inputs, outputs, options) {
|
|
855
|
+
this.inputs = inputs;
|
|
856
|
+
this.outputs = outputs;
|
|
857
|
+
this.outputsLengthInElements = outputs.varIds.length * outputs.seriesLength;
|
|
858
|
+
this.lookups = options == null ? void 0 : options.lookups;
|
|
859
|
+
if (this.lookups) {
|
|
860
|
+
for (const lookupDef of this.lookups) {
|
|
861
|
+
resolveVarRef(this.listing, lookupDef.varRef, "lookup");
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
const outputVarSpecs = outputs.varSpecs;
|
|
865
|
+
if (outputVarSpecs !== void 0 && outputVarSpecs.length > 0) {
|
|
866
|
+
this.outputIndicesLengthInElements = getEncodedVarIndicesLength(outputVarSpecs);
|
|
867
|
+
} else {
|
|
868
|
+
this.outputIndicesLengthInElements = 0;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// src/js-model/js-model-constants.ts
|
|
874
|
+
var _NA_ = -Number.MAX_VALUE;
|
|
875
|
+
|
|
876
|
+
// src/js-model/js-model-lookup.ts
|
|
877
|
+
var JsModelLookup = class {
|
|
878
|
+
/**
|
|
879
|
+
* @param n The number of (x,y) pairs in the lookup.
|
|
880
|
+
* @param data The lookup data, as (x,y) pairs. The length of the array must be
|
|
881
|
+
* >= 2*n. Note that the data will be stored by reference, so if there is a chance
|
|
882
|
+
* that the array will be reused or modified by other code, be sure to pass in a
|
|
883
|
+
* copy of the array.
|
|
884
|
+
*/
|
|
885
|
+
constructor(n, data) {
|
|
886
|
+
this.n = n;
|
|
887
|
+
this.data = data;
|
|
888
|
+
if (data.length < n * 2) {
|
|
889
|
+
throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${n}`);
|
|
890
|
+
}
|
|
891
|
+
this.lastInput = Number.MAX_VALUE;
|
|
892
|
+
this.lastHitIndex = 0;
|
|
893
|
+
}
|
|
894
|
+
getValueForX(x, mode) {
|
|
895
|
+
return this.getValue(x, false, mode);
|
|
896
|
+
}
|
|
897
|
+
getValueForY(y) {
|
|
898
|
+
if (this.invertedData === void 0) {
|
|
899
|
+
const numValues = this.n * 2;
|
|
900
|
+
const normalData = this.data;
|
|
901
|
+
const invertedData = Array(numValues);
|
|
902
|
+
for (let i = 0; i < numValues; i += 2) {
|
|
903
|
+
invertedData[i] = normalData[i + 1];
|
|
904
|
+
invertedData[i + 1] = normalData[i];
|
|
905
|
+
}
|
|
906
|
+
this.invertedData = invertedData;
|
|
907
|
+
}
|
|
908
|
+
return this.getValue(y, true, "interpolate");
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Interpolate the y value from the array of (x,y) pairs.
|
|
912
|
+
* NOTE: The x values are assumed to be monotonically increasing.
|
|
913
|
+
*/
|
|
914
|
+
getValue(input, useInvertedData, mode) {
|
|
915
|
+
if (this.n === 0) {
|
|
916
|
+
return _NA_;
|
|
917
|
+
}
|
|
918
|
+
const data = useInvertedData ? this.invertedData : this.data;
|
|
919
|
+
const max = this.n * 2;
|
|
920
|
+
const useCachedValues = !useInvertedData;
|
|
921
|
+
let startIndex;
|
|
922
|
+
if (useCachedValues && input >= this.lastInput) {
|
|
923
|
+
startIndex = this.lastHitIndex;
|
|
924
|
+
} else {
|
|
925
|
+
startIndex = 0;
|
|
926
|
+
}
|
|
927
|
+
for (let xi = startIndex; xi < max; xi += 2) {
|
|
928
|
+
const x = data[xi];
|
|
929
|
+
if (x >= input) {
|
|
930
|
+
if (useCachedValues) {
|
|
931
|
+
this.lastInput = input;
|
|
932
|
+
this.lastHitIndex = xi;
|
|
933
|
+
}
|
|
934
|
+
if (xi === 0 || x === input) {
|
|
935
|
+
return data[xi + 1];
|
|
936
|
+
}
|
|
937
|
+
switch (mode) {
|
|
938
|
+
default:
|
|
939
|
+
case "interpolate": {
|
|
940
|
+
const last_x = data[xi - 2];
|
|
941
|
+
const last_y = data[xi - 1];
|
|
942
|
+
const y = data[xi + 1];
|
|
943
|
+
const dx = x - last_x;
|
|
944
|
+
const dy = y - last_y;
|
|
945
|
+
return last_y + dy / dx * (input - last_x);
|
|
946
|
+
}
|
|
947
|
+
case "forward":
|
|
948
|
+
return data[xi + 1];
|
|
949
|
+
case "backward":
|
|
950
|
+
return data[xi - 1];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
if (useCachedValues) {
|
|
955
|
+
this.lastInput = input;
|
|
956
|
+
this.lastHitIndex = max;
|
|
957
|
+
}
|
|
958
|
+
return data[max - 1];
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Return the most appropriate y value from the array of (x,y) pairs when
|
|
962
|
+
* this instance is used to provide inputs for the `GAME` function.
|
|
963
|
+
*
|
|
964
|
+
* NOTE: The x values are assumed to be monotonically increasing.
|
|
965
|
+
*
|
|
966
|
+
* This method is similar to `getValueForX` in concept, except that this one
|
|
967
|
+
* returns the provided `defaultValue` if the `time` parameter is earlier than
|
|
968
|
+
* the first data point in the lookup. Also, this method always uses the
|
|
969
|
+
* `backward` interpolation mode, meaning that it holds the "current" value
|
|
970
|
+
* constant instead of interpolating.
|
|
971
|
+
*
|
|
972
|
+
* @param time The time that is used to select the data point that has an
|
|
973
|
+
* `x` value less than or equal to the provided time.
|
|
974
|
+
* @param defaultValue The value that is returned if this lookup is empty (has
|
|
975
|
+
* no points) or if the provided time is earlier than the first data point.
|
|
976
|
+
*/
|
|
977
|
+
getValueForGameTime(time, defaultValue) {
|
|
978
|
+
if (this.n <= 0) {
|
|
979
|
+
return defaultValue;
|
|
980
|
+
}
|
|
981
|
+
const x0 = this.data[0];
|
|
982
|
+
if (time < x0) {
|
|
983
|
+
return defaultValue;
|
|
984
|
+
}
|
|
985
|
+
return this.getValue(time, false, "backward");
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Interpolate the y value from the array of (x,y) pairs.
|
|
989
|
+
* NOTE: The x values are assumed to be monotonically increasing.
|
|
990
|
+
*
|
|
991
|
+
* This method is similar to `getValue` in concept, but Vensim produces results for
|
|
992
|
+
* the `GET DATA BETWEEN TIMES` function that differ in unexpected ways from normal
|
|
993
|
+
* lookup behavior, so we implement it as a separate method here.
|
|
994
|
+
*/
|
|
995
|
+
getValueBetweenTimes(input, mode) {
|
|
996
|
+
if (this.n === 0) {
|
|
997
|
+
return _NA_;
|
|
998
|
+
}
|
|
999
|
+
const max = this.n * 2;
|
|
1000
|
+
switch (mode) {
|
|
1001
|
+
case "forward": {
|
|
1002
|
+
input = Math.floor(input);
|
|
1003
|
+
for (let xi = 0; xi < max; xi += 2) {
|
|
1004
|
+
const x = this.data[xi];
|
|
1005
|
+
if (x >= input) {
|
|
1006
|
+
return this.data[xi + 1];
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return this.data[max - 1];
|
|
1010
|
+
}
|
|
1011
|
+
case "backward": {
|
|
1012
|
+
input = Math.floor(input);
|
|
1013
|
+
for (let xi = 2; xi < max; xi += 2) {
|
|
1014
|
+
const x = this.data[xi];
|
|
1015
|
+
if (x >= input) {
|
|
1016
|
+
return this.data[xi - 1];
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (max >= 4) {
|
|
1020
|
+
return this.data[max - 3];
|
|
1021
|
+
} else {
|
|
1022
|
+
return this.data[1];
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
case "interpolate":
|
|
1026
|
+
default: {
|
|
1027
|
+
if (input - Math.floor(input) > 0) {
|
|
1028
|
+
let msg = `GET DATA BETWEEN TIMES was called with an input value (${input}) that has a fractional part. `;
|
|
1029
|
+
msg += "When mode is 0 (interpolate) and the input value is not a whole number, Vensim produces unexpected ";
|
|
1030
|
+
msg += "results that may differ from those produced by SDEverywhere.";
|
|
1031
|
+
throw new Error(msg);
|
|
1032
|
+
}
|
|
1033
|
+
for (let xi = 2; xi < max; xi += 2) {
|
|
1034
|
+
const x = this.data[xi];
|
|
1035
|
+
if (x >= input) {
|
|
1036
|
+
const last_x = this.data[xi - 2];
|
|
1037
|
+
const last_y = this.data[xi - 1];
|
|
1038
|
+
const y = this.data[xi + 1];
|
|
1039
|
+
const dx = x - last_x;
|
|
1040
|
+
const dy = y - last_y;
|
|
1041
|
+
return last_y + dy / dx * (input - last_x);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return this.data[max - 1];
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
// src/js-model/js-model-functions.ts
|
|
1051
|
+
var EPSILON = 1e-6;
|
|
1052
|
+
function getJsModelFunctions() {
|
|
1053
|
+
let ctx;
|
|
1054
|
+
const cachedVectors = /* @__PURE__ */ new Map();
|
|
1055
|
+
const cachedSortVectors = /* @__PURE__ */ new Map();
|
|
1056
|
+
return {
|
|
1057
|
+
setContext(context) {
|
|
1058
|
+
ctx = context;
|
|
1059
|
+
},
|
|
1060
|
+
ABS(x) {
|
|
1061
|
+
return Math.abs(x);
|
|
1062
|
+
},
|
|
1063
|
+
ARCCOS(x) {
|
|
1064
|
+
return Math.acos(x);
|
|
1065
|
+
},
|
|
1066
|
+
ARCSIN(x) {
|
|
1067
|
+
return Math.asin(x);
|
|
1068
|
+
},
|
|
1069
|
+
ARCTAN(x) {
|
|
1070
|
+
return Math.atan(x);
|
|
1071
|
+
},
|
|
1072
|
+
COS(x) {
|
|
1073
|
+
return Math.cos(x);
|
|
1074
|
+
},
|
|
1075
|
+
EXP(x) {
|
|
1076
|
+
return Math.exp(x);
|
|
1077
|
+
},
|
|
1078
|
+
GAME(inputs, x) {
|
|
1079
|
+
return inputs ? inputs.getValueForGameTime(ctx.currentTime, x) : x;
|
|
1080
|
+
},
|
|
1081
|
+
// GAMMA_LN(): number {
|
|
1082
|
+
// throw new Error('GAMMA_LN function not yet implemented for JS target')
|
|
1083
|
+
// },
|
|
1084
|
+
INTEG(value, rate) {
|
|
1085
|
+
return value + rate * ctx.timeStep;
|
|
1086
|
+
},
|
|
1087
|
+
INTEGER(x) {
|
|
1088
|
+
return Math.trunc(x);
|
|
1089
|
+
},
|
|
1090
|
+
LN(x) {
|
|
1091
|
+
return Math.log(x);
|
|
1092
|
+
},
|
|
1093
|
+
MAX(x, y) {
|
|
1094
|
+
return Math.max(x, y);
|
|
1095
|
+
},
|
|
1096
|
+
MIN(x, y) {
|
|
1097
|
+
return Math.min(x, y);
|
|
1098
|
+
},
|
|
1099
|
+
MODULO(x, y) {
|
|
1100
|
+
return x % y;
|
|
1101
|
+
},
|
|
1102
|
+
POW(x, y) {
|
|
1103
|
+
return Math.pow(x, y);
|
|
1104
|
+
},
|
|
1105
|
+
POWER(x, y) {
|
|
1106
|
+
return Math.pow(x, y);
|
|
1107
|
+
},
|
|
1108
|
+
PULSE(start, width) {
|
|
1109
|
+
return pulse(ctx, start, width);
|
|
1110
|
+
},
|
|
1111
|
+
PULSE_TRAIN(start, width, interval, end) {
|
|
1112
|
+
const n = Math.floor((end - start) / interval);
|
|
1113
|
+
for (let k = 0; k <= n; k++) {
|
|
1114
|
+
if (ctx.currentTime <= end && pulse(ctx, start + k * interval, width)) {
|
|
1115
|
+
return 1;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
return 0;
|
|
1119
|
+
},
|
|
1120
|
+
QUANTUM(x, y) {
|
|
1121
|
+
return y <= 0 ? x : y * Math.trunc(x / y);
|
|
1122
|
+
},
|
|
1123
|
+
RAMP(slope, startTime, endTime) {
|
|
1124
|
+
if (ctx.currentTime > startTime) {
|
|
1125
|
+
if (ctx.currentTime < endTime || startTime > endTime) {
|
|
1126
|
+
return slope * (ctx.currentTime - startTime);
|
|
1127
|
+
} else {
|
|
1128
|
+
return slope * (endTime - startTime);
|
|
1129
|
+
}
|
|
1130
|
+
} else {
|
|
1131
|
+
return 0;
|
|
1132
|
+
}
|
|
1133
|
+
},
|
|
1134
|
+
SIN(x) {
|
|
1135
|
+
return Math.sin(x);
|
|
1136
|
+
},
|
|
1137
|
+
SQRT(x) {
|
|
1138
|
+
return Math.sqrt(x);
|
|
1139
|
+
},
|
|
1140
|
+
STEP(height, stepTime) {
|
|
1141
|
+
return ctx.currentTime + ctx.timeStep / 2 > stepTime ? height : 0;
|
|
1142
|
+
},
|
|
1143
|
+
TAN(x) {
|
|
1144
|
+
return Math.tan(x);
|
|
1145
|
+
},
|
|
1146
|
+
VECTOR_SORT_ORDER(vector, size, direction) {
|
|
1147
|
+
if (size > vector.length) {
|
|
1148
|
+
throw new Error(`VECTOR SORT ORDER input vector length (${vector.length}) must be >= size (${size})`);
|
|
1149
|
+
}
|
|
1150
|
+
let sortVector = cachedSortVectors.get(size);
|
|
1151
|
+
if (sortVector === void 0) {
|
|
1152
|
+
sortVector = Array(size);
|
|
1153
|
+
for (let i = 0; i < size; i++) {
|
|
1154
|
+
sortVector[i] = { x: 0, ind: 0 };
|
|
1155
|
+
}
|
|
1156
|
+
cachedSortVectors.set(size, sortVector);
|
|
1157
|
+
}
|
|
1158
|
+
let outArray = cachedVectors.get(size);
|
|
1159
|
+
if (outArray === void 0) {
|
|
1160
|
+
outArray = Array(size);
|
|
1161
|
+
cachedVectors.set(size, outArray);
|
|
1162
|
+
}
|
|
1163
|
+
for (let i = 0; i < size; i++) {
|
|
1164
|
+
sortVector[i].x = vector[i];
|
|
1165
|
+
sortVector[i].ind = i;
|
|
1166
|
+
}
|
|
1167
|
+
const sortOrder = direction > 0 ? 1 : -1;
|
|
1168
|
+
sortVector.sort((a, b) => {
|
|
1169
|
+
let result;
|
|
1170
|
+
if (a.x < b.x) {
|
|
1171
|
+
result = -1;
|
|
1172
|
+
} else if (a.x > b.x) {
|
|
1173
|
+
result = 1;
|
|
1174
|
+
} else {
|
|
1175
|
+
result = 0;
|
|
1176
|
+
}
|
|
1177
|
+
return result * sortOrder;
|
|
1178
|
+
});
|
|
1179
|
+
for (let i = 0; i < size; i++) {
|
|
1180
|
+
outArray[i] = sortVector[i].ind;
|
|
1181
|
+
}
|
|
1182
|
+
return outArray;
|
|
1183
|
+
},
|
|
1184
|
+
XIDZ(a, b, x) {
|
|
1185
|
+
return Math.abs(b) < EPSILON ? x : a / b;
|
|
1186
|
+
},
|
|
1187
|
+
ZIDZ(a, b) {
|
|
1188
|
+
if (Math.abs(b) < EPSILON) {
|
|
1189
|
+
return 0;
|
|
1190
|
+
} else {
|
|
1191
|
+
return a / b;
|
|
1192
|
+
}
|
|
1193
|
+
},
|
|
1194
|
+
//
|
|
1195
|
+
// Lookup functions
|
|
1196
|
+
//
|
|
1197
|
+
createLookup(size, data) {
|
|
1198
|
+
return new JsModelLookup(size, data);
|
|
1199
|
+
},
|
|
1200
|
+
LOOKUP(lookup, x) {
|
|
1201
|
+
return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
|
|
1202
|
+
},
|
|
1203
|
+
LOOKUP_FORWARD(lookup, x) {
|
|
1204
|
+
return lookup ? lookup.getValueForX(x, "forward") : _NA_;
|
|
1205
|
+
},
|
|
1206
|
+
LOOKUP_BACKWARD(lookup, x) {
|
|
1207
|
+
return lookup ? lookup.getValueForX(x, "backward") : _NA_;
|
|
1208
|
+
},
|
|
1209
|
+
LOOKUP_INVERT(lookup, y) {
|
|
1210
|
+
return lookup ? lookup.getValueForY(y) : _NA_;
|
|
1211
|
+
},
|
|
1212
|
+
WITH_LOOKUP(x, lookup) {
|
|
1213
|
+
return lookup ? lookup.getValueForX(x, "interpolate") : _NA_;
|
|
1214
|
+
},
|
|
1215
|
+
GET_DATA_BETWEEN_TIMES(lookup, x, mode) {
|
|
1216
|
+
let lookupMode;
|
|
1217
|
+
if (mode >= 1) {
|
|
1218
|
+
lookupMode = "forward";
|
|
1219
|
+
} else if (mode <= -1) {
|
|
1220
|
+
lookupMode = "backward";
|
|
1221
|
+
} else {
|
|
1222
|
+
lookupMode = "interpolate";
|
|
1223
|
+
}
|
|
1224
|
+
return lookup ? lookup.getValueBetweenTimes(x, lookupMode) : _NA_;
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
function pulse(ctx, start, width) {
|
|
1229
|
+
const timePlus = ctx.currentTime + ctx.timeStep / 2;
|
|
1230
|
+
if (width === 0) {
|
|
1231
|
+
width = ctx.timeStep;
|
|
1232
|
+
}
|
|
1233
|
+
return timePlus > start && timePlus < start + width ? 1 : 0;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// src/perf/perf.ts
|
|
1237
|
+
var isWeb;
|
|
1238
|
+
function perfNow() {
|
|
1239
|
+
if (isWeb === void 0) {
|
|
1240
|
+
isWeb = typeof self !== "undefined" && (self == null ? void 0 : self.performance) !== void 0;
|
|
1241
|
+
}
|
|
1242
|
+
if (isWeb) {
|
|
1243
|
+
return self.performance.now();
|
|
1244
|
+
} else {
|
|
1245
|
+
return process == null ? void 0 : process.hrtime();
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function perfElapsed(t0) {
|
|
1249
|
+
if (isWeb) {
|
|
1250
|
+
const t1 = self.performance.now();
|
|
1251
|
+
return t1 - t0;
|
|
1252
|
+
} else {
|
|
1253
|
+
const elapsed = process.hrtime(t0);
|
|
1254
|
+
return (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// src/runnable-model/base-runnable-model.ts
|
|
1259
|
+
var BaseRunnableModel = class {
|
|
1260
|
+
constructor(options) {
|
|
1261
|
+
this.startTime = options.startTime;
|
|
1262
|
+
this.endTime = options.endTime;
|
|
1263
|
+
this.saveFreq = options.saveFreq;
|
|
1264
|
+
this.numSavePoints = options.numSavePoints;
|
|
1265
|
+
this.outputVarIds = options.outputVarIds;
|
|
1266
|
+
this.modelListing = options.modelListing;
|
|
1267
|
+
this.onRunModel = options.onRunModel;
|
|
1268
|
+
}
|
|
1269
|
+
// from RunnableModel interface
|
|
1270
|
+
runModel(params) {
|
|
1271
|
+
var _a;
|
|
1272
|
+
let inputsArray = params.getInputs();
|
|
1273
|
+
if (inputsArray === void 0) {
|
|
1274
|
+
params.copyInputs(this.inputs, (numElements) => {
|
|
1275
|
+
this.inputs = new Float64Array(numElements);
|
|
1276
|
+
return this.inputs;
|
|
1277
|
+
});
|
|
1278
|
+
inputsArray = this.inputs;
|
|
1279
|
+
}
|
|
1280
|
+
let outputIndicesArray = params.getOutputIndices();
|
|
1281
|
+
if (outputIndicesArray === void 0 && params.getOutputIndicesLength() > 0) {
|
|
1282
|
+
params.copyOutputIndices(this.outputIndices, (numElements) => {
|
|
1283
|
+
this.outputIndices = new Int32Array(numElements);
|
|
1284
|
+
return this.outputIndices;
|
|
1285
|
+
});
|
|
1286
|
+
outputIndicesArray = this.outputIndices;
|
|
1287
|
+
}
|
|
1288
|
+
const outputsLengthInElements = params.getOutputsLength();
|
|
1289
|
+
if (this.outputs === void 0 || this.outputs.length < outputsLengthInElements) {
|
|
1290
|
+
this.outputs = new Float64Array(outputsLengthInElements);
|
|
1291
|
+
}
|
|
1292
|
+
const outputsArray = this.outputs;
|
|
1293
|
+
const t0 = perfNow();
|
|
1294
|
+
(_a = this.onRunModel) == null ? void 0 : _a.call(this, inputsArray, outputsArray, {
|
|
1295
|
+
outputIndices: outputIndicesArray,
|
|
1296
|
+
lookups: params.getLookups()
|
|
1297
|
+
});
|
|
1298
|
+
const elapsed = perfElapsed(t0);
|
|
1299
|
+
params.storeOutputs(outputsArray);
|
|
1300
|
+
params.storeElapsedTime(elapsed);
|
|
1301
|
+
}
|
|
1302
|
+
// from RunnableModel interface
|
|
1303
|
+
terminate() {
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
// src/js-model/js-model.ts
|
|
1308
|
+
function initJsModel(model) {
|
|
1309
|
+
let fns = model.getModelFunctions();
|
|
1310
|
+
if (fns === void 0) {
|
|
1311
|
+
fns = getJsModelFunctions();
|
|
1312
|
+
model.setModelFunctions(fns);
|
|
1313
|
+
}
|
|
1314
|
+
const initialTime = model.getInitialTime();
|
|
1315
|
+
const finalTime = model.getFinalTime();
|
|
1316
|
+
const timeStep = model.getTimeStep();
|
|
1317
|
+
const saveFreq = model.getSaveFreq();
|
|
1318
|
+
const numSavePoints = Math.round((finalTime - initialTime) / saveFreq) + 1;
|
|
1319
|
+
return new BaseRunnableModel({
|
|
1320
|
+
startTime: initialTime,
|
|
1321
|
+
endTime: finalTime,
|
|
1322
|
+
saveFreq,
|
|
1323
|
+
numSavePoints,
|
|
1324
|
+
outputVarIds: model.outputVarIds,
|
|
1325
|
+
modelListing: model.modelListing,
|
|
1326
|
+
onRunModel: (inputs, outputs, options) => {
|
|
1327
|
+
runJsModel(
|
|
1328
|
+
model,
|
|
1329
|
+
initialTime,
|
|
1330
|
+
finalTime,
|
|
1331
|
+
timeStep,
|
|
1332
|
+
saveFreq,
|
|
1333
|
+
numSavePoints,
|
|
1334
|
+
inputs,
|
|
1335
|
+
outputs,
|
|
1336
|
+
options == null ? void 0 : options.outputIndices,
|
|
1337
|
+
options == null ? void 0 : options.lookups,
|
|
1338
|
+
void 0
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
function runJsModel(model, initialTime, finalTime, timeStep, saveFreq, numSavePoints, inputs, outputs, outputIndices, lookups, stopAfterTime) {
|
|
1344
|
+
let time = initialTime;
|
|
1345
|
+
model.setTime(time);
|
|
1346
|
+
const fnContext = {
|
|
1347
|
+
timeStep,
|
|
1348
|
+
currentTime: time
|
|
1349
|
+
};
|
|
1350
|
+
model.getModelFunctions().setContext(fnContext);
|
|
1351
|
+
model.initConstants();
|
|
1352
|
+
if (lookups !== void 0) {
|
|
1353
|
+
for (const lookupDef of lookups) {
|
|
1354
|
+
model.setLookup(lookupDef.varRef.varSpec, lookupDef.points);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if ((inputs == null ? void 0 : inputs.length) > 0) {
|
|
1358
|
+
model.setInputs((index) => inputs[index]);
|
|
1359
|
+
}
|
|
1360
|
+
model.initLevels();
|
|
1361
|
+
const lastStep = Math.round((finalTime - initialTime) / timeStep);
|
|
1362
|
+
const stopTime = stopAfterTime !== void 0 ? stopAfterTime : finalTime;
|
|
1363
|
+
let step = 0;
|
|
1364
|
+
let savePointIndex = 0;
|
|
1365
|
+
let outputVarIndex = 0;
|
|
1366
|
+
while (step <= lastStep) {
|
|
1367
|
+
model.evalAux();
|
|
1368
|
+
if (time % saveFreq < 1e-6) {
|
|
1369
|
+
outputVarIndex = 0;
|
|
1370
|
+
const storeValue = (value) => {
|
|
1371
|
+
const outputBufferIndex = outputVarIndex * numSavePoints + savePointIndex;
|
|
1372
|
+
outputs[outputBufferIndex] = time <= stopTime ? value : void 0;
|
|
1373
|
+
outputVarIndex++;
|
|
1374
|
+
};
|
|
1375
|
+
if (outputIndices !== void 0) {
|
|
1376
|
+
let indexBufferOffset = 0;
|
|
1377
|
+
const outputCount = outputIndices[indexBufferOffset++];
|
|
1378
|
+
for (let i = 0; i < outputCount; i++) {
|
|
1379
|
+
const varIndex = outputIndices[indexBufferOffset++];
|
|
1380
|
+
const subCount = outputIndices[indexBufferOffset++];
|
|
1381
|
+
let subscriptIndices;
|
|
1382
|
+
if (subCount > 0) {
|
|
1383
|
+
subscriptIndices = outputIndices.subarray(indexBufferOffset, indexBufferOffset + subCount);
|
|
1384
|
+
indexBufferOffset += subCount;
|
|
1385
|
+
}
|
|
1386
|
+
const varSpec = {
|
|
1387
|
+
varIndex,
|
|
1388
|
+
subscriptIndices
|
|
1389
|
+
};
|
|
1390
|
+
model.storeOutput(varSpec, storeValue);
|
|
1391
|
+
}
|
|
1392
|
+
} else {
|
|
1393
|
+
model.storeOutputs(storeValue);
|
|
1394
|
+
}
|
|
1395
|
+
savePointIndex++;
|
|
1396
|
+
}
|
|
1397
|
+
if (step === lastStep) {
|
|
1398
|
+
break;
|
|
1399
|
+
}
|
|
1400
|
+
model.evalLevels();
|
|
1401
|
+
time += timeStep;
|
|
1402
|
+
model.setTime(time);
|
|
1403
|
+
fnContext.currentTime = time;
|
|
1404
|
+
step++;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// src/js-model/exec-js-model.ts
|
|
1409
|
+
function execJsModel(jsModel) {
|
|
1410
|
+
const runnableModel = initJsModel(jsModel);
|
|
1411
|
+
const inputs = [];
|
|
1412
|
+
const outputVarIds = jsModel.outputVarIds;
|
|
1413
|
+
const startTime = jsModel.getInitialTime();
|
|
1414
|
+
const endTime = jsModel.getFinalTime();
|
|
1415
|
+
const saveFreq = jsModel.getSaveFreq();
|
|
1416
|
+
const outputs = new Outputs(outputVarIds, startTime, endTime, saveFreq);
|
|
1417
|
+
const params = new ReferencedRunModelParams();
|
|
1418
|
+
params.updateFromParams(inputs, outputs);
|
|
1419
|
+
runnableModel.runModel(params);
|
|
1420
|
+
const outputVarNames = jsModel.outputVarNames.map((name) => name.replace(/"/g, '\\"'));
|
|
1421
|
+
const header = outputVarNames.join(" ");
|
|
1422
|
+
console.log(header);
|
|
1423
|
+
for (let i = 0; i < outputs.seriesLength; i++) {
|
|
1424
|
+
const rowValues = [];
|
|
1425
|
+
for (const series of outputs.varSeries) {
|
|
1426
|
+
rowValues.push(series.points[i].y);
|
|
1427
|
+
}
|
|
1428
|
+
console.log(rowValues.join(" "));
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
// src/js-model/_mocks/mock-js-model.ts
|
|
1433
|
+
var MockJsModel = class {
|
|
1434
|
+
constructor(options) {
|
|
1435
|
+
// from JsModel interface
|
|
1436
|
+
this.kind = "js";
|
|
1437
|
+
this.vars = /* @__PURE__ */ new Map();
|
|
1438
|
+
this.lookups = /* @__PURE__ */ new Map();
|
|
1439
|
+
this.outputVarIds = options.outputVarIds;
|
|
1440
|
+
this.outputVarNames = options.outputVarIds;
|
|
1441
|
+
this.initialTime = options.initialTime;
|
|
1442
|
+
this.finalTime = options.finalTime;
|
|
1443
|
+
this.outputVarIds = options.outputVarIds;
|
|
1444
|
+
if (options.listingJson) {
|
|
1445
|
+
this.modelListing = JSON.parse(options.listingJson);
|
|
1446
|
+
this.internalListing = new ModelListing(this.modelListing);
|
|
1447
|
+
}
|
|
1448
|
+
this.onEvalAux = options.onEvalAux;
|
|
1449
|
+
}
|
|
1450
|
+
varIdForSpec(varSpec) {
|
|
1451
|
+
for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) {
|
|
1452
|
+
if (listingSpec.varIndex === varSpec.varIndex) {
|
|
1453
|
+
return listingVarId;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
return void 0;
|
|
1457
|
+
}
|
|
1458
|
+
// from JsModel interface
|
|
1459
|
+
getInitialTime() {
|
|
1460
|
+
return this.initialTime;
|
|
1461
|
+
}
|
|
1462
|
+
// from JsModel interface
|
|
1463
|
+
getFinalTime() {
|
|
1464
|
+
return this.finalTime;
|
|
1465
|
+
}
|
|
1466
|
+
// from JsModel interface
|
|
1467
|
+
getTimeStep() {
|
|
1468
|
+
return 1;
|
|
1469
|
+
}
|
|
1470
|
+
// from JsModel interface
|
|
1471
|
+
getSaveFreq() {
|
|
1472
|
+
return 1;
|
|
1473
|
+
}
|
|
1474
|
+
// from JsModel interface
|
|
1475
|
+
getModelFunctions() {
|
|
1476
|
+
return this.fns;
|
|
1477
|
+
}
|
|
1478
|
+
// from JsModel interface
|
|
1479
|
+
setModelFunctions(fns) {
|
|
1480
|
+
this.fns = fns;
|
|
1481
|
+
}
|
|
1482
|
+
// from JsModel interface
|
|
1483
|
+
setTime(time) {
|
|
1484
|
+
this.vars.set("_time", time);
|
|
1485
|
+
}
|
|
1486
|
+
// from JsModel interface
|
|
1487
|
+
setInputs() {
|
|
1488
|
+
}
|
|
1489
|
+
// from JsModel interface
|
|
1490
|
+
setLookup(varSpec, points) {
|
|
1491
|
+
const varId = this.varIdForSpec(varSpec);
|
|
1492
|
+
if (varId === void 0) {
|
|
1493
|
+
throw new Error(`No lookup variable found for spec ${varSpec}`);
|
|
1494
|
+
}
|
|
1495
|
+
this.lookups.set(varId, new JsModelLookup(points.length / 2, points));
|
|
1496
|
+
}
|
|
1497
|
+
// from JsModel interface
|
|
1498
|
+
storeOutputs(storeValue) {
|
|
1499
|
+
for (const varId of this.outputVarIds) {
|
|
1500
|
+
storeValue(this.vars.get(varId));
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
// from JsModel interface
|
|
1504
|
+
storeOutput(varSpec, storeValue) {
|
|
1505
|
+
const varId = this.varIdForSpec(varSpec);
|
|
1506
|
+
if (varId === void 0) {
|
|
1507
|
+
throw new Error(`No output variable found for spec ${varSpec}`);
|
|
1508
|
+
}
|
|
1509
|
+
storeValue(this.vars.get(varId));
|
|
1510
|
+
}
|
|
1511
|
+
// from JsModel interface
|
|
1512
|
+
initConstants() {
|
|
1513
|
+
}
|
|
1514
|
+
// from JsModel interface
|
|
1515
|
+
initLevels() {
|
|
1516
|
+
}
|
|
1517
|
+
// from JsModel interface
|
|
1518
|
+
evalAux() {
|
|
1519
|
+
var _a;
|
|
1520
|
+
(_a = this.onEvalAux) == null ? void 0 : _a.call(this, this.vars, this.lookups);
|
|
1521
|
+
}
|
|
1522
|
+
// from JsModel interface
|
|
1523
|
+
evalLevels() {
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
// src/wasm-model/wasm-buffer.ts
|
|
1528
|
+
var WasmBuffer = class {
|
|
1529
|
+
/**
|
|
1530
|
+
* @param wasmModule The `WasmModule` used to initialize the memory.
|
|
1531
|
+
* @param numElements The number of elements in the buffer.
|
|
1532
|
+
* @param byteOffset The byte offset within the wasm heap.
|
|
1533
|
+
* @param heapArray The array view on the underlying heap buffer.
|
|
1534
|
+
*/
|
|
1535
|
+
constructor(wasmModule, numElements, byteOffset, heapArray) {
|
|
1536
|
+
this.wasmModule = wasmModule;
|
|
1537
|
+
this.numElements = numElements;
|
|
1538
|
+
this.byteOffset = byteOffset;
|
|
1539
|
+
this.heapArray = heapArray;
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* @return An `ArrType` view on the underlying heap buffer.
|
|
1543
|
+
*/
|
|
1544
|
+
getArrayView() {
|
|
1545
|
+
return this.heapArray;
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* @return The raw address of the underlying heap buffer.
|
|
1549
|
+
* @hidden This is intended for use by `WasmModel` only.
|
|
1550
|
+
*/
|
|
1551
|
+
getAddress() {
|
|
1552
|
+
return this.byteOffset;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Dispose the buffer by freeing the allocated heap memory.
|
|
1556
|
+
*/
|
|
1557
|
+
dispose() {
|
|
1558
|
+
var _a, _b;
|
|
1559
|
+
if (this.heapArray) {
|
|
1560
|
+
(_b = (_a = this.wasmModule)._free) == null ? void 0 : _b.call(_a, this.byteOffset);
|
|
1561
|
+
this.numElements = void 0;
|
|
1562
|
+
this.heapArray = void 0;
|
|
1563
|
+
this.byteOffset = void 0;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
function createInt32WasmBuffer(wasmModule, numElements) {
|
|
1568
|
+
const elemSizeInBytes = 4;
|
|
1569
|
+
const lengthInBytes = numElements * elemSizeInBytes;
|
|
1570
|
+
const byteOffset = wasmModule._malloc(lengthInBytes);
|
|
1571
|
+
const elemOffset = byteOffset / elemSizeInBytes;
|
|
1572
|
+
const heapArray = wasmModule.HEAP32.subarray(elemOffset, elemOffset + numElements);
|
|
1573
|
+
return new WasmBuffer(wasmModule, numElements, byteOffset, heapArray);
|
|
1574
|
+
}
|
|
1575
|
+
function createFloat64WasmBuffer(wasmModule, numElements) {
|
|
1576
|
+
const elemSizeInBytes = 8;
|
|
1577
|
+
const lengthInBytes = numElements * elemSizeInBytes;
|
|
1578
|
+
const byteOffset = wasmModule._malloc(lengthInBytes);
|
|
1579
|
+
const elemOffset = byteOffset / elemSizeInBytes;
|
|
1580
|
+
const heapArray = wasmModule.HEAPF64.subarray(elemOffset, elemOffset + numElements);
|
|
1581
|
+
return new WasmBuffer(wasmModule, numElements, byteOffset, heapArray);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// src/wasm-model/wasm-model.ts
|
|
1585
|
+
var WasmModel = class {
|
|
1586
|
+
/**
|
|
1587
|
+
* @param wasmModule The `WasmModule` that provides access to the native functions.
|
|
1588
|
+
* @param outputVarIds The output variable IDs for this model.
|
|
1589
|
+
*/
|
|
1590
|
+
constructor(wasmModule) {
|
|
1591
|
+
this.wasmModule = wasmModule;
|
|
1592
|
+
function getNumberValue(funcName) {
|
|
1593
|
+
const wasmGetValue = wasmModule.cwrap(funcName, "number", []);
|
|
1594
|
+
return wasmGetValue();
|
|
1595
|
+
}
|
|
1596
|
+
this.startTime = getNumberValue("getInitialTime");
|
|
1597
|
+
this.endTime = getNumberValue("getFinalTime");
|
|
1598
|
+
this.saveFreq = getNumberValue("getSaveper");
|
|
1599
|
+
this.numSavePoints = Math.round((this.endTime - this.startTime) / this.saveFreq) + 1;
|
|
1600
|
+
this.outputVarIds = wasmModule.outputVarIds;
|
|
1601
|
+
this.modelListing = wasmModule.modelListing;
|
|
1602
|
+
this.wasmSetLookup = wasmModule.cwrap("setLookup", null, ["number", "number", "number", "number"]);
|
|
1603
|
+
this.wasmRunModel = wasmModule.cwrap("runModelWithBuffers", null, ["number", "number", "number"]);
|
|
1604
|
+
}
|
|
1605
|
+
// from RunnableModel interface
|
|
1606
|
+
runModel(params) {
|
|
1607
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1608
|
+
const lookups = params.getLookups();
|
|
1609
|
+
if (lookups !== void 0) {
|
|
1610
|
+
for (const lookupDef of lookups) {
|
|
1611
|
+
const varSpec = lookupDef.varRef.varSpec;
|
|
1612
|
+
const numSubElements = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
|
|
1613
|
+
let subIndicesAddress;
|
|
1614
|
+
if (numSubElements > 0) {
|
|
1615
|
+
if (this.lookupSubIndicesBuffer === void 0 || this.lookupSubIndicesBuffer.numElements < numSubElements) {
|
|
1616
|
+
(_b = this.lookupSubIndicesBuffer) == null ? void 0 : _b.dispose();
|
|
1617
|
+
this.lookupSubIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numSubElements);
|
|
1618
|
+
}
|
|
1619
|
+
this.lookupSubIndicesBuffer.getArrayView().set(varSpec.subscriptIndices);
|
|
1620
|
+
subIndicesAddress = this.lookupSubIndicesBuffer.getAddress();
|
|
1621
|
+
} else {
|
|
1622
|
+
subIndicesAddress = 0;
|
|
1623
|
+
}
|
|
1624
|
+
const numLookupElements = lookupDef.points.length;
|
|
1625
|
+
if (this.lookupDataBuffer === void 0 || this.lookupDataBuffer.numElements < numLookupElements) {
|
|
1626
|
+
(_c = this.lookupDataBuffer) == null ? void 0 : _c.dispose();
|
|
1627
|
+
this.lookupDataBuffer = createFloat64WasmBuffer(this.wasmModule, numLookupElements);
|
|
1628
|
+
}
|
|
1629
|
+
this.lookupDataBuffer.getArrayView().set(lookupDef.points);
|
|
1630
|
+
const pointsAddress = this.lookupDataBuffer.getAddress();
|
|
1631
|
+
const numPoints = numLookupElements / 2;
|
|
1632
|
+
const varIndex = varSpec.varIndex;
|
|
1633
|
+
this.wasmSetLookup(varIndex, subIndicesAddress, pointsAddress, numPoints);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
params.copyInputs((_d = this.inputsBuffer) == null ? void 0 : _d.getArrayView(), (numElements) => {
|
|
1637
|
+
var _a2;
|
|
1638
|
+
(_a2 = this.inputsBuffer) == null ? void 0 : _a2.dispose();
|
|
1639
|
+
this.inputsBuffer = createFloat64WasmBuffer(this.wasmModule, numElements);
|
|
1640
|
+
return this.inputsBuffer.getArrayView();
|
|
1641
|
+
});
|
|
1642
|
+
let outputIndicesBuffer;
|
|
1643
|
+
if (params.getOutputIndicesLength() > 0) {
|
|
1644
|
+
params.copyOutputIndices((_e = this.outputIndicesBuffer) == null ? void 0 : _e.getArrayView(), (numElements) => {
|
|
1645
|
+
var _a2;
|
|
1646
|
+
(_a2 = this.outputIndicesBuffer) == null ? void 0 : _a2.dispose();
|
|
1647
|
+
this.outputIndicesBuffer = createInt32WasmBuffer(this.wasmModule, numElements);
|
|
1648
|
+
return this.outputIndicesBuffer.getArrayView();
|
|
1649
|
+
});
|
|
1650
|
+
outputIndicesBuffer = this.outputIndicesBuffer;
|
|
1651
|
+
} else {
|
|
1652
|
+
outputIndicesBuffer = void 0;
|
|
1653
|
+
}
|
|
1654
|
+
const outputsLengthInElements = params.getOutputsLength();
|
|
1655
|
+
if (this.outputsBuffer === void 0 || this.outputsBuffer.numElements < outputsLengthInElements) {
|
|
1656
|
+
(_f = this.outputsBuffer) == null ? void 0 : _f.dispose();
|
|
1657
|
+
this.outputsBuffer = createFloat64WasmBuffer(this.wasmModule, outputsLengthInElements);
|
|
1658
|
+
}
|
|
1659
|
+
const t0 = perfNow();
|
|
1660
|
+
this.wasmRunModel(
|
|
1661
|
+
((_g = this.inputsBuffer) == null ? void 0 : _g.getAddress()) || 0,
|
|
1662
|
+
this.outputsBuffer.getAddress(),
|
|
1663
|
+
(outputIndicesBuffer == null ? void 0 : outputIndicesBuffer.getAddress()) || 0
|
|
1664
|
+
);
|
|
1665
|
+
const elapsed = perfElapsed(t0);
|
|
1666
|
+
params.storeOutputs(this.outputsBuffer.getArrayView());
|
|
1667
|
+
params.storeElapsedTime(elapsed);
|
|
1668
|
+
}
|
|
1669
|
+
// from RunnableModel interface
|
|
1670
|
+
terminate() {
|
|
1671
|
+
var _a, _b, _c;
|
|
1672
|
+
(_a = this.inputsBuffer) == null ? void 0 : _a.dispose();
|
|
1673
|
+
this.inputsBuffer = void 0;
|
|
1674
|
+
(_b = this.outputsBuffer) == null ? void 0 : _b.dispose();
|
|
1675
|
+
this.outputsBuffer = void 0;
|
|
1676
|
+
(_c = this.outputIndicesBuffer) == null ? void 0 : _c.dispose();
|
|
1677
|
+
this.outputIndicesBuffer = void 0;
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
function initWasmModel(wasmModule) {
|
|
1681
|
+
return new WasmModel(wasmModule);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
// src/wasm-model/_mocks/mock-wasm-module.ts
|
|
1685
|
+
var MockWasmModule = class {
|
|
1686
|
+
constructor(options) {
|
|
1687
|
+
// from WasmModule interface
|
|
1688
|
+
this.kind = "wasm";
|
|
1689
|
+
// Start at 8 so that we can treat 0 as NULL
|
|
1690
|
+
this.mallocOffset = 8;
|
|
1691
|
+
this.allocs = /* @__PURE__ */ new Map();
|
|
1692
|
+
this.lookups = /* @__PURE__ */ new Map();
|
|
1693
|
+
this.initialTime = options.initialTime;
|
|
1694
|
+
this.finalTime = options.finalTime;
|
|
1695
|
+
this.outputVarIds = options.outputVarIds;
|
|
1696
|
+
if (options.listingJson) {
|
|
1697
|
+
this.modelListing = JSON.parse(options.listingJson);
|
|
1698
|
+
this.internalListing = new ModelListing(this.modelListing);
|
|
1699
|
+
}
|
|
1700
|
+
this.onRunModel = options.onRunModel;
|
|
1701
|
+
this.heap = new ArrayBuffer(8192);
|
|
1702
|
+
this.HEAP32 = new Int32Array(this.heap);
|
|
1703
|
+
this.HEAPF64 = new Float64Array(this.heap);
|
|
1704
|
+
}
|
|
1705
|
+
varIdForSpec(varSpec) {
|
|
1706
|
+
for (const [listingVarId, listingSpec] of this.internalListing.varSpecs) {
|
|
1707
|
+
if (listingSpec.varIndex === varSpec.varIndex) {
|
|
1708
|
+
return listingVarId;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return void 0;
|
|
1712
|
+
}
|
|
1713
|
+
// from WasmModule interface
|
|
1714
|
+
cwrap(fname) {
|
|
1715
|
+
switch (fname) {
|
|
1716
|
+
case "getInitialTime":
|
|
1717
|
+
return () => this.initialTime;
|
|
1718
|
+
case "getFinalTime":
|
|
1719
|
+
return () => this.finalTime;
|
|
1720
|
+
case "getSaveper":
|
|
1721
|
+
return () => 1;
|
|
1722
|
+
case "setLookup":
|
|
1723
|
+
return (varIndex, _subIndicesAddress, pointsAddress, numPoints) => {
|
|
1724
|
+
const varId = this.varIdForSpec({ varIndex });
|
|
1725
|
+
if (varId === void 0) {
|
|
1726
|
+
throw new Error(`No lookup variable found for var index ${varIndex}`);
|
|
1727
|
+
}
|
|
1728
|
+
const points = new Float64Array(this.getHeapView("float64", pointsAddress));
|
|
1729
|
+
this.lookups.set(varId, new JsModelLookup(numPoints, points));
|
|
1730
|
+
};
|
|
1731
|
+
case "runModelWithBuffers":
|
|
1732
|
+
return (inputsAddress, outputsAddress, outputIndicesAddress) => {
|
|
1733
|
+
const inputs = this.getHeapView("float64", inputsAddress);
|
|
1734
|
+
const outputs = this.getHeapView("float64", outputsAddress);
|
|
1735
|
+
const outputIndices = this.getHeapView("int32", outputIndicesAddress);
|
|
1736
|
+
this.onRunModel(inputs, outputs, this.lookups, outputIndices);
|
|
1737
|
+
};
|
|
1738
|
+
default:
|
|
1739
|
+
throw new Error(`Unhandled call to cwrap with function name '${fname}'`);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
// from WasmModule interface
|
|
1743
|
+
_malloc(lengthInBytes) {
|
|
1744
|
+
const currentOffset = this.mallocOffset;
|
|
1745
|
+
this.allocs.set(currentOffset, lengthInBytes);
|
|
1746
|
+
if (lengthInBytes > 0) {
|
|
1747
|
+
this.mallocOffset += lengthInBytes;
|
|
1748
|
+
} else {
|
|
1749
|
+
this.mallocOffset += 8;
|
|
1750
|
+
}
|
|
1751
|
+
return currentOffset;
|
|
1752
|
+
}
|
|
1753
|
+
// from WasmModule interface
|
|
1754
|
+
_free() {
|
|
1755
|
+
}
|
|
1756
|
+
getHeapView(kind, address) {
|
|
1757
|
+
if (address === 0) {
|
|
1758
|
+
return void 0;
|
|
1759
|
+
}
|
|
1760
|
+
const lengthInBytes = this.allocs.get(address);
|
|
1761
|
+
if (lengthInBytes === void 0) {
|
|
1762
|
+
throw new Error("Failed to locate heap allocation");
|
|
1763
|
+
}
|
|
1764
|
+
if (kind === "float64") {
|
|
1765
|
+
const offset = address / 8;
|
|
1766
|
+
return this.HEAPF64.subarray(offset, offset + lengthInBytes / 8);
|
|
1767
|
+
} else {
|
|
1768
|
+
const offset = address / 4;
|
|
1769
|
+
return this.HEAP32.subarray(offset, offset + lengthInBytes / 4);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
|
|
1774
|
+
// src/model-runner/synchronous-model-runner.ts
|
|
1775
|
+
function createRunnableModel(generatedModel) {
|
|
1776
|
+
switch (generatedModel.kind) {
|
|
1777
|
+
case "js":
|
|
1778
|
+
return initJsModel(generatedModel);
|
|
1779
|
+
case "wasm":
|
|
1780
|
+
return initWasmModel(generatedModel);
|
|
1781
|
+
default:
|
|
1782
|
+
throw new Error(`Unable to identify generated model kind`);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
function createSynchronousModelRunner(generatedModel) {
|
|
1786
|
+
const runnableModel = createRunnableModel(generatedModel);
|
|
1787
|
+
return createRunnerFromRunnableModel(runnableModel);
|
|
1788
|
+
}
|
|
1789
|
+
function createRunnerFromRunnableModel(model) {
|
|
1790
|
+
const listing = model.modelListing ? new ModelListing(model.modelListing) : void 0;
|
|
1791
|
+
const params = new ReferencedRunModelParams(listing);
|
|
1792
|
+
let terminated = false;
|
|
1793
|
+
const runModelSync = (inputs, outputs, options) => {
|
|
1794
|
+
params.updateFromParams(inputs, outputs, options);
|
|
1795
|
+
model.runModel(params);
|
|
1796
|
+
return outputs;
|
|
1797
|
+
};
|
|
1798
|
+
return {
|
|
1799
|
+
createOutputs: () => {
|
|
1800
|
+
return new Outputs(model.outputVarIds, model.startTime, model.endTime, model.saveFreq);
|
|
1801
|
+
},
|
|
1802
|
+
runModel: (inputs, outputs, options) => {
|
|
1803
|
+
if (terminated) {
|
|
1804
|
+
return Promise.reject(new Error("Model runner has already been terminated"));
|
|
1805
|
+
}
|
|
1806
|
+
return Promise.resolve(runModelSync(inputs, outputs, options));
|
|
1807
|
+
},
|
|
1808
|
+
runModelSync: (inputs, outputs, options) => {
|
|
1809
|
+
if (terminated) {
|
|
1810
|
+
throw new Error("Model runner has already been terminated");
|
|
1811
|
+
}
|
|
1812
|
+
return runModelSync(inputs, outputs, options);
|
|
1813
|
+
},
|
|
1814
|
+
terminate: () => __async(this, null, function* () {
|
|
1815
|
+
if (!terminated) {
|
|
1816
|
+
model.terminate();
|
|
1817
|
+
terminated = true;
|
|
1818
|
+
}
|
|
1819
|
+
})
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
518
1822
|
|
|
519
1823
|
// src/model-scheduler/model-scheduler.ts
|
|
520
1824
|
var ModelScheduler = class {
|
|
@@ -599,19 +1903,26 @@ function createSimpleInputValue(varId) {
|
|
|
599
1903
|
}
|
|
600
1904
|
// Annotate the CommonJS export names for ESM import in node:
|
|
601
1905
|
0 && (module.exports = {
|
|
1906
|
+
BufferedRunModelParams,
|
|
1907
|
+
MockJsModel,
|
|
1908
|
+
MockWasmModule,
|
|
602
1909
|
ModelListing,
|
|
603
1910
|
ModelScheduler,
|
|
604
1911
|
Outputs,
|
|
1912
|
+
ReferencedRunModelParams,
|
|
605
1913
|
Series,
|
|
606
|
-
WasmBuffer,
|
|
607
|
-
WasmModel,
|
|
608
|
-
createFloat64WasmBuffer,
|
|
609
1914
|
createInputValue,
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
1915
|
+
createLookupDef,
|
|
1916
|
+
createRunnableModel,
|
|
1917
|
+
createSynchronousModelRunner,
|
|
1918
|
+
decodeLookups,
|
|
1919
|
+
encodeLookups,
|
|
1920
|
+
encodeVarIndices,
|
|
1921
|
+
execJsModel,
|
|
1922
|
+
getEncodedLookupBufferLengths,
|
|
1923
|
+
getEncodedVarIndicesLength,
|
|
1924
|
+
getJsModelFunctions,
|
|
1925
|
+
initJsModel,
|
|
1926
|
+
initWasmModel
|
|
616
1927
|
});
|
|
617
1928
|
//# sourceMappingURL=index.cjs.map
|