Contents summary

What’s new?

New features of Simile version 5.0

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

Elements of the model diagram

Introduction to compartments, flows, and the other elements used in model diagrams

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 version 5

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 and 5.1 for a more comprehensive list.

Happy modelling!


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.

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, 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.


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 [image] 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.

3. Add an interest flow and a withdrawal flow.

· Click on the [image] flow symbol in the toolbar.

· Move the mouse 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.

4. Add a variable for the interest rate

· Click on the [image] 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 [image] 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 [image] 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 connection points where arrows meet nodes (these can be dragged around the boundary of the node); 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.


Step 3: Adding initial values, parameter values and equations

<< Previous Step Next Step >>

1. Prepare to set component properties

· Click on the [image] 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 [image] 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.


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

  • 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.


Step 5: Choosing the output displays

<< Previous Step Next Step >>

1. Select the graph-plot display

  • Click on the [image] “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 [image] “Add a variable” button on the plotter toolbar
  • Click on the compartment labelled account in the list of model variables.


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.


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 [image] pointer button in the toolbar.

2. 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.

3. Run the model again

  • Click on the “Play” button on the toolbar.

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


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.

3. Loading a model from file

Either:

  • Select the [image] “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


Model diagram elements

Elements of the model diagram

Simile model diagrams are constructed from the following set of 11 symbols. The first four, the compartment, flow, variable and influence, are the fundamental elements of all System Dynamics models. All models will include one or more of these elements.

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

Simile has a very rich concept: the submodel, which allows model elements to be grouped to represent an object or multiple objects. One chapter of the help is dedicated to the submodel concept. The following symbols are used in models involving submodels.

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
iteration | Represents an iterative loop within a single time-step

In : Contents


Model diagram elements : Compartment

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);
  • 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 >> Model diagram elements


Model diagram elements : Flow arrow

Flow arrow

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.

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 an “Input parameter”.

Rules

  • A flow arrow can only be drawn into and/or out of a compartment.

  • 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 >> Model diagram elements


Model diagram elements : Variable

Variable

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. “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. Expression is some function of simulation time (i.e. involves the built-in function time).
Intermediate variable | One or more influence arrows pointing to it. One or more influence arrows pointing from it
Output variable: typically, this is used to report on some aspect of model behaviour (e.g. the ratio of two compartments). | One or more influence arrows point to it. No influence arrows pointing from it.
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 symbol may have zero or more influence arrows pointing from it.

  • A variable may not have flow arrows pointing to or from it.

In : Contents >> Model diagram elements


Model diagram elements : Influence arrow

Influence arrow

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. This has no meaningful modelling function, but acts as a temporary placeholder to the influence arrow until it is connected to an element inside the submodel. In order to do this, drag an influence arrow from the node at the submodel boundary to the desired element inside the submodel.

  • 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.

Iteration

  • Influence arrows have one property that can be set. To invoke the property dialogue box for an influence arrow, double-click on the arrow. The property is “Use values made in same time step”. This is used in combination with the iteration symbol to implement many iterative methods. The property indicates how the ambiguity associated with a circular loop of influences is to be resolved.

  • 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.

In : Contents >> Model diagram elements


Model diagram elements : Submodel

Submodel

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 [image] 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 [image] 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. The submodel then represents each of that number of instances. Visually, it now appears different, because it now has multiple lines on the left- 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.

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 (again, 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.

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 normal submodel, 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 will either be zero (if the submodel does not exist), or one, if it does. This 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.

However, if you use a population submodel to model the trees, then you have a problem. A population submodel exports a list of values rather than an array: it has to do this, because the number of values can change dynamically, rather than being fixed. Currently, Simile does not have a list-processing language corresponding to the array-processing language as above. All you can do with a list is to sum it, count the number of elements in it, or find it minimum or maximum value.

The satellite submodel is a mechanism for dealing with problems like this. 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.

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 incremental compilation of a complex model

Complex models — that is, models with a large number of symbols and equations — can take a significant to build (i.e. generate the program for simulating the behaviour of the model). It can be as long as 10+ minutes for a complex model (100s of equations) on a slow computer.

Normally the build process is done with the whole model, and every time you make some change, no matter how small, it has to be done again before you can run the model. However, it is possible to specify that a submodel is built separately (in technical terms, a separate DLL is generated for it). This greatly speeds up the re-building process for any changes made to this submodel, since Simile has only to re-build the submodel, not the whole model.

In : Contents >> Model diagram elements


Model diagram elements : Initialisation

Initialisation

The Initialisation symbol is used to specify the initial number of individuals in a population submodel.

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.

So, assuming that you already have a population submodel in your model diagram:

  1. click on the Initialisation symbol on the toolbar;
  2. move the mouse to within the envelope of the population submodel;
  3. click the mouse to deposit the Initialisation symbol in the submodel.

Rules

  • You can have a maximum of one Initialisation symbol in any one population submodel. It does not make sense to have more than one, since Simile would then not know which one to use.

  • 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.

  • Although it is possible to draw an influence arrow from the migration symbol to another element, the only use of this is with the channel_is( ) function. The value of the migration symbol is not the value entered or calculated.

In : Contents >> Model diagram elements


Model diagram elements : Migration

Migration

The Migration 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 Migration symbol determines the total number of new instances that are created.

How to add a Migration symbol

The migration symbol only has meaning in the context of a population submodel. Therefore, it makes sense to construct a population submodel first, then add the migration symbol to it. This is not strictly necessary: you can add the migration 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.

So, assuming that you already have a population submodel in your model diagram:

  1. click on the migration symbol on the toolbar;
  2. move the mouse to within the envelope of the population submodel;
  3. click the mouse to deposit the migration symbol in the submodel.

Rules

  • The migration 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 migration 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.

  • Although it is possible to draw an influence arrow from the migration symbol to another element, the only use of this is with the channel_is( ) function. The value of the migration symbol is not the value entered or calculated, but the fraction remaining before the next instance is created. (See “Interpretation” below for details.)

Interpretation

The migration 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 migration 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?

Case 1: time step = 1, migration = 3

Three new instances are created every time step.

Case 2: time step = 1, migration = 0.7

During the first time step, the value for migration (0.7) is not enough to create a new instance of the population submodel. Simile then remembers the value 0.7. When it comes to the next time step, the value for migration is then added on, giving 0.7+0.7=1.4. This is sufficient to create one new instance, leaving 0.4 in the bank.

The process continues, as shown here:

1 0.0 0.7 0.7 0 0.7

2 0.7 0.7 1.4 1 0.4

3 0.4 0.7 1.1 1 0.1

4 0.1 0.7 0.8 0 0.8

5 0.8 0.7 1.5 1 0.5

6 0.5 0.7 1.2 1 0.2

7 0.2 0.7 0.9 0 0.9

8 0.9 0.7 1.6 1 0.6

9 0.6 0.7 1.3 1 0.3

10 0.3 0.7 1.0 1 0.0

Case 3: time step = 0.1, migration = 0.7

The value for migration is a migration rate, expressed in whatever your global unit of time is (typically 'year'). Therefore a value of migration of 0.7 individuals per year gives a value of 0.07 individuals in one time step (0.1 year). Exactly the same procedure as above is applied, with the migration value accumulating until a whole number of individuals can be created.

Case 4: time step = 1, migration = 3.4

The same procedure as above is applied, with 3 new instances being created in some time steps, and 4 in others.

You might well feel uncomfortable with the deterministic nature of the process. In this case, it is up to you to engineer a suitable stochastic mechanism that generates new individuals at the same average rate. In the future, Simile will include functions for sampling from appropriate frequency distributions for handling a variety of options (please contact the authors of Simile if you want to discuss this). In the meantime, and if your rate of migration is less than 1, then you can treat the value as a probability that migration will occur, and use the following expression for migration:

if rand_var(0,1)<0.7 then 1 else 0

where 0.7 is the migration rate.

In : Contents >> Model diagram elements


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.

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.

So, assuming that you already have a population submodel in your model diagram:

  1. click on the reproduction symbol on the toolbar;
  2. move the mouse to within the envelope of the population submodel;
  3. click the mouse to deposit the reproduction symbol in the submodel.

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 would normally be pretty inappropriate to have more than one method for reproduction, but it is perfectly legal as far as Simile is concerned.

  • Although it is possible to draw an influence arrow from the reproduction symbol to another element, the only use of this is with the channel_is( ) function. The value of the reproduction symbol is not the value entered or calculated, but the fraction remaining before the next instance is created. (See “Interpretation” below for details.)

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 severely restricts the modelling you can do: in particular, it rules 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 until it has sufficient to make one new individual.

The following cases illustrate how Simile interprets the information provided in the reproduction symbol. In all cases, the analysis is for ONE INDIVIDUAL in the current population: the total input of new individuals into the population is the sum of the input from each individual.

Case 1: time step = 1, reproduction = 3

Three new instances are created every time step.

Case 2: time step = 1, reproduction = 0.7

During the first time step, the value for reproduction (0.7) is not enough to create a new instance of the population submodel. Simile then remembers the value 0.7. When it comes to the next time step, the value for reproduction is then added on, giving 0.7+0.7=1.4. This is sufficient to create one new instance, leaving 0.4 in credit. The process continues, as shown here:

1 0.0 0.7 0.7 0 0.7

2 0.7 0.7 1.4 1 0.4

3 0.4 0.7 1.1 1 0.1

4 0.1 0.7 0.8 0 0.8

5 0.8 0.7 1.5 1 0.5

6 0.5 0.7 1.2 1 0.2

7 0.2 0.7 0.9 0 0.9

8 0.9 0.7 1.6 1 0.6

9 0.6 0.7 1.3 1 0.3

10 0.3 0.7 1.0 1 0.0

Case 3: time step = 0.1, reproduction = 0.7

The value for reproduction is a reproduction rate, expressed in whatever your global unit of time is (typically “year”). Therefore a value of reproduction of 0.7 individuals per year gives a value of 0.07 individuals in one time step (0.1 year). Exactly the same procedure as above is applied, with the reproduction value accumulating until a whole number of individuals can be created.

Case 4: time step = 1, reproduction = 3.4

The same procedure as above is applied, with three new instances being created in some time steps, and four in others.

You might well feel uncomfortable with the deterministic nature of the process. In this case, it is up to you to engineer a suitable stochastic mechanism that generates new individuals at the same average rate. In the future, Simile will include functions for sampling from appropriate frequency distributions for handling a variety of options (please contact the authors of Simile if you want to discuss this). In the meantime, and if your rate of reproduction is less than 1, then you can treat the value as a probability that reproduction will occur, and use the following expression for reproduction:

if rand_var(0,1)<0.7 then 1 else 0

where 0.7 is the reproduction rate.

This may be a pretty reasonable way of representing things, if it is the case that some individuals produce 1 offspring, and others produce none, with a probability of 0.7 and 0.3 respectively. (Biologically, it is possible that some individuals may produce 2 or more offspring, with the average being 0.7. In that case, the above method is only a rough approximation, and you should aim to develop a solution based on the relative probability of different numbers of offspring.)

In : Contents >> Model diagram elements


Model diagram elements : Extermination

Extermination

The mortality symbol is used to specify the conditions under which one instance of a population submodel is destroyed.

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.

So, assuming that you already have a population submodel in your model diagram:

  1. click on the mortality symbol on the toolbar;
  2. move the mouse to within the envelope of the population submodel;
  3. click the mouse to deposit the mortality symbol in the submodel.

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.

In : Contents >> Model diagram elements


Model diagram elements : Role arrow

Role arrow

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. The dimensions of the matrix depend on the number of role arrows used, and the different uses are therefore described in separate sections.

· one role arrow

· two role arrows – two submodels

· two role arrows – one submodel

How to add a role arrow

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. Therefore, these two submodels must already exist in your model diagram.

  1. click on the role arrow symbol on the toolbar;
  2. move the mouse to inside the submodel that has a role in an association;
  3. drag the mouse to inside the submodel that represents the association itself;
  4. release the mouse button.

In : Contents >> Model diagram elements


Model diagram elements : 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 “Master”, and the role arrow points from it, to the other submodel, called “Satellite”. “Master” is a multiple-instance submodel, with fixed dimensions. In the following example, there are ten instances of “Master”. Inside “Master” 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 “Master”.

To start with, consider that the [image] condition symbol in “Satellite” is omitted. In this case, ten instances of “Satellite” are created, the same as the number of instances of “Master”. Inside “Satellite” is a variable called “var1”. There is an influence arrow from the variable “index” in “Master” to “var1”, and its equation is simply “index”. The value of “var1” in each instance of Satellite is therefore equal to the “index” of the equivalent instance of “Master”.

To illustrate how “var1” is treated, there are four influence arrows taken from it. Two influence arrows point to variables “count” and “sum” within “Master” and two point to variables “count” and “sum” outside “Master”. 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 “Master”.

  • Inside “Master”, the equation “count({var1})” returns 1, and “sum({var1})” returns a value equal to “index” of the same instance.
  • Outside “Master”, 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 “Master”, the value returned from “Satellite” is received as a list, which is not what would happen if “Satellite” were nested inside “Master”. An integrating function such as sum() or count() must be used immediately on a list. Inside “Master”, the list consists of a single number, so sum({var1}) 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 this is possible. Suppose one wishes “Satellite” to exist for only the odd-numbered instances of “Master”. In this case, the equation “fmod(index(1),2)==1” would be used. Note that the index() function used within “Satellite” refers to the index of the equivalent instance of “Master”.

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 “Master”. There can never be more instances of “Satellite” however than instances of “Master”.

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

  • Inside “Master”, the equation “count({var1})” 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})” 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 “Master”, 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 “Master” it would not be possible directly to receive the list in a variable outside “Master”.

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


Model diagram elements : Role arrow : Two role arrows - two objects

Two role arrows – two 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”. 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. Change the local names to be “indexA” and “indexB” to avoid confusion. Right-click the parameter name to alter it, 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. 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 [image] 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


Model diagram elements : Role arrow : Two role arrows - one object

Two role arrows – one 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.

 | var1_I |  |  | var1_II
 | value | count | sum | value | count | sum
Instance 1 | {1 1 1} | 3 | 3 | {1 2 3} | 3 | 6
Instance 2 | {2 2 2} | 3 | 6 | {1 2 3} | 3 | 6
Instance 3 | {3 3 3} | 3 | 9 | {1 2 3} | 3 | 6

· 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 [image] condition symbol can be used inside “Association” to permit fewer instances than the square of the number of instances of “Object” to be generated. 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”. 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.

So, assuming that you already have the submodel that you wish to make conditional in your model diagram:

  1. click on the Condition symbol on the toolbar;
  2. move the mouse to within the envelope of the multiple-instance submodel;
  3. click the mouse to deposit the Condition symbol in the submodel.

Rules

  • A condition element only has use within a submodel (since it specifies which potential instances exist).

  • 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”.

  • 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.

In : Contents >> Model diagram elements


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

  1. Click on the Iteration symbol on the toolbar.
  2. Click the mouse to deposit the Iteration symbol.

Rules

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 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.

  • The expression in the equation dialogue box for a 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 >> Model diagram elements


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 eleven 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

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

Searching for a particular element

The following advanced topics are dealt with separately.

Rescaling symbol size in a particular submodel

Controlling the amount of detail shown in the model diagram

Following influences around the diagram

Adding pictures to the model diagram

Adding text to the model diagram

Setting preferences

In: Contents


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 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. 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. The elements will all be selected when the drag is released. If any part of an element (excluding the caption) is included in the area, it will be included in 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.


Working with model diagrams : Adding node-type elements

Adding node-type elements

The node-type elements are the [image] variable and the [image] compartment, as well as the elements used in population submodels. 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. 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.

Note that it is not possible to add a node-type element to an area of your diagram that is already occupied. No error message appears, so if this happens, simply click somewhere else where there is sufficient space, or [image] move existing elements around to make sufficient space.

In: Contents >> Working with model diagrams


Working with model diagrams : Adding arrow-type elements

Adding arrow-type elements

The arrow-type elements are the [image] influence, [image] flow and [image] 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.
  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 node where you want the arrow to start.
  3. Click on the node where you want the arrow to end.
  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.

Specific instructions for each type of arrow

Flow arrow

A flow 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 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) 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 [image] 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 [image] 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. 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 may find that one or more arrows leaving the submodel become detached from the point on the submodel boundary that the influence is attached to. You can usually fix this by selecting the [image] move tool from the toolbar, and dragging the attachment point around the submodel.

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 [image] 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.
  3. Repeat (2) if you want to add more submodels.

Note that the submodel you make may or may not enclose existing model elements. 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. You will need to move them around prior to drawing the submodel envelope if this is what you wish to do. The elements are then deemed to be enclosed inside the submodel. Any influence arrows coming from outside this new submodel to elements inside it, or vice versa, will be redrawn to show a break at the submodel boundary.

Note that temporarily enclosing some model elements in a submodel is an easy way of moving a block of elements around the model diagram. You enclose them in a submodel envelope, select the move tool, move the submodel around (thus moving the contained elements at the same time, then delete 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 : Changing labels

Changing the label for elements on a model diagram

To re-label any element in the model diagram:

  1. Click on the [image] select tool on the toolbar.
  2. Click on the label of the element in the model diagram that you wish to change.
  3. Use the Backspace or the Delete key to remove the existing label.
  4. 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 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, then Simile will generate an error message and leave the label unchanged.

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 : Adding pictures

Adding pictures

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

To include a picture on the model diagram it must be a bitmap in gif or jpeg format. Either the whole model desktop can be used, or a submodel can be used as a placeholder. The bitmap will be cropped or tiled to fit in the available space.

The following procedure is used to add a picture 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 follows:

  1. Click on the [image] 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.
  3. Repeat (2) if you want to add more placeholders.

  • Secondly, to add the picture, use the [image] 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. 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 or tiled as necessary, or add model diagram elements, which will appear in front of the picture.

Note that 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 : Adding text

Adding text

There is limited support for including text on the model diagram. In particular, a submodel must be used as a placeholder.

The following procedure is used to add text.

  • Firstly, add a submodel of the desired size and shape, as follows:

  1. Click on the [image] 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.
  3. Repeat (2) if you want to add more placeholders.

  • Secondly, re-label the submodel. This is the text you wish to display. It is most suitable for adding short titles to mark sections of your model.

  4. Click on the [image] select symbol in the tool bar.
  5. Edit the caption as desired.
  6. Click on the [image] move symbol in the tool bar.
  7. Move the caption to the centre of the placeholder.

  • Finally, to size the text as desired, double-click within a blank area within the submodel. This invokes the submodel properties dialogue box. Then:

  1. Click the “More…” button to view all the available properties.
  2. Slide the “Relative scale” bar to make the text larger or smaller.
  3. Click “OK” to return to the model window.

The selected text will now appear in the submodel placeholder.

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. Click on the [image] pointer tool.
  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:

  • Moving labels
  • Moving flow valve symbols
  • Moving influence arrows
  • Moving role arrows
  • Moving and re-sizing submodels
  • Moving groups of 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.

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 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 valve symbols

Moving flow valve symbols

You cannot change the actual path taken by a flow arrow. However, you can change the position of the valve (bowtie) symbol on the flow arrow, by dragging it along the arrow in the desired direction. You can also move the cloud associated with flows, generating a corresponding re-alignment of the flow route.

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

If you draw two flows between the same two compartments in opposite directions, then the flows largely or completely 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, unlike flow 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.

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


Working with model diagrams : Moving and re-sizing submodels

#TJMovingandresizingsubmodels#Moving and re-sizing submodels

The following rules govern the behaviour of the [image] 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 include an existing element within an existing submodel by moving either the element or the submodel boundary. It is necessary instead to delete the submodel boundary and re-draw it. Re-draw the envelope in the usual manner (see “Adding submodels”) to include all the elements. Note that all the properties of the submodel are lost when it is deleted, and it may be necessary to edit the caption and the other properties of the submodel afterwards. Similarly, it is possible to delete the element to be included, and to add it (see “Adding node-like elements” or “Adding arrow-like elements”) again within the submodel. It may be necessary to edit the caption and the other properties of the element afterwards.

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


Working with model diagrams : Moving role arrows

Moving role arrows

When you draw two relation arrows from the same submodel to an association submodel, then they are drawn one on top of the other. To separate them, you can:

  1. drag the dot at either end of the arrow, to move that end up or down the submodel boundary; or
  2. drag anywhere along the length of the relation arrow, to change the path taken by the arrow between the start and end dots.

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.

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


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 [image] pointer tool.
  2. Move the mouse to the element in the model diagram that you wish to delete.
  3. Click to select the element. You can select more than one element at this point, holding down the Ctrl key.
  4. Use the context menu (right-click) and choose the delete command.

Please note

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

In: Contents >> Working with model diagrams


Working with model diagrams : Duplicate submodel

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 [image] 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) [image] copy and [image] 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.

In: Contents >> Working with model diagrams


Working with model diagrams : Groups of elements

Groups of elements

It is often convenient to be able to move or delete a group of elements all at once. This can be done using the [image] submodel envelope to group the elements together temporarily, whilst moving or deleting them. The submodel envelope can be itself deleted afterwards.

Moving a group of elements

  1. Select [image] submodel tool.
  2. Draw a submodel around the group of components you wish to move. Note that for this to be possible, the components must have been placed within a rectangular area, within which there are no other components. For more information on drawing the submodel envelope, see “Adding submodels”.
  3. Select the [image] move tool
  4. Drag the submodel to move it (and its contents). Note that for this to be possible, there must be clear canvas with no obstructing elements along the path that you drag the submodel to its destination.
  5. Select the [image] delete tool.
  6. Delete the submodel boundary.

Deleting a group of elements

  1. Select [image] submodel tool.
  2. Draw a submodel around the group of components you wish to delete. Note that for this to be possible, the components must have been placed within a rectangular area, within which there are no other components. For more information on drawing the submodel envelope, see “Adding submodels”.
  3. Open the submodel into its own window, by double-clicking on its border. For more informatio, see “Opening a window for a submodel”.
  4. In the newly-opened submodel window, select [image] new, or use the New command on the File menu, to delete all the components.
  5. Close the submodel window, using the Close command on the File menu.
  6. Select the [image] delete tool.
  7. Delete the submodel boundary.

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 (a compartment or a variable), 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 [image] ghost button on the tool bar, or select the “Ghost” item on the “Tools” menu.
  2. Click on the element to be ghosted.
  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.

Once a ghost is created, changes to its value or equation, 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.

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.

Note that if you delete the original element, all its ghosts will become undefined. You can delete a ghost without affecting the original, unless you have added influence arrows or flows to the ghost, in which case the original will become incomplete.

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 [image] 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.4x scaling: symbols are slightly bigger
To fit | automatic re-sizing of diagram to fit the window. Note that this is according to the least constraining dimension, so you may not actually see your whole diagram in the window. Thus, if you have a diagram which is very wide, but not tall, then it will be “zoomed to fit” vertically, and you will have to scroll left and right to see the rest of the diagram.
Out a bit | approx 0.7x scaling: symbols are slightly smaller
Out lots | 0.5x scaling: symbols are halved in (linear) size

Zooming using the Zoom buttons on the toolbar

  • has the same effect as “Zoom...in a bit” item 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...out a bit” item in the View menu: it scales by approx. 0.7x, making the symbols smaller and showing more of the diagram.

In: Contents >> Working with model diagrams


Working with model diagrams : Searching for a particular variable

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 elements using text contained in the element’s 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

Elements are searched in order, with the first to match the text being highlighted. If this is not the one you want, or you want to find others using the same text, use the “Find Next” tool. Alternatively, you can choose the commands “Find...” and “Find next” on the Edit menu.

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”. It is also a useful way to find the elements that are influenced by a particular element. These are of course also indicated by influence arrows, but on large diagrams these can be difficult to follow, and if the element is ghosted, may also originate from the ghost. In that case, enter the name of the element in the “Find” dialogue box and search for its use in equations.

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 case-sensitive, so “VAR” will not 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”.

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 submodel properties dialogue box. This dialogue box is displayed by double-clicking anywhere within the submodel, or by opening the submodel in a new window, and selecting the “Properties…” command from the “Model” menu.

If the slider control is not displayed in the dialogue box, click the “More” button. This reveals the advanced settings.

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 “Model” menu. This control allows you to reduce the absolute size of the desktop symbols, meaning that the symbols in submodels are now relatively larger.

In: Contents >> Working with model diagrams


Working with model diagrams : Inspect model variable

Inspect model variable

The snapshot tool 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 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 ( [image]) 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.

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 ( [image]) 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.

Note 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


Working with model diagrams : Controlling the amount of detail shown

Controlling the amount of detail shown in the model diagram

By default, Simile displays all the elements in the model diagram: 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.

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 two buttons, 'Components influencing selection' and 'components influenced by selection'. Hitting either 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 : 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 options are displayed in four sections:

  • View
  • Edit
  • Build
  • Save
  • Run

Please consult each section for further help.

In: Contents >> Working with model diagrams


Working with model diagrams : Preferences : View

Preferences dialogue box

“View” settings

In new model windows, display toolbar, component bar and equation bar

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.

Display popups over model components for equations, values and comments

While in [image] pointer mode, holding the pointer over any model component will cause a popup window to appear including that component's equation, value(s) 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.

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

Use large buttons

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

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


Working with model diagrams : Preferences : Edit

Preferences dialogue box

“Edit” settings

Rectilinear flow routing

Flows 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 this 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.

Delete 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 deleted individually. The default is that clicking on a link at any point will delete the whole link. This alternative, of deleting only the section clicked on, is used to create a slider-controlled variable at each end of the deleted section.

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


Working with model diagrams : Preferences : Build

Preferences dialogue box

“Build” settings

Position of run control and input sliders

Position of the run control and slider windows, when not using the single window run time environment is 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.

Use which C++ compiler

Models can be compiled and linked using either Microsoft Visual C++ (any 32-bit version) or GNU mingw GCC (version 2.95.2 or later).

Use single-window run time environment

This option selects between the single-window and multiple-window run time environments.

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


Working with model diagrams : 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.

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


Working with model diagrams : Preferences : Run

Preferences dialogue box

“Run” settings

Use single-window run time environment

This option selects between the single-window and multiple-window run time environments.

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


Working with equations

Equations are the mathematical basis for simulating the behaviour of a model. 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. 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. For more information, see the Introduction to equations.

How to enter equations

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

  • the Equation bar, for simple expressions; or
  • the Equation dialogue window, for more complex expressions.

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:

  • the components of an equation;
  • functions; generally, and specifically:
    • built-in functions; or
    • user-supplied functions

Working with variables and data types

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

  • Arrays and lists
  • Dimensions
  • Parameters for fixed or variable quantities
  • Physical units
  • Enumerated types
  • Local names within equations for other variables

In: Contents


Working with equations : Introduction

Introduction to equations

Equations are used for two purposes:

  • to provide the initial value for model elements that need to be initialised, such as [image] compartments;

  • to enable a value for each other type of element to be calculated while the model is running.

In the first case, the equation is used only at the very start of the simulation: the element’s value may change subsequently as the simulation proceeds. This use of the equation applies to just two types of model element: the compartment and the initialisation element for population submodels. For a compartment, it specifies the initial value of that compartment: the value of the compartment will change during the course of the simulation as a result of the flows into or out of it. For the initialisation element, the equation specifies how many instances of a population submodel initially exist: these may be destroyed and others created as the simulation proceeds.

In the second case, the equation is being referred to throughout the simulation. This use of the equation applies to all other types of model element.

In all cases, you (the model developer) enter the equation using the equation bar or equation dialogue window. The equation dialogue window is required for entering some more complex types of expression. This window is displayed by double-clicking on a model element (except for a submodel or an influence arrow) when you are in [image] Pointer mode.

An equation has the general form: quantity = expression where “quantity” is some quantity in the model (such as variable or flow) and “expression” is some algebraic expression that is evaluated when the model is running to provide the value for the quantity.

Since you have clicked on the symbol for a particular quantity, you have already specified what quantity the equation is for, and thus you do not have to enter the left-hand side of the equation: all you have to do is to enter the expression.

It is sometimes not appreciated that an equation is constantly being re-evaluated during the course of a simulation run. Thus, an equation for calculating the flow rate for water out of a tank, in terms of the amount of water in the tank, might be:

outflow = 0.1*tank

i.e. the outflow is proportional to the amount of water in the tank. When the model is running, the value for the amount of water in the tank is changing, and thus the calculated outflow changes as well.

In: Contents >> Working with equations


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 [image] button, or hit return, to set the equation.
  • Click on the [image] 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 those elements listed in a drop-down list under the [image] button.

  • Click on any element listed in the drop-down box to enter it into the equation.

A selection of the most-commonly used functions are listed in a drop-down list under the [image] button. If the function you require is not listed, you can still type its name directly into the edit box.

  • Click on any function listed in the drop-down list to enter it into the equation.

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 [image] compartments, [image] flows and [image] variables, as well as the control symbols [image] iterations and [image] conditions, and the population symbols. (Note that three other model elements, [image] submodels, [image] influence arrows, and [image] role arrows each have their own dialogue box).

The equation dialogue 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 brackets ready for argument expressions to be entered there if needed.

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, 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.

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 ‘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: the value for the model element is set when the model is built and can change during the simulation. The value can be 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 of working with variable parameters, see the help section “Variable parameters”, and for a full explanation of working with sliders, see the help section “Sliders”.

  2. 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. 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”.

  3. 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.

Notes:

    • 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 linear interpolation of 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 must be in comma-separated value (CSV) format, 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.

    • Default: By default, the data source is an equation. For this reason, the equation bar is commonly used to enter simple equations. It is necessary to invoke the equation dialogue box only when changing the data source to File or Slider, or if you wish to use the list boxes to construct complex equations more easily.

The data source panel also contains entry fields for minimum and maximum values and for units. It also shows the current array dimensions of the model element. The minimum and maximum values do not actually constrain the component’s value but they are used when attaching I/O tools to set the range of values which can be displayed. 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.

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. 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 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. Right-click on the name in the list box to edit it. Each other model element can have only one local name in this one (though the other model element might be referred to using a different local name in further other model elements expressions). For this reason, if you edit the local name, you may also need to edit the expression itself to update the corresponding references.

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 put comments directly into the equation text by enclosing them in /* ... */ symbols.

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 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).

  2. 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.

  3. The user might use the makearray(…) function.

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.

  2. 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].

  3. 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).

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.

Processing lists

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 pass lists around from one variable to another. Rather, you must perform some legitimate list-processing operation, such as using the function sum(…) to sum the values of the list.

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.

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.

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.

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 : 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. Right-click on the name in the list box to edit it. Each other model element can have only one local name in this one (though the other model element might be referred to using a different local name in further other model elements expressions). For this reason, if you edit the local name, you may also need to edit the expression itself to update the corresponding references.

Use the equation dialogue box to edit the local name.

In: Contents >> Working with equations


Working with equations : Input parameters

Parameters

There are two kinds of parameter that can be used in models.

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.
Variable parameter | The value of a variable parameter is first set when the model is ready to run, but it can change throughout the simulation. Values can be taken from a file, a table editor, or using a slider control.

In: Contents >> Working with equations


Working with equations : 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. Finally, 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.

Use the equation dialogue box to designate a variable as an variable parameter. It is also possible to set the initial value of a compartment in the same way. 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 equations : 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).

Use the equation dialogue box to designate a variable as an 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 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.

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 [image] button on the equation bar, and in the “Parameter” column 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 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.

Mathematical operators

You can use the following mathematical operators:

+ | addition | e.g. 15+7 (evaluates to 12)
- | subtraction | e.g. 15-7 (evaluates to 8)
* | multiply | e.g. 15*7 (evaluates to 105)
/ | divide | e.g. 15/7 (evaluates to 2.1428…)
^ | 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 : 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

or

Y = if condition1 then expression1 elseif condition2 then expression2 elseif expression3 then condition3 ...... 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)

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

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


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 actions.

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.

A | B | and | or | xor | A | not
1 | 1 | 1 | 1 | 0 | 1 | 0
1 | 0 | 0 | 1 | 1 | 0 | 1
0 | 1 | 0 | 1 | 1 |  |
0 | 0 | 0 | 0 | 0 |  |

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


Working with equations : Intermediate variables

Intermediate variables

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.

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.

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.

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).

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. These functions are listed in a text file, using Simile's equation language to formulate the expression.

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


Working with equations : Built-in functions

Built-in functions

Alphabetical list of all functions (except trigonometric functions , which are listed separately)

Function | Description | Input(s) | Result
abs(X) | Returns the absolute value of X | numeric | numeric
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
ceil(X) | Rounds up X to the next whole number | numeric | numeric
channel_is(X) | X is an immigration, reproduction or creation channel. Returns true if this individual appeared through that channel. | Boolean | numeric
count([X]) | Number of values in the array [X] or the list {X} | scalar array/list | integer
delay(X,n) | Returns value of variable X, n time steps ago | variable, integer | numeric
dt(I) | Returns the duration of the time step level I | numeric | numeric
element([X],I) | Picks the I'th value form the array [X] | array of any type,integer | type
exp(X) | Returns e to the power X | numeric | numeric
floor(X) | Rounds X down to a whole number | numeric | numeric
fmod(X,Y) | Returns remainder after dividing X by Y | numeric, numeric | numeric
greatest([X]) greatest({X}) | Returns the largest value from an array [X] or the list {X} | numeric array/list | numeric
hypot(X,Y) | Returns length of hypotenuse of triangle with base X and height Y | numeric, 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. | numeric | numeric
init_time(1) | Returns the time at which this instance appeared -- argument is dummy | numeric | numeric
int(X) | Returns integer part of X | numeric | numeric
last(X) | Recalls value of X from previous time step | numeric | numeric
least([X]) least({X}) | Returns the smallest value from an array [X] or the list {X} | numeric array/list | numeric
log(X) | Returns natural logarithm of X | numeric | numeric
log10(X) | Returns base-10 logarithm of X | numeric | numeric
makearray(X,N) | Makes an array consisting of N lots of X | any type, numeric | array of same type
max(X,Y) | Returns greater of X and Y | numeric, numeric | numeric
min(X,Y) | Returns lesser of X and Y | numeric, numeric | numeric
parent(I) | Returns the id of the individual whose reproduction gave rise to this one, or 0 if it immigrated or was created | numeric | integer
place_in(I) | When making an array with makearray, this gives each term's position in the array -- argument is nesting depth | numeric | integer
pow(X,Y) | Returns X raised to the power Y | numeric, numeric | numeric
prev(N) | Returns the value of this component N time steps ago | numeric | numeric
product([X]) product({X}) | Result is the product of all elements of the array [X] or the list {X} | numeric array/list | numeric
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, which stays the same until the simulation is reset. | numeric, numeric | numeric
rand_var(X,Y) | Returns a random number between X and Y, with a new value every time step. | numeric, numeric | numeric
round(X) | Rounds X up or down to the nearest whole number | numeric | numeric
size(S) | Takes the name of a fixed-membership submodel and returns the number of instances that it has. | submodel | integer
size(S,I) | Takes the name of a fixed-membership submodel and returns the size of one of its dimensions | submodel, numeric | integer
sqrt(X) | Returns the square root of X | numeric | numeric
stop(X) | Stops the simulation, displaying value of X in a popup message | numeric | numeric
sum([X]) | Result is the sum of all elements of the argument | numeric array/list | numeric
time() | Returns the current simulation time (the argument is ignored) | numeric | numeric
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 | any
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 | any

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

In: Contents >> Working with equations >> 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 : 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 : 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 : 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 : channel 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 : 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 : 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)

Comments

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 : delay function

delay function

delay(var,n)

Input: a variable name and a number (real or integer) of time steps

Result: the value (real or integer) of the named variable, n time steps ago

This function returns some previous value of another variable, a arbitrary period of time before. The period of time is defined in time steps (not units). The number need not be an integer, but since time steps are discrete, the effect will always be as if the next largest integer was specified. 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.

Examples:

runoff=delay(rain,10)

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 two examples:

element([3,2,7,4,9,34,1,5], [[5,2], [1,5]]) --> [[9,2], [3,9]]

element([[5,7],[1,4],[8,5]], [3,3,2,2]) --> [[8,5], [8,5], [1,4], [1,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 : 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.

Comments

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 : 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 : 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.

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 : 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 : 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 : 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 : 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 delay( ) function, which is 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 : 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 : 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 : 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 : 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(0, 1), rand(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.

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 : 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 : 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 : 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 : 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 : 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 : 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 : 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 side of a one-hectare plot, assuming that the values are in metres.

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 : 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.

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 : 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 : 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 : 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 : 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.

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

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 : 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 : 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


Working with equations : Trigonometric functions

Trigonometric functions

Function | Description | Input(s) | Result
acos(X) | Returns the arccos (inverse cosine) of X. Result is in radians. | numeric | numeric
acosh(X) | Returns the inverse hyperbolic cosine of X. | numeric | numeric
acot(X) | Returns the inverse arccotangent of X. | numeric | numeric
acot2(X,Y) | Returns the inverse arcotangent of the ratio of X to Y. | numeric, numeric | numeric
acoth(X) | Returns the inverse hyperbolic cotangent of X. | numeric | numeric
arctan(X) | Returns the arctan (inverse tangent) of X. Same as atan(X). | numeric | numeric
asin(X) | Returns the arcsine of X. Result is in radians. | numeric | numeric
asinh(X) | Returns the inverse hyperbolic sine of X. | numeric | numeric
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). | numeric | numeric
atan2(X,Y) | Returns the arctangent of X. Result is in radians. | numeric,numeric | numeric
atanh(X) | Returns the inverse hyperbolic tangent of X. | numeric | numeric
cos(X) | Returns the cosine of X (an angle in radians) | numeric | numeric
cosh(X) | Hyperbolic cosine of X. | numeric | numeric
cot(X) | Returns the cotangent of X (an angle in radians) | numeric | numeric
coth(X) | Hyperbolic cotangent of X. | numeric | numeric
hypot(X,Y) | Returns length of hypotenuse of triangle with base X and height Y | numeric, numeric | numeric
sin(X) | Returns the sine of the argument (an angle in radians) | numeric | numeric
sinh(X) | Hyperbolic sine of X. | numeric | numeric
tan(X) | Returns the tan of the argument (an angle in radians) | numeric | numeric
tanh(X) | Hyperbolic tangent of X. | numeric | numeric

In: Contents >> Working with equations >> 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.

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. 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).

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.

Options

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.

X axis resolution

Clicking on the ► button doubles the number of vertical lines in the graph pad area; clicking on the ◄ 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.

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. 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 zero or more indices, which are used to extract a particular item of data from the table. If there is no index, the row number is used instead.

For example, a series of samples of soil quality might have two indices, an x- and a y-coordinate. The data column 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.

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.

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 | Y | Height | Width
1 | 1 | 12.3 | 1.3
2 | 1 | 12.7 | 1.2
3 | 1 | 13.1 | 0.9
1 | 2 | 11.8 | 1.5
2 | 2 | 12.3 | 1.4
3 | 2 | 11.7 | 0.9
1 | 3 | 13.5 | 1.0
2 | 3 | 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 equations


Working with equations : Table dialogue

Table dialogue

The table dialogue window is used to create a table from data stored in a file. The table dialogue is invoked from two different places. It is used by the equation dialogue box to create a table for use by the table function. It is also used by the file parameter dialogue box to create a table for a fixed parameter.

Each table has zero or more indices, which are used to extract a particular item of data from the table in your model. If there is no index, the row number is used instead.

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”.

After selecting a CSV file, 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.

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 | Y | Height | Width
1 | 1 | 12.3 | 1.3
2 | 1 | 12.7 | 1.2
3 | 1 | 13.1 | 0.9
1 | 2 | 11.8 | 1.5
2 | 2 | 12.3 | 1.4
3 | 2 | 11.7 | 0.9
1 | 3 | 13.5 | 1.0
2 | 3 | 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 equations


Working with equations : User-supplied functions

User-supplied functions

There are two different mechanisms for users to supply functions for use in expressions. One is user-defined macros, which provide a short-hand for long or complex expressions that would otherwise have to be used repeatedly in expressions. The other is user-defined external procedures, written in a programming language such as Tcl or C++.

In: Contents >> Working with equations


Working with equations : External 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. This allows users to 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. This directory is located within the Simile program files tree. The format of the 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, so it must start with a lowercase letter.
  • X1, X2 … Xn are a series of one or more variable identifiers. These have the format of Prolog variables, so they must start with uppercase letters. These arguments to the function are replaced when the function is used, by the symbolic names of the influencing variables. 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, with each complete part being separated from the next by a comma.

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 macros.pl file distributed with Simile contains a number of examples of function definitions. These do 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].

  • 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.

  • newton_raphson(Lo_start, Hi_start, Poly) takes two starting values, and a value that is derived from its result by other variables in the model. It returns a new value on each time step, attempting by linear extrapolation from the last two values to return a value for which Poly will be zero.

  • true() and false(): return Booleans for true and false respectively.

Comment lines, starting with a %, can be included in this file, although standard multi-line comments bounded by /*...*/ cannot 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


Working with equations : External procedures

External procedural functions

To include user-defined external procedures, there are three files:

  1. defns.pl -- a list of function declarations in the Prolog form

    function(Name, ResultType, ArgTypes).

    where “Name” is the name of the function, “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.

  2. procs.cpp -- 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.

  3. 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.

In: Contents >> Working with equations


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 [image] select mode, or by using the “Properties” command of the “Model” menu, when the submodel is opened in a separate window.

  • Submodel properties dialogue

Operations on submodels

The following tools are used to perform operations on submodels.

Opening a new window for a submodel

Saving a submodel

Loading a saved submodel as a stand-alone model

Loading a saved stand-alone model as a submodel

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

  • Population (variable membership) submodels offer control over the number of instances using special model elements

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.

  • Conditional submodels use Boolean logic to determine the existence or otherwise of parts of the model.

  • Iterative submodels contain components that are evaluated repeatedly until a finishing condition is met.

  • Satellite submodels are used to extract a subset of values from a population submodel according to a given condition.

  • Association submodels represent the properties of an association between two other submodels.

  • Externally-supplied procedures, with array arguments and results and their own internal state, can be embodied by submodels.

In: Contents


Working with submodels : Submodel properties dialogue

Submodel properties dialogue

The submodel properties window enables you to set the properties of a particular submodel. Invoke the dialogue box by double-clicking in any blank area of the submodel, or by selecting the Model…Properties menu item. The advanced properties are hidden by default. To display advanced properties, click the “More” button. To hide the advanced properties again, click the “Less” button. If any of the advanced properties do not have their default value, the advanced properties will be displayed initially.

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 two 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, [image] reproduction, [image] immigration and [image] extermination.

Background shade

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. 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 image will be cropped to fit.

Comments

The Comments box enables you to type in free-form comments about the submodel. Use this to document the date of creation, author, main features, etc.

Calculation

  • Build submodel in separate dll
    This enables you to specify that this submodel (and its children, if any) are built in a separate dll. This is not always possible, but if it is possible, it may speed up the build process on subsequent occasions, as it may not be necessary to re-build every dll. See build submodel separately for information on the circumstances in which this is possible.
  • Use own code
    Allows an external procedure to set values in the submodel. See Using externally-supplied procedures for details.
  • 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.

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.

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 : 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. Since 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.

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 two special cases. “Time step #-1” and “Time step #0” have special meanings. The former denotes that the submodel should be updated only when the model is built. The latter denotes that the submodel should be updated only when the model is built or when the reset button on the Run Control is used. In neither case 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 : Build separately

Build submodel separately

Building submodels in separate libraries is an advanced topic. It can be useful to reduce the time taken to build large models when only local changes are being made, but it is only impossible in specific circumstances, and in these cases, model behaviour can be unpredictable.

When a model is built, it is first translated into C++ source code, and then the source code is compiled (using the GCC or Microsoft Visual C compilers) into a dynamic link library (*.dll) or shared object (*.so) file. A single library is prepared for the whole model, so if any change (however small) is made to any part of the model, the whole library must be re-compiled. This can take a long time. In order to avoid this, it is possible to specify that one or more submodels should be compiled into separate libraries. If nothing in the submodel is changed, it is not necessary to re-compile the library. Breaking a large model into several smaller libraries in this way can substantially reduce build times when a localised change is made, affecting only one of the libraries.

In general any submodel can be flagged to build separately, but there are a number of cases in which it is not possible. These are if it:

  • uses a different time step than one used in the top level model
  • uses ghosts from other submodels or the top level model
  • is part of an association

In addition to the above prohibitions, there is a more complex class of restriction. If one separately-built submodel relies on another separately-built submodel for the calculation of some of its elements, whilst the other also relies on the first for the calculation of the same elements, there can be conflicts. In preparing the C++ code, these cases are handled appropriately wherever possible, but the results cannot be guaranteed. If you suspect a model is behaving strangely in these circumstances, it would be best to build the model as a single library.

In: Contents >> Working with submodels >> Submodel properties


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 [image] 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 that changing the size of the new window 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 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 [image] 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 : Loading a saved submodel as a stand-alone model

Loading a saved submodel as a stand-alone model

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 : Importing a submodel from file

Loading a saved stand-alone 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 [image] 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.

In: Contents >> Working with submodels


Working with submodels : Multiple-instance submodels : Fixed dimensions

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 [image] 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.

  2. 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).

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.

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: we will be adding other distributions, e.g. Normal, in the future (and it is possible to engineer these yourselves).

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

You could use the sketch graph function 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.

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 : 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.

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.

  2. Open up the submodel properties dialogue by selecting the [image] 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.

  3. 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.

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 #LJFunctions#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 : 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 [image] 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

<< Previous Step 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).

<< Previous Step 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

<< Previous Step 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.

<< Previous Step 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

<< Previous Step Next Step >>

We clear the submodel, by selecting File: New from the submodel window’s menu.

<< Previous Step 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.

<< Previous Step 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

<< Previous Step

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!

<< Previous Step

In: Contents >> Working with submodels >> Plug-and-play modularity


Working with submodels : Conditional submodels

Conditional submodels

A conditional submodel specifies the conditions under which a submodel, or an instance of a fixed-membership multiple-instance submodel, exists. By “exist” we mean that Simile evaluates the expressions in the submodel. It does this by evaluating a Boolean expression in a condition symbol placed inside the submodel.

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.

In: Contents >> Working with submodels


Working with submodels : Satellite submodels

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.

However, if you use a population submodel to model the trees, then you have a problem. A population submodel exports a list of values rather than an array: it has to do this, because the number of values can change dynamically, rather than being fixed. Currently, Simile does not have a list-processing language corresponding to the array-processing language as above. All you can do with a list is to sum it, count the number of elements in it, or find it minimum or maximum value.

The satellite submodel is a mechanism for dealing with problems like this. 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:

  • please see the “Introduction to the association submodel concept”.

To create an association submodel:

  1. Create an unique identifying variable(s) in the associated submodels. The variable(s) allow unique identification of an instance. This is easy to specify, using a variable(s) taking the value of the submodel index (or indices).
  2. Create a single instance submodel which will be the association submodel itself, containing variables that specify the association.
  3. Create one or more multiple instance submodels that will be associated, each playing a role in the association.
  4. Draw role arrows from the associated submodels to the association submodel. The role arrows should be given meaningful names indicating the role the instances of the source 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 associated submodels.
  6. Include in the association submodel all the variables that belong equally to all role-playing 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:

  • please see the “Worked example: water flow between soil layers”.

Note that there are some advanced aspects of optimising the performance of models using associations For more information please see:

  • Role arrow properties dialogue box
  • One-sided relationship enumeration

In: Contents >> Working with submodels


Working with submodels : Introduction to association submodels

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.

How do I add an association submodel?

Association submodel name Verb Owns

Role arrow name Noun Owner, Owned

Submodel name Noun Farmer, Field

but can use “me” and “other” for the role arrow names when symmetry means that there aren’t two distinct nouns.

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.

1. 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.

1. 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.

2. 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.

3. 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.

4. 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.

5. We enter the actual condition for the existence of the relationship into the condition symbol. The expression for this is:
above? = layer_number == layer_number_0 - 1
(i.e. we are checking that the variable with the local name “layer_number” is equal to the value of the variable with the local name of “layer_number_0”, 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.

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” in the equation dialogue box, while the second has the local name “outflow_0”. In this particular model, we want it to be from the upper layer, so we select the variable

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” and “interflow_0”; and
  • each of these is a list (i.e. {interflow} and {interflow_0}), 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_0}.

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 from a layer to any layer below it, then the list could contain several values.

Anyway, the fact that it’s in a list means that we have to extract a single value by summing up the elements of this list. So the actual equation we use for inflow is:

inflow = sum{interflow_0})

In: Contents >> Working with submodels >> Association submodels


Working with submodels : Role properties dialogue

Role properties dialogue

There is an advanced property of role arrows that is set using this dialogue box. Note that it is not normally necessary or desirable to set this property. It allows 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 only 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 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. 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 to us about your model.

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.

Comments

Free-form comments can be entered in this text box, and are stored with the model.

In: Contents >> Working with submodels >> Association submodels


Working with submodels : One-sided relationship enumeration

One-sided relationship enumeration

One-sided relationship enumeration is a feature 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.

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).

Conventionally 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.

So far, it is important to emphasise that we have followed the procedure that has been standard in Simile for many years. The final step, yet to be presented, however, vastly increases the efficiency of the generated code..

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( index(1) is {neighbours_ids_border} )

In this expression, neighbours_ids is the list of neighbours, and index(1) is the index of the pixel that is potentially in the border. The condition is true (and the relationship therefore exists) for the pixel in the border, if any of the elements of the list of the neighbour_ids equates to the index of the pixel.

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. 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 v4.0 use. The example can be used as a starting-point for most work on rasters, grid squares and so on.

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.

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 input<n>, 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 output<n>, 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 are passed by reference – 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 – 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 – these are all specified by the model contents.

  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


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. It does this in response to the Model…Run command.

  • Running models

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.

  • Single-window Model Run Environment

  • Multiple-window Model Run Environment

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.

  • Working with helpers

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 PEST

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.

  • Working with external data

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.

  • Scripting

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 behind the scenes. 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.

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 C, is included in the Simile distribution. Microsoft Visual C++ is also supported.

In: Contents >> 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 two most commonly used helpers can be selected using these buttons on the tool bar:

the plotter; and

the data table;

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 [image] 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 [image] open button on the tool bar.
  • A [image] new configuration can be selected, to remove all the currently displayed helpers.

Arranging pages, and panes

Add notebook

Add notebook page

Divide pane vertically or horizontally

Adding helpers

Add plotter

Add table

Add sliders

Add other helper

Manipulating layout

Copy display to clipboard

Cut display to clipboard

Paste display from clipboard

Delete display or helper

Saving and restoring configurations

New configuration

Open configuration

Save configuration

In: Contents >> Running models


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. 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 : 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 : 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 [image] play button will begin execution at the current time for a number of time steps set using “Execute for”.

  • the [image] stop button will stop the simulation (if one is running) and set the current time to zero.

  • the [image] 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
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.

The other fields on this tab are:

  • Execute for
    This setting controls the number of time units for which the model is run.

  • 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 of the time unit. The display interval can be the same as, or longer, than the time step. You should choose a value longer than the time step if you have decided to use a very small time step for doing the calculations, but the displayed variables actually change fairly slowly. In this case, it will slow the calculation down unnecessarily to update the display after each time step: you only need to update the display after several time steps have elapsed.

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.

  • 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.

  • 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.
    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. The value entered in the Time step field is now the maximum length of a time step.

  • 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.

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 time step 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 size 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.


Running models : Sliders

Sliders for Variable Parameters

This window contains one slider (or switch) for each variable marked as being an “Variable parameter” in the equation dialogue box for that variable. 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 is given, then the slider is positioned at the mid-way point.

The sliders are positioned by the user to set the value at the start of the simulation. Once the simulation is running, the sliders can be moved to provide dynamic control over the variable. The model is updated with the new value in the next time step. Sliders are grouped by submodel, if possible.

To add a display of sliders, use the [image] sliders toolbar button, or select “Slider control” from the Standard tools submenu on the “Add” menu. You can add all the variable parameters in the model to the same display, using the sliders toolbar button in the display, or you can add sliders individually, using the [image] add button.

Sliders for Boolean variables are displayed as check-boxes, and do not have minimum and maximum values.

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.

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.

  • Using the Plotter helper

  • Using the Data table helper

  • Using other helpers

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.

Clearing the display

To remove all the plotted data, click on the [image] button.

Selecting elements to plot

One or more elements can be added to the graph.

  • to add an element, click on the [image] 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 [image] button. An instruction is then posted to click on the element to be removed, in the legend of the graph.

Range selection

The range displayed on each axis of the graph can be controlled by simple dragging movements. The range is a function of both how large the difference between maximum and minimum is, and what the minimum is. Accordingly, 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 : 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. 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 [image] button. This preserves the column headings, but removes all the rows of data.

Arranging the layout

The layout of the table is controlled using the Table properties dialogue box. 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. It is also possible to exclude time from the table, tabulating current values only.

Choosing column headings

The elements to be tabulated are selected as column headings. The procedure for choosing column headings is as follows:

  • to add a column(s), click on the [image] 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 a column(s), click on the [image] 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.

Altering precision

By default, all variables are tabulated with four decimal places of precision. This can be increased or decreased as desired, but only before each run of the simulation. The procedure for changing precision is as follows:

  • to increase the precision to which the numbers are displayed, click on the [image] button. This increases the precision by one order of magnitude.

  • to decrease the precision to which the numbers are displayed, click on the [image] button. This decreases the precision by one order of magnitude.

Standard scientific notation is used automatically where appropriate. This uses the same number of significant figure as the decimal display.

In: Contents >> Running models >> Working with helpers


Running models : Working with visualisation tools : Save and restore tool configuration

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.

  • in the single-window run time environment, save configurations using the “Save configuration” item on the “File” menu; or
  • in the multiple-windows run time environment, save configurations using the “Save” item in the “IOTools” menu.

Load configuration

The procedure for loading configurations differs, depending on whether the single or multiple-window run time environment is selected.

  • in the single-window run time environment, load configurations using the “Load configuration” item on the “File” menu; or
  • in the multiple-windows run time environment, load configurations using the “Load” item in the “IOTools” menu.

In: Contents >> Running models >> Working with helpers


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.

  • in the single-window run time environment, add helpers using the “Add” menu; or
  • in the multiple-windows run time environment, add helpers using the “Add tool” submenu in the “IOTools” menu.

The other helpers included in the standard installation of Simile are:

Plot value against time [image] Lollipop diagram [image] Spatial grid display [image] Polygon diagram (map) [image] 3d viewer [image] Time profiles

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.

One other tool, that is rather different from the others, is used to initialise the pseudo-random number generator:

Initialise pseudo-random number generator

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 : Plot value against time

Plot value against time helper

This is the classic time-plot 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 : Lollipop diagram

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, 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.

The screen shot shows the default view of the trees. Clicking on the “aboveBelow” button swaps to an aerial view from directly above the trees. Some trees may be shading others from view, in which case click the “Swap Z Order” button to bring the hidden trees to the top.

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 : Grid display

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. Each instance of the submodel is given a different x- and y-coordinate, often using the index function. The spatial grid display uses only the x-coordinates to determine the number of columns: the number of rows is determined automatically from the number of columns and the number of instances that exist of the submodel.

The element to be used to colour the grid should be given a maximum and minimum value in the equation dialogue box. These will be used to calculate the corresponding colour changes. The colours corresponding the high, middle and low values can be selected using the respective buttons. The intermediate colours are calculated as shades of these. The window is resizable, but it is necessary to use the zoom in and out buttons to alter the size of the grid squares.

A three-dimensional view of a rectangular grid is also possible using the 3d viewer.

In: Contents >> Running models >> Working with helpers


Running models : Working with visualisation tools : 3d viewer

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. Please see the “Examples” page of Simulistics’ web site for examples of models using the 3d viewer.

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


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 : Initialise pseudo-random number generator

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 [image] 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, …

In: Contents >> Running models >> Working with helpers


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

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.

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

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, a copy of which has been placed on Simulistics' website for ease of reference. 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. The '-' button allows you to remove a value.

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. The only difference is that when loading measurement data for PEST, you choose (via a checkbox) whether it is a single value (for each instance) which will be compared at the end of the run, or whether it is a time series to be compared with the model value at times throughout the run.

When you have loaded your measurement data you can save references to it in a scenario file, as you would for parameter data.

In: Contents >> Running models >> 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.

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

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

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 file which contains the values. This other file 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. Alternatively it can be an image file, with each pixel standing for a data value according to its colour, or any of a range of other raw data formats.

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.

Overview of the scenario file mechanism

Using the scenario file mechanism

Modifying scenario values during a session

Working with time series

Keeping raw data in the scenario file

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.

Simile provides a variety of mechanisms for providing these values:

Entered into the Equation field of the equation dialogue

This is the standard way of doing things, and is the method illustrated in Simile introductory tutorials.

Generated by sampling from some random distribution

For example, you might use the rand_var function, with arguments of 10 and 20, to get randomly-generated temperature values in the range of 10 to 20 degrees. (It is a moot point as to whether you consider that this technique comes under the heading of providing input data: whatever your view, it certainly does the same job as if the data had been provided from a data file.)

Entered into the sketch graph function in an equation

This could be used, for example, to provide a set of observed temperature records over time:

graph(time())

or different values for some parameter for different instances of a multiple-instance submodel:

graph(index(1)).

See the help information on the graph function for more details.

Entered into the table function in an equation

This enables you to pick up tabulated values from a .csv data file. It has close similarities to the mechanism described in this section, but it differs in one important respect. When you use the table function to load tabulated data values from a file, and then subsequently save the model, the values are saved along with the model. This is fine for small data sets, but can greatly increase the size of models using large amounts of data. In contrast, the File Parameter mechanism does not save loaded data with the model. See the help information on the table function for more details.

Set using a slider

If you declare a variable to be an “Input parameter” in the equation dialogue, then Simile automatically generates a window containing a slider for each variable so declared (or a set of sliders if the variable has multiple instances). You can then move the slider to set the value of the variable - and indeed to change it during the course of a simulation run.

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 comma-separated value (CSV) file containing tabulated data. This means that a single (potentially very large) CSV file 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 : Using the scenario file mechanism

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

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 “File Parameter”.
  3. Close the equation dialogue window.

Note that the variable now appears in speckled form, 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 in speckled form, 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 in speckled form, 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 in speckled form, 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. Browse through your file system to find the .csv file containing the data values.
  3. Click on the OK button.
    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 File 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 in speckled form, 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. Browse through your file system to find the .csv file containing the data values.
  3. Click on the OK button.
    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. Browse through your file system to find the .csv file containing the data values.

  3. Click on the OK button.
    You will now see a window listing the columns in the table, by the label associated with each column.

  4. 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.

  5. Repeat this action for the inner index. In the example above, this column header is IndH.

  6. Double-click on the label corresponding to the column of values you wish to assign to the variable. In the example, it is Val.

  7. Click on the OK button.

  8. Click Save if you wish to save this setting (along with any others), and specify a file to save it in.

  9. 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: 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 in a Simile session. So what do you do if you then want to modify scenario values prior to subsequent runs during the same session?

Simple: select the option Parameters... under the I/O tools menu. 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.

In: Contents >> Working with external data


Working with external data: Working with time series

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.
  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


Working with external data: Raw data in scenario file

Saving raw data in scenario files

Normally, when dealing with scenarios containing large numbers of data values, a modeller would create a scenario file with individual values saved literally, and array values saved by reference to whatever files they were originally loaded from. Sometimes, though, this is not the easiest approach, having two main problems:

  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 as an alternative, it is possible to have all the data saved in the scenario file, in a format that converts easily to the internal representation of numbers. For this to happen, when you load an array using any tab in the Table Data dialogue, you check the box labelled 'Include values in scenario file' before hitting OK. When the scenario file is subsequently saved (see Using the scenario file mechanism), the values will be saved along with it, and the files from which they were originally loaded will not be required again when the scenario file is reloaded. It will also reload very quickly.

In: Contents >> Working with external data


Scripting

Simile scripting language

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/).

  • Command reference
  • Example scripts
  • From other interpreters

In: Contents


Scripting : Command Reference

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.)

  • ModelWindow
  • RunControl
  • TableHelper

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 arguement, 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. smPath (submodel path) can be omitted if the parameter variables 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 Run

Makes a loaded model runable.

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).

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 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 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 MergeParams filepath ?smPath?

File parameters may be read in from CSV files. Once a model is made runable (by calling simileScript::ModelWindow Run) then in order to run a model with file parameters, use the command above before building the model. 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

similescript::TableHelper objectName model_window_object window_title

For example:

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.

In: Contents >> Scripting


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 <Simile installation directory>/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


Working with files

Opening and saving models

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.

The "Close" command will close your model (prompting you to save it, if it has changed) and also close the current window unless it is the last window open. 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 will open the model in a new Simile 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 [image] "Go to model window" and [image] "Go to run control" toolbar buttons to move back and forth between the pair.

Model file formats

  • Model file format

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

  • Model declarations

Prolog-format model declarations
  • C++ program & executables

C++ source code and compiled libraries
  • PostScript graphics

PostScript-format model diagram

Reporting problems

  • 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 model declarations

Export model declarations

To save the model in a Prolog-format text file, use the "Export" command on the "File" menu, and select the "Model declarations" item. The default file extension is *.pl (Prolog), but you can enter a file name with a *.sml extension if you wish. This format contains all the information necessary to define the model, and it can be used instead of the usual format. The advantage is that the files are much smaller than usual, and, if you are familiar with the Prolog language, you can edit the file yourself or write programs to reason with it. This is the file format used in versions of Simile prior to v3.0.

You can open models saved in this format, using the usual “Open” command on the “File” menu.

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 PostScript 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. In Microsoft Windows, a separate Print command is available, to use any Windows-compatible printer.

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 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 an arbitrary index number.

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. Invoke the context menu for the Desktop (by right-clicking anywhere on the top-level submodel).
  2. Select Properties...
  3. Click on “More” in the Properties dialogue window to view the advanced options.
  4. 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.
  5. Click on the word “fruit” now entered into the Enumerated types list, to highlight it.
  6. Type “apples” into the same edit field, and click on “Add member”.
  7. 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.
  8. To see what the list of values is for “fruit”, hover over the name and observe the pop-up reminder.
  9. You can now (or at some later stage) define additional enumerated types in the same way.

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.

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

Using files

Instead of typing the names into the list of members, when creating a new enumerated type, it is easy to read the names from a file. Create the type, e.g. “fruit” as above, and then click the “Get from file” button. This will open the table dialogue box. Use this to create an array of the names from a column in the CSV file.

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.


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


Evaluation Edition limits

Upgrade to a full licence

This Evaluation Edition of Simile has been specially developed for introducing new users to this award-winning software. It is limited to saving models of no more than 25 functions. You can build and run larger models, but you cannot save them. We hope this introduction to Simile will inspire you to upgrade to the Standard Edition. To upgrade, please visit the web site of Simulistics, the developers of Simile.

www.simulistics.com


Running models : Working with visualisation tools : Polygon diagram

Polygon diagram (map) helper

The polygon diagram colours a collection of polygons according to the value of a specified variable. It is typically implemented using a multiple-instance fixed membership submodel. Each instance of the submodel is given a different index, often using the index function.

The co-ordinates of the polygon outline can be sourced from the model itself or from a dxf file. If from the model the multi-instance submodel must include an array of x co-ordinates and a seperate array of y co-ordinates to describe the outline. In the example model Spatial diffsion over a hexagonal grid the multi-instance submodel "Hexagon" contains the multi-instance submodel "borders" which provides the co-ordinates for the polygon borders. Of course the polygons can be irregular such as the outlines of countries. The polgygons would then represent a multi-instance submodel which in turn represented countries of the world.

The colours corresponding the high, middle and low values can be selected using the properties dialogue box. The intermediate colours are calculated as shades of these. The window is resizable, but it is necessary to use the zoom in and out buttons to alter the size of the map.

In: Contents >> Running models >> Working with helpers


Running models : Working with visualisation tools : Save and restore model state

Standard helpers: Save/restore state

The Save/restore state helper enables you to capture the values for all variables in a model at anytime during the course of a simulation and dump them into a file. This file can be used on a subsequent occasion to assign values to all the variables (including compartments, flows, etc) in the model. You can thus carry a simulation on from the point where you left off previously: maybe it was taking a long time and you needed to interrupt it to go home; or maybe you want the initial state for a model to be some equilibrium state obtained by running the model until equilibrium is achieved.

The generated file is a text file, which simply gives the full path name for all the variables in the model (that is, the variable's label preceded by the names of all the submodels that contain it), followed by the value or values for that variable (plural values if the variable is inside one or more multiple-instance submodels).

You may find it useful to generate this file simply to help in understanding a complex model, since, working alongside the model diagram and equations, it enables you to follow chains of calculations. So if, for example, one variable has an unexpectedly large value, you can check out all the variables used to calculate it.

Since the generated file is a text file, you can also edit it. This will in fact have no effect for intermediate variables (there values are calculated from their influencing variables), but you might find it a useful way to adjust parameter values or re-set compartment values.

Example

This toy model has a fixed-membership submodel with five instances, along with a compartment, flow, parameter and output variable.

Saving its state produces a file as follows:

/Desktop/flow1=3

/Desktop/comp1=2

/Desktop/var1=1

/Desktop/var2=8

/Desktop/submodel1/var3=1 0.958 2 0.607 3 0.788 4 0.422 5 0.818

It's all pretty obvious, except to note that the values for the variable inside the submodel are in pairs: the first value gives the instance number (1, 2, 3...), while the second gives the value for that instance. (The instance numbers are negative for population submodels.)

In: Contents >> Running models >> Working with helpers


Working with submodels : Adding a submodel to the model diagram

Adding a submodel to the model diagram

Case 1: constructing an empty submodel

  1. Click on the [image] submodel symbol on the toolbar.
  2. Move the mouse into a blank area of the screen.
  3. Drag the mouse diagonally (the submodel envelope will drag with you) until you have enclosed the area you wish to contain the submodel.
  4. Release the mouse button.
  5. You can then insert model elements in the normal way into this space; or you can load a Simile model in from file.

Case 2: enclosing existing submodel elements in a submodel

  1. Ensure that the elements you wish to enclose in a submodel envelope are arranged in a group, so that it is possible to enclose them in a rectangle without also enclosing model elements that you do not wish to be part of the submodel.
  2. Click on the submodel symbol in the Simile toolbar.
  3. Move the mouse into a blank area of the screen.
  4. Drag the mouse diagonally (the submodel envelope will drag with you) until you have enclosed the elements you wish to include in the submodel.
  5. Release the mouse button.

In: Contents >> Working with submodels


Working with submodels : Iterative submodels

Iterative submodels

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. In the past, Simile would reject this loop at build time, but setting a new 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.

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.

That’s all there is to it, except that it’s worth noting what to do if the iteration does not converge. It is necessary to use the new “Abort Execution” command in the “Model” menu of the model diagram window (i.e. NOT in the run control window).

In: Contents >> Working with submodels