linny-r 1.5.5 → 1.5.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/package.json +1 -1
- package/static/index.html +3 -1
- package/static/linny-r.css +9 -5
- package/static/scripts/linny-r-gui-chart-manager.js +26 -4
- package/static/scripts/linny-r-gui-controller.js +3 -1
- package/static/scripts/linny-r-gui-experiment-manager.js +6 -5
- package/static/scripts/linny-r-gui-monitor.js +5 -3
- package/static/scripts/linny-r-model.js +125 -108
- package/static/scripts/linny-r-vm.js +279 -238
@@ -750,8 +750,8 @@ class LinnyRModel {
|
|
750
750
|
}
|
751
751
|
|
752
752
|
isConstrained(node) {
|
753
|
-
// Return the constraint that node is involved in if such constraint
|
754
|
-
// and otherwise NULL
|
753
|
+
// Return the constraint that node is involved in if such constraint
|
754
|
+
// exists, and otherwise NULL.
|
755
755
|
let c = null;
|
756
756
|
for(c in this.constraints) if(this.constraints.hasOwnProperty(c)) {
|
757
757
|
c = this.constraints[c];
|
@@ -761,25 +761,25 @@ class LinnyRModel {
|
|
761
761
|
}
|
762
762
|
|
763
763
|
get runLength() {
|
764
|
-
// Return the number of time steps to by computed for a simulation
|
765
|
-
// NOTE:
|
764
|
+
// Return the number of time steps to by computed for a simulation.
|
765
|
+
// NOTE: This includes a final lookahead period.
|
766
766
|
return this.end_period - this.start_period + 1 + this.look_ahead;
|
767
767
|
}
|
768
|
-
|
768
|
+
|
769
769
|
inferDimensions() {
|
770
|
-
//
|
771
|
-
// NOTE:
|
770
|
+
// Generate the list of dimensions for experimental design.
|
771
|
+
// NOTE: A dimension is a list of one or more relevant selectors.
|
772
772
|
let newdim;
|
773
773
|
this.dimensions.length = 0;
|
774
|
-
// NOTE:
|
774
|
+
// NOTE: Ignore the equations dataset.
|
775
775
|
for(let d in this.datasets) if(this.datasets.hasOwnProperty(d) &&
|
776
776
|
this.datasets[d] !== this.equations_dataset) {
|
777
777
|
// Get selector list
|
778
778
|
const
|
779
779
|
ds = this.datasets[d],
|
780
|
-
// NOTE:
|
780
|
+
// NOTE: Ignore wildcard selectors!
|
781
781
|
sl = ds.plainSelectors;
|
782
|
-
// Ignore datasets with fewer than 2 "plain" selectors
|
782
|
+
// Ignore datasets with fewer than 2 "plain" selectors.
|
783
783
|
if(sl.length > 1) {
|
784
784
|
newdim = true;
|
785
785
|
// Merge into dimension if there are shared selectors
|
@@ -3108,12 +3108,12 @@ class LinnyRModel {
|
|
3108
3108
|
// Set an array to [0, ..., run length] of numbers initialized as
|
3109
3109
|
// "not computed" to ensure that they will be evaluated "lazily"
|
3110
3110
|
// NOTES:
|
3111
|
-
// (1) the first element (0) corresponds to t = 0, i.e., the model
|
3112
|
-
// step just prior to the time step defined by start_period
|
3113
|
-
// (2)
|
3114
|
-
// element 0
|
3115
|
-
// (3) `other` specifies value for t = 1 and beyond if vector is
|
3116
|
-
// and has to to be initialized to a constant (typically 0)
|
3111
|
+
// (1) the first element (0) corresponds to t = 0, i.e., the model
|
3112
|
+
// time step just prior to the time step defined by start_period.
|
3113
|
+
// (2) All vectors must be initialized with an appropriate value for
|
3114
|
+
// element 0.
|
3115
|
+
// (3) `other` specifies value for t = 1 and beyond if vector is
|
3116
|
+
// static and has to to be initialized to a constant (typically 0).
|
3117
3117
|
v.length = this.runLength + 1;
|
3118
3118
|
v.fill(other);
|
3119
3119
|
v[0] = initial;
|
@@ -9800,6 +9800,11 @@ class Chart {
|
|
9800
9800
|
dy = 0,
|
9801
9801
|
x = 0,
|
9802
9802
|
y = rt + rh + font_height;
|
9803
|
+
// Store XY-area coordinates for use by Chart Manager.
|
9804
|
+
this.plot_ox = rl;
|
9805
|
+
this.plot_oy = rt + rh;
|
9806
|
+
this.plot_width = rw;
|
9807
|
+
this.plot_height = rh;
|
9803
9808
|
if(this.histogram) {
|
9804
9809
|
// Draw bin boundaries along the horizontal axis
|
9805
9810
|
dx = rw / this.bins;
|
@@ -9820,15 +9825,15 @@ class Chart {
|
|
9820
9825
|
// If multiple bars (`vv` is number of visible variables), draw
|
9821
9826
|
// ticks to mark horizontal area per run number.
|
9822
9827
|
if(vv > 1) {
|
9823
|
-
this.addSVG(['<line x1="', rl, '" y1="', rt + rh
|
9824
|
-
'" x2="', rl, '" y2="', rt + rh +
|
9828
|
+
this.addSVG(['<line x1="', rl, '" y1="', rt + rh,
|
9829
|
+
'" x2="', rl, '" y2="', rt + rh + 6,
|
9825
9830
|
'" stroke="black" stroke-width="1.5"/>']);
|
9826
9831
|
}
|
9827
9832
|
x = rl + dx;
|
9828
9833
|
for(let i = 0; i < runs.length; i++) {
|
9829
9834
|
if(vv > 1) {
|
9830
|
-
this.addSVG(['<line x1="', x, '" y1="', rt + rh
|
9831
|
-
'" x2="', x, '" y2="', rt + rh +
|
9835
|
+
this.addSVG(['<line x1="', x, '" y1="', rt + rh,
|
9836
|
+
'" x2="', x, '" y2="', rt + rh + 6,
|
9832
9837
|
'" stroke="black" stroke-width="1.5"/>']);
|
9833
9838
|
}
|
9834
9839
|
if(selx.plot_dimensions.length > 0) {
|
@@ -9920,22 +9925,31 @@ class Chart {
|
|
9920
9925
|
maxv *= (maxv > 0 ? 1.1 : 0.9);
|
9921
9926
|
if(minv < 0) minv *= 1.1;
|
9922
9927
|
}
|
9928
|
+
// For bar chart, maxv must be non-negative.
|
9929
|
+
if(stat_bars) maxv = Math.max(maxv, 0);
|
9923
9930
|
const range = maxv - minv;
|
9931
|
+
this.plot_min_y = minv;
|
9932
|
+
this.plot_max_y = maxv;
|
9924
9933
|
if(range > 0) {
|
9925
9934
|
const step = this.labelStep(range, 5, VM.NEAR_ZERO);
|
9926
9935
|
let x0 = rl,
|
9927
9936
|
y0 = rt + rh,
|
9928
9937
|
maxy = Math.ceil(maxv / step) * step,
|
9929
9938
|
miny = (minv >= 0 ? 0 : -Math.ceil(-minv / step) * step);
|
9939
|
+
this.plot_min_y = miny;
|
9940
|
+
this.plot_max_y = maxy;
|
9930
9941
|
y = miny;
|
9931
9942
|
const labels = [];
|
9932
9943
|
while(y <= maxy) {
|
9933
|
-
// NOTE:
|
9934
|
-
//
|
9935
|
-
|
9944
|
+
// NOTE: Large values having exponents will be "neat" numbers,
|
9945
|
+
// so then display fewer decimals, as these will be zeroes.
|
9946
|
+
const v = (Math.abs(y) > 1e5 ? VM.sig2Dig(y) : VM.sig4Dig(y));
|
9947
|
+
// NOTE: Force number to become a string so that its length
|
9948
|
+
// attribute can be used when drawing it.
|
9949
|
+
labels.push('' + v);
|
9936
9950
|
y += step;
|
9937
9951
|
}
|
9938
|
-
// First calculate dy as the vertical distance between labels
|
9952
|
+
// First calculate dy as the vertical distance between labels.
|
9939
9953
|
dy = rh / (labels.length - 1);
|
9940
9954
|
// Draw labels, starting at lowest Y
|
9941
9955
|
y = rt + rh;
|
@@ -9946,11 +9960,11 @@ class Chart {
|
|
9946
9960
|
y -= dy;
|
9947
9961
|
}
|
9948
9962
|
// Then calculate dx and dy as the respective horizontal and
|
9949
|
-
// vertical pixel equivalents of one unit
|
9963
|
+
// vertical pixel equivalents of one unit.
|
9950
9964
|
dx = rw / time_steps;
|
9951
9965
|
dy = rh / (maxy - miny);
|
9952
9966
|
y0 = rt + rh + dy * miny;
|
9953
|
-
// Draw axes Y = 0 and X = 0 in black and slightly thicker
|
9967
|
+
// Draw axes Y = 0 and X = 0 in black and slightly thicker.
|
9954
9968
|
this.addSVG(['<line x1="', x0, '" y1="', y0, '" x2="', x0 + rw,
|
9955
9969
|
'" y2="', y0, '" stroke="black" stroke-width="2"/>']);
|
9956
9970
|
this.addSVG(['<line x1="', x0, '" y1="', rt, '" x2="', x0,
|
@@ -10024,8 +10038,8 @@ class Chart {
|
|
10024
10038
|
const
|
10025
10039
|
rnr = runs[ri],
|
10026
10040
|
bv = bar_values[vi][rnr],
|
10027
|
-
|
10028
|
-
|
10041
|
+
barh = Math.abs(bv) * dy,
|
10042
|
+
bart = y0 - Math.max(0, bv) * dy;
|
10029
10043
|
x = rl + ri * dx + barsp + vcnt * varsp;
|
10030
10044
|
this.addSVG(['<rect x="', x, '" y="', bart,
|
10031
10045
|
'" width="', barw, '" height="', barh,
|
@@ -10328,8 +10342,8 @@ class ActorSelector {
|
|
10328
10342
|
// CLASS ExperimentRunResult
|
10329
10343
|
class ExperimentRunResult {
|
10330
10344
|
constructor(r, v, a='') {
|
10331
|
-
// NOTE:
|
10332
|
-
// or an XML node
|
10345
|
+
// NOTE: Constructor can be called with `v` a chart variable, a dataset,
|
10346
|
+
// or an XML node. When `v` is the equations dataset, then `a` is the
|
10333
10347
|
// identifier of the dataset modifier to be used.
|
10334
10348
|
this.run = r;
|
10335
10349
|
if(v instanceof ChartVariable) {
|
@@ -10350,12 +10364,11 @@ class ExperimentRunResult {
|
|
10350
10364
|
this.exceptions = VM.UNDEFINED;
|
10351
10365
|
this.last = VM.UNDEFINED;
|
10352
10366
|
} else {
|
10353
|
-
// Copy relevant properties of chart variable `v
|
10354
|
-
// NOTE:
|
10355
|
-
//
|
10356
|
-
//
|
10357
|
-
//
|
10358
|
-
// set the run_index for the chart of this variable
|
10367
|
+
// Copy relevant properties of chart variable `v`.
|
10368
|
+
// NOTE: Vector must be computed, unless the vector already has
|
10369
|
+
// length greater than 0. Computation will be for the running
|
10370
|
+
// experiment, so NO need to set the run_index for the chart of
|
10371
|
+
// this variable.
|
10359
10372
|
v.computeVector();
|
10360
10373
|
this.N = v.N;
|
10361
10374
|
this.sum = v.sum;
|
@@ -10366,13 +10379,14 @@ class ExperimentRunResult {
|
|
10366
10379
|
this.non_zero_tally = v.non_zero_tally;
|
10367
10380
|
this.exceptions = v.exceptions;
|
10368
10381
|
// NOTES:
|
10369
|
-
// (1)
|
10370
|
-
// (2)
|
10371
|
-
// vector may change again (for the next experiment, or when
|
10372
|
-
// a chart after a run)
|
10373
|
-
// (3) slice(0, N) takes elements 0 to N-1, so add 1 to run length
|
10382
|
+
// (1) Run results are vectors: "initial value" v[0] is also stored.
|
10383
|
+
// (2) Use slice() to make a copy of the vector, as the variable's
|
10384
|
+
// vector may change again (for the next experiment, or when
|
10385
|
+
// drawing a chart after a run).
|
10386
|
+
// (3) slice(0, N) takes elements 0 to N-1, so add 1 to run length.
|
10374
10387
|
this.vector = v.vector.slice(0, this.run.time_steps + 1);
|
10375
|
-
//
|
10388
|
+
// Use the last step of the experiment time period for the LAST
|
10389
|
+
// statistic.
|
10376
10390
|
this.last = (this.vector.length > 0 ?
|
10377
10391
|
this.vector[this.vector.length - 1] : VM.UNDEFINED);
|
10378
10392
|
}
|
@@ -10380,18 +10394,18 @@ class ExperimentRunResult {
|
|
10380
10394
|
// This dataset will be an "outcome" dataset => store statistics only
|
10381
10395
|
// @@TO DO: deal with wildcard equations: these will have *multiple*
|
10382
10396
|
// vectors associated with numbered entities (via #) and therefore
|
10383
|
-
// *all* these results should be stored (with # replaced by its value)
|
10397
|
+
// *all* these results should be stored (with # replaced by its value).
|
10384
10398
|
this.x_variable = false;
|
10385
10399
|
this.object_id = v.identifier;
|
10386
10400
|
if(v === MODEL.equations_dataset && a) {
|
10387
10401
|
this.attribute = a;
|
10388
10402
|
} else {
|
10389
10403
|
this.attribute = '';
|
10390
|
-
// NOTE:
|
10404
|
+
// NOTE: The running experiment determines the modifier.
|
10391
10405
|
const xx = MODEL.running_experiment;
|
10392
10406
|
if(xx) {
|
10393
10407
|
const mm = v.matchingModifiers(xx.activeCombination);
|
10394
|
-
// Use the first matching selector, as this is the most specific one
|
10408
|
+
// Use the first matching selector, as this is the most specific one.
|
10395
10409
|
if(mm.length > 0) this.attribute = mm[0].selector;
|
10396
10410
|
}
|
10397
10411
|
}
|
@@ -10401,18 +10415,18 @@ class ExperimentRunResult {
|
|
10401
10415
|
this.non_zero_tally = 0;
|
10402
10416
|
this.exceptions = 0;
|
10403
10417
|
const
|
10404
|
-
// NOTE:
|
10418
|
+
// NOTE: Run result dataset selector will be plain (no wildcards).
|
10405
10419
|
x = v.modifiers[this.attribute].expression,
|
10406
10420
|
t_end = MODEL.end_period - MODEL.start_period + 1;
|
10407
|
-
// N = # time steps
|
10421
|
+
// N = # time steps.
|
10408
10422
|
this.N = t_end;
|
10409
10423
|
let r,
|
10410
10424
|
// Use the time-scaled (!) vector of the dataset...
|
10411
10425
|
rv = v.vector;
|
10412
10426
|
if(x) {
|
10413
|
-
// ... or use the result of the modifier expression if defined
|
10427
|
+
// ... or use the result of the modifier expression if defined.
|
10414
10428
|
if(x.isStatic) {
|
10415
|
-
// For static expressions, statistics can be inferred directly
|
10429
|
+
// For static expressions, statistics can be inferred directly.
|
10416
10430
|
r = x.result(0);
|
10417
10431
|
this.mean = r;
|
10418
10432
|
this.sum = r * t_end;
|
@@ -10423,7 +10437,7 @@ class ExperimentRunResult {
|
|
10423
10437
|
} else if(Math.abs(r) > VM.NEAR_ZERO) {
|
10424
10438
|
this.non_zero_tally = t_end;
|
10425
10439
|
}
|
10426
|
-
// Preclude further computation of statistics
|
10440
|
+
// Preclude further computation of statistics.
|
10427
10441
|
rv = null;
|
10428
10442
|
} else {
|
10429
10443
|
// Ensure that expression vector is computed in full
|
@@ -10432,7 +10446,7 @@ class ExperimentRunResult {
|
|
10432
10446
|
}
|
10433
10447
|
}
|
10434
10448
|
if(rv) {
|
10435
|
-
// Do not include t = 0 in statistics
|
10449
|
+
// Do not include t = 0 in statistics.
|
10436
10450
|
for(let t = 1; t <= t_end; t++) {
|
10437
10451
|
r = rv[t];
|
10438
10452
|
// Map undefined values and all errors to 0
|
@@ -10446,68 +10460,71 @@ class ExperimentRunResult {
|
|
10446
10460
|
this.minimum = Math.min(this.minimum, r);
|
10447
10461
|
this.maximum = Math.max(this.maximum, r);
|
10448
10462
|
}
|
10449
|
-
// Compute the mean
|
10463
|
+
// Compute the mean.
|
10450
10464
|
this.mean = this.sum / t_end;
|
10451
|
-
// Compute the variance
|
10465
|
+
// Compute the variance.
|
10452
10466
|
let sumsq = 0;
|
10453
10467
|
for(let t = 1; t <= t_end; t++) {
|
10454
10468
|
r = rv[t];
|
10455
|
-
// Map undefined values and all errors to 0
|
10469
|
+
// Map undefined values and all errors to 0.
|
10456
10470
|
if(r < VM.MINUS_INFINITY || r > VM.PLUS_INFINITY) r = 0;
|
10457
10471
|
sumsq += Math.pow(r - this.mean, 2);
|
10458
10472
|
}
|
10459
10473
|
this.variance = sumsq / t_end;
|
10460
10474
|
this.last = rv[t_end];
|
10461
10475
|
}
|
10462
|
-
// Do not store the RR vector
|
10476
|
+
// Do not store the RR vector, since outcomes are meant to reduce
|
10477
|
+
// the amount of memory (and model file size).
|
10463
10478
|
this.vector = [];
|
10464
10479
|
} else {
|
10465
|
-
// Parsing run results while loading a file: `v` is an XML tree
|
10480
|
+
// Parsing run results while loading a file: `v` is an XML tree.
|
10466
10481
|
this.initFromXML(v);
|
10467
10482
|
}
|
10468
|
-
// The vector MAY need to be scaled to model time by different methods,
|
10469
|
-
// since this is likely to be rare, such scaling is performed
|
10470
|
-
// the method-specific vectors are initially set to NULL
|
10483
|
+
// The vector MAY need to be scaled to model time by different methods,
|
10484
|
+
// but since this is likely to be rare, such scaling is performed
|
10485
|
+
// "lazily", so the method-specific vectors are initially set to NULL.
|
10471
10486
|
this.resetScaledVectors();
|
10472
10487
|
}
|
10473
10488
|
|
10474
10489
|
resetScaledVectors() {
|
10475
|
-
// Set the special vectors to null, so they will be recalculated
|
10490
|
+
// Set the special vectors to null, so they will be recalculated.
|
10476
10491
|
this.scaled_vectors = {'NEAREST': [], 'MEAN': [], 'SUM': [], 'MAX': []};
|
10477
10492
|
}
|
10478
10493
|
|
10479
10494
|
get displayName() {
|
10480
|
-
//
|
10495
|
+
// Return the name of the result variable.
|
10481
10496
|
const
|
10482
10497
|
obj = MODEL.objectByID(this.object_id),
|
10483
10498
|
dn = obj.displayName;
|
10484
|
-
// NOTE:
|
10499
|
+
// NOTE: For equations dataset, only display the modifier selector.
|
10485
10500
|
if(obj === MODEL.equations_dataset) {
|
10486
10501
|
const m = obj.modifiers[this.attribute.toLowerCase()];
|
10487
10502
|
if(m) return m.selector;
|
10488
|
-
console.log('WARNING: Run result of non-existent equation',
|
10503
|
+
console.log('WARNING: Run result of non-existent equation',
|
10504
|
+
this.attribute);
|
10489
10505
|
return this.attribute;
|
10490
10506
|
}
|
10491
10507
|
return (this.attribute ? dn + '|' + this.attribute : dn);
|
10492
10508
|
}
|
10493
10509
|
|
10494
10510
|
get vectorString() {
|
10495
|
-
// Vector is stored as semicolon-separated floating point numbers
|
10496
|
-
// to N-digit precision to keep model files more compact
|
10511
|
+
// Vector is stored as semicolon-separated floating point numbers
|
10512
|
+
// reduced to N-digit precision to keep model files more compact.
|
10513
|
+
// By default, N = 6; this can be altered in linny-r-config.js.
|
10497
10514
|
if(this.was_ignored) return '';
|
10498
10515
|
let v = [],
|
10499
10516
|
prev = '',
|
10500
10517
|
cnt = 1;
|
10501
10518
|
for(let i = 0; i < this.vector.length; i++) {
|
10502
|
-
// Format number with desired precision
|
10519
|
+
// Format number with desired precision.
|
10503
10520
|
const f = this.vector[i].toPrecision(CONFIGURATION.results_precision);
|
10504
|
-
// While value is same as previous, do not store, but count
|
10521
|
+
// While value is same as previous, do not store, but count.
|
10505
10522
|
if(f === prev) {
|
10506
10523
|
cnt++;
|
10507
10524
|
} else {
|
10508
10525
|
if(cnt > 1) {
|
10509
|
-
// More than one => "compress"
|
10510
|
-
// NOTE:
|
10526
|
+
// More than one => "compress".
|
10527
|
+
// NOTE: Parse so JavaScript will represent it most compactly.
|
10511
10528
|
v.push(cnt + 'x' + parseFloat(prev));
|
10512
10529
|
cnt = 1;
|
10513
10530
|
} else if(prev) {
|
@@ -10516,10 +10533,10 @@ class ExperimentRunResult {
|
|
10516
10533
|
prev = f;
|
10517
10534
|
}
|
10518
10535
|
}
|
10519
|
-
// Add the last "batch" of numbers
|
10536
|
+
// Add the last "batch" of numbers.
|
10520
10537
|
if(cnt > 1) {
|
10521
|
-
// More than one => "compress"
|
10522
|
-
// NOTE:
|
10538
|
+
// More than one => "compress".
|
10539
|
+
// NOTE: Parse so JavaScript will represent it most compactly.
|
10523
10540
|
v.push(cnt + 'x' + parseFloat(prev));
|
10524
10541
|
cnt = 1;
|
10525
10542
|
} else if(prev) {
|
@@ -10529,7 +10546,7 @@ class ExperimentRunResult {
|
|
10529
10546
|
}
|
10530
10547
|
|
10531
10548
|
unpackVectorString(str) {
|
10532
|
-
//
|
10549
|
+
// Convert semicolon-separated data to a numeric array.
|
10533
10550
|
this.vector = [];
|
10534
10551
|
if(str && !this.was_ignored) {
|
10535
10552
|
const numbers = str.split(';');
|
@@ -10571,8 +10588,8 @@ class ExperimentRunResult {
|
|
10571
10588
|
this.x_variable = nodeParameterValue(node, 'x-variable') === '1';
|
10572
10589
|
this.was_ignored = nodeParameterValue(node, 'ignored') === '1';
|
10573
10590
|
this.object_id = xmlDecoded(nodeContentByTag(node, 'object-id'));
|
10574
|
-
// NOTE:
|
10575
|
-
// 1.3.0 and higher
|
10591
|
+
// NOTE: Special check to guarantee upward compatibility to version
|
10592
|
+
// 1.3.0 and higher.
|
10576
10593
|
let attr = nodeContentByTag(node, 'attribute');
|
10577
10594
|
if(this.object_id === UI.EQUATIONS_DATASET_ID &&
|
10578
10595
|
!earlierVersion(MODEL.version, '1.3.0')) attr = xmlDecoded(attr);
|
@@ -10590,40 +10607,40 @@ class ExperimentRunResult {
|
|
10590
10607
|
}
|
10591
10608
|
|
10592
10609
|
valueAtModelTime(t, mtsd, method, periodic) {
|
10593
|
-
//
|
10594
|
-
// NOTE:
|
10610
|
+
// Return the experiment result value for model time `t`.
|
10611
|
+
// NOTE: Result for t = 0 should always be v[0], irrespective of scaling.
|
10595
10612
|
if(t === 0 || this.was_ignored) return VM.UNDEFINED;
|
10596
|
-
// Now t will be > 0
|
10613
|
+
// Now t will be > 0.
|
10597
10614
|
const
|
10598
10615
|
rtsd = this.run.time_step_duration,
|
10599
|
-
// NOTE:
|
10616
|
+
// NOTE: Absolute scaling means "use time step t as index".
|
10600
10617
|
t_multiplier = (method === 'ABS' ||
|
10601
10618
|
Math.abs(rtsd - mtsd) < VM.NEAR_ZERO ? 1 : mtsd / rtsd);
|
10602
10619
|
let v = null,
|
10603
10620
|
ti = t;
|
10604
10621
|
if(t_multiplier !== 1 && !method) method = 'NEAREST';
|
10605
10622
|
if(t_multiplier === 1) {
|
10606
|
-
// If same time scale, use the result vector without any scaling
|
10607
|
-
// NOTE: vector[0] corresponds with t = 1
|
10623
|
+
// If same time scale, use the result vector without any scaling.
|
10624
|
+
// NOTE: vector[0] corresponds with t = 1.
|
10608
10625
|
v = this.vector;
|
10609
10626
|
} else if(this.scaled_vectors.hasOwnProperty(method)) {
|
10610
|
-
// Other methods: compute entire vector, anticipating on more "gets"
|
10627
|
+
// Other methods: compute entire vector, anticipating on more "gets".
|
10611
10628
|
v = this.scaled_vectors[method];
|
10612
10629
|
if(v.length <= 0) {
|
10613
|
-
// Infer the "official" method name
|
10630
|
+
// Infer the "official" method name.
|
10614
10631
|
let mcode = method.toLowerCase();
|
10615
10632
|
if(mcode === 'mean' || mcode === 'sum') mcode = 'w-' + mcode;
|
10616
|
-
// NOTE: scaleData expects "pure data", so slice off v[0]
|
10633
|
+
// NOTE: scaleData expects "pure data", so slice off v[0].
|
10617
10634
|
VM.scaleDataToVector(this.vector.slice(1), v, rtsd, mtsd, MODEL.runLength,
|
10618
10635
|
1, VM.UNDEFINED, periodic, mcode);
|
10619
|
-
// NOTE:
|
10620
|
-
// will depend on periodicity
|
10636
|
+
// NOTE: The scaled vector WILL have an "initial value" v[0], which
|
10637
|
+
// will depend on periodicity.
|
10621
10638
|
}
|
10622
10639
|
} else {
|
10623
|
-
// Unrecognized method
|
10640
|
+
// Unrecognized method.
|
10624
10641
|
return VM.UNDEFINED;
|
10625
10642
|
}
|
10626
|
-
// Apply periodicity while ignoring v[0] (which is only used when t=0)
|
10643
|
+
// Apply periodicity while ignoring v[0] (which is only used when t=0).
|
10627
10644
|
if(periodic) ti = (ti - 1) % (v.length - 1) + 1;
|
10628
10645
|
if(ti < v.length) return v[ti];
|
10629
10646
|
return VM.UNDEFINED;
|
@@ -10740,17 +10757,17 @@ class ExperimentRun {
|
|
10740
10757
|
}
|
10741
10758
|
|
10742
10759
|
addResults() {
|
10743
|
-
//
|
10744
|
-
// NOTE:
|
10760
|
+
// Add the experiment chart variables and outcomes as run results.
|
10761
|
+
// NOTE: Experiments may have different time step durations.
|
10745
10762
|
this.time_step_duration = MODEL.timeStepDuration;
|
10746
10763
|
// Reset each output chart to achieve that all chart variables will
|
10747
|
-
// be recomputed for the current model settings
|
10764
|
+
// be recomputed for the current model settings.
|
10748
10765
|
for(let i = 0; i < this.experiment.charts.length; i++) {
|
10749
10766
|
this.experiment.charts[i].resetVectors();
|
10750
10767
|
}
|
10751
|
-
// Calculate number of vectors/outcomes/equations to store
|
10768
|
+
// Calculate number of vectors/outcomes/equations to store.
|
10752
10769
|
this.oc_list = MODEL.outcomes;
|
10753
|
-
// NOTE:
|
10770
|
+
// NOTE: All equations are also considered to be outcomes.
|
10754
10771
|
this.eq_list = Object.keys(MODEL.equations_dataset.modifiers);
|
10755
10772
|
const
|
10756
10773
|
cv = this.experiment.variables.length,
|
@@ -10760,19 +10777,19 @@ class ExperimentRun {
|
|
10760
10777
|
if(cv) xr.push(pluralS(cv, 'variable'));
|
10761
10778
|
if(oc) xr.push(pluralS(oc, 'outcome'));
|
10762
10779
|
if(eq) xr.push(pluralS(eq, 'equation'));
|
10763
|
-
// NOTE:
|
10764
|
-
// a substantial amount of time
|
10765
|
-
// timeouts so that the browser can update the progress needle
|
10780
|
+
// NOTE: For long simulation periods, computing run results can take
|
10781
|
+
// a substantial amount of time. Hence it is performed using function
|
10782
|
+
// timeouts so that the browser can update the progress needle.
|
10766
10783
|
UI.setMessage('Processing experiment run results: ' + xr.join(', '));
|
10767
10784
|
UI.setProgressNeedle(0);
|
10768
10785
|
this.steps = cv + oc + eq;
|
10769
|
-
// Keep track of progress
|
10786
|
+
// Keep track of progress.
|
10770
10787
|
this.step = 0;
|
10771
10788
|
this.addChartResults(0);
|
10772
10789
|
}
|
10773
10790
|
|
10774
10791
|
addChartResults(vi) {
|
10775
|
-
// Add a run result object for chart variable with index `vi
|
10792
|
+
// Add a run result object for chart variable with index `vi`.
|
10776
10793
|
if(vi < this.experiment.variables.length) {
|
10777
10794
|
this.results.push(
|
10778
10795
|
new ExperimentRunResult(this, this.experiment.variables[vi]));
|
@@ -10785,9 +10802,9 @@ class ExperimentRun {
|
|
10785
10802
|
}
|
10786
10803
|
|
10787
10804
|
addOutcomeResults(oi) {
|
10788
|
-
// Add a run result object for outcome dataset with index `vi
|
10805
|
+
// Add a run result object for outcome dataset with index `vi`.
|
10789
10806
|
if(oi < this.oc_list.length) {
|
10790
|
-
// NOTE:
|
10807
|
+
// NOTE: This stores results only for "active" selectors (current run).
|
10791
10808
|
this.results.push(new ExperimentRunResult(this, MODEL.outcomes[oi]));
|
10792
10809
|
this.step++;
|
10793
10810
|
UI.setProgressNeedle(this.step / this.steps);
|
@@ -10798,22 +10815,22 @@ class ExperimentRun {
|
|
10798
10815
|
}
|
10799
10816
|
|
10800
10817
|
addEquationResults(ei) {
|
10801
|
-
// Add a run result object for equation with index `ei
|
10818
|
+
// Add a run result object for equation with index `ei`.
|
10802
10819
|
if(ei < this.eq_list.length) {
|
10803
10820
|
const k = this.eq_list[ei];
|
10804
|
-
// NOTE:
|
10821
|
+
// NOTE: Passing key `k` as 3rd parameter signals "use this attribute".
|
10805
10822
|
this.results.push(
|
10806
10823
|
new ExperimentRunResult(this, MODEL.equations_dataset, k));
|
10807
10824
|
this.step++;
|
10808
10825
|
UI.setProgressNeedle(this.step / this.steps);
|
10809
10826
|
setTimeout((x) => x.addEquationResults(ei + 1), 0, this);
|
10810
10827
|
} else {
|
10811
|
-
// Register when this result was stored
|
10828
|
+
// Register when this result was stored.
|
10812
10829
|
this.time_recorded = new Date().getTime();
|
10813
|
-
// Clear the progress needle
|
10830
|
+
// Clear the progress needle.
|
10814
10831
|
UI.setProgressNeedle(0);
|
10815
10832
|
UI.setMessage('');
|
10816
|
-
// Log the time it took to compute all results
|
10833
|
+
// Log the time it took to compute all results.
|
10817
10834
|
VM.logMessage(VM.block_count - 1,
|
10818
10835
|
`Processing run results took ${VM.elapsedTime} seconds.`);
|
10819
10836
|
// Report results if applicable.
|
@@ -10829,8 +10846,8 @@ class ExperimentRun {
|
|
10829
10846
|
}
|
10830
10847
|
|
10831
10848
|
addMessages() {
|
10832
|
-
//
|
10833
|
-
// they can be viewed when an experiment run is selected in the viewer
|
10849
|
+
// Store the message texts of the virtual machine (one per block) so that
|
10850
|
+
// they can be viewed when an experiment run is selected in the viewer.
|
10834
10851
|
this.warning_count = 0;
|
10835
10852
|
this.solver_seconds = 0;
|
10836
10853
|
for(let i = 0; i < VM.messages.length; i++) {
|
@@ -10846,7 +10863,7 @@ class ExperimentRun {
|
|
10846
10863
|
}
|
10847
10864
|
|
10848
10865
|
resetScaledVectors() {
|
10849
|
-
//
|
10866
|
+
// Set the vectors with scaled run results to NULL so they will recompute.
|
10850
10867
|
for(let i = 0; i < this.results.length; i++) {
|
10851
10868
|
this.results[i].resetScaledVectors();
|
10852
10869
|
}
|