Skip to content

Commit

Permalink
fix!: remove startTime and endTime from ModelSpec interface and handl…
Browse files Browse the repository at this point in the history
…e SAVEPER != 1 (#298)

Fixes #291
  • Loading branch information
chrispcampbell authored Dec 10, 2022
1 parent 2012603 commit 921014a
Show file tree
Hide file tree
Showing 41 changed files with 319 additions and 181 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ jobs:
pnpm install
- name: Install Emscripten
shell: bash
run: |
./scripts/install-emsdk
Expand Down
2 changes: 0 additions & 2 deletions examples/hello-world/sde.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ export async function config() {

modelSpec: async () => {
return {
startTime: 2000,
endTime: 2100,
inputs: [{ varName: 'Y', defaultValue: 0, minValue: -10, maxValue: 10 }],
outputs: [{ varName: 'Z' }],
datFiles: []
Expand Down
4 changes: 2 additions & 2 deletions examples/sir/config/model.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
model start time,model end time,graph default min time,graph default max time,model dat files
0,200,0,100,
graph default min time,graph default max time,model dat files
0,100,
4 changes: 2 additions & 2 deletions examples/template-default/config/model.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
model start time,model end time,graph default min time,graph default max time,model dat files
0,100,0,100,
graph default min time,graph default max time,model dat files
0,100,
7 changes: 1 addition & 6 deletions examples/template-default/packages/core/src/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ModelScheduler, Outputs } from '@sdeverywhere/runtime'
import { spawnAsyncModelRunner } from '@sdeverywhere/runtime-async'
import type { InputId } from '../config/generated/spec-types'
import { config } from '../config/config'
import { endTime, outputVarIds, startTime } from './generated/model-spec'
import { createModelInput, createSimpleInputValue, Input } from './inputs'
import modelWorkerJs from './generated/worker.js?raw'

Expand Down Expand Up @@ -97,7 +96,7 @@ export async function createModel(): Promise<Model> {
for (const inputSpec of config.inputs.values()) {
defaultInputs.push(createSimpleInputValue(inputSpec.varId, inputSpec.defaultValue))
}
const defaultOutputs = createOutputs()
const defaultOutputs = runner.createOutputs()
const initialOutputs = await runner.runModel(defaultInputs, defaultOutputs)

// Capture data from the reference run for the given variables; note that we
Expand Down Expand Up @@ -128,10 +127,6 @@ function createInputs(): Map<InputVarId, Input> {
return orderedInputs
}

function createOutputs(): Outputs {
return new Outputs(outputVarIds, startTime, endTime)
}

/**
* Return the set of output variables that are needed for reference data. This
* includes output variables that appear with a "Ref" dataset in one or more
Expand Down
5 changes: 0 additions & 5 deletions examples/template-minimal/sde.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ export async function config() {

modelSpec: async () => {
return {
// TODO: Change these values as desired (usually they will be the same as
// the `INITIAL TIME` and `FINAL TIME` values from the mdl, but you can
// use different values here)
startTime: 2000,
endTime: 2100,
inputs: [
// TODO: List your input variables here
{ varName: 'Y', defaultValue: 0, minValue: -10, maxValue: 10 }
Expand Down
16 changes: 0 additions & 16 deletions packages/build/docs/interfaces/ModelSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,6 @@ that should be included in the model generated by SDE.

## Properties

### startTime

**startTime**: `number`

The start time (year) for the model (typically the same as `INITIAL TIME`).

___

### endTime

**endTime**: `number`

The end time (year) for the model (typically the same as `FINAL TIME`).

___

### inputs

**inputs**: [`InputSpec`](InputSpec.md)[]
Expand Down
6 changes: 0 additions & 6 deletions packages/build/src/_shared/model-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ export interface OutputSpec {
* that should be included in the model generated by SDE.
*/
export interface ModelSpec {
/** The start time (year) for the model (typically the same as `INITIAL TIME`). */
startTime: number

/** The end time (year) for the model (typically the same as `FINAL TIME`). */
endTime: number

/** The input variable specs. */
inputs: InputSpec[]

Expand Down
2 changes: 0 additions & 2 deletions packages/build/tests/build/build-dev.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { build } from '../../src'
import { buildOptions } from '../_shared/build-options'

const modelSpec: ModelSpec = {
startTime: 2000,
endTime: 2100,
inputs: [{ varName: 'Y', defaultValue: 0, minValue: -10, maxValue: 10 }],
outputs: [{ varName: 'Z' }],
datFiles: []
Expand Down
2 changes: 0 additions & 2 deletions packages/build/tests/build/build-prod.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { build } from '../../src'
import { buildOptions } from '../_shared/build-options'

const modelSpec: ModelSpec = {
startTime: 2000,
endTime: 2100,
inputs: [{ varName: 'Y', defaultValue: 0, minValue: -10, maxValue: 10 }],
outputs: [{ varName: 'Z' }],
datFiles: []
Expand Down
2 changes: 0 additions & 2 deletions packages/build/tests/config/sde.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export async function config() {
modelFiles: [resolvePath(__dirname, '..', '_shared', 'sample.mdl')],
modelSpec: async () => {
return {
startTime: 2000,
endTime: 2100,
inputs: [{ varName: 'Y', defaultValue: 0, minValue: -10, maxValue: 10 }],
outputs: [{ varName: 'Z' }],
datFiles: []
Expand Down
2 changes: 1 addition & 1 deletion packages/create/src/step-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export async function chooseGenConfig(projDir: string, mdlPath: string): Promise
const modelCsvHeader = origModelCsvContent.split('\n')[0]

// Add line and write out updated `model.csv`
const modelCsvLine = `${initialTime},${finalTime},${initialTime},${finalTime},${datPart}`
const modelCsvLine = `${initialTime},${finalTime},${datPart}`
const newModelCsvContent = `${modelCsvHeader}\n${modelCsvLine}\n`
await writeFile(modelCsvFile, newModelCsvContent)

Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-check/src/vite-config-for-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ function injectModelSpec(prepDir: string, modelSpec: ModelSpec): VitePlugin {
const dataSizeInBytes = stagedFileSize('static-data.ts')

const moduleSrc = `
export const startTime = ${modelSpec.startTime};
export const endTime = ${modelSpec.endTime};
export const inputSpecs = ${JSON.stringify(inputSpecs)};
export const outputSpecs = ${JSON.stringify(outputSpecs)};
export const modelSizeInBytes = ${modelSizeInBytes};
Expand Down
18 changes: 10 additions & 8 deletions packages/plugin-check/template-bundle/src/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ import type {
Scenario
} from '@sdeverywhere/check-core'

import type { InputValue, InputVarId, ModelRunner, Point } from '@sdeverywhere/runtime'
import { Outputs } from '@sdeverywhere/runtime'
import type { InputValue, InputVarId, ModelRunner, Outputs, Point } from '@sdeverywhere/runtime'
import { spawnAsyncModelRunner } from '@sdeverywhere/runtime-async'

import type { Input } from './inputs'
import { getInputVars, setInputsForScenario } from './inputs'
import { getOutputVars } from './outputs'

import { startTime, endTime, inputSpecs, outputSpecs, modelSizeInBytes, dataSizeInBytes } from 'virtual:model-spec'
import { inputSpecs, outputSpecs, modelSizeInBytes, dataSizeInBytes } from 'virtual:model-spec'

import modelWorkerJs from '@_model_worker_/worker.js?raw'

Expand Down Expand Up @@ -50,8 +49,7 @@ export class BundleModel implements CheckBundleModel {

// Create an `Outputs` instance that is initialized to hold output data
// produced by the Wasm model
const outputVarIds = outputSpecs.map(o => o.varId)
this.outputs = new Outputs(outputVarIds, startTime, endTime)
this.outputs = modelRunner.createOutputs()
}

// from CheckBundleModel interface
Expand Down Expand Up @@ -149,9 +147,13 @@ export function createBundle(): Bundle {
outputVars,
implVars: new Map(),
inputGroups: new Map(),
datasetGroups: new Map(),
startTime,
endTime
datasetGroups: new Map()
// TODO: startTime and endTime are optional; the comparison graphs work OK if
// they are undefined. The main benefit of using these is to set a specific
// range for the x-axis on the comparison graphs, so maybe we should find
// another way to allow these to be defined.
// startTime,
// endTime
}

return {
Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-check/template-bundle/src/empty-model-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import type { InputSpec } from './inputs'
import type { OutputSpec } from './outputs'

export const startTime = 0
export const endTime = 0
export const inputSpecs: InputSpec[] = []
export const outputSpecs: OutputSpec[] = []
export const modelSizeInBytes = 0
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-config/src/__tests__/config1/model.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
model start time,model end time,graph default min time,graph default max time,model dat files
0,200,0,200,Data1.dat;Data2.dat
graph default min time,graph default max time,model dat files
0,200,Data1.dat;Data2.dat
16 changes: 1 addition & 15 deletions packages/plugin-config/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ export class ConfigContext {
private readonly configDir: string,
public readonly strings: Strings,
private readonly colorMap: Map<ColorId, HexColor>,
public readonly modelStartTime: number,
public readonly modelEndTime: number,
public readonly graphDefaultMinTime: number,
public readonly graphDefaultMaxTime: number,
public readonly datFiles: string[]
Expand Down Expand Up @@ -137,8 +135,6 @@ export class ConfigContext {
export function createConfigContext(buildContext: BuildContext, configDir: string): ConfigContext {
// Read basic model configuration from `model.csv`
const modelCsv = readConfigCsvFile(configDir, 'model')[0]
const modelStartTime = Number(modelCsv['model start time'])
const modelEndTime = Number(modelCsv['model end time'])
const graphDefaultMinTime = Number(modelCsv['graph default min time'])
const graphDefaultMaxTime = Number(modelCsv['graph default max time'])
const datFilesString = modelCsv['model dat files']
Expand All @@ -165,17 +161,7 @@ export function createConfigContext(buildContext: BuildContext, configDir: strin
colors.set(colorId, hexColor)
}

return new ConfigContext(
buildContext,
configDir,
strings,
colors,
modelStartTime,
modelEndTime,
graphDefaultMinTime,
graphDefaultMaxTime,
datFiles
)
return new ConfigContext(buildContext, configDir, strings, colors, graphDefaultMinTime, graphDefaultMaxTime, datFiles)
}

function configFilePath(configDir: string, name: string, ext: string): string {
Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-config/src/gen-model-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export function writeModelSpec(context: ConfigContext, dstDir: string): void {
}

emit('// This file is generated by `@sdeverywhere/plugin-config`; do not edit manually!')
emit(`export const startTime = ${context.modelStartTime}`)
emit(`export const endTime = ${context.modelEndTime}`)
emit(`export const inputVarIds: string[] = ${JSON.stringify(inputVarIds, null, 2)}`)
emit(`export const outputVarIds: string[] = ${JSON.stringify(outputVarIds, null, 2)}`)

Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-config/src/processor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ const specJson1 = `\

const modelSpec1 = `\
// This file is generated by \`@sdeverywhere/plugin-config\`; do not edit manually!
export const startTime = 0
export const endTime = 200
export const inputVarIds: string[] = [
"_input_a",
"_input_b",
Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-config/src/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ async function processModelConfig(buildContext: BuildContext, options: ConfigOpt
context.log('info', `Done generating files (${elapsed}s)`)

return {
startTime: context.modelStartTime,
endTime: context.modelEndTime,
inputs: context.getOrderedInputs(),
outputs: context.getOrderedOutputs(),
datFiles: context.datFiles
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-config/template-config/model.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
model start time,model end time,graph default min time,graph default max time,model dat files
0,100,0,100,Data1.dat;Data2.dat
graph default min time,graph default max time,model dat files
0,100,Data1.dat;Data2.dat
2 changes: 1 addition & 1 deletion packages/plugin-wasm/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ async function buildWasm(
addFlag('SINGLE_FILE=1')
addFlag('EXPORT_ES6=1')
addFlag('USE_ES6_IMPORT_META=0')
addFlag(`EXPORTED_FUNCTIONS=['_malloc','_runModelWithBuffers']`)
addFlag(`EXPORTED_FUNCTIONS=['_malloc','_getInitialTime','_getFinalTime','_getSaveper','_runModelWithBuffers']`)
addFlag(`EXPORTED_RUNTIME_METHODS=['cwrap']`)

await context.spawnChild(prepDir, command, args, {
Expand Down
2 changes: 0 additions & 2 deletions packages/plugin-worker/src/vite-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ function injectModelSpec(modelSpec: ModelSpec): VitePlugin {
const outputVarIds = modelSpec.outputs.map(o => sdeNameForVensimVarName(o.varName))

const moduleSrc = `
export const startTime = ${modelSpec.startTime};
export const endTime = ${modelSpec.endTime};
export const numInputs = ${modelSpec.inputs.length};
export const outputVarIds = ${JSON.stringify(outputVarIds)};
`
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-worker/template-worker/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { initWasmModelAndBuffers } from '@sdeverywhere/runtime'
// generate a worker that won't run correctly in Node or the browser.
import { exposeModelWorker } from '@sdeverywhere/runtime-async/worker'

import { startTime, endTime, numInputs, outputVarIds } from 'virtual:model-spec'
import { numInputs, outputVarIds } from 'virtual:model-spec'
import loadWasmModule from '@_wasm_'

async function initWasmModel() {
// Load the wasm module asynchronously
const wasmModule = await loadWasmModule()

// Initialize the wasm model and its associated buffers
return initWasmModelAndBuffers(wasmModule, numInputs, outputVarIds, startTime, endTime)
return initWasmModelAndBuffers(wasmModule, numInputs, outputVarIds)
}

exposeModelWorker(initWasmModel)
9 changes: 8 additions & 1 deletion packages/runtime-async/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { BlobWorker, spawn, Thread, Transfer, Worker } from 'threads'

import type { ModelRunner } from '@sdeverywhere/runtime'
import { Outputs } from '@sdeverywhere/runtime'

/**
* Initialize a `ModelRunner` that runs the model asynchronously in a worker thread.
Expand Down Expand Up @@ -56,16 +57,22 @@ async function spawnAsyncModelRunnerWithWorker(worker: Worker): Promise<ModelRun

// Wait for the worker to initialize the wasm model (in the worker thread)
const initResult = await modelWorker.initModel()
const rowLength: number = initResult.rowLength
let ioBuffer: ArrayBuffer = initResult.ioBuffer

// The row length is the number of elements in each row of the outputs buffer
const rowLength = initResult.rowLength

// Use a flag to ensure that only one request is made at a time
let running = false

// Disallow `runModel` after the runner has been terminated
let terminated = false

return {
createOutputs: () => {
return new Outputs(initResult.outputVarIds, initResult.startTime, initResult.endTime, initResult.saveFreq)
},

runModel: async (inputs, outputs) => {
if (terminated) {
throw new Error('Async model runner has already been terminated')
Expand Down
25 changes: 17 additions & 8 deletions packages/runtime-async/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ let inputsWasmBuffer: WasmBuffer
let outputsWasmBuffer: WasmBuffer

interface InitResult {
outputVarIds: string[]
startTime: number
endTime: number
saveFreq: number
rowLength: number
ioBuffer: ArrayBuffer
}
Expand All @@ -28,12 +32,12 @@ const modelWorker = {
}

// Initialize the wasm model and associated buffers
const result = await initWasmModel()
const wasmResult = await initWasmModel()

// Capture the `WasmModel` instance and `WasmBuffer` instances
wasmModel = result.model
inputsWasmBuffer = result.inputsBuffer
outputsWasmBuffer = result.outputsBuffer
wasmModel = wasmResult.model
inputsWasmBuffer = wasmResult.inputsBuffer
outputsWasmBuffer = wasmResult.outputsBuffer

// Create a combined array that will hold a copy of the inputs and outputs
// wasm buffers; this buffer is no-copy transferable, whereas the wasm ones
Expand All @@ -43,12 +47,17 @@ const modelWorker = {
const outputsLength = outputsWasmBuffer.getArrayView().length
const ioArray = new Float64Array(runTimeLength + inputsLength + outputsLength)

// The row length is the number of elements in each row of the outputs buffer
const rowLength = result.endTime - result.startTime + 1

// Transfer the underlying buffer to the runner
const ioBuffer = ioArray.buffer
return Transfer({ rowLength, ioBuffer }, [ioBuffer])
const initResult: InitResult = {
outputVarIds: wasmResult.outputVarIds,
startTime: wasmModel.startTime,
endTime: wasmModel.endTime,
saveFreq: wasmModel.saveFreq,
rowLength: wasmModel.numSavePoints,
ioBuffer
}
return Transfer(initResult, [ioBuffer])
},

runModel(ioBuffer: ArrayBuffer): TransferDescriptor<ArrayBuffer> {
Expand Down
Loading

0 comments on commit 921014a

Please sign in to comment.