You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# `simulation` - Simulation and modeling for Node and the browser
1
+
# `simulation` - Simulation and modeling for Node and browsers
2
2
3
3
`simulation` is a multi-method simulation package for Node or the browser. Use it to create models for the environment, business, or other areas. For example, it can be used to create models of disease spread, population growth, or the adoption of a product in the marketplace.
4
4
5
5
`simulation` supports differential equation models (also called System Dynamics models) in addition to Agent Based Models, or any mixture of the two techniques.
6
6
7
-
In addition to building models directly with the package, `simulation` also supports importing and running models built with [Insight Maker](https://insightmaker.com).
7
+
In addition to building models directly with the package, `simulation` also supports importing and running models in the [ModelJSON](https://github.com/scottfr/modeljson) format or the [Insight Maker](https://insightmaker.com) format.
8
8
9
-
## Installing the package
9
+
## Quickstart
10
10
11
-
### Installation with NPM
11
+
Copy this HTML into an *index.html* file and open it in your browser.
Note that this neither bundles nor minifies the code. For production use cases, it is recommended to use a bundler.
70
+
71
+
## Installing with NPM
72
+
73
+
To use the package with NPM and Node.js, run this command:
14
74
15
75
```shell
16
76
npm install --save simulation
@@ -24,16 +84,6 @@ In the README, we will also be using the optional `simulation-viz-console` packa
24
84
npm install --save simulation-viz-console
25
85
```
26
86
27
-
### Directly importing the modules
28
-
29
-
You can also import `simulation` ES6 modules directly from the source code without using NPM:
30
-
31
-
```javascript
32
-
import { Model } from"simulation/src/api/Model.js";
33
-
```
34
-
35
-
The code will work without transpilation in modern browsers.
36
-
37
87
## Example usage
38
88
39
89
### Our first simulation model
@@ -166,7 +216,7 @@ Let's now look at a more complex model: disease spread. One simple way to model
166
216
167
217
***Susceptible** people who are healthy and can be infected,
168
218
***Infected** people who are sick and spreading the disease,
169
-
* and, **Recovered** people who were infected but are now better. We'll also assume recovered people and are now immune to the disease.
219
+
* and, **Recovered** people who were infected but are now better. We'll also assume recovered people are now immune to the disease.
170
220
171
221
We'll use three stocks to represent these categories, and we'll use flows to move people between them.
172
222
@@ -437,9 +487,9 @@ When building interactive simulations, you can adjust values within the simulati
437
487
438
488
To do so, use the `simulateAsync` method of a `Model`. `simulateAsync` returns a promise that resolves to the completed simulation results or rejects with an error.
439
489
440
-
`simulateAsync` takes a single parameter containing an object with an async `onPause` function. `onPause` is awaited whenever the simulation is paused. You can specify how often the simulation is paused with the `timePause` model property (set it to the same value as the time step to pause each time step) or by calling the `pause()` function within the simulation.
490
+
`simulateAsync` takes a single parameter containing an object with an async `onStep` function. `onStep` is awaited at the end of each time step.
441
491
442
-
When `onPause` is called, it is passed the current simulation state along with a `setValue(primitive, value)` method. Calling `setValue` sets the current value of `primitive` to `value`.
492
+
When `onStep` is called, it is passed the current simulation state along with a `setValue(primitive, value)` method. Calling `setValue` sets the current value of `primitive` to `value`.
443
493
444
494
Here is an example of an interactive simulation where the user decides how much water flows into a bucket each time step:
445
495
@@ -468,8 +518,7 @@ let m = new Model({
468
518
timeStart:2020,
469
519
timeLength:5,
470
520
timeUnits:"Years",
471
-
timeStep:1,
472
-
timePause:1// Pause the simulation each year
521
+
timeStep:1
473
522
});
474
523
475
524
@@ -486,7 +535,11 @@ let inflow = m.Flow(null, bucket, {
486
535
487
536
488
537
let results =awaitm.simulateAsync({
489
-
onPause:async (simulation) => {
538
+
onStep:async (simulation) => {
539
+
if (simulation.time===m.timeStart+m.timeLength) {
540
+
// It's the end of the simulation, so we don't need to ask for input
541
+
return;
542
+
}
490
543
console.log(`[Time: ${simulation.time}; Current bucket volume: ${simulation.results.value(bucket, simulation.time)}]`);
491
544
492
545
let newRate =awaitgetNumber("Enter the new inflow rate as a number (e.g. 5 or 2.7): ");
@@ -504,7 +557,7 @@ process.exit();
504
557
505
558
## Equations
506
559
507
-
`simulation` uses a DSL for its equations. This allows us to cleanly implement features like built-in units and vectors.
560
+
`simulation` uses a DSL for its equations. This allows us to cleanly implement features like built-in units and vectors. Documentation for the equation capabilities are available [here](/equations.md). A brief overview of capabilities follows.
508
561
509
562
Values of other primitives are referenced with the notation `[Primitive Name]`. When referencing a primitive, the primitives must either be connected directly (e.g. a flow connected to a stock) or connected via a link (e.g. `Model.link(referencedPrimitive, referencingPrimitive)`).
510
563
@@ -574,9 +627,7 @@ add(1, 2)
574
627
575
628
### Built-in functions
576
629
577
-
See here for a list of built-in functions:
578
-
579
-
https://insightmaker.com/functions
630
+
`simulation` has an [extensive list of built-in functions](/equations.md).
580
631
581
632
582
633
## Simulation algorithms
@@ -606,6 +657,42 @@ The 4th order Runge Kutta method is more complex and requires four different flo
606
657
Model accuracy may be increased by decreasing the time step (at the cost of increased computation). Cutting the time step in half will double the computation required. Between the two methods, Runge Kutta is more accurate per unit of computation than Euler's method. The exception is if your model contains sharp discontinuities in flow rates (like step functions), in which case the averaging behavior in the Runge Kutta method may not be desirable.
607
658
608
659
660
+
661
+
## Importing and exporting ModelJSON files
662
+
663
+
`simulation` supports importing and exporting models using the [ModelJSON format](https://github.com/scottfr/modeljson).
664
+
665
+
Here we load a ModelJSON model and run it. Then we modify the model and convert the changed model back to ModelJSON.
0 commit comments