This chapter describes the submodel concept as used in Simile. This construct is a key feature of Simile.
A submodel in Simile is a way of bundling up a number of model elements, including other submodels. This is done by either drawing a submodel envelope around a number of elements in the model diagram, or by creating an empty submodel and inserting model elements into it. However, the reasons for wanting to do this are many and varied, and it is important to appreciate that the submodel construct can be used for a range of modelling needs. These are normally considered as being pretty separate, so it may come as some surprise to see that the same model-diagram construct can be used for these different purposes. However, there are considerable benefits by using a single method, both in terms of what you need to learn, and in terms of the machinery that lies inside Simile. This section overviews the different uses of the submodel construct, and the different types of submodel that you can have.
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.
Once part of a model is made into a submodel, you can open up a separate window for it (by double-clicking on its boundary). 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.
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.
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 Simile the information about this interfacing to be stored in a file (an interface spec file). When you next load one of the submodels from a file, you simply refer to the interface spec file, and all the influence links are made in one quick operation.
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 (in 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 (rather 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:
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.
When a model is implemented in a conventional programming language, large chunks of the program can be enclosed inside an if...endif block: i.e. whether it is actually evaluated depends on some condition. This programming device may be applied to several different purposes:
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.
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:
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:
When you pass information out of fixed-membership multiple-instance submodel, it appears as an array with a fixed number of elements. You can extract the value for any one element using the element([array],index) function, and the element you extract will correspond to the instance in the fixed-membership submodel. This makes it possible to select values for one variable on the basis of the value for some other variable.
However, when you pass information out of a population submodel or an association submodel, all you get is a list of values: each value is not tagged with the index (instance number) of the submodel instance that produced it. Thus, if you had a population submodel for a population of rabbits, and you wanted to find the total weight of all rabbits over two years in age, you couldn't do it simply by looking at a list or lists coming out of the submodel.
The satellite submodel is a way of making this possible. It is a submodel with a single role arrow pointing at it (in contrast with an association submodel, which has two role arrows). At most there will be one instance of this submodel for every instance of the parent submodel (the one the role arrow comes from). But, as with a conditional or an association submodel, you can place a condition model element (the question mark symbol) inside it, and this can limit the number of instances to be some subset of the maximum number possible. The condition you insert is then specified to restrict the subset to that which you require.
By default, all parts of your model tick at the same rate, as specified by the Update every... value in the run control dialogue window. However, you will sometimes want to get parts of the model updated less (or more) frequently than others. For example, you may have a model containing both trees and a crop. The crop you want to grow on a weekly basis, so you can capture its response to rainfall patterns, pest outbreaks etc. The trees grow slowly, and there is no point at all in calculating tiny increments on a week-by-week basis. Conversely, your model may include a fire spread submodel, which is triggered only very occasionally but then needs to simulate the spread of fire at very short time steps. In order to specify this, you need to ensure that the component of the model with a separate time base is in a separate submodel. You then specify the time base for this submodel (and, by default, any inside it) in the submodel properties box. When you come to run the model, Simile then realises that there is more than one time base for the model, and adds one or more extra Update every... in the run control dialogue window. The user of the model then needs to specify each one separately, in terms of the model's unit of time. In the above example, the value 1 (year) and 0.02 (years, equals roughly 1 week) could be specified for the two Update every... values.