Simile documentation and help

What’s new?

New features of Simile versions 6 and 7. The latest version of this help can be found online at simulistics.com

Getting started: how to build and run a simple model

Learn basic techniques for working with model diagrams, adding equations, running models and displaying the results

Graphical modelling in Simile

Introduction to Simile's graphical language, components and associated concepts

Working with model diagrams

Zooming; changing what is displayed; changing scale; printing

Working with equations

How to formulate equations; functions; sketched-graph and tabulated relationships

Working with submodels

Types of submodel; saving submodels as models; loading submodels from file; plug-and-play modularity

Running models

Preparing a model for running; running the model; displaying results

Working with external data

Loading parameter values, time-series data and other values into a model at run time: the scenario file mechanism

Scripting

            Writing scripts to automate repetitive tasks or to batch model simulations

Working with files

Opening and saving models, exporting model code and graphics

New in recent versions

New in version 7.0:

Experiment setup

A model can now be run simultaneously with its default parameters and with various other combinations of parameters, using multiple processors if they are available. Results for all cases are shown together and the experiment setup can be saved for use with different versions of the model.

All files saved together

Simile’s saved model file now also contains the helper setup information, the parameter metadata and the experiment setup all together. They can still be saved and loaded separately for transferring between models.

Changes to parameter handling

Equation sets default value for fixed parameter

This matches the behaviour for variable parameters, although fixed parameters do not have to have a value in the model or min/max values.

Parameter array/list format is now JSON

The format for values for matrices etc. or lists of time points was previously Simile’s own, now JSON objects can be cut and pasted in the parameter tab

File parameters are now a tab in explorer pane

They can be adjusted without opening a separate dialogue. This tab also contains the experiment setup.

Interface is more responsive

Model execution now happens in a separate thread at the code level rather than the scripting language level, meaning more responsiveness during long runs.

Text size can be customized

As screens get higher and higher resolution, default text sizes are more likely to be difficult to use. Simile’s new text size preference option affects the whole user interface layout to accommodate the chosen size, which is consistent across the whole interface.

Audio output

A new way of perceiving a rapidly varying value in the model – play its waveform through your sound card. Oscillations, noise, periodicity changes etc. have never been so clear.

Option for indices to start at 0

Simile has always considered array indices to start at 1. Now they do so by default, but starting at 0 can be set for the whole model or a particular hierarchy of submodels. The setting affects the results of the element(), index() and place_in() functions as well as the indices shown in I/O tools.

Removed:

The Simile Scripting Language

Replaced by the Simile/R interface

Multi-window model run environment

Improvements in screen technology mean the single-window MRE is sufficient for all cases.

32-bit x86 versions

X86_64 is now ubiquitous, and 64-bit versions have better performance and can handle more complex models and larger datasets.
 

New in version 6.12:

 

Execution in browser

Interface to executing model, with run control, explorer pane, I/O tools and additionally the model diagram, can now used a tabbed browser window, which gives better looks, improved performance and a preview of what execution would look like in SimiLive

Submodel representing FIFO pipe to/from another tool

A Simile model can now exchange data with another tool as it runs, representing the external process as a submodel and connecting via a FIFO or bidirectional pipe.
 

New in version 6.9:

 

Database access 

Has now been completely overhauled. This means that model parameters can be read from a MySQL database in Linux, and reading them from an ODBC source such as .xls works in 64-bit Windows. .xlsb, .xlsm and .xlsx formats can also be used, and the data logger tool can write to any of these in Windows and to MySQL in Linux

New 'order' function 

Allows arrays to be sorted efficiently

2-D Shape Layers

2-D layers visualization now includes 2-D versions of the 3-D shapes from the projection viewer

Models as Maps

Components in a flat model can now represent components in an instance of a grid submodel according to their position on the diagram

Images on diagrams

There is now an image component that allows arbitrary images to be placed on the model diagram

New in version 6.4:

 

Generic 3-D shapes visualization tool

Display model data as lines, spheres or ellipses, and view as current lollipop diagram

New in version 6.2:

 

Data logger

Record values of several variables over time to a single file

Units for time series indices

e.g., 20*min to apply one reading every 20 minutes of simulated time

New in version 6.1:

 

Special-purpose submodels

Pre-defined submodel types for rectangular and hexagonal grid cells which allow communication between neighbours without the use of an association submodel

element() function works on lists

It can have a list as the first argument, and a single value, array or list as the second, allowing sublists of values to be picked from variable-membership submodels

Base instance lookup on more submodel types

A 2-dimensional array submodel, or a variable membership (including population) submodel can now have its indices looked up when building an association involving it

Layered display tool

Maps of different model values and a new tool for drawing widgets representing moving individuals can be superimposed or juxtaposed within one window, along with text and static images

New in version 6.0:

 

Discrete-event based modelling

Simile can now model systems in which instantaneous changes take place at arbitrary times, alongside continuous processes

Diagram-defined functions

Modellers can create functions to use in Simile equations by making model fragments that implement their behaviour

​Save and re-run editing sessions

Jump forwards and backwards between pre-defined points, for presentation or training

New in version 5.0:

Direct loading of grid data

Load 2-dimensional parameter arrays from comma-separated grids, image files or other datafile formats

Saving raw data in scenario files

Keep all the parameter information in one place, and have models start up faster

Following influences round the diagram

Simile v5 makes it easy to show, and follow, the way information flows round the model

with_greatest(...) and with_least(...) functions

New functions allowing data from special submodel instances to be picked out

Adaptive step size variation

Get more accurate results more quickly in 'stiff system' problem domains

There are a lot of other improvements, most of which do not require the modeller to do anything differently; see What's new in Simile 5.0, 5.1, etc for a more comprehensive list.

Happy modelling!

 

 

 

Getting started: how to build and run a simple model


Getting started: how to build and run a simple model

This section takes you through the whole process of building and running a model as quickly as possible. The exercise is based on a simple model of a bank account, since we are all familiar with this context, and we can readily do the calculations ourselves. This should save you from thinking that there is something mysterious about how Simile calculates the behaviour of a model.

The model: a simple bank account model

Step 1: Starting Simile: what's on the screen

Step 2: Making the model diagram

Step 3: Adding initial values, parameter values and equations

Step 4: Initialising the model

Step 5: Choosing the output displays

Step 6: Running the model

Step 7: Repeating the model edit/run cycle

Step 8: Saving and loading the model

 

Simple bank account model

The model: a simple bank account

Next Step >>

We will make a model for a simple bank account, with interest paid annually at a rate of 10%, and $10 taken out every year. The account initially contains $300. This is what we expect to happen:

Year 1

Opening balance

$300.00

     

Interest paid in

 

$30.00

 

0.1 x 300

Withdrawal    

$10.00

 

Closing balance

$320.00

   

300 + 30 - 10

Year 2

Opening balance

$320.00

     

Interest paid in

 

$32.00

 

0.1 x 320

Withdrawal    

$10.00

 

Closing balance

$342.00

   

320 + 32 - 10

Year 3

Opening balance

$342.00

     

Interest paid in

 

$34.20

 

0.1 x 342

Withdrawal    

$10.00

 

Closing balance

$366.20

   

342 + 34.2 - 10

And so on. Note that the increments are getting bigger each year because each time the balance goes up, so the interest paid increases. The balance of the bank account is increasing at a faster and faster rate.

Having understood the calculations that we are going to perform, we now turn to the concepts needed to express these ideas in Simile.

We use a compartment to represent the amount of money held in the bank account, since this a quantity that changes incrementally over time. We use two flows, one to represent the gain of money from interest and the other to represent the loss of money by withdrawal. One flow (interest) will go into the compartment, while the other flow (withdrawal) will come out of the compartment. We will also use a variable to represent the interest rate (10%, or 0.1). This variable will be linked to the flow representing the payment of interest by an influence arrow, indicating that the amount of interest paid depends on the interest rate. Since the amount of interest paid also depends on the amount in the bank account, there we will also use an influence arrow from the compartment representing the bank account to this flow.

In this tutorial we want to introduce you mainly to the mechanics of working with Simile, and these are explained in detail in the following steps. The concepts involved in representing even a simple system like this one in a modelling language can be quite complex.

Next Step >>

 

Step 1: Starting Simile: what's on the screen

 

Step 1: Starting Simile: what's on the screen

<< Previous Step Next Step >>

Starting Simile

You start Simile by double-clicking on the desktop icon created during installation, or by clicking on the Simile icon in the Start Menu.

These are both shortcuts to the file <Simile Program Files>\System\bin\Simile.exe, where <Simile Program Files> is the directory you chose to install the program. By default, this is commonly "C:\Program Files\Simile50", though if you are using a network, it may be on a remote hard drive. If you would like to be able to start Simile from a different location, create a shortcut to this file.

Linux users can start Simile by typing the command 'simile' in a terminal. Also, a shortcut is added to the Science/Education submenu of the Applications menu, which can be dragged to the desktop or taskbar, depending on your desktop environment.

On a Mac, Simile will be added to the Applications folder, from which it can be dragged to the desktop or task bar.

Within a few seconds, the main window will be displayed.

The Main Window

When Simile starts, you see a single window. This contains:
 

  • a menu bar (at the top of the screen on a Mac), containing a standard File menu, some menus specific to Simile, and a Help menu. Hold the mouse over the title for each menu to see the options it contains.
     
  • a toolbar, extending over two rows. The top row has standard tools (e.g. for opening and closing files), plus some specific to Simile.
  • a component bar, containing buttons corresponding to each type of model-diagram element: you will use these for building up your model diagram. The right-hand part contains buttons for editing the model diagram. Hold the mouse over each button to get a brief description of its function.
  • an equation bar, for entering equations into the model. At the right-hand end of the equation bar are the tools to accept or reject changes to equations, and to help build equations.
     
  • a big blank area (the "desktop canvas") with faint lines. This is where you will draw your model diagram. The grid can help you arrange your diagram neatly.

<< Previous Step Next Step >>

 

Step 2: Making the model diagram

Step 2: Making the model diagram

<< Previous Step Next Step >>

We begin by drawing the model diagram for the bank account model. A note on colours used in the following description: when you add a component to the model diagram, it is initially drawn in blue. This means that the component is selected. You will see the ways in which this is useful later on. When the component is not selected, it will turn red. This is its usual colour, and means that the component needs some extra information (like a value or equation) before the model can be built.

1. Add a compartment to the model diagram.

  • Click on the compartment symbol in the toolbar.
  • Move the mouse to the middle of the desktop window, and click again.

You should see a box labelled comp1.

2. Rename the compartment "account".

Type in the label account.
Note that immediately after adding the compartment, its label is selected (indicated by blue background as shown above) so you can just type the new label. See section 8 below for how to change the label later.

3. Add an interest flow and a withdrawal flow.

  • Click on the flow symbol in the toolbar.
  • Move the mouse into some space to the left of the compartment labelled account, hold the mouse button down, and drag the mouse into the centre of the compartment. Release the mouse button.
  • Type in the label interest.
  • Move the mouse into the centre of the compartment, and drag to the blank area to its right. Release the mouse button.
  • Type in the label withdrawal.

As an alternative to dragging out the flow, you can just click on its start and finish positions.

4. Add a variable for the interest rate

  • Click on the variable symbol in the toolbar.
  • Move the mouse to the blank area above the interest flow, and click once.
  • Type in the label interest rate.

7. Draw the influences

  • Click on the influence arrow button in the toolbar.
  • Move the mouse to the middle of the compartment labelled account, and drag an influence arrow to the flow labelled interest.
  • Release the mouse button when the flow has turned green.
  • Move the mouse to the middle of the variable labelled interest rate, and again drag an influence arrow to the flow labelled interest.

8. Re-arrange the model diagram

  • Click on the pointer button in the toolbar.
  • Move the mouse to the middle of the compartment labelled account.
  • Drag the mouse, and watch the compartment and its associated arrows re-arrange themselves.
  • You can also move the following components:
  • the cloud symbol at the end of each flow arrow;
  • the variable;
  • the valve symbols on the flows;
  • the middle of an influence arrow;
  • the position of the "kink" that appears in a flow arrow when it goes between two components that are not exactly above, below or to the left or right of one another; and
  • the labels. (A note on moving captions: if a component is selected, and is coloured blue, then the caption can be edited. To edit a caption, click on the label and type. You can drag the mouse to select a range of characters. To move the label relative to its component, make sure the component is not selected. You can then drag the label into its new position.)

This completes the drawing of the model diagram. In the next step, you will provide the numeric values and equations you need for simulating the behaviour of the bank account. Note, however, that this sequence (complete the model diagram before providing any quantitative information) is followed here for convenience: in general, you are free to provide the quantitative information at any stage in the diagramming process.

<< Previous Step Next Step >>

 

Tags: 

Step 3: Adding initial values, parameter values and

Step 3: Adding initial values, parameter values and equations

<< Previous Step Next Step >>

1. Prepare to set component properties

Click on the pointer button in the toolbar.

2. Assign the initial value for the compartment

  • Click on the compartment labelled account.
  • Enter the value 300 into the equation bar.
  • Click on the green tick mark or press the Return key.

3. Add the interest rate equation

  • Click on the flow labelled interest.
  • Variables account and interest_rate are now listed as influences upon interest. These influences are visible by clicking on the xs button. Selecting an influence from the drop-down list, places the text in the equation bar.­

  • Enter the expression account*interest_rate into the equation bar, either by selecting each variable in turn or by typing. Be sure to use an underscore rather than a space in interest_rate.
  • Click on the green tick mark.

4. Assign the value for the withdrawal flow

  • Click on the withdrawal flow.
  • Enter the value 10 in the equation bar.
  • Click on the green tick mark.

5. Assign the value for interest rate

  • Click on the variable labelled interest rate.
  • Enter the value 0.1 in the equation bar.
  • Click on the green tick mark.

Notice that every component of the model diagram is now black, rather than red as it was before. This indicates that every component has been mathematically specified, and so the model is ready for running: Simile has enough information to work out the flows, and thus to update the amount of money in your bank account forward through time.

<< Previous Step Next Step >>

 

Step 4: Preparing to run the model

Step 4: Preparing to run the model

<< Previous Step Next Step >>

This and subsequent steps assume that you are using the single-window Run-Time Environment. This is the default, so it is the one that you will be using if you have installed Simile and not changed your Preference settings. If the windows that appear when you come to run the model differ from the ones shown here, then please go to the "Edit" menu, select the "Preferences" item, and then select the "Use single-window Run-Time Environment" option.

1. Run the model

  • Open the Model menu
  • Select the Run item.

Simile creates a new window: the execution window. This contains the controls for running the model; a list of the variables in the model; and an area where any of a variety of tools for showing model results can be displayed.

2. Change the time step

Simile supplies a default time step of 0.1 when you first run a model. In natural science, a time step shorter than the time unit results in greater mathematical accuracy, but here we are dealing with an unnatural example; a bank paying compound interest on the balance of the account at the start of each year.

The above screenshot was taken from Simile v4; in v5 and later, the run settings are displayed on a separate tab within the run control notebook. Click on this tab to get at them, and then on the Run Control tab again to get the main controls back.

  • Change the value for Time step #1 from 0.1 to 1.

This is because we want to use a time step of 1 year rather than the default value of 0.1 years.

3. Change the duration of the simulation run

  • Change the value for Execute for from 100 to 10.

This is because we want to run the model for just 10 years at a time.

<< Previous Step Next Step >>

 

Step 5: Choosing the output displays

Step 5: Choosing the output displays

<< Previous Step Next Step >>

1. Select the graph-plot display

  • Click on the "Plotter" display tool on the toolbar; or select it from the list in the Add menu.

2. Choose the variable you wish to have displayed

Note the graph window that appears. This is initially scaled with default values on both axes, but will rescale itself as needed. You can re-size the panel containing the graph by dragging on the little boxes on the horizontal and vertical panel separators.

  • Click on the "Add a variable" button on the plotter toolbar
  • Click on the compartment labelled account in the list of model variables.

You can either click on the line representing the compartment in the "Explorer" tab at the bottom left of the execution window, or you can go back to the model diagram and click on the compartment there.

<< Previous Step Next Step >>

 

Step 6: Running the model


Step 6: Running the model

<< Previous Step Next Step >>

1. Start the simulation

  • Click on the "Play" button in the Run control dialogue window.

Note the line that appears on the graph.

2. Continue the simulation

  • Click on the "Play" button again.

The simulation carries on for another 10 years.

<< Previous Step Next Step >>

 

Step 7: Repeating the model edit/run cycle

Step 7: Repeating the model edit / run cycle

<< Previous Step Next Step >>

1. Return to the desktop canvas

  • Click on the "Go to Model Window" toolbar button.

2. Prepare to edit the component properties

  • Click on the pointer button in the toolbar.

3. Change the interest rate from 10% to 15%

  • Click on the interest rate variable.
  • Change its value from 0.1 to 0.15
  • Click on the green tick mark.

4. Run the model again

  • Click on the "Run" button on the toolbar.

The model will automatically rebuild, re-initialise and run again.

<< Previous Step Next Step >>

 

Step 8: Saving and loading the model

Step 8: Saving and loading the model

<< Previous Step

1. Save the model to file

  • Select the "Save As…" item in the File menu in the main (model diagram) window.
  • Navigate through the file directory system in the normal way, to the directory where you wish to save the model.
  • Enter a name for your model, and save it.

2. Loading a model from file

Either:

  • Select the "Open…" item in the File menu
  • Search for your model.
  • Click on the OK button.

or:

  • Select the "Reopen -->" item in the File menu
  • Select from the list of recently-used models

<< Previous Step

 

Graphical modelling in Simile

Simile's graphical language supports three different but overlapping modelling concepts:

  • System dynamics
  • Discrete event based
  • Object- or agent-based

System dynamics allows a system to be represented as quantities of real or abstract materials in reservoirs (compartments), moving continuously between them via a network of flows with rates derived from the state of the system. It is at the heart of Simile, and the diagram components that underlie it are used in all Simile's modelling concepts. If you are new to computer modelling, you should familiarize yourself with the system dynamics approach first.

Discrete event based modelling (new to Simile v6) allows instantaneous changes in a system's state to occur at arbitrary times. Event occurrences can be scheduled in advance, or triggered by model values crossing thresholds, or by other events, possibly after a delay. In pure event-based modelling, there is no regular time step and the state of the model does not change between events. Simile allows continuous change and discrete events in the same model.

Object- or agent-based modelling allows a single template for a functional unit in the model (known as a 'class') to work as many actual units (known as 'instances' or 'individuals') in the model. In Simile, instances can be permanent or can be created and destroyed as the model runs. Relations between instances can be specified, allowing influences to work between particular pairs of instances of the same or different classes.

Graphical Modelling in Simile : System Dynamics

System Dynamics modelling in Simile

A model is made up of compartments, representing quantities of material, and flows, representing movements between compartments. Where material moves in or out of the area of interest, a flow ends in a cloud. A flow has a bowtie, representing a valve or pump that sets its rate. Flows are calculated from compartment levels, and variables can be used for intermediate results, for constants, or for getting data into or our of the model. Influences indicate which component values affect which others.

See also the 1st video in the Simile Tutorial Series.

compartment

An amount of some substance

flow

A process moving a substance between compartments

variable

A constant or variable quantity

influence

Represents the fact that one quantity is used to calculate another

Model diagram elements : Compartment

Compartment

How to add a Compartment symbol

See Adding node-type elements. Note that you can add a compartment on top of a cloud, in which case the cloud becomes a compartment.

Interpretation

The compartment symbol is used to represent a quantitative state variable. Notionally, we think of a compartment as containing an amount of some substance, though it can be used in other situations where we want to represent the concept of state.

The informal interpretation of a compartment in System Dynamics modelling is that it represents a real, physical compartment that can contain some substance, just like a tank holds water. The compartment requires to be given an initial value - how much water does the tank hold at the start of the simulation? - and we need to construct flows in and out of the compartment so that the amount it holds can change over time.

This interpretation is fine to begin with, but must not be taken too literally. A compartment in System Dynamics modelling is, mathematically-speaking, a state variable: i.e. it is a variable whose behaviour is described by a differential (or difference) equation. And, unlike real, physical compartments, a compartment in System Dynamics:

  • can go negative (if the flows out are greater than the flows in, when the compartment gets to zero);
  • has infinite capacity (can go on increasing indefinitely);
  • cannot contain multiple substances. A real tank can contain both water and oil, but in System Dynamics modelling we would need a separate compartment for each one. However Simile allows a compartment to be an array with the dimensions of an enumerated type -- this could be used to model a single tank containing multiple substances.
  • can represent some state that does not correspond to the amount of a substance (such as the height of a tree, the area of land, the time when some event happened, or the x co-ordinate of a moving object).

Rules

  • You should not draw an influence arrow to a compartment, except for the special case of initialising it from other model variables. The behaviour of a compartment is determined solely by the net flows in and out of it. Its value at any point of time is found by incrementing or decrementing its value from the previous time step with the net inflow. But when you draw an influence arrow to a model element, you are saying that its value is calculated directly from the influencing variable, and that is incompatible with an approach base on adding or subtracting something from its previous value.
  • If you do draw one or more influence arrows to a compartment to initialise it in terms of other model variables, then those variables should be static (i.e. not time-varying).
  • If two compartments are connected by a flow arrow, then the two compartments should represent the same substance, and should have the same units.

In : Contents >> Graphical Modelling >> System Dynamics

 

Model diagram elements : Flow arrow

Flow arrow

How to add a Flow arrow

See Adding arrow-type elements.

Interpretation

The flow arrow is used to specify a term contributing to the rate of change of a compartment. If the flow arrow enters a compartment, it specifies a positive contribution to the rate of change of that compartment. If it leaves the compartment, it specifies a negative contribution to the rate of change.

The information on the flows entering and leaving each compartment is used to calculate the net rate of change of the compartment. The net rate of change is the sum of all the inflow values minus the sum of all the outflow values. The net rate of change is in turn used to calculate the change in the value of the compartment.

If your model needs to keep track of changes in the amount of a substance but you are not interested in where it comes from or goes to, your flow may start or finish on a blank part of the model diagram. In this case a "cloud" will be drawn at the end point, indicating that the amount of substance there plays no role in the model. Each cloud may only have one flow connected to it.

Influences to and from a flow are attached to a "bowtie" (or "valve") symbol which is positioned on the flow. This represents the point that controls the rate of the flow.

In most respects, a flow is treated just like a variable. You can use the full range of the equation language when you enter an equation for the flow, just as you can do for a variable. You can have influence arrows going from it to other parts of the model, again just like a variable. The two differences are that:

  • a flow is the only way you can express a rate of change term for a compartment; and
  • a flow cannot be a "file parameter".

Rules

  • A flow arrow can only be drawn into and/or out of a compartment.
  • Influence arrows can be drawn to and from flows.
  • The units for a flow value must be the units of the corresponding compartment(s) that it is linked to, per unit of time. For example, if you have a flow going into a compartment whose units are kg, and the unit of time for the model is a year, then the units for the flow must be kg/year.
  • It is quite legitimate to have an influence arrow going from one flow to another. You might wish to do this if one flow is proportional to another, or if the two flows are in different submodels.

In : Contents >> Graphical Modelling >> System Dynamics

 

Model diagram elements : Variable

Variable

How to add a Variable symbol

See Adding node-type elements.

Interpretation

A variable is used to hold one or more values. The value or values come from a mathematical expression. The expression may simply be a number, or it may be a complex mathematical expression involving various variables, operators (such as + and -), functions (such as log or square root), and conditional elements. The value of a variable may vary during the course of a simulation, if it is calculated from other parts of the model that change over time, or it may be constant.

The term "variable" is used to refer to a specific type of model element. This single element can be used for a wide variety of purposes, each of which is referred to in a different way by some modellers. There is rich potential for confusion here, so the following table sets out the correspondence between how a Simile variable is used in a model, and how a modeller would interpret that use. (In case you are wondering why we don't have a number of model elements, one for each type of use: the answer is that this would lead to an unnecessary proliferation of element types. Also, you might wish to change the role of a variable as you build up a model, and you would not want to have to keep on deleting one symbol and replacing it by another.)

Modelling use

Set-up of "variable"

Parameter (a coefficient in an equation): e.g. the reproductive rate per individual animal. Could also be a site constant: e.g. elevation above sea level. Its value will remain constant throughout a simulation run.

No influence arrows pointing to it.

One or more influence arrows pointing from it.

Value is a numeric constant or value is not supplied and "Fixed parameter" radio button is selected.

Input lever: a slider control can be generated for each such variable, and the user can modify its value during the course of a simulation run by moving the slider left or right.

No influence arrows pointing to it.

One or more influence arrows pointing from it.

Value is a numeric constant (representing initial slider position).

"Variable parameter" radio button is selected.

Exogenous variable: this is a variable whose value changes during a simulation run, and which influences the value of other variables, but which is not itself influenced by other variables. Typically used for climatic inputs, such as temperature or rainfall.

No influence arrows pointing to it.

One or more influence arrows pointing from it.

Value is some function of simulation time (i.e. involves the built-in function time).

Intermediate variable, also referred to as a derived variable

One or more influence arrows pointing to it.

One or more influence arrows pointing from it

Value is a function of the variables influencing it and also possibly of model properties such as current time

Output variable: typically, this is used to report on some aspect of model behaviour (e.g. the ratio of two compartments).

No influence arrows pointing from it.

Otherwise as intermediate variable

Attribute of an object: there is only sense in doing this if the variable is inside a multiple-instance submodel, with different instances having different values. E.g. the x-coordinate or the species type of each of many trees.

No influence arrows pointing to it.

No influence arrows pointing from it.

Rules

  • A variable symbol may have zero or more influence arrows pointing to it.
  • A variable cannot have influence arrows pointing to it if it is a "file parameter".
  • A variable symbol may have zero or more influence arrows pointing from it.
  • A variable may not have other kinds of arrow pointing to or from it.

In : Contents >> Graphical Modelling >> ​System Dynamics

 

Model diagram elements : Influence arrow

Influence arrow

How to add an Influence arrow

See Adding arrow-type elements.

Interpretation

To say that "A influences B" (i.e. to draw an influence arrow from A to B) means that A is used to calculate a value for B: in other words, the equation for calculating B will include A.

Rules

You can drag an influence arrow from and to most model elements. The exceptions and special cases are noted here below. Note that if you try to drag an influence arrow to a model element that cannot receive one, then it turns blue instead of green, and you will not be able to connect them together. You can store comments associated with an influence arrow by double-clicking the arrow.

Compartments

  • Elements that influence a compartment are used only to calculate the initial value of the compartment. Thereafter, the value of the compartment is calculated by adding the flows in and subtracting the flows out. It is not common therefore to draw an influence arrow to a compartment, though it is possible (in order to calculate the initial value). For example, although one may informally say "water temperature influences fish population size", in the model, temperature must actually influence one of the processes (reproduction, death and so forth) which change the fish population size. The influence arrow from the temperature variable must therefore point to one (or more) of the flows in or out , and not to the compartment representing fish population size itself.

Submodels

  • When working with submodels, you may find that an input parameter (A) in one submodel actually corresponds to a variable (B) in another, especially when the two submodels were developed separately, then later brought together. In order to get rid of the duplication, draw an influence arrow from B to the influence arrow from A. This is the only circumstance in which it is possible to draw one influence arrow pointing to another. Input parameter A will disappear, and the influence arrows will be re-drawn to show B directly influencing the element previously influenced by A.
  • You can drag an influence arrow to a submodel boundary, from either inside or outside the submodel. This has no meaningful modelling function, but acts as a temporary placeholder to the influence arrow until it is connected to an element on the other side of the boundary. In order to do this, drag an influence arrow from the head of the existing arrow to the desired element.
  • You cannot drag an influence arrow from a submodel boundary, other than to complete an influence arrow drawn to the submodel boundary (as described in the previous bullet point).

Influence and role arrows

  • You cannot drag an influence to a role arrow or to another influence arrow.
  • If an influence shares part of its route with one or more role arrows (in either direction), then the normal interpretation is that the values it supplies will only be those from the base model instances in the corresponding roles, or from the association model instances for which the instance containing the destination is in the appropriate role. The different interpretations are selected by prefixing the caption of the source component (or suffixing if going from association to base) with the caption of the relevant role. As of Simile v6, the interpretations can be enabled or disabled by checkboxes in the influence properties dialogue. Also the interpretation that would apply if the role arrow were not present, i.e., get values from all source model instances, is also available and can also be enabled or disabled.
  • In Simile v6.1, an alternative interpretation is provided for influences within multiple-instance submodels -- the ability to get values from all instances, as if the destination were outside the submodel, rather than just from the current instance. Furthermore, for influences within special-purpose submodels, there are interpretations that provide values from just a special subset of other instances, e.g., neighbour instances. Again, any of these (as well as the default interpretation) can be enabled or disabled from the properties dialogue.
  • If an interpretation is enabled that gets values from other instances than the current one, the influence arrow will be decorated with an oblique stack that it passes through, indicating that it carries values between different instances of its submodel.
  • To invoke the property dialogue box for an influence arrow, double-click on the arrow, or right-click on it and select "Properties..." from the context menu.

Calculation order

An influence arrow indicates that the value of one component is used in calculating the value of another. So it puts a constraint on the order in which the two values can be calculated each time step; the one at the head must be done after the one at the tail.

This means that if it is possible to get from a model component around a loop of influence arrows back to the same component, the model cannot be executed, because no ordering of the calculations can satisfy all the constraints. The problem is called circularity. Usually this problem indicates that a certain variable in the model should in fact be a compartment, and an influence that connects to it should instead connect to a flow going to it. But there are some circumstances in which circular influences are OK.

  • Influence arrows have one further property that can be set. The property is "Use values made in same time step". The property indicates how the ambiguity associated with a circular loop of influences is to be resolved.
  • Normally, the value of the component at the end of an influence is calculated after that at its start in each time step. Selecting "Use values..." removes this constraint, and shows this by drawing the arrow dashed instead of solid.
  • This may be used in combination with the iteration symbol to implement many iterative methods.
  • You can also use this property to create a model process that iterates a fixed number of times and stores all its intermediate results in an array. In this case you do not need the iteration symbol. If you have two components in different fixed-membership submodels, and each has the same number of instances, then they can each have an influence to the other provided one of the influences has the "Use values made in same time step" property, and the equation of the component at the end of this influence uses only values of the other component with indices lower than its own. Subject to a similar restriction it is also possible to specify iteration between a base submodel and its association submodels.

There are two functions in the equation language, "last()" and "sofar()", which also allow a model with a circular chain of influences to execute. Putting "last()" around an expression means that its value at the end of the last time step is to be used, so the component using it does not have to be evaluated after it each time step. Putting "sofar()" round a value has the same effect as selecting the "Use values..." property described above for the influences used by that value; it is used to resolve circularity problems involving intermediate variables, where there is no influence arrow on which the property could be set.

In : Contents >> Graphical Modelling >> ​System Dynamics

Graphical Modelling in Simile : Discrete event based

Event-based modelling in Simile

A pure discrete-event-based model includes only event symbols (time series and derived/delayed) and states. An event symbol only has a value at the point in time at which it occurs. The value of a derived event occurrence is calculated by its equation, which can include the value of the triggering event occurrence.  A state has a rule for each event symbol that influences it. When an influencing event occurs, the state's new value is given by the corresponding rule, otherwise it stays the same.

A model that mixes system dynamics (continuous) and discrete-event based operation also includes limit event symbols and squirts. A limit event occurrence is triggered when its equation reaches its minimum or maximum value, allowing continuous processes to set off events. A squirt is a derived event which causes an instantaneous transfer of material between compartments, allowing events to affect continuous processes. State changes can also affect continuous processes, but only squirts can cause discontinuities in the values of compartments.

See also the 5th video in the Simile Tutorial Series.

event

An instantaneous occurrence which can have a magnitude

state

A quantity set by events according to rules

squirt An instantaneous transfer of a substance between compartments
If an influence originates from a discrete event valued component, it is shown 'bulged' to indicate that it carries a discrete event value. Such an influence cannot terminate on a continuous-valued component.

immigration

The channel components which specify changes to the membership of population submodels can be either continuous or discrete valued. If one or more  discrete valued influence terminates on one of these, it is discrete valued and behaves like a squirt component, adding or removing as many submodel members immediately as the continuous version would over one time unit.

reproduction

removal

In: Contents >> Graphical Modelling

Discrete event-based modelling : Event element

Event

How to add an Event symbol

See Adding node-type elements.

Interpretation

An event symbol represents something that happens at an instant in time, such as the arrival of a package. The event represented by a symbol may occur any number of times during a model run, or not at all. An event occurrence can have a numerical magnitude, and having a magnitude of zero is the same as not occurring. The effects of an event occurrence can be proportional to its magnitude. Alternatively it can be boolean, i.e., all-or-nothing. Event symbols should not have array equations, but can go in multi-instance submodels, in which case the event can occur independently in each instance of the submodel.

In system-dynamics models, time advances by regular steps. When an event is about to occur, Simile will execute a time step with a size that will advance the time to exactly the point at which the event is predicted to occur, in order that the effects of changes made by the event are not subject to time step rounding errors.

There are three types of event, which differ in how they are triggered. The equation dialogue for an event includes radio buttons to select between these event types, and they are distinguished by different 'decorations' on the event symbol in the model diagram.

Modelling use

Set-up of "event"

 Limit event : This represents an event that occurs when a model value reaches some pre-set limit. It requires an equation and a minimum and/or  maximum value to be entered. The event occurs when the value of the equation reaches the minimum or maximum, and the event should cause  the value to go no further in that direction. The event is boolean (i.e., has no magnitude) if only one limit is present. If both are present its magnitude is -1 at the lower limit and 1 at the upper limit. Hence its equation does not affect its magnitude, only its time of occurrence.

The exact time at which the event occurs is determined by extrapolation of the equation value over the previous system-dynamics time step. If the integration method is Euler, linear extrapolation is used; if Runge-Kutta, it is done by a quadratic approximation. If adaptive step-size variation is selected, a check is done that the crossing actually occurs around the predicted time, and the time step is re-calculated with a new prediction if the difference is too great.

Only has inflluence arrows from continuous valued components

One or more influence arrows pointing from it to other events, squirts or states

Magnitude is on/off if one limit supplied, integer of -1 or 1 if both limits supplied

 Time series: This gets its values from outside the model like a time series variable parameter, but the event occurs at the time points entered, with the values entered giving the magnitudes of the corresponding occurrences. 'Interpolate' is not allowed (nothing happens between the time points) but 'restart' is, so a pattern of event firing can repeat. The equation of a time-series event only serves to define its units. A slider control can be generated for each such variable, and the user can generate events during the course of a simulation run by moving the slider left or right to set its magnitude and hitting the 'zap' button.

If a time series event symbol is put inside a multi-instance submodel, the values in the series must be arrays with the dimensions of the submodel. At each time point in the series, the event will occur in all instances of the submodel for which the corresponding array element is non-zero (or 'true' if type is boolean).

No influence arrows pointing to it.

One or more influence arrows pointing from it to other events, squirts or states.

Occurrence times and magnitudes given by series data

 Derived event (No decorations): This is an event that occurs as a result of other event occurrences. It must have an influence from at least one other event or squirt, and may occur whenever any of them occur. It may also have influences from other components, whose values may be used in its equation. Its equation is evaluated when it is triggered, and gives its magnitude. The equation cannot refer to event values directly, but can include the special function 'trigger_magnitude()' which gives the magnitude of the triggering event, or their sum if more than one happens simultaneously. If the trigger magnitudes sum to zero, or the equation evaluates to zero (or 'false' if type is boolean) the event will not occur.
The equation of a derived event can be of the form after(t,x) where t and x are subexpressions. In this case the magnitude of the event is x at the time of triggering, but it does not occur until t time units later. This is the only context in which after(...) can be used.

Must have an influence from at least one other event or squirt, can have other influences to it

One or more influence arrows pointing from it to other events, squirts or states.

 

In: Contents >> Graphical Modelling >> Discrete-event based

Discrete event-based modelling : Squirt arrow

Squirt arrow

How to add a Squirt arrow

See Adding arrow-type elements.

Interpretation

The squirt arrow is used to specify where event occurrences cause sudden changes to the value of a compartment. If the squirt arrow enters a compartment, it specifies a positive step change to that compartment. If it leaves the compartment, it specifies a negative step change (unless the magnitude of the squirt occurrence is negative in which case these directions are reversed, as for a negative flow value). Many aspects of using squirts are similar to using flows.

If your model needs to keep track of changes in the amount of a substance but you are not interested in where it comes from or goes to, your squirt arrow may start or finish on a blank part of the model diagram. In this case a "cloud" will be drawn at the end point, indicating that the amount of substance there plays no role in the model. Each cloud may only have one flow or squirt connected to it.

Influences to and from a squirt arrow are attached to a "target" (or "bulb") symbol which is positioned on the squirt arrow. This represents the point that generates the transfer. Influences from a squirt arrow start from this point and are used in the same way as those from an event symbol, and must go to other squirts, events or states.

In most respects, a squirt is treated just like a derived event. You can use the full range of the equation language when you enter an equation for the squirt, including the trigger_magnitude() and after() functions, just as you can do for a derived event. The two differences are that:

  • a squirt is the only way you can express an instantaneous change term for a compartment; and
  • a squirt cannot be a time series event or a limit event.

Rules

  • A squirt arrow can only be drawn into and/or out of a compartment.
  • Influences can be drawn to a squirt's bulb, and must include one from another squirt or event symbol.
  • Influences can be drawn from a squirt's bulb to other squirts, events or states.
  • The units for a squirt value must be of the same dimensions as the units of the corresponding compartment(s) that it is linked to. For example, if you have a squirt going into a compartment whose units are kg, and the unit of time for the model is a year, then the units for the squirt can be kg, g, lb etc. An automatic conversion will be performed if necessary. The time units do not matter (unlike flow units) because the transfer is instantaneous.

In: Contents >> Graphical Modelling >> Discrete-event based

Discrete event-based modelling : State element

State

How to add a State symbol

See Adding node-type elements.

Interpretation

A state is a model value that is changed by events, but otherwise stays the same. A state does not have a unique equation, but rather a set of rules, each consisting of an event (the trigger) matched with an equation (the effect). There will be one rule for each event that influences the state, plus an extra effect labelled "reset..." that sets the initial value of the state when the model resets (or when a new instance of the state's parent submodel is created).

In the equation dialogue for a state, the influencing event symbol captions (and reset...) are listed to the left of the equation field, and clicking on an event caption shows the effect for an occurrence of that event. In the equation bar, a pull-down menu to the left selects the caption of the event whose effect is to be edited. The popup text for the state is a condensed form of the rules, e.g., "9 on event1, 6 on event2, 0 on reset."

Components with continuous values can also influence the state, and their values can be used in one or more of its effect equations.

The value of a state after an event occurrence depends only on the effect equation of that event, and not on its previous value. However the equation can use the prev(0) function to refer to the state's previous value if the new value is to be a function of it. The equation can also use the trigger_magnitude() function to refer to the magnitude of the triggering event occurrence if this is to affect the state's new value. The effect equations cannot use the after(t,x) function; the state's value always changes immediately after the triggering event occurs.

Currently the order in which the rules are applied if multiple triggerring events occur simultaneously is undefined.

Rules

  • A state must have influences from at least one event or squirt symbol
  • A state must have an equation for each event or squirt symbol influencing it, plus one for reset
  • Other components (including other states) can influence it, and their values can be used in its equations
  • All of its equations must evaluate to quantities with the same units and dimensions
  • A state can influence any other component

In: Contents >> Graphical Modelling >> Discrete-event based

Graphical Modelling in Simile : Object- or agent-based

Object- or agent-based modelling in Simile

A submodel is a distinct group of components in a model, and can represent a class. Submodels with specified dimensions have a fixed number of potential instances. Population submodels represent groups of individuals who appear, move, reproduce and disappear according to the four process or channel symbols -- creation, immigration, reproduction and loss.

A role arrow causes the submodel at the head to have an instance or group of instances for each instance of that at its tail, as if it were nested inside. Each role arrow multiplies the potential number of instances of the submodel at its head. This can contain condition symbols, which allow the existence of each instance to be turned on or off.

The alarm symbol indicates that when the model values are updated, the components in its submodel should be evaluated repeatedly until the alarm's test condition is met. Condition and alarm symbols have slightly different effects when influenced by events. A conditional submodel only exists at the point at which the triggering event occurs, while an alarm submodel's components are only re-evaluated (but maybe many times) when the triggering event occurs, and keep the same values at other times.

submodel

An envelope enclosing a group of model elements, collectively representing a class of object

initialisation

A process creating the initial number of instances of a population submodel

migration

A process creating new instances of a population submodel

reproduction

A process creating new instances of a population submodel for each existing instance

extermination

A process destroying instances of a population submodel

role

Represents the fact that one object is associated with another, with each playing a role in the association

condition

Represents the fact that an instance of a submodel can exist only under specific conditions

alarm

Represents an iterative loop within a single time-step

 

In: Contents >> Graphical Modelling

Model diagram elements : Submodel

Submodel

How to add a submodel symbol:

See Adding Submodels

A submodel is first and foremost a way of grouping together a number of other model elements, including other submodels. This is done by either drawing a submodel envelope around a number of elements in the model diagram, or by creating an empty submodel and inserting model elements into it.

However, the reasons for wanting to do this are many and varied, and it is important to appreciate that the submodel construct can be used for a range of modelling needs. There are considerable benefits to using a single method to fulfil this range of needs, both in reducing what you need to learn, and keeping the resulting models simple and flexible.

This section overviews the different uses of the submodel construct, and the different types of submodel that you can have. Other sections provide more detail on particular topics.

Using a submodel to show the main components of a complex model

You have constructed a model with a number of compartments and flows. Some relate to vegetation; some to the animals in the area; some to soil water and nutrients. By grouping the model-diagram elements for these different parts into submodels (called "Vegetation", "Animals" and "Soil"), the gross structure of the model is immediately apparent.

Conversely, you may prefer to design a model in a top-down fashion. Starting with a blank screen, you can rapidly add submodels corresponding to the main components of a proposed model, then subsequently add the various compartments, flows etc inside these.

Using a submodel for multiple views on a model, perhaps at different scales

Once part of a model is made into a submodel, you can open a separate window for it (by double-clicking on its boundary with the pointer). This window can be kept on the screen while you scroll the main model diagram to some other part of the model. Also, you can change the zoom factor for each main model window or submodel window separately, enabling you to see part of the model in fine detail while maintaining an overview of the whole model at a coarser scale.

Using a submodel to make a part of a model into a stand-alone model

For the model described above, you may want to see how the vegetation part behaves, assuming fixed inputs from the animal and soil sections that affect it. You draw a submodel envelope around the vegetation, open up a separate window for it, then use the File: Save command to save it to a file. You can then start up Simile again, and load just the saved vegetation submodel (which is now a model in its own right). You can now explore how it behaves by itself. This can be very useful for testing and debugging purposes.

Using a submodel for modular modelling: swapping one module for another

For many years, the battle cry of those fed up with the implementation of models in computer programs was "modular modelling!". If we had a modular modelling system, it was argued, then models could be easily constructed from a number of pre-programmed modules, and the effectiveness of the community as a whole would be greatly increased by the sharing of these modules, avoiding huge duplications of effort.

The submodel concept in Simile supports modular modelling. You can open up a separate window for a submodel (say, a vegetation submodel); clear the contents of the submodel (by doing File: New), then load a different vegetation model into the submodel window. Influence links with the rest of the model can then be made one by one.

Furthermore, Simile supports plug-and-play modularity (which is what is normally meant by "modular modelling"). If two or more vegetation submodels have been designed to share a common set of influences (in and out) with the rest of the model, then the information about this interfacing can be stored in a file (an interface specification file). When you next load one of the submodels from a file, you simply refer to the interface specification file, and all the influence links are made in one quick operation.

Using a submodel for disaggregation;

or (conversely) specifying a fixed number of objects of a certain class

These two terms are lumped together because they are the same concept, seen from opposite perspectives. You can disaggregate an area into a number of patches; or you can think in terms of one patch, then have multiple patches to represent some larger area. The end result in both cases is exactly the same.

Once you have made a submodel you can specify (by going to its Properties dialogue box) that it is a "fixed-membership submodel", and specify a number of instances. In the "Control of number of instances" panel, select the "Using specified dimensions" radio button and enter the number you require. The submodel then represents each of that number of instances. Visually, it now appears different, because it now has multiple lines on the right- and bottom-edges: like a stack of cards. Internally, Simile now handles each instance separately: each can have its own parameter and initial values, while they all have the same compartments, flows etc.

This enables many forms of disaggregation to be captured. For example:

  • disaggregating a population into age, size, or sex classes;
  • disaggregating a vegetation component into the several species that make it up;
  • disaggregating soil or forest canopy into a number of layers;
  • disaggregating space into grid squares, polygons, or some other form of spatial unit.

Note that there are two further options in the pull-down menu: rectangular grid and hexagonal grid. These also correspond to fixed-membership submodels, but make special functions available within the submodel for capturing various properties of rectangular/hexagonal grids.

Using a submodel to specify a dynamically-varying population of objects

The modelling world divides into those whose models are based on differential/difference equations (with or without disaggregation); and those who subscribe to an approach based on collections of objects (variously called object-oriented, individual-based or agent-based modelling).

Simile enables a population approach to be combined with a differential-difference equation approach. For example, a modeller might represent the vegetation in terms of compartments and flows, while the herbivores might be represented as individual animals, which are created, grow and die. In order to do this, a submodel is specified as being a population submodel (Specify control of number of instances as "using population symbols" in its Properties dialogue box), and model elements can be added for specifying the initial number, and the rules for the creation of new individuals and the elimination of those already n the population. Visually, the submodel now appears with a shadow line for the top- and left-edges, and another for the bottom- and right-edges.

The remaining option for controlling instance numbers is "Using number of data records in file". This will set the number of instances according to the number of values provided for fixed parameters within that submodel, so the same model can be used for simulations involving datasets of different sizes.

Using a submodel to specify the conditional existence of some part of the model

When a model is implemented in a conventional programming language, large chunks of the program can be enclosed inside an if … end if block: i.e. whether it is actually evaluated depends on some condition. This programming device may be applied to several different purposes:

  • You may want to have several alternative ways of modelling some part of the system (e.g. a growth function), only one of which is active in any one run of the model. A flag determines which one is active.
  • You may want to model a set of species using a single submodel, but with only some species present in any one run of the model.
  • You may want to model a number of spatial patches, some of which contain one land use type, and others of which contain another. You need to include a submodel for each one within the multiple-instance patch submodel - but switch one or the other on in a particular patch.

All these situations can be handled in Simile using a conditional submodel. This is simply a submodel, either simple or fixed-membership, but with a condition symbol added. Visually, we can tell that it's a conditional submodel both by the presence of the condition symbol, and by a set of dots going down diagonally to the right from the submodel envelope. The condition contains a Boolean expression: if this evaluates to "true", then the submodel (or an instance of it) exists; if not, then it doesn't.

A conditional submodel will, like any other, have influences coming out from the model elements it contains. However, the number of values passed along each influence could be anything from zero (if no instances of the model exist) to the number given in the fixed-membership specification (if they all do). It is thus a variable-size data structure: in other words, a list (with the name of the variable enclosed in curly braces {…} ). In Simile, the only thing that can be done with a list is to evaluate it: usually, to sum its values. If the list is empty, then the sum is zero. If the list contains a single element, then the sum is whatever this value is.

Using a submodel to specify an association between objects

Once our modelling language allows us to think in terms of multiple objects of a certain type, then it is frequently the case that we start to recognise relationships between objects. These relationships may be:

  • between objects of the same type: one tree shades another; one grid square is next to another; one person is married to another; or
  • between objects of one type and objects of another: one farmer owns a field; one field is close to a village.

Since Simile is a visual modelling language, and since such relationships are an important aspect of the design of a particular model, Simile provides visual elements to show diagramatically such relationships between objects. Unfortunately, the term "relationship" is normally used in ecological modelling to refer to a relationship between variables (as opposed to objects), so we use the term "association" instead. This is the same term used in UML (the Unified Modelling Language, the standard object-oriented design language used in the software-engineering community).

An association can itself have properties. We can, for example, have a variable representing the actual distance between a field and a village: this is a property of neither the field or the village, but of the association between them. In Simile, the submodel is the construct that is able to hold a number of quantities, therefore we use a submodel to represent an association: it is then called an association submodel.

However, such a submodel is simply a normal Simile submodel. It becomes an association submodel by virtue of being linked to the submodel (or submodels) representing the objects that have the association. The linking is done using role arrows: one role arrow is drawn for each type of object that participates in the association. Thus:

  • for the owns association between farmer and field, we draw a single role arrow from the farmer submodel to the owns association submodel, and one from the field submodel to the owns association submodel;
  • for the next to association between one grid square and another, we draw two role arrows from the grid square submodel to the next to association submodel: one role arrow represents the field under consideration, while the other represents its neighbour.

Using a submodel to specify a satellite relationship between one object and another

Let's say that you have a multiple-instance submodel containing information on the species and volume of a set of individual trees: each instance is one tree. You would like to find the total volume of all trees belong to species 1.

This is easy to do if you have model the trees using a fixed-membership submodel (i.e. assuming that you have a fixed number of trees). You simply take influence arrows from the species and volume variables inside the submodel to a variable outside (say total), and give total the equation:

total = sum(if [species]==1 then [volume] else 0)

[species] and [volume] are both arrays with the same number of elements, and Simile's array language matches them up.

This technique will also work if you use a population submodel to model the trees. But suppose you want to do several operations on only the trees of a particular species? Rather than apply the species condition each time, you can make a satellite submodel corresponding just to the individuals you are interested in. It would involve creating a new submodel for the species 1 trees, using a single role arrow from the tree submodel to this satellite submodel, and entering the condition "species==1". An instance of this submodel will be created for each tree of species 1, and not for the others. If you then take the "volume" value into the submodel, then you can extract the volumes just for species 1.

A satellite model with the appropriate condition can represent any subgroup of the instances in its base model, including cases where instances may become members or stop being members of the subgroup as the model runs.

Using a submodel to specify different time bases for different parts of a model

By default, Simile uses the same time step to update all the model state variables. However, if you are modelling a system containing trees and crops, then you might very well want to model the trees on an annual basis (time step of one year), and the growth of the crop on a weekly basis (time step of 1 week).

Simile enables you to specify a time step category for any submodel. For each new time step category that you request, Simile adds an extra Update every entry in the Run Control dialogue window, and that is where you specify the actual time step (e.g. 0.01) to be used for each category.
 

Using a submodel to allow iterative calculation of a function

Some calculations simply cannot be done within the system-dynamics paradigm, as they involve actions that are repeated until some indication of completion is achieved -- for instance, methods involving successive approximation.

These can be included in a Simile model by creating a submodel for the iterative calculation, and including an alarm symbol. This is a boolean valued component, and will cause all the variables in the submodel to evaluate repeatedly until it evaluates to 'true'. If the iteration involves values from the previous calculation step, these can be referenced using an influence arrow with the "Use values made in same time step" property.

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Initialisation

Initialisation

The Initialisation symbol is used to specify the initial number of individuals in a population submodel. It is sometimes called the Creation symbol, and belongs to the group of symbols known as channels. The symbol's icon represents the rising sun.

How to add an Initialisation symbol

The Initialisation symbol only has meaning in the context of a population submodel. Therefore, it makes sense to construct a population submodel first, then add the Initialisation to it. This is not strictly necessary: you can add the Initialisation first, then construct a submodel around it, then make the submodel into a population submodel, but it is better practice to construct the population submodel first.

See Adding node-type elements.

Rules

  • You can have any number of Initialisation symbols in any one population submodel. The initial population count will be the sum of their values. You may use more than one when the initial population consists of subgroups with different properties. You can use the channel_is( ) function on the initialisation channels to indicate which group each individual belongs to, and set its properties accordingly.
  • You do not need to have an Initialisation symbol in a population submodel. If you do not have one, then the initial number of instances for the population is zero. You would then have to have a migration symbol if you wanted your population ever to have any instances. (If you only had a reproduction symbol, then the population would never be able to get going, since reproduction only works for individuals already in the population.)
  • The Initialisation symbol may receive influence arrows, but (usually) only from variables calculated at the start of the simulation run, whose values do not change. A typical application would be to initialise the number of instances in the population from some fixed environmental attribute, such as the soil type or the area of the system being modelled.
  • It is possible to draw an influence arrow from the initialisation symbol to another element. The usual use of this is with the channel_is( ) function. Otherwise, the value of the initialisation symbol is always the number of individuals it caused to be created at the start of the run, even if the value of its expression changes as the model runs.​

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Migration

 Immigration

The Immigration symbol is used to specify the creation of new instances of a population submodel during the course of a simulation. In contrast to the Reproduction symbol, which specifies this in per instance terms (i.e. the creation of new instances per existing member of the population), the Immigration symbol determines the total number of new instances that are created. Note that the process adding new individuals need not be an actual immigration from another place -- it could be anything that causes new members of a population, unrelated to existing individuals, to appear throughout a run.

Immigration belongs to the group of symbols known as channels. The symbol's icon represents a bird on the wing.

How to add an Immigration symbol

The immigration symbol only has meaning in the context of a population submodel. Therefore, it makes sense to construct a population submodel first, then add the immigration symbol to it. This is not strictly necessary: you can add the immigration symbol first, then construct a submodel around it, then make the submodel into a population submodel, but it is better practice to construct the population submodel first.

See Adding node-type elements.

Rules

  • The immigration symbol can receive influence arrows from anywhere in the model, including from within the same submodel. This information is then be used to calculate the current value for the rate of creation of new instances of the population. If the influence arrow comes from within the same population, then this input will be presented (in the Equation dialogue window) as a list, not as a scalar. See below for the reasons for this, and what you should do about it.
  • You can include as many immigration symbols as you like. In real-world terms, each one corresponds to a separate process leading to the new instances being created: for example, some new trees can appear in a forest from seeds blowing in from outside the forest, while others can appear from a forester planting seedlings.
  • It is possible to draw an influence arrow from the immigration symbol to another element. The usual use of this is with the channel_is( ) function. The value of the immigration symbol is the value of its equation.

Interpretation

The immigration symbol it is used to determine the creation of new instances of a population submodel. This must be in terms of whole numbers: you cannot have a part of a new individual. And yet, the value for the immigration term can be a floating-point number, e.g. 1.3. So how does Simile use this value to calculate the creation of new instances?

The value of the immigration symbol's equation is the number of new instances created over the course of one time unit. Typically the time step is not the same as a time unit, so each time step the value of an internal variable is incremented by the immigration symbol's value divided by the number of time steps in a time unit. If this value is one or greater, the integer part of the number is subtracted from it and that number of new individuals are added to the population. The fraction part remains to be incremented on the next time step.

In order that a model with many immigration processes behaves realistically rather than adding all new individuals synchronously, the internal variable for each one is initialized to a random fraction between 0 and 1. Thus there is a possibility that a new individual will arrive through immigration in any time step, even if the value of the channel is small.

Immigration events

An immigration symbol can be either continuous or discrete event valued. If any influences from events or squirts terminate on the immigration symbol, it is discrete event valued. In this case it will be evaluated in the same way as an event or squirt. When the event occurs, the value will be added to the latency (fraction remaining after previous additions) and new individuals added to the popualtion immediately if the result is 1 or greater.

Avoiding random behaviour

You might well feel uncomfortable with the non-deterministic nature of the process. To avoid any random variation between runs, you can make sure that the value of the equation for immigration divided by the number of time steps in a time unit is always a whole number, which will result in exactly that number of individuals being added each time step. The length of the time step is selected when running the model, and can be found with the dt() function.

If using discrete event valued immigration channels, all you need to do is make sure the event magnitude is integer valued, as the time step size does not affect the result of an addition event.

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Reproduction

Reproduction

The reproduction symbol is used to specify the rate of creation of new instances of a population submodel by each existing instance. It thus differs from the migration symbol, which specifies the total rate of creation of new instances. It belongs to the group of symbols known as channels. The symbol's icon represents an egg.

How to add a Reproduction symbol

The reproduction symbol only has meaning in the context of a population submodel. Therefore, it makes sense to construct a population submodel first, then add the reproduction symbol to it. This is not strictly necessary: you can add the reproduction symbol first, then construct a submodel around it, then make the submodel into a population submodel, but it is better practice to construct the population submodel first.

See Adding node-type elements.

Rules

  • The reproduction symbol can receive influence arrows from anywhere in the model, including from within the same submodel. This information can then be used to calculate the current value for the rate of creation of new instances of the population. As with all other relationships within a population submodel (except for the migration symbol), influences coming from within the same submodel relate to the properties of the same instance. So, for example, an influence from a variable "bodyweight" to the reproduction symbol indicates that it is each individual's body weight that influences its own rate of reproduction.
  • You can include as many reproduction symbols as you like. Biologically it is unusual to have more than one method for reproduction (though some organisms reproduce asexually and sexually at different stages of their life cycle), but it is perfectly legal as far as Simile is concerned.
  • It is possible to draw an influence arrow from the reproduction symbol to another element. The usual use of this is with the channel_is( ) function. The value of the reproduction symbol is the value of its equation.

Interpretation

The reproduction symbol captures the concept that, in many biological situations, the production of new individuals by those already in the population - reproduction - is an important mechanism for increasing population size. Moreover, the ability of an individual to reproduce will depend on its own characteristics: its age or weight, for example.

As with the migration symbol, Simile needs to resolve the fact that the value for reproduction is a floating point number, while new individuals can only be created one-by-one. The method it uses to do this is similar to that used for migration, and essentially involves the use of the reproduction term to contribute fractions of an individual to an accumulator: when the accumulator exceeds a whole number, then that number of new instances for the submodel are created, and the accumulator is reduced by the number of instances created.

There is, however, an important issue that the designers of Simile had to address. Should there be one accumulator for the whole population, or one for each of the current set of instances? In the former case, if you had five instances, each with a reproduction value of 0.1, then one new individual would be created every 2 time units. In the latter case, for the same settings, you would get no new instances for ten time units, then five would be created at the same time. The first approach seems more attractive, but suffers from a fatal flaw: it assumes that the parentage of newly-created individuals is irrelevant. This would severely restrict the modelling you could do: in particular, it would rule out modelling evolution, since that requires some concept of (biological) inheritance, which in turn means that each individual needs to know who its parent(s) are. Also, the second approach gives the same behaviour as the first if the value for reproduction is treated stochastically (e.g. as a probability), rather than as a precise deterministic contribution until you have enough credit to make one individual. Therefore, in Simile, each individual accumulates its own credit, starting with a random fraction, until it has sufficient to make one new individual.

Like migration channels, reproduction channels can be discrete event valued. If the event that triggers a reproduction event is outside the population submodel, then when it occurs, all individuals in the population will reproduce, subject in each case to the equation of the reproduction channel having a positive value. Alternatively the triggering event can be inside the population submodel, in which case only the individuals in which the event occurs will reproduce.

As in the case of the migration symbols, the accumulators are initialized to random fractions between 0 and 1. This ensures that if the reproduction rates are the same in a lot of individuals, the new ones do not all appear in the same time step but in a random pattern with no pre-determined peaks or troughs. If this non-deterministic behaviour is not required, the technique described for deterministic migration can be used to eliminate it.

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Extermination

Extermination

The extermination symbol is used to specify the conditions under which one instance of a population submodel ceases to exist. It is sometimes called the loss or mortality symbol. It belongs to the group of symbols known as channels. The symbol's icon represents an axe.

How to add a Extermination symbol

The extermination symbol only has meaning in the context of a population submodel. Therefore, it makes sense to construct a population submodel first, then add the mortality symbol to it. This is not strictly necessary: you can add the mortality symbol first, then construct a submodel around it, then make the submodel into a population submodel, but it is better practice to construct the population submodel first.

See Adding node-type elements.

Rules

  • The mortality symbol can receive influences from anywhere in the model, both inside and outside the population submodel of which it is a part. This means that the chances of an individual instance being destroyed can depend on both factors that are external to the population, and on the characteristics of that particular individual.
  • There can be multiple mortality symbols in the same population submodel.
  • It is possible to draw an influence arrow from the mortality symbol to another element. The usual use of this is with the dies_of( ) function. The value of the mortality symbol is the value of its equation.

Interpretation

A mortality channel represents a 'risk factor' for the individuals in its population. Its value should be a fraction between 0 and 1, and this represents the probability of the individual for whom it has that value being removed over one time unit. In this sense it works like radioactive decay; the individuals do not 'lose health' before they die, but rather any surviving individual's chance of dying is determined solely by its current mortality, no matter what it has been in the past. Note that this is different from the behaviour of the migration and reproduction channels, where the rate is summed over multiple time steps. If you require your model to capture a situation in which individuals do die as a result of losing health, the process of health loss must be represented explicitly in the model, with the mortality channel only becoming nonzero when they actually go.

The rate of removal is spread over every time step; if there are 10 time steps in a time unit, and an individual's mortality is 0.3, then there is a roughly 0.03 (exactly 1- (1-0.3)0.1) chance of removal in each time step. Multiple mortality channels act independently; if there are two, and for a given individual they each have a value of 0.5 over a time unit, then the probability of that individual being removed in that time unit is 0.75. A value of 1 in any time step makes it certain that the individual will be removed in that time step.

Individuals are removed at the start of the time step following the one in which their number came up. This means other values from their submodel instances can be used in that time step. A function is available in the equation language, dies_of(), which returns true if the argument is from a mortality symbol that results in the individual's removal in that time step (cf. channel_is( ))

A removal channel can also be discrete-event valued, if it has an influence from an event or squirt. In this case, when the triggering event happens, individuals may be removed immediately. The magnitude of the removal event is the probability, as a fraction of 1, that the individual will be removed at that point. If the value is 1 or greater, removal is certain. In order to avoid any random behaviour in a model containing removal channels, they should only ever have values of 0 or 1. Removal symbols, whether discrete or continuous valued, can have boolean units ("true" or "false") which have the same effect as 1 and 0. 

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Role arrow

Role arrow

How to add a Role arrow

See Adding arrow-type elements.

Interpretation

Role arrows join submodels that participate in some form of association, or where one is a satellite of the other. The following sections detail the mathematical methods invoked by the role arrow. In each case, a multi-dimensional matrix is created containing instances of the submodel at the head of the role arrow. The dimensions of the matrix depend on the number of role arrows used, and the different uses are therefore described in separate sections.

Rules

  • A role arrow can only be drawn between two submodels, one representing the object that plays a role in an association, and the other representing the association itself.
  • Role arrows cannot be added in such a way that they form a loop.

In: Contents >> Graphical Modelling >> Object/agent based

Role arrow : Single role arrow

Single role arrow

Using a single role arrow to connect two submodels is almost exactly equivalent to nesting one submodel inside the other. In effect, the submodel that the role arrow points to, is nested inside the submodel that the role arrow points from. This alternative diagram form is useful because of the extra flexibility it allows in laying out the model diagram. It is also helpful to understand this simple use of role arrows before using them in more complex ways.

The following model diagram illustrates the relevant features of the use of a single role arrow to connect two submodels. In this case, one submodel is called "Base" (or "Master"), and the role arrow points from it, to the other submodel, called "Satellite". "Base" is a multiple-instance submodel, with fixed dimensions. In the following example, there are ten instances of "Base". Inside "Base" there is a variable called "index". The equation for "index" is "index(1)". The variable "index" therefore has a unique value within each instance of "Base".

When adding the equations for this model, you will notice that the role arrow is having an effect on the parameter names corresponding to influences that come from inside a submodel at its far end. First, have a look at "var1" in the "Satellite" model. Now, if the role arrow were not present, the only available parameter name for this would be "[index]", representing an array of the values of "index" in the 10 instances of "Master". However, with the role arrow present, you can use the parameter name "single_index", made by combining the names of the role arrow and source component. This is a scalar quantity, and has the value of "index" in the particular instance of "Master" associated with each instance of "Sattelite". It is as if "Satellite" were a simple submodel inside "Master", with one instance for each instance of its parent. (Note, if using Simile v5.7 or later, the parameter name "[every_index]" is also available, which stands for the array of 10 values that you would get if the role arrow were not present. In versions 6 and on, the availability of the different interpretations of an influence can be enabled or disabled in the influence properties dialogue -- see Influences and Roles).

Something similar happens for influences going in the other direction from the role arrow. Now, look at "sum" in the "Master" model. The parameter name "{var1_single}" is available. The curly brackets indicate that this stands for a list of values -- but because the role arrow is used, the list will contain only the values from instances of "Satellite" associated with each particular instance of "Master". In this case, that means at most one instance, and hence one value, for each instance of the base model. (Again, if using Simile v5.7 or later, the parameter name "{every_var1}" is also available, which stands for the list containing values from all instances of the associated model).

Now let's look at what happens on execution. To start with, consider a case in which the condition symbol in "Satellite" is omitted (or equivalently, where it has an equation whose value is always "true", such as 1>0). In this case, ten instances of "Satellite" are created, the same as the number of instances of "Base". Inside "Satellite" is a variable called "var1". There is an influence arrow from the variable "index" in "Base" to "var1", and its equation is simply "single_index". The value of "var1" in each instance of Satellite is therefore equal to the "index" of the equivalent instance of "Base".

To illustrate how "var1" is treated, there are four influence arrows taken from it. Two influence arrows point to variables "count" and "sum" within "Base" and two point to variables "count" and "sum" outside "Base". There is an important difference in the values received in these two circumstances, which is easy to understand if you consider "Satellite" is treated as if it were nested inside "Base".

  • Inside "Base", the equation "count({var1_single})" returns 1, and "sum({var1_single})" returns a value equal to "index" of the same instance.
  • Outside "Base", the equation "count({var1})" returns 10, and "sum({var1})" returns a value equal to sum of the index of all the instances, i.e. 55, in this case (calculated from 1+2+3+…+9+10)

Beware one point: both inside and outside "Base", the value returned from "Satellite" is received as a list, even if there is no condition symbol in the satellite. An integrating function such as sum() or count() must be used immediately on a list. Inside "Base", the list consists of a single number, so sum({var1_single}) returns the value of the number. The reason for using a list is that the list may in fact be empty, rather than containing a single value, for reasons described below. Note that curly braces are used to denote the list.

Now consider a simple equation for the condition symbol. In the example given, the condition symbol has no influence arrows pointing to it, though it can have. Suppose one wishes "Satellite" to exist for only the odd-numbered instances of "Base". In this case, the equation "fmod(index(1),2)==1" or "index(1)%2==1" would be used. Note that the index() function used within "Satellite" refers to the index of the equivalent instance of "Base".

Using the condition symbol in this or other ways permits the number of instances of "Satellite" to be less than the number of instances of "Base". There can never be more instances of "Satellite" however than instances of "Base", unless the satellite submodel has dimensions of its own.

In the example chosen above, in which only odd-numbered instances of "Satellite" are created, the four influence arrows behave like this.

  • Inside "Base", the equation "count({var1_single})" returns either zero or one. It returns one, only if this is an odd-numbered instance, i.e. for instances 1, 3, 5, 7 and 9. Otherwise it returns zero. In these cases, i.e. instances, 2, 4, 6, 8 and 10, the list is an empty list. Similarly, the equation "sum({var_single})" returns either zero or a value equal to "index" of the same instance. It returns zero for each empty list, i.e. instances 2, 4 ,6, 8 and 10.
  • Outside "Base", the equation "count({var1})" returns five. The equation "sum({var1})" returns 25 (calculated from 1+3+5+7+9).

When using the condition symbol in "Satellite", the use of the role arrow is more convenient than the equivalent nested arrangement. If "Satellite" were nested inside "Base" it would not be possible directly to receive the list in a variable outside "Base" -- you would instead get an array of lists.

Many satellite instances per base instance

In the above example, the satellite submodel does not have any dimensions of its own. It only has multiple instances because the base model does, and each base model instance can have at most one associated satellite submodel instance. But you can set dimensions for the satellite model, in which case each base model instance can be associated with up to this number of satellite model instances.

If you do this, then for equations inside the satellite submodel, index(1) means the index of that instance within the group associated with its base model instance, while index(2) means the index of the base model instance (as long as the satellite submodel has only one dimension).In other words, the value that is index(1) in a base model index is available as index(2) in its satellite model instances.

As an example, you could create a model where base instance 1 has 1 satellite instance, base instance 2 has 2, and so forth. The satellite would have dimensions 10 and the condition equation would be "index(1) <= index(2)". In the satellite, "var1" still has the index value of the corresponding base model. There would then be 1+2+...+10 == 55 satellite instances, and the value of "sum" outside the submodels would be 1*1 + 2*2 + ... + 10*10 = 385. Another example: set the condition equation to "index(1) >= index(2)". Now, base instance 1 will have 10 satellite instances, instance 2 has 9 and so forth. There are still 55 satellite instances, but "sum" is now 1*10 + 2*9 + ... + 10*1 = 220.

In : Contents >> Model diagram elements >> Role arrows

 

Role arrow : Two role arrows from different submodels

Two role arrows from different submodels

If a single role arrow between two models can be compared to nesting one submodel inside the other, using two role arrows to link submodels both to a third can be compared to creating an area where the two submodels overlap and are interleaved with each other. From the point-of-view of "Object A", "Object B" is nested within "Object A". From the point-of-view of "Object B", "Object A" is nested within "Object B".

The following model diagram illustrates some of the features of this arrangement. Two multiple-instance submodels are created, "Object A" with two instances, and "Object B" with three. Both these objects are linked with role arrows to the third submodel "Association". One instance of "Association" is automatically created for each possible pair of instances of "Object A" and "Object B".

In this case, there are six instances of "Association", resulting from the two "Object A" and the three "Object B". Inside "Association" is a variable "var1". The two variables that influence "var1" have the full path names "../Object A/index" and "../Object B/index", and each has been set to the index of its own submodel with the equation "index(1)". The instance of "Object A" and the instance of "Object B" from which each "index" is taken is determined by the instance of "Association". Each instance of "Association" receives one of the six possible pairs of the "index" variables.

Local names for the two different full path names are created to avoid duplication, and to avoid using illegal characters such as spaces in the equation. In this case we have changed the local names to be "indexA" and "indexB" to avoid confusion, as described in the help page. In this simple example, the equation for "var1" is "indexA*indexB".

If this were represented by a table, it would look like this:

 

Object A - instance 1

indexA" = 1

Object A - instance 2

"indexA" = 2

Object B - instance 1

"indexB" = 1

Association - instance 1

"Var1" = 1

Association - instance 4

"Var1" = 2

Object B - instance 2

"indexB" = 2

Association - instance 2

"Var1" = 2

Association - instance 5

"Var1" = 4

Object B - instance 3

"indexB" = 3

Association - instance 3

"Var1" = 3

Association - instance 6

"Var1" = 6

The order of the instances in "Association" is determined by the order in which the role arrows are added. It is not usually important, but selecting "allow base instance lookup" in a role arrow's properties will ensure that "index(1)" in an equation in the association submodel refers to the indices of that arrow's base submodel. To understand how "var1" is represented, six influence arrows are taken from "var1" to different parts of the model.

  • Inside "Object A"
 

{var1}

count({var1})

sum({var1})

Instance 1

{1 2 3}

3 6

Instance 2

{2 4 6}

3 12
  • Inside "Object B"
 

{var1}

count({var1})

sum({var1})

Instance 1

{1 2}

2 3

Instance 2

{2 4}

2 6

Instance 3

{3 6}

2 9

To understand where both these sets of results for "{var1}" come from, look down (for "Object A") or across (for "Object B") the relevant lines of the full six instance "Association" table given above. The count() and sum() functions operate on the given {var1} to produce the results shown.

  • Outside both "Object A" and "Object B"
 

{var1}

count({var1})

sum({var1})

 

{1 2 3 2 4 6}

6 18

As with the use of a single role arrow, the condition symbol will permit the number of instances of "Association" to be less than the product of the number of instances of "Object A" and "Object B". The Boolean expression used in the condition symbol can involve influences from other model elements and can use the index(x) function to return the instance of both "Object A" and "Object B", using x=1 and x=2 respectively.

In : Contents >> Model diagram elements >> Role arrows

 

Role arrow : Two role arrows from the same submodel

Two role arrows from the same submodel

The most common use of the role arrow is (unfortunately) the most difficult to visualise. In this case, two different instances of the same object play two different roles in an association. One might think of this as being like each instance having all the other instances nested within it.

In the case of the single role arrow, or the case of two role arrows from two objects, the role itself was not an important element. The role arrow represented graphically the nesting arrangement. In this case however, the names of the two different role arrows are the only means of distinguishing the instances of the single object within the association submodel.

The following model diagram illustrates a simple example of the use of the association submodel in this way. There is an "Object" submodel, which has three instances. Two role arrows, "Role I" and "Role II", link "Object" to the "Association" submodel.

In this case, nine instances of "Association" are created, one for each possible pair of instances of "Object". Inside "Association" are two variables "var1" and "var2". Each of these receives a single influence arrow from the "index" variable in "Object", BUT, look at the list of parameters in the equation dialogue box, and two are given. These two parameters refer to the "index" variable in each of the members of the pair of instances of "Object" that generate this instance of "Association".

A unique local name for each parameter is automatically generated, but to avoid confusion, right click on each local name to rename it indexI and indexII, for "Value(s) of ../Object/index (from Object in Role I)" and "Value(s) of ../Object/index (from Object in Role II)" respectively. In this example, "var1" is given the expression "indexI" and "var2" is given the expression "indexII".

If this were represented as a table, it would look like this:

 

Object in Role I

"indexI" = 1

Object in Role I

"indexI" = 2

Object in Role I

"indexI" = 3

Object in Role II

"indexII" = 1

var1 = 1

var2 = 1

var1 = 2

var2 = 1

var1 = 3

var2 = 1

Object in Role II

"indexII" = 2

var1 = 1

var2 = 2

var1 = 2

var2 = 2

var1 = 3

var2 = 2

Object in Role II

"indexII" = 3

var1 = 1

var2 = 3

var1 = 2

var2 = 3

var1 = 3

var2 = 3

So far, the results are rather similar to those where two objects are involved. This is also true of what follows, though it is less obvious. To understand how "var1" is represented, six influence arrows are drawn from it to different parts of the diagram. (Symmetrical results are generated using "var2", though these are not given here.)

Inside "Object", "var1" again appears as two distinct parameters, distinguished by the name of the role arrow. Alter the local names to "var1_I" and "var1_II" for "Value(s) of ../Association/var1 (to Object in Role I)" and "Value(s) of ../Association/var1 (to Object in Role II)" respectively, as before. Look at the full nine-instance table above to determine the values of "var1_I" and "var1_II", by reading across (for "Role II") or down (for "Role I") the relevant line.
OBJECT Values of var1 for role I sum count values of var1 for role II sum count

Instance 1

{1 1 1}

3 3

{1 2 3}

6 3

Instance 2

{2 2 2}

6 3

{1 2 3}

6 3

Instance 3

{3 3 3}

9 3

{1 2 3}

6 3
What's going on here is that, since the values of "var1" in each instance of the association submodel are set from the instance of the "Object" in "Role I", then the values going to the "Object" in Role I" are the same as what came from it for each instance. On the other hand, the values going to the "object" in "Role II" are all different, since the associations with that instance in "Role II" each have a different instance in "Role I". This is how the association enables values to be passed selectively between different instances of a submodel -- by taking them to the association in one role and bringing them back to the base instance in another. The values would be passed in the reverse direction if those from "var2" (which are set from "objects" in "Role II") are passed back to those in "Role I".
 
Outside "Object", "var1" has the value {1 1 1 2 2 2 3 3 3} and thus count({var1}) is 9 and sum({var1}) is 18. Note that values from all nine instances of "Association" are received by elements outside "Object".

The condition symbol can be used inside "Association" to permit fewer instances than the square of the number of instances of "Object" to be generated, and thus pass values between base instances selectively.

Inside the association submodel, the index(x) function returns the index of each of the members of the pair of instances that generate this instance of "Association" with x = 1 for "Dimension 1 of Object (3) in Role II for Association" and x = 2 for "Dimension 1 of Object (3) in Role I for Association". To identify which index refers to the use of which role arrow, see the indices panel on the Parameters tab of the equation dialogue box.

Note that the "(3)" is the size of the given dimension. Influences from other elements can also be used in the Boolean expression for the condition symbol.

In : Contents >> Model diagram elements >> Role arrows

 

Model diagram elements : Condition

Condition

A condition model element is used to specify whether a submodel, or a potential instance of a multiple-instance submodel, actually exists.

How to add a Condition symbol

The condition symbol only has meaning inside a submodel. Therefore, you should make the submodel first, then add the condition symbol to it. This is not strictly necessary: you can add the condition symbol first, then construct a submodel around it, but it is better practice to construct the submodel first.

See Adding node-type elements.

Rules

  • A condition element only has use within a submodel (since it specifies which potential instances exist). It should not appear in a population or per-record submodel because these have their own means of creating and destroying instances.
  • The expression in the equation dialogue box for a condition element is a Boolean expression: that is, it returns the value "true" or "false". This normally takes the form of some sort of comparison, using the conditional operators such as >, <, >= etc, combined with logical operators such as "and" and "or". However, conditions of the form "index(1) is <expr>" or "any(index(1) is <list_expr>)" are also allowed; see one-sided relation enumeration.
  • A condition may have influences to it from anywhere in the model. It cannot have influences from it, since either its value is "true" or its submodel instance does not exist.
  • If a condition is inside a simple submodel, then that submodel either exists or not, depending on the result of evaluating the condition's expression.
  • If a condition is inside a fixed-membership submodel, then each instance of the submodel may exist or not, depending on the condition's expression (which would make use of the built-in function index to refer to particular instances).
  • If the condition model element is inside an association submodel, then the relation exists between a particular pair of object instances only if the condition's expression evaluates to "true" for that pair. The condition's equation can use values from base instances in particular roles in order to set the association to exist only if the base instances' values match in a certain way.

In: Contents >> Graphical Modelling >> Object/agent based

Model diagram elements : Iteration

Iteration

An iteration model element makes its parent submodel an iterative submodel, whose contents should be evaluated repeatedly until a finishing condition is met.

How to add an Iteration symbol

See Adding node-type elements.

Rules

The iteration symbol contains the condition that marks the successful convergence of the iteration. On each time step of the model, after the compartment values have been adjusted, the values of all variables are calculated as normal. Then if the alarm symbol's equation evaluates to "false", the variables in its submodel are calculated again, and the test repeated, until it evaluates to "true" at which point the loop exits. See iterative submodel for a full description with examples, but a simple case of evaluation by successive approximation could be implemented as follows.

An influence arrow coming from the alarm symbol can be used as an argument to the function iterations( ). This function returns the number of iterations made so far. This function can be used to set the initial value (also called the guess) for the loop, i.e. when the number of iterations so far is equal to zero. This can also be set if the value of the alarm is "true" since this is how it is left at the end of the previous time step. If the number of iterations so far is one or more, or if the value of the alarm is "false", then the result of the last calculation should be used. Since the last calculation depends on the result calculated from the guess, a circular loop of influences is present. Normally, Simile would reject this loop at build time, but setting a property of the influence arrow: "Use values made in same time step" to true, allows the loop to be processed. Influence arrows with this property set are drawn with a dashed line. To set this property for an influence arrow, double-click on it to invoke the property dialogue box.

Note that if the value of the alarm symbol is used directly to decide if the initial guess should be used, then its influence should also be dashed, as the value of the alarm symbol is set by a test on the result. This is not necessary if using the "iterations()" function, which does not check for circularity involving its argument.

  • The expression in the equation dialogue box for an iteration element is a Boolean expression: that is, it returns the value "true" or "false". This normally takes the form of some sort of comparison, using the conditional operators such as >, <, >= etc, combined with logical operators such as "and" and "or".

In: Contents >> Graphical Modelling >> Object/agent based

Working with model diagrams

Working with model diagrams

Working with the model diagram is the heart of the modelling process. The model diagram is a graphical representation of the all the elements and relationships within the system being modelled. Using the model diagram elements, and the tools described here, an infinite range of models can be created. All work on the model diagram uses a selection mechanism to determine the elements affected.

Adding node-type elements

Adding arrow-type elements

Adding submodels

There are four tools for manipulating the elements of the model diagram.

Selecting, in order to duplicate, move, delete or label elements

Dragging the canvas around inside the viewport to show different parts of the model (this can also be done with the scrollbars or mouse wheel)

Creating ghost elements

Inspect a model variable

 

The following tools are provided for convenience in working with model diagrams

Printing model diagrams

Undoing and redoing changes

Zooming in and out

  Aligning symbols on a grid

Searching for a particular element

The following advanced topics are dealt with separately.

  •  

Rescaling symbol size in a particular submodel

  •  
Customizing the diagram's appearance
  •  

Controlling the amount of detail shown in the model diagram

  •  

Following influences around the diagram

  •  

Adding pictures to the model diagram

  •  

Saving and re-running a Simile editing session

  •  

Setting preferences

In: Contents

Working with model diagrams : Adding node-type elements

Adding node-type elements

The node-type elements are:

  • the variable
  • the compartment
  • the event
  • the ​​​​ state

as well as the elements used in population submodels. The T text box and  image element also behave as node-type elements, though no node is associated with them. The following procedure is used to add node-type elements.

  1. Click on the required node symbol in the tool bar.
  2. Click on the diagram canvas where you want to place the element.
  3. At this point the caption is selected and you can type in your chosen caption (except for images).
  4. Repeat (2) if you want to add more nodes of the same type.

Note that the button you selected on the tool bar remains depressed until you select another button (i.e. to add a different element, or to change into a different mode, such as label or move). This allows you to add quickly several elements of the same type.

There are other methods if you want to add just one element without leaving pointer mode. Any of the following will add a single element to the diagram:

  • Drag from the tool bar symbol to the chosen place on the diagram.
  • Right-click at the chosen place on the diagram, and in the context menu select "Create New" -> your chosen node type. The population submodel membership controls are listed in their own submenu.

However you add a node, it appears with a default caption, e.g., "comp33". Since this caption is rarely what it needs to be in the finished model, it is selected for editing when the node is added, so you can immediately type in a more appropriate one, e.g., "Bananas".

Note that it is not possible to add a node-type element to an area of your diagram that is already occupied. A warning message appears, so if this happens, simply click somewhere else where there is sufficient space, or move existing elements around to make sufficient space. You can also adjust the relative size of components in a submodel to make more room around them.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Adding arrow-type elements

Adding arrow-type elements

The arrow-type elements are the influence, flow,  squirt and role arrows. In general, arrows link two nodes, though there are exceptions, as explained below. There are two methods of adding arrow-type elements.

  1. Click on the required arrow symbol in the tool bar.
  2. Drag the mouse from the place where you want the arrow to start, to the place where you want it to end. If you drag outside the model window during this operation, it will be scrolled in that direction bringing more space into view.
  3. Repeat (2) if you want to add more arrows of the same type.

Alternatively,

  1. Click on the required arrow symbol in the tool bar.
  2. Click on the place where you want the arrow to start. The cursor becomes a 'cross-hairs' indicating another click on the diagram is needed to finish adding the link.
  3. Click on the place where you want the arrow to end. If you miss the exact point, you can keep the button down and drag to it. If you drag outside the model window during this operation, it will be scrolled in that direction bringing more space into view.
  4. Repeat (2) and (3) if you want to add more arrows of the same type.

Note that the button you selected on the tool bar remains depressed until you select another button (i.e. to add a different element, or to change into a different mode, such as label or move). This allows you to add quickly several elements of the same type.

You can also add a single link using either of the methods you would use to add a single node without changing mode, i.e.,

  • Drag from the link's toolbar symbol to the start point on the diagram, or
  • Right click at the start point to get the context menu, and select "create new" followed by the link type.

Either of these actions sets the cursor to 'cross-hairs', requiring another click to set the end point of the new link.

Specific instructions for each type of arrow

Flow and  squirt arrow

A flow or squirt arrow must:

  • begin in a blank area of the screen, and end in a compartment; or
  • begin in a compartment, and end in a blank area of the screen; or
  • begin in a compartment, and end in a compartment.

Note that if the flow or squirt arrow begins or ends in a blank area of the screen, Simile automatically adds the source/sink symbol (a cloud).

Note also that if you draw two flow arrows between the same two compartments in opposite directions, the arrows mainly lie on top of each other, but the valve (bow-tie or target) symbols are separated. You need to be careful that you know which valve symbol is associated with which arrow, when you come to add influence arrows or equations to the flows. You may like to use the move tool to drag the ends of the flows around one of the compartments to separate them from one another.

Influence arrow

An influence arrow must:

  • begin in any model element (except a submodel or an influence arrow); and
  • end in any model element (except a submodel or influence arrow).
     

There is an exception to this rule. If you have an influence arrow coming from an input variable inside a submodel to some element (E1); then it is legal to draw an influence arrow from some other element (E2) to this influence arrow. The effect of this is to eliminate the input variable and to cause the influence arrow to go directly from E2 to E1.

Note that if you should accidentally miss the target model element, then the influence arrow will go shooting off to the edge of the model diagram window or submodel boundary. If that happens, then simply click on the undo button in the toolbar, and try again. The reason for this behaviour is to allow you to add placeholders for influence arrows to be taken from submodels. Drag an influence arrow from the placeholder on the submodel boundary, to the desired element outside the submodel to complete the link.

Multiple influences coming from a variable in a submodel to variables outside it will share a common link as far as possible. So will multiple influences coming from a variable outside a submodel to variables inside it. This makes for a much neater diagram when there are lots of influences. However, this can cause odd behaviour when the influences point to variables on opposite sides of the submodel. You can usually fix this by selecting the move tool from the toolbar, and dragging the attachment point around the submodel boundary.

Role arrow

A role arrow must:

  • begin in a submodel; and
  • end in a submodel.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Adding submodels

Adding submodels

The following procedure is used to add a submodel to the model diagram.

  1. Click on the submodel symbol in the tool bar.
  2. Drag the mouse from a blank area of the desktop canvas, corresponding to one corner of the submodel envelope, to the opposite corner of the area that you want to be enclosed in the submodel envelope. If you drag outside the model window during this operation, it will be scrolled in that direction bringing more space into view.
  3. Repeat (2) if you want to add more submodels.

Alternatively,

  1. Click on the submodel symbol in the tool bar.
  2. Click on the place where you want to put one corner of the submodel envelope. The cursor becomes a 'cross-hairs' indicating another click on the diagram is needed to finish adding the link.
  3. Click on the opposite corner of the area that you want to be enclosed in the submodel envelope. If you miss the exact point, you can keep the button down and drag to it. If you drag outside the model window during this operation, it will be scrolled in that direction bringing more space into view.
  4. Repeat (2) and (3) if you want to add more submodels.

You can also add a single submodel using either of the methods you would use to add a single node without changing mode, i.e.,

  • Drag from the submodel symbol to the first corner point on the diagram, or
  • Right click at the corner point to get the context menu, and select "create new -> submodel".

Either of these actions sets the cursor to 'cross-hairs', requiring another click to position the diagonally opposite corner of the new submodel.

Note that the submodel you make may, or may not, enclose existing model elements. Simile will not allow you to add a submodel with the boundary passing through an existing component other than a link. When making a submodel, you can either make it to enclose some existing model elements, or it can begin life empty, with the intention of adding elements later on. The following notes apply to the two situations:

Submodel is drawn around existing model elements

The elements must be arranged so that it is possible to enclose them in a rectangle without enclosing any elements you don't want in the submodel. You may need to move them around prior to drawing the submodel envelope to achieve this. The elements are then deemed to be enclosed inside the submodel. Any links coming from outside this new submodel to elements inside it, or vice versa, will be redrawn to show a crossing point at the submodel boundary.

Submodel does not enclose existing elements

You need to find an empty area of your model diagram that is big enough to contain the new submodel. You may need to move existing model elements around in order to create some space.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Selecting model diagram elements

Selecting model diagram elements

The selection mechanism is straight-forward. First select one or more elements on the model diagram, then perform an action on the selection.

To select a single element, click on it using the pointer. To continue to select further elements, hold down the Ctrl key (Cmd key on the Mac) whilst clicking on them. If you select an element by mistake, click on it again with the Ctrl key held down, and it will be unselected, leaving the rest of the selection unchanged. To abandon a selection altogether, click in a blank area of the diagram, outside any selected submodels. To select multiple elements at once, drag the pointer across the area containing them: a marquee (rectangular selection) will be drawn around the elements that are included in the area. If you drag outside the model window during this operation, it will be scrolled in that direction bringing more space into view. The elements will all be selected when the drag is released. If any part of an element (other than the caption) is included in the area, it will be included in the selection. If you drag a marquee around some elements while holding the Ctrl key down, any elements in the marquee that were not already selected will be added to the selection. You cannot unselect elements by ctrl-dragging.

The context menu contains the commands "Select all", "Unselect all" and "Invert selection". These apply within the submodel in which you right-click to display the menu, and any submodels nested within it.

Selected components and captions will be highlit in blue. Links between selected components are also highlit in blue, while links between selected and unselected components are green. These green links will stretch if the selection is moved, and will be deleted if it is cut, but will not be put on the clipboard.

Ghosts of selected components, and base components of selected ghosts, will be highlit in bright green. It is also possible to have components connected to the selection highlit like this. Under the "View" menu, select "Highlight back" -> "One level". Now all components starting influences going to the selection, including via ghosts, are highlit. There is also the option to highlight back two or three levels, and an equivalent choice for highlighting forwards, which shows up components influenced by the selection. Components that are highlit in this way are not affected by actions done on the selection.

Various actions can be performed on selected element(s). The actions are available in the context menu, invoked with a right click. Once one or more elements are selected, the action chosen from the context menu will be performed on the selection, wherever the mouse is when the right-button is clicked.

The selection can be cut or copied to the clipboard. If you paste the clipboard into another program, such as Microsoft Word, a picture (metafile) will be shown in the document. If you paste the clipboard into Simile, the elements will be inserted, complete with functions and other properties.

In: ​Contents >> Working with model diagrams

Working with model diagrams : Duplicating elements

Duplicating elements

You can make multiple copies of one or more elements. This can be quick when some parts of your model are similar to one another. Follow these basic steps.

  1. Click on the pointer tool on the tool bar.
  2. Click to select the element you wish to copy. If you wish to copy more than one element, hold down the Ctrl key whilst selecting the elements.
  3. Use the context menu (right-click) copy and paste commands.

The selected elements will be duplicated into an area where there is sufficient space to receive them. The elements will also receive new valid names to avoid clashing with the existing selection. The elements are selected ready to move to the desired position together.

Important! You should not need to duplicate groups of elements multiple times in Simile -- if you find yourself doing so, think about using a multi-instance submodel instead.

In: Contents >> Working with model diagrams

Working with model diagrams : Moving elements

Moving model diagram elements around

You will inevitably want to change the layout of the elements in your model diagram. For the elements you have placed on the diagram yourself, such as compartments and variables, you will find that at some stage you need to move them around, to make the diagram neater, easier to understand, etc. For some elements, such as the route taken by arrows and the placement of labels, you will want to arrange them to suit yourself: perhaps an influence arrow goes behind a compartment, or two labels run together.

The basic steps are:

  1. Select the pointer tool if not already selected.
  2. Move the mouse to the element you wish to move.
  3. Click to select the element.
  4. Drag the element to the new position.

For node-type elements, the effect is pretty obvious. But note that:

  • All arrows are sticky, so that moving any node-type element causes all the arrows associated with it to move around, according to the built-in arrow pathway algorithm.
  • Nodes cannot be moved into space occupied by other nodes. However, if you keep on dragging past an obstruction, then the element you are moving will leap into position as soon as there is sufficient free space.

Special considerations apply to the following elements:

In: Contents >> Working with model diagrams

Working with model diagrams : Moving labels

Moving labels

You can move a label for a model element independently of moving the element itself. (I.e. if you move the element, the label keeps the same relative position; but if you move the label, then only the label moves - the element doesn't.)

There is no constraint on where you move the label to, so it is possible for the label to be visually far removed from the element that it is labelling. You can also move the label to be inside the element: e.g. a compartment label inside the compartment, or a submodel label inside the submodel rather than (by default) just outside it. Clicking on either the label or the element will highlight both, which is useful if you reach a situation where it is not obvious which label goes with which element.

To move a label relative to its element, the element itself must not be selected. If the element is selected, then dragging the mouse across the label will select the text of the label, allowing you to edit the label. To move the label instead, click in a blank area of the diagram or choose "Unselect all" from the context menu to ensure that nothing is selected, and then drag the label to its new position.

In: Contents >> Working with model diagrams >> Moving model diagram elements

Working with model diagrams : Moving flow or squirt valve symbols

Moving flow or squirt valve symbols

If a flow or squirt arrow has a "kink",you can adjust the position where this is drawn by clicking on the middle section, well away from the bowtie symbol, and dragging it along the length of the rest of the flow. In other cases, you cannot change the actual path taken by a flow arrow. However, you can always change the position of the valve (bowtie or target) symbol on the arrow, by dragging it along the arrow in the desired direction. You can also move the cloud associated with flows or squirts, generating a corresponding re-alignment of the route.

If you draw two flows between the same two compartments in the same direction, then the second one may partially overlap the first, including the valve symbol. You can move one or both valve symbols or kinks to enable each to be handled separately.

If you draw two flows between the same two compartments in opposite directions, then the flows may partially overlap, but the valve symbols will not, so that you do not have to move them for each one to be visible.

In: Contents >> Working with model diagrams >> Moving model diagram elements

Working with model diagrams : Moving influence arrows

Moving influence arrows

With influence arrows, you can change the route taken by the arrow. Simply drag any part of the arrow, and the whole arrow will be redrawn along a new curve.

Where an influence arrow is broken into several segments, as it traverses submodel boundaries, each segment is treated independently. Thus, dragging one segment only affects that segment. Dragging a node at the start or end of the influence arrow likewise only affects the first or last segment.

You can move the dot where the influence arrow crosses a submodel boundary. This changes only the two segments that enter or leave the dot. Click on the dot or on the arrow head connected to it, and drag around the boundary. It can be quite hard to select the dot/arrowhead for moving rather than the link shaft on either side.

In: Contents >> Working with model diagrams >> Moving model diagram elements

Working with model diagrams : Moving role arrows

Moving role arrows

Role arrows can be moved in the same way as influence arrows, by dragging any part of them. Note that as for influences, the endpoints of a role arrow cannot be moved as such; the effect of dragging them is the same as that of dragging any other part of the arrow.

When a relation arrow crosses several submodel boundaries then, as with influence arrows, the effect of such changes are local to a given segment of the relation arrow. You can drag the blobs that are drawn where they cross intermediate submodel boundaries, and this will affect the routes of the sections either side of that boundary.

Two role arrows that connect the same pair of submodels cannot be positioned directly on top of one another.

In: Contents >> Working with model diagrams >> Moving model diagram elements

Working with model diagrams : Moving and re-sizing submodels

Moving and re-sizing submodels

The following rules govern the behaviour of the move tool, when applied to submodels.

  • dragging in any blank area of a submodel moves the whole submodel and all its contents, if the submodel is selected;
  • dragging the submodel boundary resizes the submodel by moving the boundary that is dragged; and
  • dragging a corner of the submodel resizes the submodel in both the horizontal and vertical directions.

If a submodel is not selected (i.e. the boundary is not drawn blue) then dragging in a blank area within the submodel draws a rectangular marquee for selecting elements within the submodel. Only if the submodel is selected, is it possible to move it by dragging.

When moving or re-sizing a submodel, there must be sufficient area of blank canvas (with no obstructing elements) available.

Note that it is not possible to move an element across a submodel boundary, or vice versa. This is because such a move would change the actual semantics (mathematical properties) of the model, which "move" operations generally do not. It is necessary instead to cut the element (or group of elements) from one side of the boundary, and paste them in the other. This will cause any links between the element(s) and other parts of the model diagram to be broken, and they must be added again individually.

If a lot of elements are to be moved in or out of a submodel, it may be easier to delete the submodel boundary and redraw it around a different group of components. Any special properties of the submodel, e.g., dimensions, will have to be set again when it is re-created.

In: Contents >> Working with model diagrams >> Moving model diagram elements

Working with model diagrams : Moving groups of elements

Moving groups of elements

To move a group of elements while keeping them in the same places relative to each other, select the whole group as described in Selecting model diagram elements, then click on any selected element, or inside any selected submodel, and drag. It must be a fully selected element (not a highlit link connecting a non-selected element) and only components inside the same submodel as the dragged component will be moved.

Movement will stop if any component in the group being moved collides with another component. In very complex models, moving large groups of components may cause Simile's graphics to respond slowly as it redraws highlit links and checks for collisions. If this becomes a problem, use the preferences dialogue to choose "Quick drag" as described in Preferences: Edit. This turns off collision detection and link updating during a drag, allowing the graphics to run at full speed. In this mode, link re-routing and collision detection are done only when the group is dropped at the end of the drag. If the move results in elements overlapping, or ending up in a different submodel from where they started, the selection will return to where it was at the start of the drag.

In: Contents >> Working with model diagrams

Working with model diagrams : Deleting elements

Deleting elements from the model diagram

To delete elements from the model diagram, follow these basic steps:

  1. Click on the pointer tool of not already using it.
  2. To delete a single element, right-click on it.
  3. To delete multiple elements, first select them, then right-click on any selected element (or click on "Edit" in the menu bar)
  4. In the context menu, choose the "delete" command.

You can also delete the selection by hitting the "delete" key.

Please note

If you should accidentally delete something, then the Undo tool will bring it back again.

In: Contents >> Working with model diagrams

Working with model diagrams : Changing labels

Changing the label for elements on a model diagram

To re-label any element in the model diagram:

  1. Click on the select tool on the toolbar.
  2. Select an element in the model diagram, or a group of elements whose labels you wish to change.
  3. Click on the label of a selected element to change it, or drag across the label to select some text for cut/copy/delete.
  4. Use the Backspace or the Delete key to remove the existing label.
  5. Type in the label you wish for this model element. You can use any characters from the keyboard, including spaces, capital letters, the RETURN character and special characters, except for the period ( . ), the forward slash ( / ) and the reverse slash ( \ ).

If you try to change a label to one that already exists in the same submodel, or you use illegal characters in the label, or only use whitespace in the label so it cannot be seen, then Simile will generate an error message and leave the label unchanged. However any label is allowed for a T text element.

Suggestions

  • Using the RETURN character is a good way of avoiding having long labels that stretch across the model diagram.
  • You should choose labels that to some extent make the model diagram self-documenting: someone who is knowledgeable about the subject area of the model should be able to read the diagram and have a good idea of what most of the labels mean.
  • However, remember that the labels are (by default) the names of the variables used in equations. Therefore, you should avoid labels that are too long and wordy. (You can however provide your own local names for variables inside equations, so you can use long labels if you prefer.)
  • Remember also that the full label for an element in the model diagram is the label that you give it, along with the labels of any submodel(s) that it is enclosed within. (This is just like file names: the name of a file is the name given to it, along with the names of all the directories it is enclosed within.) Therefore, if you have a biomass compartment in each of two submodels - say "animal" and "plant" - then it is quite acceptable to label each of the two compartments with the same label, "biomass", since one is "plant/biomass" and the other is "animal/biomass".
  • Choose names that reflect the type of element that you are re-labelling: see below.

Appropriate types of label for different types of model element

Compartments

The label should reflect the fact that this is (usually) referring to an amount of something. Thus, use terms like biomass, area or numbers.

Flows

The label should reflect the fact that the a flow is (usually) some process. Thus, use terms like production, growth, reproduction.

Simple submodels

The label should reflect the subsystem being modelled, for example, "vegetation".

Multiple-instance submodels (fixed-membership and population submodels)

The name should reflect one instance of the type represented by the submodel. Thus:

  • if you are modelling a stand of trees, then the submodel should be called "tree";
  • if you are modelling an area as multiple patches, then the submodel should be called "patch";
  • if you are modelling multiple size classes, then the submodel should be called "size-class".

i.e. use the singular, not the plural. The reason for this is that the submodel represents a single individual: the fact that there is a set of them is indicated by the appropriate setting in the Properties box for the submodel: it is not an intrinsic property of the submodel itself.

Association submodels

The label should reflect the type of association that exists between the two types of object involved in the relation. Thus:

  • if the association submodel represents ownership between people and patches of land, then label it "ownership";
  • if the association submodel represents the fact that some spatial units are next to others, then label it "next to".

Role arrow

The label should reflect the role of the object in the association. Thus, if the association submodel is used to represent ownership of patches of land by people, then the role arrow coming from the person submodel should be labelled "owner", and the role arrow coming from the patch submodel should be labelled "owned".

In: Contents >> Working with model diagrams

Working with model diagrams : Create ghosts

Creating ghost elements

Large diagrams can become unwieldy, due to the long distances across which influence arrows must be drawn. To work around this, it is possible to create a ghost of a node element, which has the same value at all times as the original. The ghost can be placed close to the other element(s) that the original element influences. A ghost can be recognised by its appearance (ghostly).

A single original element can be ghosted more than once, each ghost being placed closer to other elements. Influence arrows and flows can be drawn to and from ghosts as usual. These will affect all instances of the original. To create a ghost, the following procedure is used:

  1. Click on the ghost button on the tool bar, or select the "Ghost" item on the "Tools" menu.
  2. Click on the element to be ghosted. The cursor now takes on a 'cross-hair' appearance, indicating another click is needed to complete the operation.
  3. Click on the model diagram to place the ghost. If you click on an existing element on the model diagram, it will become the ghost. If you click in a blank area, a new symbol will be placed there.

Alternatively, you can:

  1. Click on the ghost button on the tool bar, or select the "Ghost" item on the "Tools" menu.
  2. Drag from the component to be ghosted, to the location of the new ghost.

Once a ghost is created, changes to its equation or other properties will also affect the original, and other ghosts created from the same original. Care must be taken in using ghosts as it is easy to overlook the fact that a ghost exists elsewhere and will be affected by changes made to the original which are not appropriate for the ghost. When a component is selected, all its ghosts are highlit in bright green.

There are implied influence arrows between the original element and its ghost. You can turn on the display of these influence arrows, in order to find all related ghosts for example, using the "Show detail… Ghost links" command of the View menu. Once the ghost links are displayed, they can be deleted, in which case the component at the end ceases to be a ghost, and is marked incomplete (red) unless it has an equation of its own.

It is sometimes useful to replace a component in one part of a model with the ghost of another, allowing the value of the ghosted component to be used everywhere the value of the original component was previously used. To do this, you can click on, or drag to, another component when creating a ghost. The component becomes a ghost, keeping all its connections. For this to happen it must be the same type as the component being ghosted. The original equation of the replaced component is remembered, and reappears if it ceases to be a ghost.

Note that if you delete the original element, all its ghosts will become undefined unless they previously had equations of their own. You can delete a ghost without affecting the original, unless you have added influence arrows or flows to the ghost, in which case these will no longer be used by the original.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Printing



Printing model diagrams

To print a model diagram, either select the "Print…" option on the "File" menu, or click the button on the tool bar. Either command will invoke the print dialogue box, which allows you to select a printer, choose the number of copies, and change printer settings, such as printing in portrait or landscape orientation.

The model diagram is scaled to fit on a single sheet of paper.

In: Contents >> Working with model diagrams

Working with model diagrams : Undoing and redoing changes



Undoing and redoing changes to the model diagram

A record is kept of the last 32 changes you have made to the model diagram, including operations like adding new elements, deleting, moving and renaming elements, and entering or changing a value or equation.

Undo

The Undo button on the toolbar and the Undo command on the Edit menu reverses the effect of the preceding operations in turn (up to a maximum of 32). You must undo operations in sequence, it is not possible to undo an earlier change without also undoing all subsequent changes.

Redo

The Redo button on the toolbar is, in effect, an un-undo button: it reverses the effect of a preceding click on the Undo button. As with the Undo button, you can Redo any number of Undo's (up to the maximum of 32). However, note that the Redo button is only activated immediately after a click on the Undo button. If you click on Undo, then do something else (like add a new compartment), then the Redo button is greyed out and you can no longer use it.

In: Contents >> Working with model diagrams

Working with model diagrams : Zooming in and out

Zooming in and out

You can zoom in and out of a model diagram. Zooming in makes the symbols bigger but shows less of a large diagram. Zooming out shows more of the diagram but makes the symbols smaller.

There are two methods for zooming:

  • using the Zoom... item in the View menu
  • using the Zoom buttons on the toolbar

Zooming using the "Zoom..." item in the View menu

In lots

2x scaling: symbols are doubled in (linear) size.

In a bit

approx. 1.25x scaling: symbols are slightly bigger

To selection Scales and scrolls the diagram so the viewport fits around the selected nodes and submodels. This will not change the size or shape of the overall diagram.

To fit

Re-sizes the whole diagram so all components just fit the window. Note that this is according to the most constraining dimension, so the operation may add more whitespace to the overall diagram. Whitespace outside the viewport is trimmed from the diagram.

Out a bit

approx 0.8x scaling: symbols are slightly smaller. If the diagram shrinks below the size of the viewport, whitespace will be added around the edges.

Out lots

0.5x scaling: symbols are halved in (linear) size. If the diagram shrinks below the size of the viewport, whitespace will be added around the edges.

Zooming using the Zoom buttons on the toolbar

  • has an effect between the "Zoom...in a bit" and "Zoom...in lots" items in the View menu: it scales by approx. 1.4x, making the symbols larger and showing less of the diagram.
  • has the same effect as the "Zoom...to fit" item in the View menu: see above for a detailed description of its behaviour.
  • has the same effect as the "Zoom...to selection" item in the View menu: see above for a detailed description of its behaviour.
  • has an effect between the "Zoom...out a bit" and "Zoom...out lots" items in the View menu: it scales by approx. 0.7x, making the symbols smaller and showing more of the diagram. Whitespace may be added.

In: Contents >> Working with model diagrams

Working with model diagrams: Aligning symbols on a grid

Aligning symbols on a grid

Simile's desktop area can display a grid of horizontal and vertical lines which is used to aid accurate placement of model components. The display of this grid is turned on or off by means of the toggle-grid button () in the menubar. The functions of the grid can be activated whether or not it is currently being displayed.

Controlling grid appearance

The pitch of the grid (frequency of lines) and how heavy they appear on the desktop can be adjusted from the 'Layout' tab in the Preferences dialogue. There is also an option on this tab to select whether the grid appears initially in a new window.

Using the grid

The 'Edit' tab in the Preferences dialogue has a checkbox labelled 'snap to grid'. When this is checked, any component added to a model will 'snap' to the nearest grid intersection. When dragging a component, or dragging a submodel boundary, it will 'jump' between successive grid intersections or lines. This does not happen when dragging a link to change its route, when dragging a component's caption, or when dragging a bowtie along a flow.

Components that were previously placed higgledy piggledy can be aligned to the grid by selecting them, then choosing 'align to grid' from the Edit menu. This works whether or not 'snap to grid' is checked. Components are aligned on their parent submodel's grid. Note that if a submodel has a relative scale that does not go into 1 an exact number of times, then its internal grid will not match up with its parent model's grid.

Changing the grid pitch does not itself cause components to snap to the new grid; this must be done afterwards using Edit -> Align to grid.

In: Contents >> Working with model diagrams

Working with model diagrams : Searching for a particular element

Searching for a particular element

Navigating through large or complicated diagrams is made easier by the search facility. This will highlight the element you are looking for, and centre it in the window, if the model diagram extends beyond the window's edges. You can search for components by following connections around the diagram, or using text contained in their caption, equation or description and comments, using the "Find" tool.

The simplest way is to use the two tools provided on the toolbar:

  • "Find" calls up a dialogue box into which you enter the text, and specify which text elements to search
  • "Find Next" searches for successive occurrences of variables satisfying your search criterion

There are two search modes available in the dialog box:

  • According to influence arrows and ghost relations in the model (selected by upper row of buttons)
  • By looking for keywords in the text associated with components (selected by "OK" button)

Elements are searched in order, with the first to match the search conditions being highlighted. If this is not the one you want, or you want to find others that satisfy the same conditions, use the "Find Next" tool. Alternatively, you can choose the commands "Find..." and "Find next" on the Edit menu. "Find Next" will be available to continue to show the results of the last search until a new search is done. If you choose "Find..." from the context menu after right clicking in a submodel, the search will only turn up components within that submodel, even if you choose "Find next" somewhere else.

The description and comments associated with an element are entered using the equation dialogue window, as is the equation itself. The caption (or name) of an element is entered on the model diagram.

Note that the text is not case-sensitive, so "VAR" will mach "var". Note also that the text will match its use anywhere within the text elements searched, so "ar" will match both "car" and "arm". Also note that you cannot put a newline in the search string, as hitting the Return key starts the search. You can instead include \n (backslash-n) in the search string, and this will match a newline in the text being searched for.

Searching equations is a useful way to find where a particular function is used. For example, searching for the text "rand" in equations will find all the elements using the functions "rand_var" and "rand_const".

As well as searching for text, the search system can follow influences around the diagram, even when these come to and from ghosts of the starting point. To use this feature, first select one or more nodes in the diagram, then hit the "Find" button. The dialogue contains a "Follow influences" panel with three buttons, "Components influencing selection", "Components equivalent to selection" and "Components influenced by selection". If you hit the first of these, the selection will be cleared and a component which starts an influence arrow going to a previously selected component will itself be selected. Now you can hit either "Find next" to go to another component that influences the original selection, or "Find" followed by "Components influencing selection" to go to a component influencing the one you just went to. "Components influenced by selection" does the same thing but searches forwards along influences rather than backward, and "Components equivalent to selection" merely finds ghosts of selected components, or bases of selected ghosts.

In: Contents >> Working with model diagrams

Working with model diagrams : Rescaling symbol size in submodels

Rescaling symbol size in submodels

When you construct a submodel envelope around part of a model diagram, then the symbols inside it are the same size as the ones outside. Similarly, if you construct an empty submodel, then the symbols you place inside the submodel are, by default, the same size as symbols you place outside. In principle, one could construct a complex model, containing many (perhaps nested) submodels, with all the symbols being the same size at any level of nesting. In practice, however, this may be undesirable or difficult to achieve.

You can control the scale of the symbols inside the submodel relative to those in the desktop by using the "Relative scale" slider control in the "basic" tab of the submodel properties dialogue box. This dialogue box is displayed by double-clicking anywhere within the submodel, or by selecting the "Properties…" command from the context menu, which can be displayed either by right-clicking in the submodel or by opening the submodel in a new window, and using the "Edit" menu in this window.

The default symbol size is the same as the desktop, i.e. a relative scale of 1, and using the slider control it is possible to reduce this to make the symbols smaller. If you wish to make the symbols in a submodel larger than in the desktop, you must use the same slider control on the desktop window, either by double-clicking on the desktop or selecting the "Properties…" command from the context menu. This control allows you to reduce the absolute size of the desktop symbols, meaning that the symbols in submodels are now relatively larger.

Note that if you open a separate window to display the submodel's contents (e.g., by doubleclicking on its border) and then do zoom operations in that window, these may also affect the relative scale of the submodel contents. For instance, if you "zoom out" and this results in more whitespace being added around the components, then the scale is reduced because the extra space has to fit inside the same submodel envelope in the parent. This may also happen if you expand the separate window to display more space. Conversely if you "zoom to fit" in the separate window, this may trim whitespace from the submodel contents, causing their relative scale to increase so they fill the submodel envelope.

In: Contents >> Working with model diagrams

Working with model diagrams : Customizing the diagram's appearance

The "View -> Customize" menu selections display a dialogue that allows you to customize almost any aspect of the model diagram. You can change the appearance of just one type of component, or all components at once. The dialogue displays an example of how the component (a compartment if customizing all components) will look after any changes are applied.

image here

Text panel

This panel is displayed only when customizing a item type that has a caption, or the text box item type, or all item types at once.

Default caption offset and anchor

In this display, dragging the caption will set the relative position in which it appears to the component by default. This setting is overridden when dragging the captions of individual components on the diagram. The caption can be dragged by any of nine 'anchors' -- the four corners, the middles of the four sides, and the centre. Dragging the caption by an anchor sets the point that will remain the same when the text is changed; e.g., if it has been dragged by the top anchor, then adding new lines to the caption will cause it to be extended downwards.

Size and font

A horizontal slider allows the relative size of the text (relative, that is, to the scaling applied in whichever submodel the component is in) to be set. Below that, three drop-down menu buttons allow the font family, weight and slant to be set. Not all combinations of these are available on any given machine, and in the case that the desired combination cannot be displayed, a close approximation will be selected. The "All..." button to the right of these opens a separate dialogue from which any font available on the system can be selected.

Bounding box and colour

Text can be displayed with a bounding box, to allow it to show against a similarly coloured background and to make it easier to click on in a cluttered screen. The border and background of this box can be turned on and off with the appropriate checkbuttons in this panel. The border is the same colour as the text; the background is some other colour chosen to contrast with this. The "Set colour" button displays a dialogue which allows the default colour of the captions to be changed, although if a component is incomplete, selected or highlit, the caption will always be the same colour as the component's outline. When you hover over this button, it turns the currently selected colour.

Graphics panel

The graphics panel is displayed when customizing any item type except the text box, or all item types at once.

Colours

Items (except role arrows, influences and submodels, which have no fill) are drawn on the diagram using two colours, the outline and the fill. The fill colour is always the same, and can be set with the "Set fill" button. The outline colour depends on whether the component is incomplete, selected or highlit. "Set outline" sets the colour that applies if none of these are the case, and the other buttons set the colour for each of these cases. "Highlight" is the colour of a link between a selected and an unselected component, and "target" is the colour of a ghost when its base is selected, or vice versa, or a component highlit as a result of the highlighting choices in the View menu. All these buttons turn the currently selected colour when hovered over.

The colour used in a particular circumstance can be set to transparent. Any component or part of a component displayed as transparent will be invisible. A useful trick for very complex diagrams is to set the outline colour for influences to transparent. This prevents them appearing at all unless a component they connect to is selected.

Size and thickness

These sliders alter the size and thickness of each component type. Size is interpreted differently for some components; for a submodel it means the radius of the corner arcs, while for a link it sets the relative size of its arrowhead and 'blob' at the start, as well as the bowtie for flows.

Action buttons

This dialogue has four action buttons at the bottom:

  • Normalize: reload the dialogue settings with Simile's defaults
  • Done: Apply any changes to the diagram and quit the dialogue
  • Apply: Apply any changes to the diagram and keep the dialogue open
  • Cancel: Close the dialogue, ignoring any changes that were made since the last 'apply'.

If a model is saved after its appearance has been customized, the customization settings will be saved with it and restored when it is reopened, provided "Save models as canvas file" is selected on the Save tab of the Preferences dialogue. Otherwise no custoization will be saved and the model will have the default appearance when reopened.

In: ​Contents >> Working with model diagrams

 

Working with model diagrams : Controlling the amount of detail

Controlling the amount of detail shown in the model diagram

By default, Simile displays all the elements in the model diagram (except for ghost links): compartments, flows, variables, influence arrows, labels, etc. However, you may want to suppress the display of some of the elements to make the diagram less cluttered and less confusing, especially if you are showing a fairly complicated model to someone else for the first time.

Simile enables you to control:

  • which types of elements are displayed; and
  • the levels of submodel nesting that are displayed for each type of element.

The first submenu for the Show detail item in the View menu enables you to select the type of element whose display you want to change. You can then select the submodel nesting level from a further submenu.

If you select:

 None

then that type of element is not displayed at all.

 All

then it is displayed at all levels.

1
levels

it is displayed only at the top (Desktop) level.

2 levels

it is displayed at the Desktop level and the top level of submodel (but not the submodels nested inside the top-level submodels).

The elements are arranged in order, such that turning off the view of compartments also turns off the view of variables at the same level. Turning off the view of variables also turns off the view of influence arrows, and so forth. This is to avoid producing nonsensical or misleading views.

Note that they apply within each window that displays part of the model. So, if you set submodel display to 1 level, so only the outlines of the submodels are displayed, then click on a submodel's boundary to open a new window for it, that window will show the contents of the submodel down to the next level.

There are three other mechanisms for limiting the amount of detail.

  1. If you open the properties dialogue box for a particular submodel and go to the Advanced tab, there is a checkbutton labelled "hide contents" in the Appearance panel. If you check this, the submodel will be displayed as an empty box, while other submodels at the same level still display their contents.
  2. At the bottom of the "Show detail" menu is a submenu for "Influence sections". This can be set to "Local", meaning only influences fully inside the same submodel are shown, or "Terminal" meaning only those actually connecting a component are shown, as well as "All", the default setting.
  3. As described in Customizing the diagram's appearance, you can set the default colour of a component's outline or fill to transparent. This is useful because it will then normally be invisible, but will show up if it is selected or highlit or becomes incomplete.

If you adjust the level of detail in a model's display, then save the model, these settings will be restored when the model is reopened.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Following influences around

Following influences around the diagram

When creating a complex model, it can be very useful to see at a glance which components are influencing, and which are influenced by, the component you are looking at. This is particularly useful if you have a model spread over a very large diagram with ghosts used extensively to reduce the clutter of influence arrows. It is also very useful for debugging a running model - if you are looking at a component which seems to have the wrong value, it is useful to be able to jump to the values that are influencing that component to see where the error is creeping in.

Simile provides two mechanisms for following influences, one focused on the diagram and the other on the search mechanism.

Highlighting upstream/downstream

Normally, the selection is shown in blue, and the links to and from the selected area in dark green. There is also a set of highlit components, normally shown in light green (though all these colours are customizable, see "customizing desktop appearance"). The highlit components include the ghosts of components in the selection, and components whose ghosts are in the selection. But it can be modified to also include components influencing or influenced by those in the selection, at up to two steps away in either direction.

To enable highlighting of more components, select one of the last two entries of the desktop's View menu, 'Highlight Back' or 'Highlight Forwards'. Each of these has entries for One or Two functions, as well as the default setting of bases or ghosts only. Once this is done, components in the specified relation to the selection will be highlit immediately whenever a selection is made.

Searching for related components

This method causes the model diagram to scroll to show the relevant components, which is convenient for very large models. Make your selection in the normal way, then hit the 'Find' button as described in the Searching section. At the top of the dialogue that appears are three buttons, 'Components influencing selection', 'Components equivalent to selection' and 'components influenced by selection'. Hitting any of these buttons will start the search immediately; other fields in the search dialogue are ignored. One result is selected at a time, as for other searches, and the diagram scrolls if necessary to place the selected result at the centre. Since each result becomes a new selection, when you reach the one that is along the path you are following, you can immediately open a new search dialogue to continue searching from that point.

In: Contents>> Working with model diagrams

Working with model diagrams : Adding background pictures

Adding background pictures

There is limited support for including pictures on the model diagram.

To include a picture on the model diagram it can be in one of a wide range of formats, including gif, png  or jpeg format. An image can be placed on the diagram using the  image component, in which case it cannot overlap other components. Alternatively it can cover the whole desktop background, or a particular submodel. The image can be cropped, stretched or tiled to fit in the available space.

The following procedure is used to add a background image to the model diagram.

  • Firstly, if you wish to use a submodel as a placeholder, add a submodel of the desired size and shape, as described in Adding submodels.
  • Secondly, to add the picture, use the select tool to double-click within a blank area, within the submodel if you have added one, or if not, anywhere on the desktop. This invokes the submodel properties dialogue box. Then:
  1. Click the "Image…" button in the "Background shade" section.
  2. Browse your file system and select the picture you wish to use, which must be in gif or jpeg format, and click "Open".
  3. Select one of the "Tiled", "Centred" or "Scaled" radio buttons to control how it is positioned. "Tiled" or "Centred" will cause it to be cropped if it is larger in pixels than the space available.
  4. Click "OK" to return to the model window.

The selected picture will now appear in the background of the model, or on the model desktop. You can continue to work with the submodel exactly as normal. You can resize it, in which case the picture will be cropped, stretched or tiled as necessary, or add model diagram elements, which will appear in front of the picture.

The submodel's background colour, or whatever is behind it if it is transparent, will show through any transparent or low-alpha parts of the image.

Note that if the image is positioned centred (i.e., cropped if it is larger in pixels than the space available) the zoom commands do not affect the size of bitmaps (these are fixed in pixels). Therefore if a model diagram is zoomed in to higher magnification, the bitmap will appear smaller than before, relative to its placeholder.

In: Contents >> Working with model diagrams

 

Working with model diagrams : Saving and re-running a Simile editing session

Simile v6 introduces the ability to save and re-play the actions that are carried out in a model editing session. This is useful for presentation and training purposes.

Normally, when editing a model, the 'undo' and 'redo' buttons will move the process back or forwards one operation each click. But during re-play of a session, they can move the action forwards or backwards between pre-defined points. This is useful to skip to important points in the model development process.

To record a session, open a previously saved model or start with a blank desktop. While making changes to the model, when you reach a point at which you want the replay to pause, select View -> In replay -> Pause from the desktop menu. Do not save the model while recording a session, as playback will start from the last point at which a model is loaded or saved. When you have completed the session, select Export -> Session record, and choose a file name for it. It will have the .ssn extension.

To play back the session, in an empty model window, simply select Import -> Session record and navigate to the session you saved earlier. If the session started with opening a model, Simile will re-open the model. It will run through the session to the first point at which you selected a pause while creating it. Note that if you want to start with a view of the model you initially loaded, you should select a pause immediately after loading it.

You can now use the 'redo' button to jump forward through the session between the saved pause points. After the last pause, the model will jump to the end of the session. The 'undo' button will jump back to earlier pauses and eventually to the beginning of the session. You can navigate backwards and forwards through the session with the two buttons. If you start editing the model directly during a session playback, the part of the session after where you were when you edited it will be lost -- the 'undo' button will now take you back through your edits as normal, then back through the session jumping between pause points, and 'redo' will take you forward through the session and then into the new edits at the point at which you made them.

Long sessions can be recorded in several stages. After recording the first stage, you can save the model if required, then in a new empty desktop, play back the session and continue to work on the model, creating further pause points. When you save the session again, it will consist of the two sessions running one after the other.

In: Contents >> Working with model diagrams

Working with model diagrams : Preferences

Preferences dialogue box

You can specify your preferred settings for the interface. The settings are edited using the preferences dialogue box. The settings are stored between sessions in a file called "prefs" in the .simile hidden folder in your home directory. The settings are stored in this file automatically; there is no need to edit it yourself.

The preferences box is displayed by selecting the last item in the "Edit" or context menu, but the preferences always apply to the whole of Simile. It is a 'persistent' rather than a modal box, which means you can continue working with Simile while it is displayed. Most changes take effect instantly, though some only apply when you actually interact with the relevant part of the diagram (e.g., flow routing). Those where you have to type in a preference (e.g., numerical) can be made to take effect immediately by hitting Return. The "OK" or "Cancel" buttons will remove the box; "OK" saves changes to the preferences, while "Cancel" puts the preferences back as they were when it was opened.

The options are displayed in six sections, in a tabbed notebook in the box:

  • Layout, for options relating to how the diagram window looks
  • Content, for options relating to popups and dialogues
  • Edit, to control the model design process
  • Build, for options which affect how the model is converted into a program
  • Save, for choices about how much information to save
  • Run, for options about how the output of the model is presented.

Please consult each section for further help.

In: Contents >> Working with model diagrams

 

Preferences : Layout

Preferences dialogue box: "Layout" settings

 

Initial window position:

Your computer's operating system will normally decide where to put Simile's first window on your screen when you start it. This is usually the best choice, but on some setups you may prefer to always have it in the same place, in which case you can select "Where it was last time" in this panel, causing Simile to remember the position of the last model window when it closed.

In new model windows, display: bars and grid

When a new model window is created, which happens both when Simile is started or when a submodel is opened in its own window, the window is capable of displaying the standard toolbar, component bar and equation bar, if desired. Note that this does not change the display of the tool bars in existing windows. To control the display of the tool bars in existing windows use the "View" menu and check or uncheck the "Toolbar", "Component bar" or "Equation bar" items. The default is to display all three tool bars, unless the window is not large enough.

The display of the placement grid behaves the same way, but there is also a toolbar button to turn it on and off. Note that snapping to the grid can happen whether or not it is displayed.

Placement grid pitch and depth.

These choices allow you to set the vertical and horizontal pitch of the placement grid. Choosing different values for each of these results in a rectangular grid. The depth sets the visual prominence of the grid lines. How strong they actually appear will also depend on the display device. (Note that if your desktop or submodel background is very dark, you might want the grid to be lighter than the background, in which case enter a negative number here.)

Toolbar and popup formats

An alternative set of tool bar and component bar buttons is provided with 24x24 pixel graphical images. The default is to use 16x16 pixel graphical images.

Normally, hovering over any active object in Simile's display (e.g., buttons, menu entries) will pop up a message with a brief description of what it does. The second option on this tab turns these popups on and off.

By default, Simile's popup tool tips are rectangles drawn inside the window containing the component they describe, and cannot extend outside that window. Selecting 'Top-level popups' makes them draw as separate windows, which can look better although they may be positioned wrongly in some desktop setups.

Widget theme

Simile's user interface components can be configured to a number of different themes. The theme chosen by default is the one that most closely matches a typicall application on the platform you are using. If you prefer another theme, you can select it here, with immediate effect.

In: Contents >> Working with model diagrams >> Preferences

 

Preferences : Content

Preferences dialogue box : "Content" settings

 

Display popups over model components for equations, values and comments

While in pointer mode, holding the pointer over any model component will cause a popup window to appear including that component's equation, value(s) (while the model is running) and description and comments. These can be suppressed by unchecking any or all of these options. If none is selected, the popups are suppressed completely.

  • The equation is displayed on a green background.
  • The description and comments are displayed on a brown background.
  • The current value for the variable, provided you have built the model, is displayed on a yellow background.

The 'Size limit' sets the maximum number of characters that can appear in a field of a model component popup, in order to keep the boxes to a reasonable size. If there are more characters than this (e.g., values from a submodel with thousands of instances) then the middle of the text will be replaced with '.....'.

Normally, an array or list value is displayed as a sequence of indices alternating with values. This can be overlong and hard to read for multidimensional values, so as an alternative Simile v6.9 and later can pop-up 2-D values as matrices, where the indices are not displayed but can be inferred from the row and column positions of the values. This mode is selected with the 'Show 2-D values as matrices' checkbox.

Note that an alternative, especially for complex data structures, is to use the snapshot tool.

Equation listings show parameter origins, enumerated type definitions, comments

The three checkboxes in this section control the behaviour of the equation listing generator.

  • 'Parameter origins' lists the paths to each component whose value is used in the equation.
  • 'Enumerated type definitions' lists the members of enumerated types with the submodels where they are defined.
  • 'Comments' includes descriptions and comments added to all components. 

In: Contents >> Working with model diagrams >> Preferences

 

Preferences : Edit

Preferences dialogue box : "Edit" settings

Snap-to-grid, Quick drag, Custom keypad button.

When "Snap to grid" is selected, any time a component is added to or dragged around the diagram, its position will jump to the nearest intersection on the placement grid. When submodel boundaries are dragged, they will jump to the nearest parallel line on the grid. This does not affect link routing, or caption or bowtie positioning.

When "Quick drag" is selected, collision detection is turned off when dragging components and boundaries, and only done at the end of the drag. This allows dragging to be smoother in very complex models on a slow computer.

The keypad in the equation dialogue has a button for inserting a special character (left of AC). By default this is μ, the 'micro-' prefix for physical units. In this box you can set it to any hard-to-find character you use frequently, e.g., π (the numerical constant pi -- copy it from here!). You can also set it to a word.

Select links end-to-end

Influences and other arrows that cross submodel borders are divided into sections. This option controls whether sections of influence arrows can be selected individually. The default is that clicking on a link at any point, or selecting either of its end points, will select all the sections of the link that are part of the same branch. This alternative, of selecting only the section clicked on, allows parts of a link to be deleted, leaving hanging sections that can be rejoined in different combinations. This is useful for separating and rejoining parts of a model, particularly when building a model from a selection of modules which can be connected together in different arrangements.

Link routing

Flows and squirts can be drawn as either a series of horizontal and vertical sections (following a rectilinear route) or as a straight line (at any angle) between source and sink. Checking or unchecking the 'kink flows' box does not cause the diagram to be redrawn immediately, but when flows are redrawn, they will be redrawn in the new style. The default is for rectilinear flow routing, i.e., kinked if necessary rather than diagonal.

Influences and role arrows are drawn with a default clockwise curvature, but their routes can be adjusted after adding them. The values here set the number of degrees through which they turn when first added -- zero means draw them straight, negative means curve anticlockwise.

Default background for submodels

Submodels can have a background colour and/or a background image, or neither, in which case the background is transparent. A transparent submodel will show the background of its parent submodel through it. This can look messy if the placement grids do not align, so Simile's default behaviour is to give new submodels their own white background. This opton allows new submodels to be transparent (or black for that retro glow look) by default instead.

In: Contents >> Working with model diagrams >> Preferences

 

Preferences : Build

Preferences dialogue box : "Build" settings

 

Use which C++ compiler

 

To run a Simile model at maximum speed, it is converted into a c++ program. This program must then be compiled into executable code. The Windows and (up to release 5.4) Mac versions of Simile include a compiler (GNU g++) and associated tools to allow the code to be created without anything else being installed. This is the 'Default' compiler choice.

The Linux and current Mac versions do not include a c++ compiler; there must be one present on your system. Most Linux machines have one already, and if you do not, it should be simple to add it via your distribution's package management tools. If you have installed Simile as a .deb or .rpm package, the installation process will ensure that the compiler is also installed from the repository. This preference option does not appear on Linux. The Mac version will prompt you to install XCode command-line tools when you run Simile, if it is not already installed. This includes the GNU c++ compiler, which will then be the only choice available.

Even if you have a built-in compiler, you may wish to use another that is present on your system. This choice allows you to do so. Models can be compiled and linked using either Microsoft Visual C++ (Windows only, any 32-bit version) or GNU G++ (version 2.95.2 or later). The GNU compiler is included in the XCode Tools for the Mac, and is available for Windows as part of the MinGW toolchain. Hence on Windows you will see the 'default' option, plus the 'GNU' and 'Microsoft' options if the appropriate compilers have been installed.

Pause to edit c++ code

This option allows you to look at, and perhaps modify, the c++ program generated by Simile before it is compiled. This can be educational, and allows you to include the model source code in other tools. Because it is primarily used for debugging, this option also turns on various other messages relating to code generation.

Extra compiler flags

An 'expert' option -- add text here to specify optimization, inclusion of debugging symbols, saving of intermediate files and other exotic compiler features.

In: Contents >> Working with model diagrams >> Preferences

Preferences : Save

Preferences dialogue box : "Save" settings

Save models as canvas or model file only

Saving canvas data to a separate .cnv file allows the screen to be redrawn more quickly when loading models. It does not affect the model itself, and all the diagram information is still saved with the .sml model file. The default is to save the canvas information.

Show how many reopen options

The "File" menu contains a recently-used file list, to speed up re-opening models. The number of entries on this list is controlled here.

Unsaved edits

These options control what to do if closing a window with an unsaved model (full or short save reminder) or if leaving the equation bar after having made changes to its contents (apply change, abandon change, or ask what to do in a dialogue).

Leaving equation bar

If you are editing a component's equation in the equation bar, you van save the new version by hitting newline or selecting the 'tick' button. This option specifies whether to also save the new version if you just go straight to some other action in the model window. If this is chosen, beware that you may get an error message at an unexpected moment if the equation is not valid when you exit the edit.

Saving .csv files

The most widespread version of the .csv data file format is to have the rows separated by newlines and the columns separated by commas. However, other column separators are occasionally used, such as semicolon and space (note that the entry field will appear the same with a space in it as with nothing!) This controls the column separator used when writing .csv data from the snapshot tool, the data table helper or the logging helper. The column separator to use when reading a .csv file can be set in the file parameter dialogue.

In: Contents >> Working with model diagrams >> Preferences

Preferences : Run

Preferences dialogue box : "Run" settings

Run time environment

Use single window: This option selects between the single-window and multiple-window run time environments. The former is the most common choice.

Reset sliders on model reset

This controls whether resetting a model to its initial state causes sliders that have been adjusted during the previous run to return to their default positions. The sliders will always return to default positions when re-running the model.

Position of run control and input sliders

When not using the single window run time environment, the initial positions of the run control and slider windows are specified here, in the form xy, x and y specify the desired location of window on the screen, in pixels.

Each of x and y must be preceded by + or - . If x is preceded by +, it specifies the number of pixels between the left edge of the screen and the left edge of window's border; if preceded by - then x specifies the number of pixels between the right edge of the screen and the right edge of window's border. If y is preceded by + then it specifies the number of pixels between the top of the screen and the top of window's border; if y is preceded by - then it specifies the number of pixels between the bottom of window's border and the bottom of the screen. For instance, "+100-100" would place the window a short way in from the bottom left corner. Enter "default" to use Windows built-in placement algorithm.

Numerical value precision

These set the number of significant figures that are used when a floating-point numerical value appears in a popup or a snapshot window. By default it is 12, and setting it greater than this will result in meaningless extra digits being added because the internal representation is double-precision. These displays may be easier to read if you select a lower precision. This setting does not affect data displayed in the I/O tools, which have their own means of setting precision.

Occurrences during execution

There are various things that can pause the model before the execution period set in the run control is complete. Some will always stop it, such as a 'stop()' function executing with a nonzero argument, or a discontinuity when adaptive step size variation is in operation. Others, such as compartment under/overruns, can be set to have that effect in the run control. In any case, a message is displayed in the log tab in the run control; selecting 'dialogue interactions' here causes a more prominent dialogue box to appear as well, requiring an 'OK' before the model can be restarted.

In: Contents >> Working with model diagrams >> Preferences

Working with equations

Working with equations

Equations are the mathematical basis for simulating the behaviour of a model. All node-type elements with the exception of file parameters, and all flows and squirts, must have equations for the model to run.

Before its equation is entered, a model element is displayed in red. It is not possible to run the simulation whilst any model elements are still red. If you make a change to the model that causes a component's equation to become invalid, for instance deleting an influence going to that component, it will be displayed in red to indicate that its equation must be edited before the model can run. Simile has an equation language that allows great power and flexibility in specifying expressions, reading data from tables, or sketching semi-quantitative relationships by hand. 

How to enter equations

There are two ways to enter equations for calculating model element values. Either use:

In either case, a helpful error message will appear if you enter an equation that cannot be used by Simile.

How to write equations

The following topics provide detailed reference information on the parts that make up a complex expression, and on the mathematical functions available, both built-in and user-supplied. See:

When is the equation evaluated?

  • For compartments and population initializers (creation), the equation defines the initial value, and is applied when the model is first built, when it is reset, or when the submodel instance containing the compartment or population comes into existence (for instance, if it is itself in a population submodel).

  • For rule-based state variables, the 'On reset...' equation is evaluated whenever a compartment's would be. The other equations are evaluated when their corresponding events occur.

  • For events and squirts, the equation is only evaluated when they occur.

  • For other components, the equation defines their value at any time while the model is running.

Working with variables and data types

Further information on variables and data types useful in understanding Simile.

In: Contents

Working with equations : Equation bar

The equation bar

The equation bar offers a quick and simple way to enter equations for any elements on the model diagram.

  • Select the pointer tool
  • Click on the element whose equation you wish to edit.

The name of the element is placed on the left hand side of the equation bar.

  • Click on the equation bar edit box to enter a value or an expression for the element.
  • Click on the button, or hit return, to set the equation.
  • Click on the button if you make a mistake. It restores the previous entry.

Elements which are calculated from other elements, i.e. are at the end of one or more influence arrows, have the local names of those elements listed in a drop-down list under the button.

  • Click on any name listed in the drop-down box to enter it into the equation. The name is added at the position of the cursor in the equation text.

A selection of the most-commonly used functions are listed in a menu cascade under the button. The top level of this cascade also contains an entry labelled "Enum. type constants", for adding the names and members of any enumerated types defined in the hierarchy containing the selected component. This also allows access to the "boolean" unit type and its values.

  • Click on any function that appears in the menu cascade to enter it into the equation. The function is added at the position of the cursor in the equation text, and the cursor is moved to inside the parentheses after the function, so you can immediately add its arguments. One more useful thing: if you select part of the text in the equation bar before adding a function from the menus, the function is added with its parentheses around the selection, so the selection becomes the argument.

Auto-complete feature

Typing in the equation bar activates the auto-complete feature. If the first few characters typed match the start of any entry in the cascade menu described above, i.e., valid input parameters, function names or enumerated type names or members, the remaining text in the shortest of those possible matches will be inserted into the text and highlit. The cursor moves to the end of the highlit text. The modeller can then do one of the following:

  • Hit the left or right arrow, return or tab to keep the inserted text. If a function name has been completed, the text includes the pair of parentheses that will enclose its arguments, so hitting left-arrow will keep the completion and position the cursor within the parentheses ready to add the arguments.
  • Hit the up arrow; this will select alternative completions from the same initial characters.
  • Continue to type; the completion text will be ignored. Completions will continue to appear as long as the typed characters still match some menu entries.

Re-use previously entered equation

The entry field in the equation bar has a drop-down list containing equations previously entered in the current editing session. The list can be accessed by hitting down-arrow while editing the equation, or by clicking the down-arrow button to the right of the entry field. This is useful if you need to add similar equations for a lot of components (though you should think about using a single component in a multiple-instance submodel instead!) Also if you leave the equation bar and the equation produces an error message, you need to click on the component again to get back into the equation bar after which the equation you entered will be gone -- you can get it back from the drop-down list to edit it and fix the problem.

In: Contents >> Working with equations

Working with equations : Equation dialogue window

Equation dialogue window

The equation dialogue window is used to identify the data source used to calculate a value for a model element, as well as to set various other properties of the model element. The same dialogue window is used for all the node-type elements, e.g., compartments,flows andvariables, as well as the control symbols iterations and conditions, and the population symbols. For the state symbol, the dialogue appears a little differently because an equation must be entered for each trigger event that influences the state. (Note that three other model elements,submodels, influence arrows, androle arrows each have their own dialogue box).

To open the equation dialogue window:

  • Select the pointer tool
  • Doubleclick on the component whose equation you wish to edit.

Alternatively:

  • Right-click on the component to be edited
  • Select 'Properties...' from the context menu.

The equation dialogue window consists of a notebook with three tabs. The first of these, labelled 'Main', is initially topmost, and contains the following panels which help you create the equation for your component:

Functions:

This panel displays a tree diagram containing all Simile's built-in functions, plus any user-defined functions that have been added on your system. They are grouped into categories, and have popups giving a brief description of each function. Doubleclicking on a function name will insert the function into the equation at the cursor position, and leave the cursor between the parentheses ready for argument expressions to be entered there if needed. If you have selected part of the equation text, the function is added with the selected text inside its parentheses.

Parameters:

The parameters in an equation are the values of the components that are linked to its own component by influence arrows. The parameters panel will show all the names associated with the parameters that have been connected. These are usually the same as the names of the components they come from, but may be different to avoid duplication, or in the case where a role arrow is being used to select only certain values from the component.

You can double-click on the parameter names to insert them into your equation, or hover over them to display a popup showing the location of their source and any roles that have been used to select their values. The next tab includes a panel that allows you to change the local names of the parameters.

Keypad:

This panel contains an array of buttons which insert text into whichever entry field has the cursor. They include buttons for moving the cursor back and forth, deleting a character and deleting all the text.

The second to right button on the top row inserts customizable text. By default it is set to µ since this character might otherwise be hard to find (it represents the micro- prefix for units) but you can set it to other characters or strings using the entry under the Edit tab in the Preferences dialogue window. Another useful setting for this might be π, which is interpreted as its trigonometrical value, or e if you are entering a lot of numbers in scientific notation.

Data source:

These three radio buttons set the data source to one of the following options:

  1. Variable parameter/Time series event: the value for the model element is set from the equation when the model is built, and can be changed during the simulation. The value can be set using a scenario file, and displayed and set through a user-operated slider control. This option is only relevant if the model element is at the beginning of a chain of influences. It cannot be used to alter the value of a model element that is calculated from the values of other model elements. The minimum and maximum values that the parameter can accept must be entered in the neighbouring text boxes. For a full explanation see the help sections Variable parameters and Time series events, and for a full explanation of working with sliders, see the help section Sliders.

  1. Fixed parameter: the value for the model element is set when the model is built and does not change. The value can be set using a scenario file. This option is only relevant if the model element is at the beginning of a chain of influences. It cannot be used to alter the value of a model element that is calculated from the values of other model elements. An equation can be entered, but it is only used for setting the array dimensions of the parameter. i.e., its value is never used. For a full explanation of working with fixed parameters, see the help section on Fixed parameters an for a full explanation of working with scenario files, see the help section Working with external data. Not available for events.

  2. Limit event: This option is only available for events. If it is chosen, the equation is not the value of the event but is used to determine when the event occurs, by detecting when its value reaches one of the supplied bounds.

  1. Equation: the value for the model element is calculated using the expression given in the text box. The expression is first evaluated when the model is built, and subsequently re-evaluated at each time step. For a full explanation of equations, see the help section Components of an equation. In brief, equations consist of functions operating on the values of the other model elements that influence this one. A list of functions is provided. Double-click on any of the function names to insert it into the equation text box. A list of the indices of the model element is also given. One index is listed for each level of nesting of the submodel(s) containing the model element. Double-click on any of the index names to insert the corresponding index() function into the equation text. Finally, a list of the other model elements (if any) that influence this one is presented. Double-click on any of the model element names to insert the name into the equation text.

Explicitly defined functons:

An equation can include one sketch graph or table function, which can be used exactly like any other function. These require extra data to be supplied, so they are added by clicking on buttons. If you just type graph() or table() into your equation, you will get an error message complaining that no data has been supplied to specify the behaviour of the function.

  • Graph: This button enables the user to sketch a graph for a mathematical relationship. The relationship is sketched in a window opened up by clicking on this button. Having done this, a reference to a function graph() is automatically added to the expression in the Equation box. This function is evaluated at run time by referring to the graph sketched by the model developer. See the help entry for the graph function for more information.

  • Table: This button enables a user to specify a tabulated relationship. The tabulated values are held in a data file, and clicking on this button enables you to browse through your file system for the data file, which can be in a variety of formats, and then choose the particular column of data you require from this file. Having done this, a reference to a function table() is automatically added to the expression in the Equation box. The function is evaluated at run time by doing a table look-up on the values provided. See the help entry for the table function for more information.

The data source panel also contains entry fields for minimum and maximum values and for units. Min/max values have various uses in simulation but do not actually constrain the value of the component. They set the scaling of display tools to fit the likely values that will be taken by the model components. Since the I/O tools have access to these values it would be possible to create an I/O tool that would display a warning if a value goes outside its minimum/maximum range. Minimum and maximum must be entered for variable parameters in order to set the range of values for their slider controls when the model runs. For compartments, the model execution can be set up to produce a message if the compartment's value goes outside the specified minimum or maximum. For limit events, they set the values which the equation must reach to trigger an occurrence.

The units entry field can usually be ignored, because a default units value will be generated from the equation and inserted there automatically. It only needs editing if you want a non-default unit (e.g., a real value for an integer constant) or if you want to specify the physical units of a quantity, such as metres per second.

The panel also shows the current array dimensions of the model element. The dimensions depend on the equation and the dimensions of any parameters, so they are not editable. For instance the result of sum() will have one less dimension than its argument, while the result of makearray() will have one more. 

The following panels are to be found on the second tab, "Parameters, etc..."

Indices:

If your component is inside a multiple instance submodel you can use the index(n) function to get the identity of the submodel instance currently being evaluated. However if you are inside many such submodels, multidimensional submodels, or particularly association submodels where you can also use index(n) to get the indices of the current base model instances, it can be confusing working out which nesting level you want. So this panel contains a list of all the available index arguments with popups explaining which index each one gives. Again, doubleclicking them inserts them into the equation text.

Influences

If the component has influence arrows connected to it from other components in the diagram, these will be listed in the Influences panel, along with their units and array dimensions if any. Doubleclicking on an influence's name will insert it into the equation text at the cursor position.

Hover the mouse over the local name of a model element listed in the influences list box to see the full path name of the model element. The local name is automatically composed from the full path name by replacing characters that have other meanings in equations (such as spaces, parentheses and carriage returns) with underscores. If you would prefer to use a different local name to refer to the full path name, the local name can be edited. Click on the name in the list box to edit it. The name you enter will only be used in this equation, which must use this name.

In the case where role arrows are used to select only a certain set of values from a component in another submodel, the default local name will also include the apropriate role arrow's caption. For the case of two role arrows between the same pair of submodels, influences between the submodels will get two local names each, one for the values associated with each role.

The local name will be enclosed in square or curly brackets if it refers to an array or list (see below), with nested brackets for nested sructures. These make the equation more readable, and you must keep them when editing the local name.

The 'units' field can also be edited, to set the units that will be used to convert the physical quantity of the incoming parameter into a number which will be used in the equation. See the section working with physical units for a full explanation of how this field is used.

The 'dimensions' field cannot be edited. This tells you the array dimensions of the value that this parameter supplies. Normally this will be the dimensions of the source component itself multiplied by those of any submodels the influence comes out of, though special rules apply for population symbols (creation and immigration behave as if outside their submodels) and those taking part in roles (normally you get a list, but going backwards along an 'exclusive' role you get a single value).

Documentation

Documentation appears on a separate tab in the dialogue box. You can enter a short title for the component and/or a longer description. For components with complex equations you can also put comments directly into the equation text by enclosing them in /* ... */ symbols.

 

In: Contents >> Working with equations

Working with equations : Understanding error messages

Working with equations : Understanding error messages

Don't panic!

If you try to set an equation for a component that Simile would not be able to use to generate a value, an error message will appear in a dialogue, something like this:

The message is generated by Simile in an attempt to help you find out what is wrong with the equation and how to put it right.

Syntax errors

There are two basic kinds of error messages. The first is the 'syntax error', an example of which is shown above. This is produced when the equation does not conform to the syntax, or grammar, of the equation language. Often the problem is the result of a typo, but it can also occur when the modeller uses a different idiom for writing an equation than the one Simile understands. For instance, in the above equation, the modeller has written '2.5x' to mean 'multiply x by 2.5', whereas Simile does not recognize this notation -- you need to include a multiplication symbol, as in '2.5*x'.

Simile uses the parser built into its Prolog engine to decode equations, but this takes a slightly different syntax than Simile's equation language, so the text is preprocessed first to make it compatible. In this case, single-quotes have been inserted around the variable names 'x' and 'y'. The parser reports the position at which it found the problem, and the error message shows the preprocessed text with <HERE> inserted at that position. It is usually clear from this what the problem was in the original equation.

Note that only the first syntax error is picked up -- the parser gives up after finding one. So just changing '2.5x' to '2.5*x' in this example will result in another syntax error, because '4y' also needs to be changed to '4*y'.

Context errors

These are raised if the grammatical structure of the equation makes sense, but there are components that do not correspond to values, operators or functions in Simile, or functions are being used in a type of component in which they make no sense. Each kind of error has its own message, and the explanation should be sufficient to pinpoint the problem.

If you got the error message after clicking 'OK' in the equation dialogue, or hitting Newline or clicking 'tick' in the equation bar, then after you dismiss the message you will be back editing the equation, and you can try to fix the problem. If you get it after leaving the equation bar, you will have to click on the component again and use the pull-down menu to get the equation back into the bar before editing it.

The error message also has a 'More info...' button, although all the info is in fact displayed in the original message. The 'More info...' dialogue does have selectable text that can be copied and pasted for reporting, and a 'Help' button that brings you to this page.

 

 

Working with equations : Components of an equation

Components of an equation

Expressions can consist of one or more of these components: numerical constants, symbolic names, mathematical operators, functions, and conditional expressions.

Numerical constants

Numerical constants are any numeric values, consisting of the digits 0-9, with an optional decimal point and a leading minus sign (for negative values). A leading 0 is optional for numbers less than 1.0. Standard scientific notation is provided (e.g. 0.12345E3 for 123.45), or you can enter very small or very large numbers by multiplying a value by 10 raised to a power, e.g. 0.12345*10^11 or 0.12345*10^-11. See also the section on Arrays and lists for details of how to enter arrays of numerical constants.

Enumerated Type constants
 

Symbolic names

A symbolic name represents the value of one of the variables, compartments or flows that influences the element in question. Each time the value of the expression is calculated, the current value of the influencing element is used.

The only symbolic names for model quantities that you can enter into an expression are those that influence the element in question. These are listed by clicking on the  pull-down menu button on the equation bar, and in the "Parameter" column of the main tab of the equation dialogue box. These must be entered exactly as shown, using the same punctuation (note especially the _ underscore symbols), and using the same case. The easiest way to do this is to select them from the pull-down menu, or to double-click on the name in the "Parameter" column.

Note that the symbolic name entered into the expression is the local name. This can be different from the name displayed on the model diagram, either to make the expression easier to read, or to avoid using certain illegal characters. Local names will also be modified when values come from a multi-instance submodel.
 

Mathematical operators

You can use the following mathematical operators:

+

 

e.g. 15+7 (evaluates to 22)

-

 

e.g. 15-7 (evaluates to 8)

*

 

e.g. 15*7 (evaluates to 105)

/

 

e.g. 15/7 (evaluates to 2.1428…)

//

integer division

e.g. 15//7 (evaluates to 2)

%

integer modulo

e.g. 94%22 (evaluates to 6)

^

raise to a power

e.g. 15^2 (evaluates to 225)

Functions

Simile provides a large number of functions that you can use in expressions already built-in, and the facility to extend this list.

Conditional expressions

Equations can include conditional expressions. These enable a complex expression to be constructed from a number of sub-expressions, with the conditional elements being used to select between one expression or another. Standard Boolean operators are available for constructing conditional expressions.

Intermediate variables

The equation dialogue box can be used to enter one or more assignments, before the expression that returns the element's value. These intermediate variables can be used to simplify complex expressions.

In: Contents >> Working with equations

Working with equations : Boolean expressions

Boolean expressions

Boolean expressions return only "true" or "false". Boolean expressions are commonly used in conditional expressions to decide between two or more alternative subexpressions, but a Simile variable can have a boolean value if its whole equation is a boolean expression; indeed, condition and alarm components have to have boolean values.

Constants

The expressions "true" and "false" may be used as Boolean constants in expressions. Note that quotation marks must be used around the words. This is because these constants are implemented as built-in enumerated types.

Mathematical comparisons

A simple condition consists of a direct comparison between two values, using the relational operators

>

greater than

X > Y

X is greater than Y

<

less than

X < Y

X is less than Y

>=

greater than or equal to

X >= Y

X is greater than or equal to Y

<=

less than or equal to

X <= Y

X is less than or equal to Y

==

equal to

X == Y

X is equal to Y

!=

not equal to

X != Y

X is not equal to Y

Thus, the following are legal examples:

  • 5 > 3 though it's hard to see the point of this, since this is always true
  • height <= 30 where the variable "height" is an influencing variable

Each of the two terms, on the left and right of the comparison, can themselves be arbitrary mathematical expressions. Thus, the following are also legal:

  • 5 > 3*2 (result is false, since 5 < 6)
  • 0.1*height <= 30
  • k*z+2 < 17*h

Logical comparisons

Four Boolean operators can be used in expressions. There are "and", "or", "xor" and "not". The following table shows the two alternative forms of these operators, which can also written in symbolic form. Note also that a comma "," is accepted as an alternative symbol for "and".

     

A and B

A && B

true if and only if both A and B are true

A or B

A ; B

true if either A is true or B is true

A xor B

A != B

true if either A is true or B is true, but not both

not A

! A

true if and only if A is not true

The truth tables for the four operators are given here. Note that "and", "or" and "xor" require two operands, whilst "not" requires one operand. The equation parser will signal an error if an incorrect number of operands is used.

Functions

Some functions return boolean values, i.e., any(), all(), channel_is(), dies_of(), and first().

In: Contents >> Working with equations >> Components of an equation

Working with equations : Conditional expressions

Conditional expressions

Simple equations, like Y = 5+7*X, provide a single, continuously-varying method for calculating a value for an element from the value(s) for one or more other elements. Often, however, the expression we want to use for calculating the result depends on the values of one or more aspects of the system. This means that we need a way, in a single equation, for choosing between alternative expressions. Conditional expressions provide a means for doing this.

In general terms, a simple equation has the form:

Y = expression.

A conditional equation has the form:

Y = if condition1 then expression1 else expression2

Y = if condition1 then expression1 elseif condition2 then expression2 elseif condition3 then expression3 ...... else expressionx

where:

  • expression is any legal Simile mathematical expression, including numeric constants, variables, mathematical operators and functions - and indeed further conditional expressions (i.e. conditional expressions can be nested).   When you nest condironal expressions, the nested if...then...else... must be enclosed in round brackets.   E.g. if a>5 then (if b<3 then 5 else 4) else 0 

  • condition is a Boolean expression constructed using Boolean operators or relational operators.

Note that while some programming languages, such as C and Fortran, allow you to use a numerical value of 1 or 0 to represent "true" or "false" in a conditional expression, Simile does not allow this. We feel that this practice makes the equations less readable. Instead, you can convert the number n into a boolean, using the expression "n !=0 ".

In: Contents >> Working with equations >> Components of an equation

Working with equations : Intermediate variables

Intermediate variables

Motivation

In a procedural programming language, a complicated calculation may be broken down into several steps each carried out by a separate instruction. This may be done when an intermediate result is subsequently required more than once to save calculating it each time, or just to make the program more readable. 

In Simile, a similar result could easily be achieved by having a chain of variables linked by influences, where each except the first and last represents an intermediate value. However this could make the diagram more confusing than it need be.

Alternatively you can define and then use intermediate results in the equation. They are assigned with a single '=' sign and the assignment is separated from the rest of the equation with a comma, like this:

a = f(input1,...), b = g(a, input1...), result = h(a, b, input1...)

Local variable assignments can be made before an expression, separated from the expression by a comma.  The expression returning the value of the element must come at the end.  The local variables can be used in the expression, often to simplify it.

Example

In the following example, the local variable q is assigned a value, then the main expression follows after a comma, with q being used to simplify what would otherwise be an extremely complex expression:

q=(Topt-Tmin)/(Tmax-Topt),

if ((T>Tmin)&&(T<Tmax)) then

   (((T-Tmin)^q) * (Tmax-T)) / (((Topt-Tmin)^q) * (Tmax-Topt))

else

   0

 

There are four parameters influencing this expression, T, Topt, Tmin, and Tmax, through influence arrows in the normal way.  The assignment of a value to q is a purely local affair.

Note that the assignment of the local variable uses a single = sign. This is not to be confused with the double == of an equality test.

In: Contents >> Working with equations >> Components of an equation

 

Working with equations : Functions

Functions

Simile provides a large number of built-in functions that can be used in mathematical expressions. These include standard mathematical functions, such as log(…) as well as functions specific to Simile.

Some functions have one or more arguments (in brackets, after the function name). Others, such as the time() function, which returns the current simulation time, do not. You must still write the brackets after the function name, even if there are no arguments. This indicates that the name is a function name.

For most functions, the arguments are scalar values, i.e. a single quantitative value. In some cases, an argument is expected to be some other type of data structure, such as a Boolean value (true or false), or an array or list (such as the sum(…) function, which returns the sum of the values in an array or list.

 

It is possible to include user-defined functions. These can be specific to modelling in a restricted domain (such as plant physiology), so it will be possible for researchers in a particular community to build up and share common libraries of functions. 

Two special functions are graph(…) and table(…), which relate to a graphically-represented and a tabulated relationship respectively. These can be included in an expression like any other function, but differ from other functions in that the result they return for a given input value can be different in each equation in which it is used: it's definition is local to the equation, rather than being universally defined (like the log(…) function, for example).

In: Contents >> Working with equations >> Components of an equation

Working with equations : Built-in functions

Built-in functions

Alphabetical list of most commonly used functions,  Trigonometric functions are listed separately. Please see the other categories at the bottom of the page for less common or recently added functions.

 Template  Effect

Input(s)

Return

value

abs(X)

Returns the absolute value of X

   

all([X])

all{X})

Result is true if all the elements of the array [X] or the list {X} are true

boolean array/list

 Boolean

any([X])

any({X})

Result is true if any of the elements of the array [X] or the list {X} are true.

boolean array or list

 Boolean
at_init(X) Returns X's value when last initialized or reset Any Same as input

at_posn(C)

at_posn(C, X, Y)

Causes component to get value from instance of C in a grid submodel Any, two optional integers Scalar as 1st argument
binome(P, N) Returns a value from the binomial distribution with probability P and number of trials N

Real value from 0 to 1,                  Integer value

Integer value

ceil(X)

Rounds up X to the next whole number

   

channel_is(X)

X is an immigration, reproduction or creation channel. Returns true if this individual appeared through that channel.

   
colin([X]) Returns an index to the given array, with probabilities proportional to the array's values Array of numeric values Integer or enumerated type member
const_delay(X, T) Returns the value of X as it was T time units earlier in the run, or 0 or "false" if the component did not exist at that time Any non-array type, numeric constant As 1st argument

count([X])

Number of values in the array [X] or the list {X}

scalar array/list

 

delay1(x,t), delay3(x,t), delayn(x,t,n)

Insert a material delay of order 1, 3 or n

numerical

numerical, numerical, integer (delayn only)
dies_of(X) X is a loss channel. True if channel specifies the removal of the individual this time step. from loss channel Boolean

dt(I)

Returns the duration of the time step level I

   

element([X],I)

Picks the I'th value form the array [X]

array of any type,integer or enumerated type member

 

exp(X)

Returns e to the power X

   

exprnd(mean [, seed])

Samples an exponential distribution

numerical[, integer] numerical
first(T) Returns "true" if argument is the first member of its enumerated type Enumerated type member Boolean
firsttrue([B]) Takes an array of booleans and returns the index of the first with value "true" Array of booleans Integer or enumerated type member

floor(X)

Rounds X down to a whole number

   

fmod(X,Y)

Returns remainder after dividing X by Y

numeric, numeric

 
following(T) Returns next member of argument's enumerated type Enumerated type member Enumerated type member
forcst(input, time, horizon [, initial]) New in v6.6: Performs simple trend extrapolation Real, real, real [,real] Real
gaussian_var(X,Y) Returns a sample from a Gauusian distribution with mean X and SD Y Real, real real

greatest([X])

greatest({X})

Returns the largest value from an array [X] or the list {X}

numeric array/list

 
howmanytrue([B]) Takes an array of booleans and returns the number that are true List or array of booleans Integer
hypergeom(P, M, S) Returns a deviate from a hypergeometric distribution for population, P, number of marks M, and sample size S. integer, integer, integer integer

hypot(X,Y)

Returns length of hypotenuse of triangle with base X and height Y

numeric, numeric

 

index(I)

Returns the index (instance number) of a member of a fixed membership or population submodel, for the level I of submodel nesting.

 Integer Integer or enumerated type member

inf()

New in v6.6: Returns the value of positive infinity.

 Real None

init_time(1)

Returns the time at which this instance appeared -- argument is dummy

   
in_preceding(X) New in Simile v5.7: Returns value of X in preceding submodel instance Any scalar or array type As argument
in_progenitor(X) New in Simile v5.8: Returns value of X in submodel instance that reproduced to make current one Any scalar or array type As argument

int(X)

Returns integer part of X

   
interpolate(X, [Xarray], [Yarray]) Returns interpolated value from [Yarray] corresponding to X's place in Xarray

Numeric, Array of numeric, Array of numeric

Numeric
iterations(B) Counts executions of iterative submodel Boolean Integer

last(X)

Recalls value of X from previous time step

   

least([X])

least({X})

Returns the smallest value from an array [X] or the list {X}

numeric array/list

 

log(X)

Returns natural logarithm of X

   

log10(X)

Returns base-10 logarithm of X

   

makearray(X,N)

Makes an array consisting of N lots of X

any type, integer

array of same type

max(X,Y)

Returns greater of X and Y

numeric, numeric

 

min(X,Y)

Returns lesser of X and Y

numeric, numeric

 
order([X]) Returns an array holding the indices of the argument array in ascending order of their values array of numeric array of integer

parent(I)

Returns the id of the individual whose reproduction gave rise to this one, or 0 if it immigrated or was created

   

place_in(I)

When making an array with makearray, this gives each term's position in the array -- argument is nesting depth

   
poidev(X) Returns a value from the Poisson distribution with the given mean numeric integer
posgreatest([X]) Returns the index of the highest value in the argument array Array of numeric values Integer or enumerated type member
posleast([X]) Returns the index of the lowest value in the argument array Array of numeric values Integer or enumerated type member

pow(X,Y)

Returns X raised to the power Y

numeric, numeric

 numeric
preceding(T) Returns previous member of argument's enumerated type Enumerated type member Enumerated type member

prev(N)

Returns the value of this component N time steps ago

   

product([X])

product({X})

Result is the product of all elements of the array [X] or the list {X}

numeric array/list

numeric

pulse(H, T [, I])

Generates a single time step pulse of magnitude M at time T, and before or after at intervals of I if I present

numeric, numeric, numeric

numeric

ramp(T,S)

Generate a linearly increasing or decreasing value over time with the given slope

numeric, numeric

numeric

rand_const(X,Y)

(Deprecated) Returns a random number between X and Y, which stays the same until the simulation is reset.

numeric, numeric

 

rand_var(X,Y)

Returns a random number between X and Y, with a new value every time step.

numeric, numeric

 
rankings([X]) Returns ranking of each element in order of size Array of numerics Array of integers

round(X)

Rounds X up or down to the nearest whole number

   
sgn(X) Returns the size of X; -1 if negative, 1 otherwise    

size(S)

Takes the name of a fixed-membership submodel and returns the number of instances that it has.

   

size(S,I)

Takes the name of a fixed-membership submodel and returns the size of one of its dimensions

submodel, numeric

 

smth1(x,a), smth3(x,a), smthn(x,a,n)

Insert a material smoothing of order 1, 3 or n

numerical

numerical, numerical, integer (smthn only)

sqrt(X)

Returns the square root of X

   

step(H, T)

Generate a step increase (or decrease) at the given time

numeric, numeric numeric

stop(X)

Stops the simulation, displaying value of X in a popup message

   
subtotals([X])

Returns running totals from summing the elements in the supplied array

Numeric array Numeric array

sum([X])

Result is the sum of all elements of the argument

numeric array/list

 

time()

Returns the current simulation time (the argument is ignored)

   
trigger_magnitude() Returns value of triggering event    As triggering event
var_delay(X,T) Returns value of X as it was T time units earlier in run, or 0 or "false" if this is before component existed Any non-array type, numeric expression As first argument

with_colin({N},{X})

Returns a value from the list {X} with probabilities proportional to the corresponding values in the list {N}

numeric list,       any list

member of second arg

with_greatest([N],[X])

with_greatest({N},{X})

Returns the value from an array [X] or the list {X} whose position in the array or list corresponds to the largest value in the array [N] or list {N}

numeric array/list, any array/list

 

with_least([N],[X])

with_least({N},{X})

Returns the value from an array [X] or the list {X} whose position in the array or list corresponds to the smallest value in the array [N] or list {N}

numeric array/list, any array/list

 

In addition, a full range of trigonometric functions are provided.

In: Contents >> Working with equations >> Functions

Built-in functions : Arithmetic functions

Arithmetic functions

Built-in functions : abs function



abs function

abs(X)

Returns the absolute value of X - i.e. ignores its sign

Input: numeric scalar or numeric array

Result: numeric scalar or array

Examples:

abs(3) --> 3

abs(-3) --> 3

abs([2,-3,4,-5]) --> [2,3,4,5]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : pow function



pow function

pow(X,Y)

Returns X raised to the power Y

Input: numeric, numeric

Result: numeric

Comment:

This is equivalent to the use of the ^ operator: i.e.

pow(5,2)

is the same as

5^2

The latter should be used of preference, as it is the more familiar notation.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : min function



min function

min(X,Y)

Returns lesser of X and Y; i.e. it returns X if X<=Y, otherwise it returns Y.

Inputs: numeric, numeric

Result: numeric

Comments:

The min function is a useful way of ensuring that some value does not go above some threshold. For example, if b increase as a increases, but does not exceed 20, then the equation for b could be:

b = min(20, 0.2*a)

This avoids the use of a cumbersome if…then… else… construction

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : max function



max function

max(X,Y)

Returns greater of X and Y; i.e. it returns X if X>=Y, otherwise it returns Y.

Inputs: numeric, numeric

Result: numeric

Comments:

The max function is a useful way of ensuring that some value does not go below some threshold. For example, if b declines as a increases, but does not go below zero, then the equation for b could be:

b = max(0,10-0.2*a)

This avoids the use of a cumbersome if...then...else... construction.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : inf function

inf function

New in v6.6

inf()

Returns the value of positive infinity

Input: none

Result: numeric

Built-in functions : sgn function

sgn function

sgn(X)

Returns -1 if X is negative, or 1 if X is zero or positive

Input: numeric, or array of numeric values

Result: integer, or array of integer values

Examples:

sgn(1.9) --> 1

sgn(-1.1) --> -1

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : sqrt function



sqrt function

sqrt(X)

Returns the square root of X

Input: numeric

Result: numeric

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : round function



round function

round(X)

Rounds X up or down to the nearest whole number

Input: numeric, or array of numeric values

Result: numeric, or array of numeric value

Examples:

round(1.9) --> 2

round(1.1) --> 1

round([1,2.1,3.9]) --> [1,2,4]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : log10 function



log10 function

log10(X)

Returns base-10 logarithm of X

Input: numeric

Result: numeric

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : log function



log function

log(X)

Returns natural logarithm of X

Input: numeric; or an array of numeric values

Result: numeric; or an array of numeric values

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : ceil function



ceil function

ceil(X)

Rounds up X to the next whole number (stands for 'ceiling')

Input: numeric, or array of numeric values

Result: numeric, or array of numeric value

Examples:

ceil(1.9) --> 2

ceil(1.1) --> 2

ceil([1,2.1,3.9]) --> [1,3,4]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : exp function



exp function

exp(X)

Returns e (the base of natural logarithms) to the power X

Input: numeric, or an array of numeric values

Result: numeric, or an array of numeric values

Example:

The exponential growth of a population is given by the formula

Nt = N0er.t

where:

Nt is the population size at time t,

N0 is the initial population size,

e is the base of natural logarithms,

r is the intrinsic growth rate, and

t is current time
 

We can represent this in Simile using a single variable (called N), with its equation being

N = 10*exp(0.1*time(1))

assuming that the initial population size = 10 and the value of r is 0.1.
 

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : floor function

floor function

floor(X)

Rounds X down to a whole number.

Input: numeric, or an array of numeric values

Result: numeric, or an array of numeric values

Examples:

floor(3.1) --> 3

floor(3.99) --> 3

floor([1.1,2.4,3.7,4.9]) --> [1,2,3,4]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : int function



int function

int(X)

Returns integer part of X

Input: numeric

Result: numeric

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : hypot function



hypot function

hypot(X,Y)

Returns length of hypotenuse of right-angle triangle with base X and height Y

Inputs: numeric, numeric

Result: numeric

Examples:

hypot(3,4) --> 5 (a 3:4:5 triangle)

hypot(x1-x2,y1-y2) --> the distance between two points with co-ordinates (x1,y1) and (x2,y2) respectively.

hypot(x-[xs],y-[ys]) --> [distances] I.e. an array containing the distance from one point with co-ordinates (x,y) to a set of points, with co-ordinates held in the arrays [xs] and [ys]. See comments.

Spatial modelling frequently requires that one object knows the distance to another. This requires that each has x,y co-ordinates. It is then simple to use the hypot function to work out the straight-line distance between them, as shown in the second example above.

The same principle applies when you use a multiple-instance submodel to represent a set of spatially-located objects. In this case, each object may want to know how far it is to all the other objects - for example, in working out the competition between trees in an individual-based tree model. The following model diagram fragment shows a typical model configuration for doing this:

Each tree has x,y co-ordinates. These are exported to two array variables, xs and ys, whose equations are simply:

xs = [x]

and

ys = [ys]

These arrays are then brought back into the submodel, and used to generate an array containing the distance for each tree to all the other trees, using the equation given in the third example above.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : fmod function



fmod(X,Y)

Returns remainder after dividing X by Y

Inputs: numeric, numeric

Result: numeric

Examples:

fmod(7,3) --> 0.333 (7/2 = 2.333, i.e. the remainder is 0.333)

fmod(time(1),1) --> a result that climbs from 0 to 1 repeatedly (i.e. a sawtooth pattern) as the simulation proceeds. See comments below.

fmod((index(1)-1),5)+1 --> 1,2,3,4,5,1,2,3,4,5,1,2,3... for successive values of index(1). See comments below.

This apparently obscure function in fact has (at least) two very valuable uses.

First, it can be used to generate regular cycles, in particular annual or daily cycles. Consider the case or a model with the time unit being one year, and a time step of less than a year. You want various exogenous variables (such as temperature or rainfall) to vary in a prescribed fashion during the course of each year, with the annual pattern repeating itself from one year to the next. The following diagram is typical of the model fragment you could use for representing this:

The variable time is simply set equal to current simulation time, using the function time(1). The variable season is set to rise from 0 to 1 every year. If your model used a time unit of one week, then the equation would be changed to

season = fmod(time,52)

and the value for season would then correspond to week number. The equations for rainfall and temperature are for illustration purposes only: you would need to replace them by something appropriate.

Second, the fmod function can be used to generate a regular spatial arrangement (rows and columns) for a 2D grid. Let's say that you are modelling an area of 10x10 grid squares. In Simile, you would set up a submodel, called perhaps Patch, with 25 instances. In order to give each patch location on a grid, each one needs to have a row and column attributes, with each patch having a unique combination of the numbers 1..5 for row and column. The only thing we know about each patch is that it has an index number (given by the built-in function index(1)), a value ranging between 1 and 25. The trick is to get row number to be, in sequence,

1,1,1,1,1,2,2,2,2,2,3,3,3...

and column number to be, in sequence,

1,2,3,4,5,1,2,3,4,5,1,2,3...

thus giving each of the 25 instances a unique row-and-column pair.

This is readily done using the following two equations:

row = floor((index(1)-1)/5)+1

column = fmod((index(1)-1),5)+1

See the floor function to understand why the row numbers should be in the first sequence above. For column, we divide the index number for each instance by 5, taking the remainder: the '-1' and +1' are there to ensure that we get the results in the blocks of five that we require. See a grid-based spatial model example to see this in action.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : Trigonometric functions

Trigonometric functions

   

Input(s)

 

acos(X)

Returns the arccos (inverse cosine) of X. Result is in radians.

   

asin(X)

Returns the arcsine of X. Result is in radians.

   

atan(X)

Returns a value in radians (range -pi/2 to pi/2), being the arctangent of X (the ratio of two sides of a right triangle). Same as arctan(X).

   

atan2(X,Y)

Returns the arctangent of X. Result is in radians.

numeric,numeric

 

cos(X)

Returns the cosine of X (an angle in radians)

   

cosh(X)

Hyperbolic cosine of X.

   

hypot(X,Y)

Returns length of hypotenuse of triangle with base X and height Y

numeric, numeric

 

sin(X)

Returns the sine of the argument (an angle in radians)

   

sinh(X)

Hyperbolic sine of X.

   

tan(X)

Returns the tan of the argument (an angle in radians)

   

tanh(X)

Hyperbolic tangent of X.

   

In: Contents >> Working with equations >> Functions

 

Built-in functions : List handling

List handling

Built-in functions : product function



product function

product([X])

product({X})

Result is the product of all elements of the array [X] or the list {X}

Input: numeric array or list

Result: numeric

Example:

product([2,3,4]) --> 24

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : place_in function



place_in function

place_in(I)

When making an array with the makearray function, place_in() returns the current position in the array. If makearray() functions are nested one inside another, the argument to the place_in() function will determine which position is returned. An argument of 1 refers to the innermost makearray().

Input: integer

Result: integer

Examples:

makearray(if place_in(1)==1 then 10 else 5, 4) --> [10, 5, 5, 5]

makearray(if place_in(1)==2 then 10 else 5, 4) --> [5, 10, 5, 5]

makearray(makearray(if place_in(2)==1 then 10 else 5, 4), 2) --> [[10, 10, 10, 10], [5, 5, 5, 5]]

makearray(makearray(if place_in(1)==1 then 10 else 5, 4), 2) --> [[10, 5, 5, 5], [10, 5, 5, 5]]

makearray(4*place_in(1),12) --> [4 8 12 16 20 24 28 32 36 40 44 48]

makearray(makearray(place_in(1)*place_in(2),12),12) -->

[[1 2 3 4 5 6 7 8 9 10 11 12],

[2 4 6 8 10 12 14 16 18 20 22 24],

[3 6 9 12 15 18 21 24 27 30 33 36],

[4 8 12 16 20 24 28 32 36 40 44 48],

[5 10 15 20 25 30 35 40 45 50 55 60],

[6 12 18 24 30 36 42 48 54 60 66 72],

[7 14 21 28 35 42 49 56 63 70 77 84],

[8 16 24 32 40 48 56 64 72 80 88 96],

[9 18 27 36 45 54 63 72 81 90 99 108],

[10 20 30 40 50 60 70 80 90 100 110 120,

[11 22 33 44 55 66 77 88 99 110 121 132],

[12 24 36 48 60 72 84 96 108 120 132 144]]

Comments:

This function is only meaningful inside makearray() function. If used elsewhere, the equation parser will signal an error.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : makearray function

makearray function

makearray(X,N)

Makes an array consisting of N lots of X

Input: any type, numeric

Result: array of same type

Examples:

makearray(7, 3) --> [7, 7, 7]

makearray([rand_var(0, 1), rand_var(0, 5)], 5) --> [[0.62352, 2.43459], [0.11933, 0.423529], [0.94208, 4.43623], [0.40088, 1.63023], [0.11769, 4.97782]]

Comments:

This is an array constructor. The first argument can be any expression, and the second is an integer. The result is an array, each of whose elements is generated by evaluating the first argument. The size of the array is the value of the second argument, which must be a constant. If the first argument is an array, the result will be an array of arrays. See also the place_in function, which is used in complex constructions with makearray.

Use of makearray() is called explicit replication. It differs from implicit replication in that the expression being replicated is evaluated separately for each member of the generated array, including any implicit (but not explicit) intermediate results. This means that no attempt is made to combine the dimensions of the two arguments. The second argument must be a scalar integer, and the result will be an array whose outermost dimension is that value, and whose inner dimensions are the dimensions of the first argument.

makearray() could have been designed to work differently on an array first argument, replicating each element rather than the whole array. As in the case of implicit replication, the actual behaviour was chosen to be that which would be hardest to achieve by combining other functions. If you need to replicate the elements of an array, you can first split it up with the element() function then rejoin the results with makearray, e.g., makearray(makearray(element([3,6,9],place_in(2)),2),3) -> [[3,3],[6,6],[9,9]], whereas if makearray itself worked like this, it would be very hard to get its actual behaviour.

See also: place_in  function

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : with_greatest function


with_greatest function

with_greatest([N], [X])

with_greatest({N}, {X})

Returns the value from an array [X] or the list {X} whose position in the array or list corresponds to the largest value in the array [N] or list {N}.

Inputs: numeric array or list, same dimensioned array or list with members of any type

Result: single value from second input

Example:

with_greatest([2,5,7,3], ["red", "blue", "green", "yellow"]) --> "green"

This example would require the definition of an enumerated type with the members "red", "blue", "green" and "yellow".

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : sum function

sum function

sum([X])

sum({X})

Result is the sum of all elements of the array [X] or the list {X}

Input: numeric array/list

Result: numeric

Example:

sum([2,3,4]) --> 9

sum([[1,2],[3,4]]) --> [4,6]

Comment:

Note the behaviour with nested arrays. A new array results, consisting of the sum of the first value of each array, the sum of the second value of each array, etc.

sum function

sum([X])

sum({X})

Result is the sum of all elements of the array [X] or the list {X}

Input: numeric array/list

Result: numeric

Example:

sum([2,3,4]) --> 9

sum([[1,2],[3,4]]) --> [4,6]

Comment:

Note the behaviour with nested arrays. A new array results, consisting of the sum of the first value of each array, the sum of the second value of each array, etc. The reason it is implemented this way is that the converse (generating an array of the sums of each sub-array in the original, i.e., [3,7] in the above example) is easier to generate explicitly if required. In the case where the 2-D array is a value coming out of nested 1-D submodels, it can be produced by putting the sum() function inside the outer submodel. If the array is only available as a 2-D value, the same effect can be produced using the element() and makearray() functions as follows:

makearray(sum(element([[1,2],[3,4]], place_in(1))),2) --> [3,7]

All other cumulative functions behave the same way regarding selection of elements from multidimensional arrays.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : order function

order function (new in v6.9)

Takes an array of numeric values and returns an array containing the indices of those values in ascending order.

Example:

order([1,9,2,10,3,8,5]) -> [1,3,5,7,6,2,4]

Note that the result of order() can be used to get the original values in ascending order by using it in the element function. e.g.,

mixed = [1,9,2,10,3,8,5]

sort = order(mixed)

element([mixed],[sort]) -> [1,2,3,5,8,9,10]

 

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: interpolate function

interpolate(X, [Xarray], [Yarray])

X is an input value.   The arrays Xarray and Yarray define a series of coordinates.   They must contain the same number of elements, and the values in Xarray must be in ascending order.   If the value of X is less than the first element of Xarray, then the result is the first element of Yarray.     If the value of X is greater than the last element of Xarray, then the result is the last element of Yarray.   Otherwise, the result is the value obtained by linear interpolation between the two points which bracket the value of X.

Examples:
   interpolate(3, [2,4,7], [10,20,30])  --> 15  (linear interpolation between the points (2,10) and (4,20))
   interpolate(1, [2,4,7], [10,20,30])  --> 10  (X value is less than first element of Xarray, so use first element of Yarray)
   interpolate(9, [2,4,7], [10,20,30])  --> 30  (X value is greater than first element of Xarray, so use last element of Yarray)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: rankings function

rankings function

Takes an array of numeric values, and returns an array with the ranks of the corresponding elements in the argument. This is 1 for the largest element, and equal to the size of the array for the smallest.

Example:

rankings([1,9,2,10,3,8,5]) -> [7,2,6,1,5,3,4]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: subtotals function

subtotals function

Takes an array of numeric values, and returns an array containing the running totals from summing the elements in the original array.

Example:

subtotals([1,9,2,10,3,8,5]) -> [1,10,12,22,25,33,38]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : element function

element function

element([X],I)

Picks the Ith value from the array [X]

Inputs: an array [X] of any type

integer I

Result: type

Examples:

element([10,20,30,40],3) --> 30 (since 30 is the value of the 3rd element of the array.

element([[1,2], [3,4], [5,6]],2) --> [3,4] (since the array [3,4] is the 2nd element of the input array)

element([10,20,30,40],index(1)) --> 10 for the first instance of a four-instance submodel, 20 for the second instance, etc, since index(1) has the value 1 for the first instance, 2 for the second instance, etc.

Comments:

This is an essential function for use with multiple-instance submodels, in which case it is almost always used in combination with the function index(1) in the second argument. One common use is to provide each instance of a multiple-instance submodel with a unique value for some parameter or other value. The third example (above) illustrates this: that could, for example, be the expression in a compartment element inside a four-instance submodel, initialising the compartment for each of the four instances to 10, 20, 30 and 40 respectively.

For advanced users:

The element function has rather more power than suggested above. The second argument can act as a sort of template to say how values (or sub-arrays) from the first argument are to be picked up. This is illustrated by the following example:

element([3,2,7,4,9,34,1,5], [[5,2], [1,5]]) --> [[9,2], [3,9]]

If the first argument is multidimensional and the second argument is a one-dimensional array, the elements of the second argument will be used to pick elements from the innermost arrays of the first argument from whuch to build the result, e.g.,

element([[3,5,11], [1,2,8]], [2,1,2]) --> [1,5,8].

The reason it works this way is that the converse behaviour, i.e., each element of the second argument selecting a value from the corresponding element of the first argument, is easy to get in the case where the first argument is a value from a nested submodel by putting the element() function inside the outer submodel, and can be obtained in general by building up from simple cases, e.g.,

makearray(element(element([[3,5,11], [1,2,8]],place_in(1)), element([3,1], place_in(1))), 2) --> [11,1].

makearray(element([[5,7],[1,4],[8,5]], element([3,3,2,2], place_in(1))), 4) --> [[8,5], [8,5], [1,4], [1,4]]

Use of element() on lists

Starting with Simile version 6.1, it is possible to have a list-valued expression as the first argument of element(), in which case the result is a sublist of that list, i.e., a list containing some, all or none of the members of the original list in the same order. The second argument can be a single value, in which case the resulting list has one element if the list includes a value with that index, and none otherwise. So applying sum() to it gives either a value from the original list or zero.

If the second argument is an array or list, the result is a sublist of the first argument containing all the values whose indices appear as values in the second argument. There are a few points to note about all these uses:

  • It is not computationally efficient. The values from the list are found by searching through it sequentially rather than by lookup as can be done on arrays.
  • If the second argument is an array or list, its values must be in ascending order, or in the order in which they appear in the definition if they are of an enumerated type. If a value occurs more than once in the second argument, the value with that index will still only appear once in the result. This is because rather than searching the list from the start for each value, the generated code merely starts from where the last one was found, since the indices in the original list should always be in ascending order. (This does not apply when selecting a sublist from a list of neighbour values in a special-purpose submodel; the direction identifiers can be in any order, and if one occurs more than once, its value from the original list will also be repeated).
  • The resulting list cannot itself be used as the first argument of element(), or arithmetically combined with other list-valued expressions.

element() with multiple indices

Starting with Simile version 6.1, if you have a 2-D (or higher) array, you can look up a single member by using element() with 3 (or more) arguments, e.g.,

element([[arr]], x, y)

Formerly you would have had to do this by nesting element() calls, but the new format is neater and allows the indices to be matching arrays or lists themselves to get multiple values.

Examples:


element([[6,1,8],[7,5,3],[2,9,4]], 2, 2) --> 5
element([[6,1,8],[7,5,3],[2,9,4]], [2,1,3], [3,1,2]) --> [3,6,9]

 

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : any function



any function

any(([X])

any({X})

Result is true if any of the elements of the array [X] or the list {X} are true.

Input: boolean array or list

Result: boolean

Examples:

any([false,false,false,true,false]) --> true

any([false,false,false]) --> false

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : all function



all function

all([X])

all({X})

Result is true if all the elements of the array [X] or the list {X} are true

Input: boolean array/list

Result: boolean

Examples:

all([true,true,true,false]) --> false

all([true,true,true,true]) --> true

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : least function


least function

least([X])

least({X})

Returns the smallest value from an array [X] or the list {X}

Inputs: numeric array/list

Result: numeric

Example:

least([2,5,7,3]) --> 2

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : greatest function



greatest function

greatest([X])

greatest({X})

Returns the largest value from an array [X] or the list {X}

Inputs: numeric array or list

Result: numeric

Example:

greatest([2,5,7,3]) --> 7

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : with_least function


with_least function

with_least([N], [X])

with_least({N}, {X})

Returns the value from an array [X] or the list {X} whose position in the array or list corresponds to the smallest value in the array [N] or list {N}.

Inputs: numeric array or list, same dimensioned array or list with members of any type

Result: single value from second input

Example:

with_least([2,5,7,3], ["red", "blue", "green", "yellow"]) --> "red"

This example would require the definition of an enumerated type with the members "red", "blue", "green" and "yellow".

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : Model properties

Model properties

Built-in functions : after function

after function

after(T, M)

Use only as whole equation of derived event. Instead of firing immediately when triggered, event is delayed by value of 1st argument, then fires with magnitude the 2nd argument had when triggered.

Inputs: Real, Any data type

Result: Same type as 2nd arg

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : last function

last function

last(X)

Recalls value of X, another element, from previous time step. X must influence this element in order to be used in the equation. See prev, for a function that returns a previous value from this element itself.

This function has been replaced with the const_delay( ) and var_delay( ) functions, which are more general in allowing the value of a variable to be returned from an arbitrary number of time steps before.

Input: numeric

Result: numeric

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : as_number function

as_number function

as_number(N)

Converts integral types to integer

Input: Boolean, enumerated type or integer (for flexibility)

Result: Value of argument as integer

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : prev function



prev function

prev(N)

Returns the value of this element itself, N time steps ago. See last, for a function that returns a previous value of any element other than this one itself.

Input: numeric

Result: numeric

Example:

Consider a variable that flips from state 1 to state 2 when some triggering condition is satisfied (the Boolean variable, trigger, is true, for example) then stays in state 2. The equation for the variable could make use of prev, as follows:

if time()==0 then 1 elseif trigger then 2 else prev(1)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : parent function



parent function

parent(1)

Returns the id (instance number) of the individual whose reproduction gave rise to this one, or 0 if the individual being considered was created at the start of the simulation or by immigration.

Input: numeric (but a dummy value: use the value 1).

Result: integer (in fact, a negative integer number, being the instance number of a member of a population submodel. These are all numbered from -1 downwards.)

Comment:

This function is vital for the simulation of any form of biological inheritance from one generation to the next. You have to know who the parent is before you can allow the newly-created individual to inherit (possibly with modification) one or more of the characteristics of the parent.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : time function

time function

time()

Returns the current simulation time.

Input: none

Result: numeric (units = day)

Comment:

Any model which has exogenous variables (variables that change as a function of time, independently of the behaviour of the model, such as air temperature or rainfall) needs some way of knowing what the current clock time is: i.e. how far the simulation has proceeded. This function provides that information.

This function is not strictly-speaking necessary: you could get exactly the same behaviour by having a single compartment, initialised to zero, with a single flow in, with a constant value of 1. So, after 1 time unit the value of the compartment would be 1, after 12.5 it would be 12.5, and so on. However, the function is provided to avoid cluttering up the model with an extra compartment and flow.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : delay1, delay3, delayn functions

delay1, delay3, delayn functions

delay1(input, duration [, initial])

delay3(input, duration [, initial])

delayn(input, duration, n [, initial])

Arguments:

input: the value to be delayed

duration: time by which to delay the input value

n (delayn only): order of the material delay (delayn only)

initial (optional): the value of the result when the function first applies

Result:

The delayed value of input.

The delay1, delay3 ​and delayn function calculates a first, third or nth-order material delay of input, using an exponential delay time of delay duration, and an optional initial value initial for the delay. delay3 does this by setting up a cascade of three first-order material delays, each with a delay duration of delay duration/3. Other versions of the function behave analogously. delay3 returns the value of the final delay in the cascade. If you do not specify an initial value initial, all functions assume the value to be the initial value of input.

The delay3 function will return the value of delay 3 in the structure and equations shown in the following figure:

Compartment   comp1 : 
    Initial value = start_fill (real)
Compartment   comp2 : 
    Initial value = start_fill (real)
Compartment   comp3 : 
    Initial value = start_fill (real)
Flow   delay 1 : 
    delay 1 =         comp1*3/duration (1/day) 
Flow   delay 2 : 
    delay 2 =         comp2*3/duration (1/day) 
Flow   delay 3 : 
    delay 3 =         comp3*3/duration (1/day) 
Flow   inflow : 
    inflow =         input (1/day) 
Variable   start fill : 

    start fill =         initial*duration/3 (real) 

Example:

Delay 3 = delay3(input, 5) where input = 5 + step(10,3) produces the pattern shown below:

 

Built-in functions : first function

first function

first(T)

Takes an argument T that is a member of an enumerated type, and returns "true" if it is the first member of its type, and "false" otherwise.

Input: enumerated type member, or array of enumerated type members

Result: boolean, or array of boolean values

Examples:

If enumerated type "fruit" is defined as "apple", "grape", "banana":

first("apple") --> "true"

 

first(["banana", "apple", "banana"]) --> ["false", "true", "false"]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : following function

 

following function

following(T)

Takes an argument T that is a member of an enumerated type, and returns the next member of the enumerated type.

Input: enumerated type member, or array of enumerated type members

Result: enumerated type member, or array of enumerated type members

Examples:

If enumerated type "fruit" is defined as "apple", "grape", "banana":

following("apple") --> "grape"

following(["grape", "apple", "grape"]) --> ["banana", "grape", "banana"]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : forcst function

forcst(<input>,<time>,<horizon>[,<initial>])

New in v6.6

The forcst function performs simple trend extrapolation. Here's how it works. First, forcst calculates the trend in input, based upon the value of input, the first order exponential average of input, and the averaging time. (Think of the averaging time as the time over which you wish to calculate a trend.) Then forcst extrapolates the trend into the future - you specify the distance into the future by providing a value for horizon. If you do not specify initial, forcst substitutes 0 for the initial value of the trend in input.

The forcst function is equivalent to the structural diagram and equations shown in this figure:

Put diagram here

Compartment   Average input : 

    Initial value = input-(averaging*initial) (real)
Flow   change in average : 
    change in average =         (input-Average_input)/averaging (1/day) 
 Variable   averaging : 
    averaging =         Variable parameter (day) 
 Variable   forecast : 
    forecast =         input*(1+trend*horizon) (real) 
Variable   horizon : 
    horizon =         Variable parameter (day) 
 Variable   initial : 
    initial =         Variable parameter (real) 
Variable   input : 
    input =         Variable parameter (real) 
Variable   trend : 
    trend =         (input-Average_input)/(Average_input*averaging) (1/day) 

Example:

Sales_Forecast = FORCST(Sales,10,15,0) produces a forecast of sales 15 time units into the future. The forecast is based on current sales, and the trend in sales over the last 10 time units. The initial growth trend in sales is set to 0.

Built-in functions : in_preceding function

in_preceding function -- new in Simile v5.7

Usage: in_preceding(expression of any type) returns that type

Definition: Used in a multi-instance submodel, returns the value of the argument expression  as it would be in the preceding instance of that submodel, or 0 or "false" in the first instance. The argument can include the function prev(0) to refer to the value in the previous submodel instance of the component in whose equation the in_preceding() function appears.

Note that a model that contains a circular set of influences can build and run properly if the input parameter associated with one of the influences is only used in the argument of an in_preceding() function. This is because since the value of the argument is calculated for one submodel instance and then used in the next, there is no actual circular dependency.

Example 1:

A 5-instance submodel contains a variable with the equation

index(1)+in_preceding(prev(0)).

The values will be:

1 3 6 10 15

Example 2:

An 8-instance submodel contains two variables, "received" and "forwarded". These are connected to one another by influences in each direction. The equation for "forwarded" is received/2. The equation for "received" is

if index(1)==1 then 200 else in_preceding(forwarded)

The values of "received" for the 8 instances will be:

200 100 50 25 12.5 6.25 3.125 1.5625
In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : ramp function

ramp(time,slope)

Generates a ramp of slope slope, starting at time time and zero before that time.

Result: the ramp function.

Arguments: time at which to start ramping, slope (positive or negative) of ramp

Example:

the function ramp(20,-7) will have a return value of 0 at time 20 and -70 at time 30

 

Built-in functions : smth1, smth3, smthn functions

smth1, smth3, smthn functions

smth1(input, averaging [, initial])

smth3(input, averaging [, initial])

​smthn(input, averaging, n [, initial])

Arguments:

input: the value to be smoothed

averaging: time over which to smooth the input value

n (smthn only): order of the material smoothing

initial (optional): the value of the result when the function first applies

Result:

The smoothed value of input.

The smth1, smth3 and smthn functions perform a first-, third- and nth-order respectively exponential smooth of input, using an exponential averaging time of averaging, and an optional initial value initial for the smooth. smth3 does this by setting up a cascade of three first-order exponential smooths, each with an averaging time of averaging/3. The other functions behave analogously. They return the value of the final smooth in the cascade. If you do not specify an initial value initial, they assume the value to be the initial value of input.

The smth3 function will return the value of comp3 in the structure and equations shown below.

Compartment   comp1 : 
    Initial value = initial (real)

 

Compartment   comp2 : 
    Initial value = initial (real)

Compartment   comp3 : 
    Initial value = initial (real)

 

Flow   flow1 : 
    flow1 =         (input-comp1)*3/averaging (1/day) 

Flow   flow2 : 
    flow2 =         (comp1-comp2)*3/averaging (1/day) 

Flow   flow3 : 
    flow3 =         (comp2-comp3)*3/averaging (1/day) 

Examples:

Smooth_of_Step = smth3(Step_Input,5)

where

Step_Input = 5 + step(10,3) produces the pattern shown below.

 

 

 

 

Built-in functions : step function

step(height,time)

creates a step function. Output is 0 up until time, and equal to step thereafter.

Result: the step function.

Arguments: height of step, time at which to step.

Example:

step(30, 20) has output 0 at time 19, and 30 at time 20 and after

Built-in functions : stop function



stop function

stop(n)

Input: is a number (real or integer) of your choice

Result: None (see text)

When executed, this function halts execution of the model, and produces the following error message:

Simile ran into a problem trying to run this model.

While it was trying to calculate the value of variable

var (node x) during execution of the model at

time t, there was a user-defined interruption: n.

It is useful to define error conditions where you (the model designer) know that the model should not be used or is not applicable for some reason. Trivially, it can be used to guard against mathematical errors, for example:

if (time()-50) != 0 then 1/(time()-50) else stop(5)

This form has some merit when running in C++, but generally, to track down mathematical errors, it is easier to debug in Tcl. If execution in Tcl would take too long, then this is a useful alternative. Its primary use however, is to enable you to catch out-of-range conditions in the specific circumstances of your model.

The use of an error code in the user-defined interruption (e.g. stop(13) ) enables you to see which stop( ) function caused the model to stop running, if there is more than one in your model.

Result is undefined, because simulation stops at the point at which the function is called, but has integer type (this is important because if it is called in a conditional, the other branch of the conditional must also have a numerical type).

Examples:

if population>50 then stop(1) else 0

if (time()-50) != 0 then 1/(time()-50) else stop(5)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : trend function

trend(<input>,<time>[,<initial>])

New in v6.6

The trend function calculates the trend in input, based upon the value of input, the first order exponential average of input, and the exponential averaging time averaging time. trend is expressed as the fractional change in input per unit time. If you do not specify initial, trend substitutes the value 0 for the initial value of the trend.

The trend function is equivalent to the structural diagram and equations shown in this figure:

Put diagram here

Compartment   Average input : 

    Initial value = input-(averaging*initial) (real)
Flow   change in average : 
    change in average =         (input-Average_input)/averaging (1/day) 
 Variable   averaging : 
    averaging =         Variable parameter (day) 
Variable   initial : 
    initial =         Variable parameter (real) 
Variable   input : 
    input =         Variable parameter (real) 
Variable   trend : 
    trend =         (input-Average_input)/(Average_input*averaging) (1/day) 

Example:

Yearly_Change_in_GNP = TREND(GNP,1,.04)

This equation calculates the annual change in the input GNP. It starts with an initial value of .04 (4% per year).

Built-in functions : var_delay function

var_delay function

var_delay(var,n)

Input: a variable name and a numerical value (real or integer) of time units

Result: the value (any type) of the named variable, n time units ago

This function returns some previous value of another variable, an arbitrary period of time before. The period of time is defined in time units (not steps). The number need not be an integer, but whatever the actual time step, delay is always rounded to the nearest multiple of 0.1 of a time unit. The variable whose previous value is required is specified by name. The variables must be linked with an influence arrow.

This is a general replacement for the last( ) function, which returns the value of the named variable from the previous time step only. The delay must be between 0 and 100 and is rounded to the nearest 0.1. The delay can vary; if the delay is constant, the function const_delay() will do the job more efficiently.

Examples:

runoff=var_delay(rain,soak_time)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: at_init function

at_init function

at_init(X)

Returns the value the argument had when first used, i.e., on model reset or when the submodel instance containing this equation was created.

at_init(X) creates an implicit intermediate result, which has the same dimensions as its argument. So if this result is implicitly replicated elsewhere in the equation, the same value will be used each time. See makearray for behaviour in explicit replication.

Input: Any data type

Result: Same type as input

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: at_posn function

at_posn function

at_posn(C)

at_posn(C,Row,Col)

Must form the whole equation of a component. Sets the component's value to the value of a component in an instance of a 2-D submodel representing a grid. C is the caption of the component in the grid submodel, and Row and Col if present are the outer and inner indices of the source instance (i.e., grid square) from which to get the value. If Row and Col are not present, the grid is mapped onto the diagram of the submodel containing the target component and the source instance selected by the component's position in the submodel diagram.

Input: Any data type plus optionally two integers

Result: Same type as input

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: const_delay function

 

const_delay function

const_delay(var,n)

Input: a variable name and a numerical constant (real or integer) of time units

Result: the value (any type) of the named variable, n time units ago

This function returns some previous value of another variable, a arbitrary period of time before. The period of time is defined in time units (not steps). The number need not be an integer, but whatever the actual time step, delay is always rounded to the nearest multiple of 0.1 of a time unit. The variable whose previous value is required is specified by name. The variables must be linked with an influence arrow.

This is a general replacement for the last( ) function, which returns the value of the named variable from the previous time step only. The delay must be a numeric constant; for variable delay see var_delay().

Examples:

runoff=const_delay(rain,10)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: dies_of function

 

 

dies_of function

dies_of(X)

Returns true if argument is the loss channel that will cause the individual to disappear at the end of the current time step.

Input: value from a loss channel in the local submodel

Result: boolean

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: in_progenitor function

in_progenitor function -- new in Simile v5.8

Usage: in_progenitor(expression of any type) returns that type

Definition: Used in a population submodel, returns the value of the argument expression  as it would be in the instance of that submodel containing the reproduction channel responsible for the instance being evaluated, or 0 or "false" in an instance that arrived via a channel other than reproduction. The argument can include the function prev(0) to refer to the value in the progenitor submodel instance of the component in whose equation the in_progenitor() function appears.

Note that a model that contains a circular set of influences can build and run properly if the input parameter associated with one of the influences is only used in the argument of an in_progenitor() function. This is because since the value of the argument is calculated for the progenitor instance and then used in the offspring instance, and the progenitor always comes before the offspring in evaluation order, there is no actual circular dependency.

Important: If the progenitor instance has been removed (see Extermination) then using this function will return meaningless values, and may cause model execution to be aborted due to memory access violations. To avoid this problem, make the in_progenitor function itself the argument of an at_init() function, e.g., at_init(in_progenitor(index(1))). If this is done, the inner argument will be evaluated for the progenitor instance when the offspring instance is created -- at which time the progenitor definitiely exists -- and then retained within the offspring instance's data structure. The only reason for not doing this would be if changes in the value in the progenitor continue to affect the offspring, and offspring never outlive their progenitors, e.g., in an L-systems model of tree branching.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: iterations function

iterations function

iterations(X)

Returns number of iterations that have been done up to this point in an alarm submodel. Argument is the boolean balue from the alarm symbol.

Input: value from an alarm symbol in the local submodel

Result: integer

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: preceding function

preceding function

preceding(T)

Takes an argument T that is a member of an enumerated type, and returns the previous member of the enumerated type.

Input: enumerated type member, or array of enumerated type members

Result: enumerated type member, or array of enumerated type members

Examples:

If enumerated type "fruit" is defined as "apple", "grape", "banana":

preceding("grape") --> "apple"

preceding(["banana", "grape", "banana"]) --> ["grape", "apple", "grape"]

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: pulse function

New in v6.6. Note this function is provided purely for compatibility with continuous-only modelling tools, and new models should use squirts instead.

pulse function:

pulse(magnitude, first_time [, interval])

Generate a pulse with a duration of a single time step and a given cumulative value.

Result: the pulse waveform

Arguments:

magnitude: the cumulative value of the pulse. This will be the level change of a compartment due to a flow with this value coming into it.

first_time: The first, last or only time at which the pulse will occur

interval (optional) : If this is positive, the pulse will occur regularly with this interval after the initial time

If it is negative, the pulse will occur with this interval up until the initial time and not after

If zero or not present, the pulse will occur only once at the initial time

Example: pulse(20, 12, 5) generates a pulse value of 20/DT at time 12, 17, 22, etc.

 

Built-in functions: trigger_magnitude function

trigger_magnitude function

trigger_magnitude()

Returns a value representing the magnitude of the triggering event. Can only be used in the equations of derived events, squirts and rule-based state variables. Events influencing these components are not listed as parameters so this function is used to get their values. If the trigger is a simple event, this function gives the value of that event's equation. If it is a time series, it is the current value from the series. If it is a limit event then it is 'true' if there is only one limit, and -1/1 for lower/upper limit if both are given.

Inputs: none

Result: same units and dimensions as triggering events

 

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : sofar function



sofar function

sofar([X])

sofar({X})

Result is…

Input: numeric array/list

Result: numeric

Example:

Comment:

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : size function



size function

size(S)

size(S,I)

The first form takes the name of a fixed-membership submodel and returns the number of instances that it has. The second form takes the name of a fixed-membership submodel and returns the size of the Ith level of nesting of this submodel.

Input: submodel name

Result: integer

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : dt function



dt function

dt(I)

Returns the duration of the level I time step.

Input: numeric. This is the time step level.

Result: numeric

Examples:

dt(1) --> 0.1 (for a model whose top-level time step was set to 0.1 in the Run Control panel)

dt(2) --> 0.001 (for a model whose 2nd-level time step was set to 0.001 in the Run Control panel)

If you are starting off with Simile, it is unlikely you will need to understand the concept of "time step index". You will probably just be making models with a single time step, hence one level, so don't worry about anything except the use of dt(1).

The main use of the dt function is to engineer the addition or removal of a specified amount of a substance into or out of a compartment. The only handle we have for causing changes to the amount in a compartment are flows, and flows are expressed as a rate per unit of time (whatever time unit is used for the model, e.g. year). This creates a problem if we want to add or remove a specified amount of substance at some instant in time. For example, consider a model with a time unit of year, a time step of 0.1, and with a compartment X from which we want to remove 5 units at the instant that some condition, which only lasts for 1 time step (0.1 years), is met. If we simply had a flow out that was zero when the condition was not met, and was 5 when the condition was met, then for one time step the flow would be 5 (units per year): hence, only 0.5 units would be removed in the 1/10th of a year, not the 5 we intended. What we need to do is to artificially inflate the flow rate by a factor of 10 (in this case, with a time step of 0.1) for this one time step. We do this by dividing the flow rate (in our flow equation) by 0.1 (in this case), or by dt(1) in general. The flow rate then appears to be 50 units per year for that one time step, giving a loss of 5 units in the one time step. Bingo!

The actual flow expression for the case considered above would be:

flowout = 5/dt(1)

Special case

Using the argument zero in the function, i.e. dt(0), is equivalent to saying dt(n), where n is the time step index of the submodel in which the function is used. This is useful, because when a submodel time step index is changed, it is then not necessary to edit the dt() functions within it to preserve the meaning.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : count function



count function

count([X])

count({X})

Number of values in the array [X] or the list {X}

Input: array or list of values (numeric or boolean)

Result: integer

Examples:

count([4,5,6]) --> 3

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : channel_is function

channel function

channel_is(X)

X is an immigration, reproduction or creation channel. Returns true if this individual appeared through that channel.

Input: numeric

Result: Boolean

Examples:

channel_is(cr1) --> true, for each instance of the population that was initially created through channel cr1.

Comments:

This function can only be used inside population submodels. Its argument is the name of a channel (i.e. a population control symbol, one of creation, immigration or reproduction). Note that the value of the channel itself is not used, just the name. The result can be used in calculations inside the population submodel. For example, the expression

land_owned = if channel_is(im1) then 0 elseif channel_is(cr1) then 10

would allocate 10 acres of land to each member of the original population, but none to immigrants.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : init_time function



init_time function

init_time(1)

Returns the time at which this model component first came into existence. This really only has any use for:

  • population submodels, so that the model knows when a new member of the population was created; and
  • conditional submodels, so that the model knows when the submodel, or one instance of it, came into existence because the condition controlling it became true.

Input: numeric. In fact, the argument is not used, so simply insert the number 1. The only reason for having the brackets and an argument enclosed between them is that this is the only way that Simile can recognise that this is a function.

Result: numeric

Example:

Let's assume you have a population submodel, and some property of each individual is related to its age (e.g. its growth rate, or its probability of dying). Simply create a variable called age (inside the submodel), and insert the following equation:

age = time(1) - init_time(1)

The result is the difference between the current simulation time (given by the function time(1), and the time when the instance was created, given by init_time(1).

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : index function


index function

index(I)

Returns the index (instance number) of a member of a fixed membership or population submodel, for the level of submodel nesting specified by the argument.

Input: numeric

Result: numeric

Comment:

The index function is frequently used in conjunction with the element function when working with multiple-instance submodels: both fixed-membership and population submodels.

The argument specifies which index is to be returned. You can see summary information about the meanings of the different indices in the listbox headed Indices: in the equation dialogue. The argument is an integer between 1 and the maximum number of indices available. index(1) corresponds to the 'innermost' index, i.e., if you have one multiple-instance model inside another, the result of index(1) will be the index of the inner submodel instance, and the result of index(2) will be that of the outer submodel instance. Similarly, if a submodel has two dimensions, then index(1) and index(2) will be valid in that submodel, giving an instance's position along the inner and outer dimension respectively.

Relation submodels do not usually have indices of their own, but you can get the indices of their base submodel instances using the index() function. If one of the roles in a relation has been specified to 'allow base instance lookup', then the base submodel for this role will be 'innermost' and and the index of the instance in this role will be the result of calling 'index(1)' in the relation submodel.

For fixed-membership submodels, the function returns an integer value between 1 and n, where n is the number of instances for the submodel. For variable-membership submodels, it returns an integer between 1 and n, where n is the maximum possible index. For a population submodel this would be the total number of instances of the population that have ever existed during this simulation run. For a conditional submodel the maximum will be the size given in the submodel dimensions. For either of these, an instance with a particular index number may or may not exist.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : Statistics

Statistical functions produce variates from distributions, and generally produce different values at each point in the model where they are called.

There are up to three forms of each statistical function:

  • The form with a _const suffix. This will produce a new value when the simulation is initialized or reset, or when a submodel instance containing it is created. This value stays the same until the end of the run, or until the submodel instance containing it ceases to exist.
  • The form with a _var suffix (or no suffix). This will produce a new value on each time step for each instance where it occurs. The sequence of values for all such functions can be initialized using the Initialize pseudo-random tool. If there is no _const form of a function, the _const behaviour can be produced by wrapping this form in the at_init() function.
  • The form with an extra argument. The last argument (an integer) serves as a seed for the values produced by that particular occurrence of the function. These will be the same each run, and independent of any other statistical functions in the model. For instance if it is used in a conditional submodel, it will start producing the same sequence of results each time an instance of the submodel comes into existence (assuming the seed value is the same).

If a statistical function only has one form, it behaves like the 'var' form.

Built-in functions : rand_const function

rand_const function

rand_const(X,Y)

Returns a random number between X and Y at the start of the simulation or when the submodel instance is created. The random-number generator is not called again, and so the value stays the same until the simulation is reset.

Input: numeric, numeric

Result: numeric

Comment:

The main use of this function is to assign values to a set of instances of a multiple-instance submodel (fixed-membership or population). For example, to randomly assign initial sizes to a set of trees in a multiple-instance tree submodel, we could use the equation:

size = rand_const(12,20)

or to assign random locations to the trees, we could use the equations:

x = rand_const(0,50)

y = rand_const(0,100)

which would randomly place the trees in the left-hand half of a one-hectare plot, assuming that the values are in metres.

The use of rand_const() is deprecated because it cannot be made to behave in the same way as rand_var when implicitly replicating over an array. It is implemented by internal conversion to at_init(rand_var(x,y)) and this form should be used in full to make the replicatio behaviour clear.

Historical note: You may come across some models that use a rand(X,Y) function. This behaves like rand_const if Simile deduces that the model element will only be called at initialisation time, and like rand_var if the equation contains some variable that changes over time. The use of this function is now also deprecated because the semantics of the two uses are so very different. Also, there are some situations when you need to be able to over-ride this behind-the-scenes decision about how the function should behave.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : rand_var function

rand_var function

rand_var(X,Y)

Returns a random number between X and Y, with a new value every time step.

Input: numeric, numeric

Result: numeric

Comment:

This function is used for doing stochastic modelling and Monte-Carlo simulations, i.e. one or more processes in the model (like giving birth or dying) have a random element to them.

rand_var gives a new result for every call, and if it is used in an expression that is replicated to make an array, each element's random value will be different.

rand_var uses the pseudo-random sequence generator built into the c++ compiler which Simile is using to create executable models. The sequence is initialized with a value generated from the process ID and clock time when Simile starts up, so no two runs will produce the same results. However, if it is required that a model has exactly the same behaviour each time it runs, despite including calls to rand_var, this can be achieved by means of a tool that sets the seed to a given value; see Initializing pseudo-random sequence.

Historical note: You may come across some models that use a rand(X,Y) function. This behaves like rand_const if Simile deduces that the model element will only be called at initialisation time, and like rand_var if the equation contains some variable that changes over time. The use of this function is now deprecated because the semantics of the two uses are so very different. Also, there are some situations when you need to be able to over-ride this behind-the-scenes decision about how the function should behave.

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : binome function

binome function

binome(prob, n)

Input: Real numerical value, integer value

Result: A value from the binomial distribution with the given probability and number of trials. A new random deviate is generated each time step.

The binomial distribution describes the probability of a given number of positive outcomes occurring when a number n of trials are carried out, each with a certain probability p of a positive outcome.

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Examples:

coins_heads_up = binome(0.5, coins_tossed)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : colin function

colin function

colin([Array])

Returns a deviate from a distribution whose relative probabilities are given by the values in the argument array. A new deviate is generated each time step.

Inputs: array of probabilities (real).

Outputs: index to value in array (int).

This can be used to make a deviate from an explicit set of probabilities where the pattern does not match any other built-in statistical function.

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Example:

colin([1,1,1,10,1]) --> 4 (usually), 1,2,3 or 5 (occasionally).

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : exprnd function

exprnd function

exprnd(mean [, seed])

Returns: value sampled from an exponential distribution (numerical)

Arguments: mean of distribution (numerical), seed for random sequence (integer, only required if a reproducible series of values is needed)

Example: A Geiger counter pointed at a radioactive source will emit a series of clicks at random times. The durations of the intervals between the clicks are distributed exponentially.

In: Contents >> Working with equations >> Functions >> Built-in functions

 

Built-in functions : gaussian_var function

gaussian_var function

gaussian_var(mean, sd)

Input: Two real numerical values

Result: A random sample from a Gaussian (normal) distribution, with the supplied mean and standard deviation. A new random sample is generated each time step.

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Examples:

daily_rainfall = gaussian_var(annual_rainfall/365, 1.0)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions : with_colin function

with_colin function

with_colin({ProbList},{ValList})

Takes two lists with equal size, and returns an element from the second argument, picked at random with the probability of each element proportional to the value of the corresponding element in the first argument. A new return value is generated each time step.

Inputs: list of probabilities (real), list of corresponding values (any).

Outputs: element picked from second list (any).

This can be used to make a deviate from an explicit set of probabilities where the pattern does not match any other built-in statistical function.

Note that it only works on lists; if you want to do something similar with fixed-size arrays, you can combine the element and colin functions to achieve the same effect as follows: element([ValList], colin([ProbList]))

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Example:

with_colin({1,1,1,10,1}, {"apples", "pears", "oranges", "grapes", "bananas"}) --> "grapes" (usually), "apples", "pears", "oranges" or "bananas" (occasionally)

In: Contents >> Working with equations >> Functions >> Built-in functions

Built-in functions: hypergeom function

hypergeom function

hypergeom(Pop, Mark, Sample)

Returns a deviate from a hypergeometric distribution for a given population, number of marks, and size of sample.

Inputs: Population size (int), number of marked individuals (int), size of sample from population (int)

Outputs: deviate of number of marked individuals from sample

The hypergeometric distribution tells us the range of probabilities of getting a number of "marked" individuals when taking a sample of a certain size from a population, a given number of which are "marked".

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Example: A research process involves ringing a certain number of seabirds from a population and releasing them, then at a later date recapturing a different number of the birds and checking how many ringed individuals are retreived. If a random group of individuals are captured each time, the probability of getting n rings back is equal to the probability of getting the result n from the equation:

rings_retrieved = hypergeom(Seabird_population, Birds_ringed, Birds_caught)

In: Contents >> Working with equations >> Functions >> Built-in functions

Buit-in functions : poidev function

poidev function

poidev(mean)

Input: Real numerical values

Result: A value from the Poisson distribution with the given mean. A new random deviate is generated each time step.

The poisson distribution describes the probability of a given number of positive outcomes occurring in the limiting case of the binomial distribution, i.e., with very many trials each with a very small chance of a positive outcome.

This function is implemented using a pseudo-random sequence generator; notes regarding its behaviour can be found in the documentation for the rand_var function.

Example: A hospital serves a large community in which a certain percentage of individuals are thought to be carriers of the hospital superbug MRSA. If we admit a small number of individuals to hospital, we would expect the probability of getting a certain number of MRSA carriers in that group to be equal to the probability of getting that number as the result of this equation:

MRSA_positive_admissions = poidev(Total_admissions*MRSA_prevalence_percent/100)

In: Contents >> Working with equations >> Functions >> Built-in functions

Working with equations : User-supplied functions

User-defined functions

There are three different mechanisms for users to supply functions for use in expressions:

  1. user-defined macros, which provide a short-hand for long or complex expressions that would otherwise have to be used repeatedly in expressions.
  2. user-defined external procedures, written in a programming language such as Tcl or C++.
  3. model-fragment function definitions (introduced in Simile v6), in which the behaviour of a function is implemented by a separate Simile model.

User-supplied function declarations and definitions should be put in files in the Functions directory in Simile's local data tree. This tree is created automatically when you first run Simile. Its location is:

  • On Windows: "My Simile Files", under "Documents" (Windows 7 or Vista) or "My Documents" (earlier Windows versions)
  • On Linux: .simile, in the user's home directory
  • On MacOS: Simile, in the user's home directory

Declarations and definitions in the Functions directory in Simile's installation tree (e.g., "Program files/Simile54") are for functions treated as "Built-In", i.e., expected to be available in any Simile system. It is worth looking at these for guidance in writing your own functions, as the formats are the same.

In: Contents >> Working with equations

User-defined functions : Macro definitions

Macro definitions

Macro definitions provide a shorthand for long, complex expressions that would otherwise have to be used in equations, possibly in several different elements. The definitions are stored in one or more external files, which are read each time Simile starts. Users may edit the files to include user-defined macros.

Each new macro is defined in a new line in any file with the extension .pl in the Functions directory. There are two places where this directory can be; one is within the Simile program files tree (for built-in functions), and the other is under Simile's local directory (for functions to be treated as user-defined). Any functions added by modellers should be placed in the latter location;  this has the effect that when a model requiring the functions is saved, they are marked as user-defined, and if the model is subsequently opened on a system where the function definitions are not present, a warning is displayed saying which user-defined functions are missing.

The format of the macro definition line is:

f(X1, X2 ... Xn) --> F(X1, X2 ... Xn).

where:

  • f is the name of the user-defined function. This has the format of a Prolog atom or variable, so it must start with a letter, and unlike the built-in function names it is case-sensitive.
  • X1, X2 … Xn are a series of one or more variable identifiers. These also have the format of Prolog atoms or variables, so they must start with letters and are case sensitive. These formal arguments to the function are replaced when the function is used, by the actual argument values. If the function requires no arguments, you must place a pair of single quotes between the empty parentheses.
  • F(X1, X2 … Xn) represents any expression that could be used in an element's equation. The variable identifiers can be used as quantities anywhere in this expression. This is the macro itself. As with any expression in the equation language, it may extend over more than one line.
  • The symbol '-->' means 'maps onto'. It, and the final period, are part of Prolog syntax.
  • Next line shows how to write 0-ary (no arguments) macro definitions (leave parentheses out) and macro definitions calling 0-ary functions or macros (put empty atom in parentheses).
    init_time --> at_init(time('')).
    Note the argument in the call is two single quotes, not a double quote.
     

The function, as it appears on the left side of the arrow, can then be used in any Simile equation, with any sub-expression taking the place of each of the variable identifiers. The result returned by the function will be the same as that which would have been returned by the expression on the right hand side, if the same sub-expressions had been substituted for the variable identifiers.

The .pl files distributed with Simile (and installed in the Functions directory in Simile's program files) contain a number of examples of function definitions. These include the following:

  • subtotals(Arr): Takes an array and returns another array of the same size containing the totals of all the values up to that point in the original array. e.g., subtotals([1,2,4,3]) = [1,3,7,10].
  • rankings(Arr) Takes an array and returns an array of integers of the same size each representing the position in the sequence of largest to smallest (largest = 1) of the corresponding value in the original array. e.g., rankings([8.2, -5.1, 2.5]) = [1,3,2].
  • with_greatest(Arr1, Arr2) Takes two arrays and returns the element of the second in the position corresponding to the largest-valued element of the first
  • colin(Arr) Takes an array and on each time step returns an integer, with the probability of each value being proportional to the value at that position in the original array.

Comment lines, starting with a %, can be included in this file, and standard multi-line comments bounded by /*...*/ can be used.

If there is a syntax error in a user function definition, this will cause a warning to be produced when Simile is started. The other definitions will still be usable.

In: Contents >> Working with equations >> User-defined functions

User-defined functions : External procedures

External procedural functions

To include user-defined external procedures, there are three files:

  1. A file under the Functions directory with the .pl extension. This file can also contain macro definitions. Procedurally defined functions that are treated as being built-in to Simile go in Simile's installation tree, while those that are treated as user-defined go in the local information tree. The declarations take one of two possible forms:

    function(Name, ResultType, ArgTypes).
    This form is used for ordinary, deterministic functions.
    sample(Name, ResultType, ArgTypes).
    This form is used for functions which give a new value each time they are called, even if the arguments do not change. This is used for stochastic functions such as gaussian_var, and is required because Simile otherwise tries to be lazy -- it only re-evaluates a function if the arguments change.

    In either form, "Name" is the name of the function, which is used in Simile's equation language. "ResultType" the type of the result - one of int, real, boolean or any - and "ArgTypes" a list of argument types in the same form. These allow the Prolog equation parser to accept this function in equations, and to put it into the target language program as a procedure call wherever it is used.

  1. procs.cpp -- This is in the same Functions directory as the function declaration. It contains the C++ implementation of the function. When the model is built in C++, during compilation of the generated code, this file is included (via support1.cpp) and linked into the resulting model library.
  1. procs.tcl -- contains the Tcl implementation of the function. This is sourced just prior to the model program, but not in global scope so any global variables used by the procedure need to be declared both inside it and out.

These files are stored in the Functions directory of the Simile program files tree. If you wish to build models in both C++ and Tcl, using the same function name, you must include the function definition is both procs.cpp and procs.tcl.

It is generally not a good idea to use global variables in the function definitions, because if the functions are used in more than one place in the model, a value set when running one instance of it may be used when running another instance.

In: Contents >> Working with equations >> User-defined functions

User-defined functions : Model Fragments

Model Fragments as Function Definitions

This feature, introduced in Simile v6, is really, really easy to use. Suppose you need to have a particular function available in your model, and you have no idea how to program it in c++ or write a macro expression for it, but you can easily make a simple Simile model that implements the function. One option would be to build such a model, and copy it to every part of the model you are working on where you need the function it provides. The trouble is, this would make the diagram confusing and the model would be harder to maintain, since if you changed the implementation of the function you would have to change all the occurrences of the model fragment that carries it out.

Now you can keep the model fragment somewhere else, and refer to it wherever you like by means of an ordinary function. The fragment goes in a directory called Fragments which is a subdirectory of either of the Functions directories for user-defined functions in general. The name of the function it implements, and the components of the fragment which correspond to the result and arguments, are identified by the name of the fragment file, which has the format 

functor,result,arg,... .sml

For instance, suppose you want a function that returns the first prime number greater than its argument. You could make a model fragment that looks like this:

Model fragment implementing 'next prime number' function

This model takes a number in the 'start' variable, and generates the next prime number up from it in the 'next' variable. It uses two nested iterative submodels. The outer one tries each odd number, starting from 'start', until one is found to be prime. The inner one applies the test for primeness, dividing the candidate by each odd number starting from 3 until either an exact factor is found, or the next divisor is greater than the square root of the candidate. If a factor is found, the outer submodel moves on to the next candidate and the inner one starts again.

So, we have our model, how do we make the function? By saving it in the Fragments directory with a name made of the following parts:

  • The name of the function, in this case 'next_prime'
  • The caption of the model component that has the result, in this case 'next'
  • the captions of all the arguments in the order in which they will appear in the function call, in this case just the one: 'start'

These are all separated by commas and the name finishes with the .sml extension as for any Simile model, so the full name is

next_prime,next,start.sml

Now you can use the function in any equation, e.g. "next_prime(z)>50"

Points to note:

  • The argument components must be variable parameters as shown above.
  • The result and argument components must be in the top level of the model fragment, i.e., not in a submodel
  • ​The fragment can include compartments, in which case the function will have a state and its output will depend on its inputs at earlier times
  • If you use an array as an argument to a function where it is a single value in the definition, you will get a separate instance of the fragment for each element of the array
  • The internal components of the fragments will appear in the model explorer during execution and their values can be inspected
  • Fragments can include any Simile feature, including functions defined by other fragments (but avoid circular definitions!)

In: Contents >> Working with equations >> User-defined functions

Working with equations : Graph function

Graph function

The Sketch Graph window is called from the equation dialogue when the modeller wishes to sketch, by hand, the relationship between two variables. The relationship is, mathematically, a function: that is, there is only one Y value possible for any given X value.

The graph is sketched using the mouse. The graph consists of a number of straight-line segments. The x-coordinates of the two ends of each segment is fixed, but the y-coordinate of each end can be dragged up or down with the mouse. The y-coordinate at the end of one segment is constrained to be the same as the y-coordinate at the start of the next, making a continuous, if angular, curve. The modeller can vary the number of line segments used to make up the curve: if this number is quite high, then a close approximation to a smooth curve can be obtained.

The function is actually evaluated using linear interpolation. On any one occasion, there will be a single value for the x (independent) variable. The function calculates which line segment this occurs in, and how far along the line segment it lies. Simple algebra is then used to calculate the corresponding value for the resulting dependent (y) variable. Alternatively, you can choose to have the exact y value for the closest defined x value to the one given; see "options" below.

The window itself does not show the names of the variables involved. The independent (X-axis) variable is not yet specified at this stage, since that only happens when the user returns to the Equation window. The x value can be any Simile expression. There does not need to be a specific variable associated with y-axis, since the result of evaluating the graph function is just like any other function result - a value to be incorporated into the rest of a mathematical expression: graph(weight) plays the same role in an equation as log(weight), for example.

Click the OK button to return to the equation dialogue window. New text reading "graph()" has been inserted into the expression field, if this is the first time the sketch graph has been used for this equation. You must insert, between the brackets, the name of the independent (x-axis) variable or other expression. If you have already entered a graph() expression in the equation dialogue box, then the opportunity is given to edit the previously-drawn curve. It is not possible to use two different graph() functions in the same expression.

Drawing the curve

The curve is constructed by moving the mouse into the graph pad, holding the mouse button down, then moving the mouse from left to right (or from right to left) along the desired path. You are unlikely to get it right first time. If a line segment ends up in the wrong place, just try again. For finer control, you can click on a vertical line at the required point: the ends of the two line segments meeting at this line will then jump into position.

Scaling the axes

The two edit fields along each axis (Min and Max) are used to indicate the range of each axis. You click in the edit field, then enter a value that is appropriate to the lower and upper limits respectively of the variable in the relationship. Thus, if the independent variable were temperature, and we were modelling a site in Africa, then the x-axis might be scaled to be between 10 and 40 (the units of degrees Celsius are implicit). When you change the scaling of an axis, the actual sketch stays the same, so the behaviour of the function is changed to correspond to the new axis scaling.

By default, "Min" and "Max" are 0 and 100 respectively on both axes. It is not permissible to leave any entry blank.

Current position

These two edit fields display the current position of the mouse pointer in the graph area whilst dragging the curve. You can use this display to exercise finer control over the curve. It is also possible to enter values directly into these boxes, copying values from a table for example. After entering the Y-value, press the return or enter key on the keyboard to have the graph re-drawn to include the new pair of values.

If you want exact values for all the points in the graph, click the "Edit as table" button, and enter them with the keyboard, or by cutting and pasting.

Options

Between points

The normal behaviour of the graph function is to interpolate between the two nearest defined y values to get the function's result. Alternatively you can select 'Round' here, in which case you get the exact y value for the nearest defined argument value. The shape of the sketch graph changes to illustrate the actual values returned.

Out of range

There are three options to determine what happens if the independent variable falls outside the range scaled in this window, whilst the model is running.

  • truncate: this option extends the curve horizontally to the left and to the right.
  • extrapolate: this option extends the curve along a line with the same slope as the first and the last segment.
  • wraparound: this option joins up the left and the right ends of the curve. It is useful for defining repeating functions like sin(x).

X axis resolution

Clicking on the right-arrow button doubles the number of vertical lines in the graph pad area; clicking on the left-arrow button halves the number of lines. The higher the resolution, the greater the number of line segments making up the curve, and the smoother the curve is.

Altering function while model is running

The behaviour of the sketch can be altered while the model is running, using the edit sketch helper. This does not affect the version of the function in the saved model.

In: Contents >> Working with equations

Working with equations : Table function

Table function

The table dialogue window is used to create a table from data stored in a file. The required data are extracted from the file, and saved with the model. The table function is appropriate when referring to a relatively small amount of data which will always be the same wherever the model is used, for instance, the number of days in each month of the year. If you do not wish or need to store the data in the model, you can use a file parameter to access the data when the model is run. This is significantly quicker; so much so, that for extremely large data sets it is the only feasible approach.

There are three main uses of the table function:

  • entering a value for some variable for each instance of a multiple-instance submodel;

  • entering time-series data; and

  • entering a relationship between two variables.

In all cases, the table dialogue window is accessed through the equation dialogue window of a variable. Each variable can store one table. Because it is implemented as a function, the table can be used in the equation for the variable together with other components. Each table has one or more indices, which are used to extract a particular item of data from the table.

For example, a series of samples of soil quality might have two indices, an x- and a y-coordinate. The data value would record the soil quality for each (x,y) pair. The table function would then be table(x,y) and would return the value representing soil quality at the given coordinates. In this case, x and y could be influences from other variables or could be derived from the index of a multiple-instance submodel. In other cases, the index might be derived from simulation time.

Loading the table data

When you hit the 'Table...' button, the table data dialogue appears. This is the same dialogue that is used to load the data for a file parameter, and is used in the same way. Therefore, your data can be in any of the formats that are supported for file parameters -- but remember that very large datasets will be handled inefficiently, so use file parameters instead. The data is stored as an array in the model, so any indices loaded from the file must be integers.

Using the table function

The table function always takes at least one argument, and if there is more than one index, takes as many arguments as there are indices. It returns the item of data referred to by the arguments. Each application of the table function makes use of a different source of its arguments. We now examine these in turn.

Entering a value for each instance of a multiple-instance submodel

Suppose that we have a model that contains multiple instances of some type of object: for example, multiple patches of land, multiple trees in a stand of trees, or multiple species of vegetation in an area. We have a file containing actual data for this scenario: for example, a database containing elevation and slope data for the patches of land; species, height and diameter for the trees; or growth rates and initial biomass for the vegetation.

Create the table, selecting as data column the column containing the data you wish to use. Do not specify an index. The row number will be used instead. Return to the equation dialogue window by clicking OK.

Notice that Simile has automatically inserted table() into the Equation box. Change this to table(index(1)) : this indicates that each value in the column of data from the file will be assigned to the corresponding instance number in the model.

Entering time-series data

Many ecological models include exogenous variables, such as temperature or rainfall, which influence the behaviour of the model but are not themselves influenced by it. Sometimes the modeller is content to generate values inside the model, using a time-series generator to produce a sequence of values with appropriate statistical properties. Often, however, historical records exist, and the modeller wants to use these in the model.

As stated above, the table() function is only appropriate if the amount of data is relatively small and it is to be stored as part of the model. If you have large datasets which you want to load into the model as it runs from a separate file, you should look at working with time series data.

The quickest way to include a small time series in your model is to have a data file, as specified above, with at least two columns: one for the variable of interest (e.g. temperature), and one giving the time when each temperature measurement was made. Drag the column heading corresponding to the variable of interest (say, temperature) into the Use as data column edit box. Drag the column heading corresponding to the simulation time into the list box labelled Use as indices.

The text table() is inserted into the equation box. Change this to table(int(time())). Because time() returns a floating point number, the int() function is used to convert it to an integer. The text now reads table(int(time())).

There is more information on working with time series in the Working with External Data section of the help.

Entering a relationship between two variables

In this case, one or more other elements are used as the argument(s) to the table function. For example, if we have a series of pairs of temperature and rainfall values that produce different growth rates, we can use the expression table(temperature, rainfall). Note that both arguments must be integers. If they are not, use the int() function to convert them.

In: Contents >> Working with equations

Working with equations : Arrays and lists

Arrays and lists

Arrays are data structures that consist of more than one element. Each element of the array may be:

  • a scalar: a single real, integer or Boolean value; or
  • an array or list: thus arrays and lists can be nested (to any depth).

Arrays can be created either automatically (when required) or by the user.

Lists are data structures that consist of zero or more elements, and can only be created automatically. Lists are created when values from a population submodel, conditional submodel or other variable-membership submodel are used outside the submodel itself.

Referring to arrays and lists

An array variable is denoted by enclosing the variable's name in square brackets. Thus, [weight] represents an array of one or more weights. This is a one-dimensional array (a vector), because the variable name is enclosed in a single pair of square brackets. By contrast, [[weight]] is a two-dimensional (rectangular) array of weights. This could be used to represent, for example, the weight of each of 10 varieties of fruit (orange, apple, banana, etc) in each of 20 samples.

Note that the size of the array (also known as its dimensions) is not referred to when the array is used in equations. The dimensions are shown in dimensions field of the equation dialogue box.

An list variable is denoted by enclosing the variable's name in curly brackets. Thus, {weight} represents a list of zero or more weights.

How arrays are made

There are three ways in which an array can appear in a model.

  1. An influence arrow might be drawn from a variable inside a fixed-membership, multiple-instance submodel to a variable outside the submodel. As soon as the influence crosses the submodel boundary, what was referred to as a scalar variable inside the submodel becomes an array outside it, since there is now a fixed set of values (one for each submodel instance).
  1. The user might build an array inside the equation dialogue for a variable by explicitly listing all the elements of the array. Thus, if you enter [2,4,6,7] in the equation dialogue for a variable, then its value becomes the array consisting of these four values. Note that the square bracket notation has two quite different interpretations. When the square brackets enclose the name of a single variable, then it is understood that this variable is an array. When the square brackets enclose more than one values, then it is understood that the whole structure is an array. This difference is illustrated by the following examples: (a) [weight] and (b) [weight, height]. The first is referring to an array called weight (which could have any number of values). The second is defining an array with two elements, the scalar variable weight and the scalar variable height. The latter has just two elements.
  1. The user might use the makearray(…) function. This is called explicit replication.

Processing arrays

Arrays can be processed in a number of ways.

  1. You can use a function that is expecting an array as an argument. For example, the function sum(…) will sum the elements of an array.
  1. You can use arrays in mathematical expressions. Simile has powerful built-in methods for calculating with array variables which totally avoid the need for looping structures for calculating with arrays. For example, the expression: [k]*[weight] where both arrays have the same number of elements, returns an array with each element equal to the corresponding value of [k] multiplied by the corresponding value of [weight].
  2. You can also combine scalar values with arrays in expressions. In this case, the result has the same dimensionality as the array, with the scalar value being used the same way for each element. For instance, 2 + [3,4,6,7] = [5,6,8,9]. This is called implicit replication.
  3. Similarly you can combine arrays of different dimensionalities (but not different dimensions), e.g., a 3-element array with a 3x2-element array. What happens is that the function is applied separately to each corresponding set of elements in the argument arrays, and the results combined to give the result array.
  4. You can extract particular values from an array. The function element(array,i) returns the i'th element from the array. Thus: element([2,4,6,3],2) returns the value 4 (being the second element of the array).

Array-valued components

If a component's equation evaluates to an array, the component will be displayed with a repeated border as shown above, to indicate a stack of different values. An influence from that component to another will allow the array to be used in the destination component's equation in any of the ways described above. The number of layers in the stack indicates the outermost dimension of the array, up to a maximum of four. Condition boxes and population membership channels cannot have array values.

How lists are made

There is only one way in which a list can appear in a model: by having an influence arrow coming out of a submodel with a variable number of instances. This means:

  • a population submodel;
  • a relation (association) submodel; or
  • a conditional submodel.

As of Simile v6.1 an influence arrow within a special-purpose submodel can be set to deliver values from 'neighbour' components, which form a list as some instances have more neighbours than others.

Processing lists

Lists can be used in functions and operators along with scalar values or other lists with the same member ids (e.g., from another variable in the same submodel). The rules for combining scalars and lists are similar to those for combining arrays as described above. Lists must be processed as soon as they appear in the variable outside the submodel which receives an influence arrow from a variable inside it. You cannot have a component whose value is a list or array of lists. Rather, you must perform some legitimate list-processing operation, such as using the function sum(…) to sum the values of the list, so the variable's value is a scalar or fixed array.

As of Simile v6.1 the 'element()' function can be used to extract a sublist from a list, but the result is still a list, so some aggregating function must be applied to it when creating a component value from it.

More about Replication

In many cases, it is obvious how implicit replication will be applied when combining values with functions or operators. If one is scalar, then whatever the dimensions of the other, the result will have those dimensions. But what if the values are arrays with different nestings? If we add a 1-D array to a 2-D array, the result will be a 2-D array -- but how will the values of the 1-D array be shared out?

What happens is, the elements of the lesser-dimensional array are assigned to the elements of the higher-dimensional array with the same outer indices. For instance, [[1,2],[3,4]] + [10,20] is [[11,12], [23,24]] and not [[11,22], [13,24]]. Effectively the second argument is replicated from [10,20] to [[10,10], [20,20]]. Another way of looking at the same process is to imagine that the arguments are separated into groups, then the function applied to each group and the results combined back into arrays. So, [[1,2],[3,4]] + [10,20] becomes [ [1,2] + 10, [3,4] + 20 ].

The easiest way to remember how it is done is to learn the reason for it being that way, which is as follows: a modeller might wish to get either of the two possible results above, depending on the needs of their model. If they want the second case, they can be sure of getting it by using the makearray() function on the second argument, so they are actually adding [[1,2],[3,4]] and [[10,20], [10,20]] which have the same dimensions. However, if they want the first case, it would be more complicated to arrange it using such explicit replication, so to make things simpler, that is how implicit replication works.

In: Contents >> Working with equations

Working with equations : Dimensions



Dimensions

The dimensions field in the equation dialogue box is provided for reference only. It is not necessary to edit this information. The dimensions are a measure of the size of an array (or vector). Note that a vector is a one-dimensional array, and the term array is used here to cover both.

[2,3,4] has dimensions 3

[[2,3,4],[4,6,8]] has dimensions 2,3

In: Contents >> Working with equations

Working with equations : Physical units

Physical units

Unit definitions

Component values in Simile, and parameters used in equations, may be assigned physical units (e.g., cubic metres) by the modeller. There is a large set of such units built into Simile, and it can be extended with extra unit definitions provided by the modeller. The supplied units will be used to provide consistency checking and unit conversions where appropriate.

First off, there are the baseline units. These are the ones in terms of which all other units are defined. Simile comes with five baseline units predefined, metre (m), gramme (g), second (s), kelvin (k) and radian (rad). These are measures of length, mass, time, temperature and angle respectively. You can use either the short or long form to specify the units of a value.

Next there are the decimal multiplier prefixes, such as micro (). All those defined in SI are available. To use a decimally multiplied unit, simply put its prefix in short form before the short form of the unit itself, for instance kg = 1000 grammes (kilogramme). Some combinations of a multiplier and a base unit have a long form defined, e.g., kilogramme (kg), centimetre (cm). Again you can use either the short or long form to specify your units. Note that where appropriate we provide both the UK and US spellings.

Finally there are derived units, which are defined in terms of numerical constants and other units. You can write a derived unit using the short forms of other units (including other pre-defined derived units), integers and the symbols * (multiply), / (divide) and ^ (power). You can only use ^ with an integer exponent, as it works as a shorthand for multiplying, e.g., m^3 (cubic metre) means the same as m*m*m. There are also a number of pre-defined derived units. These include W (watt), psi (pound per square inch) and so forth. They may have a long form, and you can use either short or long form, and precede the short form with a decimal multiplier prefix, e.g., MJ for megajoule. Short forms of derived units can also be combined using symbols as above, e.g., W/m^2 = watts per square metre.

The definitions of all units are provided in the file new_units.pl in the Functions directory of the Simile installation. If you want to add extra units for your own application domain, create a file with a .pl extension in the appropriate place (see User-defined functions) and add the definitions in the same format as the built-in unit definitions. Note that all definitions define a short form in terms of other short forms -- you specify the longhands separately if they are needed. You cannot do anything with longhand forms except use them on their own to specify the units of model quantities -- all definitions, combinations and decimal multiplications must be done on short forms.

Effects of setting units

There are two mechanisms within Simile for checking that physical units are compatible and for including a unit conversion where appropriate.

  • Mechanism I is a method of using units to perform an ad-hoc conversion between values in different systems, without cluttering equations with conversion constants. This mechanism performs conversions between different Simile components.

  • Mechanism II is a system of entering equations with dimension checking, enforcing consistency and performing the required conversions automatically. This mechanism performs conversions within a component's equation.

The first mechanism is always active. To activate the second mechanism, select the "Yes" option in the drop-down field labelled "Use units in math" in the Model...Properties dialogue box. The options are "Default", "Yes" or "No". The default is to inherit the setting from the parent submodel. In a top-level submodel (i.e. desktop), the default is "No". It is possible to have submodels with equation dimension checking and submodels without in the same model.

When you enter a new equation with the equation dialogue, you can enter a unit specification in the units field. If you do not do so, or if you use the equation bar, the value is given the default units for its equation. In the equation box, you can also specify units for the values associated with incoming influences. If you do not provide units for them, they get the same units as the component they come from.

 

Mechanism I : Ad-hoc conversions

 

If you enter units for a value from an incoming influence, and the value of the component from which that influence comes also has units, Simile will perform a compatibility check and add a conversion if one is required. This makes it straightforward to include unit conversions when integrating models from different sources; provided the appropriate units are specified on each side of any link between them, the conversions will be built in automatically.

If the units at the source are real (i.e., it has no physical units) then it can be given any physical units at the destination and no conversion will be done. But if it does have physical units, then any units given to it at the destination must be compatible with them. That is to say they must have the same physical dimensions. For instance, mph (miles per hour) are compatible with m/s (metres per second) because they are both measures of speed. If one component has units of mph, and another has an influence from it which is given units of m/s, then the value from that influence that is used in the equation will be the result of converting the source value from mph to m/s, i.e., dividing it by about 2.25. However mph is not compatible with, say, km, because km is a measure of distance, not speed.

The same sort of check is also performed when a flow joins a compartment. Because the compartment's value is a function of the flow's value over time, the flow's units must be compatible with the units for the rate of change of the compartment over time. For instance it would be OK for the compartment to have units of litre and a connecting flow to have units of ft^3/day, because the first is volume and the second a rate of change for volume. In this case a conversion will be done on the amount of change due to the flow before adding it to or subtracting it from the compartment. But they could not both have units of litre, because the flow must be compatible with the compartment's rate of change rather than its actual value. In a future version of Simile we may allow a flow to have two different sorts of units at once, one for each end, to capture the situation in which it transforms one substance into another, e.g., a chemical reaction. In the mean time, if a flow has no physical units then no conversion will be performed at either end.

 

Mechanism II : Fully consistent physical dimensions

 

When units checking within math is selected, setting an equation causes it to be checked for consistency of units. This works by generating a physical sort of units for each subexpression in the equation starting with the units of the incoming parameters, and ending with a default sort of units for the result.

When adding or subtracting two quantities, both quantities must have the same units. There is one exception: if one quantity is a numerical constant, it automatically takes the units of the other. If the two quantities have the same dimensions but do not also have the same units, it is necessary also to specify a conversion for one or both to the same units. This can be done by changing the units associated with a parameter as described in the last section. When that is done, a conversion will be applied to the parameter value before it is used in the equation, so it becomes compatible with the quantity added to or subtracted from it. For example, adding one distance in feet to another in metres, it is necessary first to either convert the former to metres, the latter to feet, or both to a third unit, such as km. The result will be in the units of both the arguments.

When multiplying or dividing two quantities, the units of the result are determined by multiplying or dividing the units of the quantities themselves. e.g., the result of dividing a parameter with units metre by one with units metre/second will have units second.

Explicit conversion of dimensions

Although it should always be possible to create a model in which strict conservation of physical units applies, it is often the case that a model will include some ad-hoc representation of a complex relationship for which the exact equations are not available. In this case, the units of an equation's result may bear no relationship to those of its arguments. For instance, you might have a flow into a model compartment with dimensions mass/time, and the rate of this flow is set by a sketch graph against time. A sketch graph, like trig and exponential functions, must have a unitless argument, and produces a unitless result. However, the result of the time() function has dimensions time, and so cannot be used directly as the argument. For this kind of situation, you can include a unit name in the equation, with double-quotes around it to distinguish it from a parameter name, to represent unity with those units. So the argument for the graph function would be time()/"day" if the x-axis values on the graph represented numbers of days. Similarly, the result of the graph function is a unitless value, so it must be given units to allow it to make sense to the rest of the unit-checking-enabled model. This can be done by multiplying it by unit specifications -- for instance if the y-axis values on the graph represented mass transfer rates in kg/hour, the equation would be graph(...)*"kg"/"hour".  Of course the flow might go into a compartment whose units were some measure of mass other than kg, bit Simile would perform the appropriate conversions in this case.

If all the compatibility requirements are met, the end result of this process is a sort of units for the result of the equation. This is used as the default sort of units for the value being calculated. If you supply another sort of units for this value, it must be compatible with the default in terms of dimensions, and if the two are not the same an extra conversion may be applied after the equation has been calculated and before its value is assigned to the component. Note that the default units generated for the equation may not be in the most readable form, for instance if a result in watts is generated the units from the components might actually be something like N*m/s. In such a case you can set the units manually to the normal form, and no conversion will be done because they are mathematically equivalent.

In the physical sciences, many models can be completely expressed in terms of physically meaningful quantities. With this sort of model, it is a good idea to enable units checking within math, as it provides an extra safeguard against mistakes. In ecology and the social sciences, it is more common to use ad-hoc parameterisation that defies physical interpretation. In these cases, it is probably not useful to use this system, which is why it is switched off by default.

In: Contents >> Working with equations

Working with equations : Enumerated types

Enumerated types

Enumerated types allow you to refer to a each object in a collection by name, where the alternative is to use an arbitrary index number. To understand what is meant by an arbitrary index number, consider the following contrasting situations.

Let's say, for example, that you want to model soil water dynamics, with the soil divided into (say) four layers. You would create a submodel with four instances, numbered 1 to 4. You can then find the value for water content in the third layer using an expression such as element([water],3). In this case, the index number refers meaningfully to the layer number.

Now, suppose you wanted to model the growth and yield of four fruit trees: say apples, oranges, lemons and pears. You could use the above approach, creating a submodel with four instances, but in this case you would have to remember that instance 1 is "apples", 2 is "oranges", and so on. The index number is now arbitrary, since any order would be as good as any other.

The enumerated type mechanism enables you to associate the name of each fruit with each instance of the submodel, and to use this name (rather than a number) when referring to a particular instance. This considerably increases the clarity of your model, since someone trying to follow the logic of the model does not need to keep on checking up on the correspondence between an integer number and some more meaningful label.

Defining an enumerated type

Before you can use an enumerated type, you must define it. Enumerated types are defined at the level of the submodel. All submodels contained within the submodel in which the type is defined also have access to the definition. It is therefore most simple to define it for the whole model (so that any submodel in the model can then use it). To do this:

  1. Go into the submodel properties dialogue for the Desktop, either by doubleclicking on the background or by selecting "Properties..." from the edit or context menus
  2. Click on the "Advanced" tab in the Properties dialogue window to view the advanced options.
  3. Click in the edit field above the "Add type" button, type in the name for the enumerated type, e.g. "fruit", and click the "Add type" button.
  4. Click on the word "fruit" now entered into the Enumerated types list, to highlight it.
  5. Type "apples" into the same edit field, and click on "Add member".
  6. Repeat for "oranges", "lemons" and "pears". If at any stage the word "fruit" becomes un-selected, select it again to enable you to add new members.
  7. To see what the list of values is for "fruit", hover over the name and observe the pop-up reminder.
  8. You can now (or at some later stage) define additional enumerated types in the same way.

Alternatively, once you have supplied the name of the type, you can read the members from a file. To do this, click on the "Get from file" button. This displays the table entry dialogue, and you can use this as if you were specifying a data table to load. However, the data is not actually loaded; instead, all the different values are listed, removing duplicates, and these are made into the members of your enumerated type. The values must be textual, not numbers, so only data entry from columns or grids is allowed.

Using an enumerated type

The following model diagram will serve to illustrate how an enumerated type can be used. It shows a variable size inside a multiple-instance submodel (one instance for each fruit). This variable is exported as an array outside the submodel, then one value is picked up from this array.

If this model were set up without using an enumerated type, then the following would be used:

Submodel fruit: Number of instances (using specified dimensions): 4

Variable size: if index(1)==1 then 4.2 else 3.7

Variable sizes: [size] (Dimensions are automatically set to 4)

Variable size_apples: element([sizes],1)

If this model (with the same model diagram) were set up using an enumerated type (e.g. fruit, as defined above), then the following would be used:

Submodel fruit: Number of instances (using specified dimensions): fruit (i.e. the name of the enumerated type is entered into the dimensions edit field, and automatically sets the number of instances for the submodel to the number of values in the enumerated type - in this case, four.)

Variable size: if index(1)=="apples" then 4.2 else 3.7

Variable sizes: [size] (dimensions are automatically set to fruit)

Variable size_apples: element([sizes],"apples")

Things to note:

The same enumerated type can be used in several places. For example, you could have another submodel that also has dimensions of fruit.

A component's value can be a member of an enumerated type, either specified as a constant or the result of a function such as posgreatest() that returns an array index. Such a value can be used to index an array, or tested for equality with another member of the same type.

Note that the only test we can do with an enumerated type value is a test of equality with the index of a submodel (if index(1)=="apples"...). We can't use the greater-than or less-than operators, since the list is unordered (what a statistician would call nominal rather than ordinal).

Additional considerations

You can use the member names as indices when reading parameter values from a file. This is particularly convenient when the file was used to create the list of member names.

For example, the following file could be used

fruit, price

apples, 7.0

oranges, 7.4

lemons, 7.2

pears, 8.1

Using array functions

You can use the makearray function to create an array. For example, the equation

makearray(1,"fruit")

will create an array with dimensions (size) equal to the number of members in the enumerated type "fruit". It will be populated with values of 1. You can use the test place_in(n)==member to set each value separately. For example, the equation

makearray(if place_in(1)=="apples" then 7.0 elseif place_in(1)=="oranges" then 7.4 elseif place_in(1)=="lemons" then 7.2 else 8.1, "fruit")

will result in the same array as the above table.

Why is it called an enumerated type?

In programming, a type is a set of values from which a variable may take its value. Thus if a variable is of type "integer", then this set of values is all the whole numbers. If it is of type "real", then it is the set of all decimal values that can be represented on the computer. If it is an enumerated type, then the set of values is defined by an explicit list of all the values that the variable is allowed to take. The standard example is the enumerated type "days of the week", in which the set of allowed values is given by the list [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]. A particular variable (e.g. "washing day") can be defined to be of this type: we then know that its value must be one of these seven possible values.

In: Contents >> Working with equations

Working with equations : Local names

Local names

The local name is automatically composed from the full path name by replacing characters that are illegal in equations (such as spaces and carriage returns) with underscores. If you would prefer to use a different local name to refer to the full path name, the local name can be edited. To do this, you must have the equation dialogue box open, and click on the tab labeled "Parameters etc.". If you edit the local name, you may also need to edit the expression itself to update the corresponding references.

Names for roles

When a component in a multi-instance submodel influences another component, it may have different names in the equation according to which instances of the source the values are coming from. Normally if the destination is outside the multi-instance submodel, it gets all the instance values as an array or list, but if there is a role arrow connecting the source's submodel with the destination's, there will be an alternative local name referring to the list of values of only the source instances related to the destination. Also a link within a submodel can be set to allow the destination to refer to all the source values rather than just that from the same instance, or in the case with explicit grid array submodels, only those values from the instance's neighbours. The default local names in these cases are made up as follows, supposing the source component is called 'muffin', and the relation arrow, if one is involved, is called 'great':

Default role names
muffin Value sharing submodels with destination
great_muffin

Value in base submodel of local satellite or association

{muffin_great}

List of values from instances of satellite or association for which local model is base 

[every_mufin] array of all values from source irrespective of relations

{from_8_nbrs_muffin}

{from_6_nbrs_muffin}

list of values from an instance's neighbours in explicit rectangular or hexagonal grid arrays respectively
[all_muffin] array of all values from local submodel instances

Note also:

  • Roles including other instances of the submodel containing the destination only appear in the list of available local names if they have been enabled by editing the properties of the influence they refer to.
  • If a relation has had the 'exclusive role' property selected, then the name in the base submodel for values from the satellite or relation to which it connects will refer to a single instance rather than a list (i.e., no curly brackets) as we are asserting there will only be one of them.

Local names can be edited in the "Parameters etc." tab of the equation dialogue, but any brackets indicating a value's array or list nature must be retained. If a component's name is edited on the model diagram, any local names for that component's values in equations for components influenced by it will also be updated accordingly, and the equations themselves updated to use the new versions, provided the local names themselves have not been edited. Any local names that have been edited will be kept as they are if the name of the component they refer to is changed.

In: Contents >> Working with equations

Working with equations : Equation Listings

For documentation purposes, it may be necessary to produce a listing of all equations in a model, including such information as how the value of each other component is referred to in the equation, the definitions of any enumerated types used, and so forth. This can be done by selecting the 'List equations' entry from the 'Model' menu. The listing can be selected and copied from its window, and pasted into other applications.

In: Contents >> Working with equations

Working with submodels

Working with submodels

Simile enables you to wrap any part of your model diagram up in a round-cornered box, called a submodel. The submodel concept can be used to address a wide range of modelling needs, including plug-and-play modularity, disaggregation, spatial modelling and individual-based modelling. If you are new to Simile, you are strongly encouraged to read the introduction to the submodel element, so that you are aware of the various uses of submodels in your modelling.

Defining properties

A submodel's properties are set using a dialogue box invoked by double-clicking anywhere within the submodel in select mode, or by using the "Properties" command of the context menu for that submodel.

Operations on submodels

The editing operations in the context menu apply to the components in the submodel for which it was invoked. Also, the following tools are used to perform operations on submodels:

   

Opening a new window for a submodel

   

Saving a submodel

   

Loading a saved model as a submodel

   

Advanced use of submodels

  • Plug-and-play modularity uses submodels to substitute one alternative section of a model for another, or to include a model developed for another purpose or at a different time within a second model.
  • Multiple-instance submodels allow a single system of components in a model to stand for many similar structures in the domain being modelled
  • Iterative submodels contain components that are evaluated repeatedly until a finishing condition is met.
  • A submodel may be given a different time step index than its parent, allowing processes in the submodel to be simulated with a shorter or longer time step than those in the parent model.
  • Satellite submodels are used to extract a subset of values from a population submodel according to a given condition.

In: Contents

Working with submodels : Context menu

The context menu (also known as the edit menu) can be invoked for the desktop, or for the contents of a submodel. The actions in the context menu apply only to the submodel for which it was invoked. To invoke the context menu for a submodel, either:

  • Right-click in the background of the submodel while in pointer mode, or
  • Click o the "Edit" item in the menu bar of a window that has been opened to display the contents of that submodel.

The context menu contains the following entries:

  • Create new (only if invoked by right clicking): Creates a node-type component or starts a flow or submodelat the point selected
  • Undo/Redo: only works for top level, and applies to the whole model
  • Copy diagram: puts a copy of the model's graphics onto your desktop's clipboard, for pasting into other graphical applications
  • Cut/copy/paste/delete: move the selected part of the diagram to or from Simile's own clipboard
  • Reroute links, align to grid: tidy up the selected part of the diagram
  • Select/unselect all, invert selection: Manipulate the selection to set which components other operations will be applied to
  • Find, find next: search the submodel's contents for captions, equations or comments containing given text
  • Properties: open the submodel properties dialogue for this submodel
  • Preferences: applies to the whole of Simile

In: Contents >> Working with submodels

Working with submodels : Submodel properties dialogue

Submodel properties dialogue

The submodel properties window enables you to set the properties of a particular submodel. To invoke the dialogue box, either:

  • double-click in any blank area of the submodel, or
  • select the "Properties..." item in the context menu for the submodel.

The properties dialogue has two tabs, "Basic" for those most commonly used, and "Advanced" for those that are needed less often.

Basic properties

Control of number of instances

The most important property of a submodel is that it can exist in a number of different instances. Each instance follows the same logic in its calculations, but can differ in the values of its attributes. There are three mechanisms for controlling the number of instances of each submodel.

  • Using specified dimensions (default)

    This radio button enables you to specify that the submodel has fixed dimensions. By default, each new submodel exists only in a single instance. The dimensions can be set to be any vector or higher-order array. For example, entering 10 in the edit box, creates a vector of 10 instances of the submodel. Entering "10,10" in the edit box, creates an two-dimensional array of 100 instances of the submodel.

  • Using number of data records in file

    This radio button allows the number of instances of a submodel to be controlled by the number of data records in the file. The submodel must contain one or more fixed parameters, (i.e. a variable whose values are read in from a data file). The values for the fixed parameters are set in the normal way, and the number of records determines the number of instances created.

  • Using population symbols

    This radio button enables you to specify that the submodel is a population submodel. In this case, control of the number of instances is performed using the population symbols: creation, reproduction, immigration and extermination.

Instead of the radio buttons, Simile v6.1 includes a pulldown menu of six submodel types. When a selection is made, a message explaining the type is shown, together with entry fields for additional information  required for that type. Simple (dimensionless) submodels are now separate from those with array dimensions, and there are two predefined special-purpose types: rectangular and hexagonal grid.

 

Background shade and/or image

These three buttons are used to specify the nature of the background colour for the submodel. The "Clear background" button specifies that the submodel is actually transparent: it will take on the colour of the enclosing submodel (or the main desktop window). (i.e. it should be read as "the background is clear", rather than the instruction "Clear the background").

The "Background shade" button calls up a standard colour selection dialogue window. Use this to select the colour of the submodel's background. This is highly recommended: having coloured submodels greatly enhances the effectiveness of the model diagram in communicating the structure of the model to other people.

The "Image…" button calls up a standard file selection dialogue window. Use this to select an image file (in either gif or jpeg formats) for the background of the submodel. There are three modes for image display:

  • Tiled: If the submodel is larger than the image, the image will be repeated (tiled) across the area of the submodel; if the submodel is smaller than the image, the bottom and right of the image will be cropped to fit.
  • Centred: The image will be displayed at the centre of the submodel. If the image is larger than the submodel box, only the centre of the image will be displayed. Note that a centred image will not be displayed in the background of windows showing only that submodel, because it might look confusing.
  • Scaled: the image will be stretched or shrunk along each axis to fit the submodel exactly.

If a background shade as well as an image is specified, the background shade will be visible through transparent parts of the image, and also around a centred image if it is smaller than the submodel.

Appearance

  • Hide contents

    This suppresses the display of all model elements inside the submodel. You can do this for neatness of the diagram, so that some person looking at a complex model is spared the detail of a nested submodel. However, it is also useful if you are working with a complex model diagram, since a number of screen operations (such as deleting a model element) become quite slow with a complex model when all model elements are displayed.

  • Relative scale

    This changes the size of the model diagram elements in this submodel relative to those in its parent.

Description and comments

The Description and Comments boxes enable you to type in free-form comments about the submodel. Use this to document the date of creation, author, main features, etc.

Advanced properties

Calculation

The following options can be selected:

  • Use units in math

    This selects how physical units and dimensions are handled when checking equations in this submodel. The two mechanisms for handling units are described here. Selecting 'No' means only the first mechanism is used. 'Yes' enables both mechanisms. 'Default' uses the same setting as the submodel's parent model, or first mechanism only for the top-level model.

  • Time step index

    This enables you to specify on which time step the submodel is updated. In most models, there is only one time step (the "Time step #1" value in the Run Control window), which applies to all submodels. In that case, you do not need to do anything here. However, in certain circumstances, it is useful to be able to change this. See time step index for information on these cases.

The following options are alternatives to 'Build from components' which indicates that Simile should calculate the values of the submodel's components in the normal manner.

Enumerated types

Enumerated types are created using this dialogue box. Enumerated types are lists of names that can be chosen amongst when setting the value of a variable of that type. Please see the help page for more information on enumerated types and on how to create them.

In: Contents >> Working with submodels

 

Working with submodels : Opening a new window

Opening a new window for a submodel

You may want to open a new window for a submodel for one of two reasons:

  • to view and edit the submodel independently of the main model
  • to save the submodel to file, or load a previously-saved submodel into the current model.

You open up a new window for the submodel by selecting Pointer mode from the tool bar, then double-clicking on the submodel envelope. Note that it is fairly easy to miss, and click inside the submodel. In that case, the submodel properties dialogue will appear. If that happens, click "Cancel" and try again.

Note that any changes you make to the submodel in its own window are simultaneously made to the submodel in the desktop window. You can edit the model diagram using the same set of tools as are available in the desktop window. Note however, that the toolbars may not be displayed if the window is not large enough. All the tools must then be accessed through the menus.

Note also that any actions that change the scroll region of the new window, for instance growing it beyond its current scroll region, will alter the scale of the submodel relative to its parent. To understand this, consider the following terminology:

  • The submodel panel is that part of the main desktop window occupied by the submodel, i.e. that is enclosed in the submodel envelope.
  • The submodel window is the separate window opened up for viewing and editing the submodel.
  • The submodel scroll region (also called the canvas) is the area behind the submodel window that is available for the submodel diagram.

Thus, the submodel window reveals part of the canvas. We can move around the canvas by scrolling the window with the side and bottom scroll bars. Only if the window is actually the same size as the canvas, will not need to scroll the window to see the whole canvas.

Note, now, that the submodel canvas always represents the same area as the submodel panel. Thus:

  • if you increase the size of the submodel canvas, then the size of model-diagram elements in the submodel panel will decrease, relative to the other elements in the desktop window; and
  • if you increase the size of the submodel panel, and use the zoom to fit option for the submodel window, then the size of model-diagram elements in the submodel panel will increase, relative to the other elements in the desktop window.

In all cases, however, you can also adjust the relative scale of the submodel without opening up a separate window for it, by using the relative scale slider in the submodel dialogue window.

In: Contents >> Working with submodels

Working with submodels : Saving a submodel to file

Saving a submodel

In order to save a submodel to file, open a new window for the submodel, then select the "Save" command on the "File" menu of the submodel window.

The submodel will be saved as a .sml file. In fact, this file will contain nothing to indicate that it is a submodel: Simile makes no distinction between a main (top-level) Simile model saved to file, and a submodel saved to file. If the submodel had influences coming into it from other parts of the model, then the influenced variables in the submodel will be converted to "Input Parameters", indistinguishable from input parameters in top-level models specified by the model designer. The only thing to note is that these automatically-created input parameters will appear red in the model diagram if you have not specified "Min" and "Max" values for them in the equation dialogue prior to saving the submodel.

In: Contents >> Working with submodels

Working with submodels : Importing a submodel from file

Loading a saved model as a submodel

In your current model, create an empty submodel. This should be fairly large, so that the diagram of the model you will be inserting is not all squashed up.

Select pointer mode, and double-click on the boundary of the submodel. (If you miss, you will see the submodel properties dialogue window: cancel this and try again). You will see a new model diagram window, just like the main desktop window except smaller. It will have the same menu as the main desktop window.

Select the "Open" command from the "File" menu, and locate and load the Simile model (.sml) file.

You will see the loaded model in both the new submodel window, and in the round-cornered submodel box in the main Desktop window. You can close the submodel window, or keep it there if you want to work on the submodel and it is too small in the main Desktop window. Note that, if you enlarge the submodel window, you will probably want to do Zoom to fit in order to get the model submodel diagram to occupy the whole of the available space.

Any model or submodel saved to file can be treated as a submodel or as a model. No real distinction is made between the two concepts. If you load a previously-saved model into a submodel window, then it will become a submodel in the current model. If, on the other hand, you load a previously-saved submodel into the desktop window (i.e. the main, top-level window), then it will become a model in its own right.

So, in order to load a previously-saved submodel as a stand-alone model, all you need to do is to start a new session of Simile (or select the "New" command from the "File" menu in the desktop window), then select the "Open" command from the "File" menu in the desktop window, and find the .sml file that contains the previously-saved submodel.

Any variables in the submodel that had previously received influences from outside the submodel automatically become "Input parameters". If they had been previously assigned min and max values, then you will get a slider for each such variable when you come to run the submodel (now a model). Any such variable that had not been assigned minimum and maximum values will appear red when you load the submodel, and you need to open up the equation dialogue for this variable and either:

  • unclick the "Input parameter" check box and enter a value into its equation dialogue; or
  • enter min and max values.

In: Contents >> Working with submodels

Working with submodels : Multiple-instance submodels

Multiple-instance submodels

Multiple-instance submodels are one of Simile's most valuable features, for constructing object-based models. For real-world objects, such as a tree, it is useful to be able to model several particular instances of the object, each acting in the same general way, though differing in their particular attributes.

  • Fixed membership submodels have a specified number of instances
  • Per-record submodels have one instance for each set of data loaded for its parameters.
  • Population (variable membership) submodels offer control over the number of instances using special model elements
  • Special-purpose submodels have many instances, and extra features which assist in modelling particular common phenomena, e.g., spatial grids

Working with submodels : Multiple-instance submodels : Fixed

Multiple-instance submodels: fixed membership

A fixed-membership submodel is one type of multiple-instance submodel. In this case, the number of instances is fixed throughout the simulation run.

By making a fixed-membership multiple-instance submodel, we are saying that:

  • The model contains a fixed number of objects, each of which behaves according to the same rules (represented by the model elements and equations inside it).
  • Each object may (and usually does) differ in one or more numeric values: the initial value for compartments, or the values of parameters.

When should I use a fixed-membership multiple-instance submodel?

Fixed-membership submodels are useful for handling many forms of disaggregation in model design. You may, for example, be interested in modelling the changing population of a country like the UK. You first model has a single compartment, representing the total population size. You then decide to represent this information on a regional basis, in order to capture differences in population parameters in different regions. You have now disaggregated your model into multiple regions. Your model diagram looks very similar: the only difference is that the part representing population dynamics is now wrapped up in a multiple-instance submodel, one instance for each region. This is a fixed membership submodel, because the number of regions is fixed.

Conversely, fixed-membership models can be used for scaling up. To take the previous context, you might have begun making a model of the population growth of just one region. You then want to scale the model up to the whole of the UK. Again, you wrap up the original model and make it into a fixed-membership, multiple-instance submodel.

Although disaggregation and scaling up are conceptually very different - in fact, opposite - activities, the appearance of both the before and after model diagrams is the same in both cases. The only difference comes in terms of the initialisation and parameterisation for the original model.

How to make a fixed-membership submodel

  1. Use the submodel tool to drag a submodel envelope on your model diagram. The submodel may be drawn in an open area of the model diagram, and not enclose anything. Or you can drag the submodel around existing elements on your model diagram, if you want those enclosed in the submodel.
  1. Open up the submodel properties dialogue by selecting the Pointer tool, then double-clicking anywhere in the blank area of the submodel (not on its border, and not on any existing elements). Note that the "Generated set" radio button has been selected by default. This term denotes that the submodel is to be fixed-membership. Enter a value into the "Dimensions" box corresponding to the number of instances you want. Click on the "OK" button.
  1. Back on the model diagram, the submodel's appearance has now changed. Its simple border has now been replaced by multiple lines on the bottom and right, indicating that there is a fixed number of multiple instances (it's meant to look like a stack of cards).

Dimensions of a fixed-membership submodel

The dimensions of a submodel are a list of one or more dimensions, separated by commas if there is more than one. Each dimension can be:

  • An integer greater than 1, or
  • The name of an enumerated type, or
  • size(x), where x is the name of another component in the model. The dimension then has the same value as the dimensions of the named component.

If there is just one dimension, the submodel's instances form a one-dimensional array, or vector, in which each instance has a unique index which is a number starting from one (if the dimension is numerical) or a member of the enumerated type whose name is the dimension.

If there is more than one dimension, the submodel instances are arranged in an n-dimensional array, with each instance having indices corresponding to its place long each dimension.

How to make the different instances different

There are two main ways in which you can make one instance different from the others.

  • You can give each instance a different initial value for one or more compartments.
  • You can give each instance a different value for one or more parameters.

Conceptually, these are very different. In the first case, you are saying that the differences between the individuals are simply in terms of the state they happen to be in when you start the simulation. In the second case, you are saying that the individuals differ in some intrinsic property. You can of course mix these: individuals may differ in both their initial state and their parameterisation.

There are several methods you can use to assign different values to different instances. These techniques apply equally to compartments and parameters.

Load the values from a file

If you put a fixed parameter inside a fixed membership submodel, then when you run the model, there will be an entry in the file parameters dialogue requiring values for this parameter. The data you enter will have to include a value for each instance of the submodel.

Generate the values randomly

Enter the expression

rand_const(0,10) (replacing 0 and 10 by whatever range you want)

in the Equation box for the compartment or parameter to cause each instance to be assigned a value randomly picked from the specified range. rand_const(A,B) samples from a rectangular probability distribution over the range A...B: Simile also alows you to use values from other distributions, e.g. Normal (and it is possible to engineer these yourselves).

Note that if there is no explicit indication that they return a constant value, Simile's statistical functions return a new sample from the given distribution on each time step. If you are using a sampling function to set up a multiple instance submodel with data that conforms to a statistical pattern, it is probable that you want each instance to keep the value it was given when the model was initialized or reset. This can be arranged by wrapping the statistical function in the at_init() function, e.g., at_init(gaussian_var(50,10)).

Select elements from an array

If your submodel has a small number of instances, you can explicitly list the value for each instance in an array, and select from this array the value for each instance.

Let's say you want to model the loss of water from 5 tanks. The tanks differ in terms of the initial amount of water they hold: say 10,5,20,50 and 9 litres. You have made the water flow model into a submodel with 5 instances. You could use the following expression in the Equation box to initialise the water compartment:

element([10,5,20,50,9],index(1)) (replacing [10,…,9] by whatever you need)

This selects the value 10 for the first instance, the value 5 for the second, and so on. See the help information on the functions element and index for more information.

Alternatively, you could have a separate array variable, say "initial_water", whose only job is to hold the array of values, take an influence arrow from it to the compartment, then select a value from that array for each instance:

initial_water = [10,5,20,50,9]

water = element([initial_water],index(1))

Use conditional expressions

You can develop expressions conditional on the value of index(1) (i.e. the numeric index of each instance) in a wide variety of ways. For example, you want the first three instances to have a value of 20, and the rest 10, then you could use the expression:

if index(1)<=3 then 20 else 10

Use a sketched graph or built-in table

You could use the sketch graph or built-in table functions in the equation dialogue to specify the values of the compartment or parameter as a function of index(1). This is particularly appropriate if the instances have a natural ordering, e.g. age-classes in a population, or soil layers, when the quantity under consideration might be considered to have some ordered relationship with the instance number.

The in_preceding() function

This calculates the value of its argument in the immediately preceding instance of the submodel. For instance, a variable with the equation in_preceding(prev(0))+1 will have a value of 1 in the first instance, 2 in the second, and so on up to the total number of instances in the last instance, irrespective of the submodel's dimensions.

Variables exported from a fixed-membership multiple-instance submodel

If you take an influence from a variable (a) in a fixed-membership multiple-instance submodel to another variable (b) in the same submodel, then b sees a as a scalar variable: i.e. as having a single value. You could use an expression for b like

3*a

How can this be, when we know that a has one value for every instance of the submodel? It's because the equation is expressed as a general rule: whatever value of a a particular instance has, then its value of x is 3 times greater.

However, things change when we take an influence from a variable (a) in the submodel to one outside (c). Because c is outside the submodel, it can see all the values of a. a must now be treated as an array of values, not as a single value.

An array is denoted by enclosing the name of the variable with [...], thus a inside the submodel has become [a] outside it. Thus, when we open up the Equation dialogue window for c, the influencing variable appears as an array, and its name is enclosed in square brackets. And the expression for calculating c must do the same. Thus, legitimate expressions for c are:

3*[a] c becomes an array with as many elements as a, each multiplied by 3

sum([a]) c has a single value, equal to the sum of the elements in the array [a]

In: Contents >> Working with submodels

Working with submodels : Multiple-instance submodels : Per-record submodels

Submodels with one instance per data record

It may be that you want to run your model with many different datasets, and these datasets each have different numbers of records which are supposed to correspond to instances of a submodel. Or perhaps you have nested submodels, where the membership of the inner submodel is different in each instance of the outer submodel, with the actual memberships being determined by the numbering of data records in a file.

For these cases, Simile provides the option of setting the number of instances according to the number of data points given for the fixed parameters within the model. To use this option, open the submodel properties dialogue and select the second radio button on the "Control of number of instances" panel, captioned "Using number of data records in file". The submodel will have the same border style as a population submodel, but should not contain any of the population control symbols. It must contain at least one fixed parameter.

When running the model, you must provide data for the fixed parameter(s). For each instance containing the per-record submodel, there must be at least one data item (the submodel must have at least one member) and the indices should run from 1 consecutively to the number of instances. You can have nested per-record submodels, possibly with the memberships of both the outer and inner submodels being set by the same parameter.

In: Contents >> Working with submodels

Working with submodels : Multiple-instance submodels : population

Multiple-instance submodels: population

A population submodel is one type of multiple-instance submodel. In this case, the number of instances may vary throughout the simulation run.

By making a population submodel, we are saying that the model contains a collection of objects, and individual objects can be created and destroyed during the course of a simulation run. The objects may (and usually do) differ in their attributes, but this is not such a central idea as it is for fixed-membership submodels: we can get interesting behaviour from a population model even if all the individuals have the same initial state and the same parameterisation.

See also the 6th video in the Simile Tutorial Series.

When should I use a population submodel?

When I introduced the idea of fixed-membership multiple-instance submodels, I said that you can decide to have one in your model either by breaking something into smaller pieces (disaggregation), or by representing a larger unit as a multiple of a set of smaller units (scaling up).

Similar ideas apply to using a population submodel, but we use slightly different language. If you are interested in the behaviour of some large unit, such as the population dynamics of the deer on an estate, then you may consider it appropriate to model this in terms of all the individual deer on the estate. This is more a process of decomposition of the population into individuals rather than disaggregation. With the latter term, the small unit is like a miniature version of the larger one, with all the same attributes, whereas an individual deer is not a smaller version of a population. Conversely, you may have first modelled one deer, following its life history, then decided to make a model with lots of those rather than just one. This is more a process of multiplication rather than scaling up. (There is no standard terminology here. Don't worry too much about the terms used: the important point is to see that something different is going on with populations.)

How to make a population submodel

  1. Use the submodel tool to drag a submodel envelope on your model diagram. The submodel may be drawn in an open area of the model diagram, and not enclose anything. Or you can drag the submodel around existing elements on your model diagram, if you want those enclosed in the submodel.
  1. Open up the submodel properties dialogue by selecting the Pointer tool, then double-clicking anywhere in the blank area of the submodel (not on its border, and not on any existing elements). Click on the "Population" radio button. Do not enter a value into the "Dimensions" box. You can use the Creation symbol to specify the initial number of individuals in the population. Click on the "OK" button.
  1. Back on the model diagram, the submodel's appearance has now changed. Its simple border has now been replaced by a double line on the bottom and right, and a double line on the top and left.

How to make the different instances different

In general, you can use methods that are the same as or similar to those used for fixed-membership multiple-instance submodels, with some differences:

  • Use the channel_is() function. If your population has multiple channels (creation, immigration and reproduction symbols) then an equation can apply this function to a parameter corresponding to an influence from one of the channels to get a boolean result which is true in each individual that appeared due to that channel.
  • Use the parent() function. If your population contains a reproduction symbol, an equation can apply this function to a parameter corresponding to an influence from this symbol. The result is the index number of the individual that became the parent of the current individual, or 0 if the current individual appeared due to some other channel.
  • The in_progenitor() function evaluates its argument as if in the population individual whose reproduction channel caused the current individual to come into existence. For instance, in_progenitor(index(1)) is equivalent to parent().
  • You cannot put a file parameter (fixed or variable) in a variable-membership submodel. This is because the table created by loading the data for a file parameter has a fixed number of values, and cannot be matched to a variable number of submodel instances.

Variables exported from a population submodel

With a fixed-membership multiple-instance submodel, variables are exported as arrays, since Simile knows precisely how many elements there are, and this number remains fixed for the duration of the simulation run. However, the number of instances for a population submodel can change dynamically during the course of the simulation run. Therefore, the set of values for a variable are exported as a list rather than an array. The number of elements in a list can vary, and (unlike an array) we can attach no particular significance to "the third element" of the list (since this might refer to quite different instances at different times during the course of the simulation)

Note that although an array can be passed around from one variable to another, a list must be processed into a scalar (single-valued) quantity as soon as it is received. Since any quantity exported from a population submodel must be a list, this means that the receiving variable must derive a single value from this list: its sum, perhaps, or its largest value, using a function capable of having a list as one of its arguments.

Special model diagram elements for population submodels

Four of the model diagram elements are only used in population submodels. They are:

  • initialisation, for specifying the initial number of instances;
  • migration, for specifying an absolute rate of creating new instances;
  • reproduction, for specifying the rate per individual for creating new instances; and
  • extermination, for specifying the conditions under which an instance is removed.

See the appropriate entries for further information on how to use these elements.

In: Contents >> Working with submodels

 

Working with submodels : Multiple-instance submodels : Special-purpose submodels

Special-purpose submodels

Generally, a Simile submodel has no built-in semantics besides what is described above for specifying its dimensions and how the number of instances is determined. However, certain uses of submodels are so common that we have decided to create special types of submodel to better support these uses, making models using them simpler and computationally faster. So, instead of the three radio buttons, Simile v6.1 includes a pulldown menu of six submodel types. When a selection is made, a message explaining the type is shown, together with entry fields for additional information  required for that type. Simple (dimensionless) submodels are now separate from those with array dimensions, and there are two predefined types:

Rectangular grid

The submodel has two dimensions and represents rectangular patches that cover a larger rectangular area. In addition to the usual features of array submodels, rectangular grid submodels can contain the following:

  • The functions row_id() and column_id() can be used to get the indices of each instance's row and column in the grid (these are equivalent to index(2) and index(1) respectively)
  • An influence's properties can be edited to enable the role "Include list of values from up to 8 grid squares...". When this role is enabled, the equation of the destination component can refer to the source component values in two ways: by the normal name, which just gives the value in the same submodel instance as normal, or by the name prefixed with "from_8_nbrs_", which gives a list of values from the instances representing the 8 grid squares adjoining the current one at sides or corners. There may be fewer than 8 values, e.g., if the current square is on the side or corner of the whole grid.

Hexagonal grid

The submodel has two dimensions and represents regular-hexagonal patches that cover a larger, roughly rectangular area in a honeycomb pattern. The patches have vertical sides, and odd-numbered rows are shifted half a width to the right so they tesselate with the even-numbered rows above and below. Hexagonal grid submodels can contain the following:

  • The functions row_id() and column_id(), as for rectangular grids
  • The functions hex_centre_x() and hex_centre_y() which give the x and y coordinates respectively of the centre of the hexagon relative to the bottom-left corner of the grid, in multiples of the length of one side of a hexagon
  • The functions hex_vertices_x() and hex_vertices_y() which give arrays of six values that are the x and y coordinates of the vertices of each hexagon, in the same terms as the centres above
  • An influence's properties can be edited to enable the role "Include list of values from up to 6 grid hexagons...". When this role is enabled, the equation of the destination component can refer to the source component values in two ways: by the normal name, which just gives the value in the same submodel instance as normal, or by the name prefixed with "from_6_nbrs_", which gives a list of values from the instances representing the 6 grid hexagons sharing an edge with the current one. There may be fewer than 6 values, e.g., if the current hexagon is on the side or corner of the whole grid.

More about values from neighbours

These special influence roles are intended to replace the requirement of having a separate self-association submodel representing the neighbour relationship between members of spatial grid arrays, and moving values between neighbours by taking them out to this association submodel by one role and back by the other. The lists of values they generate are variable-membership (due to different neighbour counts at sides/corners) so must be summed or applied to some other cumulative function before being assigned to the value of a local variable. However, all the usual operations can be applied to them before this. In fact the grid cell submodel itself can be made variable-membership, by adding a condition component to it just as is done for ordinary array submodels. This could be useful if we have an irregularly shaped area that we want to break down into grid cells -- in this case, set the dimensions of the grid so it covers the whole area, then add a condition that is true only for those cells that fall into the irregular area. Cells will then have fewer neighbours if they are at the edge of the selected area, and a single 'island' cell would have no neighbours, with the neighbour influence roles supplying empty lists.

Additionally, the lists have indices from special enumerated types representing the different directions in which the neighbour can lie. For the rectangular grid these are the points of the compass: nw, n, ne, etc. For the hexagonal grid these correspond to odd-numbered hours on a clock face, and so are written 1h, 3h ... 11h. These can be used like members of any other enumerated type, and to make a multi-instance submodel in which they are the indices, the dimension should be rect_nbr or hex_nbr. Now, because Simile v6.1 also introduces the ability to use the element() function to select sublists from lists, we can get other sets of neighbour data that might be useful, e.g.,

element({from_8_nbrs_size}, ["n","w","e","s"])

will produce a list of the values of 'size' in only the neighbouring rectangles that share a whole side with the current one.

element({from_6_nbrs_fire}, ["1h", "3h", "5h"])

will produce a list of the values of 'fire' in only the neighbouring hexagons further right than the current one. Note though that this could also be done by comparing the results of the hex_centre_x() function in the local and neighbouring hexagons, e.g., is 'fire' true in any neighbour hexagon to the right? use:

any({from_6_nbrs_fire} and {from_6_nbrs_xctr}>xctr)

...where xctr is another variable with equation hex_centre_x() and an influence to the current one with values from neighbours enabled.

In: Contents >> Working with submodels

Working with submodels : Plug-and-play modularity

Plug-and-play modularity using submodels

"Plug-and-play" modularity means the ability to replace one module in a model with another, without having to specify how the module's inputs and outputs link up with the rest of the model. This requires that the modules to be swapped share the same interface to the rest of the model.

In Simile, a module is a submodel. There is a mechanism for replacing one submodel with another: simply open a separate window for the submodel, and use the File: Open command to load a new submodel. However, this by itself does not automatically remake all the links between variables in the submodel and those in the rest of the model.

In order to have plug-and-play modularity, we need to specify the interface between a submodel and the rest of the model. This means stating which variable in the submodel is linked to which variable in the main model, and the nature (dimensions, units) of the two variables. This specification is saved in a separate interface specification file, and can be loaded when we create a new submodel, in order to re-make all the linkages.

Demonstration of plug-and-play modularity

  • Step 1: Build a model with submodels
  • Step 2: Save one of the submodels as a separate model
  • Step 3: Save the interface specification
  • Step 4: Clear the submodel
  • Step 5: Load an alternative version of the submodel
  • Step 6: Load the interface specification file

In: Contents >> Working with submodels

Working with submodels : Plug-and-play modularity : Step 1



Step 1: Build a model with submodels

Next Step >>

In this simple example, we make a model of the interaction between plant
growth and soil water. We use a submodel for each component. Note that
at this stage we do not actually need to use submodels: they merely serve
to show the main functional components of this model.

Next Step >>

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Plug-and-play modularity : Step 2

Step 2: Save the submodel as a separate Simile model

Next Step >>

We first open up a separate window for the soil submodel by double-clicking on its boundary.

We now select the "Save as..." command from the submodel window's File menu (not the menu for the main model window).

Next Step >>

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Plug-and-play modularity : Step 3



Step 3: Save the interface specification


Next Step >>

We save the interface specification for the interface between the soil
water submodel and the rest of the model, using the "Save Interface"
command from the "Model" menu of the submodel window.


Next Step >>

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Plug-and-play modularity : Step 4



Step 4: Clear the submodel


Next Step >>

We clear the submodel, by selecting File: New from the submodel window's
menu.


Next Step >>

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Plug-and-play modularity : Step 5

Step 5: Load an alternative version of the submodel

<< Previous Step Next Step >>

We now load an alternative version of the submodel.

This new submodel also has a variable called "Soil water" (though in this case it is a Simile variable, not a compartment), and a flow called "transpiration". Note also that this submodel is structurally different from the first submodel: all that matters for plug-and-playability is that the two models have the same interfacing variables: the rest of their structure is irrelevant.

At this stage, the linkages are not re-made. The Soil submodel contains an unsatisfied input parameter "Plant biomass", while the main model contains an unsatisfied input parameter called "Soil water". These undefined elements are shown in red.

Next Step >>

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Plug-and-play modularity : Step 6



Step 6: Load the interface specification file

We select an interface specification file using the "Load interface"
command from the "Model" menu of the submodel window (again, not the main
model window).

Now, Simile automatically re-makes the linkages between the submodel and
the rest of the model.

Finally, we can close the submodel window, since it is not required any
more. We now have the new model!

In: Contents >> Working with submodels >> Plug-and-play modularity

Working with submodels : Conditional submodels

Conditional submodels

A conditional submodel is used when there are conditions under which a submodel, or an instance of a fixed-membership multiple-instance submodel, may or may not exist. By "exist" we mean that Simile evaluates the expressions in the submodel. The existence of each instance of the submodel is determined by evaluating a Boolean expression in a condition symbol placed inside the submodel.

The conditional submodel may represent a phenomenon that only occurs at certain times, for instance bush fires. Or it may represent a phenomenon that occurs in some, but not all, of the members of a group; for instance, if an area of interested is represented by a grid, then some vegetation types, e.g., forest, may be present in only some of the grid squares, so the processes associated with them sould be represented in a conditional submodel of the grid-square model.

If the submodel has influence arrows going from inside to variables outside itself, then:

  • if the submodel exists, the values emerging from the submodel are those calculated from the variables in the normal way;
  • if the submodel (or instance of it) does not exist, then a value is not exported for each variable: there is no value, since the variable just doesn't exist.

This means that we cannot be sure how many values are going to be exported from a single variable inside the conditional submodel. For a simple submodel, there could be zero or one values. For a fixed-membership multiple-instance submodel, there could be 0…n values, where n is the number of instances for the submodel.

Therefore values are always exported as a list from a conditional model, since a list (as opposed to an array) is the data structure used when the number of values in the data structure can vary dynamically over time. A list must be processed as soon as it is received: it cannot be passed around as a persistent data structure. Typically, you will simply use the sum function to add the values in the list together.

A few more detailed considerations:

  • The condition equation itself, and the equations of any variables in the submodel that affect the condition, must be evaluated in every case. If the condition comes out false, the values of these variables are discarded.
  • The condition cannot depend on a value outside the submodel that itself depends directly on values inside, since getting this value would require the existence status of the submodel to be already known. Simile reports this as a circularity problem.

In: Contents >> Working with submodels

Working with submodels : Iterative submodels

Iterative submodels

Motivation

System-dynamics models are usually a very naturalistic way of describing a process that takes place. The actual way in which one quantity influences another in the problem domain is mirrored by one variable influencing another in the model. If a calculation must be repeated a certain number of times with each value depending on the previous one, it can be done in a multi-instance submodel using the in_preceding() function to allow each instance to refer to values from the previous one.

However, we may wish to create a model of a system in which our best understanding of how a certain quantity is evaluated involves a procedural computation in which an instruction loop is repeatedly executed until some exit condition is met. Using a multi-instance submodel is wasteful because the number of iterations needed may vary widely, and we are not interested in values from iterations before the last one. An example is the Ball-Berry model of stomatal conductance. Although in nature stomatal conductance is the result of a purely incremental process, the easiest way to evaluate it in a model of plant physiology is to include an iterative calculation with a finishing condition. If performing a calculation like this in a procedural programming language such as c++, you would use a 'while' loop. Such a calculation could be included using Simile's ability to implement a submodel's behaviour using a piece of code in c++, but this is not ideal, since:

  • One shouldn't need to learn a programming language to use Simile
  • It defeats the point of the model's behaviour being visually explicit

Simile therefore allows iterative processes to be represented graphically. This involves a mechanism to specify that the components inside a submodel are evaluated repeatedly until a specified end condition is met. With this system, a modeller can not only implement iterative approximations to natural processes such as the Ball-Berry model -- they can also create graphically explicit procedures for solving abstract problems, such as finding prime numbers or efficiently sorting an array.

Implementation

An iteration symbol and a property for influence arrows are included, to allow a loop to be executed multiple times within one time step. Such looping may be required, for example, when the value of a variable cannot be calculated directly from others, but is found by trying many successive values to minimise some error function.

The basic elements of an iterative loop are as follows.

The iteration symbol contains the condition that marks the successful convergence of the iteration. An influence arrow coming from the alarm symbol can be used as an argument to the function iterations( ). This function returns the number of iterations made so far. This function can be used to set the initial value (also called the guess) for the loop, i.e. when the number of iterations so far is equal to zero. If the number of iterations so far is one or more, then the result of the last calculation should be used. Since the last calculation depends on the result calculated from the guess, a circular loop of influences is present. Normally, Simile would reject this loop at build time, but the definition of the iterations() function makes it explicit that the influence from the alarm symbol refers to its value on the previous iteration, and therefore cannot be part of a circularity.

You do not have to use the iterations( ) function; if the results of previous iterations are irrelevant, as for instance in a generate-and-test algorithm, you may not need to have any influences from the alarm symbol at all. Alternatively, if each result does depend on previous ones but the actual number of iterations is irrelevant, you can use the boolean value of the alarm symbol directly to choose between starting a new iterative approximation (true) and refining the result of the previous iteration (false).  In this case you would get a circularity, but setting a property of the influence arrow: "Use values made in same time step" to true, allows the loop to be processed. You also need to set this property on influences that convey the result of the last iteration step for use at the start of the following step. Influence arrows with this property set are drawn with a dashed line, and the equation that uses their value gets the one from the previous iteration rather than the current one. To set this property for an influence arrow, double-click on it to invoke the property dialogue box.

It is unlikely that any of the above description is comprehensible without an example. The included example model for Ball-Berry stomatal conductance poses a problem for conventional System Dynamics modelling tools because it depends upon the solution of the following pair of simultaneous equations.

Gs = g0 + g1 * A * H / Ca

A = Gs * AQ

Apart from the external parameters, g0, g1, H, Ca and AQ, the equation for Gs depends only on A, and the equation for A depends only on Gs. In this implementation, the loop is opened, by introducing a place-holder for Gs, called Gs_0. This variable is calculated from A. A is calculated using Gs. A guess is made for the initial value of Gs. Subsequently, Gs is set to the last calculated value of Gs_0. The influence arrow from Gs_0 to Gs is dashed, indicating that the value from the previous iteration is to be used. The alarm symbol terminates the iterative loop when Gs and Gs_0 differ by less than one part in one thousand.

Caution

Alarm submodels should always behave as if everything in the submodel is executed repeatedly until the finishing condition is reached. However, Simile always tries to do as little work as possible, so this may not actually happen. For instance if the submodel contains constants, these are not set in each loop but set just once before the loop starts.

Also, if the exit condition in the iteration symbol does not depend directly or indirectly on a certain value in the submodel, then Simile will assume that that value is not relevant to the loop calculation and it will instead be calculated only once after the loop has finished. For instance, we made a test model that carried out a merge sort by iterating until the required number of merges were done. Since we know that for an array of n elements, the number of merges needed is log2(n), we just had a condition that counted this number of iterations. However, this resulted in only one actual merge being done rather tha a series to build sorted sublists of increasing lengths. The fix was to make the exit condition depend on the output array, to force it to be merged every cycle. This could have been done by actually checking that each value was larger than the preceding one, but it is simpler just to check for some dummy never-true condition e.g. sum([out])!=sum([out]) as well as the right number of iterations having been done.

Another problem is that if you make a mistake when building an iterative submodel, you may end up with the exit condition never being met. The model will then go into an endless loop. To escape the loop, hit 'pause' on the run control, and wait for the 'model seems to have got stuck' message -- you can then exit the model and try to fix the problem.

In: Contents >> Working with submodels

Working with submodels : Time step index

Time step index

Introduction

Specifying different time step indices for different submodels is an advanced topic. It can lead to misleading results, and should be used only in accordance with the following notes.

By default, all the model state variables are updated using the same time step. When Euler integration is used to update the state variables, differential equations are, in practice, solved as if they were difference equations, with a small but finite δt. By specifying δt , the time step, to be reasonable small, the results of the difference equations are the same as the expected results of the differential equations. You can, however, take advantage of this ability to specify δt, to use different time steps for different submodels.

A common example is in the calculation of compound interest on money in a savings account. It is important when specifying that interest is to be compounded, that the period over which the compounding occurs is specified. For example, the same investment in two savings accounts, both paying compound interest at 12 per cent, will yield different amounts after one year if one account compounds monthly and the other compounds annually. In modelling these accounts, you would need to specify a different δt, the time step, for each, in order that the state variable (the amount in the account) was updated at different rates, either monthly or annually.

Another reason for having several time steps is when a model contains components that behave on different time scales. For instance a model of a grazing system might contain a lot of plants, with physiological processes that can be modeled with a time step of a day, and animals whose movements would be modeled on a time step of seconds or minutes. To model all the plants at the shorter time step would be inefficient, so the animals are handled by a separate submodel which is run with a shorter time step.

It is possible to specify up to seven time step indices. For each new time step category that you request, an extra Time step #x entry is added in the Run Control window, and that is where you specify the actual time step (e.g. 0.01) to be used for each index.

Notes

The following notes will help you use this concept:

  • Note that the TIME UNIT is the same over the whole model, and that all flows are expressed per time unit. The run control also specifies how long the model should be run for, in terms of time units.
  • Each submodel TIME STEP is specified in terms of a multiple of the time unit. The submodel time steps *must* be ordered from long to short, #1 must be the longest, #7 the shortest. During each time step that affects a submodel (i.e. its own and all longer ones) all the elements of the submodel are updated. Note, particularly, that since flows are expressed in time units, a compartment's value does not change each time step by the value that is entered (or calculated) for the flow, but by the same multiple of that value as the time step is of the time unit.
  • To refer to the time step in the model, use the function dt().

Special cases

In addition to the seven time step indices available, there are three special cases:

  • "Initialize only" denotes that the submodel should be updated only when the model is built.
  • "New params only" denotes that the submodel should be updated only when the model is built or when it is reset after new values for fixed parameters have been loaded.
  • "Reset only" denotes that the submodel should be updated only when the model is built or when it is reset.

In none of these cases will the submodel be updated during the simulation.

Example

For the example of compound interest given above, set the time step index for the annual submodel to #1 and for the monthly submodel to #2. In the run control, you will then need to set time step #1 = 12 and time step #2 = 1. Flows in both submodels will be expressed in the same time units, in this case, per month.

Note that this is exactly equivalent to time step #1 = 1 and time step #2 = (1/12). Then the implicit time unit is one year, and the flows will be expressed on an annual basis.

As a final point, note that it is possible to set explicitly the time unit for each flow. Enter explicit physical units such as kg/week or kg/day. If the compartment has compatible physical units, such as kg, then the appropriate conversion will be performed. If you do this, note especially that you must be consistent throughout a network of flows.

In: Contents >> Working with submodels >> Submodel properties

 

Working with submodels : Satellite submodels

Satellite submodels

A satellite submodel is one that has a single role arrow that connects to it from another submodel. An example is illustrated in the Role arrow topic. Put simply, the effect of the role arrow is to allow the satellite model to behave in some ways as if it were a submodel of the base model, while still also being a submodel of the model actually containing it. Each instance of the satellite model is associated with an instance of the base model, and influences running between the two will only reference data between base model instances and their own associated satellite model instances. By default there is one satellite model instance per base model instance, but this can be made more by giving the satellite model its own dimensions, or nesting it in another submodel which has dimensions. Also satellite models can be conditional, so some base model instances have different numbers of satellites, or none at all.

Satellite submodels are not used very often, because most modelling problems are expressed more clearly by association submodels. But they are worth discussing because they are the simplest use case of the role arrow, so they are a good way of understanding its semantics, which remain the same when it is used in more complex cases. Also, some problems are best modelled in terms of satellite submodels.

Let's say that you have a multiple-instance submodel containing information on the species and volume of a set of individual trees: each instance is one tree. You would like to find the total volume of all trees belong to species 1.

This is easy to do if you have model the trees using a fixed-membership submodel (i.e. assuming that you have a fixed number of trees). You simply take influence arrows from the species and volume variables inside the submodel to a variable outside (say total), and give total the equation:

total = sum(if [species]==1 then [volume] else 0)

[species] and [volume] are both arrays with the same number of elements, and Simile's array language matches them up. If you use a population submodel to model the trees, then you do not have a problem: you can use more than one list in the arguments of a Simile function or operator, provided they always have the same length, and the result will be a list of the same length, which is fine so long as it is not assigned to the result without being summed or otherwise converted into a single value. The equation would be:

total = sum(if {species}==1 then {volume} else 0)

If you want to get lots of summary information about trees of one particular species, then rather than summing the results of a conditional expression like this for each one, you could make the equations simpler by creating a satellite submodel with variables for the same values that are in the base model. In the above case, it would involve creating a new submodel for the species 1 trees, using a single role arrow from the tree submodel to this satellite submodel, and entering the condition "species==1". An instance of this submodel will be created for each tree of species 1, and not for the others. If you then take the "volume" value into the submodel, then you can extract the volumes just for species 1.

In: Contents >> Working with submodels

Working with submodels : Association submodels

Association submodels

Association submodels are used to contain properties of relationships between one or more other submodels. If only one submodel is involved, the relationship is between different instances of the submodel. If there are two submodels, the relationships are between the instances of the two submodels. An association submodel (which looks just like a normal submodel) is used to contain elements that are held in common between the submodel instances taking part in the association. In effect, these elements do not belong to just one or other submodel but to both. For instance, the concept of a salary requires an employer paying the salary as well as the employee receiving it.

Association submodels are often used to represent a model concisely that otherwise would require repetition. If you are familiar with object-oriented programming, you will notice that association submodels are similar in concept to association classes.

For more information:

Terminology

A 'base submodel' is a submodel that takes part in an association.

A 'relation' is an association between instances of the same base model.

A 'role' is the arrow that connects a base submodel to an association.

To create an association submodel:

  1. Create one or more multiple instance submodels that will be associated, each playing a role in the association. These are the base submodels.
  2. Create unique identifying variables in the base submodels. The variables allow unique identification of an instance. This is easy to specify, using variables taking the value of the submodel index (or indices).
  3. Create a single instance submodel which will be the association submodel itself, containing variables that specify the association.
  4. Draw role arrows from the base submodels to the association submodel. The role arrows should be given meaningful names indicating the role the instances of the base submodel play in the association. Meaningful role names make specifying the equations in the association much easier.
  5. Add a condition symbol in the association submodel specifying when the association holds true. The condition is an expression involving the identity variables of the base submodels.
  6. Include in the association submodel all the variables that belong equally to all base submodels.
  7. Draw influences between relevant variables in associated submodels and the association submodel and specify these variable's equations.

To follow this in practice:

Note that there are some advanced aspects of optimising the performance of models using associations For more information please see:

In: Contents >> Working with submodels

Working with submodels : Introduction to association

Introduction to the association submodel concept

The association submodel concept in Simile represents possibly the most significant contribution that Simile has made to the field of ecological modelling. It is a very powerful concept, with two key benefits:

  • it enables important aspects of the model design - the relationship between objects - to be represented in the diagram; and
  • it greatly reduces the computational cost of models involving interactions between large numbers of objects of the same type, thus rendering some models tractable that otherwise would simply take too long to run.

However, it's also true that a significant amount of effort is required on the part of the modeller to understand the association submodel, and how to use it in a given situation. This is partly because the ideas involved are unfamiliar, at least in the formal, computational way needed in a modelling environment such as Simile; and partly because the ideas are difficult. However, for the modeller who deals with interactions between many objects, the effort spent in learning how to use the association submodel will be well worthwhile.

But in order to understand how to use the relational submodel in your modelling, it is important to understand why we have introduced this construct.

Why is there an association submodel concept in Simile?

Consider a model in which we decide to have two types of object: farmers and fields. There are multiple farmers, and there are multiple fields. Each farmer has dynamic attributes (such as the amount of cash they have) and each field has dynamic attributes (such as the state of crop growth or the amount of nitrogen in the soil). Clearly, in Simile terms, our model would have two multiple-instance submodels: one for the farmers, and one for the fields.

However, there are interactions between farmers and fields. The amount of grain in a field is influenced by the harvesting decision of the farmer that owns a particular field. And the cash held by a particular farmer is increased by revenue from the grain sold from each of the fields owned by that farmer. How can we handle this?

There are two ways. Let's consider the case of calculating the grain yield for each farmer. One way is for each farmer to be presented with the grain yield from all the fields, and to use only the values from the fields he owns. This can be readily done in Simile: it simply requires that the array of grain yields is multiplied by an array (also with as many elements as fields), containing 0's or 1's, with the 1's indicating that the farmer owns the field. This works fine for smallish problems, but it means that the number of operations that have to be performed is equal to n*m, where n is the number of farmers and m is the number of fields. Thus, with 1000 farmers and 5000 fields, Simile would be performing 5 million calculations every time step. This is hugely wasteful of computing time, since in fact it only needs to do 5000 (one for each field).

The other way is to pass to each farmer only the grain yield values for the fields that he himself owns. In the present example, that would be an average of 5 values per farmer - instead of 5000! These values can then simply be summed to give the total grain yield for each farmer.

The job of the association submodel is to make it possible to restrict the amount of information in this way.

Naming the components of an association

The following practise is suggested, as it results (with luck) in meaningful text being generated for the parameter names that are used in equations. These are generated by appending the name of the relevant role arrow to the name of the source component.

Model object: Grammatical class of Caption: Example(s):
Base submodel Noun Farmer, field
Role arrow Adjective Owning, owned
Association submodel Verb (or abstract noun) Owns (or Ownership)

You can also use "my" and "his" for the role arrow names when symmetry means that there aren't two distinct adjectives, as might be the case in a neighbour relationship between grid squares.

In: Contents >> Working with submodels >> Association submodels

Working with submodels : Association submodel worked example

Worked example: water flow between soil layers

We want to model the movement of water between four soil layers. Each layer has a compartment representing the amount of water held in that layer. Water draining out of one layer will enter the layer immediately below it. The following diagram illustrates the system, with notional rates of 10, 20 and 30 units of water per unit of time flowing between the layers.

We begin by constructing a fixed-membership submodel to represent the four layers: each instance represents one layer. Each layer has a single compartment, for the amount of water in that layer. The compartment has a flow in, for the water flowing into it from the layer above, and a flow out, for the water flowing from that layer to the layer below. (There may well be other flows, but they are not relevant to the use of association submodels.) At this stage, we have not entered any values, so all the model elements are red.

Now, some of the elements have an association with each other - the relationship of one being immediately above the other.

  • Layer 1 is above layer 2
  • Layer 2 is above layer 3
  • Layer 3 is above layer 4

But potentially there could be associations between each instance and all the other instances. In other words, the relationships that we have, in this particular system, are a subset of all the 4x4 relationships that potentially could exist. We can represent this in a matrix (below), with as many rows and columns as we have instances in our submodel.

The ticks show when the relationship of being next to exists between an upper layer and a lower layer. Note that, in this particular problem, the relationship is not symmetrical: layer 1 is above layer 2, and not the other way around. In some cases, the relationship could be symmetrical (like neighbourliness in a spatial grid), but not here.

We will now modify the model diagram to represent the fact that this relationship exists between layers.

Quite a lot has happened here, so I'll explain the changes one-by-one.

We have added in a new submodel, and called it "Above". At this stage, it's just like any other submodel. Think of this submodel as a container to represent things about the relationship that exists between soil layers. We have to do this outside the "Layer" submodel (because anything inside the "Layer" submodel relates to an individual layer); and it needs to be some sort of container, because there are potentially lots of things we can say about the relationship between pairs of objects.
We draw two role arrows, each one going from the "Layer" submodel to the "Above" submodel. Each arrow shows one partner in the association. They're called role arrows because each one represents one role in the association. Here, we re-label them as "upper" and "lower", to indicate that one partner plays the role of being higher, the other the role of being lower.
We add a condition model element, labelled "above?" to the association submodel - that's the one with the question-mark inside it in the diagram above. Every association submodel needs one of these, so that we can specify which of all the possible relations between the objects actually exists.
We add in a variable, here called "layer number", in the "Layer" submodel. The equation for this is
layer number = index(1)
so it has a value 1 for the first layer, 2 for the second layer, and so on. i.e., as the layers go down, the index numbers go up.
We take an influence from "layer number" to the condition element. This is because Simile needs to know the layer number for each partner in the relationship in order to work out whether the relationship exists between any pair of layers. Once it knows that the "upper" partner has a layer number one greater than the "lower" one, then the relationship exists.
We enter the actual condition for the existence of the relationship into the condition symbol. The expression for this is:
above? = layer_number_upper == layer_number_lower - 1
(i.e. we are checking that the variable with the local name "layer_number_upper" is equal to the value of the variable with the local name of "layer_number_lower", minus one.) Where do the two layer_number variables come from? The answer is that they both come from the single "layer number" symbol - but one is the value of layer number for the upper layer, while the other is the value of layer number for the lower layer.

We are now in a position to pass information between pairs of instances of the "Layer" submodel. In this case, we want to pass the value for the amount of water passing out of one layer to the layer below it.

We begin by specifying how much water flows out of each layer to the layer below. Here, I've assumed 10 units per unit of time from the first layer, 20 from the second, and so on. In this particular context, this value is a property of each layer: each layer calculates the flow out of it. This could be because the flow is related to the water content of that layer, for example. We show this as a set of value beneath each column, since the columns refer to the upper layer.

This very simple property can be specified by supplying the following equation for the flow: outflow = element([10,20,30,0],index(1)).

In terms of our model diagram, the fact that we have provided values for the four outflows simply means that the outflow arrow is now black:

Now, each of the first three of these outflows in fact constitutes an interflow between the two layers: i.e. it is a property of the relationship between the two layers. In our matrix, we can therefore enter the values in the boxes corresponding to the linkage between the upper and lower layers:

On the model diagram, we add a variable inside the "Above" submodel, here called "interflow", and take an influence arrow to it from "outflow". This shows that (in this particular model) the interflow is calculated from the each soil layer's outflow.

Because we are inside the "Above" association submodel, we could (potentially) set interflow to the outflow from the upper layer or the outflow from the lower layer. The first has the local name "outflow_upper" in the equation dialogue box, while the second has the local name "outflow_lower". In this particular model, we want it to be from the upper layer, so we set the equation to: interflow = outflow_upper.

However, we know that the interflow between layers becomes the inflow for the lower layer. In our matrix, we show this fact by copying the interflow values across to the right, to the column representing the inflow into each layer.

In the model diagram, we draw an influence arrow from the "interflow" variable in the "Above" submodel to the "inflow" variable in the "Layer" submodel.

When we look inside the equation dialogue window for inflow, we get a bit of a surprise. We expect to see interflow as an influencing variable, but:

  • we actually see it offered twice, with local names "interflow_lower" and "interflow_upper"; and
  • each of these is a list (i.e. {interflow_lower} and {interflow_upper}), rather than a normal variable.

It's offered twice, because we could (potentially) be interested in the interflow values relating to the upper layer (those under the columns in the matrix above); or the interflows relating to the lower layer (the interflows to the right of the rows in the matrix above). We want the latter, so we choose {interflow_lower}.

Why is the information from the submodel a list rather than a scalar variable? Well, potentially there could be as many values as there are soil layers. In this particular case, we happen to have put in a condition that restricts it to one value for three of the layers, and none at all for one layer, so our list will contain only zero or one value, depending on the layer. But if we had allowed water to flow directly to a layer from any layer above it, then the list could contain several values.

Anyway, the fact that it's in a list means that we have to convert it to a single value by summing up the elements of this list. So the actual equation we use for inflow is:

inflow = sum({interflow_lower})

The model now only requires initial values for the water compartment to make it runnable. On running it, you will note that water in each of the top three layers decreases by 10 per time unit, as this is the amount by which the outflow is greater than the inflow. The water in the bottom layer increases by 30 per time unit, because its outflow is zero.

In: Contents >> Working with submodels >> Association submodels

Working with submodels : Role properties dialogue

Role properties dialogue

There are two advanced properties of role arrows that are set using this dialogue box. Note that it is not normally necessary or desirable to set these properties. They allow the program generation routines to make certain assumptions. If these assumptions are not valid, chaos will result.

Exclusive role

An exclusive role is one such as motherhood. Although each mother may have many children, each child has (or at some point had) exactly one mother. This is often expressed as a one-to-many relationship.

If you know there is always exactly one element in the list returned from the association submodel to the base model in this role, then you may (but do not need to) check the "Exclusive role" check box. The single element will then be returned by itself, without being enclosed in a list as would otherwise be the case. Note that in the aforementioned case of a motherhood relation, it would be the "is_child" role that is marked as exclusive, since the base model with the "child" role is getting the values from the unique association with a mother.

This allows you to use the value as an argument to functions such as element(). It may also be necessary to use this in conjunction with the property of influence arrows: "Use values made in same time step". It would probably help to talk about your model on the forum.

Allow base instance lookup

If you want to use one-sided relation enumeration, then the base model whose index you are looking up (as you loop over the instances of the other base model) has to be the one whose index is referred to as index(1) in the relation model. By default this would be the one with the role arrow that you added most recently, but it can be set using this property on its role arrow.

Since only one base model index can correspond to index(1) in the association submodel, setting this property on one role arrow clears it from other role arrows going to the same association submodel.

Setting this property never does any harm, and has other uses: if for some reason you have to delete one of your base models then re-create it, Simile might decide to change the order in which it assigns the index values in the association submodel, so what was previously index(1) becomes index(2). For this reason it's better to set variables in the base models to their indices and have influences from these into the association model (it also makes the equation more readable), but if you have referred directly to base model indices, setting this property allows you to control which base model index gets used as index(1).

Comments

Free-form comments can be entered in this text box, and are stored with the model. You are encouraged to comment your role arrows at length, so if you have used them wrongly, someone else can figure out how to put them right.

In: Contents >> Working with submodels >> Association submodels

Working with submodels : One-sided relationship enumeration

One-sided relationship enumeration

One-sided relationship enumeration, also known as base instance lookup, is a feature that makes it quicker to create associations between submodels with large numbers of instances. The problem is that when creating an association, Simile would normally loop over instances of one of the base submodels, and for each instance, loop over the instances of the other, checking the existence condition of the association for each possible pairing of base models. This means that if one base model has n instances and the other m, the number of checks that must be made is nxm, potentially a very large number. Base instance lookup can be used if there is sufficient data in the instances of one base submodel to calculate the indices of the instance(s) of the other base model with which it will be associated. For this to be the case, the association must be independent of the actual values in one of the submodels (except those that can be derived from its index, e.g., physical location of a grid square). It can of course be used in self-associations, where the same submodel serves as base model on both sides of the association.

To illustrate the technique, we will discuss the case of using it specifically to make more efficient the creation of large rasters. A raster is a grid of pixels. Each pixel is equivalent in size and shape. Usually, each pixel is square, though it is also possible to work with other rasters. In this discussion, we shall consider only square grids. Note that Simile version 6.1 introduces a feature that allows a raster to have a built-in neighbour relationship without any need for an association submodel, and that this feature internally uses something like base instance lookup to create this relationship.

Square grid example

In a square grid, each pixel has potentially eight neighbours: north-west, north, north-east, west, east, south-west, south and south-east. However, pixels at the edge of the grid will have only a subset of those neighbours. For example a pixel on the northern edge of the grid will have five neighbours (west, east, south-west, south, and south-west) and one in the south-west corner will have only three: (north, north-east and east).

To take advantage of the powerful features in Simile, we represent the pixels as instances of a multiple-instance submodel. The number of instances is equal to the width of the grid (in pixels) multiplied by the height. Each pixel has an id number, equal to the index of its position. The row and column that the pixel is in can be calculated from the id number, knowing the width of the grid.

Within each pixel, we can create an eight-instance submodel representing each possible neighbour. To allow for edge effects, we can make the existence of each of the eight conditional. Each (possible) neighbour-instance has a row and column calculated from its position relative to its parent pixel. Now each pixel has access to a list of its neighbours.

To use this knowledge, we can create an association submodel, representing the relationship of "neighbourhood" between the central pixel and the (up to) eight pixels that border it. Two role arrows are drawn between the pixel submodel and the neighbourhood submodel, representing the pixel in the centre and the pixels in the border.

The final step is to create a condition in the neighbourhood model that evaluates for each pixel whether any given pixel is in the neighbourhood. Since each pixel has a list of its own neighbours, this condition is simply:

any(my_id_border == {neighbours_ids_centre} )

In this expression, neighbours_ids_centre is the list of ids of neighbours from the instance in the "centre" role, and my_id_border is the index of the pixel that is potentially in the border (set to index(1) in a variable inside the grid square submodel). The condition is true (and the relationship therefore exists) for a centre and a border pixel, if any of the elements of the list of the neighbour_ids in the centre equates to the index of the pixel in the border.

So far, it is important to emphasise that we have followed the procedure that is standard in Simile for many different types of relationship. We now need to look carefully at what this model represents, how Simile is converting it into a computer program, and how it can be changed to make it more efficient.

What does the model represent?

This model looks unusual as the condition for the relation uses values from a submodel of the base model. But the operation is pretty similar to the self-relation in the previous section, with the difference that each base model instance can be in relation with many other instances. Any time the index of the instance in the "border" role matches any of the indices from the "neighbours" submodel of the instance in the "centre" role, an association instance will be created. Now if the "centre" instance needs to have information from all the "border" instances, this can be passed to the association via the "border" role and back via the "centre" role. Because different instances have different numbers of "neighbours" submodels, they have different numbers of associations.

How is Simile running it?

Now for the bad news. When Simile creates a program for any association submodel, it first creates nested loops for each of the base models. If there are two role arrows from the same base model as in this case, it will loop through all its instances, and for each one, loop through all its instances again. This is so it can compare values from every instance with those from every other instance, in order to decide which pairs the association holds between. In this model there is yet another loop inside these -- it has to loop through the instances of "neighbours" in the "centre" role to see if any match the index of the square in the "border" role.

This only has to be done when the model is initialized, as the definition of the relationship clearly dos not change over time or from run to run. Once the relationship is created, the association submodel instances have pointers to their base instances so they remember which ones to use. But if there are, say, a million grid squares (not an excessive number for Simile) it takes 8x1012 comparisons to set up the relationship, which would keep your computer busy for hours. So what can we do?

How can we improve efficiency?

Very easily, just get rid of the association submodel, and instead have any variable that needs to be shared between neighbours taken outside the grid square submodel into an array variable of its own. Then draw an influence from that array to a variable in the "neighbours" submodel, and give it the equation element([array_outside],neighbours_ids).  The values of this variable can then be summed inside the grid square but outside the "neighbours" submodel to give the sum of the original values from all an individual's neighbours. This only needs one level of looping through the grid square model, since it is using the neighbours_ids values directly to index the array rather than comparing them with those from other instances.

But this model is not as clear as one with an explicit neighbour relationship, especially if many values are passed between neighbours. So we have added a feature to the interpretation of the condition symbol that allows an association to be built in a similar manner, i.e., by using the index to look up one of the base instances rather than seaching through all of them and comparing their indices with a value we got from the first base instance. To do this, we rewrite the condition's equation like this:

any(index(1) is {neighbours_ids_centre} )

Previously, this expression would have been written with the equality operator "==", instead of the key word "is". The new key word has been introduced in order to invoke the efficient program generation that is possible for rasters. Note that we have also replaced the reference to the variable my_id in the submodel with the "border" role, with the function index(1). This is because index(1) means the same thing (because we set "Allow base instance lookup" in the properties dialogue of the "border" role arrow), and we cannot use a variable from the base model in that role until we have looked up the base instance itself.

This is not the only situation that is applicable: in general, as the name implies, the feature is useful for any situation where the relationship can be calculated in a loop over only ONE of the roles. In this case, because each pixel is able to calculate its own list of neighbours, it is not necessary to take each possible pair of pixels and determine if they are neighbours. It is from this short cut that the improvement in efficiency stems.

There is a model in the catalogue on Simulistics web site, showing all this in practice. If, without looking at the example, you could create an equivalent model, you are a graduate summa cum laude of Simile use. The example can be used as a starting-point for most work on rasters, grid squares and so on.

Variable-membership base models

In the original implementation, it was not possible to set an association model's membership by base instance lookup if the base instance was itself variable-membership. This was because a variable-membership submodel is implemented as a linked list of data structures, and the only way to find a member with a particular index is to search sequentially through the list. This is the normal way of setting up an association, so in the case of a one-to-one or many-to-one association, having a special construct would not improve efficiency.

However, in Simile v6.1 we have extended the element() function to select sublists from lists. This it does by going through the list sequentially, and returning values as it find indices that match the elements of the second argument (which therefore need to be in ascending order). So, we can do something similar when building a many-to-many association. If the submodel on one side can generate an array or list of index values for a variable-membership submodel on the other side (possibly the same submodel) these can now all be looked up in a single pass by using the 'any(...)' construct described above.

Having implemented this, we found that one-sided enumeration is quite a lot faster than checking every combination of base models even in the case of a one-to-one relationship involving a variable-membership base model. This is partly because searching for a single index value can be stopped as soon as it is found, but mostly because a lot less pointer arithmetic is required just to check an index than to actually get values from the model and plug them into the existence condition equation. So, using 'index(1) is...' is now also recommended for variable-membership base submodels.

Looking up instances by multiple indices

Another small change in Simile v6.1 is to allow more than one index to be specified when looking up a base submodel instance. The indices must be specified in descending order (i.e., outermost first) and joined by 'and', e.g.,


index(2) is y and index(1) is x

or

any(index(2) is {list_of_y} and index(1) is {matching_list_of_x})

This will work when looking up instances of fixed or variable membership base submodels, but the number of indices specified must be exactly the number of indices that the base submodel has. This capability has been added to make it possible to look up instances of the new special-purpose submodels.

In: Contents >> Working with submodels >> Association submodels

Working with submodels : Using externally-supplied procedures

Using externally-supplied procedures

As of version 4.8, submodels in Simile can be used to embody operations specified by procedures supplied separately, either as c or c++ code, or by shared libraries. You can also include your own code in a simile model using the external procedural functions mechanism, but using a submodel offers a number of advantages, namely:

  1. The external procedure can accept arrays as inputs, and write arrays as outputs

  2. Many outputs can be written by the procedure

  3. A procedure embodied by a submodel can have its own internal state.

However, note that there are very few cases in which you actually need an external procedure to implement a particular algorithm as a submodel, since more or less anything is possible using an iterative submodel. The facility described here is included primarily for the case where you already have a procedure or library to implement a complicated operation.

A submodel that embodies an external procedure can also contain components whose values will be calculated by the normal Simile mechanism. It can be any of the types of submodel used by Simile.

Incorporating external code requires that we have variables in the submodel which hold the values going in and out of it. It is important that the datatypes of these variables, and their dimensions if they are arrays, match up to those that the external code is expecting. But most importantly of all, they must be passed in the right order.

Datatypes and dimensions

Simile's variables all have datatypes of int or double-precision. The datatype of each variable is derived from its equation and the datatypes of its parameters. If the equation is for an enumerated type member or a boolean value, the variable's datatype will be int. If it is for a numerical value, the datatype will be int if the value has no physical dimensions and its equation will only ever produce an integer (e.g., index(1)), or double otherwise. If you need to pass an integer value to or from your external procedure, make sure it is actually an integer. The unit appears in the model diagram popup for the variable, and in its equation dialogue. If the unit is real (i.e., datatype is double) when you want an int, go into the equation dialogue and delete the old 'units' entry, and do the same with any input parameters with units of real.

All Simile's real values are double-precision. If your procedure uses single precision floats, you must adapt it to read and write double-precision values.

The dimensions of array variables also depend on the equation. For inputs to the external procedure, your model should be generating arrays with the right dimensionality and datatype anyway. Variables for outputs from the external procedure must be given equations for default values, which basically serve the purpose of creating an array of the right dimensionality containing values of the right datatype. For instance, if your external procedure creates a 5x3 array of integers, the value into which it is put can have the equation makearray(makearray(0,3),5). If you put 0.0 instead of 0, you will get a 5x3 array of double-precisions. Default value equations are also used to set the datatype and dimensions of file parameters.

Simile's arrays of size n use elements 0 through n-1 of a c++ array. In earlier versions of Simile, the arrays were actually made one element too big, and elements 1 through n were used, with element 0 being unused. This has changed, in order to make it easier to integrate other c++ procedures which typically use element 0 as the first element of an array. However, the equation language functions that deal with array elements, i.e., index(n), element(m,n) and place_in(n), still use 1 as the index for the first value, so old Simile models will run unchanged (and use less memory!)

Parameter order

The order is specified by the names of the variables. Values to be passed to the procedure must be given captions beginning with "inputn", where n is the position in which that input is passed. When choosing this position, characters in the caption from the first non-alphanumeric character (e.g., space, underscore, parentheses) are ignored, and can be used to make the model diagram more readable, so for instance a variable called "input3 (volume of porridge)" will still be passed as the third input.

A similar scheme applies for outputs. Their captions begin with "outputn", where n is the position in the outputs in which that output appears. The external procedure gets as arguments all the inputs in order, followed by all the outputs in order. An output variable's default value may or may not be overwritten by the procedure, but there are two differences between the handling of inputs and outputs:

  • The procedure will not run in each time step until the input values and default output values have all been set in the model, but the input values can be used to calculate values of other Simile variables before or after the procedure has run, while output values will only be used elsewhere after the procedure has run,

  • Scalar (non-array) inputs are passed to the procedure as their actual values, while scalar outputs and all arrays are passed by reference, i.e., the procedure gets a pointer to a memory location where it can read the default value and write its result.

The return value of the procedure is not used by the model, but it just indicates to Simile whether an error has occurred in the procedure.

How often to run

Simile assumes that if the inputs and default outputs to a procedure do not change over time, then neither will its actual outputs, so the procedure will only be called at initialization or reset of the model. If you know the procedure's outputs change over time by themselves, make sure it runs every time step by setting an unused default output value to something you know changes over time, e.g., time().

Specifying the procedure

Now the submodel's contents specify how the procedure is to be called. But we still need to tell Simile the external procedure's name, and where to find it. Open the submodel properties dialogue, and look in the calculation panel. There is a checkbutton labelled 'Use own code'. After checking this you can hit the 'setup' button to get a subdialogue in which you specify the procedure. This has three sections:

  1. The procedure name section. Enter just the name of the procedure, not its parameters, as these are all specified by the model contents as described above.

  2. The name of a file to be included when building the model. This can either be a c or c++ (.c or .cpp) source code file containing the whole procedure definition, or a header file (.h) containing the declaration of the procedure in a precompiled library file.

  3. A list of library files. You do not need any library files, but they must be readable by the compiler Simile is using. For Unix systems the shared objects (.so or .dylib) work fine, but for Windows using the included compiler you need an archive (.a) file. Gnu MINGW includes utilities for creating this if all you have is a dynamic-linked library (.dll).

If your model is to run on multiple platforms, include libraries for all of them; Simile will only use the appropriate ones on each platform.

State for external code

One reason for using an externally written procedure is if you have a legacy model, written in FORTRAN or similar, which you would rather include in a Simile model as is than re-implement in Simile. These models are likely to include state variables of their own, allowing them to have dynamic behaviour. There are two issues here; firstly, we need to know when to reset these values and when to update them. An external procedure can tell what Simile is doing, by accessing the time and dt global arrays of doubles. These have a value at index 0 plus a value for each time step size in the Simile model. The values of t and dt for the time steps give you the time of last evaluation and the step size respectively for each different step size (like the time(n) and dt(n) functions), but the index 0 values are especially useful. time[0] gives the current integration method and which pass is being done if it is Runge-Kutta, while dt[0] indicates whether the model is being initialized (negative), reset (0) or updated (appropriate time step number). This can be used to select the action for an external model.

If an external procedure is only ever going to be called once per time step, then it can simply keep its state in locally declared variables. However, if you call the same external procedure in two different submodels, or in a multiple instance submodel, then each one must have its own instance of the state. Simplest way to do this is to make an array of the appropriate size in Simile and pass it to the procedure as an output. If the default values are constants, Simile will not write them once it has initialized, and the external procedure can use the space as a scratch pad unique to each instance.

In: Contents >> Working with submodels

 

Working with submodels : Communicating with another application

Communicating with another application

Simile version 6.11 introduces the ability for a submodel to incorporate communication with a separate application during model execution. The purpose of this feature is to enable systems to be modelled where individual components in different modelling environments must run in combination, and each system has its own means of managing execution. For instance, one might use Simile to create a farm-scale or larger model of an agricultural system, but want to use existing models in another tool such as APSIM for the various crops and soils in the system

Pretty picture here

 

It is possible to implement such communication using externally-supplied procedures as described in the previous section, but supplying a procedure that carries out communication with another process rather than implementing the submodel itself. However, doing communication this way would require the procedure to be manually re-written each time a change was made to the format of data being passed back and forth while developing the combined model. Also, in the case of a multi-instance submodel, the external procedure is called once for each instance in sequence, meaning it is hard to avoid problems if the remote process is running the instances in some other order.

Implementation of the connection

For these reasons, we have built a remote connection interface specification into Simile itself, and this can be selected as a third option, after normal execution or use of external procedure, in the Submodel Properties dialogue. Communication is via named pipe in Windows, or Unix socket (which is the closest equivalent to a Windows named pipe) in MacOS or Linux. Note that the commands in c# to operate on named pipes work unchanged on Unix sockets in these systems, allowing remote models implemented in c# to be cross-platform. Selecting remote connection allows the modeller to enter the name of the connection, which can be anything in Windows but must be an available filesystem location in MacOS or Linux.

The dialogue for specifying the remote interaction has two other fields:

  • Command to start. This is a system command that is called to start the remote model each time the Simile model is initialized or reset. This can be used if it is possible to run the remote model from the command line, in order to save the modeller from having to start the remote model via its own interface at this point. Default is 'none', meaning no command is issued.
  • Time unit. At the start of the simulation, Simile works out the offset between the times as represented on each system, but if the unit is something other than 'day' on the remote system it must be entered here. e.g. if you enter 'year' while the Simile time unit is default or 'day', then the Simile model will advance 365 units for each time unit in the remote model. 

When the model is initialized, Simile opens a connection as the server at the given location. The remote system can then connect as a client. If the submodel is multiple-instance, Simile will accept one client connection for each instance. These can all be made to the same server location. The two systems then exchange data over the pipe as the models run, as described in the next section. It is up to the remote system to close the pipes at the end of its run, which signals Simile also to pause. Resetting the Simile model will cause it to issue the start command again and accept a new connection for each submodel instance. Exiting the Simile model (e.g., before initializing an updated version) will delete the pipe or socket. Here is a description of the server operation in pseudocode:

create server pipe
while {model initialized or reset} {
  issue start command if set
   foreach {submodel instance} {
      accept connection
      foreach {submodel dimension} {
         read integer index from connection
      }
      assign connection to submodel instance
      read real remote time from connection
      time offset = remote time - simile time
   }

   foreach {time step} {
      evaluate inputs from rest of model
      foreach {submodel instance} {
         if {simile time + time offset >= remote time} {
            write real (simile time + time offset + time step) to connection
            for (n=1; n<=inputs; ++n) {
               write input n to connection as appropriate type
            }   
            flush connection
         }
      }
      foreach {submodel instance} {
         if {simile time + time offset >= remote time} {
            if (remote system has closed connection) {
               signal model execution pause
               delete submodel reference to connection
            } else {
               read real remote time from connection
               for (n=1; n<=outputs; ++n) {
                         read output n from connection as appropriate type
               }
            }
         }
      }
      evaluate rest of model from outputs
   }
   delete any remaining connections
}
delete server pipe

Data transfer protocol

The values to send and receive via the pipe are specified in the same manner as the values to pass to an external procedure as described in the last section, except the numerical part of their caption determines the order in which they are sent to or received from the pipe.

Data passes along the pipe in raw binary format, one byte for a boolean, four for an integer or eight (double precision) for a floating-point value. These sizes correspond to what is sent automatically in c# by the BinaryWriter Write() method, according to the datatype of its argument, and what is received in c# by the BinaryReader ReadBoolean(), ReadInteger() and ReadDouble() methods respectively. If a data value, or an index for the communication submodel instances, is a member of an enumerated type then that value is passed as a string in a format compatible with the c# ReadString() method, i.e., a byte giving the string length followed by that number of bytes for its characters.

When a remote system connects as a client implementing one instance of a multi-instance submodel, it must first identify which submodel instance that connection is for. To do this it sends one integer for each dimension of the submodel, giving its index. For a single-instance submodel, no indices are needed.

Next the remote system must send its notion of the time at initialization, as a floating-point value. This is taken by Simile to be equivalent to the "Time at reset" specified in the run control. Time units are assumed to be the same for the systems. This is also the time at which the first interaction is to take place.

Multiple instances

There are two ways of having multiple instances of an external process communicate with Simile as multiple instances of a submodel. Firstly, the parent model containing the externally implemented submodel might already be multiple-instance. In this case, the start command will be issued once for each instance of the parent model, after which Simile will wait for a single client connection, which will be used for the submodel in that parent instance. In this case the remote process does not need to send any indices when connecting. The start command can include arguments that are specified by model components in the parent submodel whose captions are of the form 'paramn' where n is an integer, in much the same way as inputs to external code are specified. Typically, one of these components would be set to the index of the parent model instance to let the remote process know which submodel instance to start. 

Alternatively, the externally implemented submodel itself can be set multi-instance. In this case the start command will be issued only once, and it is up to the remote process to make a client connection to the pipe for each submodel instance. When a connection is made, a value or set of values must be sent by the remote process providing the index or indices of the submodel instance corresponding to that connection. The connections for each instance within a single parent instance can be made in any order. It is possible to combine these methods, and have multiple parent model instances each with multiple submodel instances implemented by separate pipe client connections, but such complexity is unlikely to be needed.

Interactions during model execution

When Simile executes, if the model time is equal or greater than the time at which the next interaction is expected (which will be true at reset, see above) it carries out an interaction. Components in the submodel with captions starting with input1, input2 etc will have their values sent to the remote system, and those with captions starting output1, output2 etc will be read from the remote system. The naming may seem back to front, but it corresponds to the system used for submodels implemented as a hand-coded c++ procedure, where input1, input2 etc correspond to inputs to the procedure.

Simile starts by sending values. First, a floating-point value is sent, representing the earliest time at which the next interaction could occur (typically the current time plus one time step). This has been adjusted to fit the remote system's notion of time as determined from the initial exchange. Then each input value (to remote system) is sent, in the order of their numbers, the datatype according to their units in Simile. If any of the inputs are arrays, all their values are sent as a block. All these, including the time, are sent to each client instance from its Simile submodel instance. After they are all sent, Simile starts receiving values. First it reads a floating-point value, representing the earliest time (in the remore system's notion of time) at which the next interaction can occur. Then it reads a value of the appropriate type for each output value (from remote system) in order. Again if an output value is an array, a block of data is read for all the values. All the reads are then repeated for each further submodel instance if there are multiple instances.

Error codes

The interface management uses numerical codes as in the user-defined stop function to signal when something has gone wrong. These cause messages to appear as popup boxes or in the log tab of the run control pane, according to the preference settings. They will typically contain text like "There was a user-defined exit: 71". Here is an explanation of the more common codes:

Error code Meaning Remedy
70 Server could not be created Check pipes exist on your system
71 Server could not be added to filesystem Delete anything already present in that location
72 Server cannot listen for clients Reduce number of simultaneous connections
73 Client cannot connect Ensure client connection type is compatible
76 Failed to write time to pipe Remote model should always read a set of data after writing one
77 Failed to read time from pipe No problem, remote model has exited normally
78 Failed to read submodel indices from pipe Make sure remote model is sending an index (integer or string) for each submodel dimension

How to implement a remote system

The interface allows two approaches to designing the interaction:

  1. Serial execution. Simile runs until it sends the input values from the connection submodel, then it waits while the remote system processes those values and returns its outputs to the connection submodel, then Simile completes the time step while the remote system waits for the next set of values.
  2. Both systems run at once. Whichever arrives first at the time specified by the other for the next interaction will send values to the pipe (this does not block execution; the values are buffered by the OS) then wait until the other does the same, after which both can read values and continue in parallel to the next interaction point.

There is a simple trade-off here; in the serial case, a value in Simile can be passed to the remote system, affect an output from the remote system and have that affect another value in Simile all in one time step, and this can happen every time step if the step is the same in each system. In the parallel case, overall execution may be faster on multi-processor systems, but the effect of a change to a remote model's input will not be seen in its outputs until after two interactions have taken place.

Working with submodels : Interfacing a network model with a grid

Interfacing a network model with a grid

comps on map bkgnd

If you have a modelling problem in which you are dealing with reservoirs of a substance at different locations, with varying transfers to and from them, you would normally choose one of:

  • a single instance model with a network of compartments and flows representing reservoirs and transfers
  • a multi-instance model disaggregated into grid squares, with a compartment representing levels in each square, and transfers between them making use of an association

Each of these approaches has its strengths, but in some situations we may wish to combine the two. For instance, we may be modelling a hydrological problem in which water diffuses through a region as groundwater, but which also contains reservoirs from which water is taken for industrial or agricultural use. Because we are interested in water dynamics over the entire area we would use a grid model, with a neighbour association to handle diffusion between adjacent squares, but we would also want to include associations between squares at larger distances to represent water transport by engineering such as pipelines and aqueducts. It would be possible to build a grid submodel with separate relations for neighbours and longer connections, but representing the water supply network as an actual network in its own submodel makes the model easier to understand and maintain.

Simile's system for integrating models like this takes its inspiration from the ModFlow/WEAP interface, a system for connecting a network model in a special-purpose water engineering tool with a grid-based hydrology model. As in WEAP, the compartments in the network model are laid out within their submodel boundary according to the actual position of their corresponding features in the landscape being modelled. Thus the submodel appears like a topographical map of the water features on the landscape. To make the location of the features clearly readable, an actual map of the region can be used as a background image in the submodel, such as is shown in the image at the top of this page.In order for a component in the network model to get its value from the right instance of the corresponding component in the grid model, you would normally use the element() function with three arguments -- the parameter name associated with the grid component, and the row and column indices of the instance. This would be messy, requiring influences to each network component as well as working out and entering the actual indices. So instead we provide the at_posn() function, which as its name suggests, gets the value of the grid component in the instance at the corresponding position. Its only argument is the grid component's caption, and it must be the whole equation. An alternative form has three arguments, adding the row and column indices which replace those derived from the component's position. This is for use in cases where it is impractical to use the component's position in its submodel to select the grid instance, as in the case where a lot of them occupy a small region of the grid. The network model components now behave similarly to ghosts of the referenced component instances for the appropriate grid squares.

Any component can use the at_posn() function as its equation, provided it has the same quantization (discrete vs continuous) as the corresponding grid component.  For instance, in the diagram at the top of this page, the variables captioned conc_n all have the equation at_posn(concentration) and can be used to plot a graph of the pollutant concentrations at their positions on the map.

The network model can thus get values from the grid, but if the component is a compartment, its value will not be affected by transports (flows/squirts) in/out of the rest of the network model. These transports must now be directed to/from the grid instance compartment, and this currently requires some extra bits and pieces to be added to the model by hand. Suppose you have a grid model representing the diffusion of a pollutant around a watershed. That model might contain a compartment called 'pollutant' representing the amount of it in each square, along with flows carrying it between neighbouring squares according to concentration and transport rate. Now, if we want to show pollutant being added at various points on a separate map-related submodel, we would add compartments to it at the appropriate positions with flows going in representing rates of addition, and equations set to at_posn(pollutant). To get these to affect the grid submodel, we add a further submodel called 'pollutant_flows'. This gets three variables, 'stock_x', 'stock_y' and 'transp'.

flow attachment

These names are recognized by Simile when the model is built, and the submodel properties are automatically edited to make it a multi-instance submodel with an instance for each flow connected to a compartment whose equation is at_posn(pollutant). 'stock_y' gets the row indices in the grid containing 'pollutant' for the positions of these compartments, either from their actual locations in their submodel or from the 2nd argument of at_posn() if present, while 'stock_x' similarly gets the column indices. 'transp' gets the values of the flows themselves (negated if they go out of the compartment concerned). The modeller may do anything she wants with these values, but the intention is to use them to set up a flow to the compartment in the grid submodel. This is most simply done by creating an association submodel between the grid and the submodel picking up the flow values (called 'connect' in the diagram). Here, 'transp' and the new flow 'contam' have the values 'role2_transp' and sum({'transp_role1'}) respectively, to simply pass the values between instances according to the relation. 'role1' has 'Allow base instance
lookup'  selected in order to use one-sided relation enumeration to set up the relationship as efficiently as possible, not that this matters with only a handful of flows, and to do this the equation for cond1 must be 'index(2) is role2_stock_y and index(1) is role2_stock_x'

 There will now be an instance of 'connect' relating each flow in the network model to the grid model instance where it takes effect. This image shows the grid helper displaying pollution hotspots resulting from the flows in the first image (note the correspondance between the positions of the pollution hotspots and the positions of the compartments within the map submodel in that image).

results from example

If your network model has squirts instead of, or as well as, flows that must affect the grid model, you should add another specially-named submodel to handle them, and interface that to the grid submodel as described above. The differences are as follows:

  • its name should be target_squirts rather than target_flows (target is 'pollutant' in the example)
  • the 'transp' component inside it is a derived event rather than a variable, which will occur when the corresponding squirt does
  • the derived event in the relation model and the squirt in the grid model have the equation 'trigger_magnitude()'
  • The influences connecting them have their properties set up so as only to include source events corresponding to the roles of the relation.

In: Contents >> Working with submodels

Running models

Running models

Once you have drawn the model diagram and specified how to calculate the value of each element, you are ready to perform a simulation. During the simulation, the model is run for a specified number of time steps, and the changing values of any of the elements can be plotted, recorded in tables, or displayed using a variety of other visual tools. You can develop your own displays specific to the needs of your models.

Preparing models to run

Before it runs a model, Simile generates an executable program from the model diagram.

Diagnostic messages

How Simile interacts with the modeller to display and correct problems

Run time environment

Simile provides two alternative environments for running models and seeing the results of the simulation. The standard one uses a single window containing a number of panels: one for controlling the simulation, another for any input sliders, and others that can contain graphs or other ways of visualising model behaviour. The alternative, multiple-window environment has a separate window for each of these.

You decide which of the two run-time environments you want by ticking or un-ticking the option "Single-window Model Run Environment" in the Preferences dialogue window, obtained by selecting the Preferences item in the Edit menu.

As of Simile v6.12 it is possible to have a browser window display the status of the running model.

Controlling model execution

Whichever execution environment you choose, you control the model's execution via the run control panel. This is either a special box within the single execution window, or a whole window itself, but looks the same in either case. It allows you to:

  • start, pause and reset the model's execution,

  • set the time for which it will execute and the frequency of display updates, and

  • adjust other execution variables such as the step size and integration method.

Visualising model behaviour

The term "helper" is the generic term in Simile for any tool for displaying model behaviour (i.e. the values for variables), or for entering values into a running model.

Parameter estimation and predictive analysis

Simile incorporates an interface to the PEST parameter estimation tool. This carries out parameter estimation by varying model parameters in order to match model behaviour with measured data from the system being modelled. It can generate prediction ranges for model outputs based on combinations of parameter values found in this way.

Working with external data

If your model has variables whose data source is chosen as being from file, i.e. so-called "file parameters", then it requires data to be provided before the simulation can proceed. A file parameter dialogue window will appear to enable you to provide the required information.

Scripting model execution

In addition to the interactive run-time environments, a scripting interface is provided to enable simulations to be run without user interaction. This is often useful for simulation experiments, e.g. running the same model for a set of scenarios (probably defined by parameters in a scenario file), for sensitivity analysis or parameter estimation.

In: Contents

Running models : building models

Running simulations : preparing a model for running

Simile runs a model by executing a program that it has generated specifically for that model. This program contains all the instructions need to calculate the values of the model variables as they change over time. Whenever you want to run the model after making any changes to it, you must re-generate this program. At the same time, the value of all the variables are calculated ready for the start of the simulation.

To build the model, select either the "Run" command in the Model menu, or the "Debug" command. These generate programs in either of two languages, C++ or Tcl, respectively. Use the "Debug" command if you have a problem running your model, due to a mathematical error. You will get a more informative error message. Otherwise, use the "Run" command, for faster model execution.

If you use the Windows or Mac versions of Simile, you may choose to use a c++ compiler already installed on your computer rather than the one included with Simile. The Preferences dialogue window, obtained by selecting the Preferences item in the Edit menu, is used to indicate which C++ compiler is to be invoked. An open source C++ compiler, GNU g++, is included in the Simile distribution. Under Windows, Microsoft Visual C++ is also supported. Linux users on the other hand are expected to have the GNU g++ compiler installed on their system, and Simile will always use this compiler.

Development of a model will often involve an "edit/run cycle" in which the modeller alternates between exploring the behaviour of the running model, and making changes to the model diagram and equations. Changes to the model diagram and equations are not reflected in the behaviour of the executing model until "Run" or "Debug" is selected again. Interacting with an executing model that is out-of-date will produce a warning message and a change in the status indicator. This warning message provides an option of rebuilding the model, and there is also a "rerun" button in the model window toolbar (play arrow or running man) that rebuilds the model and starts it running in a single operation.

In: Contents >> Running models

Running models : diagnostic dialogues

Running models: diagnostic dialogues

The point at which you attempt to run a newly built model is where you are most likely to encounter failures due to incompleteness or inconsistencies in the model's definition. You should not give up at this point; a bit of attention to the messages will enable the problems to be fixed.

The first dialogue that appears will have an outline description of the problem, and only two buttons. Depending on the nature of the problem, these can be:

  • OK / More info...

The problem has stopped whatever task was in progress from being completed. You can hit "OK" to go back and try again, or "More info..." to see a more detailed message, and get a reference to these help pages where appropriate.

  • Give up / See all...

The task in progress can continue, although it will not be successfully concluded. You can hit "Give up", fix the indicated problem and try again, or "See all..." to keep running the task and display a list of all the problems found at the end.

  • Default option / More options...

There are several possible actions that can be taken at this point. The most frequently chosen is named on the left button, while the right button opens another dialogue displaying all the options.

Errors during model building

These are problems that come up during the process of converting the Simile model to code that can run on the computer. There are many possible causes, the simplest being that not all components have their values specified (i.e., they are still red). Other building errors can arise if a component has been specified correctly, but its specification does not make sense in its context in the model, often because the context was changed after the component was edited. Several of these messages include useful information to help fix the problem, for instance:

Problem building code, e.g., Simile failed to convert var1 (in submodel submodel1) into a program instruction.

Something like this means that the component has an equation, but it no longer fits the component's place in the model. If you hit 'More info', then 'See full error text', you will see the error you would get if you tried to enter the same equation for the component now (or else you can just do so!). For instance, the parameter names that can be used in the equation might have changed, or a submodel index might no longer be valid.

Problem with model design, e.g., This model cannot be executed because it contains the following circular set(s) of function evaluations: [var1,increment(var2_sum),var2_sum,var2,made_for(var1,var2,1)]

Here, no one component is wrong, but the model cannot be built because together they do not make sense. In this case, a set of influence arrows form a circle, so there is no sensible order in which to evaluate the components they join together (see rules for using influences). The error message includes a list of all the components that form the circular chain, plus other entries representing intermediate steps performed by Simile in evaluating components. 

Problem during compilation of model code

Simile has managed to convert the model into executable code, but the compiler (a separate program that turns c++ code into binary instructions) is having none of it. This usually means that there is a bug in Simile which is causing it to generate incorrect c++ code. The only thing you can do is file a bug report including your model code to Simulistics. However a compilation error is also triggered by an explicit division by zero, since the compiler will not build binary code that inevitably gives bad results. In that case you can rebuild your model using the 'debug' menu entry to find the location of the division-by-zero expressed in terms of model components (i.e., which component, in which submodel).

Problems linking model with parameters or visualization tools

These can occur either when a new helper setup or parameter file is loaded while a model is running, or if a model is changed and rerun while keeping the same helper setup or parameters. It means the component names listed in the file no longer exactly match the components in the model.

For example, the above is the "Some parameter values unused" dialogue.  If a parameter metafile contains parameterization information relating to components that do not exist in the model you are trying to run, you have four options: Discard values (the default: ignore values for the missing component and keep loading the rest of the data), Give up, Use elsewhere (find a model component with a different name that can take the values for the missing one) or see help. The initial dialogue offers only the "Discard values" option and "More options...". Choosing the latter brings up the dialogue displayed above.

The Use elsewhere button is useful in the case where you have changed the name of a model component or a submodel containing it, or added or deleted a submodel boundary around it, since saving the parameter metafile. In the case above, the dialogue is pointing out that some parameters are for a component in a submodel that no longer exists in the model. In this case, hitting Use Elsewhere will bring up a tree diagram showing all the submodel captions in your model, and their nesting relation. When you select a submodel from this list, Simile will try to find the components from the lost submodel in that submodel instead, and supply the parameter data to them. If this works, you should re-save the parameter metafile later to avoid having to do the same thing again next time you open the model.

Problems during model execution

e.g., "Simile ran into a problem trying to run this model.
While calculating the value of {external procedure} during execution of the model at time 1275.0, there was an OS signal: 11 (SIGSEGV)."

These messages relate to problems in a model's logic that only become apparent when the model is running. These occur because some of Simile's advanced features require that the modeller stick to certain rules when using them, or else something undefined will happen in the model. The most commonly used such features are:

  • The element() function. The second argument can be an expression, but it must always evaluate to a number between 1 and the number of elements in the array that is the first argument, otherwise it will attempt to get a value that does not exist.
  • Dashed influences. These allow a model containing a circle of influences to be executed, specifying that the component at the head of the dashed influence can be evaluated without waiting for the one at the tail. But its equation should contain something like an 'if' clause to insert a boundary condition in any case where the tail does not already have a value anyway.
  • Base instance lookup. While Simile will not allow a base instance lookup if the index is out of range, it is possible to cause other problems with this feature, for instance by looking up multiple base instances in the wrong order, e.g., any(index(1) is [10, 5, 1]).

When an error like this occurs, the model cannot continue to run. If it happens during reset or initialization, the execution LED goes grey and the model must be rebuilt before it will run again. If it happens during execution, the LED goes red and the model can be reset and run again. However, in either case, if the same problem occurs again, Simile will crash.

To get more information about the cause of these bugs, run the model using the 'debug' menu entry. This causes the model to be built and run in a scripting language, where attempts to access undefined values will produce a list of procedure calls from which Simile can deduce what actually was missing in the model. Here's an example:

Here we can see the name of the variable in whose equation the error occurred (event1), the name and indices of the submodel instance containing it (Collide) and so on up to the desktop, and the identity of the missing quantity (the variable "worn") and why it failed (it was looking for the value from the instance of its parent submodel "seatbelt" with index 0 -- the index of the first element is 1). The message about using the debug option is irrelevant -- to get this level of detail, the modeller must already be using it. There are similar messages if the variable itself is missing, for instance due to unprotected use of the dashed influence, or a bad index for an array variable.

 

In: Help >> Running models

Running models : Single window run time environment

The single-window Model Run Environment

Controlling a simulation and displaying results is performed within the Model Run Environment (MRE). The single-window MRE provides flexible self-contained access to all the controls needed to perform a simulation and to display the results.

It is divided into a number of sections. In the upper left corner is the "Run Control". In the lower left corner is a tabbed panel containing the model "Explorer". On the right hand side are four notebook pages, which can each contain one or more "helpers". Helpers are used to display the behaviour of a model whilst it is running, for example, a graph of a variable, or a data table. Helpers are also used to provide data for the model, for example, using "Input sliders".

To add a helper to a page, select the required helper from the "Add" menu. The three most commonly used helpers can be selected using these buttons on the tool bar:

the plotter;

the data table; and

the Input sliders.

The pages can be divided vertically or horizontally, to allow more than one helper to be display on each page, and pages can be added or removed. Once one or more helpers have been added to the pages, and are arranged as you wish, the configuration can be saved to a file, for use the next time the same model is built.

  • To save the current configuration of helpers, chose the "Save configuration…" item on the "File" menu, or use the save button on the tool bar.
  • To load a previously saved configuration of helpers, chose the "Load configuration…" item on the "File" menu, or use the open button on the tool bar.
  • A new configuration can be selected, to remove all the currently displayed helpers.

Arranging pages, and panes

Add notebook

Creates a new notebook, initially with four pages, in the current pane
     

Add notebook page

Adds a page to the notebook containing the current pane
     

Divide pane vertically or horizontally

Splits a pane into two new ones separated by a sash which can be dragged

Adding helpers

Add plotter

   

Add table

   

Add sliders

   

Add other helper

Manipulating layout

Copy display to clipboard

Copies helper window to Simile's clipboard; also copies its graphics to system clipboard for pasting into other graphical applications
     

Cut display to clipboard

As above but also removes helper window from the pane
     

Paste display from clipboard

Inserts a copy of the helper window from the clipboard to the current pane, with the same setup
     

Delete display or helper

Removes helper window from pane, or deletes pane if it is already empty
     

Print display contents Prints the graphics of the helper in the current pane

Saving and restoring configurations

New configuration

Sets MRE to its initial state of one notebook with four empty pages
     

Open configuration

Loads a previously saved configuration. Model components referred to by the helpers in the configuration should exist in the current model.
     

Save configuration

Saves a configuration for reloading later, or for inclusion in a model package.

In: Contents >> Running models

 

Running models : Working with visualisation tools : Save and restore

Helper configurations

You will probably be working with a particular model over a period of time, testing it, modifying it and exploring its behaviour. Often, you will want to have the same displays each time you run a simulation. Simile enables you to save a particular configuration of helpers in a file, and re-load them on a subsequent occasion.

Helper configurations

You will probably be working with a particular model over a period of time, testing it, modifying it and exploring its behaviour. Often, you will want to have the same displays each time you run a simulation. Simile enables you to save a particular configuration of helpers in a file, and re-load them on a subsequent occasion.

Each configuration can contain one or more instances of one or more types of helper, each instance linked up to particular variables in the model. You can have several configurations for the same model. You can also use the same configuration for different models - perhaps slightly different versions of one model - so long as the variable names are the same. For this reason, configurations are stored in separate files, and not in the file used to save the model itself.

New configuration

Any existing helpers are closed and removed by selecting a new configuration. It is only necessary to name the configuration when saving it, in which case any suitable name and directory can be chosen in the usual way.

Save configuration

The procedure for saving configurations differs, depending on whether the single or multiple-window run time environment is selected.

Load configuration

The procedure for loading configurations differs, depending on whether the single or multiple-window run time environment is selected.

In: Contents >> Running models >> Working with helpers

 

Running models : Multiple window run time environment

The multiple-window Model Run Environment

The multiple-window Run-Time Environment uses a separate window for the dialogue windows and displays concerned with running the model. There are the model diagram window, the Run Control, Sliders (if required) and helpers. Helpers are used to display the behaviour of a model whilst it is running, for example, a graph of a variable, or a data table.

In the multiple-window Run-Time Environment, the display helpers are selected from the "I/O Tools" menu of the model diagram window. Each time one is selected, another window is created, plus (in some cases) instructions for selecting the variables which are to be displayed by the helper. To remove a helper, close its window. Note that the "I/O Tools" menu appears only when a model has been built.

Note that this Model Run Environment is provided mainly for compatibility with earlier versions of Simile, and will be phased out with the release of Simile v7. Some old helpers may only function effectively in this environment, for example. Otherwise, the new single-window Model Run Environment should prove more flexible and convenient.

In: Contents >> Running models

Running models : Running in browser

Running in browser (Simile v6.12 on)

If this option is selected, then instead of a run control window appearing as part of the Simile user interface, a new browser window or tab will be created to show the model run status. This looks similar to the SimiLive web interface, and actually downloads some code from the SimiLive server in order to operate, but the model data is coming from the local Simile which will be acting as a web server.

If the option is selected when the model is already running using the Simile single-window run interface, then then that Simile window will be hidden and the browser page will be layed out according to the layout of visualization tools previously in use, i.e., with the same set of notebook tabs and the same panes and display tools visible in each tab. There will be an extra notebook tab showing the model diagram, complete with equation and value tooltips over the model components. Switching to and from execution in the browser causes the model to reset. Further visualization tools can be added using the tool buttons in the browser page. However these changes are lost when going back to running the model in Simile's own run environment.

This mode of model execution is useful for previewing how model execution will look if it is to be published for use via SimiLive. Also, the 3-D shape viewer in browser execution is implemented in WebGL and produces fully rendered displays, which look a lot better than the displays in Simile's own shape viewer, and also has better performance rendering complex scenes.

Running models : Run control

Run control panel

The run control panel is a notebook containing two tabs. The first of these, headed 'Run control', is the one usually displayed, and provides the most commonly used actions for controlling the execution, as well as indications of progress. The other tab, 'Run settings', gives access to selections which fine-tune the model execution, and will not usually be displayed.

Run control tab

The run control is used to start and stop the simulation of the model.

  • the play button will begin execution at the current time for a number of time steps set using "Execute for".

  • the stop button will stop the simulation (if one is running) and set the current time to zero.

  • the pause button will pause the simulation at the current time.

Note that the pause button is only displayed if a simulation is running, and the play button is only displayed if one is not.

The progress bar indicates the elapsed time as a proportion of the total. To the right of the progress bar is an LED which changes colour to indicate the current status of the simulation. This table explains the meanings of the most commonly seen LED colours.

LED colour

Corresponding model status

Black

Model is stopped and ready to run

Purple

Model is stopped and ready to run, but has been edited since the execution was started so the results might not correspond to the current model diagram

Yellow

Model is initializing, resetting or loading data from file parameters

Green

Model is executing

Blue

Display tools are busy updating their images

Red

The model has been stopped, either by executing the stop(...) function, or by a mathematical error, and needs to be reset

 Grey

The model code is loaded but some fixed parameter values must be supplied for it to run

White

The model has been stopped by a program error, and the executable code needs to be rebuilt

During a long run, the LED may appear some shade between green and blue; this can be interpreted as indicating what proportion of time Simile is spending actually executing the model as opposed to redrawing the displays of the visualization tools. From version 5.4 onwards, Simile is capable of running the model and updating its displays simultaneously when running on a multi-CPU computer; the LED is blue while doing both at once.

The other fields on this tab are:

  • Execute for

    This setting controls the number of time units for which the model is run each time you push the "play" button. You can enter a negative number here to use your model for backcasting, i.e., extrapolating the past from the present.

  • Current time

    This setting displays the current number of elapsed time units. It is possible to enter a value into this field, if you wish to begin a simulation at some time other than zero. Note, however, that unless your model contains events that occur at some pre-defined time, this is unlikely to make any difference.

  • Display interval

    During the course of a simulation run, each helper extracts values from the model for whatever variables it is displaying. This happens at an interval determined by the value in this field. The display interval is specified as a fraction (or multiple) of the time unit. The display interval cannot be shorter than the shortest time step. Setting a short display interval will cause fast-changing values to be displayed with more detail, but will slow down execution of the model.

Starting with version 6.0, there is a checkbox to the left of the display interval field, labelled 'event;' if this is checked, the state of the display tools will also be updated whenever a discrete event occurs in the model. This is particularly useful in two cases: where values of events are being recorded, since an event only has a value at the exact point in time at which it occurs; and when an event causes a change in direction of a continuously varying component, in which case this option allows a graph point to be added at the exact position of the direction change.

  • Time step

    The time step for a simulation model is the fraction of the unit of time at which all variables are updated within the model. For example, imagine a model consisting of a single compartment which is initially empty, and a flow into the compartment at a rate of 2 litres per day. In this case, if the unit of time is set to be the day, and a time step of 0.1 days is chosen, then Simile will calculate the change to the compartment every 1/10th of a day. Thus, after the first time step, the container would contain 0.2 litres, i.e. 1/10 of 2 litres, 0.4 litres after the next time step, and so on. After one day (ten time steps) the compartment will contain 2 litres.

Run settings tab

The following actions are available on the second tab of the run control panel:

  • Select time units

    This setting is for use with physical units, to specify the particular time unit, rather than using abstract time units. If you have not specified consistent physical units for all flows, you should not change this setting from the default "unit". If you have specified consistent physical units, you should choose the unit you wish to use to specify how long to execute the model for.

  • Integration method

    The integration method determines how the update of state variables is calculated on each time step. If your model uses Systems Dynamics elements only (i.e. compartments, flows and variables) then you will find Runge-Kutta to be more accurate with less computational effort. For all other models, Euler integration will be more reliable. Please see the page on Runge-Kutta integration for more details.

  • Adaptive step size variation

    Some problem domains have behaviour that alters between slow, steady changes and rapid fluctuations. These are known as 'stiff systems' and one way to model them accurately is to use adaptive step size variation. What happens is that the model execution monitor makes an estimate of the integration error after each time step, and if it is greater than a certain limit, it reverts the model to the state it was in at the start of that time step and re-does it as two time steps of half the duration. The error estimation and reduction process is repeated for each of those time steps, but if a very low error value is estimated after the second of two equal steps, the time step returns to its previous longer value before execution continues. The value entered in the Time step field is now the maximum length of a time step.

    To enable adaptive step size variation, check the box to the left of the word "Adaptive;" and enter a suitable error limit in the entry box to the right. Note that the error limit is used as an absolute value, so models with large numerical values will tend to be run with shorter time steps than those with small numerical values. This changes with Simile v5.7: the error sensitivity now depends on the difference between the user-supplied minimum and maximum values for the compartment (see Equation Dialogue). The larger this difference, the less sensitive the step size will be to integration errors for a given compartment. If either the minimum or maximum value is not specified, it will treat the difference as 100, which results in the same behaviour as for earlier Simile versions.

  • Limiting execution speed

    Simple models run very, very fast in Simile. This may not always be desirable, for instance if one is trying to control an ongoing simulation in real time by using a slider, or if trying to stop it in response to some event. So it is possible to limit the frequency at which model time steps are executed. To do this, check the box to the left of the label "Limit updates/sec to:" and enter your maximum update rate to the right.

  • Time at reset

    Normally, the model time after reset is zero. However, it is sometimes useful to have the model time set differently at reset, for instance if the model's initial state relates to a historical date and it is parameterized with a time series that is indexed by subsequent dates. In this case, the time units may (or may not) be set to Year, and 'time at reset' set to a given year, so the model time corresponds to the calendar time in the domain being simulated. This will also result in the X axis of graphs, etc, being annotated with values that can be read as the calendar time.

  • "Pause on:" occurrences

    If an occurrence type is selected here, the model will pause whenever that thing happens. The preferences dialogue includes an option that decides whether a dialogue will be displayed when this happens. In any case an entry will be added to the Log tab, describing what happened, and the model can be restarted by hitting the 'Play' button again. The occurrence types are events (which does not include time series events) and compartment under/overruns. If this is selected, the model will pause every time a compartment goes below its minimum or above its maximum value, as set in the equation dialogue. This can be useful for debugging models.

Log tab

This tab contains a list of descriptions of things that happen while running the model, including events and compartment under/overruns if they are selected (see above), and user-defined pauses. The contents of the log tab are formatted as a table with fields enclosed in curly brackets, and can be cut and pasetd into other applications, e.g., spreadsheets.

Further notes

What display interval should I use?

When choosing a display interval, bear in mind the following factors:

  • If it is very small, then you will slow down the simulation. Updating the display is relatively time-consuming, and the smaller the display interval, the more frequently this happens.

  • If it is too large, you may miss important dynamics, especially in a simulation that shows sudden swings in behaviour. An extreme case of this is when you are simulating switching behaviour: for example, in simulating overflow of a container with fixed capacity by allowing an overflow to operate when the contents of the container exceeds a maximum. In this case, you may get a very misleading graph for the overflow (perhaps showing extended periods of no overflow followed by extended periods of an overflow). If you do obtain apparently aberrant behaviour, then set the display interval to be the same as the time step, so that you are quite sure that you are seeing exactly what is happening to the variable.

Observing the proportion of time that the LED status indicator is blue will give you an idea of how important it is to choose the optimum display interval. If the status indicator is blue most of the time you will be able to improve the performance significantly by increasing the display interval. If it is green most of the time, increasing the display interval will have little effect.

Time steps

If the processes that you are simulating in your model are truly continuous, then you are actually specifying a model based on differential equations, with compartments corresponding to state variables. In general, digital computers cannot solve such models exactly, so they resort to various numerical methods for calculating the value of the state variable forward through time. There is a large numbers of such methods, with some of them producing far greater accuracy for a given amount of computational effort than others. Simile uses the simplest such method, the Euler method. The reason for this is that, in general, a Simile model can contain features that make it unsuitable for solving through other, more advanced, numerical methods.

What time step should I use?

There is no simple answer to this question. If the processes you are modelling happen on a discrete-time basis - for example, animals reproducing once per year - then you can use a time step of 1. Otherwise, explore the effect of reducing the time step. If you get no significant difference in model behaviour, then use the bigger time step. If you do get a significant difference, then keep on reducing the time step until you cease to get a change in behaviour.

A useful rule-of-thumb is that no state variable should change by more than two parts in one hundred over one time step.

Why is the time step labelled as being "Time step #1"?

Different submodels in a model can be specified as operating on different time steps (in the submodel properties dialogue). For example, you might have a model with a human demographic submodel operating on an annual time step, and a lake pollution submodel operating on a 1/100th of a year basis. In that case:

Time step #1 = 1

Time step #2 = 0.01

How does adaptive step size variation work?

Simile's adaptive step size variation mechanism differs from other implementations. How it works is, at the end of a time step, a compartment's rate of change is calculated and compared with what it was expected to be when its value at that time was calculated. In the simple case of Euler integration, a compartment's value is calculated with the assumption that its rate of change stays the same throughout the time step, so the estimated error is the difference between the new rate of change and the previous one, times the current step size. Error estimation for Runge-Kutta integration works in a way analogous to this, but the estimated rate of change is a function of the intermediate rates of change generated during the application of that method.

Back-casting

Entering a negative number in the "Execute for..." field in the Run Control enables certain back-casting calculations to be performed. Time will obey the usual rule of stepping from the "Current time" (which you can enter) in steps of magnitude given by "Time step" for the total number of units specified by "Execute for". For example, you could request execution for 100 time units, enter a current time of -100, and a time step of 0.1. Simile will then perform as it usually does by default with 1000 calculations, but in reverse.

In the model equations, you have entered "Initial values" for the compartments (state variables). When the model is first built, or subsequently reset, the "Current time" is set to zero and the compartments are allocated these initial values. Even if the "Current time" is manually changed after this, the compartment values are not changed. It is therefore not possible to enter time-dependent initial values in the model. On the other hand, if you want to enter "Initial values" that represent the state of the system at some non-zero time, this can be achieved by altering the "Current time" setting after the model is built or reset.

If, however, the model is not reset, then the state variables will retain their values from the end of the previous run. This allows a model's calculations to be repeated in reverse, simply by reversing the sign of the time step. (This is a good check on the numerical accuracy of the solution: if the initial values are not re-calculated exactly at the end of the reverse calculation, then the difference is equal to double the error.)

Note: Only models consisting of System Dynamics elements only can reasonably be treated in this way. If population submodels are used, it is not possible to reverse the action of the population control elements through time.

This works with both Euler and Runge-Kutta integration, and given the restriction above, it can usually be assumed that Runge-Kutta integration is preferable.

In: Contents>> Running models

Running models : Using Runge-Kutta integration

Runge-Kutta integration

Runge-Kutta integration provides more accurate values for a given level of computational effort than Euler integration, for those models involving only systems of differential equations. Simile always uses Euler integration by default, because it is applicable to any model.

For example, consider the equation dy/dt = t, and given y = 0 at t = 0. In this case, there is an analytical solution, y = ½t2, and therefore at t = 100, y = 5000. Using the Euler integration algorithm, and using a step-size of 0.1 (the default) Simile calculates the answer to be 4995. Using Runge-Kutta integration, the correct answer of 5000 is found using the same step size (and therefore approximately the same computational effort). Even using a step size of 0.01 the answer is calculated to be 4999.5, using Euler integration.

However, it must be noted that Runge-Kutta integration is not always applicable, unlike Euler integration, which can be used to solve any system of differential or difference equations.

In particular, Simile allows the construction of difference equations, where certain quantities accumulate in sudden increments corresponding to weeks, months or years, for example. Interest payments, in particular, correspond to this method of accumulation. These systems must be solved by Euler integration, with the step size chosen to correspond to the periodicity.

Furthermore, although Runge-Kutta integration does not fail when used with discontinuous functions (such as are involved in the creation and destruction of instances of population submodels) the results will be no more precise than using Euler integration.

The choice between Euler and Runge-Kutta integration is made at run time, using a drop-down box in the Run Control. The chosen method is saved with the model and restored when the model is loaded. The user can experiment with running a model using either method, without having to rebuild the model, to understand whether a significant improvement is achieved.

In: Contents >> Running models

Running models : Working with visualisation tools

Working with helpers

A helper is a tool that can be used to interact with a simulation. Simile provides helpers to display the results of a simulation, for example, to plot graphs, or tabulate data, or to enter data into a simulation as it proceeds. Some helpers do both: for example, the grid display helper also enables the user to set a value for any grid square. It is simple to add new helpers to Simile. If you are interested in learning how to develop new helpers for your own models, please contact us at Simulistics.

Most of the helpers are used as follows:

  • If using the Single-window Model Run Environment, select or create an empty pane
  • Add a helper tool, either by clicking that helper's button in the MRE toolbar or by selecting it from the pull-down menu ("Add..." or "I/O Tools" -> "Add...")
  • Specify which model variables will drive the display, by clicking on them either in the model diagram or in the Model Explorer tool
  • If the tool can display multiple data items, hit the + button to add further items to the display.

Extra features common to several helpers:

  • Clear the display with the clear button
  • Remove a data item from the display with the - button (values already displayed for it may persist)
  • Add notes to the display area of canvas-based helpers (e.g., plotter, grid display) with the T text button
  • Configure the helper with the configure button

Simile comes provided with a number of standard helpers. Some are generic, such as the "Plotter" and "Data table" helpers. Others are quite domain-specific - the "Lollipop diagram" helper, for example, was developed for displaying tree growth - but are included because (with a little imagination) they can be applied to a range of situations.

The configuration of helpers best suited to viewing a particular model can be saved to a file.

In: Contents >> Running models

 

Running models : Working with visualisation tools : Plotter

Plotter helper

 

The plotter helper is for plotting graphs of one or more variables against time. If a variable has many values, e.g., one in a multiple instance submodel, all the values will be plotted. Different colours are used for different variables, and for data from successive model runs. Hovering over a trace on the diagram will result in a popup window giving the indices of the particular value it represents, the time in the run at which that point was plotted, and its value at that time and at the current time.

Clearing the display

To remove all the plotted data, click on the button.

Selecting elements to plot

One or more elements can be added to the graph.

  • to add an element, click on the button. An instruction is then posted to click on the model element to be plotted. This can be on the model diagram or in the model explorer.
  • to remove an element, click on the button. An instruction is then posted to click on the element to be removed, in the legend of the graph. Data already plotted for that element will not be removed untiil the clear button is clicked.

Highlighting a trace

Clicking on one of the traces will highlight it by drawing it in double thickness. You can highlight many traces at once. Clicking on it again will reset its display state to normal.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : Table

Data table helper

The data table helper is a tool for tabulating the results of a simulation run. You can use it if you want to inspect the simulation results in more detail than you can on a graph, or if you want to export the results, as a data file in comma-separated value (CSV) format, to data presentation or analysis software, e.g. Microsoft Excel.

You can specify as many model variables as you want. Any of the variables can be nested in multiple-instance submodels to any depth, in which case each instance of the submodel will be allocated one column. The leftmost column displays the times at which the values were recorded. Columns can be removed, if desired, after the simulation has completed. The precision (number of decimal places) to which the numbers are displayed can be increased or decreased before each run of the simulation.

Note that for very large arrays of values this tool can run quite slowly, because it is oriented towards interactive display. It can be improved by turning off updating at every display time (this option is available in the properties dialogue). If you want to save very large data sets, or time series from long runs, it may be quicker to use the snapshot tool.

Clearing the display

To remove all the tabulated data, click on the button. This preserves the column headings, but removes all the rows of data except those corresponding to the current time.

Choosing elements to tabulate

The elements to be tabulated are selected as column headings. The procedure for choosing elements is as follows:

  • to add an element, click on the button. An instruction is posted, to click on the element to be tabulated. The element can be chosen from the model diagram or from the model explorer.

  • to remove an element, click on the button. An instruction is posted, to click on the column headings to be removed. The first click indicates the start of the range of columns to be removed, the second click indicates the end of the range. If the same column is selected twice, only that column is removed.

Saving table data

To save the data displayed in the helper, click on the Save button. The table will be saved in .csv format with the headers and values arranged as they currently appear in the display. Where headers are spread over more than one column, empty fields will be added to the saved table so that subsequent headers in the same row still line up with the correct data columns.

Arranging the layout

The layout of the table is controlled using the Table properties dialogue box. Clicking on the Properties button will bring up a dialogue box with two tabs. These tabs provide options to change the table layout, and to alther the way in which values are displayed.

Adjusting table layout:

This allows the user to designate which dimensions of the data to use as row and column headings. For example, time can be used as either a row or column heading, and element names and element indices can be used similarly. This tab also includes the option to show current values only as an alternative to showing values for all time points with the relevant time as a row or column heading.

Adjusting value display format

This tab, titled "Variable formats",  provides several options for adjusting the way in which values are displayed in the table. The pulldown menu at the top allows you to specify which values the changes made here should apply to; the default is "All" but you can choose to re-format the values of only one particular variable in the table by selecting its caption here.

The leftmost listbox allows you to select the type of value which is being displayed. As opposed to pure numeric values, you may choose to display them as angles (d °m ' s ") with conversion from radians if appropriate, or dates/times with conversion from Julian days. Boolean is provided in case your data uses numerical values to represent true/false states, but if the value is actually boolean in the model, this will be selected by default.

The next listbox allows you to select from a variety of formats for each value type, most importantly between General and Scientific (exponential) for numeric values. The right frame allows the number of decimal places displayed to be adjusted via a spinbox, and provides an option to highlight negative values by displaying them in red as in accounting ledgers.

Logging data over time

Normally, the table helper shows data from the model at any time point corresponding to start of a display interval. By selecting "current values only" from the layout tab, the helper can be made to display only the values for the start of the current display interval. No time heading or time values will appear. In this mode you can unselect "update at display intervals" on the same tab, which results in the data not being updated at all except when the update button is clicked. When a time axis is displayed, the data is still logged even when it is not updated in the table, so clicking the update button will result in all the values since it was last clicked being displayed.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualization tools : Layers

Layer display

The layer display tool differs from Simile's other display tools in that it allows a number of different types of display to be superimposed to create a composite image of processes in a 2-D modelled world. When the layer display is selected, a blank window appears in the run environment, and the 'Add' menu is replaced by a 'Layers' menu which allows the modeller to add instances of layer tools to the display, and to manipulate existing layers.

There are currently four different layer tools:

As of Simile v6.9 there are also a set of '2-D shapes' tools, for adding layers consisting of circles, lines or ellipses. These are analogous to the corresponding object types in the 3-D Shapes tool.

The spatial grid and polygon maps are similar to the corresponding stand-alone spatial grid and polygon tools, with the exception that they cannot be used to change values of model components. The background photo tool simply allows an image to be displayed behind anything that is added by the other tools, and the moving individuals tool displays icons (specified as series of Tk canvas drawing commands) for members of a submodel which includes values representing their co-ordinates in a 2-D space.

Layers menu

When the layer tool is first added, the layers menu will consist of a single entry labelled "Add new layer here". This cascades to a set of menus listing the available layer tools according to their source, like the menu for selecting the regular helper tools. Once a layer tool is added, the modeller will be prompted to select files and/or click on model components whose values will control the layer display, after which the layer will be added to the display. The layers menu now has a new entry for this layer, with 'Add new layer here' entries above and below it.

Once layers have been added, the menu lists all the existing layers, with 'Add new layer here' entries above, below and between them to allow new layers to be added at any position in the stack. Selecting the entry for an existing layer cascades to options to move the layer to the top or bottom of the stack, up or down one level, delete it or open its properties dialogue. A layer's properties dialogue will have a set of input widgets, some of which are unique to the layer type, and some common between various layer tools. The common ones are:

  • Select colours: This allows the colours representing the different model values (as shown in the legend) to be changed.
  • Range: The range of values covered by the colour spectrum can be widened or narrowed.
  • Offset and scale: Normally, data with the same numerical X and Y coordinates will display at the same point in the window in any layer tool, but these values adjust the display position of each layer. They can be used to compensate for different coordinate units being used in different parts of your model, or to show different maps side by side in the same window.
  • Legend side: For tools that can display a legend, this selects at which side of the window it appears, if at all. If multiple legends are added to the same side, the ones for the higher layers will be drawn on the inside.

In: Contents >> Running models >> Working with helpers

Working with visualization tools : Layers : Spatial grid map

Spatial grid map

 

This layer tool is very similar to the spatial grid display, with a couple of exceptions:

  • It cannot be used to set the values of model components
  • If used with a component in a hexagonal grid, the cells will be shown in a 'brickwork' pattern corresponding to the centres of the hexagons.

This tool may also be slower than the spatial grid display, since a more complex image scaling operation is required to get the grid to the exact scale to match other components.

In: Contents >> Running models >> Working with helpers >> Layer tool

Working with visualization tools : Layers : Polygon map

Polygon map

This layer tool is generally similar to the polygon helper, and is set up in a similar way. The differences are as follows:

  • It can be set to redraw the polygon outlines at each display interval, to cope with models in which polygons appear and disappear, or change shape
  • It cannot be used to set values of model components
  • The value for the colour is selected first. If this is from a hexagonal grid submodel, there is no need to provide vertex coordinates -- the helper generates the hexagon outlines itself.
  • The properties dialogue allows a stipple pattern to be chosen for filling the polygons. This allows lower layers to be partially seen through them.

This tool is faster than the old polygon helper with large numbers of polygons.

In: Contents >> Running models >> Working with helpers >> Layer tool

Working with visualisation tools : Layers : 2-D Shapes

2-D Shape Layer

 

This layer tool is similar to the stand-alone 3-D shape viewer, but displays 2-D shapes in a layer rather than projected 3-D shapes. Whereas one instance of the 3-D shape viewer can display sets of shapes corresponding to several sets of model valriables, each instance of the shape viewer layer only displays a set for one group of model variables. If multiple sets of shapes are required, each one can be added in the same view as a separate layer.

 

The shapes that can be added are circle, ellipse or line. Each has a separate submenu entry for adding it, so once it is added, the modeller is prompted for the information that enables the display to be set up. X and Y co-ordinates are set from components in the model, or fixed numeric values can be entered in an input field. If a model component is chosen for the colour of a shape, the colour legend editor appears in order to record how the model values will be converted into colours for the corresponding components.

Working with visualisation tools : Layers : Spatial input layer

Spatial input layer

This layer helper allows spatial input to be sent to a model during execution. When it is added as a layer, the modeller is requested to select three variable parameters from the model. These must be scalar with numerical units.

 

The first two of these will hold the X and Y coordinates of a position in the field of view of the layer tool. They are not changed until the modeller clicks or drags within the tool. At that point they will be continually updated with the pointer position within the layer tool until the unclick. The final variable is set to zero at any time when a click or drag is not in progress. It is set to 1 when a click occurs and is incremented by 1 whenever the pointer coordinates change during a drag. This is so the model can keep track of the speed or duration of the drag. It is set to zero again on the unclick.

 

This tool does not itself display anything within the layer helper area. Normally it would be added to a layer tool which is also showing a spatial grid covering the area in which the coordinates could be expected to fall, so the tool could be 'zoomed to fit' resulting in the input pointer layer also extending over the right range of coordinates. If there is no actual grid to display, the area covered by the input tool could be set by adding four 'line' layers, each with a single line corresponding to one side of the rectangle containing the desired input coordinates. These coordinates could be entered directly to the layer tool as numbers, or got from model variables.

Working with visualization tools : Layers : Background photo

Background photo

This is not really a visualization tool at all -- it just allows an image to be displayed as a background to the layers. Generally the image will be some form of map that corresponds to the data in the model. Because the pixel pitch of the image may not correspond to the position data in the model, the properties dialogue allows an offset and scale to be set for the image display. Thus the tool also allows the whole layer display to be annotated with small images.

When the tool is selected, a file selection dialogue appears for choosing the image file, which immediately displays. Its offset and scale are then adjusted via its properties dialogue. To change the image, delete the layer and add a new one.

In: Contents >> Running models >> Working with helpers >> Layer tool

Working with visualization tools : Layers : Show moving individuals

Show moving individuals

If a model includes a group of submodel instances representing mobile individuals, it may be desirable to display them on a map background using icons. That is what this layer tool is for. It can draw a lot of copies of an icon representing an individual at positions specified by model data. It can also vary the size and orientation of the icons according to data from the model.

The image data file

In order to do this, the icon must be expressed as a series of canvas drawing commands in the Tk language. Tk is the standard graphics extension for scripting languages including Tcl, Perl, Python and Ruby. An example file to draw the ants in the image on the Layer tool page is included in Simile's examples directory, and the images for Simile's population channels are also encoded in this way. These files typically have the extension .cnv. It is hoped to offer a Paintbox-style drawing tool for creating images in this format in the near future.

The file consists of a series of commands to draw the icon on a canvas referred to as $c. This will cause it to be drawn in the layer display when sourced by this tool's code. If the ability to rotate the icon is to be used, then only canvas objects that can be drawn at any angle should be included, i.e., avoid arcs and ovals (unless circular) and rectangles. As well as drawing commands, the file should include an instruction to set the hotspot -- this is the point in the image that will be positioned on the map point given by the model data, as a pair of integers, e.g.,

set hotspot {100 150}

Similarly the scale should be set, i,e., the number of canvas units of the drawing commands corresponding to one unit of map space. A large value will mean the image is drawn small, and is useful for precision because positions and line thicknesses in the image file must be integers.

set scale 10

It should also set the axis direction, in which the image as drawn by the canvas commands appears to be facing. This can either be a compass point (ne, sw, etc), an hour on the clock face (6h, 9h, etc) or a number which will be treated as the number of radians the axis lies anticlockwise from the x axis. e.g., these three forms are valid and equivalent:

set axis n

set axis 12h

set axis 1.57

Setting up the tool

When the layer is selected, a file selection dialogue appears for choosing the image file. Once the file is selected, its contents are loaded into the helper setup, so the file is not consulted again -- if the image is altered, the layer must be deleted and re-created to display the new version of the image. Now you will be prompted to click on model components for the x and y coordinates of the individuals' positions on the map. These have to be supplied. You will be prompted to click on two more model components to specify the size and orientation of the individuals. If you do not wish the icons to be changed in size, just click on one of the components you have already clicked on at this point, and the size will not be altered. The value of the orientation component can be a number, which is interpreted as the number of radians anticlockwise from the x axis which the image will be shown facing. Alternatively it can be a member one of the enumerated types used to index the neighbour directions in the special-purpose submodels, in which case the image will be drawn facing in that direction. In either case, if the value of the direction component is the same as the axis direction in the model file, the icon is drawn unrotated. If no rotation is to be done, select a component that has already been selected for x or y position as the rotation.

In: Contents >> Running models >> Working with helpers >> Layer tool

Running models : Working with visualization tools : 3-D Shape Viewer

3-D Shape Viewer

This is another helper that can superimpose shapes representing information from a number of different model components which may represent different types of object and have different array dimensions. In this case, a set of model components can be used to provide data for a shape or group of shapes in a 3-D scene. For instance in this representation of a plant, a sphere is used to show the root volume, cylinders are used to show the leaf stems (petioles) and ellipses are used to show the leaves themselves.

When the helper is first invoked, the grid is displayed showing X axis indices in red, Y in blue and Z in black. There are currently three types of shape which can be added. The dimensions of all model values used to create each set of shapes must be the same. To add a set of shapes, select the type using the menu button at the bottom. You will then be prompted to specify how the shape corresponding to each model instance will be drawn.

The controllable aspects of the shape include its geometry, specified as one or more sets of X, Y and Z coordinates, possibly its size or thickness specified as a single value, and one or more colours. Each of these aspects can be set to correspond to a model value (by clicking its component), or given a fixed value in the helper (by entering the number). In the case of colours, a value for all that group of shapes can be selected using a standard colour selection dialogue, so shapes in that set will have the same colour(s). Alternatively, the colours can be set like the geometry, according to the values of a model component. If this is done, the standard dialogue for creating a colour legend is displayed, so the modeller can specify how the model values map onto displayed colours. Note that for this tool there is currently no opportunity to set the range of values covered by the colour legend; it is always from zero to the number of swatches (which can be up to 255). 

When the selections are complete, the shapes will be added to the display.

Sphere

This is the simplest type. It requires model components representing the X, Y and Z coordinates of the sphere centres, and one for the radii of the spheres. The colour must also be specified.

Line

This requires seven model components, representing the X, Y and Z co-ordinates of the start and end of the line, plus one representing the line thickness. The colour must also be specified.

Ellipse

This requires eight model components. The first three are the X, Y and Z co-ordinates of the ellipse centre. Then there is one for the radius of the ellipse along the X (major) axis, and one for the eccentricity, which is the factor by which the Y axis radius is smaller. The ellipse will be drawn parallel to the XY plane if the next two are zero. The first of these is the rotation about the X axis, which rolls the ellipse around the major axis. Then comes rotation about the Y axis, which tilts it around the minor axis. The last one is rotation around the Z axis, which revolves the ellipse in its plane. Note that each rotation also rotates the axes for subsequent rotations. In addition to the geometry, two colours must be specified for ellipses, the first for the front (initially upper) surface, the second for the back.

Navigating the scene

The view in the shape viewer can be adjusted using the mouse. The camera can be swivelled around the centre of the view by left-dragging in the view window, and zoomed in and out using the scroll wheel. Right-dragging will cause the camera to move perpendicularly to the direction in which it is looking.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualization tools : Sliders

Sliders for Variable Parameters

This window contains sliders (or switches, or combo boxes, depending on the data type) for variables marked as being  "Fixed parameters" or "Variable parameters" in the equation dialogue box for those variables.

Choosing which vaues to display

You can use the add button to add a slider for a model component if it is a fixed or variable parameter. The - button allows you to remove the slider for a particular model component. The "add all variables" button will add sliders for all model components marked as variable parameters, as it is for these that sliders are most usually required. The Clear button will remove all sliders. Sliders are grouped by submodel, if their variables are in different submodels.

Input widgets for different data types

On this page I am sometimes using the word "slider" to refer to an input widget for a model component, but it will only actually be a graphical slider if the component has a numerical value. In this case the slider will be drawn horizontally with a numerical legend with values between the component's minimum and maximum values as specified in the equation dialogue. If the component has an integer value, the slider will snap between integer points when it is dragged along the scale, otherwise it can be dragged smoothly along the scale. There is an entry box to the left of each slider, allowing a number to be typed in if you want to set the slider's position to an exact value.

Note that each slider is scaled individually according to the maximum and minimum values provided in the equation dialogue box. This information comes from the values for Min and Max entered in the Equation dialogue window. The initial value for the slider comes from the value entered into the Equation field of that window; if no value was given, then the slider is positioned at the mid-way point.

If the component has a boolean value, its entry widget will be a checkbutton. Checking the button sets the value to "true".

If the component's value is a member of an enumerated type, the entry widget is a combobox with a pulldown list of the type's members, allowing you to choose one.

Sliders for multiple values

Adding a slider for a variable with multiple values (e.g., from a multiple-instance submodel) will cause a group of input widgets to be added. The variable's caption appears above, rather than to the left of, the sliders, and each one has an index to the left indicating which model value it affects. If the values form a one-dimensional array, there will be a single input widget for each value. However, if the array is more than one-dimensional, there will only be a separate slider for each inermost index. Moving a slider will set all the values with that innermost index.

You cannot add a slider for a model component inside a variable-membership (e.g., population) submodel.

Interaction with the model (changed in v6.8)

Moving a slider directly affects the corresponding value in the model. If the model is not actually running when the slider is moved, an extra rate evaluation is immediately performed in order that other model values that depend on the slider are also immediately affected. This does not affect state variables such as compartment values. After this rate evaluation is done, the visualization tools are updated so the values being displayed are those resulting from the slider move. For example this update may produce a vertical line on the plotter between the old and new values.

Resetting the model now causes variable parameters to go to their default values. Sliders will move to the default values by themselves on reset. So, to use a slider to run a model with different values from reset, the slider should be adjusted to the initial value after reset but before starting the model run, which now causes the value to take effect at the initial time. Simile v6.9 also includes a preference choice to allow sliders to keep their values over model reset. To choose this option, uncheck 'reset sliders on model reset' in the Run tab of the preferences window.

For fixed parameters, setting the value with a slider has the same effect as setting it in the file parameters dialogue box. That is, no change will occur until the next model reset. If you adjust an input widget, the model will prompt you to reset it before continuing to run in order that the change takes effect. The sliders cannot be adjusted while the model is running.

The slider for a value will move by itself in response to a change in the component's value caused by something else when the model is running. Thus, if you have a slider associated with a variable parameter which also receives values from a time series, the slider will move to the value for each time point as that time arrives. A slider associated with a fixed parameter compartment will move to follow the compartment's value as the model runs, but cannot be adjusted until the model in paused, after which the adjustment only takes effect when the model is reset.

In: Contents >> Running models

 

Running models : Working with visualisation tools : Others

Using other helpers

Because of the ease with which new helpers can be developed (see below for details) a great many other helpers exist, alongside the plotter and the data table. These helpers are of a variety of ages and provenances, and do not conform to any consistent interface. Some were developed for specific applications, and although they are of general interest, reflect their origins in their design.

In order to use a helper, your model firstly needs to be built: that is, you need to have selected the "Build" item from the "Model" menu, as described in Running Models. Almost all these helpers work best in the multiple-windows run time environment. The procedure for adding helpers differs, depending on whether the single or multiple-window run time environment is selected.

The other helpers included in the standard installation of Simile are:

With the exception of the "Plot value against time" helper, all these helpers are primarily designed to display data from multiple-instance submodels. The spatial grid display and the three-dimensional viewer are designed to display data from multiple patches of land. The time lollipop display and the time profiles helper are designed to display the attributes of each instance of a population submodel. All these helpers use the following procedure for binding variables.

There are a few other tools, which don't actually perform the input/output functions of helpers but which are implemented as helpers because they operate on the executing model. One  is used to initialise the pseudo-random number generator:

 Initialise pseudo-random number generator

Another is used to alter the behaviour of functions defined by sketch graphs:

 Edit function sketch graph

New to Simile v6: a tool which saves selected model values to file each time step:

 Data logger 

Binding variables to helpers

When you select, for example, the "Plot value against time" helper, you need to specify which variable in your model will be plotted. Therefore, the helper issues an instruction, asking you to select a variable by clicking on it in the model explorer or in the model diagram window. Other helpers require more than one variable: in these cases, the instructions indicate the sequence in which the variables should be selected. For example, the "Lollipop diagram" helper (which displays trees in three dimensions) requires you to click first on a variable representing the x-coordinate of each tree; then on one representing the y-coordinates; then on one representing the heights. Note that no checks are made to ensure that the variable you select for x-coordinates really does contain x-coordinates: it is up to you to choose the right one.

Each helper uses one of two methods for instructing you to select the necessary variable(s):

  • Separate instruction window: a small window instructing you to click on a model element. The window will tell you the role of the variable that you are selecting in relation to the helper's task, and you need to click on a variable that is appropriate to that role.
  • Instructions in the helper window: an instruction about what you should be doing in the helper window itself. One example is the slider input helper. Typically, this allows you to repeatedly select variables from the model, with each one being added to the helper.

Developing new helpers

Simile is probably unique in the world of visual modelling software in that no input/output tools are built into the software. Rather, every such tool is implemented as a separate program in an industry-standard interpreted language called Tcl/Tk. When you load Simile, it creates a list of available helpers by looking in the "IOTools" directory for appropriate files. This is the list of helpers that is then bound into the menus.

One advantage of this approach is that with simple programming anyone can implement a helper customised to their own requirements: there is no need to submit a request to Simulistics (though you are, of course, welcome to do so). This means that if you are modelling (for example) whales, you can implement a display helper that shows whales swimming around. These helpers can be distributed easily, as simply copying the file to the "IOTools" directory is sufficient to install the helper in each copy of Simile.

In: Contents >> Running models >> Working with helpers

 

Running models : Working with visualisation tools : Grid

Spatial grid display helper

The spatial grid display colours a two dimensional rectangular grid according to the value of a specified variable within each grid square. It is typically implemented using a multiple-instance fixed membership submodel. 

Positioning the grid squares

When you add a helper of this type, you are first requested to supply a variable to use as the colimn ids. This variable must have the same number of values as the one that is actually to be displayed, but it is only used to calculate the dimensions of the grid. The grid will have one column for each discrete value in this variable (e.g., if the values are 1,1,1,5,5,9,9,9,9 thenthere are 3 discrete values, 1, 5 and 9). The number of rows will be the total number of values divided by the number of columns. The actual values are unimportant.

You are then requested to supply a variable from which to get the values for the square colours. This variable should have the same number of values as that used to define the columns. If there are more values, the later ones will be ignored. The values are placed in the grid starting at the bottom left corner and going across to the right, then filling the next row from the bottom and so on. If there are fewer values than the number of cells in the grid, they will be used again to fill the rest of the grid.

Zooming and scrolling

The + and - buttons in this helper enlarge and reduce the displayed grid, in steps of one pixel per grid square. When the grid extends beyond the boundaries of the display port, you can use the scrollbars at the borders to bring various parts of it into view. Note that the colour legend will always obscure part of the grid if you can scroll perpendicularly to it. To see all of the grid, you can move the legend between the bottom and the right of the display using the "Orientation" radio buttons in the helper's properties dialogue. The 'Save' button will save an image showing the legend and visible part of the grid, in the format indicated by the supplied file extension.

Choosing colours for values

The legend shows which colours correspond to which values from the variable. It has different colours over a certain range of values. The range can be increased or decreased with the < and > arrow buttons in the toolbar, or it can be set exactly using the "Scale range" entry fields in the properties dialogue. If the data variable is boolean or enumerated type, there will be one colour for each of its possible values. If it is an integer, there will be a different colour for each value in the range, up to 100 colours. Otherwise, there will be 33 colours corresponding to smaller ranges of values within the whole range. Values outside the range are shown in the colour for the nearest end of the range.

For numerical values, there are initially three colours for low, middle and high, (black, yellow and white in the image above) with other colours fading between these for other values. This arrangement can be changed using the colour map editor.

Viewing and changing information

The grid display normally updates as the model runs, but can be frozen by clicking the "Freeze" button at the right of the toolbar (this feature is left over from the days when the graphics took a long time to update; these days they are very fast).

Clicking on the display gives a popup with the column and row number of the grid square in which you clicked, plus its value (which will be approximate if the display is using colours to represent ranges of values). Dragging produces more poups for each grid square entered. Hovering over a colour in the legend shows what value it represents.

The grid helper can also be used to set the values of model parameters. This does not work for variables other than parameters. Click on the "enter edit mode" button (with the pencil icon) then click on the colour legend to select a colour to "paint" onto the grid. Click on the legend again to paint a new colour. Changes made to parameter values in this way will not take effect immediately; the same rules apply as for changes made with the slider helper.

Saving information as GeoTIFF

The second tab in the properties dialogue allows the grid to be saved as a GeoTIFF (for more information see section on loading GeoTIFF data). To use this tool you must have the GDAL library installed on your computer. Load a template file from which to copy the georeferencing data, then save a new file using the data from the grid. This is useful if you have parameterized your model with data from GeoTIFF files. You can also choose to have a file saved at each display interval after the grid data is updated; the time value will be appended to the chosen filename.

A three-dimensional view of a rectangular grid is also possible using the 3d viewer.

In: Contents >> Running models >> Working with helpers

The Colour Key Editor

Simile can now produce displays of grid or polygon data with a wide choice of colour keys thanks to the colour key editor. It is possible to reproduce the sort of colour keys typically used in relief maps, thermographic imaging systems, weather maps and magnetic surveys. The colour key editor can be invoked from most visualization tools that can express data as colour.

As well as editing the key as described in the dialogue, it can be loaded or saved in .rgb format, which is widely used by GIS systems. Simile's examples directory contains a saved legend, 'eightbit.rgb', which generates swatches corresponding to the colours that would be converted into each integer between 0 and 255 when using the 'eight-bit colourmap' option in the image data loader. It is thus possible to view an image which was loaded as data in a grid helper, possibly after it has been altered by execution of the model.

Running models : Working with visualisation tools : Plot value

Plot value against time helper

This is the classic time-plot helper. For most uses, it has been largely replaced by the Plotter helper.

It was not designed for presentation in a printed document, but for giving the model developer a robust, flexible display of how the value(s) for a single variable change over time. It automatically re-scales, on both the X (time) and Y axes, it can handle a variable no matter how deeply nested in multiple-instance submodels, and it displays the results from previous runs for comparison. It also gives the current values for all the variables in text form.

Each time you select a "Plot value against time" helper, you need to choose the variable to be plotted before the helper is displayed. You are alerted to this requirement by the message:

The following screen dumps show the standard ways this helper can be used.

This shows the value for a single-valued variable "size" from three successive runs of the model, using different parameter settings on each run. Note the automatic use of a different colour for each run, and the current value displayed at the bottom-left.

This shows the set of time plots for a single variable embedded inside a fixed-membership multiple-instance submodel. Since the number of instances is fixed for the duration of the run, we have the same number of lines throughout. Note that the line for each instance is different, reflecting the fact that each instance has different parameter values even though they all behave according to the same equations.

Here again we have the plot for a single run, for a single variable embedded inside a multiple-instance submodel. This time however the submodel is a population submodel, with individual instances coming into existence and disappearing during the course of the simulation run. Note then how lines start during the simulation (unlike the previous example, when all lines started at time zero), and also terminate during the course of the simulation, as individual instances are killed off. Each line has a different slope, reflecting the fact that the model was set up with a randomly-determined parameter value for each instance.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : Profiles



Time profiles helper

The time profiles helper is designed to show multiple attributes of each
instance of a population submodel. Each instance must be assigned a unique
identifier, which is plotted sequentially on the y-axis. A stacked bar
chart display is used to plot an arbitrary number of properties of that
instance against time.

For example, each individual in a population may hold wealth in the form
of property, stocks and shares, and cash. The time profiles helper will
display the changing wealth of each individual over time (the total height
of each bar) as well as the make-up of that wealth (the height of each
coloured segment).

For best results, the variables plotted should be scaled to be less than
50. Panning and zooming operations are implemented as for the plotter helper. The y-axis can be panned up or down and
the x-axis panned left or right to display different parts of the axis at
the same magnification, whilst both axes can also be zoomed in or out to
increase or decrease the magnification.

  • The cursor takes on the shape of a
    four-headed arrow when placed over a scale point. Dragging a scale point
    alters the range displayed by zooming in or out. To zoom in, drag the
    scale points away from the origin, i.e. to the right (on the x-axis) or
    upwards (on the y-axis). To zoom out, drag the scale points towards the
    origin, i.e. to the left (on the x-axis) or downwards (on the y-axis).
  • The cursor takes on the shape of a
    two-headed arrow when placed over the axis itself. Dragging the axis
    alters the range displayed by panning up or down, left or right.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : Model Explorer

Model Explorer

The model explorer provides a nested tree view of all the variables, compartments and flows used in the model. The elements are arranged by submodel, hierarchically from the top level desktop. In variable-membership submodels, additional elements used only in those submodels are also displayed. When a "helper" window requires a variable to be selected, this action can be performed by clicking on the required variable in the model explorer.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : Lollipop

Lollipop diagram helper

The "Lollipop diagram" is a means of displaying tree-like objects distributed in two dimensions. Each object has a size, which is used to calculate both the length of the trunk and branches. After invoking the helper, three variables are required for each component whose values are to be displayed, corresponding to the x-coordinates, the y-coordinates and the sizes. These can be variables or compartments, and are typically in a multiple-instance submodel. One tree then corresponds to each instance of the submodel.

Each set of values is displayed as trees of a diferent colour. A horizontal grid is also drawn, with x positions numbered in red, and y positions in blue. Numbers corresponding to heights of trees (z variable in the legend) are positioned above the grid corners in black.

There are sliders to adjust the longitude (view angle) and latitude (view elev.) of the point on an imaginary sphere surrounding the grid from which it is viewed. The image can be printed.

Note that all three variables can change through time, so although real-world trees may not move, their graphical representations can. This means the lollipop diagram helper can also be used for simulating animal movements, and so forth.

For best results, the x- and y-coordinates should be scaled between 0 and 100, and the size should be less than 25.

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : Initialise

Standard helpers: Initial pseudo-random number generator

The functions rand_var() and rand_const() generate random numbers. For greater understanding of model behaviour it is sometimes convenient to generate the same (or the same sequence) of random numbers for several model runs. To do this, it is necessary to seed the random number generator with the same integer value each run. For this reason, they are known as pseudo-random numbers. A simple tool is provided to enter the seed.

To enter the seed:

  1. enter an integer value in the edit box;
  2. click on the "Set seed" button; and
  3. reset the model.

Note: It is important that the reset button on the "Run Control" is used AFTER initialising the pseudo-random number generator using the "Set seed" command. This is because some random numbers are generated when the model is reset.

Example

Using the seed "123" will produce the following sequence of random numbers for the function rand_var(0,100) every time the simulation is performed:

62.3463, 2.2889, 13.6723, 11.7893, 92.8648, 56.7217, 93.8688, 96.4232, 96.3378, 75.1671, 49.0097, …

(At least if you are using the bundled MinGW C compiler under Windows. Other compilers may produce different sequences, owing to using different library implementations of the pseudorandom sequence generators, but this tool can still be used to achieve repeatability.)

In: Contents >> Running models >> Working with helpers

Running models : Working with visualisation tools : 3d

3d viewer helper

The 3d viewer helper is similar in operation to the spatial grid display helper, though four variables, rather than two, are required, to display the grid in three dimensions. These are, as before, the x-coordinates and the colours, but also, the y-coordinates and a sizes. Again, these are most commonly implemented using a fixed membership multiple-instance submodel.

 

3d viewer helper

The 3d viewer helper is similar in operation to the spatial grid display helper, though four variables, rather than two, are required, to display the grid in three dimensions. These are, as before, the x-coordinates and the colours, but also, the y-coordinates and a sizes. Again, these are most commonly implemented using a fixed membership multiple-instance submodel. 

Amongst the many menu options, is the ability to switch to a surface view of the grid, as shown in the following screen shot. There are also options to rotate the graph through three dimensions, and to select the colours used.

In: Contents >> Running models >> Working with helpers

 

Other visualization tools : Event sounds helper

Other visualization tools : Event sounds helper

The motivation behind Simile's visualization tools is to provide the modeller with a continuous, immediate understanding of what the model is doing. Sometimes the best way to do this is with sounds rather than graphics. With the addition of discrete events to the modelling language, we realized that their instantaneous nature does not lend itself to the kind of graphical displays that work for continuous values. 

So we created an event logger that also produces a sound each time a selected event occurs. Add an instance of this tool in the standard way, selecting 'Event sounds' from the list of helper titles. Now after clicking '+' in the helper window's toolbar, you can select a discrete event component in your model, and a sound file to play each time the event occurs. The window will show a 'ticker bar' which will move across the screen right to left, with a vertical line added each time the event occurs. Hovering over the lines will pop up the exact time and magnitude of the occurrence they represent.

Also, the sound will be played each time the event occurs. If your event has a numeric magnitude, then the volume of the sound will be determined by where each event's magnitude falls between the min and max values given for the event. Sound files in WAV format will play on all platforms -- files in other formats (e.g., mp3) may play on your particular platform but are not guaranteed to play on all.

If the chosen event occurs very frequently, or if it is in a simple model that runs very fast, the sounds may overrun each other producing unpleasant noise. In this case you can use the 'limit updates/sec' feature to slow the model execution down to the point where the sounds can be heard separately.

 

Running models : Working with visualisation tools : Polygon diagram

Polygon diagram

This tool enables a dataset to be displayed as the colours of polygonal areas on a map. It can be used either where vector data for an actual map is available (either in the model, or in a separate file), or where an area is represented as some regular set of shapes whose vertices can be calculated by the model, e.g. hexagonal tiling.

A lot of the functionality of the polygon helper, including scrolling and zooming, working with the colour legend, and using it to edit model parameter values, is exactly the same as for the grid helper. However, the graphics of the polygon helper are not quite as fast, so you are more likely to need the 'freeze display' and 'manual update' features.

Loading co-ordinates from file

If you choose this option you will get a file selector to locate the data for the coordinates. If you choose a file with the extension .dxf, Simile will attempt to load it as a DXF file, and will then colour the polygons in the order in which they are defined in the file. Otherwise, Simile currently expects the file to contain all the X coordinates in nested list form, followed by all the Y coordinates. This is not particularly convenient, so we should add the option to set the coordinates from file using the table data dialogue too.

Loading co-ordinates from model

Of course you can put fixed parameters in the model and load them using the table data dialogue, then use them to set the boundaries of the polygons. If you choose this option, you will be asked to select model elements representing the X and Y coordinates of the polygon vertices. These elements should have two-dimensional data arrays, with the outer index being the number of the polygon whose border they define, and the inner index being the number of the vertex around that polygon. There should be the same number and arrangement of X and Y coordinates.

The usual way to get the coordinates is to have a submodel for the vertices inside the submodel representing the polygons. This should be a per-record submodel if different polygons have different numbers of vertices. Put fixed parameters for Xs and Ys inside the vertices submodel. 

In: Contents >> Running models >> Working with helpers

Running models : Working with visualization tools : Edit sketch graph function

Standard helpers : edit sketch graph function

If your model contains equations that use the graph function, their function can be altered while the model is running. The tool for doing this appears as a helper, although it does not display values from the model or directly set them.

The helper is located in the "Standard tools" subdirectory menu and is called "Edit sketch graph function". Create an instance of the helper and click on the model component whose function you wish to alter. You will then see the same sketch graph editing window as when you originally created the sketch graph. You are able to drag the sketch line as well as edit the axis values and change the settings that control how the sketch is interpreted.

Any changes you make to the sketch graph function will take effect as soon as you hit the 'OK' button, but the helper will stay up until you delete it, allowing further changes to be made at any point. Note that the edited function will not be saved with the model. If you save the model after editing the sketch using the helper, it will keep the original version of the function. To change this you must go back to the equation dialogue and hit the "Graph" button.

 

Running models : Working with visualization tools : Data logger

The Data Logger tool does not display model data, but records it in files for later analysis with statistical tools. There are other ways of doing this:

  • The Table Helper can save its contents as a .csv file, but has poor performance with large data sets
  • The Snapshot tool can record values as the model runs, but only handles one variable, and needs setting up every time the model is run

By contrast, the Data Logger can handle any size of data set that is usable within Simile, and can log multiple variables, either in separate files or as columns in a single file. Since it is a standard helper, many instances can be added for different groups of values, and the setup can be saved as part of a general helper layout.

Using the tool

The tool's canvas will be blank when it is first added. To log a variable, hit the + button and click the variable on the model diagram. It will be listed within its hierarchy of submodels, with a '-' button ffor its removal. Hit + again to add more variables. The rightmost button in the helper's toolbar switches between saving separate files for each variable (named by the variable's caption) and a single file (log.csv) with each variable in its own column.

Saved file format

The helper will not save any data until you select a folder in which to save it. Click the toolbar button with the folder icon and navigate to the desired location. Now a line is written to the log file(s) at each display point as the model executes. The files are in .csv format with the time points stored in the left hand column. If the values being saved are arrays, they will be written as series of alternating indices and values, with each series enclosed in curly brackets, i.e., the same format as data popups or directly-entered file parameters.

The file is closed when the model is paused, and opened for appending more data when it is restarted. When the model is first run after a reset or rebuild, the file will be opened for writing, so the previous contents will be overwritten unless they have been moved.

As of Simile v6.9, it is also possible to log model data to a database -- either a file in some Excel-compatible format (.xls, .xlsx etc) or a MySQL database. To log to a database file, simply select it from the file dialogue. To log to a MySQL database, cancel the file dialogue and this will cause the database specification dialogue to appear. Here you enter the hostname, username, password and name of the MySQL database.

When logging to a database, each component being logged will have values put in its own column in the database. If logging an array component, there will be a separate column for each element in the array, named value/n where value is the name of the component and n is the index of the element. (value/n1/n2/... for multi-dimensional arrays). The values will be written to a table called 'Run 0' until the model is reset, after which new tables called 'Run 1', 'Run 2' etc will be created for data values from subsequent runs.

Running models : Inspect model variable

Inspect model variable

The snapshot tool is only available once a model has been built and is ready to run. It is provided to inspect the values of complex data structures held by some model elements. By hovering over a model variable it is possible to view pop-up windows that contain an element's equation, description and value. But in some cases, particularly where the data have more than one dimension, this pop-up window is rather hard to read. In any case, if the data is a very large array, the central portion will be elided to prevent the popup window being too large. As an alternative, use the snapshot tool. This will pop-up a larger, permanent window with the values structured by dimension.

As its name implies, the snapshot tool provides a view of the data structure at a moment in time. You can leave the window displaying the snapshot open, run the model for some more time, and then click again on the same element to open a second window that displays the new data structure. Having the two windows open at the same time, each labelled with the time at which the snapshot was taken, is the easiest way to trace changes to an element or sequence of elements. If you would rather just see the current data, the snapshot tool includes an update button () which will refresh the displayed data with the current values from the model.

Saving data from snapshot tool

Normally you would use the data table helper to create a file containing model data. But because this tool is more oriented to displaying data interactively, it can operate very slowly with large tables. The snapshot tool is much quicker, although less flexible. Another alternative is to use the data logger helper, which is oriented towards storing data from many variables at once.

To save data from the snapshot tool at a given time point, hit the save button. It will prompt you for a file name and the data will be saved to this file as a comma-separated (.csv) file that can be loaded into a spreadsheet. The indices will be listed in columns to the left, outermost first, and the actual data items will appear in the rightmost column.

You can also use the snapshot tool to save data as a time series as the model runs. To do this, hit the log button () and select a file name. Then start the model executing. The values displayed in the snapshot window will not change, but after each display interval the current values will be appended to the file. In this case the indices will be listed in rows at the top of the file, outermost first, with the actual data items appearing below them, one row for each time point. The times themselves will appear in the leftmost column. To stop logging, hit the log button again.

Remember that the snapshot tool is disabled until the model has been built. Only after building the model do the elements have values. The tool is available at any point during the model run.

In: Contents >> Working with model diagrams

Parameter estimation using PEST

Parameter estimation using PEST

PEST is an advanced software tool for model calibration, parameter estimation and predictive uncertainty analysis. It is open-source and freely available, and currently distributed by S. S. Papadopoulos & Associates, Inc.

You will need to install PEST separately on your computer, and ensure that it can be executed from the command line. How to install PEST

PEST communicates with Simile models by creating files containing parameter values, running the model then reading files containing model output values. The model will be run many times. How to set up PEST interaction

When using PEST, model inputs and outputs can be individual values or sequences over time. If an output is a time series, the series itself can be plotted on a display tool alongside the model output. Running PEST

Predictive analysis can be used to get an estimate of a model output at a time later than that covered by available data, or it can be used to provide an uncertainty band around a model output trace. Working with predictive analysis

In: Contents >> Running models

How to install PEST

How to install PEST

PEST is an advanced software tool for model calibration, parameter estimation and predictive uncertainty analysis. It is open-source and freely available, and currently distributed by S. S. Papadopoulos & Associates, Inc. The Simile interface has been verified to work with PEST version 9 and later, on Windows, Linux and MacOS.

Windows users can download a pre-compiled version of PEST from this site and follow the instructions to enable it to run from the command line. Typing 'pest' to the command prompt will produce a message about usage if it is correctly installed.

Linux and Mac users will need to compile PEST from source. PEST is written in FORTRAN, and the GNU g95 compiler is suitable for compiling it. This is part of the GNU compiler collection, and is freely available from SourceForge. Some Linux distributions have the gfortran extension to gcc available from their software repositories, which is also suitable for compiling PEST.

It should be possible to build the package using the makefile shipped with it. The simplest way to get this to work is to create a symlink called 'f90' to the g95 compiler, since the makefiles all include f90 as the default compiler name. This can be placed in a directory in the executable search path, e.g., ~/bin. A symlink to the PEST executable can also be made in this directory once it is compiled.

Check that PEST is installed correctly by typing 'pest' to the command prompt before attempting to run it from within Simile. If it is set up correctly, it will generate a usage help message.

In: Contents >> Running models >> PEST

 

Setting up PEST interaction

Setting up PEST interaction

Once you have got your model behaving in a generally believable way, you can use PEST to calibrate your model parameters in order to match the model's output to a set of measured data.

Details of the operation of PEST can be found in its manual. The manual is included in the pre-compiled Windows distribution. Only the basics of PEST operation will be covered here.

The PEST interface is included in Simile as a helper. It is located in the 'Standard tools' submenu of the helpers menu. When you select it, it will create a tabbed notebook with four pages inside its top-level window. These are labelled Inputs, Outputs, Actions and Settings. If using the single-window Model Run Environment, be careful not to confuse these notebook tabs with those containing other helper pages.

Inputs

On this page you specify which model parameters will be estimated by PEST. You can add a single parameter by hitting the '+' button at the top, then clicking on the parameter in the model diagram or explorer tool. The '-' button allows you to remove a parameter. The last button adds all suitable parameters that have not already been added. Note that PEST can only optimize real (floating-point) value parameters.

A minimum and maximum value must be provided for each parameter. For fixed parameters you can type these into entry boxes. They must reflect the range of values which are plausible. For variable parameters, PEST uses the values entered in the parameter's properties before the model was built.

For variable parameters you can decide whether PEST simply picks a fixed value for them or generates a series of values. There is a checkbox and an entry field for your choice. A series will be spaced regularly over the length of the model run, which is specified in the Actions page. Note that the total number of values being estimated (including all members of each array and each series) must not exceed the number of data measurements being used, or PEST will not have enough information to estimate them all.

PEST also needs an initial estimate for each parameter value. This defaults to midway between the parameter's minimum and maximum value, but you can enter a different estimate. If you select the 'Use current data as estimates' checkbutton at the bottom of the Inputs page, PEST will use the current values at the start of the optimization for its initial estimates.

If an array parameter is used, PEST will use the same specification data for each array member, but will create a separate estimate for each member.

Outputs

On this page you specify which model values are to be looked at by PEST and compared with measured values. Any value in the model can be used, except values from inside variable-membership submodels. You can add a value by hitting the '+' button at the top, then clicking on the value in the model diagram or explorer tool. This indicates a component whose value at the end of each model run is to be compared with measured data. You can also add a value by hitting the graph icon button. This indicates a component whose value is to be sampled at a series of time points during a model run, and each sample compared with measured data. The '-' button allows you to remove a value of either type.

For each value you also need to load measurement data for comparison. PEST displays an input tool similar to the one in the 'File Parameters' dialogue, and data can be entered directly or loaded from files exactly as described for this dialogue.

When you have loaded your measurement data you can save references to it in a scenario file, as you would for parameter data. This scenario file will have the extension .smf rather than .spf to indicate that it refers to measurement data rather than parameter data. In other respects the two file formats are interchangeable.

Restrictions

Simile is a much mode expressive modelling tool than the typical command-line-driven models with which PEST is intended to work, so there are some limits on what Simile model constructs can be used when estimating parameters with PEST. In particular,

  • The interface does not support multidimensional data arrays, or any arrays that are supplied or sampled at different time points since this effectively involves a multidimensional array.
  • Data values must be real, and array indices must be integer (i.e., not enumerated-type).

In: Contents >> Running models >> PEST

 

Running PEST

Running PEST

When you have set up the inputs and outputs in your model that will be used by PEST, you can go the the Actions tab in the PEST interface tool notebook and try to run it.

The run length from the run control will be used unless you alter it in the input box. If you do not select the checkbox in the Predictive analysis section, a simple parameter estimation will be done. Note that if all your outputs are time series, the run length will be up to the last time series value and the entry box for it will have no effect.

A PEST run can be controlled in the same way as a model run : it can start, stop or pause. The progress bar is inaccurate because it is impossible to tell in advance how many model runs PEST will need before it converges on the best parameters. It just shows what proportion has been done of the maximum number of runs specified in the settings.

While PEST is running you will see the run control values and progress bar update during each run. You will also see statistics about the run appear in the execution monitor box of the Actions tab. The text box in the execution monitor displays PEST's output to the command line, which is useful in case it should fail for any reason.

Simile's other helper tools are also updated while PEST runs. This means that if you have a slider tool for the variable parameters which are under PEST's control, you can watch them update as PEST adjusts them to optimize the outputs. However you may not want the tools to be updated, as they may slow down execution, and the plotter will show a separate trace for each run. To turn off all helper updates, set the 'Display interval' entry in the Run Control dialogue to zero. Alternatively you can set it to an interval longer than the run length, so the helpers (including sliders) will only be updated at the start of each run.

When PEST has finished optimizing, the model's parameters will be set to the values it has estimated. You can now go to the file parameters dialogue and save these  values in a scenario file if they will be required later. PEST provides an indication (the 'phi' value) of how good its estimation is, and this is reported in the Actio tab of the helper -- the lower the phi value, the better the estimation. For a graphical view, if you have a time series of measurements and you are displaying the corresponding model value on a tool such as the plotter, you can select the 'show these values on plots' checkbox at the bottom of the PEST tool Outputs panel, then reset and run the model again, and a trace of the measured data will be superposed on the model data trace in the plotter tool.

PEST produces a selection of output files during a run. These are kept in Simile's temporary directory. When PEST has finished running, you can save any of these in a permanent directory using the 'Save a PEST file...' button. Each pest file has a different extension; use the extension chooser in the save dialogue to choose the file you want, and enter the name you want to give it.

If PEST fails to converge on a good set of parameters, you can adjust its settings. The global settings, such as NOPTMAX to control the maximum allowed number of optimization stages, are on the Settings tab. Settings related to each input or output, such as PARCHGLIM which affects how the maximum change of an input value on a single step is applied, can be edited in a context menu for that input or output " right click (ctrl click on Mac) on the input or output field to bring this menu up. The labels on these entries correspond to the names of the settings as described in the PEST manual, which you should refer to when adjusting them.

In: Contents >> Running models >> PEST

 

Predictive analysis

Predictive analysis

When you first run PEST, it runs in parameter estimation mode. This selects values for the input parameters which cause the outputs to most closely follow the measured values, according to the least-squares rule. The quality of fit is given by PHI " the lower this value is, the better the fit.

The purpose of predictive analysis is to determine the range over which a model output can vary while still being consistent with the measured values supplied. To get maximum and minimum predictions, PEST allows the PHI value to be larger than the minimum value found during parameter estimation.

To do a predictive analysis on a Simile model, check the checkbox in the predictive analysis frame on the Actions tab, and select a model value for which to make a prediction. This can be any non-parameter value in the model, not including those in variable-membership submodels. It can be a value which you are already using for comparison with measured data " for instance, if you are using data measured up to a certain point in time to calibrate the model but then want to predict how the same value will behave at later times on the basis of this calibration, or even use prediction to fill in a gap in your measured data.

You can also make the following selections:

  • Whether to predict maximum or minimum values

  • What multiple of the original PHI to allow for the predictions

  • At what time(s) the prediction will apply.

There are some values on the Settings tab which affect PEST's behaviour during predictive analysis; these are explained in the PEST manual. Simile supplies default values for these, based on the results obtained when running PEST in parameter estimation mode.

If the value being predicted is an array, or if the frequency and duration you set for prediction times are such that a prediction will be made at more than one time, then a complete run of PEST must be done for each prediction, because PEST itself can only predict one value at a time. Since each PEST run includes multiple model runs, predicting large numbers of values can take a very long time. The following steps might speed things up:

  • Set display interval to 0, so display tools do not take up time

  • Select 'use current values as estimates' on the Inputs tab after the parameter estimation run, so each prediction run starts with good parameter estimates.

During a prediction run, the progress bar shows how many of the prediction runs have been completed. Predicted values will be inserted into the results field, and can be displayed in tabular form and saved as a .csv file using the View button.

It is worth noting that each prediction is arrived at independently. So, if using predictive analysis to create 'error bands' around a graph of model outputs, it might be the case that although each individual value might vary as far as the predicted limits, it would be impossible for the graph line to actually follow the minimum or maximum limits, since multiple predicted values on the limit might be incompatible with each other. Remember, however clever PEST might appear, it's still only a computer program.

In: Contents >> Running models >> PEST

 

Working with external data

Working with external data

Simile provides a mechanism to enable data to be associated with model variables when you run the model, rather than having the values built into the model itself. The mechanism is based on a file called the scenario file. For each variable, this file contains either the actual values, or a reference to another location which contains the values. This other location can be:

  • a text file, in CSV (comma-separated value) format containing the data, either in a single column or as a grid of values.
  • an image file, with each pixel standing for a data value according to its colour,
  • any of a range of other raw data formats supported by the GDAL library (GeoTIFF, NetCDF 4, .hgt, etc)
  • A column in a MySQL database or Excel data file (.xls, .xlsx, etc)

A "scenario" is then the set of all the values required for the model to run. These include parameter values, site conditions, initial values for compartments, time-series data (e.g. a rainfall record), etc.

This section first provides an overview of the scenario file mechanism, outlining its motivation and capabilities. We then look at the two types of input parameters, the elements by which external data comes into the model. The File Parameter and Table Data dialogues are used to set up the relationshop between data files and parameters. We show how to create .csv files, which are the most widely used kind of data file. We then discuss how modifying parameterization fits into the model edit/run cycle, and provide some worked examples.

See also the 4th video in the Simile Tutorial Series.

In: Contents

Working with external data : Overview

Overview of the scenario file mechanism

A simulation model may require various types of input data. These can include:

  • values for parameters
  • values for site conditions: e.g. soil type
  • values for time-varying inputs (exogenous variables, such as temperature)
  • initial values for compartments (state variables)
  • values for management decisions: e.g. harvesting rate

For each of these, there may be a need to enter a set of values. For example, a compartment of a site-condition variable may be in a multiple-instance submodel and so (if you do not want all instances to have the same value), you will need to provide a different value for each instance.

We have seen a number of ways in which numerical data can be included in the model, in the section on equations. These include:

  • Including numerical constants in the text of equations
  • Sampling from a random distribution
  • Including a sketch graph or table function

...and we have also seen how fixed or variable parameters can be set when running the model, by:

However, none of these mechanisms satisfies a common modelling requirement: that a set of data values be provided for the model when the model is run. We need to be able to store the set of values in one or more files, and specify which set is to be used for a particular run. This is where the File Parameter mechanism comes in.

Design of the Simile File Parameter mechanism

The File Parameter mechanism was designed to meet the following design goals:

  • A model can be complete even though it is lacking data values needed to simulate its behaviour. By complete, I mean that Simile can proceed to build the model: i.e. generate the Tcl or C++ program. Simulating the behaviour of the model requires that the built model is associated with one or more files ("scenario files") at run time. The job of these files is to tell Simile how to obtain values for variables in the model that have not had a value provided.
  • One model can be associated with several scenario files for a single run, each file providing values for a different subset of variables.
  • Different runs of the model can be associated with a different set of scenario files (thus allowing the modeller to quickly change data inputs for a model).
  • The scenario file may either contain actual data values (e.g. for a single-valued parameter), or may contain a reference to a file in a standard format containing tabulated data. This means that a single (potentially very large) datafile can be referenced by several scenario files, thus avoiding the need to duplicate the same large volumes of data in a number of scenario files.

In: Contents >> Working with external data

Working with external data : Input parameters

Parameters

The term 'parameter' usually refers to a symbol in an equation that can take on different values. When discussing equations in Simile, we use the term to describe the local names for values from other Simile components. However, here we are talking about quantities that are parameters for the whole model; special components whose values are specified externally and will change from one run to the next as the simulated conditions change. The values for these components come from outside the model; if they have equations, these are only used to set the dimensionality or provide default values.

There are two kinds of parameter that can be used in models. A variable in Simile can be marked as a fixed or variable parameter by ticking the appropriate radio button in the equation dialogue. A compartment can be a fixed parameter (i.e., its initial value is set externally) but not a variable parameter.

Fixed parameter

The value of a fixed parameter is set when the model is ready to run, and can be taken from a file, a table editor, or entered directly. It does not change its value during the simulation. In Simile v6 or lower, any value in the equation is ignored, and used only to set the parameter's dimensions. As of Simile v7, any value in the equation is used as a default if no other has been set.

Variable parameter

The value of a variable parameter is first set when the model is initialized or reset, and it can change throughout the simulation. Values can be taken from a file, a table editor, or using a slider control. The value in the equation is used as a default if no other has been set. If no value is entered, the default is the midpoint between the lower and upper bounds.

Dimensionality

When you are adding file parameters to your model, it is important that they have the right dimensions for the data that they will hold. The file parameter dialogue only allows you to enter data that has the same dimensions as the parameter that is to represent it in the model. A fixed parameter that is not inside a multi-instance submodel will only accept a single numerical value. To enter an array of values, you must first make your parameter an array, either by putting it inside a fixed-membership multi-instance submodel, or by giving it an equation whose result has array dimensions, e.g., by using the makearray(...) function.

See also the 2nd video in the Simile Tutorial Series.

In: Contents >> Working with equations

 

Working with external data : Fixed parameters

Fixed parameters

A value of a fixed parameter is not stored with the model, but is supplied by the user when the model runs. The value cannot change during the simulation. To set the value of a fixed parameter use scenario files. These are loaded as the model is built or reset.

Use the "Units" field to define the units as integer (int), real or Boolean (Boolean). An equation can be entered whose dimensions will be used as the dimensions of the parameter data. In Simile v7 or later, the equation also sets its value if no value is entered via the parameter mechanism.

Use the equation dialogue box to designate a variable as a fixed parameter. It is also possible to set the initial value of a compartment in the same way. A fixed parameter is shown on the model diagram with a  paper roll behind its usual appearance.

In: Contents >> Working with equations >> Parameters

Working with external data : Variable parameters

Variable parameters

A value of a variable parameter is not stored with the model, but is supplied by the user when the model runs. The value can change during the simulation. There are several ways to set the value of a variable parameter. One is to use slider controls. These can be displayed in the run-time environment and provide a mechanism for the user to observe and adjust the value of the parameter. The other is to use scenario files. These are loaded as the model is built or reset, and can provide a time-series of values for the parameter.

Maximum and minimum values must be set to define the range of acceptable values for the parameter. This allows the slider control to be shown with the correct range. It is also possible to define whether the slider moves continuously or in integer increments. Use the "Units" field to define the units as integer (int) or real to effect this distinction. It is also possible to present a check-box to the user, to return the Boolean values true or false. This is accomplished by setting the "Units" field to boolean. Finally, a variable parameter can be an enumerated type; set the "Units" field to the name of the required type. In this case the slider helper will present a pull-down menu for the parameter, listing the type's members.

Use the equation dialogue box to designate a variable as an variable parameter. It is not possible to set the value of a compartment in the same way, as variable parameters get new values from outside during the execution of the model, while compartments' values are determined from their previous values by the rates of flows in and out. A variable parameter is shown on the model diagram with a slider bar behind its usual appearance.

In: Contents >> Working with equations >> Parameters

Working with external data: the File Parameter dialogue

The File Parameter dialogue allows the modeller to specify where every parameter in the model gets its values from. It contains an entry box for each parameter, which displays the values associated with it, and when you hover over it it pops up information about where those values come from. Hovering over the parameter captions, listed to the left of the entry fields, displays the units and dimensions of the required data. Simple values can be typed in directly, while long lists can be loaded from data files.

Entering the dialogue

The dialogue will be displayed whenever running a model which is missing some parameter values.

In Simile v7, the same information is present in the Parameters tab in the explorer pane of the model run environment, and parameters can be altered there. In earlier versions, the dialogue can be displayed again for the purpose of altering parameter values, by hitting the  properties button in the toolbar of the model run environment.

Using the dialogue

The dialogue divides the parameters up into their submodel levels, and includes buttons at each level to the right of the submodel name. The outermost level is titled 'TOP LEVEL' and the buttons to the right of this heading affect all the values in the model. The same set of buttons appears for each submodel level, where they affect only the parameter values inside that submodel.These buttons do the following:

  • Clear all values from that submodel's parameters
  • Load values from a scenario file
  • Create a scenario file containing these values

Note that if you create a scenario file for a submodel, the parameters in that submodel will be referenced in the file relative to that submodel level, not the whole model. So a file saved for a submodel cannot be loaded at the top level, or vice versa. However, a scenario file saved for one submodel can be loaded into another if they have the same internal layout of file parameters.

Inside the submodel boxes, there is a line for each fixed or variable parameter in that submodel. The line has an entry field into which single values, small arrays and time series can be typed, and buttons to the right. The 'tick' and 'cross' symbols finish and restart editing respectively. The 'pencil' symbol only appears for array or time series parameters, and opens the table entry dialogue for that parameter. If the table entry dialogue has already been used to enter a large data set for a parameter, the entry box will be greyed out and the tick and cross buttons will no appear -- the only way to edit the data set is to reopen the table entry dialogue.

The file parameter dialogue is displayed when you first run a model that contains fixed parameters. It can be displayed again by selecting the "Parameters..." menu item, which is in the file menu on the single-window model run environment, or under the "I/O Tools" menu on the model window if using the multiple-window model run environment.

 Comments on parameter values

It is possible to add a comment to a particular parameter value or array of values. Such a comment applies to the value itself rather than the parameter which takes that value. Use it for noting how the value was derived, e.g., from what publication it came. The comment will be popped up when you hover over the value field, along with the actual file reference. These comments will be saved with the references in the scenario files.

To edit a value's comment, double-click on its entry field. There is also a text box for editing a value's comments in the table data dialogue.

In: Contents >> Working with external data

File Parameter dialogue : Entering values directly

The simplest way to set a file parameter is to type its value straight into the entry box beside its caption in the file parameter dialogue. For single values, this is the only way to enter them initially. The tick button replaces the currently saved value with what has been typed in, while the cross button reverts the entry field to the saved value.

The datatype (e.g., INTEGER or REAL) is displayed by hovering over the caption to the left. This will also display any comment associated with the parameter. If multiple values are required, the dimensions will also be displayed at this point, e.g., 3 x 3 of REAL). If there are multiple values, you get the pencil icon to the right of the entry field, which normally you would use to load them from a file. However, you can choose to type them in.

In Simile v7, arrays and lists are entered in the JSON format. In this format, an array is an ordered list of its members, separated by commas, enclosed in square brackets. Thus a 5-element array of real could be [2.5,3.5,1.5,2.5,3.5], while a 3x3-element array of integer might be: [[5,10,15],[6,7,9],[4,1,8]]. A list is a list of pairs of index and value, with a colon between the index and value, and the pairs separated by commas, enclosed in curly brackets. Thus a time series with integer values applying at times 10, 50 and 100 could be written: {10:33, 50:45, 100:78}. An array can also be written as a list, with the integers from 1 to its size as the indices. The index-value pairs in a list do not need to be in any particular order. The older format described below also works, for the sake of backward compatibility.

In earlier versions, when typing in multiple values, you must alternate between indices and values at each level, and group sub-arrays in curly brackets. So for instance a five-element array of real could be: 1 2.5 2 3.5 3 1.5 4 2.5 5 3.5, while a 3x3-element array of integer might be: 1 {1 5 2 10 3 15} 2 {1 6 2 7 3 9} 3 {1 4 2 1 3 8}.

If redisplaying the file parameter dialogue in an earlier version, the values will be shown with hashes and colons around the indices, to make the data more readable. For instance the five-element array above would look like this: #1: 2.5 #2: 3.5 #3: 1.5 #4: 2.5 #5: 3.5. You must keep these if editing the entry field to change the value, but at this point you can also go to the table data dialogue and edit the values in a version of the table helper. If the values have previously been loaded from a datafile and there are very many of them, the entry field will be greyed out so you cannot type into it, and will also contain an ellipsis rather than listing all the values. In this case they can only be changed via the table entry dialogue.

In: Contents >> Working with external data >> The file parameter dialogue

Working with external data : Specifying time series

The File Parameters dialogue will contain entry fields for both fixed and variable parameters. Fixed parameters must be given a value; their captions in the dialogue will be shown in red until a correctly formatted value has been supplied. Variable parameters do not need a value, and can be left empty, so the value can be set by a slider while running the model. However, it is possible to enter a time series in the File Parameters dialogue, which will cause the variable parameter's value to be set at a series of specified time points while the model is running. You would normally set up the time series using the table data dialogue, but the direct method is described here to clarify the analogy with setting values for an array.

Entry format

The format for entering a time series is the same as for a one-dimensional array, except time points are given instead of indices. The time points can be REAL values, and do not have to be at regular intervals. Data for time point zero is loaded whenever the model is reset. So, to set a value five times between time 0 and time 100, the entry might look like this: 0 12 20 11 40 8 60 7 80 9

If the value to be set is an array, the data must specify a multi-dimensional array, with the time points as the outermost indices.

Special indices and values

The data for a time series can include various combinations of special index and value, which affect how the numerical data is interpreted:

  • Data at time point NOW is loaded into the model as soon as the File Parameters dialogue is closed, and then not used again. Wiggling a slider effectively sets data at time point NOW.
  • For time point OTHERS, you do not enter a value; instead, you enter one of the special values use_last, use_closest or interpolate. These select the different methods for getting a value when the time is not exactly equal to one of the indices in the series. use_last specifies the default behaviour; each value stays in the model until the next time point is reached. use_closest causes the value to change midway between the two specified time points, while interpolate means the value changes continuously and linearly between one specified time point and the next.
  • The INTERVAL time point allows you to supply a time unit which applies to the other indices. This can be useful if you have files containing time series data with the times specified in different units. For instance, if the supply the following data for a time series: 1 3.2 2 4.5 3 6.3 INTERVAL week ...then unless the time unit for model execution is set to something other than day, the variable will change value at times 7, 14 and 21. The time unit can be anything that Simile understands, e.g., ms.
  • There is also another special value, restart, which has a normal numerical time point as its index; this specifies a time at which the model starts reusing values at the beginning of the time series, starting with time 0. The value will then follow a regular pattern, whose period is the time index of the restart value. The time for restart must be the last in the sequence.

Example: rough approximation of sinusoidal variation with period 100 time units:

0 0 12.5 0.7 25 1 37.5 0.7 62.5 -0.7 75 -1 87.5 -0.7 OTHERS interpolate 100 restart

When entering time series values in the table data dialogue, there are special buttons to get these behaviours by setting the special indices and values.

In: Contents >> Working with external data >> The file parameter dialogue

Working with external data : Referencing data in files

Ther normal way to use the file parameter system is to create and save references to data in other files. To do this, click the 'pencil' icon to the right of the data entry field. This brings up the table data dialogue, which allows you to specify the file containing the data, and how to get the data from the file.

Once this has been done, hovering over the entry field will produce a popup showing which file contains the actual data. Hitting the 'pencil' button again will show the reference information and allow it to be altered.

In: Contents >> Working with external data >> The file parameter dialogue

Working with external data : Loading and saving scenario files

Once you have specified the data for all the file parameters, you can save that data in a scenario file (extension .spf, sometimes referred to as a parameter metafile). This file does not necessarily contain the actual data, it can contain references to the files that actually contain the data. It is in an XML format, allowing it to be examined and edited if required.

The normal way to save the scenario file is to click the 'diskette' button in the top-right corner of the file parameter dialogue, by the caption TOP LEVEL. This will create a file containing information for all the parameters in the model. You can save a scenario file for just the parameters in a submodel, by clicking on the 'diskette' button to the right of the caption for that submodel. This file will include the information for all submodels under that one in the hierarchy.

When the scenario file is saved, the locations of any data files referred to will be included as relative paths. This means that if you move the scenario file to a new location, for instance when copying the model and its data to another computer, the data files must be in the same location relative to the scenario file (e.g., in the same folder) as they were when it was set up.

To load a scenario file, click the 'open folder' button to the right of the submodel caption. This action will not load the data itself; that only happens when you click the 'tick' beside a parameter's entry field, or hit the 'OK' button at the bottom of the dialogue. If you have made separate scenario files for submodels, it is important that they are loaded into the same submodels for which they were saved, otherwise Simile will not be able to find the file parameter elements that they refer to, since it will be looking in the wrong submodel or at the wrong level. Loading a scenario file overwrites any information that was already present for the parameters mentioned in the file. This allows you to have one set of values for a submodel saved as part of a top-level scenario file, but still load different values just for that submodel from another scenario file.

In: Contents >> Working with external data >> The file parameter dialogue

Working with external data: The Table Data dialogue

The Table Data dialogue is used to specify how to extract data from a file of any one of a number of formats so that it can be used in a Simile component. Its main use is for getting data for file parameters, but it also appears when creating a table function that is built into a component's equation.

Image of the table data dialogue, v6.9

There are four tabs in the dialogue, corresponding to the four varieties of supported data format. These are:

In addition, this dialogue also allows you to:

In: Contents >> Working with external data

Working with external data : .csv file with data in column

This is the first tab in the table data dialogue. Use this method if the data for each component is in a single column in a file or database.

To select a file as the source of the data,  hit the "Browse..." button and navigate to it. You can select .csv or Excel-compatible files this way. As of Simile v6.9 you can also load columns from a MySQL database. To to this, hit the "MySQL Connection" button and supply the hostname, username, password and database ID for MySQL.

If using a MySQL database or an ODBC-compatible format of file (e.g., .xls) then once you have browsed to the required file or entered the database access information, you must select the table in which the relevant data appears, using the "Database table or worksheet" pulldown menu. Once the table is selected, the column headers will be loaded into the list box below. If using a .csv file, this is not needed because the whole file is one table. When selecting the file you can also edit the character (comma by default) that separates the columns.

Storing data in a file

In order to be able to access the data, they must be stored in a certain format in the file. The file should be rectangular, consisting of a certain number of rows and a certain number of columns. The number of columns corresponds to the number of variables in the file (or, in database terms, the number of fields for each record). The file has as many records as there are units for which data were recorded, plus a single header record. The format is comma-separated values (CSV) which means that each value is separated by a comma from the preceding value. There is no comma at the end of a record. Most software packages that handle data can create files in this format.

The following is an example of a simple file containing data on the age, height and diameter of five trees:

age, height, diameter

25, 15, 0.31

32, 17, 0.37

16, 10, 0.2

19, 12, 0.23

21, 14, 0.29

Creating a new table

To create a new table using the dialogue involves several steps. The first step is to select the file from which the table data are to be taken. To do this, click the "Browse" button on the dialogue box. The file path name is then displayed in the edit box "Data file".

If you are using a more recent version of Simile (5.4 or later), you can also select a data file in an ODBC-compatible format (eg, .xls) if you have the appropriate drivers loaded on your computer. In this case you also need to select the individual table or worksheet holding your data from a pulldown menu.

After selecting the file and datasheet, the table dialogue reads and displays the column headings in a list box. The column headings are taken from the first row of the file. The rest of the file is not checked, at this stage, for speed.

One (and only one) of these headings is used to designate the data column. Drag this column heading from the list box to the edit box labelled "Use as data column". In the example file shown above, you would have the choice of "age", "height" or "diameter" and could drag any one of these to the data column edit box. The cursor changes shape while you are dragging the heading, to represent the data moving.

If you wish to create one or more indices to the data column, drag the heading corresponding to the desired index into the list box labelled "Use as index". To delete an index, drag the column heading from the "Use as index" list box back into the "Table column headings" list box. It is not always necessary to designate an index. If none is given, the row number is used to access each record. If indices are given, then the array returned will consist of the values from the data column indexed by the value(s) from the index column(s) in the rows where they were found. Simile v6.7p2 introduces a new feature: if one or more index columns are specified, then the single word ,line can be used in place of a data column header, and this means that the data in the array will be the line numbers where each index value or combination of index values were found. For instance if the table at the bottom of this page were loaded with the index column headers Y index and X index (in that order!) and the data column header ,line then the first row of the resulting matrix would have the values 1,4,7, these being the rows where the y index of 1 was found, sorted by X index.

You can view the data you have loaded in a separate window. To do this, click the View/Edit button. You can make changes to the data in this window, and click OK to accept the changes or Cancel to abandon them. You can also save the data to a file. Note that if you extracted the data from a file containing more than one variable, you should not save the extracted data to the same file, or you will lose the other variables.

Editing an existing table

If a table already exists for the component, you will not need to follow the above steps again. If you wish to see or change the data in the table, you can click the View/Edit button. This will present you with the Table Editor, as above. If you wish to extract data from a different file, you can use the Browse button, as above, to begin as if creating a new table. If the data in the file have changed since the table was created, you can use the Load button, to extract the new data using the same specification of column heading and indices. (If the file is not present, perhaps because you are working on a different machine from where the model was created, clicking the load button will give an error.)

Final notes

When preparing to use multiple indices, it is often best to arrange the index columns in the data file in a logical sequence, for example as follows:

 X index  Y index  Height  Diameter
 1  1

12.3

1.3

 1  2

12.7

1.2

 1  3

13.1

0.9

 2  1

11.8

1.5

 2  2

12.3

1.4

 2  3

11.7

0.9

 3  1

13.5

1.0

 3  2

12.1

1.1

 3  3

13.0

1.1

For this file, two indices would be selected, the x- and y-values, together with one data column, either the height or the width. If both were needed, it would be necessary to have two variables, and to create a table in each one that each used one of these columns. The indices systematically provide values for a three-by-three grid. This makes it easy to extract the data using the first of the techniques outlined above.

In: Contents >> Working with external data >> The table data dialogue

Working with external data : .csv file with data in grid

If you have a .csv file with a 2-dimensional grid of data items, this can be loaded directly into a 2-dimensional array file parameter in Simile. For other 2-D formats that can be read into a spreadsheet, you can create the .csv file.

To use this file, go to the second tab in the table data dialogue. Here, you can browse to the file containing your data. When selecting the file you can also edit the character (comma by default) that separates the columns. Once you have done that, the four entry fields below will be filled, with "Finish at row" and "Finish at column" containing the number of rows and columns respectively in the file.

You can change the values in these fields in order to read only a part of the grid of values. This is most likely to be needed if the file contains headers that are not actually part of the data. For instance if the first row of the file contains headers, you specify "Start at row: 2" to avoid reading these into the table. You can use the View/Edit function to look at the data that will be read, and adjust the start row and column until it shows the data you want. Whatever values these have, the first row and column that is actually read will have index 1 in the data table (or 0 if it is a time series).

As of Simile 5.4 there are some extra features in this pane: the 'transpose' checkbutton causes the outer indices to correspond to the columns, rather than the rows. Also you can reverse the bounds, i.e., put a higher number in the "Start at..." than the "Finish at..." entries. This has the effect that the same part of the file will be read, but in the opposite order; the last row or column will contain the data items for index 1.

As of Simile v5.5 there is also the option to use fields from the grid as indices as well as data. This is analogous to the way index columns can be specified when reading data from columns, and is useful when the indices need to be enumerated type members. Below the entries for the start and finish rows and columns, there are pull-down menus to choose the source of the indices. By default these are set to "Position in data area", which causes the indices to be generated as described above. The row indices can also be got from "First column in grid" (i.e., leftmost column), or "Column to left of data". If either of these are selected, the index for each row will be the item in that row and the specified column. Note that you cannot choose these options if the data area starts at column 1, and if it starts at column 2 then they both do the same thing, i.e., get the index item from column 1. There are a similar set of options for getting the column indices from a row outside the data area.

In: Contents >> Working with external data >> The table data dialogue

 

Working with external data : Data from image

Simile can extract a 2-dimensional array of data from an image file, with each pixel in the image corresponding to a datapoint. The image can be in any format supported by the Tkimg package, which is to say, most of them.

To get image data, use the third tab in the table data dialogue. The upper panel on this tab is much the same as on the data in grid tab, and does much the same thing; you browse to the file, and select the positions in the image at which to start and finish reading data if you do not want the whole thing.As in the case of a data grid, you can reverse each axis or transpose the axes.

The unique bit is the bottom panel, Values for Colours, by which you can instruct how each colour in the image is to be converted into a value in the data array. "Value for black" and "Value for white" specify the endpoints of the range of values. For other colours, in general the lighter it is, the further from "black" and the closer to "white" the corresponding value will be. There is a pulldown menu with a choice of methods for getting values from other colours; "use luminosity" averages the intensity of red, green and blue, or you can use any of these levels on their own. For instance, an area of pure magenta will give the same value as white if using red or blue levels, and the same value as black if using green level. If using luminosity the value for magenta will be (2*white+black)/3. You can also select "use 8-bit colourmap" which just assigns a unique value to each colour in an 8-bit coloured image, the intention being that these same values are also available to set the colour legend in the grid helper, allowing a version of the image to be reproduced.

Finally there is a field to enter a value which will be used where the image is transparent (clear). You only need to enter a value here if your image has some transparent areas. This value can be outside the range from black to white.

In: Contents >> Working with external data >> The table data dialogue

Working with external data : Data from GeoTIFF or similar

GeoTIFF is a file format which is based on the TIFF image, but which is not actually an image and cannot be displayed in most image viewers. It differs from an image file in that:

  • It also contains georeferencing data, and
  • The image data can be in a number of formats including floating-point.

Simile uses GDAL (Georeferencing Data Abstraction Library) to read GeoTIFFs and other similar data files and convert them into 2-D arrays of parameter values. This library is not distributed with Simile, but it is Free Software; you must go and find it on the Web, and install it on your computer before you can use this feature of Simile. A version of GDAL is included in most Linux distributions and can be installed via the package manager. When it is installed, Simile can also create GeoTIFFs using the grid helper.

Havng done this, the procedure for reading data from a GeoTIFF is much the same as for a grid of values in a .csv file. The actual values in the file are used in the data array without any conversion; the assumption being that since they can be floating-point, whoever created the dataset would have been able to include physically meaningful values.

Because getting data from this type of file is a low-level operation, it is much faster than the other options for loading data from files where very large arrays are involved. However the price for this is the loss of the "transpose" and reverse ordering options.

In: Contents >> Working with external data >> The table data dialogue

Working with external data : View/edit as table

Once you are in the table data dialogue, you can hit the View/Edit button to bring up a version of the table helper to display your data and, if necessary, edit it. The data need not have come from a file; it might just have been typed into the entry field of the file parameters dialogue. However it will not work if the data has been loaded as raw data from the scenario file.

This tool has all the features of the table helper, i.e., you can arrange the different index and time point headings vertically or horizontally, and you can save the displayed data as a .csv file. It also allows you to edit the data, either by typing values into individual fields or by cutting and pasting a grid of values into the grid. For example, a quick way to transpose a square array: Put outer indices on rows and inner ones on columns, then cut all the data, then put inner indices on rows and outer ones on columns and paste it back in.

The main use of this tool though is to check after reading data from a file, using whatever method, that you have actually picked up the data you intended to get.

In: Contents >> Working with external data >> The table data dialogue

Working with external data : Time series

In the section on time series formats, we saw that the series includes special time points and special values to specify what what values to use away from the actual data points. If you are using one of the mechanisms provided by the table data dialogue to get your data, you do not have the opportunity to include these special points (unless they happen to be in your .csv file, and if they are, they work fine). But you can get the same effect by including them with the tools in the 'other times' panel in the top right corner. These are only available if providing values for a variable parameter when running the model. 

The pulldown menu for "Between points" allows you to select from three options which have the same effect as the special values for the time point OTHERS: "use_last", "use_closest" and "interpolate". The entry for "Wraparound at" has the same effect as the time point given for the special value "restart".

There is also an entry field to set the units for your time series indices as described for the INTERVAL point.

In: Help >> Working with external data >> The Table Data dialogue

Working with external data : Raw data in scenario file

Normally, the scenario file contains only references to data files, with information as to how the data is to be extracted. However, if you type the data straight into the entry field in the file parameter dialogue, or edit it with the table editor from the table data dialogue, the resulting data no longer corresponds to anything that can be got from a data file, so instead the data is stored directly in the scenario file. This is usually a bad thing, because the XML format used is unwieldy and verbose, and it may take a long time to load or save. But keeping references in the scenario file also has disadvantages, chiefly:

  1. When publishing a model with a scenario file like this, the file itself must be included along with all the other files referenced by it, and these must be installed in the same place in the directory tree relative to the scenario file as they were when the scenario was created

  2. The process of loading values from a .csv file is quite time consuming, as the file has to be parsed and checked for syntax errors before the ASCII numerals can be converted into their actual values, and this has to be done every time the data is loaded.

So we came up with a way to maximize convenience, and added a checkbox to the table data dialogue captioned "Include values in scenario files". If you check this, then when you save a scenario file including the parameter in question, it will include all the data for that parameter even if it is also available in the datafile. Furthermore, instead of it all being in longhand XML, it will be in raw binary format, base64-encoded into Ascii and stuffed into a CDATA field.

This means it is small. And fast. If the model uses a lot of data that isn't going to change from one scenario to the next, this is the best way of handling it. There is a slight downside; the values are unpacked and loaded directly into the model's data structures, and are never converted into the TclTk format that allows them to be displayed as text (except for a few at the start and end, to display in the file parameter dialogue, and these give you just the raw numbers if using booleans or enumerated types). So you cannot look at them or change them with the table editor -- but that gets a bit difficult with very large arrays anyway. The only way to change them is to load them once more from a datafile.

In: Contents >> Working with external data >> The table data dialogue

Working with external data : Creating CSV files

Creating CSV files

Comma delimited (CSV or comma separated value) files can be created using most common data-handling software packages. There is usually a selection of file formats available in the Save dialogue box, as pictured here for Microsoft Excel.

Note that if you get a choice of delimiters, you should choose comma between columns and newline between rows.

In: Contents >> Working with equations

Working with external data : Modifying scenario values during a session

Modifying scenario values during a session

You are only asked to specify a scenario file the first time you build and run a model that requires parameter values. So what do you do if you then want to modify scenario values prior to subsequent runs during the same session?

In Simile version 7 and later, the explorer pane in the model run environment window contains a notebook with two tabs, "Outputs" and "Parameters". All the parameter values in the current scenario appear under the Defaults heading in the Parameters tab, and they can be updated directly using any of the methods for setting them.

In earlier versions: select the option Parameters... under the File menu of the model run environment window, or under under the I/O tools menu of the model window if using multiple run windows. This produces the same dialogue window as you use to specify the scenario in the first place. You can edit any of the values you see; or you can re-load another set of data values from a .csv file to replace the ones already entered. You can also load a new scenario file, either for the whole model or for any submodel that contains file parameters.

In either case, if you change any values, you will be requested to restart the model before running it again, so the new values can take effect.

In: Contents >> Working with external data

Working with external data : Running experiments

Running experiments

As of Simile v7.0, a model can be run simultaneously with its default parameters and with various other combinations of parameters, using multiple processors if they are available. A combination of such runs is known as an experiment, as it allows comparisons between output data from the default case with data from the experimental variations. The feature is similar in some ways to the experiment feature in Apsim NG, but Simile’s version does not allow parts of the actual model to be changed between cases, although this functionality may be added in the future.

Any model containing file parameters may be used as the basis for an experiment. When you run such a model, the explorer pane (beneath the run control pane) contains two tabs, titled ‘Outputs’ and ‘Parameters’. ‘Outputs’ shows a tree diagram containing all the values in the model arranged by submodel hierarchy, while ‘Parameters’ shows a similar arrangement with just the file parameters, including an entry field and setup button for each to allow them to be altered. The entry field will include the current value of the parameter if one has been entered, or the component’s equation if using a default value included in the model (indicated by the caption appearing in blue). This tree diagram appears under the ‘Default case’ heading, indicating that these values correspond to the ‘real world’. There is also an  ‘Experimental conditions’ heading, with an empty tree. This tree can be built up by adding experimental cases.

Adding experimental cases

To add an experimental case or set of cases, right-click (or ctrl-click if using a Mac) on the experimental conditions header. This will bring up a menu of different ways to add conditions.

 Parameter value

This is the simplest way to add an experimental condition. It creates a condition in which just one parameter is varied from its default value, although that can be an array parameter. When you select this entry from the insert menu, the first thing to appear will be a dialogue box inviting you to enter a name for the new experimental case. This can be some description of the experimental procedure it is modelling, e.g., ‘swab all’.

After this dialogue is closed, a message will appear in the Parameters tree inviting you to select a model component to which to apply the new value. You can select this from the Parameters tree, or from the Outputs tree or the model diagram, but it must be a file parameter. Although the icon shows a fixed parameter, it can also be a  variable parameter, in which case the data for it will be an alternating list of time points and values to apply at those times. Once you have selected a parameter, an entry field for it will appear under the Experimental conditions header, as part of a new tree.

You can now provide a value for this version of the parameter, using any of the methods available to load values for file parameters. If it is a variable parameter, you will need to provide a time series. Because the caption of the entry is the component’s caption followed by the name of the experimental case, there may not be enough room in the pane for the entry widgets to show, in which case you can enlarge it by dragging the handle on the vertical sash between the explorer and visualization tool panes.

Once this is done, after you next reset the model, there will be two cases – the default case with the original value of that parameter, and the newly named case with the newly entered value. Visualization tools, component popups etc will show values from both cases, labelled as if they were array members.

You can add several values in this way, either for different parameters or for the same parameter in different cases. Each one will create an additional experimental case in which that particular value is applied to that parameter, but everything else is the same as the default case.

 List for parameter

If you want to add a number of experimental cases in which one particular parameter as one of a range of different values, select the entry “list for parameter” from the insert menu. After selection, you go immediately to choosing a file parameter to which to apply the different values. After choosing it, a new entry field is added to the experiment tree with the label of the parameter followed by ‘s’, meaning you can add multiple values.

At this point you can add a series of values using any of the means you would normally use to set up an array parameter. The indices can be text or numerical, and will become the names of the experimental cases for the corresponding values. If the parameter is itself an array or a time series, you need to create a nested array for the value, with the outer indices becoming the experimental case names.

If the parameter is a fixed scalar value, you can enter a series of cases for which it has a sequence of values. Instead of the normal index/value pairs, enter an expression of the form “a to b step c” for the range and frequency of values to use in the experiment. For instance if you set a list for a parameter called “level” with the entry “100 to 500 step 80” you will get cases with level set to 100, 180, 260, 340, 420 and 500. These cases will be named “level=100”, “level=180”, etc. If the step is 1 it can be left out of the entry, e.g., “2 to 6” gives cases for values of 2,3,4,5 and 6.

 Multi-factor case

If you want to create an experimental condition in which several parameter values are varied from their defaults, this is what you need to add to the experiment tree. When you select it from the insert menu, you are prompted to supply a name for the new experimental case, but that is all. The case will then appear under the experimental conditions tree. At this point, the case has the same values as the default case for all the parameters. You can add parameter values to this case by right clicking on the header. Note that only single parameter values can be added inside a multi-factor case, and only one entry field should be added for any parameter.

When you add a parameter value to a multi-factor case, you do not get to select a name for the case, because you are adding to the setup of the existing case. Instead it goes straight to picking the parameter which is to be adjusted. Continue to insert parameter value fields and enter values for them until your experimental case is complete. When you run the model now, you will see the default case and the named multi-factor case, with all the values you entered applied to their respective parameters in the latter.

 Set of permutations

In some experimental designs, a few parameters are varied and the results for each combination of possible variations are analyzed alongside the default condition. This kind of design is useful for finding particular combinations that produce exceptional results, though when working with Simile the PEST interface should also be considered for this purpose.

Simile’s experiment generator provides a tool for setting up such an experiment. The ‘set of permutations’ level can be added to the tree, and like the multi-factor case, other conditions can be added beneath it. However, rather than combining these conditions into a single case, it generates a case for each possible subset of them.

So, when a set of permutations is added, it does not itself generate a new case, or require a case name to be provided. Any of the other case specifications can be added under a permutation, and they will behave exactly as if they were added under the top level as described above. But if more than one is added, then as well as the cases they specify themselves, cases will be generated for all possible combinations of more than one of them.

For instance, if your model has two fixed parameters called ‘speed’ and ‘weight’, you might add a permutations level, and under it ad a parameter value for ‘speed’ as a case called ‘slow’, and a list for parameter ‘weight’, specified as ‘10 to 30 step 10’. The model execution will now contain the cases that these specify themselves, i.e., ‘slow’, ‘weight=10’, ‘weight=20’ and ‘weight=30’, but it will also contain combinations, named by combining the names of the cases that compose them, i.e., ‘slow+weight=10’, ‘slow+weight=20’ and ‘slow+weight=30’.

Note that adding a lot of separate cases under a permutation will very quickly give rise to a large number of conditions, e.g., five individual parameter values will give rise to 31 experimental cases in addition to the default.

In: Contents >> Working with external data

 

Working with external data : Worked Examples

Using the scenario file mechanism

Choose the use-case that is closest to your own requirement. Note, however, that in a typical application you will probably have more than one instance of some of these approaches, and you will be mixing several approaches. For example, one model may have several single-valued variables, some spatial data, and some time-series data. Together, these constitute the 'scenario'.

One a scenario has been set up according to the various use-cases detailed below, and saved in a scenario file, the scenario file can be loaded in subsequent Simile sessions simply by loading it in the scenario (parameter) file dialogue window.

Case 1: providing a single value for a scalar (single-valued) variable

The variable could represent, for example, a model parameter, a site condition, or be used to set the initial value of a compartment.

Case 2: providing a set of values for a variable inside a multiple-instance submodel: values stored in the scenario file

You can use this method if the variable is inside a submodel with a small number of instances.

Case 3: providing a set of values for an array variable: values stored in the scenario file

You can use this method if the variable is an array with a small number of elements.

Case 4: providing a set of values for a variable in a fixed-membership multiple-instance submodel: values stored in a separate file

You can use this method if the variable is inside a submodel with a large number of instances.

Case 5: providing a set of values for an array variable: values stored in a separate file

You can use this method if the variable is an array with a large number of elements

Case 6: providing values for 2-dimensional array or submodel variables

Arrays with 2 or more dimensions can be specified in a variety of ways

Case 7: Providing data for points in a time series

Each point may be a single value or an array of values; special points also discussed.

Scenario files can contain information for all the file parameters in a model, or just those relating to a single submodel, or a certain part of the submodel hierarchy. If you have a model which has file parameters spread across a lot of submodels, then the file parameter dialogue will include a lot of nested sunken frames, coresponding to the nested submodels containing the parameters. Each of these frames has a title, which is 'TOP LEVEL' for the whole model, or the caption for a submodel. To the right of this is a set of buttons, for clearing, loading and saving the parameters in that submodel and those contained within it. Saving parameters for submodels allows you to keep separate sets of parameters for different parts of your model, and to build scenarios by loading separate scenario files for different parts of the model, rather than having a single file for each possible combination of sub-scenarios.

Important: a scenario file must be loaded into the same submodel context from which it was saved, since the locations of the parameter components are specified relative to that submodel context.

In: Contents >> Working with external data

Working with external data : Scenario file : Case 1

Case 1: providing a single value for a scalar (single-valued) variable

This case applies when the model requires just one value. In other words, the variable in question is not inside a multiple-instance submodel, and has not been declared to be an array.

Typical circumstances are:

  • for providing a parameter value;
  • for setting some context-specific value: e.g. soil type, elevation
  • for initialising the value of a compartment.

On the model diagram

  1. Open up the equation dialogue for the variable, by double-clicking on it.
  2. Click the radio button labelled "Fixed Parameter".
  3. Close the equation dialogue window.

Note that the variable now appears with a tail, showing the change in its status. Note also that it is black, even though you have not supplied a value for it.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this variable.

  1. Click in the associated edit field, and type in a value.
  2. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.
  3. Click OK when you wish to proceed with the simulation.

In: Contents >> Working with external data >> Using scenario files

 

Working with external data : Scenario file : Case 2

Case 2: Providing a set of values for a variable in a fixed-membership multiple-instance submodel: values stored in the scenario file

This case applies when you have a variable in a fixed-membership submodel which has a small number of instances. A typical example might be a submodel whose job is to hold the values for each of several crop types. The number of crop types is probably small.

On the model diagram

  1. Open up the equation dialogue for the variable, by double-clicking on it.
  2. Click the radio button labelled "File Parameter".
  3. Close the equation dialogue window.

Note that the variable now appears with a tail, showing the change in its status. Note also that it is black, even though you have not supplied a value for it.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this variable.

  1. Click in the associated edit field, and type in a n pairs of values, where n is the number of submodel instances. The first value of each pair should be the number 1, 2, 3, etc. The second should be the value you wish to assign to that instance. Thus, if the submodel has 4 instances, and you want to assign the values 4, 5, 6 and 9 to the 4 instances, then you should type in:

    1 4 2 5 3 6 4 9

    just like that (i.e. with no brackets, commas or whatever).

  2. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.
  3. Click OK when you wish to proceed with the simulation.

In: Contents >> Working with external data >> Using scenario files

 

Working with external data : Scenario file : Case 3

Case 3: Providing a set of values for an array variable: values stored in the scenario file

This case applies when you have an array variable with a smallish number of elements. A typical example might be an array containing a parameter value for each of several crop types. The number of crop types is probably small (say, fewer than 20).

On the model diagram

  1. Open up the equation dialogue for the array variable that is to contain the time-series data, by double-clicking on it.
  2. Click the radio button labelled "File Parameter".
  3. Enter the expression makearray(1.0,n), changing n to the number of values in the time series, in the "Equation" edit field.
  4. Close the equation dialogue.

Note that the variable now appears with a tail, showing the change in its status. Note also that it is black, even though you have not supplied a value for it.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this array variable.

  1. Click in the associated edit field, and type in a n pairs of values, where n is the number of submodel instances. The first value of each pair should be the number 1, 2, 3, etc. The second should be the value you wish to assign to that instance. Thus, if the submodel has four instances, and you want to assign the values 4, 5, 6 and 9 to the 4 instances, then you should type in:

    1 4 2 5 3 6 4 9

    just like that (i.e. with no brackets, commas or whatever).

  2. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.
  3. Click OK when you wish to proceed with the simulation.

In: Contents >> Working with external data >> Using scenario files

Working with external data : Scenario file : Case 4

Case 4: Providing a set of values for a variable in a fixed-membership multiple-instance submodel: values stored in a separate file

This case applies when you have a variable in a fixed-membership submodel which has a largish number of instances. A typical example might be a submodel whose job is to hold the values for some attributes (e.g. elevation, soil type) of each of a large number of spatial patches.

On the model diagram

  1. Open up the equation dialogue for the variable, by double-clicking on it.
  2. Click the radio button labelled "File Parameter".
  3. Close the equation dialogue.

Note that the variable now appears with a tail, showing the change in its status. Note also that it is black, even though you have not supplied a value for it.

Check or prepare the data file

The data file should be in standard csv (comma-separated value) format. It should have one header line, consisting of one or more labels, separated by commas, followed by n lines. Each line should have the same number of values as there are labels in the header line, and again the values should be separated by commas. The number (n) of data lines should be at least as great as the number of instances for the submodel. One column should contain the values required for the variable in the model.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this variable.

  1. Click on the Read table button for this variable.
  2. Select the "data in columns" tab of the table data dialogue.
  3. Browse through your file system to find the .csv file containing the data values.
    You will now see a window listing the columns in the table, by the label associated with each column.
  4. Double-click on the label corresponding to the column of values you wish to assign to the variable.
  5. Click on the OK button.
  6. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.
  7. Click OK when you wish to proceed with the simulation.

In: Contents >> Working with external data >> Using scenario files

Working with external data : Scenario file : Case 5

Case 5: providing a set of values for an array variable: values stored in a separate file

This case applies when you have an variable with a largish number of elements. A typical example might be a variable outside a large multiple-instance submodel, containing a set of values that are to be used for each instance of the submodel..

On the model diagram

  1. Open up the equation dialogue for the variable, by double-clicking on it.
  2. Click the radio button labelled Fixed Parameter.
  3. Enter the expression makearray(1.0,n), replacing n by the number of elements in the array, into the "Equation" edit field.
  4. Close the equation dialogue.

Note that the variable now appears with a tail, showing the change in its status. It also has a 'stack' outline to indicate that it is an array. Note also that it is black, even though you have not supplied a value for it.

Check or prepare the data file

The data file should be in standard csv (comma-separated value) format. It should have one header line, consisting of one or more labels, separated by commas, followed by n lines. Each line should have the same number of values as there are labels in the header line, and again the values should be separated by commas. The number (n) of data lines should be at least as great as the number of instances for the submodel. One column should contain the values required for the variable in the model.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this variable.

  1. Click on the Read table button for this variable
  2. Select the "data in columns" tab of the table data dialogue.
  3. Browse through your file system to find the .csv file containing the data values.

    You will now see a window listing the columns in the table, by the label associated with each column.

  4. Double-click on the label corresponding to the column of values you wish to assign to the variable.
  5. Click on the OK button.
  6. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.
  7. Click OK when you wish to proceed with the simulation.

In: Contents >> Working with external data >> Using scenario files

 

Working with external data : 2-dimensional arrays : Case 6

Case 6: providing values for 2-dimensional variables

A variable will need a 2-dimensional array of parameter values if it is itself a 2-dimensional array variable, or if it is inside a 2-dimensional multiple-instance submodel, or if it is a 1-dimensional array variable inside an ordinary multiple-instance submodel, or if it is inside 2 nested multiple-instance submodels.

There are two ways of providing two-dimensional data for such a variable. The first two are generalizations of methods already described, and can also be used for higher-dimensional variables. The third involves reading data directly from a file in a 2-dimensional format, and was introduced in Simile v4.8.

Values direct from scenario file

This method is limited to small arrays. You enter the data in the edit field in the file parameter value as for one-dimensional arrays, but in place of each value there is another list of index and value pairs, in curly brackets. For instance, the data for a 4x3 array of integers could be supplied as:

1 {1 4 2 9 3 1} 2 {1 8 2 5 3 6} 3 {1 9 2 11 3 6} 4 {1 0 2 7 3 9}

Note that after these values are accepted by the dialogue, it will show the indices with a hash and colon, e.g., #2: to distinguish them from the data items. They can in fact be entered either with or without these decorations, making it easier to enter them by cutting and pasting.

It is fairly easy to see how this mechanism can be extended to cope with higher-dimensional arrays.

Values from a column in a .csv (comma-separated value) file

The data file should be in standard csv (comma-separated value) format. It should have one header line, consisting of one or more labels, separated by commas, followed by n lines. Each line should have the same number of values as there are labels in the header line, and again the values should be separated by commas. The number (n) of data lines should be at least as great as the number of instances for the submodel. One column should contain the values required for the variable in the model. There should also be one column containing the outer index values, and one column containing the inner index values.

For instance, a .csv file to generate the same array as in the last subsection, might look like this:

IndH,IndV,Val,

1,1,4,

1,2,8,

1,3,9,

1,4,0,

2,1,9,

2,2,5,

2,3,11,

2,4,7,

3,1,1,

3,2,6,

3,3,6,

3,4,9,

Note that the row index (which would normally correspond to the outer index in a 2-D array within Simile) actually appears after the column index in the file. This does not matter; the columns can be in any order in the file. So can the rows, since their ordering in the model data is going to be specified by the values in the index columns, rather than their line numbers.

When you come to run the model

Simile will produce a File Parameter dialogue window, and this will contain an entry for this variable.

  1. Click on the Read table button for this variable

  2. Select the 'Data from column' tab in the Table Data dialogue, if it is not already selected

  3. Browse through your file system to find the .csv file containing the data values.

  4. Click on the OK button.

    You will now see a window listing the columns in the table, by the label associated with each column.

  5. Drag the header of the column containing the values for the outermost index across into the 'indices' listbox. In the example above, this column header is IndV.

  6. Repeat this action for the inner index. In the example above, this column header is IndH.

  7. Double-click on the label corresponding to the column of values you wish to assign to the variable. In the example, it is Val.

  8. Click on the OK button.

  9. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.

  10. Click OK when you wish to proceed with the simulation.

Values from a grid in a .csv file

In many cases, the data for a 2-d array is available as a grid of values in a .csv file, typically one saved by a spreadsheet. In such cases it is difficult to convert it to a single column with separate columns for indices, so Simile allows this type of data to be read directly. The rows in the grid will correspond to the outermost index of the Simile array, and the columns to the innermost index. If the grid data is arranged the other way round from this, the spreadsheet's 'transpose' function can be used to swap the rows and columns.

After you click the 'get values from file' button in the File Parameters dialogue, the Table Data dialogue contains four tabs. Initially, the 'Data in Column' tab is raised, but for this case we use the 'Data in Grid' tab. So first click on that tab to raise it.

Now we see a file selector, the same as in the previous examples. Use it to open your .csv file containing the grid of values.

On opening the file, the four entry fields for start/finish at row/column will be filled with the numbers of the first and last rows and columns respectively, providing indication of the total size of the grid of data in the file. Note that any header rows and/or columns will be included in these dimensions, so the 'start at' values will always be 1. At this point you can adjust the values to correspond to the part of the grid you actually want to load. At any time you can hit the View/Edit button on the right of the dialogue, to display a grid of the values in the part of the file currently selected for loading. Ths is useful if you are unsure which part of the file contains headers and which the numerical values. However, note that the table display tool only works up to a maximum of 10,000 rows or columns.

The size of the area you eventually select must match the dimensions of the array you need to load into the model. These dimensions are displayed in the header of the Table Data dialogue for convenience. Once you have chosen the appropriate start and end points, you can use the View/Edit button again to actually change some of the values (e.g., if some were badly formatted in the file) but be aware that if you do this and then save the scenario, all the values will be saved in the parameter file, rather than just a reference to the .csv file.

Values from an image or other binary-format file

Loading a 2-D array of data from an image is very much like loading it from a grid of numerical values. Follow the same procedure except, when you open the Table Data dialogue, select the 'Data from Image' tab. You then choose the area of the image from which you want to load values, exactly as was done for the case of loading data from a .csv grid, except in this case there are no header rows or columns to worry about.

There is an important extra step when using an image file - each pixel in an image has a colour, and you must specify how these colours are to be converted into numerical values to use in the model. This has to be done before you can use the View/Edit button, since the table will display numerical values. Each pixel will correspond to a number between a lower and an upper bound. These bounds are entered as 'Value for black' and 'Value for white', and these are the values that will be generated for black, and white, pixels respectively. Value for black can be greater than or less than value for white. Pixels of other colours will generate values between these two values, as specified in the 'For other colours' pulldown menu. For instance, if you select 'Use green level', a green pixel will give the same value as a white one, since the green level in white is 100%, while a red pixel will give the same value as a black one, since the red level in green is 0%.

If the image file has 8-bit colourmap data, as is the case for most GIF files, then these values can be used directly, and by setting the values for black and for white to 0 and 255 respectively, the values themselves will be preserved. Finally, some images contain transparent areas; when using such an image you must set a separate value for transparent pixels in the 'Value for clear' entry field. This need not be in the range between the values for black and for white.

Other grid data formats

Several other data file formats, principally GeoTIFFs, can be loaded into Simile model parameters if you have the Geospatial Data Abstraction Library (GDAL) installed on your computer. This library is not included in Simile's installation, but is distributed free of charge, and is available for all operating systems for which Simile is supported. The procedure for loading these data files is the same as for loading image data, except that since the values in the files are already interpreted as numerical rather than colour, there is no need to specify how they are to be converted to numeric values. Use the last tab in the table values dialogue (Data from GeoTIFF, etc).

In: Contents >> Working with external data >> Using scenario files

Working with external data : Time series : Case 7

Working with time series

There are two principle means of loading time series data into a model, depending on whether it is desired to store the data in the model itself, in which case the table(…) function is used, or whether the data are to be read from an external file, in which case a scenario file is appropriate. It is also possible to enter the data directly into an array, which may be convenient if there are only a few rows of data.

Using an intermediate array

Whichever way the data are provided, they are stored in an array. The following procedure is suitable for transforming the array into a time series.

  1. Make a scalar variable (i.e. not an array) whose value is to change each time-step.
  2. Draw an influence from the time-series array to the scalar variable.
  3. Set the equation for the scalar variable to:

    element([time_series], time()+1)

    where [time_series] is any array that is being used to store values for the time-series.

This procedure selects one value from the array, in the row corresponding to the current simulation time. Note that in the sub-expression time()+1, the +1 is to account for array indices starting at 1, whilst the simulation begins at time()=0.

Using a file directly

The following procedure is used:

  1. Create the file in comma-separated value (CSV) format.
  2. In your model, set the variable to be a "Variable parameter". You must enter maximum and minimum values here, to allow the parameter to be set using a slider.
  3. Build the model.
  4. From the File menu of the Run Control, select the "Parameters..." command. If you are using the single-window execution environment, there is also a toolbar button to display the parameter dialogue.
  5. From the resulting parameter dialogue box, click the "Get values from file" button (with the pencil icon) next to the variable name.
  6. Create a table in the usual way, with or without an index, depending on how the values in the file are distributed with respect to time. You will need an index if the values do not correspond to times 1, 2, 3 etc.
  7. Click OK.
  8. Click the reset (stop) button.

This last step is necessary to re-set the model to use the new parameters at zero time. If you do not do this, a warning will be issued. Note that the index can start from zero.

Time series values do not have to be at regular intervals - for example, if you give a variable parameter the time series:

#0: 1 #20: 2 #80: 3

then it will change on reset and at times 20 and 80 but keep its previous value (or respond to slider input) at other times.

Getting a time series to repeat

If you want your time series values to be used again after a certain period of time, there are two ways to do this. If editing the list directly in the file parameter dialogue, you can end it with, e.g.,

#100: restart

to cause the values to restart from 0 at time 100. This must be at the end of the line.

If you are loading the values from a .csv file, then the load file dialogue will include an entry box labelled "Wraparound at:" into which you can enter a time at which to restart the time series. Doing either of these will cause the time series to repeat indefinitely over the specified period as the model runs.

In: Contents >> Working with external data

Scripting

Simile scripting language

The scripting language has been superseded by the Simile/R interface and will be phased out as of Simile v7.

Introduction

Simile includes a scripting language that provides control of all functions for model loading and execution. The objective is to allow multiple simulations using one or more models, with different parameters, time step settings and so forth for each run. The results can be recorded to a text file, for later analysis, or processed in the script. Several different approaches to meeting this need have been considered, including providing a specific graphic interface such as a new run control. We concluded that scripting allowed the most flexibility and encouraged users to find applications beyond those which we have initially considered.

Commands are provided to control key parts (model window, run control and data table) of the Simile user interface. (Simile is hidden by default.) Program objects are created that have commands (methods) that generally correspond to menu commands or tool buttons in the interactive graphical interface.

Using Simile scripting

Typically, the script interface to Simile is accessed by running the SimileScript application that is provided with Simile. A program object to control the model window is created and then used to load a model and scenario file. A run control object is then created to set time-steps, how long to run the model for, etc, and a data table control object is created to record variables. At the end of the simulation the data table object is used to write values to a file.

The script interface to Simile is accessed under Windows by running the SimileScript application that is provided with Simile. Under Linux and MacOS-X use the wish application in the Simile distribution and follow the instructions as for scripting from other interpreters . Scripts can be pasted in to the window or loaded via the File>Source menu item. Commands can also be added one at a time. This can be useful to explore the script interface capablities. Some example scripts are included below.

Simile script is an extension to TclTk and the full functionality is available to those that want to use it (see http://www.tcl.tk/).

In: Contents

Scripting : Example scripts



Example scripts

Four example scripts are included in the Examples directory of the Simile installation.

TreesTableHelper.tcl

TreesRuncontrol.tcl

TreesFP.tcl

TreesStats.tcl

In: Contents >> Scripting

Scripting : Using other interpreters



Access to Simile scripting from other TclTk installations

The scripting is provided by using TclTk and access to the script interface to Simile is available from other TclTk 8.4 installations by using the SimileAutoObj package. You will have to ensure that SimileAutoObj package is in the package search path. Add the directory in the /system/lib/SimileAutoObj to your other Tcl interpreter rather than copying the directory to your other interpreters lib directory as the SimileAutoObj package requires access to other files in the Simile installation. E.g.,

append env(PATH) {C:/Program Files/Simile42/System/bin}

lappend auto_path {C:/Program Files/Simile42/System/lib}

package require SimileAutoObj

In: Contents >> Scripting

Scripting: Simile scripting language reference

The SimileScript language is object based. There are commands to create model window objects, run control objects and table display objects. Once an object is created, methods (or commands) of those objects can be used. (To those who know TclTk, the commands follow the same rules as the Tk graphical user interface widget commands.)

Model window

Create model window object

similescript::ModelWindow objectName

For example:

similescript::ModelWindow modelWin

objectName commands (or methods in object based terminology) can now be used.

Model window object commands

Most of these commands correspond to Simile model window menu commands.

objectName Open modelFile

Load (open) an existing model file from disk. It takes one argument, modelFile,  that is the file name of the model to be loaded. Only one model may be loaded at any time. To remove the current model use: objectName New (see below).

 

 

objectName New

Removes any existing model loaded (opened). This command corresponds to the Simile model window <strong>File</strong> -&gt; <strong>New</strong> command. Removing the current model allows another model to be loaded.

objectName FileOpenDlg

Opens a file open dialog box, allowing the script user to choose the model to load (open)

at script run-time.

objectName LoadParams filepath ?smPath?

In order to run a model with file parameters use the command above before building the model.  The filepath​ refers to a parameter metafile (.spf) which contains values or references to other files. smPath (submodel path) can be omitted if the parameter variables specified in the file are relative to the top level of the model.

objectName UseMRE bool

bool must be either “true” or “false” (or other versions of Boolean values accepted by Tcl).  If “true” the single-window Model Run Environment is used. Otherwise, seperate windows will be produced for each helper (display). This command is only of use if the helpers are made visible.

objectName ListEnumTypes

(New in v5.5) Returns all the enumerated type definitions in the top level of the model, in the form of a nested list. Each sublist has the type name for its first element, and the type members for its remaining elements.

objectName GetEnumTypeMembers typeName

(New in v5.5) Returns a list of the members of the enumerated type given by typeName, if it exists in the top level of the model.

objectName ChangeEnumType typeName member...

(New in v5.5) Changes the membership of the enumerated type given by typeName, if it exists in the top level of the model. The new members are the second and any subsequent arguments passed to this function. The model must be rerun before the new definition takes effect.

 

objectName Run

Makes a loaded model runnable.

objectName Debug

Makes a loaded model runable using Tcl as the model execution environment. Tcl is slower than the usual compiled C++ executable but has more error checking. However, error checking (dubugging) is usually done from the graphical Simile user interface.

objectName Show

Makes the model window visible.

objectName Hide

Hides the model window (default).

objectName Destroy

Removes the model window.

 

 

Run control

Create run control object

similescript::RunControl objectName

For example:

similescript::RunControl runControl

objectName commands (or methods in object based terminology) can now be used.

Run control object commands

Most of these commands correspond to edit fields and buttons on the regular Simile run control dialog box.

Path - Some of the methods (commands) below take a parameter path. Model component paths end with the name of the component (e.g. compartment, variable or

submodel preceeded by a string of all the submodels the component is contained by. The submodels are seperated by a slash “/”. The toplevel model (sometimes called the “desktop”) is refered to as “/”.  Since all components are contained by the toplevel model all paths start with a leading /, e.g. “/Number of Trees” is the variable “Number of Trees” in the top level model. “/Tree/Saplings” is the variable “Saplings” in the submodel “Tree” which is contained directly by the toplevel model.

objectName Start

Start running the simulation. The simulation will run for the time set by, objectName SetExecuteFor, or the default execution time stored in the model file.  Generally, your script will be clearer if you always use objectName SetExecuteFor.  Returns a string containing the elapsed real-time to run the simulation (not CPU time), e.g.

1.27 sec

objectName  Reset

Resets the simulation to time zero.

objectName SetExecuteFor time

Set the simulation time for which the simulation will run when objectName Start is called.

objectName SetIntegrationMethod method

Set the integration method. method may be either, “Runge-Kutta” or “Euler”

objectName  SetIntegrationMethodEuler

Sets the integration method to Euler

objectName  SetIntegrationMethodRungeKutta

Sets the integration method to 4th-order Runge-Kutta.

objectName  GetStepAdaptLimit

New to Simile v5.8: Returns the current maximum proportional error used for adaptive stepsize variation. If adaptive step size variation is not in use, a value of zero is returned.

Sets the integration method to 4th-order Runge-Kutta.

objectName  SetStepAdaptLimit errorLimit

New to Simile v5.8: Sets the current maximum proportional error used for adaptive stepsize variation. If an argument of zero is supplied, adaptive stepsize variation is turned off, otherwise it is turned on.

objectName  SetTimeStep index timestep

Different submodels in a model can be specified as operating on different time steps (in the submodel properties dialogue). Use this command to set timesteps.  

objectName  SetTimeUnits units

This setting is for use with physical units, to specify the particular time unit, rather than using abstract time units. If you have not specified consistent physical units for all flows, you should not change this setting from the default “unit”. If you have specified consistent physical units, you should choose the unit you wish to use to specify how long to execute the model for. Valid values are; unit, second, minute, hour, day, week, month, year and Ma.

objectName SetDisplayInterval timeStep

Set the simulation time interval at which displays (helpers) are updated.

objectName SeedRandoms integer

New to Simile v6.4: Initializes the state of the random number generator. This can be used to ensure that a model run produces exactly the same results each time, even if it contains random functions. The argument is used to build a state for the generator, so using the same argument will ensure the same subsequent sequence of randoms.

objectName  GetCurrentTime

Returns the current simulation time.

objectName  GetDisplayInterval

Returns the simulation time interval at which displays (helpers) are updated.

objectName  GetExecuteFor

Returns the simulation time for which the simulation will run when objectName Start is called.

objectName  GetIntegrationMethod

Returns the current integration method.

objectName  GetNumberOfTimeSteps

Returns the number of different time steps used in the model.

objectName  GetPhaseCount

A synonym for GetNumberOfTimeSteps.

objectName  GetTimeStep index

Return the time interval for the given timestep index.

objectName  GetTimeUnits

Returns the current time units.

objectName  GetValue path

Return the value of a model variable given by the variable path path

objectName  RequestValues ?path ...?

New to Simile v5.6: Requests that on each display update, a call be made to a procedure defined in the script, passing the values of the variables specified in the path arguments. If there are no arguments, there will be no callbacks. The procedure ReceiveValues is called, with the objectName making the request as the first argument, the model time as the second argument, and the values of the requested variables as the subsequent arguments.

objectName  MergeParams filepath ?smPath?

This command is analogous to the model window object's LoadParams command.  Once a model is made runnable (by calling simileScript::ModelWindow Run) then in order to run a model with different file parameters, use the command above before resetting the model. The filepath​ refers to a parameter metafile (.spf) which contains values or references to other files. smPath (submodel path) can be omitted if the parameter variables in the file are relative to the top level of the model.

objectName  SetValue path value

Set the value of a model variable given by the variable path path. This only makes sense for variable parameters. Constant parameters are set by scenario file and other variables are calculated each time step.

objectName  GetMaxValue path

Returns the maximum value acceptable for the variable parameter given by path. (Values are returned for variables other than variable parameters but the values are not used.)

objectName  GetMinValue path

Returns the minimum value acceptable for the variable parameter given by path. (Values are returned for variables other than variable parameters but the values are not used.)

objectName  GetModelClass path

Returns the class of the model component given by  path. The class will be one of: SUBMODEL, VARIABLE, COMPARTMENT, FLOW, CONDITION, CREATION, REPRODUCTION, IMMIGRATION, LOSS or ALARM.

objectName  GetModelDims path

Returns the dimensions of a model component given by  path. Components of a variable instance submodel (population submodel)

objectName  GetModelEval path

Returns evaluation method of a model component given by  path. The evaluation method will be one of EXOGENOUS, DERIVED, TABLE, INPUT,
SPLIT
or GHOST.

objectName  GetModelType path

Returns the type of a model component given by  path. The type will be one of: VALUELESS, REAL, INTEGER, FLAG or EXTERNAL. FLAGs are Boolean types.

objectName  GetAllPaths

Returns a Tcl list of all model components (e.g. submodels as well as variables). E.g. {/Number of Trees} /r /Tree/Saplings /Tree {/Tree/Tree Size} {/Tree/Growth Rate}

{/Tree/Maximum Growth Rate} {/Tree/Chance of Death} {/Tree/X Position} {/Tree/Y Position} /Tree/ID

Note that paths with spaces will be returned wrapped by { }.

objectName  Show

Make the run control dialogue box visible.

objectName  Hide

Hide the run control dialogue box.

Table helper object

Create table helper object

Version 5 and up

similescript::TableHelper objectName run_control_object window_title

Version 4

similescript::TableHelper objectName model_window_object window_title

For example:

Version 5 and up

similescript::TableHelper tableHelper runControl "table1"

Version 4

similescript::TableHelper tableHelper modelWin "table1"

Table helper object commands

objectName AddVariable path

Adds the variable given by path to the list of variables to be written to the table.

objectName RemoveVariable path

Removes the variable given by path from the list of variables to be written to the table.

objectName Update

Causes the table to be updated. Use in conjunction with objectName SetUpdateAtDisplayInterval value.

objectName SetUpdateAtDisplayInterval value

If value is “true” the table updates its display every display interval (even if the table is hidden and so not visible on the screen). This takes a significant time and so the simulation will run faster if value is “false”. Use objectName Update to update the table at the end of the simulation.

objectName GetUpdateAtDisplayInterval

Return “true” or 1 if the table is set to update its display every time interval or “false” or 0 if the table does not update its display. If “false” use objectName Update before saving the contents to file or viewing the table.

objectName SetShowingRowsForTimes value

If value is “true” the table keeps a set of values for each time at which the contents are updated. This can create a large table which takes a significant time to update. If value is “false”, the table will contain only the set of values from when it was last updated. Use objectName AppendToFile to write these to file so they are gathered throughout the simulation.

objectName GetShowingRowsForTimes

Return “true” or 1 if the table is set to keep values for each time at which the contents are updated, or “false” or 0 if the table is set to show only current values. If “false” use objectName AppendToFile to save the contents to file without overwriting previous values.

objectName Clear

Clear the table.

objectName SaveToFile filename

Save the table contents to a comma separated values (CSV) file named filename. Remember to call objectName Update if objectName SetUpdateAtDisplayInterval was set to “false”.

objectName AppendToFile filename section_id

Append the table contents, preceeded by a line containing section_id, to a comma separated values (CSV) file named filename. The file will be created if it does not already exist. Remember to call objectName Update if objectName SetUpdateAtDisplayInterval was set to “false”.

objectName Show

Make the table display visible.

objectName Hide

Hide the table display.

Working with files

Working with files

Opening and saving models

When you save a model, Simile will try to save all the information required to get back to what you were doing when you open it again. If the model is running, Simile will save the executable code and the run information (execution time, integration method and the rest) and the model will start running again as soon as it is opened. If you do not want this to happen, close the model run environment, or select 'Abort execution' under the Model menu, before saving.

In Simile version 7 and later, when you save a model, the file will include the information required to re-create the parameter scenario, the visualization tool setup and the experiment setup, if they exist. Opening the file later will restore all of these. (Note that raw data in .csv and image files is not saved with the model; this must either be present in the same location relative to the model file as when it was saved, or explicitly incorporated into the scenario). Separate scenario, visualization tool and experiment setup files can still be saved and loaded after the model file is opened.

In earlier versions, if a scenario file has been associated with the model (either by loading one or by saving one) the saved model will include a reference to this file, so the parameters will be reloaded without further action when the model is opened. Similarly, if a helper setup file has been associated with the model, the saved model will include a reference to this too, and the helper setup will be restored as soon as it is opened. When opening the model, the files must be in the same location relative to it as when it was saved.

To open an existing file from disk, click the "Open" button on the toolbar or select the "Open" command from the "File" menu. The "Open" command will load a model (using the normal file dialogue box) into a new window, unless your existing window is blank, in which case it will be used for the opened model.

To save the model you are working on, click the "Save" button on the toolbar or select the "Save" or "Save As" commands from the "File" menu. If you have not already saved your model, the effect of these commands is the same. If you have already saved your model, the "Save As" command allows you to select a new file name for this revision. The "Save" command and the "Save" button on the toolbar will use the same name as before.

The "New" button on the toolbar has the effect of re-using the existing window for a new model. Note the difference from the behaviour of the "New" command on the "File" menu, which creates a new empty window.

The "Close" command will close your model (prompting you to save it, if it has changed) and also close the current window. If the current window was the last window open, closing it will exit Simile (except on the Mac, where Simile keeps running with no windows). The "Exit" command will close all your models (with prompts to save any modifications) and windows, and exit Simile.

Double-clicking on a Simile model in Windows Explorer, Finder on the Mac or most Linux file managers will open the model in a new Simile window. Dragging a Simile model file icon to the Simile icon will open the model in a new window.

On building a model, when multiple windows are open, a run control is presented as usual. If multiple models are built, then multiple run controls will be presented. Each run control is associated with one particular model window, and you can use the "Go to model window" and "Go to run control" toolbar buttons to move back and forth between the pair.

Model file formats

New major versions of Simile may use a new model file format. Information on this, and the relationship between it and previous file format is given for advanced users.

Exporting model information

Prolog-format model declarations

C++ source code and compiled libraries

Save model diagram as vector graphics

Reporting problems

Understanding Simile's error reporting tool

In: Contents

Working with files : Model file format



Model file format

Version 5.0 saves models as 'packages' by default. This was an optional feature in version 4.0 onwards, but had problems because any automatic save of a model would not include the extras that made it a package. This made it easy for the execution parameters and other package information to get lost. With Simile 5.0 and up, if you do not want a model to start running wen you open it, you must close the execution window before saving it.

Version 3.0 uses a new file format for the express purpose of making it quicker and simpler to move large models between multiple computers. In the past, the *.sml (or *.sim) file contained the Prolog-format model declarations. This file contains the minimum required to display, edit and run the model. In order to speed things up however, a number of other files were also created. These include the canvas file (*.cnv ), which contains drawing instructions and the compiled model (*.dll or *.tcl) in C++ or Tcl code. These files were stored in several different locations, including temporary folders and the "sim_bits" folder.

This caused a certain amount of confusion. In particular moving a model from one computer to another, or even from one folder to another, required Simile to re-build its supporting files. This can be a lengthy process.

In v3.0, the *.sml file now contains all the supporting information as well. Although this means it is larger than before, it is not much larger than the total size of all the files it is replacing.

One final point is also important. In order to preserve the benefit of having a plain-text representation of the declarative model, the file format is a simple multi-part MIME that bundles together all these files. This is exactly the format used when sending an email containing attached files. There are many tools available for manipulating multi-part MIME files. For example, to use Outlook Express, simply change the *.sml extension to *.eml

In summary, when you move a model file to a new location it will:

  • draw quickly when it is first loaded; and
  • build instantly, if it has not changed since it was last built.

To save a model in the old pre-3.0 format, export "Model declarations" as described in the following section.

In: Contents >> Working with files

Working with files : Export PostScript or SVG graphics

Export PostScript graphics

To export the diagram in the current window in PostScript graphics format, use the "Export" command on the "File" menu and select the option "PostScript graphics" in the sub-menu that appears. A wide range of other graphics programs and printers can interpret PostScript files. On the Linux and SunOS / Solaris operating systems, this is the only way to print model diagrams.

 

Export SVG image

To export the diagram in the current window in SVG (scalable vector graphics) format, use the "Export" command on the "File" menu and select the option "SVG Image" in the sub-menu that appears. SVG images are encoded in an XML based language and are suitable for including in web pages.

In: Contents >> Working with files

 

 

Working with files : Reporting problems



Reporting problems

In order to direct our efforts to solving the problems that affect users the most, Simile includes an error reporting tool to send information on problems to Simulistics over the Internet. In order to use the tool, you must have a connection to the Internet, and your model must not be confidential. The data sent to Simulistics includes parts of the model file, as well as information on the logical commands that were being executed at the immediately before the problem. Although we use the data you send only to help improve Simile, we would not wish to receive parts of models that you consider confidential.

All data are collected anonymously. If you wish to receive technical support for a particular problem, please contact us directly.

In: Contents >> Working with files

Working with files : Export C++ program



Export C++ program & executables

When building a model, the generated C++ source code and the compiled library (*.dll or *.so) are stored in temporary files. If you wish to modify the source code, or if you wish to use the model library in another program, you can use the "Export" command on the "File" menu and select the "C++ program & executables" to save these files in a location of your choice.

For details of the exported functions in the compiled library, please contact Simulistics.

In: Contents >> Working with files

Working with files : Export model declarations