Support for this feature under the Legacy Compiler is entering its sunset period as part of the work to deprecate the Legacy Compiler. All users of this feature should migrate their projects away from the Legacy Compiler as soon as possible. |
JavaScript export is a restricted feature which allows you to export a Project as a JavaScript file. If you would like access to this feature, please e-mail contact@silicoai.com
The exported file contains code necessary to run the calculations of the simulation, independently of the Silico application, for embedding into smart dashboards, data pipelines, or other advanced use-cases. This feature (and associated documentation) is intended for use by those with existing programming knowledge.
In order to function correctly, the exported code also needs to have access to the Silico Standard Library. This is distributed separately as a zip archive, and can be found linked in the Project Export modal (see below).
Project Export is accessible through the Project menu, under "Export to JavaScript". This will open a modal, which has a text area containing the export of the model as a JavaScript module.
The overall structure of the generated code is a prelude, consisting of implementations of builtin functions, reused code, etc. A set of Model classes then follows, one for each Model within the project. A top level Project data structure then follows that, allowing to access the Models within that Project by name.
A documented TypeScript description of the generated JS classes is as follows:
To simplify migration of projects for users, the API generated by the legacy compiler and the default compiler are the same. However, the API will evolve in future; keep an eye out for deprecation notices. |
/**
* Data for a single sketch associated with an element.
*/
export interface Sketch {
/** The tick from which the Sketch starts. */
start: number;
/**
* A dense array of values for the sketch, offset from `start`.
* Missing values can be marked using `NaN` values within the array.
* */
values: number[];
}
/**
* The output of compiling a Model within a Project. This wraps the model into a stateful
* class, which can compute arrays of output values.
*/
export declare class CompiledModel {
/** The current tick the Project is at */
public readonly tick: number;
/** The output arrays associated with each compute element. */
public readonly outputs: Float64Array[];
/**
* Calculate a single internal step of the Project, as defined by `resolution`.
* Will be replaced or made internal upon changes to resolution.
*
* Must be called once before using the `step()` function, to initialise the
* zero tick value of the Project.
*/
public calc(): void;
/**
* Calculate a full step of the project, accounting for `resolution`.
*/
public step(): void;
/**
* Run the project through to the defined endpoint, as given in the
* constructor. Appropriately called `calc`/`step` as required, so can be
* safely called straight after construction of an instance.
*/
public runToEnd(): void;
/**
* Find the output offset for a given element ID.
* This offset can be used to directly access outputs in the `outputs` field.
*/
public getOffsetById(elementId: number): number | undefined;
/**
* Override the value of a given element, by its data offset. See `setInput`
* for more detail on the behaviour of overriding elements in this way.
*/
public setInputByOffset(offset: number, value: number): void;
/**
* Return the model instance of the given submodel element.
*
* @param elementId ID of the Submodel element.
*/
public getSubmodelById(elementId: number): CompiledModel | undefined;
/**
* Override the value for the given named element. This is a helper method around
* `setInputByOffset` and `getOffsetById` and `getId`. See `getId` for specific details
* on name resolution.
*
* Once a value has been overriden, it will continue to use that set value, and not
* recalculate. This can be used for Stocks, Flows and Variables. Stocks overriden by
* this method will continue to be affected by connected flows.
*/
public setInput(panelName: string, paramName: string, value: number): void;
/**
* Static method, allowing to find the element id for a given name. The
* `panelName` is the name of the panel containing the element. The root
* level panel has the same name as the project, and can be checked in the UI
* at the left when viewing the root panel.
*/
public static getId(
panelName: string,
elementName: string,
): number | undefined;
/**
* Lookup the output values for a given name. This is a helper method around
* `getOffsetById`, `getId` and the `outputs` field, refer to `getId` for specifics
* on name resolution.
**/
public getValues(
panelName: string,
elementName: string,
): Float64Array | undefined;
/**
* Static method, returning the panels that exist within the model.
*/
public static getPanels(): PanelMetadata[];
/**
* Static map, representing the metadata for all elements within this model,
* keyed by the elementId.
*/
public elementMetadata: { [elementId: number]: ElementMetadata };
}
/**
* Metadata for an individual panel within a model.
*/
interface PanelMetadata {
name: string;
root: boolean;
}
/**
* Metadata for an individual element within a panel.
*/
interface NormalElement {
id: number;
panel: string;
type: "Variable" | "Flow" | "Stock" | "LookupTable";
name: string;
}
interface DataTableElement {
id: number;
panel: string;
type: "DataTable";
name: string;
columns: { id: number; name: string }[];
}
interface SubmodelElement {
id: number;
panel: string;
type: "Submodel";
name: string;
model: string;
}
type ElementMetadata = NormalElement | DataTableElement | SubmodelElement;
export interface CompiledProject {
byName: { [key: string]: typeof CompiledModel };
byId: { [key: number]: typeof CompiledModel };
buildRun: (modelName: string) => RunBuilder;
}
/**
* Main builder for creating a run of a project.
*
* At present, you should ensure time settings are configured before models
* are configured, as they are used for interpreting sketch data without an
* explicit start time.
*
* ```
* var builder = Project.buildRun("My Model");
* builder.setStartTime(2000).setStepCount(30);
* builder.configureModel("My Model")
* .setSketch({ element: "My Element", values: [4, 5, 6] })
* .setLookup({ panel: "My Panel", element: "Lookup 1", table: {
* 0: 4,
* 7: 15,
* 10: 16
* }});
* var run = builder.run();
* ```
*/
export declare class RunBuilder {
/**
* Set the starting tick of the run.
*/
setStartTime(startTime: number): this;
/**
* Set the number of steps for the run to take. For example, 10 steps with a
* starting tick of 20 would generate 11 values at [20, 21, .., 29, 30].
*/
setStepCount(stepCount: number): this;
/**
* Set resolution for this run. This determines the number of calculations done
* per step inbetween each tick. The default is 1.
*
* @deprecated Time settings are likely to change to an alternative to
* resolution in the future.
*/
setResolution(resolution: number): this;
/**
* Retrieve the configuration object for the given model. Will return the same
* object for the same model if called multiple times.
*/
configureModel(modelName: string): ModelConfiguration;
/**
* Start the run, but only initialise, don't step through time.
*
* Use if you want to interactively step through the run, changing inputs, etc.
*/
start(): CompiledModel;
/**
* Start the run, and calculate through to the end tick.
*
* Helpful method if just wanting to change data inputs to a run and then
* retrieve results.
*/
run(): CompiledModel;
}
/**
* Configuration for a Model within a
*/
export declare class ModelConfiguration {
/**
* Set the sketch for an element.
*
* Element name and values must be given, with optionally a panel name
* and a start time. If panel name is skipped, the root panel is assumed.
* If the start time is skipped, the configured start time of the parent
* RunBuilder (at the time of being called) is used.
*/
setSketch(config: {
panel?: string;
element: string | number;
start?: number;
values: number[];
}): this;
/**
* Override a sketch within a submodel element.
*
* Similarly to `setSketch`, element must be given and panel optionally.
* Element must resolve to a submodel element, with `targetElement`/`targetPanel`
* functioning the same as to `element`/`panel`, but for within the model the
* submodel is an instance of.
*/
setSubmodelSketch(config: {
panel?: string;
element: string | number;
targetPanel?: string;
targetElement: string | number;
start?: number;
values: number[];
}): this;
/**
* Associate lookup table data with the provided Lookup, with `element`/`panel`
* functioning in the same was as described for `setSketch`.
*
* `table` should be a map from x to y values, which will be used as the lookup.
* E.g. `table: { 4: 5, 10: 8 }` {x=4, y=5}, {x=10, y=8}, so for x values below
* 4, this will return 5, and x values above 10 will return 8. Values of x
* inbetween 4 and 10 will be interpolated between 5 and 8.
*/
setLookup(config: {
panel?: string;
element: string | number;
table: { [x: number]: number };
}): this;
/**
* Associate dataset data with the provided DataTable, with `element`/`panel`
* functioning in the same was as described for `setSketch`.
*
* `columns` should be a map from column name to sketch data, with `start` and
* `values` functioning in the same way as described for `setSketch`.
*/
setDataset(config: {
panel?: string;
element: string | number;
columns: { [columnName: string]: { start?: number; values: number[] } };
}): this;
}
The general flow in using this API is as follows:
- Add a
var $stdlib = require("...");
statement to the top of the file, importing the standard library. The imported value must be named$stdlib
. -
Use
Project.buildRun(modelName: string)
to create aRunBuilder
that can then be used to configure time and data associated with a run. This creates a project with the entry-point model set to the specified model. -
Configure the
RunBuilder
both at the top level, as well as per-model within the project viaRunBuilder#configureModel(modelName)
. This should be done for each model, if using a model with submodels. -
Get a configured
CompiledModel
, either throughRunBuilder#start()
for an interactive run, orRunBuilder#run()
for non-interactive. -
Control the model with e.g.
setInput
,step
andrunToEnd
. -
Retrieve values from the model using
getValues
.
An example of using the compiled model, running 10 steps, is as follows:
var run = Project.buildRun("My Model").setStartTime(0).setStepCount(10).run(); console.log(run.getValues("My Model", "Flow 1")); console.log(run.getValues("Panel 1", "Panel Var"));
Inputs to models can be handled either via overriding them as inputs, or via sketches.
An example of setting the value of a element is:
var run = Project.buildRun("My Model").setStartTime(0).setStepCount(10).start(); run.setInput("Panel 1", "My Variable", 10); run.runToEnd();
An example of assigning sketch values for the element Flow 1 in the root panel is:
var builder = Project.buildRun("My Model").setStartTime(0).setStepCount(10); builder.configureModel("My Model").setSketch({ element: "Flow 1", start: 5, values: [5, 2, 4, 4] }); var run = builder.run();
The API provided is not covered by any stability guarantee at this stage. If you have any feedback on the API or requirements for possible integrations, please do get in touch with us at contact@silicoai.com.
Comments
0 comments
Please sign in to leave a comment.