@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/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
- createInt32WasmBuffer: () => createInt32WasmBuffer,
65
- createWasmModelRunner: () => createWasmModelRunner,
66
- initWasmModelAndBuffers: () => initWasmModelAndBuffers,
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/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
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/model-runner/outputs.ts
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/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;
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
- if (isWeb) {
348
- return self.performance.now();
349
- } else {
350
- return process == null ? void 0 : process.hrtime();
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 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;
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
- // 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;
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
- useIndices = false;
313
+ points = new Float64Array(0);
386
314
  }
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
- };
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
- 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
- }
334
+ varRef,
335
+ points: flatPoints
415
336
  };
416
337
  }
417
338
 
418
- // src/model-runner/model-listing.ts
339
+ // src/model-listing/model-listing.ts
419
340
  var ModelListing = class {
420
- constructor(modelJsonString) {
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 modelJson.dimensions) {
425
- const dimId = dimInfo.name;
344
+ for (const dimInfo of listingObj.dimensions) {
345
+ const dimId = dimInfo.id;
426
346
  const subscripts = [];
427
- for (let i = 0; i < dimInfo.value.length; i++) {
347
+ for (let i = 0; i < dimInfo.subIds.length; i++) {
428
348
  subscripts.push({
429
- id: dimInfo.value[i],
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 modelJson.variables) {
449
- const baseVarId = varIdWithoutSubscripts(v.varName);
366
+ for (const v of listingObj.variables) {
367
+ const baseVarId = varIdWithoutSubscripts(v.id);
450
368
  if (!baseVarIds.has(baseVarId)) {
451
- const dimIds = v.families || [];
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.varIndex,
382
+ varIndex: v.index,
468
383
  subscriptIndices: subIndices
469
384
  });
470
385
  }
471
386
  } else {
472
387
  this.varSpecs.set(baseVarId, {
473
- varIndex: v.varIndex
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
- createInt32WasmBuffer,
611
- createWasmModelRunner,
612
- initWasmModelAndBuffers,
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