Manual del modelizador

Transcripción

Manual del modelizador
JUL 2015
Universidad de Valladolid – Instituto Universitario de Gestión
Forestal Sostenible
Felipe Bravo Oviedo
Celia Herrero de Aza
Cristóbal Ordóñez
[GUIA PARA LA
PROGRAMACIÓN DE
MODELOS EN
SIMANFOR]
Guia de uso de simanfor para modelizadores: detalles necesarios para la introducción
exitosa de modelos en la plataforma
Manual del modelizador
Índice
Introducción.............................................................................................................................................3
Proceso de ejecución de modelos........................................................................................................3
Caso de modelos de árbol individual..........................................................................................3
Caso de modelos de masa...........................................................................................................5
Programacion de Modelos.....................................................................................................................6
Programación de modelos de árbol individual...........................................................................9
Ejemplo de programación de un modelo de árbol individual..................................................12
Programación de un modelo de masa......................................................................................17
Ejemplo de programación de un modelo de masa..................................................................18
Detalles técnicos de SiManFor..................................................................................................21
Lenguaje de programación...............................................................................................21
Estructura de los modelos.................................................................................................22
Biblioteca de clases...........................................................................................................22
Navegación.........................................................................................................................23
Seguridad............................................................................................................................23
Programación con C#.NET...............................................................................................23
Ayuda de bibliotecas de clases........................................................................................23
Resumen de características técnicas de los modelos de crecimiento........................24
2
Manual del modelizador
Introducción
SiManFor es una herramienta que permite ejecutar modelos de crecimiento sobre inventarios
forestales para distintas especies forestales. Con ellos se pueden ejecutar “escenarios
selvícolas” que además de simular crecimiento permiten incluir intervenciones selvícolas,
análisis de mortalidad y regeneración, factores de competencia, etc. Los usuarios con permisos
de modelizador pueden programar estos modelos, para lo que es necesario conocer los
detalles técnicos de los mismos y la forma en que son cargados y ejecutados por la aplicación.
En este manual vamos a detallar los conceptos y tareas necesarios para realizar esta labor.
En SiManFor se pueden programar dos tipos de modelo diferentes: modelos de masa y
modelos de árbol individual. Para cada caso hay que utilizar una plantilla diferente tal y como se
detalla a continuación.
Proceso de ejecución de modelos
La ejecución de los modelos pasa por varias fases en las que se indica a la plataforma qué
árboles (o qué variable de parcela, si el modelo es de masa) debe procesar para obtener un
nuevo inventario con los resultados. En los diagramas 1 y 2 se puede ver la estructura de cada
tipo de modelo y las funciones asociadas a cada fase (parte derecha).
Caso de modelos de árbol individual
A continuación se detalla el significado de las fases por las que pasan los modelos:
1. Inicialización: Permite al modelo calcular las variables no disponibles en el propio
inventario pero necesarias para la ejecución del modelo. Se ejecuta una vez por cada
pie mayor incluido en el escenario.
2. Supervivencia: Determina si un árbol sobrevive o no al paso del tiempo. Se ejecuta una
vez por cada árbol incluido en el escenario.
3. Crecimiento: Modifica las propiedades (variables) del árbol nuevo después de la
proyección temporal. Se ejecuta una vez por cada árbol vivo del escenario.
4. Masa Incorporada: Realiza la inclusión de nuevos árboles al escenario al alcanzar un
tamaño inventariable. Se ejecuta una sola vez.
5. Posprocesado de parcelas: Permite al modelo el cálculo de variables derivadas
similares a las que se calcularon en el apartado de inicialización, tras los cambios
producidos en variables de árbol y parcela en las fases anteriores.
3
Manual del modelizador
Diagrama 1 - Estructura de un modelo de árbol individual en SiManFor
4
Manual del modelizador
Caso de modelos de masa
El diagrama 2 muestra el flujo de ejecución de un modelo de masa. Hay una primera función en
la que se calculan las variables necesarias para la ejecución del modelo ( Initialize), otra
función para hacer que la masa evolucione “year” años ( ApplyModel), y finalmente una función
que permite determinar la forma en la que las variables de masa cambian tras una intervención
silvícola (ApplyCutDown).
Diagrama 2 - Estructura de un modelo de masa en SiManFor
5
Manual del modelizador
Programacion de Modelos
Los modelos que se programan en SiManFor siguen el estándar de C#, y es necesario iniciarlos
con una serie de declaraciones que indican las librerías que se van a utilizar:
using System;
using System.Collections.Generic;
using Simanfor.Core.EngineModels;
En el caso de modelos de masa también hay que incluir la siguiente librería:
using Simanfor.Entities.Enumerations;
A continuación debe indicarse el espacio de trabajo y la plantilla, que son inherentes a cada tipo
de modelo y no se pueden modificar por el modelizador. En el caso de modelos de árbol
individual son los siguientes:
namespace EngineTest
{
public class Template : ModelBase
{
/// Todas las funciones y procedimientos del modelo irán entre estas llaves
}
}
Mientras que para un modelo de masa son:
namespace EngineTest
{
public class MassModelTemplate : MassModelBase
{
/// Todas las funciones y procedimientos del modelo irán entre estas llaves
}
}
Las variables que se pueden emplear en un modelo en SiManFor son de dos tipos: las definidas
por el modelizador o las dependientes de la base de datos almacenada en SiManFor. Para el
caso de variables definidas por el modelizador es necesario indicar el “tipo” de variable; por
ejemplo para una variable “numero real” cuyo nombre sea “diametroMinimo” y su valor inicial
sea “0” la instrucción sería:
double diametroMinimo = 0;
Si las variables dependen de los inventarios almacenados en SiManFor no será necesario
declararlas
para
poder
utilizarlas,
pero
hay
que
seguir
escrupulosamente
los
6
Manual del modelizador
convencionalismos asociados a la programación orientada a objetos. Estas variables poseen un
modelo de datos similar al “SiManFor Data Model” (SDM), que es el formato en el que se
“suben” los datos a la plataforma, pero distinto en cuanto a las entidades (variables) con las
que puede trabajar. Esta versión del SDM es bastante más reducida, dado que para la
ejecución de un modelo sólo se utilizan dos tablas (una con información a nivel de árbol y otra a
nivel de parcela) en las que se agrupan varias de las tablas originales.
Para ello hay que fijarse en las propiedades asociadas al objeto (variable) y tener en cuenta de
qué tabla de datos depende: “Parcela” o “PieMayor”. Además, dependiendo de la función con
la que se esté trabajando, la forma de acceder a la base de datos es diferente ya que las
variables que se pueden utilizar deben estar declaradas en el encabezado (esta declaración
depende de la función y no puede ser modificada por el modelizador). Por ejemplo, para una
variable de la base de datos “Parcela” asignada al objeto “plot”, la forma de referirse a las
variables que contiene es la siguiente (ej. de altura dominante):
public override void CalculateInitialInventory(Parcela plot)
/// En la funcién está declarada “plot” como variable de entrada de la tabla “Parcela”
{
plot.SI = plot.H_DOMINANTE.Value/10;
/// asignamos a SI (variable de parcela) el valor de H_DOMINANTE dividido por 10
}
Si queremos utilizar o cambiar variables de árbol en una función como la anterior (que no
declara un objeto de la base de datos “PieMayor”) podemos acceder a ellas con un bucle que
recorre todos los pies mayores que están en el objeto que sí se ha declarado: ”plot”. Esto lo
podemos hacer de la siguiente forma:
public override void CalculateInitialInventory(Parcela plot)
/// En la funcién está declarada “plot” como variable de entrada de la tabla “Parcela”
{
foreach (PieMayor tree in plot.PiesMayores)
{
tree.ALTURA = 27; // asigna el valor 27 a todos los “tree” que estén dentro de “plot”
}
}
Si la función elegida tiene declarada la clase “PieMayor”, la forma de referirse a la variable es
más sencilla:
public override double Survives(double years, Parcela plot, PieMayor tree)
{
double treeSurvival = 1.0F; /// declaramos una variable de usuario
tree.ALTURA = plot.H_DOMINANTE.Value +
Math.Normal(1,-5)
7
Manual del modelizador
/// asignamos a la variable de árbol ALTURA el valor de la altura dominante
return treeSurvival;
}
Además se puede acceder a otras propiedades de los objetos (variables) como por ejemplo
“HasValue”, que es de tipo lógico e indica si hay un valor almacenado en la misma. La
instrucción que lo permite es de la forma:
tree.ALTURA.HasValue
Los inventarios con los que trabajan los modelos son creados internamente por la aplicación
durante la ejecución del mismo y pueden proceder de dos fuentes distintas:
1. Inventario original, tras aplicar los criterios de filtrado que el usuario haya seleccionado.
2. Inventario resultante de aplicar un modelo o una corta previamente.
En ninguno de los dos casos el modelo de crecimiento trabaja con los datos del SDM, sino que
siempre lo hace con una versión especial de inventarios que se usa para almacenar
temporalmente los datos que se van generando en cada paso.
A continuación se listan todas las variables almacenadas en la base de datos (inventarios de
SiManFor). Los nombres deben respetarse en la programación, siguiendo las indicaciones
precedentes para referirse a ellas. En la tabla 1 se muestran las variables de parcela y las de
árbol en la tabla 2.
Tabla 1. Variables de parcela
ID_INVENTARIO – identificador
ESTADILLO – identificador de parcela
ID – identificador
A_BASIMETRICA – en m2/ha
H_DOMINANTE – en m
N_PIES – en arboles/parcela
N_PIESHA – en arboles/ha
EDAD – en años
D_MEDIO – diámetro medio en cm
D_CUADRATICO – diámetro cuadrático medio en cm
D_DOMINANTE – diámetro dominante en cm
D_MAX – diámetro máximo en cm
D_MIN – diámetro mínimo en cm
H_MEDIA – altura media en m
DM_COPA – diámetro medio de copa en m
DG_COPA – diámetro cuadrático medio de copa
en m
I_REINEKE – índice de densidad de rodal
I_HART – índice de Hart
FCC – fracción de cabida cubierta %
SI .- índice de sitio en m
Variables adicionales :
VAR_1
VAR_2
VAR_3
VAR_4
VAR_5
VAR_6
VAR_7
VAR_8
VAR_9
VAR_10
Tabla 2. Variables de árbol
ID– identificador
ID_INVENTARIO– identificador
ESTADILLO– identificador de parcela
ID_PARCELA– identificador de parcela interno
ARBOL – identificador de árbol
NUMEROINDIVIDUOS – numero de arboles a los
que representa el registro (para clases)
ESPECIE – según código IFN
DIAMETRO_1– diámetro 1 en cm
INCLINACION – inclinación
REC – rectitud del fuste
RAM – ramosidad del fuste
CONICIDAD – conicidad del fuste
PUDRICION – nivel de pudrición
CLAS_PIE – clasificación madera en pie
CLASE_SOCIOLOGICA – Clase sociológica
VCC – volumen en cm3
VSC– volumen sin corteza en cm3
ALTURA_TOC – altura del tocón
ANCHO_CM_1 – ancho de copa en m
ANCHO_CM_2
RADIO_C_1 – radio de copa en m
RADIO_C_2
RADIO_C_3
RADIO_C_4
LCW – máxima anchura de copa en m
C_MORFICO – coeficiente mórfico
8
Manual del modelizador
Tabla 2. Variables de árbol
DIAMETRO_2– diámetro 2 en cm
CALIDAD – Calidad
FORMA - Forma de cubicación
ALTURA– altura total en m
PARAMESP – parámetros especiales
OBSERVACIONES – observaciones
DAP – valor medio de diámetro 1 y 2
CORTEZA_1 – espesor en mm
CORTEZA_2 – espesor en mm
CORTEZA – espesor medio en mm
CIRCUNFERENCIA – en cm
EXPAN – factor de expansión a la hectárea
ESBELTEZ – relación altura/diámetro (m/cm)
SEC_NORMAL – en m2
EDAD130 – edad del árbol tomada a 1,3 m del suelo
IAVC – Incremento Anual de volumen con corteza
VLE – volumen de leñas
BAL – área basimétrica de los arboles mas
gruesos que el individuo en m2/ha
CR – índice de copa viva
SECCION_COPA_MAXIMA – sección copa máx.
EDAD_BASE– edad del árbol en la base
DIAMETRO_MIN - Diámetro mínimo en cm
DIAMETRO_4 – Diámetro a 4 metros en cm
FCV – fracción de copa viva
ALTURA_BC – altura a la base de la copa en m
ALTURA_MAC– altura al máximo ancho de la
copa en m
ALTURA_RM – altura a la primera rama viva en m
ALTURA_VV – altura al primer verticilo vivo en m
C_FORMA - cociente de forma
PERC_DURAMEN - %duramen
Variables adicionales no definidas
VAR_1
VAR_2
VAR_3
VAR_4
VAR_5
VAR_6
VAR_7
VAR_8
VAR_9
VAR_10
En cada conjunto de datos se han incluido otras 10 variables, denominadas VAR_1, VAR_2, ...
VAR_10. Estas pueden ser empleadas por los modelizadores en caso de que su modelo incluya
variables no definidas en la base de datos. Estas variables no se pueden cambiar de nombre,
pero se puede modificar el output para que el usuario final pueda identificarlas (se detallará
cómo en el manual de uso personalizado de “outputs”).
Asimismo es necesario indicar en el modelo qué valores hay que almacenar en estas variables.
Por ejemplo, si queremos utilizar una variable de biomasa (biomasa del fuste), podemos
calcular su valor en el modelo, y almacenarlo en una de las variables adicionales (ej. VAR_1).
Sabemos que cuando en el output vemos VAR_1, su valor hará referencia a la biomasa del
fuste.
Si queremos facilitar la lectura al usuario final también podremos modificar el output de forma
que se cambie la etiqueta de la columna y en lugar de VAR_1 aparezca “BiomasaFuste”.
Programación de modelos de árbol individual
Para incluir un modelo de árbol individual es aconsejable utilizar el modelo que se puede
descargar de la plataforma. Además se puede descargar un ejemplo de modelo completo que
puede ayudar a la programación de nuevos modelos.
Es importante tener en cuenta que el flujo de ejecución de un modelo de árbol individual es
como indica el diagrama 1. El orden de esta imagen es el que regula el funcionamiento del
escenario, independientemente del orden en el que aparezca en la plantilla del modelo.
A partir de la lectura del inventario hay una función en la que se calculan las variables de
inicialización necesarias para la ejecución del modelo ( CalculateInitialInventory). Por
9
Manual del modelizador
ejemplo, se puede calcular la altura a la que la copa es más ancha o a la base de la copa, si se
necesitan para el modelo, ya que son variables que no se miden habitualmente en los
inventarios forestales. También es posible calcular para todos los individuos variables que, en
algunos inventarios se miden únicamente para algunos pies, como la altura total. Para ello se
pueden utilizar propiedades de la variable que indican si tiene almacenado algún valor o no.
/// <summary>
/// Procedimiento que permite la inicialización de variables de parcelas necesarias
/// para la ejecución del modelo. Solo se ejecuta en el primer nodo.
/// Variables que deben permanecer constantes como el índice de sitio deben calcularse
/// solo en este apartado del modelo
/// </summary>
/// <param name="plot"></param>
public override void CalculateInitialInventory(Parcela plot)
{
/// funcion que permite el acceso ordenado a la base de datos
/// (p.ej. para calcular el BAL mas rapidamente)
IList<PieMayor> piesOrdenados = base.Sort(plot.PiesMayores, new
PieMayorSortingCriteria.DescendingByField("DAP"));
foreach (PieMayor tree in plot.PiesMayores)
{
/// se calculan las variables de árbol en este bucle
}
/// se calculan las variables de parcela en este apartado
}
A continuación tenemos las funciones que desarrollan el modelo ( Grow,
NewTreeDistribution y Survives).
AddTree,
En la primera se calcula el crecimiento:
/// <summary>
/// Procedimiento que permite modificar las propiedades del árbol durante su crecimiento después de
"years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="oldTree"></param>
/// <param name="newTree"></param>
public override void Grow(double years, Parcela plot, PieMayor oldTree, PieMayor newTree)
{
/// Ecuaciones que permiten programar como cambian las variable en “years” años
}
Según la declaración del encabezado es una función pública ( public), en la que se sobreescribe
el código por defecto (override) y no devuelve ningún valor ( void). Todas las modificaciones que
ejecuta la función se hacen sobre el inventario temporal.
10
Manual del modelizador
La masa incorporada se calcula en la siguiente:
/// <summary>
/// Procedimiento que permite añadir nuevos árboles a una parcela después de "years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <returns>Area basimetrica a distribuir o 0 si no hay masa incorporada</returns>
public override double? AddTree(double years, Parcela plot)
{
return 0.0F;
}
Esta función devuelve un valor real entero ( double?) que se utilizará en la siguente función, que
calcula
la
distribución
de
la
masa
incorporada,
como
variable
de
entrada
(AreaBasimetricaIncorporada):
/// <summary>
/// Expresa como se ha de distribuir la masa incorporada entre los árboles existentes.
/// La implementación por defecto la distribuye de forma uniforme.
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="AreaBasimetricaIncorporada"></param>
/// <returns></returns>
public override Distribution[] NewTreeDistribution(double years, Parcela plot, double
AreaBasimetricaIncorporada)
{
/// Hay que definir una matriz (distribution) que pertenece a la clase Distribution
/// que tiene 3 propiedades: diametro menor (.diametroMenor), diametro mayor (.diametroMayor)
///
y área basimetrica que se añadira al rango diamétrico (.AreaBasimetricaToAdd)
return distribution;
}
Esta función devuelve una matriz (distribution) que usa la plataforma internamente para añadir
árboles resultado del ingrowth. Finalmete tenemos una función para calcular la supervivencia:
/// <summary>
/// Función que indica si el árbol sobrevive o no después de "years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="tree"></param>
/// <returns>Devuelve el porcentaje de árboles que sobreviven</returns>
public override double Survives(double years, Parcela plot, PieMayor tree)
{
/// Ecuaciones que calculan el % de árboles que sobreviven tras “years” años
return survive;
}
11
Manual del modelizador
Esta función devuelve una variable real que utiliza SiManFor para calcular el porcentaje de
árboles que sobrevive. Cuando ese valor es menor de 1, se duplica el registro completo; al
original se le cambia el valor de la variable
EXPAN,
asignandole el valor
EXPAN*survive,
y al registro
duplicado EXPAN*(1-survive) y a variable ESTADO el valor “M”.
La parte final de un modelo de árbol individual es el recálculo de variables una vez que el árbol
ha crecido, y teniendo en cuenta los incorporados y la mortalidad (ProcessPlot).
/// <summary>
/// Procedimiento que realiza los cálculos sobre una parcela
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="trees"></param>
public override void ProcessPlot(double years, Parcela plot, PieMayor[] trees)
{
/// Instrucción que permite el acceso ordenado a la base de datos
IList<PieMayor> piesOrdenados = base.Sort(plot.PiesMayores, new
PieMayorSortingCriteria.DescendingByField("DAP"));
foreach(PieMayor tree in piesOrdenados)
{
/// se calculan las variables de árbol en este bucle
}
/// se calculan las variables de parcela en este apartado
}
Ejemplo de programación de un modelo de árbol individual
En este ejemplo se desarrolla el modelo de árbol individual para pino silvestre en Castilla y
León, IBERO Ps 2010.
using System;
using System.Collections.Generic;
using Simanfor.Core.EngineModels;
namespace EngineTest
{
/// <summary>
/// Todas las funciones y procedimientos son opcionales. Si se elimina cualquiera de ellas, se usará un
/// procedimiento o funcion por defecto que no modifica el estado del inventario.
/// Modelo IBERO, 2010, Pinus sylvestris (Castilla y Leon)
/// </summary>
public class Template : ModelBase
{
/// declaracion de variables publicas
/// como es una variable incluida en la base de datos,
/// primero se pone el conjunto al que pertenece y luego el nombre
12
Manual del modelizador
En este modelo, el volumen de cada árbol se calcula por integración, para lo que es necesario
definir la función de perfil al margen de las funciones predeterminadas. La variable a integrar
será el radio al cuadrado. Para este proposito definimos dos funciones, una con corteza
(r2_conCorteza) y otra sin corteza ( r2_sinCorteza), que tienen como variable de entrada la altura
relativa (HR) y van a devolver el radio al cuadrado ( Math.Pow(r,2)). También es necesario declarar
la tabla que almacena la variable (currentTree) y el conjunto al que pertenece (PieMayor).
public PieMayor currentTree;
/// Funciones de perfil utilizadas en el cálculo de volumenes
public double r2_conCorteza(double HR)
{
double r=(1 + 0.4959 * Math.Exp(-14.2598 * HR)) *0.8474 * currentTree.DAP.Value / 200 * Math.Pow(
(1 - HR), 0.6312 - 0.6361 * (1 - HR));
return Math.Pow(r,2);
}
public double r2_sinCorteza(double HR)
{
double r=(1 + 0.3485 * Math.Exp(-23.9191 * HR)) * 0.7966 * currentTree.DAP.Value / 200 *Math.Pow(
(1 - HR), 0.6094 - 0.7086 * (1 - HR));
return Math.Pow(r,2);
}
La primera función va a modificar el índice de sitio a nivel de parcela, y las variables a nivel de
árbol a través de un bucle (foreach). Además se ha preparado un acceso ordenado a los árboles,
con la instrucción “Ilist”, de mayor a menor diámetro, para que el cálculo del BAL (área
basimétrica de los árboles mayores que el objetivo) sea más rápido. En este bucle que recorre
todos los individuos de la parcela, se utiliza la propiedad
.HasValue
para calcular los valores que
no están presentes de distintas alturas. También se calcula el volumen con y sin corteza,
integrando las funciones definidas anteriormente con la instrucción “ IntegralBySimpson”.
/// <summary>
/// Procedimiento que permite la inicialización de variables de parcelas necesarias para la ejecución
del modelo
/// Solo se ejecuta en el primer nodo.
/// Variables que deben permanecer constantes como el índice de sitio deben calcularse solo en este
apartado del modelo
/// </summary>
/// <param name="plot"></param>
public override void CalculateInitialInventory(Parcela plot)
{
IList<PieMayor> piesOrdenados = base.Sort(plot.PiesMayores, new
PieMayorSortingCriteria.DescendingByField("DAP"));
double bal = 0; double old_sec_normal = 100000; double old_bal=0; //double sec_normal =
tree.SEC_NORMAL;
foreach (PieMayor tree in plot.PiesMayores)
13
Manual del modelizador
{
if (old_sec_normal>tree.SEC_NORMAL) {tree.BAL=bal;old_bal=bal;}
else {tree.BAL=old_bal;}
bal +=tree.SEC_NORMAL.Value*tree.EXPAN.Value/10000;
old_sec_normal = tree.SEC_NORMAL.Value;
if (!tree.ALTURA.HasValue)
{
tree.ALTURA = (13 + (27.0392 + 1.4853 * plot.H_DOMINANTE.Value * 10 - 0.1437 *
plot.D_CUADRATICO.Value * 10) * Math.Exp(-8.0048 / Math.Sqrt(tree.DAP.Value * 10)) ) / 10;
}
if (!tree.ALTURA_MAC.HasValue)
{
tree.ALTURA_MAC = tree.ALTURA.Value / (1 + Math.Exp((double)(-0.0012*tree.ALTURA.Value*100.0102*tree.BAL.Value-0.0168*plot.A_BASIMETRICA.Value )));
}
if (!tree.ALTURA_BC.HasValue)
{
tree.ALTURA_BC = tree.ALTURA_MAC.Value / (1+Math.Exp((double)
(1.2425*(plot.A_BASIMETRICA.Value/(tree.ALTURA.Value*10)) + 0.0047*(plot.A_BASIMETRICA.Value) 0.5725*Math.Log(plot.A_BASIMETRICA.Value)-0.0082*tree.BAL.Value)));
}
tree.CR=1-tree.ALTURA_BC.Value/tree.ALTURA.Value;
if (!tree.LCW.HasValue)
{
tree.LCW=(1/10.0F)*(0.2518*tree.DAP.Value*10)*Math.Pow(tree.CR.Value,
(0.2386+0.0046*(tree.ALTURA.Value-tree.ALTURA_BC.Value)*10));
}
tree.VAR_1 = tree.COORD_X;//añadido para tener coordenadas
tree.VAR_2
= tree.COORD_Y;//añadido para tener coordenadas
currentTree = tree;
tree.VCC=Math.PI*tree.ALTURA.Value*IntegralBySimpson(0,1,0.01,r2_conCorteza); //Integración
--> r2_conCorteza sobre HR en los limites 0 -> 1
tree.VSC=Math.PI*tree.ALTURA.Value*IntegralBySimpson(0,1,0.01,r2_sinCorteza); //Integración
--> r2_sinCorteza sobre HR en los limites 0 -> 1
currentTree=null;
}
plot.SI = (plot.H_DOMINANTE.Value * 0.8534446)/Math.Pow((1- Math.Exp((double) (-0.270 *
plot.EDAD.Value/10))),2.2779);
}
Función que calcula el tanto por uno de supervivencia.
/// <summary>
/// Función que indica si el árbol sobrevive o no después de "years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="tree"></param>
/// <returns>Devuelve el porcentaje de árboles que sobreviven</returns>
public override double Survives(double years, Parcela plot, PieMayor tree)
{
double cvDAP = Math.Sqrt(Math.Pow(plot.D_CUADRATICO.Value,2) - Math.Pow(plot.D_MEDIO.Value,2)) /
plot.D_MEDIO.Value;
14
Manual del modelizador
return (1 / (1 + Math.Exp(-6.8548 + (9.792 / tree.DAP.Value) + 0.121 * tree.BAL.Value * cvDAP +
0.037 * plot.SI.Value)));
}
Función que calcula el crecimiento en diámetro y en altura:
/// <summary>
/// Procedimiento que permite modificar las propiedades del árbol durante su crecimiento después de
"years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="oldTree"></param>
/// <param name="newTree"></param>
public override void Grow(double years, Parcela plot, PieMayor oldTree, PieMayor newTree)
{
double DBHG5 = Math.Exp(-0.37110 + 0.2525*Math.Log(oldTree.DAP.Value*10) + 0.7090 *
Math.Log((oldTree.CR.Value + 0.2) / 1.2) + 0.9087 * Math.Log(plot.SI.Value) - 0.1545 *
Math.Sqrt(plot.A_BASIMETRICA.Value) - 0.0004 * (oldTree.BAL.Value * oldTree.BAL.Value /
Math.Log(oldTree.DAP.Value*10)));
newTree.DAP+=DBHG5/10;
double HTG5 = Math.Exp(3.1222-0.4939*Math.Log(oldTree.DAP.Value*10)+1.3763*Math.Log(plot.SI.Value)0.0061*oldTree.BAL.Value+0.1876*Math.Log(oldTree.CR.Value));
newTree.ALTURA+=HTG5/100;
}
Función que calcula el área basimétrica que se incorpora a la masa. Por defecto se distribuirá
de forma uniforme en todas las clases diamétricas, pero es posible indicar una distribución
particular adecuada para el modelo con la función siguiente.
/// <summary>
/// Procedimiento que permite añadir nuevos árboles a una parcela después de "years" años
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <returns>Area basimetrica a distribuir o 0 si no hay masa incorporada</returns>
public override double? AddTree(double years, Parcela plot)
{
double result = 1 / (1 + Math.Exp(8.2739 - 0.3022 * plot.D_CUADRATICO.Value));
if (result >= 0.43F)
{
double BA_Added=5.7855 - 0.1703 * plot.D_CUADRATICO.Value;
if (BA_Added<0)
{
return 0.0F;
}
return BA_Added;
}
return 0.0F;
}
15
Manual del modelizador
Función que distribuye la masa incorporada (en área basimétrica) que se ha calculado en la
función anterior (si no se incluye esta función la distribución será uniforme a lo largo de toda la
distribución diamétrica).
/// <summary>
/// Expresa como se ha de distribuir la masa incorporada entre los árboles existentes.
/// La implementación por defecto la distribuye de forma uniforme.
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="AreaBasimetricaIncorporada"></param>
/// <returns></returns>
public override Distribution[] NewTreeDistribution(double years, Parcela plot, double
AreaBasimetricaIncorporada)
{
Distribution[] distribution = new Distribution[3];
double percentAreaBasimetrica = AreaBasimetricaIncorporada / plot.A_BASIMETRICA.Value;
distribution[0] = new Distribution();
distribution[0].diametroMenor = 0.0;
distribution[0].diametroMayor = 12.5;
distribution[0].AreaBasimetricaToAdd = 0.0384 * AreaBasimetricaIncorporada;
distribution[1] = new Distribution();
distribution[1].diametroMenor = 12.5;
distribution[1].diametroMayor = 22.5;
distribution[1].AreaBasimetricaToAdd = 0.2718 * AreaBasimetricaIncorporada;
distribution[2] = new Distribution();
distribution[2].diametroMenor = 22.5;
distribution[2].diametroMayor = double.MaxValue;
distribution[2].AreaBasimetricaToAdd = 0.6898 * AreaBasimetricaIncorporada;
return distribution;
}
Función que realiza calculos de variables para las que no hay ecuaciones de crecimiento, como
la altura a la base de la copa o los volumenes. Es una función complementaria a
CalculateInitialInventory
ya que se realizan cálculos de variables similares, pero después de
haber crecido y teniendo en cuenta la masa incorporada y la supervivencia.
/// <summary>
/// Procedimiento que realiza los cálculos sobre una parcela.
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="trees"></param>
public override void ProcessPlot(double years, Parcela plot, PieMayor[] trees)
{
IList<PieMayor> piesOrdenados = base.Sort(plot.PiesMayores, new
PieMayorSortingCriteria.DescendingByField("DAP"));
double bal = 0; double old_sec_normal = 100000; double old_bal=0;
foreach(PieMayor tree in piesOrdenados)
16
Manual del modelizador
{
if (!tree.ESTADO.HasValue || String.IsNullOrEmpty(tree.ESTADO.ToString()))
{
if (old_sec_normal>tree.SEC_NORMAL)
{tree.BAL=bal;old_bal=bal;}
else {tree.BAL=old_bal;}
bal
+=tree.SEC_NORMAL.Value*tree.EXPAN.Value/10000;
old_sec_normal = tree.SEC_NORMAL.Value;
tree.ALTURA = (13 + (27.0392 + 1.4853 * plot.H_DOMINANTE.Value * 10 - 0.1437 *
plot.D_CUADRATICO.Value * 10) * Math.Exp(-8.0048 / Math.Sqrt(tree.DAP.Value * 10))) / 10;
tree.ALTURA_MAC = tree.ALTURA.Value / (1 + Math.Exp((double)(-0.0012 * tree.ALTURA.Value * 10 0.0102 * tree.BAL.Value - 0.0168 * plot.A_BASIMETRICA.Value)));
tree.ALTURA_BC = tree.ALTURA_MAC.Value / (1 + Math.Exp((double)(1.2425 *
(plot.A_BASIMETRICA.Value / (tree.ALTURA.Value * 10)) + 0.0047 * (plot.A_BASIMETRICA.Value) - 0.5725 *
Math.Log(plot.A_BASIMETRICA.Value) - 0.0082 * tree.BAL.Value
tree.CR = 1 - tree.ALTURA_BC.Value
/ tree.ALTURA.Value;
tree.LCW = (1 / 10.0F) * (0.2518 * tree.DAP.Value * 10) * Math.Pow(tree.CR.Value, (0.2386 +
0.0046 * (tree.ALTURA.Value - tree.ALTURA_BC.Value) * 10));
currentTree = tree;
tree.VCC = Math.PI * tree.ALTURA.Value * IntegralBySimpson(0, 1, 0.01, r2_conCorteza);
//Integración --> r2_conCorteza sobre HR en los limites 0 -> 1
tree.VSC = Math.PI * tree.ALTURA.Value * IntegralBySimpson(0, 1, 0.01, r2_sinCorteza);
//Integración --> r2_sinCorteza sobre HR en los limites 0 -> 1
currentTree = null;
}
else{tree.BAL=0; tree.CR=0; tree.LCW = 0; tree.ALTURA_MAC = 0; tree.ALTURA_BC = 0;}
}
}
}
}
Programación de un modelo de masa
La programación de modelos de masa es más sencilla, ya que como hemos visto solo consta
de tres funciones, pero también es aconsejable utilizar el modelo alojado en la ayuda de la
plataforma. También se dispone de un ejemplo de modelo completo que puede orientar en la
programación de nuevos modelos.
Hay una primera función en la que se calculan las variables necesarias para la ejecución del
modelo (Initialize),
/// <summary>
/// Función que
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="tree"></param>
public override void Initialize(Parcela plot)
{
/// Ecuaciones para definir las variables de masa necesarias para la
17
Manual del modelizador
/// ejecucion del modelo.también se definen las variables en el
/// estado inicial que no puedan deducirse del inventario
}
otra función para hacer que la masa evolucione “years” años (ApplyModel),
/// <summary>
/// Función que
/// </summary>
/// <param name="oldPlot"></param>
/// <param name="newPlot"></param>
/// years: numero de años que esta creciendo la masa
public override void ApplyModel(Parcela oldPlot, Parcela newPlot, int years)
{
/// Ecuaciones que explican como varian las variables de masa en "years" años
}
y finalmente una función que permite determinar la forma en la que cambian las variables de
masa tras una intervención silvícola (ApplyCutDown).
/// <summary>
/// Función que
/// </summary>
/// <param name="oldPlot"></param>
/// <param name="newPlot"></param>
/// cutDownType values: ( PercentOfTrees, Volume, Area )
/// trimType values: ( ByTallest, BySmallest, Systematic )
/// value: (% de corta)
public override void ApplyCutDown(Parcela oldPlot, Parcela newPlot, CutDownType cutDownType, TrimType
trimType, float value)
{
/// Ecuaciones que explican como varian las variables de masa al cortar un
/// "value" % de masa. Se puede indicar como varía para distintos variables:
/// corta por % de pies, de area basimetrica o de volumen.
/// tambien se puede definir la variación según sean cortas por lo bajo,
/// por lo alto o sistematicas
}
Ejemplo de programación de un modelo de masa
using System;
using System.Collections.Generic;
using Simanfor.Core.EngineModels;
using Simanfor.Entities.Enumerations;
namespace EngineTest
{
public class MassModelTemplate : MassModelBase
{
/// ------------------------------------------------------------------------------------/// Modelo para masas de pino silvestre basado en los artículos:
18
Manual del modelizador
/// * del Río Gaztelurrutia, M; Montero, G.; "Modelo de simulación de claras en masas de
/// Pinus sylvestris L." monografias inia: Forestal n. 3
/// ------------------------------------------------------------------------------------/// <summary>
/// Función que calcula variables necesarias para la ejecución del modelo
/// </summary>
/// <param name="years"></param>
/// <param name="plot"></param>
/// <param name="tree"></param>
public override void Initialize(Parcela plot)
{
double parA, parB, parC, IC;
parA
= 0.8534446;
parB
= -0.27;
parC
IC
= 0.439;
= parA * plot.H_DOMINANTE.Value/10 / Math.Pow( 1- Math.Exp((double) parB *
plot.EDAD.Value/10) , 1/parC);
plot.SI = 10 * IC ;
plot.VAR_1
= IC;
double parB0, parB1,parB2, parB3;
parB0
= 1.42706;
parB1
= 0.388317;
parB2
= -30.691629;
parB3
= 1.034549;
plot.VCC = Math.Exp((double) parB0 + parB1 * IC + parB2 / plot.EDAD.Value + parB3 *
Math.Log(plot.A_BASIMETRICA.Value) );
}
/// <summary>
/// Función que hace evolucionar la masa “year” años
/// </summary>
/// <param name="oldPlot"></param>
/// <param name="newPlot"></param>
/// years: numero de años que esta creciendo la masa
public override void ApplyModel(Parcela oldPlot, Parcela newPlot, int years)
{
newPlot.SI
= oldPlot.SI.Value;
newPlot.EDAD
= oldPlot.EDAD.Value + years;
newPlot.N_PIESHA= oldPlot.N_PIESHA.Value;
newPlot.VAR_1
= oldPlot.VAR_1.Value;
// H_DOMINANTE:
double IC
= oldPlot.SI.Value/10;
double parA17, parB17, parC17, parA29, parB29, parC29;
parA17
= 1.9962;
parB17
= 0.2642;
parC17
= 0.46;
parA29
= 3.1827;
parB29
= 0.3431;
parC29
= 0.3536;
double H0_17
= 10 * parA17 * Math.Pow( 1 - Math.Exp((double) -1 * parB17 * newPlot.EDAD.Value /
10 ) , 1/parC17);
19
Manual del modelizador
double H0_29
= 10 * parA29 * Math.Pow( 1 - Math.Exp((double) -1 * parB29 * newPlot.EDAD.Value /
10 ) , 1/parC29);
newPlot.VAR_2 = H0_17;
newPlot.VAR_3 = H0_29;
newPlot.H_DOMINANTE
= H0_17 + (H0_29 - H0_17) * (IC - 1.7) / 1.2;
// AREA_BASIMETRICA:
double parA0, parA1, parB0, parB1, parA2, parB2, parB3;
parA0
= 5.103222;
parB0
= 1.42706;
parB1
= 0.388317;
parB2
= -30.691629;
parB3
= 1.034549;
newPlot.A_BASIMETRICA
= Math.Pow( oldPlot.A_BASIMETRICA.Value, oldPlot.EDAD.Value /
newPlot.EDAD.Value) * Math.Exp(parA0 * (1-oldPlot.EDAD.Value / newPlot.EDAD.Value));
// VOLUMEN
newPlot.VCC = Math.Exp((double) parB0 + parB1 * IC + parB2 / newPlot.EDAD.Value
+ parB3 *
( Math.Log(oldPlot.A_BASIMETRICA.Value)*oldPlot.EDAD.Value/newPlot.EDAD.Value + parA0*(1oldPlot.EDAD.Value/newPlot.EDAD.Value) ) );
//Altura media
parA0
= -1.155649;
parA1
= 0.976772;
newPlot.H_MEDIA
= parA0 + parA1 * newPlot.H_DOMINANTE;
//MORTALIDAD NATURAL
parA0
= -2.349350607;
parA1
= 0.000000099;
parA2
= 4.873897659;
newPlot.N_PIESHA
= Math.Pow( Math.Pow(oldPlot.N_PIESHA.Value,parA0) + parA1 *
( Math.Pow( newPlot.EDAD.Value/100 , parA2 ) - Math.Pow( oldPlot.EDAD.Value/100 , parA2 ) ), 1 /
parA0);
// D_CUADRATICO:
double SEC_NORMAL
= newPlot.A_BASIMETRICA.Value * 10000 / newPlot.N_PIESHA.Value
newPlot.D_CUADRATICO
= 2*Math.Sqrt(SEC_NORMAL/Math.PI)
;
;
}
/// <summary>
/// Función que explica el cambio en las variables tras aplicar una clara
/// </summary>
/// <param name="oldPlot"></param>
/// <param name="newPlot"></param>
/// cutDownType values: ( PercentOfTrees, Volume, Area )
/// trimType values: ( ByTallest, BySmallest, Systematic )
/// value: (% de corta)
public override void ApplyCutDown(Parcela oldPlot, Parcela newPlot, CutDownType cutDownType, TrimType
trimType, float value)
{
newPlot.VAR_9 = value;
double parA17, parB17, parC17, parA29, parB29, parC29;
parA17
= 1.9962;
parB17
= 0.2642;
parC17
= 0.46;
parA29
= 3.1827;
parB29
= 0.3431;
20
Manual del modelizador
parC29
= 0.3536;
double H0_17
= 10 * parA17 * Math.Pow( 1 - Math.Exp((double) -1 * parB17 * newPlot.EDAD.Value /
10 ) , 1/parC17);
double H0_29
= 10 * parA29 * Math.Pow( 1 - Math.Exp((double) -1 * parB29 * newPlot.EDAD.Value /
10 ) , 1/parC29);
double parA0, parB0, parB1, parB2, parB3;
parA0
= 5.103222;
parB0
= 1.42706;
parB1
= 0.388317;
parB2
= -30.691629;
parB3
= 1.034549;
double IC = oldPlot.SI.Value/10;
double parC0,parC1,parC2,SEC_NORMAL,tpuN,tpuBA;
switch (cutDownType)
{
case CutDownType.PercentOfTrees:
parC0
= 0.531019;
parC1
= 0.989792;
parC2
= 0.517850;
tpuN = value/100;
newPlot.N_PIESHA
= oldPlot.N_PIESHA.Value - tpuN*oldPlot.N_PIESHA.Value;
newPlot.D_CUADRATICO
= parC0 + parC1*oldPlot.D_CUADRATICO +
parC2*oldPlot.D_CUADRATICO.Value*Math.Pow(1-tpuN,2);
SEC_NORMAL
newPlot.A_BASIMETRICA
= Math.PI * Math.Pow(newPlot.D_CUADRATICO.Value/2,2);
= SEC_NORMAL * newPlot.N_PIESHA.Value / 10000;
newPlot.VCC = Math.Exp((double) parB0 + parB1 * IC + parB2 / newPlot.EDAD.Value + parB3 *
Math.Log(newPlot.A_BASIMETRICA.Value) );
break;
case CutDownType.Volume:
break;
case CutDownType.Area:
parC0
= 0.144915;
parC1
= 0.969819;
parC2
= 0.678010;
tpuBA
= value/100;
newPlot.A_BASIMETRICA
= oldPlot.A_BASIMETRICA.Value - tpuBA*oldPlot.A_BASIMETRICA.Value;
newPlot.D_CUADRATICO
= Math.Pow(parC0 + parC1*Math.Pow(oldPlot.D_CUADRATICO.Value,0.5) +
parC2*(1-tpuBA) ,2 );
SEC_NORMAL
newPlot.N_PIESHA
= Math.PI * Math.Pow(newPlot.D_CUADRATICO.Value/2,2);
= newPlot.A_BASIMETRICA.Value * 10000 / SEC_NORMAL;
newPlot.VCC = Math.Exp((double) parB0 + parB1 * IC + parB2 / newPlot.EDAD.Value + parB3 *
Math.Log(newPlot.A_BASIMETRICA.Value) );
break;
}
}
}
}
21
Manual del modelizador
Detalles técnicos de SiManFor
Lenguaje de programación
El lenguaje de programación de la plataforma es VisualBasic.NET, aunque esto no afecta a los
usuarios modelizadores, ya que el lenguaje de programación de los modelos es C#. Este
lenguaje es muy simple y permite un aprendizaje rápido en caso de que no se haya usado
antes.
Al final de este documento existe una relación de enlaces sobre la iniciación a la programación
de C# y los detalles técnicos del propio lenguaje.
Estructura de los modelos
Los modelos de crecimiento no son más que clases (estructuras) que agrupan un conjunto de
funciones y procedimientos, que son las que contienen los algoritmos para cada fase. Existe
una función o procedimiento que contiene las ecuaciones o algoritmos que se deben aplicar en
cada una de las fases indicadas anteriormente.
Es importante saber que el motor de SiManFor es el que se encarga de ejecutar cada una de
ellas en cada momento, y que su posición en el código del modelo no tiene relación alguna. Es
decir, aunque se recomienda un orden concreto de aparición y definición de cada función o
procedimiento, no es estrictamente necesario mantenerlo.
En la siguiente sección se puede ver el código de un modelo simple, totalmente operativo y con
comentarios en el código para que se comprendan los detalles técnicos del mismo.
Biblioteca de clases
Asociado al lenguaje de programación, existe un conjunto de clases que se pueden usar para
definir el tipo de las variables que se usen: números enteros o reales, cadenas de texto,
vectores y matrices, etc.
Además, existe una clase denominada Math que agrupa todas las funciones matemáticas y
constantes numéricas comunes: número pi y e, funciones de logaritmos, medias aritméticas,
trigonométricas, etc.
Al final de este documento existe una relación de enlaces desde los que se pueden consultar
22
Manual del modelizador
los detalles de las bibliotecas de clases y las funciones que contiene la clase Math. En estos
enlaces también se pueden consultar ejemplos prácticos para entender el funcionamiento y uso
de los mismos.
Navegación
Las variables usadas en los modelos permiten desplazarse a las distintas entidades del
inventario. Por ejemplo, dado un pie mayor, se puede obtener la parcela o el inventario al que
pertenece a través de sus propiedades. También se puede recorrer todos los árboles que
contiene una parcela a partir de la misma.
Al final de este documento encontrará el diagrama de entidades en el que se indican las
propiedades de cada entidad del inventario (el inventario propiamente, las parcelas y los pies
mayores), así como qué propiedades permiten navegar hasta otras entidades.
Seguridad
Los modelos se ejecutan en el servidor bajo una plataforma de seguridad que no permite el
acceso a áreas sensibles del sistema como el sistema de archivos o el Registro de
Configuración del sistema. Aunque la biblioteca estándar de clases que se usa en los modelos
permite usar clases que accedan a estas áreas sensibles, dicha plataforma de seguridad
bloquea los accesos, por lo que se garantiza la seguridad del servidor.
Es recomendable que los modelizadores eviten el uso de aquellas clases que pretendan
acceder o modificar partes del sistema, y se restrinjan a usar los tipos básicos de la biblioteca
de clases y sus operaciones sobre las mismas.
Programación con C#.NET
El siguiente enlace muestra la sección de Introducción a C#.NET, de MSDN Library. Esta
sección incluye los principios del lenguaje, su sintaxis y ejemplos de cómo programar de forma
general en este lenguaje.
Introducción
a
C#.NET
(.NET
Framework)
MSDN
Library
(Español)
https://msdn.microsoft.com/es-es/library/kx37x362.aspx
También puede resultar de interés este manual de C#
23
Manual del modelizador
Ayuda de bibliotecas de clases
Los siguientes enlaces muestran las secciones de documentación de la biblioteca estándar de
clases y la documentación de Math (también accesible desde el primer enlace),
respectivamente. Las clases indicadas en dicha documentación pueden usarse en los modelos,
aunque se deben tener en cuenta las limitaciones de seguridad impuestas por el motor de
ejecución de modelos.
Biblioteca
estándar
de
clases
de
.NET
Framework
MSDN
Library
(Español)
http://msdn.microsoft.com/es-es/library/ms229335.aspx
Referencia de la clase Math MSDN Library (Español) http://msdn.microsoft.com/eses/library/system.math.aspx
Resumen de características técnicas de los modelos de crecimiento
Lenguaje de programación:
C#.NET 2008
Versión de .NET Framework:
Microsoft .NET Framework 3.5 SP1
Zona de seguridad de ejecución:
Zona de Internet (privilegios mínimos)
Ensamblados incluidos:
mscorlib
Simanfor.Core.EngineModels
Espacios de nombres por defecto: System
System.Collections.Generics
Simanfor.Core.EngineModels
Tipos base usados por defecto:
System.Double
System.Object
System.String
System.Collections.Generics.Idictionary<>
System.Collections.Generics.Ilist<>
Tipos propios usados por defecto: Simanfor.Core.EngineModels.PieMayor
Simanfor.Core.EngineModels.Parcelas
24

Documentos relacionados