marqueur eStat'Perso Code implementation

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