The DSL for biogeochemical modeling allows to specify source-minus-sink-terms, compartments and connections between these compartments. The DSL allows to automatically generate graphics for models and evaluate models before execution.
Here we discuss the DSL syntax and semantics.
Model Structure
bgcModel: 'model' ID 'substances' substanceDeclaration+ ('parameters' parameterDeclaration*)? ('diagnostics' environmentVariableDeclaration*)? (compartment|connection)+ ;
The start rule defines that each model has a name (ID), declares a set of substances, parameters and diagnostic or environment values. Furthermore, a model comprises compartments and connections. There must be at least one substance declaration, parameter and diagnostic declarations are optional.
Declarations
substanceDeclaration: type=primitiveType ID unit ; parameterDeclaration: type=primitiveType ID unit "=" arithmeticExpression ; environmentVariableDeclaration: type=primitiveType ID unit ("=" expression=arithmeticExpression)? ;
Substances, parameters and diagnostics have a primitive data type which can be an integer, a floating point or a string. String types cannot be used for calculations. Each declaration also has a unit. Units help to ensure that calculations match the described unit and are a safeguard.
Parameters must and environment/diagnostic variables can be initialized with a value based on an arithmetic expression. These values are computed at start up time and then assigned to the parameters and diagnostics. Both variables can be changed during runtime using calculations.
Compartment
compartment: 'abstract'? 'compartment' ID ('extends' ID)? '{' 'states' substanceState+ ('parameters' parameterDeclaration*)? ('diagnostics' environmentVariableDeclaration*)? calculation* updateState+ '}' ;
Compartments have a name (ID), contain certain substances and can exchange substances with other compartments. They represent a major element in BGC models.
The DSL supports inheritance of compartments. To inherit from another compartment, its name must be specified after the extends keyword. This is helpful to specify shared features only once. To indicate that a compartment cannot be used directly, it can be declared abstract.
substanceState: substance=ID ("=" expression=arithmeticExpression)? ; updateState: 'update' state=ID "=" expression=arithmeticExpression ;
To handle substances in a compartment, it must be specified which substances belong to a specific compartment and how they are updated. Therefore, they are specified by specifying a substance. The respective substance can also be initialized by a specific value. In case it is not specified the value is 0.
To update the value, update rules can be specified that take in the old value and other values and parameters and calculate the resulting value of the state.
Connections
Connections allow to transfer matter between compartments. They have a name, may be restricted to a specific set of substances, and link two compartments. They can only specify the flow in one direction between two compartments, called source and target compartment.
connection: 'connection' ID ('(' ID (',' ID)* ')')? 'from' ID 'to' ID ("=" arithmeticExpression | '{' (substanceExpression | calculation)* '}') ;
There are two styles of connections:
- without substance arguments and one return value
- with substance arguments and one or multiple return values
Connections without substance arguments return one single value in their calculation which can be accessed by both compartments.
To be more constraint and reduce potential errors, connections can be restricted to specific substances and then return a vector of values. The vector values can then be accessed in a calculation or and state update by suffixing the name of the connection, e.g.,
connection assimilation(N) from Phy to Het = Phy.N/10 compartment Phy { state N update N = N - assimilation.N }
The above example uses only one return value. To express multiple return values, we can use substance expressions:
substanceExpression: substance=ID '=' expression=arithmeticExpression ;
They allow to assign to each connection substance argument one assignment.
connection assimilation(N, P) from Phy to Het { N = Phy.N/10 P = (Phy.P-Het.P)/20 }
Calculations
Calculations are short expressions that can be used in different expressions and reduce the effort to implement the same sub-expressions over and over again to avoid errors, make the code more concise and better to read.
calculation: basicCalculation | alternativeCalculation; basicCalculation: 'calc' ID "=" expression=arithmeticExpression ; alternativeCalculation: 'alternatives' ID ':' arithmeticExpression '{' basicCalculation* '}' ;
Semantics of alternative expressions are currently developed.