@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/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
- createInt32WasmBuffer: () => createInt32WasmBuffer,
65
- createWasmModelRunner: () => createWasmModelRunner,
66
- initWasmModelAndBuffers: () => initWasmModelAndBuffers,
67
- perfElapsed: () => perfElapsed,
68
- perfNow: () => perfNow,
69
- updateOutputIndices: () => updateOutputIndices
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/wasm-model/wasm-buffer.ts
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/model-runner/outputs.ts
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/model-runner/perf.ts
342
- var isWeb;
343
- function perfNow() {
344
- if (isWeb === void 0) {
345
- isWeb = typeof self !== "undefined" && (self == null ? void 0 : self.performance) !== void 0;
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
- if (isWeb) {
348
- return self.performance.now();
349
- } else {
350
- return process == null ? void 0 : process.hrtime();
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 perfElapsed(t0) {
354
- if (isWeb) {
355
- const t1 = self.performance.now();
356
- return t1 - t0;
357
- } else {
358
- const elapsed = process.hrtime(t0);
359
- return (elapsed[0] * 1e9 + elapsed[1]) / 1e6;
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
- // src/model-runner/model-runner.ts
364
- function createWasmModelRunner(wasmResult) {
365
- const wasmModel = wasmResult.model;
366
- const inputsBuffer = wasmResult.inputsBuffer;
367
- const inputsArray = inputsBuffer.getArrayView();
368
- const outputsBuffer = wasmResult.outputsBuffer;
369
- const outputsArray = outputsBuffer.getArrayView();
370
- const outputIndicesBuffer = wasmResult.outputIndicesBuffer;
371
- const outputIndicesArray = outputIndicesBuffer == null ? void 0 : outputIndicesBuffer.getArrayView();
372
- const rowLength = wasmModel.numSavePoints;
373
- let terminated = false;
374
- const runModelSync = (inputs, outputs) => {
375
- let i = 0;
376
- for (const input of inputs) {
377
- inputsArray[i++] = input.get();
378
- }
379
- const outputSpecs = outputs.varSpecs;
380
- let useIndices;
381
- if (outputIndicesArray && outputSpecs !== void 0 && outputSpecs.length > 0) {
382
- updateOutputIndices(outputIndicesArray, outputSpecs);
383
- useIndices = true;
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
- useIndices = false;
311
+ points = new Float64Array(0);
386
312
  }
387
- const t0 = perfNow();
388
- wasmModel.runModel(inputsBuffer, outputsBuffer, useIndices ? outputIndicesBuffer : void 0);
389
- outputs.runTimeInMillis = perfElapsed(t0);
390
- outputs.updateFromBuffer(outputsArray, rowLength);
391
- return outputs;
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
- createOutputs: () => {
395
- return new Outputs(wasmResult.outputVarIds, wasmModel.startTime, wasmModel.endTime, wasmModel.saveFreq);
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-runner/model-listing.ts
337
+ // src/model-listing/model-listing.ts
419
338
  var ModelListing = class {
420
- constructor(modelJsonString) {
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 modelJson.dimensions) {
425
- const dimId = dimInfo.name;
342
+ for (const dimInfo of listingObj.dimensions) {
343
+ const dimId = dimInfo.id;
426
344
  const subscripts = [];
427
- for (let i = 0; i < dimInfo.value.length; i++) {
345
+ for (let i = 0; i < dimInfo.subIds.length; i++) {
428
346
  subscripts.push({
429
- id: dimInfo.value[i],
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 modelJson.variables) {
449
- const baseVarId = varIdWithoutSubscripts(v.varName);
364
+ for (const v of listingObj.variables) {
365
+ const baseVarId = varIdWithoutSubscripts(v.id);
450
366
  if (!baseVarIds.has(baseVarId)) {
451
- const dimIds = v.families || [];
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.varIndex,
380
+ varIndex: v.index,
468
381
  subscriptIndices: subIndices
469
382
  });
470
383
  }
471
384
  } else {
472
385
  this.varSpecs.set(baseVarId, {
473
- varIndex: v.varIndex
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
- createInt32WasmBuffer,
611
- createWasmModelRunner,
612
- initWasmModelAndBuffers,
613
- perfElapsed,
614
- perfNow,
615
- updateOutputIndices
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