@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/README.md +66 -39
- package/dist/index.cjs +1537 -222
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +760 -179
- package/dist/index.d.ts +760 -179
- package/dist/index.js +1520 -214
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# @sdeverywhere/runtime
|
|
2
2
|
|
|
3
|
-
This package provides a simplified API around a System Dynamics model as generated
|
|
3
|
+
This package provides a simplified runtime API around a System Dynamics model as generated
|
|
4
|
+
by the [SDEverywhere](https://github.com/climateinteractive/SDEverywhere) transpiler.
|
|
5
|
+
|
|
6
|
+
Note that the SDEverywhere transpiler can be configured to generate model code in different formats:
|
|
7
|
+
|
|
8
|
+
- JavaScript code, which can be used directly without an extra compilation step, or
|
|
9
|
+
- C code, which can be compiled to a more optimized WebAssembly (Wasm) module (this requires an extra tool called [Emscripten](https://emscripten.org); see the `@sdeverywhere/plugin-wasm` package for more details)
|
|
10
|
+
|
|
11
|
+
The `@sdeverywhere/runtime` package presents a format-agnostic API that can be used to
|
|
12
|
+
run your model, regardless of whether you generate a pure JavaScript model or a WebAssembly
|
|
13
|
+
model.
|
|
4
14
|
|
|
5
15
|
## Quick Start
|
|
6
16
|
|
|
@@ -27,50 +37,58 @@ _NOTE:_ If you followed the "Quick Start" instructions and/or used the
|
|
|
27
37
|
steps listed below are already implemented for you in the generated `core` package,
|
|
28
38
|
and you can work directly with a `ModelRunner` and/or `ModelScheduler` instance.
|
|
29
39
|
|
|
30
|
-
### 1.
|
|
40
|
+
### 1. Import your generated model
|
|
31
41
|
|
|
32
|
-
In your application,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
In your application, import the model file that was generated by the SDEverywhere
|
|
43
|
+
transpiler.
|
|
44
|
+
Depending on how you configured your project (for example, if you set a different
|
|
45
|
+
`prepDir`), the generated model file may be in a different location than what is
|
|
46
|
+
shown in this example, but the approach will generally be the same.
|
|
36
47
|
|
|
37
48
|
```ts
|
|
38
|
-
import
|
|
39
|
-
import loadWasm from './generated/mymodel'
|
|
40
|
-
|
|
41
|
-
// These are the same lists (and must be in the same order) as the spec file passed to `sde`.
|
|
42
|
-
const inputVarNames = [] // from spec.json
|
|
43
|
-
const outputVarNames = [] // from spec.json
|
|
44
|
-
|
|
45
|
-
async function initWasmModel(): Promise<WasmModelInitResult> {
|
|
46
|
-
// Load the wasm module asynchronously
|
|
47
|
-
const wasmModule = await loadWasm()
|
|
48
|
-
|
|
49
|
-
// Initialize the wasm model and its associated buffers
|
|
50
|
-
return initWasmModelAndBuffers(wasmModule, inputVarNames.length, outputVarNames)
|
|
51
|
-
}
|
|
49
|
+
import loadGeneratedModel from './sde-prep/generated-model.js'
|
|
52
50
|
```
|
|
53
51
|
|
|
54
|
-
### 2. Initialize
|
|
52
|
+
### 2. Initialize a `ModelRunner`
|
|
55
53
|
|
|
56
54
|
The next step is to create a `ModelRunner` instance, which simplifies
|
|
57
55
|
the process of running a `WasmModel` with a given set of inputs and
|
|
58
56
|
parsing the outputs.
|
|
59
57
|
The `ModelRunner` produces an `Outputs` instance that provides easy
|
|
60
58
|
access to time series data for each output variable in the model.
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
|
|
60
|
+
Note that SDEverywhere offers two implementations of the `ModelRunner`
|
|
61
|
+
interface:
|
|
62
|
+
|
|
63
|
+
- The `createSynchronousModelRunner` function creates a `ModelRunner`
|
|
64
|
+
that runs your generated model on the main JavaScript thread. This
|
|
65
|
+
is the simplest option and is sufficient for small models, but for
|
|
66
|
+
larger models that take longer to run, it may block the JavaScript
|
|
67
|
+
thread and cause your application to appear unresponsive.
|
|
68
|
+
- The `spawnAsyncModelRunner` function (in the separate
|
|
69
|
+
`@sdeverywhere/runtime-async` package) provides an alternative
|
|
70
|
+
implementation of `ModelRunner` that runs your generated model in
|
|
71
|
+
a Web Worker or Node.js worker thread. This requires an extra
|
|
72
|
+
build-time step (see the `@sdeverywhere/plugin-worker` package),
|
|
73
|
+
but the benefit of an asynchronous runner is that the model can
|
|
74
|
+
run in a separate thread, which frees up the main thread for user
|
|
75
|
+
interface work and other computation.
|
|
76
|
+
|
|
77
|
+
The following example demonstrates the use of the
|
|
78
|
+
`createSynchronousModelRunner` function:
|
|
63
79
|
|
|
64
80
|
```ts
|
|
65
|
-
import {
|
|
81
|
+
import { createSynchronousModelRunner } from '@sdeverywhere/runtime'
|
|
82
|
+
import loadGeneratedModel from './sde-prep/generated-model.js'
|
|
66
83
|
|
|
67
84
|
async function main() {
|
|
68
|
-
// Initialize the `
|
|
69
|
-
const
|
|
70
|
-
const modelRunner =
|
|
85
|
+
// Initialize the `ModelRunner`
|
|
86
|
+
const generatedModel = await loadGeneratedModel()
|
|
87
|
+
const modelRunner = createSynchronousModelRunner(generatedModel)
|
|
71
88
|
|
|
72
|
-
// Create
|
|
73
|
-
|
|
89
|
+
// Create an array that holds the model input values; these must be in the same order
|
|
90
|
+
// as the inputs that are specified in your `sde.config.js` or `spec.json` file
|
|
91
|
+
const inputs = [2, 10] // etc
|
|
74
92
|
|
|
75
93
|
// Create an `Outputs` instance to hold the model outputs
|
|
76
94
|
let outputs = modelRunner.createOutputs()
|
|
@@ -84,21 +102,28 @@ async function main() {
|
|
|
84
102
|
console.log(`Temperature change in 2100: ${tempChangeIn2100}`)
|
|
85
103
|
```
|
|
86
104
|
|
|
87
|
-
See the `@sdeverywhere/runtime-async` package for an alternative
|
|
88
|
-
implementation of `ModelRunner` that allows for running a model in a Web
|
|
89
|
-
Worker or Node.js worker thread.
|
|
90
|
-
|
|
91
105
|
### 3. Initialize a `ModelScheduler` (optional)
|
|
92
106
|
|
|
93
|
-
If you build a more complex application with a user interface around a
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
If you build a more complex application with a user interface around a model
|
|
108
|
+
(especially with a responsive web framework such as Svelte, Vue, React, etc),
|
|
109
|
+
the `ModelScheduler` class takes care of automatically scheduling and running
|
|
110
|
+
the model whenever there are changes to input variables:
|
|
96
111
|
|
|
97
112
|
```ts
|
|
98
|
-
import { ModelScheduler } from '@sdeverywhere/runtime'
|
|
113
|
+
import { createInputValue, createSynchronousModelRunner, ModelScheduler } from '@sdeverywhere/runtime'
|
|
114
|
+
import loadGeneratedModel from './sde-prep/generated-model.js'
|
|
99
115
|
|
|
100
116
|
async function initModel() {
|
|
101
|
-
// Initialize the `
|
|
117
|
+
// Initialize the `ModelRunner`
|
|
118
|
+
const generatedModel = await loadGeneratedModel()
|
|
119
|
+
const modelRunner = createSynchronousModelRunner(generatedModel)
|
|
120
|
+
|
|
121
|
+
// Create an array of reactive `InputValue` instances; these must be in the same order
|
|
122
|
+
// as the inputs that are specified in your `sde.config.js` or `spec.json` file
|
|
123
|
+
const inputs = [createInputValue('_input1', 2), createInputValue('_input2', 0)] // etc
|
|
124
|
+
|
|
125
|
+
// Create a `ModelScheduler`
|
|
126
|
+
const outputs = modelRunner.createOutputs()
|
|
102
127
|
const modelScheduler = new ModelScheduler(modelRunner, inputs, outputs)
|
|
103
128
|
|
|
104
129
|
// Get notified when new output data is available
|
|
@@ -128,16 +153,18 @@ $ emcc \
|
|
|
128
153
|
build/<mymodel>.c build/macros.c build/model.c build/vensim.c \
|
|
129
154
|
-Ibuild -o ./output/<mymodel>.js -Wall -Os \
|
|
130
155
|
-s STRICT=1 -s MALLOC=emmalloc -s FILESYSTEM=0 -s MODULARIZE=1 \
|
|
131
|
-
-s EXPORTED_FUNCTIONS="['_malloc','_getInitialTime','_getFinalTime','_getSaveper','_runModelWithBuffers']" \
|
|
156
|
+
-s EXPORTED_FUNCTIONS="['_malloc','_free','_getInitialTime','_getFinalTime','_getSaveper','_setLookup','_runModelWithBuffers']" \
|
|
132
157
|
-s EXPORTED_RUNTIME_METHODS="['cwrap']"
|
|
133
158
|
```
|
|
134
159
|
|
|
135
160
|
Note that the generated module must export the following functions at minimum:
|
|
136
161
|
|
|
137
162
|
- `_malloc`
|
|
163
|
+
- `_free`
|
|
138
164
|
- `_getInitialTime`
|
|
139
165
|
- `_getFinalTime`
|
|
140
166
|
- `_getSaveper`
|
|
167
|
+
- `_setLookup`
|
|
141
168
|
- `_runModelWithBuffers`
|
|
142
169
|
- `cwrap`
|
|
143
170
|
|