CSR: Type file

From VLECK
Jump to: navigation, search

Type definition files define the structure of the simulated entities in the model, their parameter values, and their initial states. They serve as intermediate files between the parameter database and the model, so the model can run without having acces to the parameter database. The types define the capabilities of the simulated entities, but not their behaviour, which is written down in python code. The types do, however, relate the entities to specific implementations, i.e. classes in python code. Type do not specify individual plants or animals or whatever.

A partially valid anology is to see types as species to which individual instances in the simulated area belong. The CSR-model can have multiple type definitions files, e.g. one for plants, on for animals, and one for soil types. In the current implementation, the types for plants and animals are defined in the same type definitions file.

general

The type file follows the XML-syntax. It consists of two blocks:

  1. parameter definitions: define for each parameter used by any of the types the name and SI-unit.
  2. type definitions: define structure, parameter values, initial values, etc. of each type.
file structure
<typology>
   <parameter_definitions>
      <paramdef name="Parameter1" unit="SI-UNIT" description="any text"/>
      <paramdef name="Parameter2" unit="SI-UNIT" description="any text"/>
      <paramdef name="Parameter3" unit="SI-UNIT" description="any text"/>
      ...
   </parameter_definitions>
   <types>
      <type name="Type1"/>
      <type name="Type2" supertype="Type1"/>
      ...
   </types>



parameter definitions

Parameters are defined by the tag paramdef. The tag has three required attributes:

  1. name: the name of the parameter (case sensitive!)
  2. unit: the unit declaration. Compound units have their elemets connected by dots (eg. "kW.h") may be entered either in power notation or with a single forward slash. So: "kg.m2.s-1" is equivalent to "kg.m2/s".
  3. description: any text describing the parameter.


parameter definition
<paramdef name="Gmax" unit="mmol.m-2.s-1" description="water vapour max. conductance"/>



type definitions

general structure

The type definition is a compound structure that consists of the following blocks:

  1. parameters: assign the parameter values
  2. states: define state variables and their initial values
  3. components: define structure of the type
  4. functional_types: inherite properties from other types
  5. details: define additional information

Note: For simplicity, the surrounding tags parameters, states, components functional_types and details may be left out (s. second example).


example
<type name="Plant" implementation="plantcohort">
   <states>
    <state name="weight">5.0</state>
   </states>
   <parameters>
    <parameter name="LeafWidth">0.04</parameter>
    <parameter name="Gmax">450.</parameter>
    <parameter name="Gmin">1.</parameter>
   </parameters>
   <components>
    <component name="foliage">
       <components>
        <component name="composition" \>
       </components>
       <parameters>
        <parameter name="cAllocNPP">0.5</parameter>
       </parameters>
    </component>
   </components>



example
<type name="Plant" implementation="plantcohort">
  <state name="weight">5.0</state>
  <parameter name="LeafWidth">0.04</parameter>
  <parameter name="Gmax">450.</parameter>
  <parameter name="Gmin">1.</parameter>
  <component name="foliage">
    <component name="composition" \>
    <parameter name="cAllocNPP">0.5</parameter>
  </component>



parameters

Parameters of a type refer to parameters defined in the parameter_definitions-section of the file. The format of a parameter usage assignment is

xml
<parameter name="'''name'''">'''value'''</parameter>


name must correspond to a definition in parameter_definitions.
value is the value of the parameter.

By means of inheritance (see below), parameters can be inherited and overridden.
Components inherit their owners's parameters and may override them.

usage: Components can access their own and their owner's parameters through the parameter-member. Since the units conversion is as costly procedure in terms of execution time, it is best to pick up the parameter value before the main integration loop (but not in __init__()!). E.g.:

parameter usage
def initializeAtT0(self):
  # two equivalent ways of accessing parameter values:
  self.SLA        = self.parameters.cSLA.m2_per_m2 
  self.LeafWidth  = self.parameters["LeafWidth"].as("m")



states

The States of a type define its [CSR:state variable|state variables]. The definition of a state may be done in simple or in extended syntax:

simple state definition
<state name="name" unit="unit">value</state>



extended state definition
<state name="name" unit="unit">
       <initial age="age1">value1</initial>
       <initial age="age2">value2</initial>
    </state>


In the simple syntax, value is the initial value of the state; in the extended syntax value1 & value2 are the initial values for states of instances initialised at age age1 & age2 respectively. (The selected initial value is the one where the corresponding age is no greater then the indivuals age at initialisation time). The unit-attribute serves as metadata and is translated in the unit-attribute of the State-object, There, it can be checked at runtime.

components

Components are composites, or each component can have zero to inifinite member elements. The Components-definition block therefore is recursive. The definitions of components equal those of types, except that a component cannot inherit properties.

examples
<component name="foliage" type="PlantOrgan" implementation="Foliage">
  <parameter name="cAllocNPP">0.5</parameter>
</component>



processes

Processes represent "dynamic things that happen", in contrast to components that represent "static things that are". Examples of processes are photosynthesis, transport, and allocation. Processes can have states and parameters, but are not heritable from other processes. Often it will be more convenient to define processes in code rather than in the type-file, but both options may be used.

details

Any info that neither fits in the type-definition template nor can be hard-coded may be entered as def here, e.g.:

xml
<details>
    <def name="litterLayerType">litter</def>
    <def name="layersAndDepths">layer0=1.0, defaultLayer=2.0, defaultLayer=3.0</def>
    <def name="resources">nitrogen, phosphorous, water, carbon</def>
 </details>


In this example from the soil definition, resources is a true additional setting.
The layer-items on the other hand, could also have been defined as components. However, since a limited number of layer types are used by a potentially large number of soil types, (ab-)using details save a lot of repetitive definitions. This is not so much a matter of less typing as of creating single points of maintenance. Bypassing the instantiation system in such a way must of course be backed up by changes in the code.

code example
def _assignFromType(self, aComponentType):
    super(SoilLayer, self)._assignFromType(aComponentType)
    self._bottom  = float(aComponentType.settings["bottom"])



type inheritance

Types can inherit properties in a hierarchical fashion by assigning the supertype attribute, and in a functional (multiple inheritance) way by adding the appropriate definitions in the functional_types section.

supertype

See the example below:

Plant
<type name="Plant" implementation="plantcohort">
     <states>
        <state name="weight">5.0</state>
     </states>
     <parameters>
        <parameter name="LeafWidth">0.04</parameter>
        <parameter name="Gmax">450.</parameter>
        <parameter name="Gmin">1.</parameter>
     </parameters>
     <components>
        <component name="foliage"/>
     </components>
  </type>



Tree ("is a" Plant)
<type name="Tree" supertype="Plant">
     <states>
        <state name="crownHeight"/>
     </states>
     <parameters>
        <parameter name="Gmin">1.5</parameter>
        <parameter name="c" unit="mol.m-2.s-1" note="orig.: umol">12.103</parameter>
     </parameters>
  </type>



Here Tree defines Plant as supertype. This means that all parameters, states, components, etc. of Plant are automatically added to Tree too. In addition Tree defines the state crownHeight and the use of parameter c. Note that it redeclares parameter Gmin with a new value: for Plant Gmin has the value 1. and for Tree it has the value 1.5.

So, with supertype a type can

  • include everything from a more abstract type
  • change values of inherited properties

It cannot discard inherited properties.

functional types

Functional types allow overriding parameters beyond the hierarchical line. See the example below:


Tree
<type name="Quercus ilex" supertype="Tree">
     <parameters>
        <parameter name="Gmax">500.</parameter>
     </parameters>
     <functional_types>
        <functional_type name="Broadleaved"/>
        <functional_type name="Evergreen"/>
     </functional_types>
  </type>



Evergreen
<type name="Evergreen" supertype="functional type">
     <parameters>
        <parameter name="Gmin">10.</parameter>
     </parameters>
  </type>



Broadleaved
<type name="Broadleaved" supertype="functional type">
     <parameters>
        <parameter name="LeafWidth">0.06</parameter>
        <parameter name="Gmin">15.</parameter>
     </parameters>
  </type>



Quercus ilex is a tree for it inherits everything that makes a Plant to a tree by setting its supertype to Tree. In addition, it defines that it is both a Broadleaved Tree and an Evergreen Tree by including those in its functional_types section. In this example, Broadleaved adds a parameter names LeafWidth and sets a new value for the existing parameter Gmin.

Note however, that this in fact is a case of multiple inheritance which introduces the possibility of conflicting definitions. Look at the parameter Gmin: From Tree the value of 1.5 is inherited, Evergreen redefines it to 10. and BroadLeaved to 15. Which one will be the resulting value?

The inherited value has the lowest priority. So it won't be 1.5. The type's own parameter definitions have the highest priority. So would we have been discussing Gmax instead of Gmin, the value would unambiguousy have been 500. But Quercus ilex does not redefine Gmin, so it must come from its functional types. There is not order within a functional_types block, so no decission can be made here. The resulting value will be arbitrary, 10. or 15.

The modeler ought to have avoided this ambiguous defintion, either by changing at least one of the functional type definitions, or by including Gmin in the Quercus ilex-type's own parameter definitions.

linking types to code

An area is populated by refering to the names of the types. Knowing the name, does not yet give insight into which piece of python code will represent the behaviour of the instances. To make this connection, a type may include the attribute implementation.

xml
<type name="Plant" implementation="plantcohort">



The string "plantcohort" equals the tag by which the pyton class PlantCohort (plantcohort.py) is registered. Have a look at class_registration.py to see how this link is made, or to add your own classes:


class_registration.py
# registration for typed auto-instantiation (s. typology).
from Plant.plantcohort import PlantCohort
from animal.herbivoreCohort import HerbivoreCohort
from soil.litterLayer import LitterLayer
from soil.soilColumn import SoilColumn
from soil.soilLayer import SoilLayer
from soil.soilComponent import MineralComponent
 
 
PlantCohort.registerClass("plantcohort")  
HerbivoreCohort.registerClass("herbivore")
LitterLayer.registerClass("litterLayer")
SoilColumn.registerClass("soilColumn")
SoilLayer.registerClass("soilLayer")
MineralComponent.registerClass("MineralComponent")