The prediction model library contains the implementations of prediction models used in the simulation. The model library may be written in C or in Python.
The model library implemented in C includes source and header files.
The header file begins by defining a precompiler macro that directs the building of the shared libraries on different operating systems (dll, dylib, so). Dll is used as a convention for the filetype extension on all platforms. When compiling you should pass the value of the MODE parameter to the compiler (-D option on gcc). MODE==1 is for Windows and MODE==3 is for Mac or Linux. MODE==2 is used on Windows when compiling an aggregation library out of individual model library source files (links between model libraries). In that case none of the functions will be marked for exporting outside the dll, except for the functions in the aggregation library:
#if MODE==1
# define DLLEXPORT __declspec (dllexport)
#elif MODE==2
# define DLLEXPORT
#elif MODE==3
# define DLLEXPORT
#endif
Also numeric constants should be defined here.:
#define PI 3.1415926535897932
In the header file all the implemented functions must be defined. The model function definitions follow a simple rule: First define the actual model variables; d, D_domvmi, i_Hdom5, cd, CR_domvmi, RDF_L in the Height_growth_pine_Hynynenym function. The number of these variables naturally varies between models. These variables are follwed by a standard part repeated exatcly same for all the functions: int *nres (number of results), double *modelresult (the actual modelresult), char *errors (any error messages generated during the function call), int errorCheckMode (error checking mode - currently unused, but must be present), double allowedRiskLevel allowed risk level - currently unused, but must be present) and double rectFactor (rectification factor, used to multiply the model result if set, defaults to 1.0). This standard function signature allows dynamic call generation in the simulator core.:
DLLEXPORT int Height_growth_pine_Hynynenym (double d, double D_domvmi,
double i_Hdom5, double cr, double CR_domvmi, double RDF_L,
int *nres, double *modelresult, char *errors, int errorCheckMode,
double allowedRiskLevel, double rectFactor);
DLLEXPORT int Height_growth_spruce_Hynynenym (double d, double D_domvmi,
double i_Hdom5, double cr, double CR_domvmi, double RDF_L,
int *nres, double *modelresult, char *errors, int errorCheckMode,
double allowedRiskLevel, double rectFactor);
...
In the actual source file, the included header files are first listed:
#include "DynamictreemodelLibrary.h"
#include "SimoUtils.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
Followed by the function definitions:
int Height_growth_pine_Hynynenym(double d, double D_domvmi, double i_Hdom5,
double cr, double CR_domvmi, double RDF_L,
int *nres, double *modelresult, char *errors,
int errorCheckMode, double allowedRiskLevel,
double rectFactor) {
int ret = 1;
//Check for fatal errors
char errorStr[200] = "";
if (D_domvmi<=0)
{
ret = 0;
constructErrorMessage (errorStr, "D_domvmi<=0(D_domvmi=",D_domvmi);
}
if (CR_domvmi<=0)
{
ret = 0;
constructErrorMessage (errorStr, "CR_domvmi<=0(CR_domvmi=",CR_domvmi);
}
if (ret == 0) {
strcat(errors, errorStr);
return 0;
}
//To avoid problems caused by very little diameter minimum diameter for '
// pine is 0.1 cm!
if (d<0.1)
d=0.1;
*nres = 1;
double res =i_Hdom5*pow((d/D_domvmi),(0.80171*pow(i_Hdom5,0.4353)-0.49724*
(cr/CR_domvmi)-0.64383*cr+0.08193*RDF_L));
*modelresult = res * rectFactor;
return ret;
}
TODO: write an example of using structs as model results.
The C-functions compiled into dll files must be accompanied by Python wrapper modules for the simulator to be to call the functions. There is an utility script for generating the wrapper module files based on the C header files. If you have the development distribution of SIMO, you can find the script in src/utils folder, it’s called hToPyWrap.py. See its content for usage. The generated wrappers should be in the same folder as the model dll-files.
Each model definition must be of the form:
def model_name(arg, object_index):
in which:
The arg data object is an instance of PredictionArg class (see simo.simulation.model.predictionarg) and has a structure described below with examples on how to access the object attributes.
The values of the input variables of the model. The number and order of these must match with the variable declarations in the variables section of the model definition in the model xml file:
arg.variables[variable_index, object_index]
The model parameter values. The order in which these are used must match the order given in the parameters section of the model xml file:
arg.parameters[parameter_index]
Number of result objects. This is always 1 unless the prediction model really creates new objects; e.g. in stem distribution models each diameter or height class is a new object:
arg.nres[object_index]
Stores the model results. Again the results must be stored here in the same order as defined in the result/variables section of the model xml file:
arg.mem[variable_index, result_index]
For storing possible error messages. Before actually evaluating the model, you should test for error situations and set error messages detailing why the model can’t be evaluated and then exit:
arg.errors[object_index]
When getting or setting the attribute values of arg, object_index is always used for the object_index; e.g. the value of the first explaining variable of the model is accessed by arg.variables[0][oind]. As can be seen from the example indices always start from 0.
The model must return an integer as its return value. 1 if there were no errors and 0 if errors occurred.