[Graph logo] DRUIDIC Models = Algorithms + Objects

[Lsd Logo]

Go To
Main
Lsd Site

 



Understanding the programming of AL models

All Lsd simulation models are defined by two files. On the one hand there is the configuration file (with the extension ".lsd") that defines the basic structure of the model and its parameters and variables as well as the values of parameters and lagged variables. On the other hand there is the equation file (with the extension ".cpp") that defines how each of the variables of the model is to be computed by means of parameters and other variables.

In practice these two files are developed in tandem. The model developer starts from a basic model structure with few elements and the related equations, and he or she makes sure that the simulation program is working correctly before he gradually introduces more and more components and equations. If this procedure is not followed, it is unlikely that a correctly functioning model will be made. However, when we study an existing model, it is most easy to think in terms of a two step process: First we study the configuration file and then we study the equations that create a runnable model as well as details about parameters and variables.

The handling of data structures in C++ and Lsd

The Lsd implementation of an evolutionary model is to a large extent is a matter of specifying its data structures. We, of course, also have to specify the algorithms (equations) that work on these data structures, so Programming = DataStructures + Algorithms. However, as soon as the data structures are well understood, the writing of the necessary algorithms is fairly simple. At the same time the data structures of C++ and Lsd are combined with algorithms in a very basic way. Since their algorithms depend heavily on their data structures, it is usefull to give a short account for these data structures and the operators used to inspect, modify, create or delete them. The account, of course, cannot replace the Lsd hypertext manual.

Classes and objects in Lsd

The basis of object-oriented programming in e.g. C++ is the concepts of classes and and instances of classes (also called objects). This is made quite clear by the creator of C++ (Stroustrup 1994, 2000). A class is like a record or struct data type in a classical programming language like Pascal or C. In other words, it is like a template with premade fields. However, instead of just including fields for its data, a class also stores the operations that can be used to access and change the data. An instance of a class isnlike a variable of a particular data type in the classical languages. However, the belonging to a class means that an instance has access to the operations of that particular class, and it is through these operations that the actual data are inspected and modified.

In C++ a class description is placed in a so-called header file (with the postfix ".h"). The class description contains the names and types of the data fields included in the class. It also contains headers of the operations available in the class. In both cases the header file specifies which elements are available for "public" use and which elements are "private" for the class (in the Lsd system everything is "public"). The actual specifications of the operations are placed in other files. Thus the class descriptions for the Lsd system is placed in the file decl.h while the files for the specification of the operations are object.cpp and variab.cpp.

In the Lsd system there are only two classes: Object and Variable (capitalisation is used in the precent note to distinguish from ordinary concepts). The Object class includes a fairly large number of operations as well a name field, fields for addresses that place the Object in the model hierarchy, and a linked chain of Variables. The Variable class includes as small number of operations as well as a name field, a field with the address of the Object to which the Variable belongs, a linked chain of computed values of the Variable, as well as fields for controlling computation of the Variable during a simulation run.

The instances of the Lsd classes are created dynamically during a simulation run. In some cases all the instances are created in the beginning of the simulation run based on the information found in the Lsd configuration file. But in other cases further instances are created and old instances are destroyed during the simulation run. This is the case in the AL model if fission and fusion of firms are enabled. Let us, however, consider the simple case where the number of instances is constant during the simulation run.

When the AL user asks the Lsd system to load a configuration file, two things happen. First, the Lsd system creates the model tree with one instance of each type of Object and stores the address of the top of the tree. This top is the Root Object that includes the address of its "son", the Economy Object. The Economy includes the address of its first "son", the Firm Object. The Firm includes the address of its "brother", the Household Object. Second, the Lsd system uses the information from the data part of the configuration file to create the required number of each type of Object and to fill out some of the Variables of each Object with the user-defined initial values and simulation settings.

When the AL user asks for a simulation run, the Lsd system sets simulation time to 1 and starts to work through the model tree. When it reaches an Object it checks the Variables of the Object and checks whether they actually are variables and whether they have been updated in the present time step. If this is not the case, the system tries to make an update based on the equation of the variable. During the execution of the equation further Variables may be needed. If this is the case, the system places the address of the Variable that is being computed on a so-called run-time stack of addresses, and moves to the needed Variable. In this way the system moves through the model tree in an apparently erratic manner. However, this movement is governed by the structure of the tree and the contents of the run-time stack.

Lsd Variables

The starting point for a deeper treatment of the Lsd system and the AL model is the Variable class. In any computer language a variable (and a parameter) are basically defined by a name, a type, a memory address, and a value placed in this memory address. In Lsd all the values of Variables have the type double precision floating point numbers, i.e. very precise real numbers. So when the simulation program requires the value of a particular Variable, the Lsd system will find the memory address of that Variable and return the real number that is placed in the Variable.

This naive account for a Variable, like the productivity A of a particular firm, is not sufficient for understanding the functioning of the Lsd implementation of the model. In Lsd the concept of Variable is extended to mean "Timed Variable" so that the value should always be read with a time subscript, i.e. is This is done by making Variable a complex data structure that, among other fields (elements), includes the name (label) of the Variable, the value of the Variable, information about the time of the last update of the Variable, and settings like whether the Variable is to be saved for later data analysis.

This strategy of storing additional data and settings in standard fields of a Variable has several advantages. First, the information about the last update provides a very general way of performing simulations. Let us in this note call the Lsd simulation time T to distinguish it from the Variable's last update time t (the actual simulation time in Lsd is called t). If the Variable needs an update and this update is performed by the the algorithm (the Lsd Equation) that is connected to the Variable. Second, when the Lsd system meets a "Variable", it first checks whether it is true that it is set as a Parameter. If this is the case, the "Variable" is never updated and there is no need for a Lsd Equation. Third, if the Variable is to be saved, it will contain a list of previously computed values. At the beginning of the list the Lsd system interts the most recent value, the next list item is the value at then comes the value for etc.

For the construction of the AL model the inclusion of the field last-update into Variables is the most important aspect of the Variable class. Other fields are, however, recorded in table 3 since they may help to understand the functioning of the Lsd system.

Table 3. Most relevant fields in the Variable class of Lsd

label Name of the Variable that has to be unique within the AL model.
v     Address of the first element of the linked chain of Variables in 
      the Object. For instance, in Firm the chain consists of 14 
      Variables. The chain is only indirectly used by the AL model.
up    Address of the parent Object that contains the Variable.
next  Address of the next Variable in the linked chain of Variables of 
      a particular Object.
val   Array of values of the Variable: val[0] is the most recent update 
      of the value, val[1] is the value computed in the previous time 
      step, and so on.
num_lag Number of lagged values of the Variable needed to start the 
      simulation.
save  Save or not save the Variable in the result file.
plot  Create or not create a Run Time Plot of the Variable.
debug If debug = 1, then the simulation stops immediately after 
      computing the value of Variable.
last_update  The global simulation time when the Variable was last 
      updated.

Lsd Objects

Lsd Variables are contained in Objects. For instance, the Object Firm may contain 14 "Variables" (of which two are parameters). Each of these Variables (as well as all other Lsd Variables) have exactly the same structure since they are all instances of the same class. The "only" difference between them are the actual names, values, and settings. But any Object also includes a set of standard fields that are highly relevant to e.g. the AL model. The most relevant of these standard fields are:

Table 4. Most relevant fields in the Object class of Lsd

label Name of the Object. In the basic AL models the Objects are 
      Root, World, Options, Economy, Firm, Household
v     Address of the first element of the linked chain of Variables in 
      the Object. For instance, in Firm the chain consists of 14 
      Variables. The chain is only indirectly used by the AL model.
up    Address of the parent Object. In Firm, up is the address of the 
      Economy in which it is embedded. Root is the only object having 
      no parent (the value of up is then NULL).
son   Address to the first descendant Object. All the direct 
      descendants are listed one after another in a linked chain. In an 
      Economy son is the first of the contained Firms.
next  Address of the next Object in the linked chain of the descendants 
      of the parent of an Object. Thus the next of the first Firm is 
      the second Firm. The next of the last Firm is the first 
      Household. The next of the last Household is NULL.
The use of these fields in Lsd programming is fairly obvious. The three last fields can be used for moving through the hierarchy of the model. The label can be used to move through the linked chain of Firms and stop at the last Firm by excluding Objects with other labels (Household). The chain of Variables can be addressed through the address of the first Variable. This feature of not immediately relevant, but it explains how the Lsd system creates information on the Variables during an interactive Lsd session that defines the configuration file for the models.

Like other C++ class instances the Lsd Objects do not only contain data structures but also (access to) operations on their own data structures as well as the data structures of all the other Objects of the model. It is useful to consider a few of the Lsd operations-mainly to recognise that addressing issues dealt with by the fields of any Object (e.g. Firm) are only the top of the iceberg of the addressing problem in Lsd programming. The basic problem is that we normally cannot refer to a particular Firm by its index number like it is normally done in simulation models written in Fortran (as the original Nelson-Winter simulation models) or Pascal. Here we would simply run through the values of e.g. Q by setting i from 1 to n in the expression This is not the strategy that is encouraged for writing Lsd equations. To give a basis for studying the strategy used by the Lsd system table 5 gives a short account for some typical operations available for Lsd Objects.

Table 5. Examples of operations available in the Object class of Lsd

ObjectAddress->cal("VarName", Lag) 
     This operation provides the value of a Variable named "VarName" 
     with the time lag of Lag. The value returned depends on the 
     starting point of the search in the AL hierarchy. This starting 
     point is ObjectAddress, the so-called calling Object like p->. The 
     search strategy is described in connection with search_var.
ObjectAddress->search_var_cond("VarName", Value, Lag) 
     This operation starts from the calling Object and searches until 
     it finds a Variable with "VarName" and value = Value-or until the 
     whole model structure have been searched in vain. The search 
     strategy is to return when a value has been found by (1) search 
     among the Variables of the calling Object, (2) search among the 
     Variables of the descending Objects, and (3) search among the 
     Variables of parent Object. Each Object encountered during this 
     search performs the same search strategy.
ObjectAddress->sum("VarName", Lag) 
     Searches for the Object having a Variable with "VarName". From 
     that Object it moves through all the brother Objects and returns 
     the sum of "VarName" with requested Lag.
ObjectAddress->add_an_object("ObjectName", ExampleObjectAddress) 
     Adds an Object of type "ObjectName" to the descendants of the 
     current Object, e.g. p->. The new Object is placed in the last 
     position of the chain of the same Object and initialised according 
     to the initial values contained in the example Object.
All the four functions of table 5 have the same basic structure,
  ObjectAddress->OperationName("VarName", other arguments),
where ObjectAddress is the address of (pointer to) an Object, ObjectAddress-> is the Object that is pointed to (also called *ObjectAddress), OperationName is the name of an operation that is included in the Object, "VarName" is the name of a Variable placed within quotation marks, and other arguments are Lag, Value or ExampleObjectAddress.

This strange structure of operation calls reflects the object-oriented character of C++, where you not only have to specify in which Object a Variable is placed but also in which Object a operation is placed. Thus ObjectAddress->OperationName can be read: Call the operation with OperationName that is placed in the Object pointed to by ObjectAddress. This way of calling an operation has an additional advantage: The ObjectAdress is automatically stored in a particular C++ variable-called "this". Such information can be used by the operation, e.g. in its search strategy. The arguments placed in paranthesis after the OperationName are more standard for all kinds of programming languages. However, we see in add_an_object that an ObjectAddresses cal also used as an argument.

When solving the addressing problem, we should try to consider the situation from the viewpoint of the Object that contains the Variable that we are writing an equation for. What do we know about this particular Object? First, we know the type of the Object, e.g. Firm, and thus its place in the AL model hierarchy. Then we know the address of any particular Firm when a Variable within this Firm is being computed. This address is stored in the Lsd pointer variable called p, which might best be interpreted as the address of the parent of the Variable that is under computation. But we can also use the address p to obtain other addresses. For instance p->up means that we look into the variable up that is contained in the Object pointed to by p. This variable is in itself a pointer, namely the address of the parent of Object. Thus if the p-> Object is Firm, p->up is a pointer to Economy. Similarly, p->up->up is a pointer to the Root Object.

Let us apply this general discussion to cal, the most used operation in Lsd. From the above account we recognise that this cal function is supplied by three parameters (arguments) of which two are given in a standard way while the third is supplied by the C++ system-the address of the "calling" Object. Combined with our knowledge about the search strategy of the Lsd system, we can use this knowledge to improve the efficiency of Lsd simulations. Before we turn to this issue it should, however, be noticed that C++ is a highly efficient system and that search through pointer structures in the memory of the computer is especially efficient. However, if we have a very large number of Firms, there will be efficiency differences between the following two search strategies for finding the value of the Variable P (price) that is needed in the calculation of Variable pi (profit) in Firm but is calculated at the level of the Economy:

v[0] = p->cal("P", 0),
v[0] = p->up->cal("P", 0).
In the first case cal starts by looking for P in all the Firms before it moves to Economy in which the Variable is placed. In the second case the search starts in the Economy that contains the Firm, and here P is immediately found. There is, however, at trade-off between computational efficiency and human efficiency. It is easy to write programs that are very hard to read and understand, either for other users of the program or for its author when he returns to the program after a pause of a few months. It is mainly for this reason that the fine tuning of a program to improve efficiency should often be postponed until such efficiency is really needed (i.e. when large-scale simulation runs are required).

The implementation of the model's equations

The configuration files are not only important for running an AL model. They have a structure that is also highly relevant for the concrete design of the program that determines the value of each variable. When a Lsd simulation is running, the system will for each time step try to compute the value of each variable in each object. If we have added a new variable in the configuration file (e.g. Bankrupt[i,t] for Firm; not implemented!) and we have not yet written the equation for calculating this variable, then the system stops the computation and gives us an error message. If we, however, have an equation that adds a new object of type Firm (in the equation for Fusion), the system have no problems. We just have a clone (with inherited productivity and a share of the employment of the mother firm), so the system is already provided with the necessary equations.

The importance of the model structure goes deeper. In old-fashioned programming firms were normally represented by arrays of variables and the programmer had to be careful about the indexes. Since Lsd is extensively using so-called pointers to objects, such considerations can largely be ignored by the Lsd model developer. If a firm uses a parameter like lambda to calculate whether a R&D result is obtained, the Lsd system first searches for this parameter in the firm itself and then it moves upward in the hierarchy. Since the parameter is not defined in the firm but in the economy which contains it, lambda is found. Even if there are different lambdas in different economies, the lambda of the firm is uniquely defined. In some cases this method of finding values is too constraining, so the Lsd system provides a number of alternative search methods.

To consider the relationship between model structure and equations a little closer, we shall consider a simple AL example: the Lsd code for the calculation of the profit of a firm. This code is written in the C++ programming language enhanced by Lsd features, and at first sight it may look rather strange. But a minimal knowledge about the Lsd equations is needed (at least in the present version of the Lsd system). So, let us consider the following "equation":

1. if ( !strcmp(label,"pi") )
2.   {
3.     // Profit: pi[i,t] = P[t]*Q[i,t] - L[i,t-1], i.e. revenue (price
4.     // times quantity) minus lagged labour costs (wage rate = 1).
5.     v[0] = p->cal("P",0);
6.     v[1] = p->cal("Q",0);
7.     v[2] = p->cal("L",1);
8.     res = v[0]*v[1] - v[2];
9.     goto end;
10.  }
The code is basically a conditional sentence where the expression in parantheses after "if" is the condition while the sentences within brackets are the things to be done if the condition is true. However, two of the lines (lines 3 and 4) between the brackets starts with "//", so they are comments that are ignored by the C++ compiler.

Let us first consider the conditional expression (line 1). This expression is inspected while the Lsd system tries to evaluate one of the variables. Assuming that the Lsd system has come to the variable "pi" (profit) of a particular firm, then the system checks whether this variable has already been computed in the present time step t. If this is the case (last_update = t), then the system leaves the value unchanged. Otherwise, it runs through all the AL equations to find the equation that calculates the new value of pi. Here the Lsd system applies the C++ function for string comparison. For reasons that will not be discussed here, this function (strcmp) returns the value 0 it the searched label is equal to "pi". The value 0 is alse interpreted as false, so the conditional expression is that string compare should not be true (not is called "!" in C++).

Given that the value of pi needs an update, the Lsd system moves to the code (lines 5-9). The first task is to collect the values needed for the computation of pi. This is done in lines 5-7. In each case the command is to fetch a value at place it in a temporary vector of variables. Thus P is to be placed in the first temporary variable, Q in the second, and L in the third. The method is the same in all cases: the Lsd cal (i.e. call) function. Thus the computation of pi calls for three other variables. The starting point for this search is the address of the "parent" p of the variable under computation. So we e.g. set the value of v[0] equal to the value for P returned by the cal function . The cal function performs the above mentioned searchh through the model hierarchy. If the search values have already been computed, they are immediately returned. If not, then the computation of pi is postponed until the needed values have been computed. The cal function two parameters of which the meaning of the first (the name of the called variable or parameter) is obvious. The second is the time lag. In lines 5-6 a value for the current time step is required (time lag 0). However, in line 7 the value of employment L is required for time (time lag 1).

After these cryptical steps the rest of the equation is quite easy. In line 8 the result of the equation (res) for pi is set to P times Q minus L. In line 9 the Lsd system is asked to drop the rest of the equations (and go to a label "end" placed at the end of the list of equations); the reason is that the result has been found and the system is ready to move to the next variable that is found.

The above code may seem to be a very strange way of finding a solution to an extremely simple equation, but some advantages have already been indicated above. At the same time the costs of performing the searches (in terms of time and computer resources) are small because C++ is a highly efficient language, especially with respect to pointer operations in the memory of the computer. Further advantages becomes apparent when we turn to more complex Lsd equations. Here the equation for Fission may illustrative (but not easy to decipher). The task of this equation is not only to return a value (true if the firm has undergone a fission in the present period, false otherwise). The equation also has the effect of creating a new firm with the same productivity as the mother firm and with a share of its employment. Here is the C++/Lsd code:

1. if ( !strcmp(label,"Fission") )
2.   {
3.     // Fissions of firms are determined after new productivity is
4.     // found. The probability of a fission depends on the parameter
5.     // psi times the market share of the firm (as a Poisson
6.     // process). If a fission takes place, employment of the firm
7.     // is split according to a uniform distribution;the smallest
8.     // is set up as a new firm with the same productivity as the
9.     // mother firm.
10.    v[0] = p->cal("Regime_entryexit",0);
11.    if ( v[0] == 1 )
12.      {
13.        v[1] = p->cal("psi",0);
14.        v[2] = p->cal("s",0);
15.        if ( poisson(v[1]*v[2]) > 0 )
16.          {
17.            p->cal("A",0); // Ensure productivity is updated
18.            p->cal("Hinv",0); // Ensure Hinv is updated
19.            v[3] = p->cal("L",0);
20.            v[4] = p->cal("Lsharemax",0);
21.            v[5] = RND;
22.            v[6] = v[5]*v[4]*v[3];
23.            cur = p->up; 
24.            cur = cur->add_an_object("Firm",p);
25.            cur->write("L",v[6],t);
26.            p->write("L",v[3] - v[6],t);
27.            res = 1;
28.          }
29.        else
30.          {
31.            res = 0;
32.          }
33.      }
34.    else
35.      {
36.        res = 0;
37.      }
38.    goto end;
39.  }
Although it is possible in this code for computing Fission[i,t] to recognise several elements that were also present in the computation of pi[i,t], there are obvious differences. First, the code is an exercise in nested conditional expressions. All the 39 lines is one large conditional expression (with matching brackets in line 2 and 39) that is only executed if the variable to be computed by the Lsd system is equal to "Fission". If this is the case, we quickly meet a new condition. If Regime_entryexit = 1, then lines 12-33 are executed; else these lines are ignored and lines 35-37 are executed. This structure of the code allows the user to switch on and off fission (and fusion) by setting Regime_entryexit to true (1) and false (0). We meet yet another condition is line 15. Here a Poisson process is called to determine whether the firm will face a fission in the current period. If this is the case, then lines 16-28 are executed; otherwise lines 30-32 are executed. It is easy to see that the returned value of the function is true (1) if a fission has taken place while it is false (0) if this is not the case.

Even the slightest inspection of the code demonstrates that the returned value is not the main effect of Fission. Therefore, mathematicians characterise it as a function with serious "side effects" that complicate the analysis of its effects. These side effects are, of course, the main purpose of the code-to generate a new firm and partition the employment of the mother firm between itself and the new firm. So let us consider this part of the program (lines 15-28).

The first thing to note is that is is a Poisson process that determines whether is fission takes place (like other Poisson processer determines R&D results), so we really have to come to grips with such processes that are well known in discrete event simulation of e.g. service processes where customers come irregularly to a server with a limited capacity. In such cases we often know the average number of arrivals per time unit (Lambda[t]) or the average time between arrivals (1/Lambda[t]). A Poisson distribution is characterised by such a single parameter. The Poisson function of C++ uses the random number generator to produce a stochastic series of arrivals. To handle the R&D process, we the Poisson process has been interpreted in the following simple way: In line 15 we assume that for a given firm the average number of fusions per time period depends on the market share of the firm times an economy-wide parameter (lambda*s[i,t]). There are, of course, many other possibilities. For instance, the probability of a fission can be related to major innovations (larger then sigma or two times sigma). But this is a task for further work. At present the main problem is to avoid that the AL model becomes too complex even though we provide a mechanism that courteracts its in-build tendency towards monopoly.

Given that a fission is about to take place, the problem is how to implement the possible split-up of the firm. This, of course, depends on our theory of that matter, and this is largely related to future developments of AL. At present we just suppose that any new firm emerging from a split or spin-off of a mother firm will contain the smallest part of the firm. In line 21 we call a Lsd version of the standard random number generator. This RND function gives a random number that is uniformly distributed between 0 and 1. But since we are exploring different theories, the share of the employment for the new firm is then defined as RND times Lsharemax (line 22). The Lsharemax parameter to considered to be common for the whole economy.

The next step is to create a new firm within the economy that contains the mother firm (line 24). To perform this operation we need some knowledge about the AL model structure, the use of address variables (pointers) in C++, and the special facilities for address handling by the Lsd system. We have already met the specification of the parent Object of a Variable, p->. To get the address of the Economy that contains this parent object (a Firm), we use p->up. This address is stored as a temporary pointer variable, cur, in line 23. In line 24 the Lsd system is requested to create a new Firm based in the Economy pointed to by cur. The Lsd function add_an_object("Firm",p) has as its second parameter the parent (or mother) Firm defined by the p address. This means that the function add_an_object makes a clone of the mother Firm (including values of parameters and lagged variables). We reset the address contained in cur to the address of this new Firm.

There is, however, one task left: to reset the employment of the mother Firm and the new Firm. This is done in lines 25-26. In both cases we ask the Lsd system to (over)write the values of employment at time t (a global variable that contains the period under computation). The L variable of the new Firm is addressed by cur-> while the mother/parent Firm is addressed by p->. After the completion of this update the returned value is set to true (1).

The "equation" for Fission is one of the more complicated parts of the Lsd implementation of the AL family of models. It demonstrates that is can be quite time consuming to study the details of a simulation program. Luckily, there are simpler ways of understanding the logic and behaviour of the AL model (see sections 4-5), and there is no need of understanding all the details (unless you are checking for possible bugs in the AL implementation). So we shall turn to a less implementation-oriented overview over the AL equations and parameters.

Programming the user interface

Although the user interface is mainly an issue of of the Lsd system and not of the model programs that function within the Lsd framework, it has not been possible to drop user interface considerations from the construction of the AL program. This has led directly to the Tcl language and the Tk toolkit --- see the overview by the creator fo Tcl/Tk: Ousterhout (1994, or later edn). This is the system on which Lsd's user interface is build, and it is flexible enough to allow a wide variety of windows-based user interfaces. If Lsd and AL were constrained to a particular modelling and simulation approach, then this approach could by supported by a lot of facilities like e.g. the systems dynamics approach (see Sterman 2000) is supported by the smooth interfaces of commercial software like Stella and iThink. But Lsd and AL emphasise power and flexibility of expression over ease of use, so e.g. the model structures of Lsd programs do not reflect the computational structure like it is the case in Stella and iThink (and the other packages built on the Dynamo language). But there are, of course, many possibilities of developing the interface.

Let us concentrate on the loading and modificaion of config files. Here much needs to be done with respect to the AL user interface, as can be seen from sections 6.1 and 8.1. Here we saw that the user is required to access config files whose only description is a code of 6 or 10 bits. The user is also supposed to check against the corruption of config files by comparing the bits with the actual values that are printed to the Message Log window. This is not the kind of tasks that is normally expected from a program user.

A simple strategy would be to use the string matching facilities of C++ and Tcl/Tk to check file names against parameter values. But this does not go to the core of the matter: to give the user simple information on individual configurations -- both the premade and the self-constructed.

One tool that is under consideration in a Model Config Browser that will take the place of the present File/Load window. The Config Browser would loom like the present Model Selection Browser in the Lsd Model manager. This means that when you select a config file, then a message that describes the main characteristics of the settings, etc. will be displayed. This message comes from text that is stored after the keyword MESSAGE at the end of the config file. If the user corrects the message, then there is a possibility of overwriting the previous text of the config file.

Another helpful tool will be the AL Control Panel which can help the user to construct config files from basic templates. To allow for the fullest use of the Control Panel, the functionality of Lsd should be changed so that this panel is shown whenever the AL application is started. An important part of the control panel is the 10 control parameters that have already been discussed. Many of them are relatively independent on the others. The task of the user is e.g. to click on two "radio buttons": cumulative and science-based. In other cases there is complex interdependencies. For instance, selection of Regime_nochange = 1 will exclude quite a number of buttons of being pressed.

In principle it is a rather simple task to construct a control panel in Tcl/Tk. The problems come from the integration of Tcl/Tk into C++ and, not least, from the need of making the new facilities a smoothly integrated part of the Lsd system.



Lsd is a system for developing and compiling simulation models as stand-alone application as well as a system for exploring model applications without any knowledge of programming. Lsd is developed and maintained by Marco Valente. The ordinary Lsd web site includes manuals and downloads. The present web pages includes additional Lsd-related materials and downloads. It is not necessarily in sync with the latest Lsd version.
 

Maintained by Esben Sloth Andersen, email: esa@business.aau.dk.
Revision: 09 August 2004, 13:35.