RTS3 implementation
Overview of the design
The HOOD root diagram is composed of a few higher-level objects, which may be further decomposed.
Root diagram of the RTS3 system. Only the main links are shown. The configuration file RTS3-XP.CFG is an external (txt) file, placed here inside the root object for convenience.
The procedure Read_Config_File in Modify_Parameters package reads the text file RTS3-XP.CFG. The values in this file are first read in temporary (Auxiliary) variables. The Modify_Parameters package is generic; it is instantiated for several JEWL windows (http://www.it.bton.ac.uk/staff/je/jewl/). These windows act on the auxiliary variables, which will be tansformed into constants by the Transform_Config_File procedure in the Users_Parameters package. When the user clicks the Run > Start simulation tab control is transferred to the Execute_RTS3 package.
The Execute_RTS3 object
A Simulation_Instruments object, containing the global clock and several counters, harnesses the simulation. The status of the simulation can be known or modified (for example aborted) with the object Simulation_Status. The creatures are displayed on the screen with a Computer_Interface object, using the AdaGraph library of Jerry van Dijk (http://users.ncrvnet.nl/gmvdijk/adagraph.html)†. The Computer_Interface object is also responsible of the user interactions and of the recovery of the results.
The main objects are the Salps and Vibilia packages, implementing the two lineages of self-reproducing creatures, and the Space and Salp_Food packages, which set their environment.
The Space object
There are several ways to implement the space in a computer simulation. Each has advantages and limitations, as well as profound implications. For RTS3-XP, I made the following choices:
• The space is a
passive object, able to lodge creatures, food or inanimate things.
• It is composed of a collection of locations, indexed by their Cartesian
coordinates.
• Each location is either empty, or contains only one creature (zooid,
Vibilia, or a zooid parasited by a Vibilia), or an inanimate
obstacle.
Besides the creature it may contain, each location may include an amount of salp food, and have physical properties: light intensity, temperature, etc.
HOOD diagram of the Space object:
HOOD diagram of the Management object, a child package of Space (ROER, RWER: Read Only, Read Write Execution Request; The 'A' in the upper left corner means that this is an 'active' object):
In the current version of RTS3-XP, the space is a bi-dimensional array of Locations (a location is a cell which may be empty or occupied by a creature during 1 "day" of simulation). There is no conceptual problem to extend this array to 3 dimensions, this is mainly a computational problem; the graphical display would need to use fast primitives (OpenGL?). For the present time, I preferred to solve the real-time problems first. I will refer to the bi-dimensional array as the grid.
The grid
represents a rectangular area of the ocean, viewed from above. Because the
computer display is not infinite, this array have bounded physical dimensions.
Even if a large memory is available, the constraint of displaying each creature
on the video monitor oblige to use a minimum number of pixels to make them
conspicuous and different enough of each other (chains should at least be
distinguishable from oozooids).
The following trade-off was reached: the array dimensions are set to 316 x 224 locations; these can be displayed with a 1280 x 1024 resolution, using 4 x 4 pixel areas for each creature. This is still practicable on a 640 x 480 monitor, using smaller 2 x 2 patches. Larger grid sizes would lead to too high memory requirements - with 316 x 224 locations, the exponential increase of the salp population in 120 "days" of simulation can only be shown safely if there are 256 Mb of memory available.
A toroidal grid, commonly found in many spatial simulations, is not used because it would make visualization difficult to follow. Instead, the grid has reflective boundaries. This has no consequences on the model, because 316 x 224 is large enough to allow the salp population to develop without reaching the grid limits in 120 "days" - a duration sufficient to produce a large number of salps. However, the small size of the salp display codes has a drawback: 2 x 2 or even 4 x 4 pixels areas with different colors do not permit to easily distiguish the numerous states of the creatures. It is possible to recover a trace of the zooid states at a given time, but only when the simulation is finished. Because the zooid trajectories do not repeat identically from one run to the next, this is a problem during program development and debugging.
This problem was overcome by having the option to set smaller boundaries (158 x 69 locations) and to represent each creature with a character. In this mode, called CHAR mode, all states may be represented with a different character/color combination. This is very useful to see exactly what happened during the simulation. However, to get ecological results, one has to turn to the PIX mode, where the limits are set far enough to rule out the case of zooids bouncing on boundaries.
Each (Y, X)
location contains the following elements:
- A Code (either an Empty code, or the code corresponding to the state of the
creature occupying the location).
- An Identifier (either Null_Id or the Task_Id of the creature).
- 0.0 or more food units.
Each operation on the grid is effected via a "protected object", guaranteeing exclusive access to the creatures (no simultaneous updating possible).
Time
The global time (i.e. the time of the simulation) is maintained by a periodic task in the Simulation_Clock package. This task is started at the beginning of the simulation, with a period of Internal_Pace milliseconds (the Ada.Real-Time clock is used). The task is exited after Simulation_Duration ms or it may be interrupted from the keyboard by the user. This global clock DOES NOT drive the zooids. Each creature (zooid or Vibilia) has its own independent clock, with Internal_Pace periodicity, which starting at its birth and ending at its complete decomposition. The creatures poll the global clock to know if the simulation duration is elapsed.
Time units
The modeler reasons in "mean days". The computer translates this in milliseconds of CPU, using the equivalence: 1 (mean) day = Internal_Pace milliseconds. For input/output, variables of type Duration (a fixed-point type in seconds) are used, while amounts of CPU time are expressed with the type Ada.Real_Time.Time_Span (in milliseconds). Durations set in "days" in RTS3-XP.CFG are internally converted to Internal_Pace milliseconds.
The artificial creatures
Artificial salps and Vibilia have a structure and a behavior. Their structure is reproduced from one generation to the next. In Ada 95 the structure is conveniently implemented with a record, the fields of which contain states (values susceptible to change during the life). To model both kinds of zooids, oozooids and chains, the base record type is augmented with a specific reproductive field. The behavior of the autonomous creatures is naturally provided by an Ada task, linked by an access value to a field, Action, of the record.
Structure of Oozooid and Chain records. In this example, each oozooid gives 2 generations of chains, each chain being composed of 3 aggregates (or blastozooids).
A creature reproduces by allocating a new record. The attached task is activated at birth and starts its timed loop triggering the state changes (this corresponds to the biological clock of the organism). Each creature has thus an age; one of the fields of the record contains its birth date (read on the global simulation clock), another one its death date.
A lineage of creatures (a population) is implemented as a linked list of records. The child is connected to its parent by assigning the pointer returned by the record allocation to the reproductive field of its parent. This reproductive field is different in oozooids and chains. Oozooids may spawn 2 or 3 chain generations, therefore the oozooid reproductive field is an array indexed by the generation number. In chains, the asexual multiplication gives birth to several new oozooids, and the reproductive field is an array of access values to oozooid records. Note that the number of these oozooids depends on the amount of reserves accumulated during the life of the parent chain, so that some of the array indices may have null values.
The
records of the linked list are not deallocated when the zooids die. When the
simulation is over, this allows to recursively iterate through the list,
branching according to the reproductive field encountered. It is thus possible
to recover the final state (death date, etc.) of each traversed zooid.
The lineage of zooids starting from the First_Oozooid pointer
The representation of chains of aggregates in the software
If chains were represented faithfully in the software, i.e. with about 125 aggregates as is the case in the ocean, after one generation each chain would produce 125 oozooids, which in turn would give birth (assuming no mortality) to 125 chains, and so on. After only 3 generations, there will exist 125**3 or 1,953,125 oozooids. This is much more than a computer with 256 Mb memory may allocate. Tolerable numbers of zooids in 120 simulated days may only be obtained if Number_Of_Aggregates in the software is set to about 5. This is not a problem if the purpose of the simulation is to obtain a swarm, that is, a fair number of interacting zooids. Conclusions drawn from 600 zooids would not teach us much more than from two millions. Of course the amount of food filtered by these "scaled chains" should be adjusted to the number of aggregates they are composed of.
Screen display of the creatures
The screen, as well as the space, is a shared resource needing mutual exclusion. However, using the same controller(s) to access the space and then the screen would impose a performance penalty to the space accesses, because displaying a creature on screen (via AdaGraph) is very slow. The prime concern in RTS3-XP being accuracy of the simulation, I preferred to separate the two processes: the space access (via the protected object Controller), and the screen access (using the object Computer_Interface.Protected_Screen.Screen_Control). Pending screen requests will thus be blocked until satisfied, leaving the space requests to proceed without delay. A flag With_Mode indicates if a screen request is made in CHAR or in PIX mode.
The screen controller also manages the display of the global simulation time, and of the counters totalizing the numbers of living creatures.
It should be stressed that in this implementation, the creatures do not "physically" occupy the space: they are only represented by their external appearances. When a creature moves from one location to another, only its appearance (a graphical code) moves. The creature itself (the Oozooid_Pattern or Chain_Pattern record) stays at the same place in memory, where its location field is updated.
This implementation is consistent with the real world situation: the creatures see only the external appearance of what is in space. When a Vibilia attacks its zooid host, she first detects its appearance; after she seizes the host, she has access to its internal structure (via the pointer on the task ID, available in the External_Appearance record).
Salps moves
Zooids moves, from one location to another one, occur at the beginning of each of their internal cycles (i.e. each mean day). Moves should be done in mutual exclusion, otherwise the environment could be modified during the move by another creature. An Ada 95 protected object insure exclusive access while the creature has seized the lock associated to the operation. The Move algorithm for zooids is :
Vibilia moves and host infestation
The Vibilia must find their hosts, because they can only grow by eating the reserves of a zooid, and they can only reproduce by depositing larvae on zooids. They can only attack a host when they arrive at a location already occupied by a zooid.
Algorithm for Vibilia moves:
A Vibilia knows that a zooid is present because each space location contains the External_Appearance (a code) of the object inside it. There is a difficulty here, because zooids are members of a linked list of zooid records. It is difficult for the Vibilia to know the attributes of a given zooid, for example how much reserves it has. To eat the host's reserves, the Vibilia should know the access value of the host's record. Knowing only the host External_Appearance is not enough.
To obviate this,
the Salps package is extended by a child package
Salps.Host_Relationships providing subprograms for host interactions.
This problem was difficult to solve with Ada 83. However, Ada 95 provides the
packages Ada.Task_Identification and Ada.Task_Attributes, which
permit to associate to a given task a user-defined value. Each location can
contain the task Id of the zooid, to which the access value of the zooid record
is associated. The space is thus an array of protected locations, each location
containing the "trace" of what is inside it. An empty location is a special
case, containing the appearance Empty, and the Id: Null_Id. In
modeling terms, the space is defined by its contents. Note that in RTS3-XP, a
creature in a location has no knowledge of what is in the other locations. It
must at least explore the neighboring locations to discover their contents.
Vibilia searching zooids may however detect their presence at some distance by
exploring radiating directions from the current location. As a starting point,
I have considered that zooids are unable to detect food at distance (perhaps a
false assumption?).
Obtaining the host access value is nevertheless difficult, because zooid moves and Vibilia moves are concurrent and asynchronous. When the Vibilia arrives at a location occupied by a zooid, the Vibilia looks for the Id of the zooid, then changes the External_Appearance of the zooid to a special code, Attacked_xxx, and replaces the zooid Id with its own Id. Knowing the task Id of the zooid, the Vibilia can now inquire its access value, returned by the procedure Salps.Host_Relationships.Send_Zooid_Pointer. The Vibilia also changes the internal state of the zooid to Parasited. The Vibilia then creates a Suspension_Object with its Id passed as discriminant and suspends itself, until the zooid acknowledges it is 'parasited'. The zooid, when it discovers that it has been attacked (its state has been changed to Parasited), releases the supension state of the Vibilia.
With its host's access value, if it is Maturing, the Vibilia may eat the host's reserves. Note that there may be several larvae on the same chain, so the chain reserves must be devoured in mutual exclusion: the zooid reserves are enclosed in a protected object. If the Vibilia is Seeking_Hosts, it searches mature zooids in its neighborhood, and attack them, creating new larvae at the host location (or adjacent locations if the previous ones are occupied). Each larva receives a copy of the host's access value, so it can move with the host. When the young attains a certain age and a certain weight, it leaves the host, swims freely in the plankton, and searches new hosts.
AVibilia is either on the zooid it was deposited on (eating its reserves), or freely swimming. In the latter case, it searches zooids to devour them (if Maturing or Not_Seeking), or (if Seeking_Hosts) it searches mature zooids to deposit larvae on them (it is Not_Seeking if it has deposited all its larvae on hosts).
To have more chances to find zooids, the Vibilia "swims faster" than them. To accomplish that, it stays in more than one location per daily cycle. This is done by making 'jumps', in a loop inside the main internal cycle loop. During this loop, theVibilia tries to adjust its swimming direction in order to move towards the direction where there are the most hosts or preys (within a Search_Radius area around it). Note that this is not done using a true interception algorithm, which would involve computing the host trajectory relative to the Vibilia's, etc. It is rather a cheap way to increase its chances to encounter a suitable host or prey; remember that the zooids and the Vibilia move asynchronously. In biological terms, this models a Vibilia "sensing" the direction of maximum zooid concentration.
Because
the Vibilia and its
host live asynchronously, the Vibilia must check at the beginning of
every major interaction that its host has not died. In addition, to ensure that
during demarsupiation the host is not itself reproducing (which would raise
complex problems), a Reproducing state is set during the zooid
reproduction.
Parameters
The initial parameter values are read from the configuration file, RTS3-XP.CFG. This is a simple text file, which may be created and edited with any text editor. See this file for the necessary formatting rules. The values are read into variables in the package Auxiliary_Variables, and they are further converted into constants to be used throughout the program in the Parameters and Screen_Parameters packages.The current screen resolution is detected and the optimal size of the main graphic window is computed, according to the chosen graphical representation.
Since version 21.00 it is possible to read parameters for 2 'categories' A and
B of creatures (A being for example Salpa fusiformis and B Thalia
democratica, or B being another population of S. fusiformis with
slightly different parameter values). In RTS3_XP.CFG parameters for the B category
must be present even if the simulation concerns only A (in this case the values
for B will be ignored). In version 21.00 I tried to implement fecondation in
salps. Aggregates must be first female then male, so male chains must encounter
chains with female aggregates, i.e. a old chain should meet a young chain. This
is possible if there are 2 'categories', and the first B oozooid is created
with some lag after the first A ooz.
Food
As there are still
interrogations on the exact nature of the food ingested by Salpa
fusiformis (what species and size of algae, whether particulate organic
matter (POM) is involved, what is the role of the clogging of the filter,
etc.), it would be premature to build these assumptions in the software. In its
basic version, food is an attribute of the space locations, each one containing
0.0 or more "salp food units", measured in mg Chl a per m3 (internally
converted to µgC per location (scaled by 25). A part of the food filtered by
the zooid is converted to µ.atom.g N and used for growth and metabolism. In all
cells of the 'food area' food is periodically entirely renewed, except where it
has been exhausted. The entire renewal lasts about 0.2 ms on my 2.66 GHz
machine, less than 1ms on my portable.
Back to RTS3 page
Last modified 2009-02-26