@sdeverywhere/runtime 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +306 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +177 -16
- package/dist/index.d.ts +177 -16
- package/dist/index.js +305 -56
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ import loadGeneratedModel from './sde-prep/generated-model.js'
|
|
|
52
52
|
### 2. Initialize a `ModelRunner`
|
|
53
53
|
|
|
54
54
|
The next step is to create a `ModelRunner` instance, which simplifies
|
|
55
|
-
the process of running a
|
|
55
|
+
the process of running a generated model with a given set of inputs and
|
|
56
56
|
parsing the outputs.
|
|
57
57
|
The `ModelRunner` produces an `Outputs` instance that provides easy
|
|
58
58
|
access to time series data for each output variable in the model.
|
package/dist/index.cjs
CHANGED
|
@@ -58,6 +58,7 @@ __export(src_exports, {
|
|
|
58
58
|
MockWasmModule: () => MockWasmModule,
|
|
59
59
|
ModelListing: () => ModelListing,
|
|
60
60
|
ModelScheduler: () => ModelScheduler,
|
|
61
|
+
MultiContextModelScheduler: () => MultiContextModelScheduler,
|
|
61
62
|
Outputs: () => Outputs,
|
|
62
63
|
ReferencedRunModelParams: () => ReferencedRunModelParams,
|
|
63
64
|
Series: () => Series,
|
|
@@ -251,7 +252,7 @@ function encodeVarIndices(varSpecs, indicesArray) {
|
|
|
251
252
|
}
|
|
252
253
|
}
|
|
253
254
|
function getEncodedLookupBufferLengths(lookupDefs) {
|
|
254
|
-
var _a;
|
|
255
|
+
var _a, _b;
|
|
255
256
|
let lookupIndicesLength = 1;
|
|
256
257
|
let lookupsLength = 0;
|
|
257
258
|
for (const lookupDef of lookupDefs) {
|
|
@@ -263,7 +264,7 @@ function getEncodedLookupBufferLengths(lookupDefs) {
|
|
|
263
264
|
const subCount = ((_a = varSpec.subscriptIndices) == null ? void 0 : _a.length) || 0;
|
|
264
265
|
lookupIndicesLength += subCount;
|
|
265
266
|
lookupIndicesLength += 2;
|
|
266
|
-
lookupsLength += lookupDef.points.length;
|
|
267
|
+
lookupsLength += ((_b = lookupDef.points) == null ? void 0 : _b.length) || 0;
|
|
267
268
|
}
|
|
268
269
|
return {
|
|
269
270
|
lookupIndicesLength,
|
|
@@ -283,10 +284,15 @@ function encodeLookups(lookupDefs, lookupIndicesArray, lookupsArray) {
|
|
|
283
284
|
for (let i = 0; i < subCount; i++) {
|
|
284
285
|
lookupIndicesArray[li++] = subs[i];
|
|
285
286
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
287
|
+
if (lookupDef.points !== void 0) {
|
|
288
|
+
lookupIndicesArray[li++] = lookupDataOffset;
|
|
289
|
+
lookupIndicesArray[li++] = lookupDef.points.length;
|
|
290
|
+
lookupsArray == null ? void 0 : lookupsArray.set(lookupDef.points, lookupDataOffset);
|
|
291
|
+
lookupDataOffset += lookupDef.points.length;
|
|
292
|
+
} else {
|
|
293
|
+
lookupIndicesArray[li++] = -1;
|
|
294
|
+
lookupIndicesArray[li++] = 0;
|
|
295
|
+
}
|
|
290
296
|
}
|
|
291
297
|
}
|
|
292
298
|
function decodeLookups(lookupIndicesArray, lookupsArray) {
|
|
@@ -307,10 +313,14 @@ function decodeLookups(lookupIndicesArray, lookupsArray) {
|
|
|
307
313
|
subscriptIndices
|
|
308
314
|
};
|
|
309
315
|
let points;
|
|
310
|
-
if (
|
|
311
|
-
|
|
316
|
+
if (lookupDataOffset >= 0) {
|
|
317
|
+
if (lookupsArray) {
|
|
318
|
+
points = lookupsArray.slice(lookupDataOffset, lookupDataOffset + lookupDataLength);
|
|
319
|
+
} else {
|
|
320
|
+
points = new Float64Array(0);
|
|
321
|
+
}
|
|
312
322
|
} else {
|
|
313
|
-
points =
|
|
323
|
+
points = void 0;
|
|
314
324
|
}
|
|
315
325
|
lookupDefs.push({
|
|
316
326
|
varRef: {
|
|
@@ -324,11 +334,14 @@ function decodeLookups(lookupIndicesArray, lookupsArray) {
|
|
|
324
334
|
|
|
325
335
|
// src/_shared/lookup-def.ts
|
|
326
336
|
function createLookupDef(varRef, points) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
337
|
+
let flatPoints;
|
|
338
|
+
if (points) {
|
|
339
|
+
flatPoints = new Float64Array(points.length * 2);
|
|
340
|
+
let i = 0;
|
|
341
|
+
for (const p of points) {
|
|
342
|
+
flatPoints[i++] = p.x;
|
|
343
|
+
flatPoints[i++] = p.y;
|
|
344
|
+
}
|
|
332
345
|
}
|
|
333
346
|
return {
|
|
334
347
|
varRef,
|
|
@@ -884,18 +897,59 @@ var _NA_ = -Number.MAX_VALUE;
|
|
|
884
897
|
// src/js-model/js-model-lookup.ts
|
|
885
898
|
var JsModelLookup = class {
|
|
886
899
|
/**
|
|
887
|
-
* @param
|
|
900
|
+
* @param size The number of (x,y) pairs in the lookup.
|
|
888
901
|
* @param data The lookup data, as (x,y) pairs. The length of the array must be
|
|
889
902
|
* >= 2*n. Note that the data will be stored by reference, so if there is a chance
|
|
890
903
|
* that the array will be reused or modified by other code, be sure to pass in a
|
|
891
904
|
* copy of the array.
|
|
892
905
|
*/
|
|
893
|
-
constructor(
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
906
|
+
constructor(size, data) {
|
|
907
|
+
if (data && data.length < size * 2) {
|
|
908
|
+
throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
|
|
909
|
+
}
|
|
910
|
+
this.originalData = data;
|
|
911
|
+
this.originalSize = size;
|
|
912
|
+
this.dynamicData = void 0;
|
|
913
|
+
this.dynamicSize = 0;
|
|
914
|
+
this.activeData = this.originalData;
|
|
915
|
+
this.activeSize = this.originalSize;
|
|
916
|
+
this.lastInput = Number.MAX_VALUE;
|
|
917
|
+
this.lastHitIndex = 0;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Set new data for this lookup instance, or restore the original data.
|
|
921
|
+
*
|
|
922
|
+
* If `data` is undefined, the original data that was supplied to the constructor will
|
|
923
|
+
* be restored as the "active" data. Otherwise, `data` will be copied to an internal
|
|
924
|
+
* data buffer, which will be the "active" data. If `size` is greater than the size
|
|
925
|
+
* passed to previous calls, the internal data buffer will be grown as needed.
|
|
926
|
+
*
|
|
927
|
+
* @param size The number of (x,y) pairs in the lookup.
|
|
928
|
+
* @param data The lookup data, as (x,y) pairs. The length of the array must be
|
|
929
|
+
* >= 2*n. Note that the data will be copied into an internal data buffer, so it
|
|
930
|
+
* is not necessary to defensively copy data before calling this method.
|
|
931
|
+
*/
|
|
932
|
+
setData(size, data) {
|
|
933
|
+
if (data) {
|
|
934
|
+
if (data.length < size * 2) {
|
|
935
|
+
throw new Error(`Lookup data array length must be >= 2*size (length=${data.length} size=${size}`);
|
|
936
|
+
}
|
|
937
|
+
const dataLengthInElems = size * 2;
|
|
938
|
+
if (this.dynamicData === void 0 || dataLengthInElems > this.dynamicData.length) {
|
|
939
|
+
this.dynamicData = new Float64Array(dataLengthInElems);
|
|
940
|
+
}
|
|
941
|
+
this.dynamicSize = size;
|
|
942
|
+
if (size > 0) {
|
|
943
|
+
const subarray = data.subarray(0, dataLengthInElems);
|
|
944
|
+
this.dynamicData.set(subarray);
|
|
945
|
+
}
|
|
946
|
+
this.activeData = this.dynamicData;
|
|
947
|
+
this.activeSize = this.dynamicSize;
|
|
948
|
+
} else {
|
|
949
|
+
this.activeData = this.originalData;
|
|
950
|
+
this.activeSize = this.originalSize;
|
|
898
951
|
}
|
|
952
|
+
this.invertedData = void 0;
|
|
899
953
|
this.lastInput = Number.MAX_VALUE;
|
|
900
954
|
this.lastHitIndex = 0;
|
|
901
955
|
}
|
|
@@ -904,8 +958,8 @@ var JsModelLookup = class {
|
|
|
904
958
|
}
|
|
905
959
|
getValueForY(y) {
|
|
906
960
|
if (this.invertedData === void 0) {
|
|
907
|
-
const numValues = this.
|
|
908
|
-
const normalData = this.
|
|
961
|
+
const numValues = this.activeSize * 2;
|
|
962
|
+
const normalData = this.activeData;
|
|
909
963
|
const invertedData = Array(numValues);
|
|
910
964
|
for (let i = 0; i < numValues; i += 2) {
|
|
911
965
|
invertedData[i] = normalData[i + 1];
|
|
@@ -920,11 +974,11 @@ var JsModelLookup = class {
|
|
|
920
974
|
* NOTE: The x values are assumed to be monotonically increasing.
|
|
921
975
|
*/
|
|
922
976
|
getValue(input, useInvertedData, mode) {
|
|
923
|
-
if (this.
|
|
977
|
+
if (this.activeSize === 0) {
|
|
924
978
|
return _NA_;
|
|
925
979
|
}
|
|
926
|
-
const data = useInvertedData ? this.invertedData : this.
|
|
927
|
-
const max = this.
|
|
980
|
+
const data = useInvertedData ? this.invertedData : this.activeData;
|
|
981
|
+
const max = this.activeSize * 2;
|
|
928
982
|
const useCachedValues = !useInvertedData;
|
|
929
983
|
let startIndex;
|
|
930
984
|
if (useCachedValues && input >= this.lastInput) {
|
|
@@ -983,10 +1037,10 @@ var JsModelLookup = class {
|
|
|
983
1037
|
* no points) or if the provided time is earlier than the first data point.
|
|
984
1038
|
*/
|
|
985
1039
|
getValueForGameTime(time, defaultValue) {
|
|
986
|
-
if (this.
|
|
1040
|
+
if (this.activeSize <= 0) {
|
|
987
1041
|
return defaultValue;
|
|
988
1042
|
}
|
|
989
|
-
const x0 = this.
|
|
1043
|
+
const x0 = this.activeData[0];
|
|
990
1044
|
if (time < x0) {
|
|
991
1045
|
return defaultValue;
|
|
992
1046
|
}
|
|
@@ -1001,33 +1055,34 @@ var JsModelLookup = class {
|
|
|
1001
1055
|
* lookup behavior, so we implement it as a separate method here.
|
|
1002
1056
|
*/
|
|
1003
1057
|
getValueBetweenTimes(input, mode) {
|
|
1004
|
-
if (this.
|
|
1058
|
+
if (this.activeSize === 0) {
|
|
1005
1059
|
return _NA_;
|
|
1006
1060
|
}
|
|
1007
|
-
const
|
|
1061
|
+
const data = this.activeData;
|
|
1062
|
+
const max = this.activeSize * 2;
|
|
1008
1063
|
switch (mode) {
|
|
1009
1064
|
case "forward": {
|
|
1010
1065
|
input = Math.floor(input);
|
|
1011
1066
|
for (let xi = 0; xi < max; xi += 2) {
|
|
1012
|
-
const x =
|
|
1067
|
+
const x = data[xi];
|
|
1013
1068
|
if (x >= input) {
|
|
1014
|
-
return
|
|
1069
|
+
return data[xi + 1];
|
|
1015
1070
|
}
|
|
1016
1071
|
}
|
|
1017
|
-
return
|
|
1072
|
+
return data[max - 1];
|
|
1018
1073
|
}
|
|
1019
1074
|
case "backward": {
|
|
1020
1075
|
input = Math.floor(input);
|
|
1021
1076
|
for (let xi = 2; xi < max; xi += 2) {
|
|
1022
|
-
const x =
|
|
1077
|
+
const x = data[xi];
|
|
1023
1078
|
if (x >= input) {
|
|
1024
|
-
return
|
|
1079
|
+
return data[xi - 1];
|
|
1025
1080
|
}
|
|
1026
1081
|
}
|
|
1027
1082
|
if (max >= 4) {
|
|
1028
|
-
return
|
|
1083
|
+
return data[max - 3];
|
|
1029
1084
|
} else {
|
|
1030
|
-
return
|
|
1085
|
+
return data[1];
|
|
1031
1086
|
}
|
|
1032
1087
|
}
|
|
1033
1088
|
case "interpolate":
|
|
@@ -1039,17 +1094,17 @@ var JsModelLookup = class {
|
|
|
1039
1094
|
throw new Error(msg);
|
|
1040
1095
|
}
|
|
1041
1096
|
for (let xi = 2; xi < max; xi += 2) {
|
|
1042
|
-
const x =
|
|
1097
|
+
const x = data[xi];
|
|
1043
1098
|
if (x >= input) {
|
|
1044
|
-
const last_x =
|
|
1045
|
-
const last_y =
|
|
1046
|
-
const y =
|
|
1099
|
+
const last_x = data[xi - 2];
|
|
1100
|
+
const last_y = data[xi - 1];
|
|
1101
|
+
const y = data[xi + 1];
|
|
1047
1102
|
const dx = x - last_x;
|
|
1048
1103
|
const dy = y - last_y;
|
|
1049
1104
|
return last_y + dy / dx * (input - last_x);
|
|
1050
1105
|
}
|
|
1051
1106
|
}
|
|
1052
|
-
return
|
|
1107
|
+
return data[max - 1];
|
|
1053
1108
|
}
|
|
1054
1109
|
}
|
|
1055
1110
|
}
|
|
@@ -1500,7 +1555,8 @@ var MockJsModel = class {
|
|
|
1500
1555
|
if (varId === void 0) {
|
|
1501
1556
|
throw new Error(`No lookup variable found for spec ${varSpec}`);
|
|
1502
1557
|
}
|
|
1503
|
-
|
|
1558
|
+
const numPoints = points ? points.length / 2 : 0;
|
|
1559
|
+
this.lookups.set(varId, new JsModelLookup(numPoints, points));
|
|
1504
1560
|
}
|
|
1505
1561
|
// from JsModel interface
|
|
1506
1562
|
storeOutputs(storeValue) {
|
|
@@ -1629,14 +1685,21 @@ var WasmModel = class {
|
|
|
1629
1685
|
} else {
|
|
1630
1686
|
subIndicesAddress = 0;
|
|
1631
1687
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1688
|
+
let pointsAddress;
|
|
1689
|
+
let numPoints;
|
|
1690
|
+
if (lookupDef.points) {
|
|
1691
|
+
const numLookupElements = lookupDef.points.length;
|
|
1692
|
+
if (this.lookupDataBuffer === void 0 || this.lookupDataBuffer.numElements < numLookupElements) {
|
|
1693
|
+
(_c = this.lookupDataBuffer) == null ? void 0 : _c.dispose();
|
|
1694
|
+
this.lookupDataBuffer = createFloat64WasmBuffer(this.wasmModule, numLookupElements);
|
|
1695
|
+
}
|
|
1696
|
+
this.lookupDataBuffer.getArrayView().set(lookupDef.points);
|
|
1697
|
+
pointsAddress = this.lookupDataBuffer.getAddress();
|
|
1698
|
+
numPoints = numLookupElements / 2;
|
|
1699
|
+
} else {
|
|
1700
|
+
pointsAddress = 0;
|
|
1701
|
+
numPoints = 0;
|
|
1636
1702
|
}
|
|
1637
|
-
this.lookupDataBuffer.getArrayView().set(lookupDef.points);
|
|
1638
|
-
const pointsAddress = this.lookupDataBuffer.getAddress();
|
|
1639
|
-
const numPoints = numLookupElements / 2;
|
|
1640
1703
|
const varIndex = varSpec.varIndex;
|
|
1641
1704
|
this.wasmSetLookup(varIndex, subIndicesAddress, pointsAddress, numPoints);
|
|
1642
1705
|
}
|
|
@@ -1844,7 +1907,7 @@ var ModelScheduler = class {
|
|
|
1844
1907
|
/** Whether a model run is in progress. */
|
|
1845
1908
|
this.runInProgress = false;
|
|
1846
1909
|
const afterSet = () => {
|
|
1847
|
-
this.
|
|
1910
|
+
this.runModelIfNeeded();
|
|
1848
1911
|
};
|
|
1849
1912
|
for (const userInput of userInputs) {
|
|
1850
1913
|
userInput.callbacks.onSet = afterSet;
|
|
@@ -1855,24 +1918,24 @@ var ModelScheduler = class {
|
|
|
1855
1918
|
}
|
|
1856
1919
|
}
|
|
1857
1920
|
/**
|
|
1858
|
-
* Schedule a
|
|
1921
|
+
* Schedule a model run (if not already pending). When the run is
|
|
1859
1922
|
* complete, save the outputs and call the `onOutputsChanged` callback.
|
|
1860
1923
|
*/
|
|
1861
|
-
|
|
1924
|
+
runModelIfNeeded() {
|
|
1862
1925
|
this.runNeeded = true;
|
|
1863
1926
|
if (this.runInProgress) {
|
|
1864
1927
|
return;
|
|
1865
1928
|
} else {
|
|
1866
1929
|
this.runInProgress = true;
|
|
1867
1930
|
setTimeout(() => {
|
|
1868
|
-
this.
|
|
1931
|
+
this.runModelNow();
|
|
1869
1932
|
}, 0);
|
|
1870
1933
|
}
|
|
1871
1934
|
}
|
|
1872
1935
|
/**
|
|
1873
|
-
* Run the
|
|
1936
|
+
* Run the model asynchronously using the current set of input values.
|
|
1874
1937
|
*/
|
|
1875
|
-
|
|
1938
|
+
runModelNow() {
|
|
1876
1939
|
return __async(this, null, function* () {
|
|
1877
1940
|
var _a;
|
|
1878
1941
|
for (let i = 0; i < this.userInputs.length; i++) {
|
|
@@ -1887,7 +1950,7 @@ var ModelScheduler = class {
|
|
|
1887
1950
|
if (this.runNeeded) {
|
|
1888
1951
|
this.runNeeded = false;
|
|
1889
1952
|
setTimeout(() => {
|
|
1890
|
-
this.
|
|
1953
|
+
this.runModelNow();
|
|
1891
1954
|
}, 0);
|
|
1892
1955
|
} else {
|
|
1893
1956
|
this.runNeeded = false;
|
|
@@ -1909,6 +1972,192 @@ function createSimpleInputValue(varId) {
|
|
|
1909
1972
|
};
|
|
1910
1973
|
return { varId, get, set, reset, callbacks: {} };
|
|
1911
1974
|
}
|
|
1975
|
+
|
|
1976
|
+
// src/model-scheduler/multi-context-model-scheduler.ts
|
|
1977
|
+
var MultiContextModelScheduler = class {
|
|
1978
|
+
/**
|
|
1979
|
+
* @param runner The model runner.
|
|
1980
|
+
* @param options Additional options for the scheduler.
|
|
1981
|
+
* @param options.initialOutputs An optional `Outputs` instance that will be reused
|
|
1982
|
+
* for the initial context. This is useful for saving memory when an `Outputs`
|
|
1983
|
+
* instance was already created for, e.g., a initial baseline/reference run.
|
|
1984
|
+
*/
|
|
1985
|
+
constructor(runner, options) {
|
|
1986
|
+
this.runner = runner;
|
|
1987
|
+
/** The contexts that hold distinct sets of inputs and outputs. */
|
|
1988
|
+
this.contexts = [];
|
|
1989
|
+
/** Whether a model run has been scheduled. */
|
|
1990
|
+
this.runNeeded = false;
|
|
1991
|
+
/** Whether a model run is in progress. */
|
|
1992
|
+
this.runInProgress = false;
|
|
1993
|
+
this.initialOutputs = options == null ? void 0 : options.initialOutputs;
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Return true if the scheduler has started any model runs.
|
|
1997
|
+
*/
|
|
1998
|
+
isStarted() {
|
|
1999
|
+
return this.initialOutputs === void 0;
|
|
2000
|
+
}
|
|
2001
|
+
/**
|
|
2002
|
+
* Add a new context that holds a distinct set of model inputs and outputs.
|
|
2003
|
+
* These inputs and outputs are kept separate from those in other contexts,
|
|
2004
|
+
* which allows an application to use the same underlying model to run with
|
|
2005
|
+
* multiple I/O contexts.
|
|
2006
|
+
*
|
|
2007
|
+
* Note that the contexts created before the first scheduled model run
|
|
2008
|
+
* will inherit the data from `initialOutputs` passed to the constructor,
|
|
2009
|
+
* but contexts created after that will initially have output values set
|
|
2010
|
+
* to zero.
|
|
2011
|
+
*
|
|
2012
|
+
* @param inputs The input values, in the same order as in the spec file passed to `sde`.
|
|
2013
|
+
* @param options Additional options for the context.
|
|
2014
|
+
* @param options.externalData Additional data that is external to the model outputs.
|
|
2015
|
+
* For example, this can contain data that was captured from an initial reference
|
|
2016
|
+
* run, or other static data that is displayed in graphs alongside the model
|
|
2017
|
+
* output data in graphs.
|
|
2018
|
+
*/
|
|
2019
|
+
addContext(inputs, options) {
|
|
2020
|
+
let outputs;
|
|
2021
|
+
if (this.initialOutputs !== void 0) {
|
|
2022
|
+
if (this.contexts.length === 0) {
|
|
2023
|
+
outputs = this.initialOutputs;
|
|
2024
|
+
} else {
|
|
2025
|
+
outputs = this.runner.createOutputs();
|
|
2026
|
+
for (const varId of outputs.varIds) {
|
|
2027
|
+
const series0 = this.initialOutputs.getSeriesForVar(varId);
|
|
2028
|
+
const series1 = outputs.getSeriesForVar(varId);
|
|
2029
|
+
for (let i = 0; i < series0.points.length; i++) {
|
|
2030
|
+
series1.points[i].y = series0.points[i].y;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
} else {
|
|
2035
|
+
outputs = this.runner.createOutputs();
|
|
2036
|
+
}
|
|
2037
|
+
const context = new ModelContextImpl(inputs, outputs, options == null ? void 0 : options.externalData);
|
|
2038
|
+
const afterSet = () => {
|
|
2039
|
+
context.runNeeded = true;
|
|
2040
|
+
this.runModelIfNeeded();
|
|
2041
|
+
};
|
|
2042
|
+
for (const input of inputs) {
|
|
2043
|
+
input.callbacks.onSet = afterSet;
|
|
2044
|
+
}
|
|
2045
|
+
this.contexts.push(context);
|
|
2046
|
+
return context;
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Remove the given context from the set of contexts managed by the scheduler.
|
|
2050
|
+
*
|
|
2051
|
+
* @param context The context to remove.
|
|
2052
|
+
*/
|
|
2053
|
+
removeContext(context) {
|
|
2054
|
+
const index = this.contexts.findIndex((c) => c === context);
|
|
2055
|
+
if (index >= 0) {
|
|
2056
|
+
this.contexts.splice(index, 1);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Schedule a model run (if not already pending). When the run is
|
|
2061
|
+
* complete, save the outputs and call the `onOutputsChanged` callback.
|
|
2062
|
+
*/
|
|
2063
|
+
runModelIfNeeded() {
|
|
2064
|
+
this.runNeeded = true;
|
|
2065
|
+
if (this.runInProgress) {
|
|
2066
|
+
return;
|
|
2067
|
+
} else {
|
|
2068
|
+
this.runInProgress = true;
|
|
2069
|
+
setTimeout(() => {
|
|
2070
|
+
this.runModelNow();
|
|
2071
|
+
}, 0);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Run the model asynchronously for all relevant contexts.
|
|
2076
|
+
*/
|
|
2077
|
+
runModelNow() {
|
|
2078
|
+
return __async(this, null, function* () {
|
|
2079
|
+
this.initialOutputs = void 0;
|
|
2080
|
+
for (const context of this.contexts) {
|
|
2081
|
+
if (context.runNeeded) {
|
|
2082
|
+
context.runNeeded = false;
|
|
2083
|
+
yield this.runModelNowForContext(context);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (this.runNeeded) {
|
|
2087
|
+
this.runNeeded = false;
|
|
2088
|
+
setTimeout(() => {
|
|
2089
|
+
this.runModelNow();
|
|
2090
|
+
}, 0);
|
|
2091
|
+
} else {
|
|
2092
|
+
this.runNeeded = false;
|
|
2093
|
+
this.runInProgress = false;
|
|
2094
|
+
}
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
/**
|
|
2098
|
+
* Run the model asynchronously using the current set of input values in the given context.
|
|
2099
|
+
*
|
|
2100
|
+
* @param context The context to use for the model run.
|
|
2101
|
+
*/
|
|
2102
|
+
runModelNowForContext(context) {
|
|
2103
|
+
return __async(this, null, function* () {
|
|
2104
|
+
var _a;
|
|
2105
|
+
if (this.currentInputs === void 0) {
|
|
2106
|
+
this.currentInputs = Array(context.inputsArray.length);
|
|
2107
|
+
}
|
|
2108
|
+
for (let i = 0; i < context.inputsArray.length; i++) {
|
|
2109
|
+
this.currentInputs[i] = context.inputsArray[i].get();
|
|
2110
|
+
}
|
|
2111
|
+
try {
|
|
2112
|
+
yield this.runner.runModel(this.currentInputs, context.outputs);
|
|
2113
|
+
(_a = context.onOutputsChanged) == null ? void 0 : _a.call(context);
|
|
2114
|
+
} catch (e) {
|
|
2115
|
+
console.error("ERROR: The scheduler encountered an error when running the model:", e);
|
|
2116
|
+
}
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
};
|
|
2120
|
+
var ModelContextImpl = class {
|
|
2121
|
+
/**
|
|
2122
|
+
* @hidden This is intended for use by `MultiContextModelScheduler` only.
|
|
2123
|
+
*
|
|
2124
|
+
* @param inputs The input values, in the same order as in the spec file passed to `sde`.
|
|
2125
|
+
* @param outputs The structure into which the model outputs will be stored.
|
|
2126
|
+
* @param externalData Additional data that is external to the model outputs. For example, this can contain
|
|
2127
|
+
* data that was captured from an initial reference run, or other static data that is displayed in graphs
|
|
2128
|
+
* alongside the model output data in graphs.
|
|
2129
|
+
*/
|
|
2130
|
+
constructor(inputs, outputs, externalData) {
|
|
2131
|
+
this.externalData = externalData;
|
|
2132
|
+
/**
|
|
2133
|
+
* Whether a model run is needed for this context.
|
|
2134
|
+
* @hidden This is intended for use by `MultiContextModelScheduler` only.
|
|
2135
|
+
*/
|
|
2136
|
+
this.runNeeded = false;
|
|
2137
|
+
this.inputsArray = Array.from(inputs);
|
|
2138
|
+
this.outputs = outputs;
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Return the series data for the given model output variable or external
|
|
2142
|
+
* dataset.
|
|
2143
|
+
*
|
|
2144
|
+
* @param varId The ID of the output variable associated with the data.
|
|
2145
|
+
* @param sourceName The external data source name (e.g. "Ref"), or
|
|
2146
|
+
* undefined to use the latest model output data from this context.
|
|
2147
|
+
*/
|
|
2148
|
+
getSeriesForVar(varId, sourceName) {
|
|
2149
|
+
if (sourceName === void 0) {
|
|
2150
|
+
return this.outputs.getSeriesForVar(varId);
|
|
2151
|
+
} else {
|
|
2152
|
+
const dataForSource = this.externalData.get(sourceName);
|
|
2153
|
+
if (dataForSource !== void 0) {
|
|
2154
|
+
return dataForSource.get(varId);
|
|
2155
|
+
} else {
|
|
2156
|
+
return void 0;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
};
|
|
1912
2161
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1913
2162
|
0 && (module.exports = {
|
|
1914
2163
|
BufferedRunModelParams,
|
|
@@ -1916,6 +2165,7 @@ function createSimpleInputValue(varId) {
|
|
|
1916
2165
|
MockWasmModule,
|
|
1917
2166
|
ModelListing,
|
|
1918
2167
|
ModelScheduler,
|
|
2168
|
+
MultiContextModelScheduler,
|
|
1919
2169
|
Outputs,
|
|
1920
2170
|
ReferencedRunModelParams,
|
|
1921
2171
|
Series,
|