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