ETHZ_Logo RAMSES_Logo_Right   RAMSES   RAMSES_Logo_Left Systems Ecology  
Start    search button      Modules:   A-Z   Function   Layer        QuickRefs:   DM   AuxLib   AuxLibE   SciLib   EasyMW   MW   ISIS   RMSLib

DEFINITION MODULE SysModDSBase;

  (*******************************************************************

    Module  SysModDSBase     (ISIS_Version_1.2)

      Copyright (c) 1998-2006 by Andreas Fischlin, Dimitrios Gyalistras
      and ETH Zurich.

    Purpose   Support the declaration of entire data structures
              involved in the modeling of systems, e.g. declaration
              of an entire output vector.

    Remarks   The Data Structure Definition Language (DSDL) has
              the following EBNF:

              DataStructure ::= ["STRUCT" "="] vectorSpace;
              vectorSpace   ::= "S" ":" identifier vector { "*" vector }.
              vector        ::= "<" element { "," element } ">".
              element       ::= identifier | integer | integerRange | vectorSpace.
              identifier    ::= letter { letter | digit | "_" }.
              integer       ::= "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9".
              integerRange  ::= integer ".." integer.

              See also companion module SysModBase

              This module belongs to ISIS
              Integrative Systems Implementation Software.


    Programming

      o Design
        Andreas Fischlin         09/05/1998
        Dimitrios Gyalistras     09/05/1998

      o Implementation
        Andreas Fischlin         09/05/1998


    ETH Zurich
    Systems Ecology
    CHN E 35.1
    Universitaetstrasse 16
    8092 Zurich
    SWITZERLAND

    URLs:
        <mailto:RAMSES@env.ethz.ch>
        <http://www.sysecol.ethz.ch>
        <http://www.sysecol.ethz.ch/SimSoftware/RAMSES>


    Last revision of definition:  28/05/2002  AF

  *******************************************************************)


  FROM SysModBase IMPORT System, MObjType, MObjVar;

  (* Error constants: sysModDSBaseOffSet = DMLanguage.userBase + 350 .. 380-1 *)

  CONST
    undefOrd = -1;  (* undefined ordination number used to denote
                       undefined indices (see procedures using formal
                       argument ordTuple).  E.g.  element 1,1 out of a
                       matrix could be referenced by the tuple [1,1],
                       which contains all defined ordination numbers
                       (indices).  However, the tuple [undefOrd,undefOrd]
                       references no specific element, thus this module
                       interprets it to denote the entire structure, i.e.
                       the entire matrix *)

    endOfOrdTuple = -2;  (* used as index value to mark end of
                            indices array (see procedures using
                            formal argument ordTuple); is stronger
                            than undefOrd and functions like shortening
                            the declared dimension of the tuple. *)


  (*********************************************)
  (*#####   Declaring Object Structures   #####*)
  (*********************************************)

  PROCEDURE DeclMObjStruct(s                : System;
                           mObjStructQualId : ARRAY OF CHAR;
                           objStructType    : MObjType;
                           structDef        : ARRAY OF CHAR;
                           sepDimWithUL     : BOOLEAN);
  (*
    Declare a data structure as a structured model object.
    E.g.  use this procedure to declare an output vector.
    mObjStructQualId serves as an identifier for the entire
    data structure and allows you to reference it as a single
    entity.  objStructType is the type of the structure, e.g.
    type stateVar allows you to declare a data structure as a
    structure of state variables.  structDef defines the data
    structure according to DSDL, the Data Structure Definition
    Language (syntax given above).


    Example 1
    ---------

    Ex. use of a state vector of dimension 3:

       VAR
         x: ARRAY [1..3] OF StateVar;

    Its structure is:         "S: x<1,2,3>"

    Thus declare it as follows:

      DeclMObjStruct(s,"m.x",stateVar,"S: x<1,2,3>",FALSE);

    Above call will declare 3 state variables for you, using for
    them the identifiers: "m.x1", "m.x2", and "m.x3".
    Alternatively you could have declared this structure also in
    this way:

      DeclMObjStruct(s,"m.x",stateVar,"S: x<1..3>",FALSE);

    which is most useful for long vectors or large matrices.

    Note, you may use the underline character "_" in identifiers.
    E.g.

      DeclMObjStruct(s,"m.x",stateVar,"S: x_<1..3>",FALSE);

    would declare state variables with these identifiers: "m.x_1",
    "m.x_2", and "m.x_3".


    Once the structure has been declared, you need to bind the
    elements of the actual array of state variables, i.e.  x, to
    the declared model objects.  There are two techniques
    by which to accomplish this:

      (i) program the loop yourself:

       VAR index: ARRAY [0..0] OF INTEGER;  i: INTEGER;
         mObjQualIdent: IDENT;

       FOR i := 1 TO 3 DO
         index[0] := i-1;
         GetEleIdent(s,"m.x",index,mObjQualIdent);
         BindMObjVar(s,mObjQualIdent,x[i]);
       END(*FOR*);

      (ii) ask SysModBase to do the loop for you:

       VAR index: ARRAY [0..0] OF INTEGER;  i: INTEGER;
         mObjQualIdent: IDENT;

       GetFrstMObjStructEle(s,"m.x",mObjQualIdent,index);
       WHILE (mObjQualIdent[0]<>0C) DO
         BindMObjVar(s,mObjQualIdent,x[index[0]+1]);
         GetNextMObjStructEle(s,"m.x",mObjQualIdent,index);
       END(*WHILE*);

     The looping with the 2nd technique can be used successfully
     even if you pass unknownSystem as the actual parameter for s
     in case the model object structure is of type outVar.  This
     allows for any subsystem which wants to use the data
     structure as an input, to learn about the construction of
     identifiers and possibly of the associated tuple of
     ordination numbers, i.e.  ordTuple, of the output data
     structure without having to import any types or other
     objects from the outputting subsystem.  In such cases
     mObjStructQualId, e.g.  "m.x", is then already sufficient to
     learn about the structure of the structured model object.
     See also the routines involved in "Linking of Subsystems and
     Submodels for data exchange" as provided by the companion
     module SysModBase.


    Example 2
    ---------

     Parameter sepDimWithUL governs the use of the character underline,
     i.e.  "_", as separator between parts of an identifier which results
     from multidimensional structures.

     For example a 3 by 3 Markov matrix could be declared as this:

       VAR
         m: ARRAY [1..3],[1..3] OF Parameter;

       It defines a 2 dimensional structure:

          "S: m <1..3> * <1..3>"

     By calling

       DeclMObjStruct(s,"model.MarkovMatrix", modParam, "S: m <1..3> * <1..3>",TRUE);

     results in declaration of parameters with the tabulated identifiers
     and indices tuples:

          Identifier    Indices
          model.m1_1        0,0
          model.m1_2        0,1
          model.m1_3        0,2
          model.m2_1        1,0
          model.m2_2        1,1
          model.m2_3        1,2
          model.m3_1        2,0
          model.m3_2        2,1
          model.m3_3        2,2

     REMARK: Due to the limitation of Modula-2 to pass open array
     parameters always as arrays which start from index 0, an index
     in the tuples containing the ordination numbers for the elements in
     the data structure always start from 0. Consequently, if you
     declare this array

       VAR ind: ARRAY [1..2] OF INTEGER;

     you can bind all of the matrix' elements by this code:

       (*(i) program the loop yourself:*)
       FOR i := 1 TO 3 DO ind[1] := i-1;
         FOR j := 1 TO 3 DO ind[2] := j-1;
           GetEleIdent(s,"model.MarkovMatrix",ind,mObjQualIdent);
           BindMObjVar(s,mObjQualIdent,m[i,j]);
         END(*FOR*);
       END(*FOR*);

     or like this:

      (*(ii) ask SysModBase to do the loop for you:*)
       GetFrstMObjStructEle(s,"model.MarkovMatrix",mObjQualIdent,ind);
       WHILE (mObjQualIdent[0]<>0C) DO
         BindMObjVar(s,mObjQualIdent,m[ind[1]+1,ind[2]+1]);
         GetNextMObjStructEle(s,"model.MarkovMatrix",mObjQualIdent,ind);
       END(*WHILE*);

     Rember also, by calling

       DeclMObjStruct(s,"model.MarkovMatrix", modParam, "S: m_ <1..3> * <1..3>",FALSE);

     you can alternatively get:

          Identifier    Indices
          model.m_11        0,0
          model.m_12        0,1
          model.m_13        0,2
          model.m_21        1,0
          model.m_22        1,1
          model.m_23        1,2
          model.m_31        2,0
          model.m_32        2,1
          model.m_33        2,2



    Example 3
    ---------

    Example featuring a more complex data structure:

       CONST alpha = 1; beta = 2;

       VAR
         out: ARRAY [alpha..beta] OF RECORD
                                      theta: OutVar;
                                      y: ARRAY [1..3] OF ARRAY [1..2] OF OutVar;
                                     END;

       Its structure can be defined like this:

          "S: out  *  * <1..2>>"

       Calling

          DeclMObjStruct(s,"mo.outStruct",outVar,
            "S: out_  * *<1..2>>",FALSE);

       results in declaration of model objects with tabulated identifiers
       and indices tuples:

          Identifier                 Indices
          mo.out_alpha_theta          0,0
          mo.out_alpha_y11            0,1,0,0
          mo.out_alpha_y12            0,1,0,1
          mo.out_alpha_y21            0,1,1,0
          mo.out_alpha_y22            0,1,1,1
          mo.out_alpha_y31            0,1,2,0
          mo.out_alpha_y32            0,1,2,1
          mo.out_beta_theta           1,0
          mo.out_beta_y11             1,1,0,0
          mo.out_beta_y12             1,1,0,1
          mo.out_beta_y21             1,1,1,0
          mo.out_beta_y22             1,1,1,1
          mo.out_beta_y31             1,1,2,0
          mo.out_beta_y32             1,1,2,1

       Do the binding like this:

       CONST theta = 0; y = 1;
       VAR ordTuple: ARRAY [0..3] OF INTEGER;  i,j,k,l: INTEGER;
         mObjQualIdent: IDENT;

       (i) programing the loops yourself:

       FOR i := alpha TO beta DO ordTuple[0] := i-alpha;
         FOR j := theta TO y DO ordTuple[1] := j-theta;
           IF j=theta THEN ordTuple[2] := endOfOrdTuple;
             GetEleIdent(s,"mo.outStruct",ordTuple,mObjQualIdent);
             BindMObjVar(s,mObjQualIdent,out[i].theta);
           ELSE
             FOR k := 1 TO 3 DO ordTuple[2] := k-1;
               FOR l := 1 TO 2 DO ordTuple[3] := l-1;
                 GetEleIdent(s,"mo.outStruct",ordTuple,mObjQualIdent);
                 BindMObjVar(s,mObjQualIdent,out[i].y[k,l]);
               END(*FOR*);
             END(*FOR*);
           END(*IF*);
         END(*FOR*);
       END(*FOR*);

       Note, you can temporarily "reduce" the dimension of
       ordTuple by assigning after the lest element in use the
       reserved value endOfOrdTuple; see above assignment:

             ordTuple[2] := endOfOrdTuple;


       (ii) Let SysModDSBase construct the looping:

       GetFrstMObjStructEle(s,"mo.outStruct",mObjQualIdent,ordTuple);
       WHILE (mObjQualIdent[0]<>0C) DO
         i := ordTuple[0]+alpha; j := ordTuple[1]+theta;
         IF j=theta THEN
           BindMObjVar(s,mObjQualIdent,out[i].theta);
         ELSE (* j = y *)
           k := ordTuple[2]+1; l := ordTuple[3]+1;
           BindMObjVar(s,mObjQualIdent,out[i].y[k,l]);
         END(*IF*);
         GetNextMObjStructEle(s,"mo.outStruct",mObjQualIdent,ordTuple);
       END(*WHILE*);

  *)


  PROCEDURE MObjStructExists(mObjStructQualId : ARRAY OF CHAR): BOOLEAN;

  PROCEDURE UndeclMObjStruct(s                : System;
                             mObjStructQualId : ARRAY OF CHAR);

  PROCEDURE UndeclAllMObjStructs( s : System );


  (**********************************************)
  (*#####   Traversing Object Structures   #####*)
  (**********************************************)

  (*
    Following four procedures work also if you pass unknownSystem for
    parameter s in case the structure is of type outVar.
  *)

  PROCEDURE GetFrstMObjStructEle(s                 : System;
                                 mObjStructQualId  : ARRAY OF CHAR;
                                 VAR mObjQualIdent : ARRAY OF CHAR;
                                 VAR ordTuple      : ARRAY OF INTEGER);

  PROCEDURE GetNextMObjStructEle(s                 : System;
                                 mObjStructQualId  : ARRAY OF CHAR;
                                 VAR mObjQualIdent : ARRAY OF CHAR;
                                 VAR ordTuple      : ARRAY OF INTEGER);

  PROCEDURE GetEleIdent       (s                   : System;
                               mObjStructQualId    : ARRAY OF CHAR;
                               ordTuple            : ARRAY OF INTEGER;
                               VAR mObjQualIdent   : ARRAY OF CHAR);
  (*
    Returns in mObjQualIdent the identifier which denotes an element as
    given by the ordTuple within the structured model object
    mObjStructQualId.  E.g.  calling
    Model.p
      ordTuple[0] := 0; ordTuple[1] := 0; ordTuple[2] := 0; ordTuple[3] := 0;
      GetSubStructIdent(s,"Model.complexPar",ordTuple,mObjQualIdent);

    for a structure defined as:

      "S: p <0,1> *  * <0..2> >"

    returns in mObjQualIdent the identifier "Model.p0_m0_0".  This is
    because ordTuple defines as the ordination number for the first
    dimension the first matrix, plus the 2nd and 3rd dimensions refer to
    the dimensions of the actual matrix m (see also GetSubStructIdent).
    For instance the following code lets you learn about any identifier,
    i.e.  qualifEleIdent, of all elements in the structured model object
    "Model.complexPar":

      FOR i:= 0 TO 1 DO ordTuple[0] := i;
                          ordTuple[1] := j;
          FOR k:= 0 TO 2 DO ordTuple[2] := k;
            FOR l:= 0 TO 2 DO ordTuple[3] := l;
              GetEleIdent(s,"Model.complexPar",ordTuple,qualifEleIdent);
              (* referring to parameter p[i].m[k,l] *)
            END(*FOR*);
          END(*FOR*);
      END(*FOR*);

    based on these declarations:

      VAR
        p: ARRAY [0..1] OF RECORD
                            m: ARRAY [0..2] OF ARRAY [0..2] OF Parameter
                           END;

      VAR i: [0..1]; CONST j = 0; VAR k,l: [0..2];
        ordTuple: ARRAY [0..3] OF INTEGER;


    The actual identifiers (given you called DeclMObjStruct
    with parameter sepDimWithUL = TRUE) can be referenced via
    these ordination tuples:

      ordTuple       Identifier     ordTuple      Identifier

      0,0,0,0     Model.p0_m0_0     1,0,0,0    Model.p1_m0_0
      0,0,0,1     Model.p0_m0_1     1,0,0,1    Model.p1_m0_1
      0,0,0,2     Model.p0_m0_2     1,0,0,2    Model.p1_m0_2
      0,0,1,0     Model.p0_m1_0     1,0,1,0    Model.p1_m1_0
      0,0,1,1     Model.p0_m1_1     1,0,1,1    Model.p1_m1_1
      0,0,1,2     Model.p0_m1_2     1,0,1,2    Model.p1_m1_2
      0,0,2,0     Model.p0_m2_0     1,0,2,0    Model.p1_m2_0
      0,0,2,1     Model.p0_m2_1     1,0,2,1    Model.p1_m2_1
      0,0,2,2     Model.p0_m2_2     1,0,2,2    Model.p1_m2_2

  *)



  PROCEDURE BindMObjVar (s                : System;
                         mObjQualIdent    : ARRAY OF CHAR;
                         VAR obj          : MObjVar);

  (*
    Bind the model object variable obj (of type MObjVar = REAL)
    to the model object with identifier mObjQualIdent.  The
    latter has typically been declared by means of routine
    DeclMObjStruct (see above), which can't associate, i.e.
    bind, a particular real variable with the model object.
    Note this contrasts with the behavior of routine DeclMObj
    from module SysModBase, which binds the model object obj
    during the declaration.  Since this is not possible with a
    structured data type, you need to call BindMObjVar for
    every element in your data structure which functions as a
    model object.  Typically you traverse through your data
    structure by means of a loop similar to one of these
    techniques:

      (i)  programmed yourself

      FOR i:= 0 TO 1 DO T[0] := i;
                          T[1] := j;
          FOR k:= 0 TO 2 DO T[2] := k;
            FOR l:= 0 TO 2 DO T[3] := l;
              GetEleIdent(s,"Model.complexPar",T,qualifEleIdent);
              BindMObjVar(s,qualifEleIdent,p[i].m[k,l]);
            END(*FOR*);
          END(*FOR*);
      END(*FOR*);

      or

      (ii) let SysModDSBase construct the looping

      GetFrstMObjStructEle(s,"Model.complexPar",qualifEleIdent,T);
      WHILE (qualifEleIdent[0]<>0C) DO i := T[0]; k := T[2]; l := T[3];
        BindMObjVar(s,qualifEleIdent,p[i].m[k,l]);
        GetNextMObjStructEle(s,"Model.complexPar",qualifEleIdent,T);
      END(*WHILE*);

    and bind all involved varibles to the corrsponding model
    object declaration.

    Above examples were based on these declarations:

      VAR
        p: ARRAY [0..1] OF RECORD m: ARRAY [0..2] OF ARRAY [0..2] OF Parameter END;

      VAR i: [0..1]; CONST j = 0; VAR k,l: [0..2];
        T: ARRAY [0..3] OF INTEGER;
  *)


  PROCEDURE GetSubStructIdent (s                   : System;
                               mObjStructQualId    : ARRAY OF CHAR;
                               ordTuple            : ARRAY OF INTEGER;
                               VAR subStructQualId : ARRAY OF CHAR);
  (*
    Returns in subStructQualId the partial identifier which names the
    sub structure as given by the ordTuple with the structured model
    object mObjStructQualId. E.g. calling (T ~ ordTuple)

      T[0] := 0;        T[1] := 0;
      T[2] := undefOrd; T[3] := undefOrd;
      GetSubStructIdent(s,"Model.complexPar",T,subStructQualId);

    for a structure defined as:

      "S: p <0,1> *  * <0..2> >"

    returns in subStructQualId the identifier "Model.p0_m".  This
    is because T (ordTuple) defines only the ordination number for
    the first two dimension2; both other dimensions involved in
    the actual matrix m, are given as undefined only (confer
    GetEleIdent).  The first dimension designating which of the
    two matrices are to be referenced, points at the first one.
    On the other hand, calling

      T[0] := 1;        T[1] := 0;
      T[2] := undefOrd; T[3] := undefOrd;
      GetSubStructIdent(s,"Model.complexPar",T,subStructQualId);

    returns in subStructQualId the identifier "Model.p1_m".

    If you wish to learn about a substructure which requires
    only a few indices in ordTuple to specify it, you can temporarily
    reduce the length of the ordTuple array by using the reserved
    index value "endOfOrdTuple". E.g. with above structure

      T[0] := undefOrd; T[1] := undefOrd;
      T[2] := endOfOrdTuple;
      GetSubStructIdent(s,"Model.complexPar",T,subStructQualId);

    returns the main identifier of the complex parameter, i.e.
    subStructQualId = "Model.p".

    Substructures are of course only defined up to that level of
    recursion in the structure which are defined for all
    preceeding parts (left-side of structure) for any given
    substructure, in other words: "a branch cannot hang in the
    air!".  This implies that leaving a dimension undefined on
    which another substructure depends, will make it impossible
    for GetSubStructIdent to return a unique identifier.  E.g.
    calling

      T[0] := 0;        T[1] := undefOrd; T[2] := 0;
      T[3] := undefOrd; T[4] := undefOrd;
      GetSubStructIdent(s,"M.bigStructure",T,subStructQualId);
      GetSubStructIdent(s,"M.bigStructure",ordTuple,subStructQualId);

    for a structure defined as:

      "S: a < S: b < S: c < S: m <1,2>*<1,2> > >, beta >"

    returns in subStructQualId not "M.m" but only the empty
    string, since T[1] = undefOrd, and consequently T[2] = 0 has
    to be ignored, i.e. the substructure is not defined at all.  Only
    this

      T[0] := 0;        T[1] := 0;        T[2] := 0;
      T[3] := undefOrd; T[4] := undefOrd;
      GetSubStructIdent(s,"M.bigStructure",T,subStructQualId);

    returns the result "M.m".

    See also comments on procedures GetSubStructIdents and GetEleIdent.

    Hint: Use routine GetSubStructIdents if you want to learn
    about the identifiers of all substructures at once.
  *)


  PROCEDURE GetSubStructIdents (s                    : System;
                                mObjStructQualId     : ARRAY OF CHAR;
                                VAR subStructQualIds : ARRAY OF CHAR;
                                VAR n                : INTEGER);
  (*
    Returns in subStructQualIds all possible partial identifiers
    which name all sub structures of the structured model object
    mObjStructQualId.  The n individual identifiers are separated
    with delimiter "|".  This routine serves as a function for
    substructures with a purpose similar to that of the
    procedures GetFrstMObjStructEle and GetNextMObjStructEle for
    elements, i.e. to learn about all identifiers defined by
    the structured model object mObjStructQualId.  Ex.:

    Calling

      GetSubStructIdents(s,"M.bigStructure",subStructQualId,n);

    for a structure defined as:

      "S: a < S: b < S: c < S: m <1,2>*<1,2> > >, beta >"

    returns in subStructQualIds:

      M.m|M.c|M.b|M.a   and   n = 4

    since the structure defines these identifiers

          Identifier (elements)             T           #
          -----------------------------------------------
          M.m1_1                    0,0,0,0,0
          M.m1_2                    0,0,0,0,1
          M.m2_1                    0,0,0,1,0           5
          M.m2_2                    0,0,0,1,1
          M.abeta                   1 •

          Identifier (substructures)        T           #
          -----------------------------------------------
          M.m                   0, 0, 0,-1,-1
          M.c                   0, 0,-1 •               4
          M.b                   0,-1 •
          M.a                  -1 •

          • stands for an element with endOfOrdTuple, i.e. -2, in
            T: ARRAY [0..4] OF INTEGER;

   See also comments on procedures GetSubStructIdent and GetEleIdent.

  *)



  (*************************************)
  (*#####   Conversion Routines   #####*)
  (*************************************)

  PROCEDURE OrdTupleToStr(ordTuple: ARRAY OF INTEGER; sep: ARRAY OF CHAR;
                          VAR str: ARRAY OF CHAR);
  (*
    str is constructed up to HIGH(ordTuple) or only up to encounter of
    an element which is equal to endOfOrdTuple.
  *)

  PROCEDURE StrToOrdTuple(ordTupleStr: ARRAY OF CHAR; sepCh: CHAR;
                          VAR ordTuple: ARRAY OF INTEGER);
  (*
    IMPLEMENTATION RESTRICTION: sepCh must be a single character, thus can revert
    conversion of effect by OrdTupleToStr only if sep contained a single character.
  *)


END SysModDSBase.

  Contact RAMSES@env.ethz.ch Last updated: 25-Jul-2011 [Top of page]