!! Simulate vegetation dynamic
!|author: Giovanni Ravazzani
! license: GPL
!
!### History
!
! current version 1.0 - 31st October 2018
!
! | version | date | comment |
! |----------|-------------|----------|
! | 1.0 | 31/Oct/2018 | Original code |
!
!### License
! license: GNU GPL
!
!### Module Description
! Module to model vegetation dynamic
!
MODULE Plants
!
! Modules used:
USE DataTypeSizes, ONLY : &
! Imported Type Definitions:
short, float
USE LogLib, ONLY: &
!Imported routines:
Catch
USE GridLib, ONLY: &
!imported definitions:
grid_real, grid_integer, &
!imported routines:
NewGrid, GridDestroy, &
!imported parameters:
NET_CDF
USE GridOperations, ONLY : &
!imported routines:
GridByIni, CellArea
USE Chronos, ONLY: &
!imported definitions:
DateTime, &
!Imported routines:
DayOfYear, GetYear, &
!Imported operations:
OPERATOR (==), &
OPERATOR ( > )
USE IniLib, ONLY : &
!Imported derived types:
IniList, &
!Imported routines:
IniOpen, IniClose , &
IniReadInt , IniReadReal, &
IniReadString, SectionIsPresent, &
KeyIsPresent
USE StringManipulation, ONLY : &
!imported routines
ToString
USE PlantsAllometrics, ONLY : &
!imported routines:
CrownDiameter, CanopyCover
USE PlantsModifiers, ONLY: &
!imported routines:
AGEmod, TEMPmod, SWCmod, VPDmod, CO2mod
USE PlantsInterception, ONLY: &
!imported variables
interceptionParametersByMap, &
laimax, canopymax
USE PlantsManagement, ONLY: &
!imported definition:
Practice, &
!imported variables:
plants_management, &
management_map, &
!imported routines:
SetPlantsManagement, &
ApplyPlantsManagement, &
SetPractice
USE PlantsMortality, ONLY : &
!imported routines:
KillPlants
USE Units, ONLY : &
! imported parameters:
hectare, pi
IMPLICIT NONE
! Global (i.e. public) Declarations:
PUBLIC :: PlantsConfig
PUBLIC :: PlantsGrow
PUBLIC :: PlantsParameterUpdate
INTEGER (KIND = short) :: dtPlants
TYPE (grid_real) :: lai !!leaf area index (m2/m2)
TYPE (grid_real) :: fvcover !!fraction of cell covered by vegetation
TYPE (grid_real) :: rsMin !!minimum stomatal resistance
TYPE (grid_real) :: gpp !! carbon gross primary production (t)
TYPE (grid_real) :: npp !! carbon net primary production (t)
TYPE (grid_real) :: carbonroot !! carbon mass of root (t)
TYPE (grid_real) :: carbonstem !! carbon mass of stem (t)
TYPE (grid_real) :: carbonleaf !! carbon mass of leaf (t)
TYPE (grid_real) :: dbh !!diameter at brest height (cm)
TYPE (grid_real) :: plantsHeight !! tree height (m)
TYPE (grid_real) :: density !! Trees/hectare
TYPE (grid_real) :: stemyield !! stem yield (t)
LOGICAL :: rsMinLoaded = .FALSE.
LOGICAL :: fvcoverLoaded = .FALSE.
LOGICAL :: laiLoaded = .FALSE.
LOGICAL :: plantsHeightLoaded = .FALSE.
LOGICAL :: updatePlantsParameters = .FALSE.
TYPE PlantsSpecies
!Descriptor
CHARACTER (LEN = 50) :: name !!species name, Fagus, Abies, ...
CHARACTER (LEN = 1) :: phenology !! evergreen (E), deciduous (D)
REAL (KIND = float) :: alpha !! canopy quantum efficiency (molC/molPAR)
REAL (KIND = float) :: GPPtoNPP !!GPP/NPP ratio
REAL (KIND = float) :: k !! extinction coefficient for absorption of PAR by canopy
REAL (KIND = float) :: cra !! Chapman-Richards asymptotic maximum height
REAL (KIND = float) :: crb !! Chapman-Richards exponential decay parameter
REAL (KIND = float) :: crc !! Chapman-Richards shape parameter
REAL (KIND = float) :: as !! scaling coefficient in stem mass v diameter relationship
REAL (KIND = float) :: ns !! scaling exponent in stem mass v diameter relationship
!REAL (KIND = float) :: saf !! stem allocation factor
!REAL (KIND = float) :: raf !! root allocation factor
!REAL (KIND = float) :: laf !! leaf (foliage) allocation factor
REAL (KIND = float) :: dbhdcmin !! minimum ratio between stem and crown diameters (m/cm)
REAL (KIND = float) :: dbhdcmax !! maximum ratio between stem and crown diameters (m/cm)
REAL (KIND = float) :: denmin !! minimum tree density (trees/ha)
REAL (KIND = float) :: denmax !! minimum tree density (trees/ha)
REAL (KIND = float) :: agemax !! maximum age
REAL (KIND = float) :: tmax !! maximum temperature for vegetation growing (°C)
REAL (KIND = float) :: tmin !! minimum temperature for vegetation growing (°C)
REAL (KIND = float) :: topt !! optimum temperature for vegetation growing (°C)
REAL (KIND = float) :: theta_fswc !! parameter to compute soil water content modifier
REAL (KIND = float) :: theta_fvpd !! parameter to compute vapor pressure deficit modifier
REAL (KIND = float) :: fpra !! parameter 1 to compute allocation factors
REAL (KIND = float) :: fprn !! parameter 2 to compute allocation factors
REAL (KIND = float) :: spra !! parameter 3 to compute allocation factors
REAL (KIND = float) :: sprn !! parameter 4 to compute allocation factors
REAL (KIND = float) :: ltr !!leaf turnover rate [s-1]
REAL (KIND = float) :: rtr !!root turnover rate [s-1]
REAL (KIND = float) :: tcold_leaf !! temperature threshold that accelerates leaf turnover (°C)
REAL (KIND = float) :: sla !! specific leaf area [m2/Kg]
REAL (KIND = float) :: hdmin !! H/D ratio in carbon partitioning for low density
REAL (KIND = float) :: hdmax !! H/D ratio in carbon partitioning for high density
REAL (KIND = float) :: albedo !!plant albedo (0-1)
REAL (KIND = float) :: laimax !!maximum leaf area index used for precipitation interception (m2/m2)
REAL (KIND = float) :: canopymax !! maximum canopy storage capacity (m)
REAL (KIND = float) :: wood_density !! wood density (kg/m3)
REAL (KIND = float) :: ms !! Fractions of mean stem biomass pools per tree on each dying tree
REAL (KIND = float) :: mr !! Fractions of mean root biomass pools per tree on each dying tree
REAL (KIND = float) :: mf !! Fractions of mean leaf biomass pools per tree on each dying tree
REAL (KIND = float) :: wSx1000 !! Fractions of mean leaf biomass pools per tree on each dying tree
END TYPE PlantsSpecies
TYPE PlantsCohort !group of plants of the same species that are born during the same year
TYPE (PlantsSpecies) :: species
!state variables
REAL (KIND = float) :: age !!age [years]
REAL (KIND = float) :: gpp !! gross primary production (t/ha)
REAL (KIND = float) :: npp !! net primary production (t/ha)
REAL (KIND = float) :: lai !! leaf area index [m2/m2]
REAL (KIND = float) :: mass_root !! mass of root (t/ha)
REAL (KIND = float) :: mass_stem !! mass of stem (t/ha)
REAL (KIND = float) :: mass_stem_year_previous !! mass of stem of the previous year (t/ha)
REAL (KIND = float) :: mass_leaf !! mass of leaf (t/ha)
REAL (KIND = float) :: mass_total !! total biomass root + stem + foliage (t/ha)
REAL (KIND = float) :: stem_yield !! stem mass produced by plants cut (t/ha)
REAL (KIND = float) :: density !! number of plants per hectar
REAL (KIND = float) :: height !! plants heigth [m]
REAL (KIND = float) :: dbh !!diameter at brest heigth [cm]
REAL (KIND = float) :: canopy_cover !! percentage of surface stand covered by canopy [0-1]
REAL (KIND = float) :: crown_diameter !! diameter of crown [m]
REAL (KIND = float) :: apar !! absorbed photosynthetically active radiation (molPAR m-2)
TYPE(PlantsCohort), POINTER :: next =>null() ! pointer to the next cohort in the same stand
END TYPE PlantsCohort
TYPE PlantsStand ! list of cohorts
TYPE (PlantsCohort), POINTER, PRIVATE :: first => null()
!TYPE (PlantsCohort), POINTER, PRIVATE :: last => null()
!TYPE (PlantsCohort), POINTER, PRIVATE :: iter => null()
INTEGER (KIND = short) , PRIVATE :: lenght = 0
INTEGER (KIND = short) , PRIVATE :: i !row of the stand in grid plants_mask
INTEGER (KIND = short) , PRIVATE :: j !column of the stand in grid plants_mask
TYPE (Practice) :: thinning
END TYPE PlantsStand
!TYPE PlantsAge
! REAL (KIND = float) :: value !!age [yesrs]
! INTEGER (KIND = short) :: period !! 0 for adult tree, 1 for young tree
! INTEGER (KIND = short) :: species_count !! number of species in the cell
! TYPE (PlantsSpecies), ALLOCATABLE :: species (:)
!END TYPE PlantsAge
!
!TYPE PlantsHeight
! REAL (KIND = float) :: value !!value of height class [m]
! REAL (KIND = float) :: layer_coverage !! cell coverage of that layer
! INTEGER (KIND = short) :: dominance !! -1 no trees in veg period, 1 trees in veg period
! INTEGER (KIND = short) :: ages_count !! counter of age classes in the cell
! TYPE (PlantsAge), ALLOCATABLE :: ages (:)
!END TYPE PlantsHeight
!local (i.e. private) declarations:
!variables and parameters
LOGICAL, PRIVATE :: simulatePlants != 1 when plants dynamic is simulated, = 0 read vegetation parameters from files
LOGICAL, PRIVATE :: useCO2modifier ! define wheter use the CO2 modifier
LOGICAL, PRIVATE :: mortality ! wheter to apply mortality or not
TYPE (grid_integer), PRIVATE :: plants_mask !!define cells active for plants dynamic simulation
TYPE (PlantsStand), PRIVATE, ALLOCATABLE :: forest (:) !vector of stands
INTEGER (KIND = short), PRIVATE :: count_stands !number of stands in the forest (equal to the number of cells in the domain)
TYPE (PlantsSpecies), ALLOCATABLE, PRIVATE :: species (:) !
!REAL (KIND = float), PRIVATE :: rs_par !! fraction of shortwave radiation to compute PAR [0-1]
INTEGER (KIND = short), PRIVATE :: year_prev, year_new
REAL (KIND = float), PRIVATE, PARAMETER :: C_molar_mass = 0.0120107 ! kg/mol
!routines
PRIVATE :: AparCalc
PRIVATE :: ReadSpecies
PRIVATE :: SetIC
PRIVATE :: GrowLeaf
PRIVATE :: GrowDBH
PRIVATE :: ForestToGrid
!=======
CONTAINS
!=======
!==============================================================================
!| Description:
! Initialize Plants module
SUBROUTINE PlantsConfig &
!
(iniFile, mask, begin, end)
IMPLICIT NONE
! Arguments with intent(in):
CHARACTER (LEN = 300), INTENT(IN) :: iniFile !!configuration file
TYPE (grid_integer), INTENT(IN) :: mask !!mask of simulation domain
TYPE (DateTime), INTENT (IN) :: begin !!simulation starting date
TYPE (DateTime), INTENT(IN) :: end !!simulation ending date
!local declarations:
TYPE(IniList) :: iniDB !!store configuration info
INTEGER (KIND = short) :: i, j, k
CHARACTER (LEN = 300) :: species_file
CHARACTER (LEN = 300) :: ICfile
CHARACTER (LEN = 300) :: PMfile
REAL (KIND = float) :: scalar
!------------end of declaration------------------------------------------------
CALL IniOpen (iniFile, iniDB)
!need plants dynamic simulation?
simulatePlants = IniReadInt ('plants-simulation', iniDB)
IF ( simulatePlants == 1) THEN !plants dynamic is simulated: configure forest model
!plants mask
IF ( SectionIsPresent ( 'plants-mask', iniDB) ) THEN
CALL GridByIni (iniDB, plants_mask, section = 'plants-mask')
ELSE
CALL Catch ('error', 'Plants', 'Mask missing in configuration file')
END IF
!CO2 modifier
IF ( SectionIsPresent ( 'use-co2-modifier', iniDB) ) THEN
IF ( IniReadInt ('use-co2-modifier', iniDB) == 1 ) THEN
useCO2modifier = .TRUE.
ELSE
useCO2modifier = .FALSE.
END IF
ELSE
!if key is not found, set it to default false
useCO2modifier = .FALSE.
END IF
!mortality
IF ( KeyIsPresent ( 'mortality', iniDB) ) THEN
IF ( IniReadInt ('mortality', iniDB) == 1 ) THEN
mortality = .TRUE.
ELSE
mortality = .FALSE.
END IF
ELSE
!if mortality is not found, assume it is not considered
mortality = .FALSE.
END IF
!load species
species_file = IniReadString ('plants-species-file', iniDB)
CALL ReadSpecies (species_file)
!compute number of stands and allocate
count_stands = 0
DO i = 1, plants_mask % idim
DO j = 1, plants_mask % jdim
IF ( plants_mask % mat (i,j) /= plants_mask % nodata ) THEN
count_stands = count_stands + 1
END IF
END DO
END DO
ALLOCATE ( forest ( count_stands) )
!initialize list
k = 1
DO i = 1, plants_mask % idim
DO j = 1, plants_mask % jdim
IF ( plants_mask % mat (i,j) /= plants_mask % nodata ) THEN
!initialize the first cohort in the stand
ALLOCATE ( forest (k) % first)
NULLIFY ( forest (k) % first % next)
forest (k) % lenght = 1
!store position of stand
forest (k) % i = i
forest (k) % j = j
k = k + 1
END IF
END DO
END DO
!set initial condition
ICfile = IniReadString ('plants-ic-file', iniDB)
CALL SetIC (ICfile)
!set plants management options
IF (KeyIsPresent ('plants-management-file',iniDB) ) THEN
plants_management = .TRUE.
PMfile = IniReadString ('plants-management-file', iniDB)
CALL SetPlantsManagement (PMfile, begin, end)
!set management pratice for each stand
DO k = 1, count_stands
CALL SetPractice ( management_map % mat (forest (k) % i, forest (k) % j) , forest (k) % thinning )
END DO
ELSE !management is turned off
plants_management = .FALSE.
END IF
!set interception maps if required
IF (interceptionParametersByMap == 0 ) THEN
CALL Catch ('warning', 'Plants', 'interception parameters are set only where plants map is not nodata')
!allocate maps
CALL NewGrid (laimax, plants_mask)
CALL NewGrid (canopymax, plants_mask)
DO k = 1, count_stands
i = forest (k) % i
j = forest (k) % j
laimax % mat (i,j) = forest (k) % first % species % laimax
canopymax % mat (i,j) = forest (k) % first % species % canopymax
END DO
END IF
!allocate grids for state variables
CALL NewGrid (lai, plants_mask)
CALL NewGrid (fvcover, plants_mask)
CALL NewGrid (gpp, plants_mask)
CALL NewGrid (npp, plants_mask)
CALL NewGrid (carbonroot, plants_mask)
CALL NewGrid (carbonstem, plants_mask)
CALL NewGrid (carbonleaf, plants_mask)
CALL NewGrid (dbh, plants_mask)
CALL NewGrid (plantsHeight, plants_mask)
CALL NewGrid (density, plants_mask)
CALL NewGrid (stemyield, plants_mask)
!fill in grids
CALL ForestToGrid (lai, 'lai')
CALL ForestToGrid (fvcover, 'fv')
CALL ForestToGrid (gpp, 'gpp')
CALL ForestToGrid (npp, 'npp')
CALL ForestToGrid (carbonroot, 'root')
CALL ForestToGrid (carbonstem, 'stem')
CALL ForestToGrid (carbonleaf, 'leaf')
CALL ForestToGrid (dbh, 'dbh')
CALL ForestToGrid (plantsHeight, 'height')
CALL ForestToGrid (density, 'density')
CALL ForestToGrid (stemyield, 'stemyield')
fvcoverLoaded = .TRUE.
laiLoaded = .TRUE.
plantsHeightLoaded = .TRUE.
ELSE ! no plants dynamic simulation required: read parameters from files
!leaf area index
IF ( SectionIsPresent ( 'lai', iniDB) ) THEN
IF (KeyIsPresent ('scalar', iniDB, 'lai') ) THEN
scalar = IniReadReal ('scalar', iniDB, 'lai')
CALL NewGrid (lai, mask, scalar)
ELSE
!check if parameter may change in time
IF (KeyIsPresent ('format', iniDB, 'lai') ) THEN
IF ( IniReadString ('format', iniDB, 'lai') == 'net-cdf' ) THEN
updatePlantsParameters = .TRUE.
END IF
END IF
!read map
CALL GridByIni (iniDB, lai, section = 'lai')
END IF
laiLoaded = .TRUE.
ELSE
CALL Catch ('warning', 'Plants', 'LAI missing in configuration file')
END IF
!fraction of vegetation coverage
IF ( SectionIsPresent ( 'vegetation-fraction', iniDB) ) THEN
IF (KeyIsPresent ('scalar', iniDB, 'vegetation-fraction') ) THEN
scalar = IniReadReal ('scalar', iniDB, 'vegetation-fraction')
CALL NewGrid (fvcover, mask, scalar)
ELSE
!check if parameter may change in time
IF (KeyIsPresent ('format', iniDB, 'vegetation-fraction') ) THEN
IF ( IniReadString ('format', iniDB, 'vegetation-fraction') == 'net-cdf' ) THEN
updatePlantsParameters = .TRUE.
END IF
END IF
!read map
CALL GridByIni (iniDB, fvcover, section = 'vegetation-fraction')
END IF
fvcoverLoaded = .TRUE.
ELSE
CALL Catch ('warning', 'Plants', 'vegetation-fraction is missing')
END IF
!plants height
IF ( SectionIsPresent ( 'vegetation-height', iniDB) ) THEN
IF (KeyIsPresent ('scalar', iniDB, 'vegetation-height') ) THEN
scalar = IniReadReal ('scalar', iniDB, 'vegetation-height')
CALL NewGrid (plantsHeight, mask, scalar)
ELSE
!check if parameter may change in time
IF (KeyIsPresent ('format', iniDB, 'vegetation-height') ) THEN
IF ( IniReadString ('format', iniDB, 'vegetation-height') == 'net-cdf' ) THEN
updatePlantsParameters = .TRUE.
END IF
END IF
!read map
CALL GridByIni (iniDB, plantsHeight, section = 'vegetation-height')
END IF
plantsHeightLoaded = .TRUE.
ELSE
CALL Catch ('warning', 'Plants', 'vegetation-height is missing')
END IF
END IF
!minimum stomatal resistance. this is not computed by forest model and it may be used for computing PET
IF ( SectionIsPresent ( 'min-stomatal-resistance', iniDB) ) THEN
IF (KeyIsPresent ('scalar', iniDB, 'min-stomatal-resistance') ) THEN
scalar = IniReadReal ('scalar', iniDB, 'min-stomatal-resistance')
CALL NewGrid (rsMin, mask, scalar)
ELSE
!check if parameter may change in time
IF (KeyIsPresent ('format', iniDB, 'min-stomatal-resistance') ) THEN
IF ( IniReadString ('format', iniDB, 'min-stomatal-resistance') == 'net-cdf' ) THEN
updatePlantsParameters = .TRUE.
END IF
END IF
!read map
CALL GridByIni (iniDB, rsMin, section = 'min-stomatal-resistance')
END IF
rsMinLoaded = .TRUE.
ELSE
CALL Catch ('warning', 'Plants', 'min-stomatal-resistance is missing')
END IF
CALL IniClose (iniDB)
RETURN
END SUBROUTINE PlantsConfig
!==============================================================================
!| Description:
! update parameter map that change in time
SUBROUTINE PlantsParameterUpdate &
!
(time)
IMPLICIT NONE
!Arguments with intent(in):
TYPE (DateTime), INTENT (IN) :: time
!local declarations:
CHARACTER (LEN = 300) :: filename
CHARACTER (LEN = 300) :: varname
!------------------------------end of declarations-----------------------------
!leaf area index
IF ( time == lai % next_time ) THEN
!destroy current grid
filename = lai % file_name
varname = lai % var_name
CALL GridDestroy (lai)
!read new grid in netcdf file
CALL NewGrid (lai, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!fraction of vegetation coverage
IF ( time == fvcover % next_time ) THEN
!destroy current grid
filename = fvcover % file_name
varname = fvcover % var_name
CALL GridDestroy (fvcover)
!read new grid in netcdf file
CALL NewGrid (fvcover, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!plants height
IF ( time == plantsHeight % next_time ) THEN
!destroy current grid
filename = plantsHeight % file_name
varname = plantsHeight % var_name
CALL GridDestroy (plantsHeight)
!read new grid in netcdf file
CALL NewGrid (plantsHeight, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!minimum stomatal resistance
IF ( time == rsMin % next_time ) THEN
!destroy current grid
filename = rsMin % file_name
varname = rsMin % var_name
CALL GridDestroy (rsMin)
!read new grid in netcdf file
CALL NewGrid (rsMin, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
RETURN
END SUBROUTINE PlantsParameterUpdate
!==============================================================================
!| Description:
! Update plants state variables
SUBROUTINE PlantsGrow &
!
(time, radiation, temperature, swc, sfc, swp, rh, co2)
IMPLICIT NONE
!Arguments with intent(in):
TYPE (DateTime), INTENT(IN) :: time !!current time
TYPE (grid_real), INTENT(IN) :: radiation !!shortwave radiation [w/m2]
TYPE (grid_real), INTENT(IN) :: temperature !!air temperature [°C]
TYPE (grid_real), INTENT(IN) :: swc !! soil water content [m3/m3]
TYPE (grid_real), INTENT(IN) :: sfc !! soil field capacity [m3/m3]
TYPE (grid_real), INTENT(IN) :: swp !! soil wilting point [m3/m3]
TYPE (grid_real), INTENT(IN) :: rh !! air relative humidity [0-1]
REAL (KIND = float), OPTIONAL, INTENT(IN) :: co2 !! CO2 [ppm]
!local declarations:
CHARACTER (LEN = 300) :: filename, varname
INTEGER (KIND = short) :: k, l
TYPE (PlantsCohort), POINTER :: cohort
REAL (KIND = float) :: fSWC !! GPP soil water content modifier
REAL (KIND = float) :: fAGE !! GPP age modifier
REAL (KIND = float) :: fTEMP !! GPP temperature modifier
REAL (KIND = float) :: fVPD !! GPP vapor pressure deficit modififer
REAL (KIND = float) :: fCO2 !! GPP CO2 modifier
!REAL (KIND = float) :: deltaMroot !! root mass increment
!REAL (KIND = float) :: deltaMstem !! stem mass increment
REAL (KIND = float) :: rootaf !!root allocation factor
REAL (KIND = float) :: stemaf !! stem allocation factor
REAL (KIND = float) :: leafaf !! leaf allocation factor
REAL (KIND = float) :: pfs !!used to compute stem allocation factor
LOGICAL :: is_new_year !! flag to mark new year has begun
TYPE (Practice) :: practice
!------------end of declaration------------------------------------------------
! need to update vegetation parameters from file?
IF ( simulatePlants == 0) THEN
!check leaf area index
IF ( time == lai % next_time ) THEN
!destroy current grid
filename = lai % file_name
varname = lai % var_name
CALL GridDestroy (lai)
!read grid in netcdf file
CALL NewGrid (lai, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!check vegetation fraction
IF ( time == fvcover % next_time ) THEN
!destroy current grid
filename = fvcover % file_name
varname = fvcover % var_name
CALL GridDestroy (fvcover)
!read grid in netcdf file
CALL NewGrid (fvcover, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!check plants height
IF ( time == plantsHeight % next_time ) THEN
!destroy current grid
filename = plantsHeight % file_name
varname = plantsHeight % var_name
CALL GridDestroy (plantsHeight)
!read grid in netcdf file
CALL NewGrid (plantsHeight, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
!check minimum stomatal resistance
IF ( rsMinLoaded .AND. time == rsMin % next_time ) THEN
!destroy current grid
filename = rsMin % file_name
varname = rsMin % var_name
CALL GridDestroy (rsMin)
!read grid in netcdf file
CALL NewGrid (rsMin, TRIM(filename), NET_CDF, &
variable = TRIM(varname), time = time)
END IF
ELSE !simulate forest dynamics
year_new = GetYear (time)
DO k = 1, count_stands
cohort => forest (k) % first
DO l = 1, forest (k) % lenght !loop through all cohorts
cohort % stem_yield = 0.
!check management practices
IF ( plants_management ) THEN
IF ( ALLOCATED (forest (k) % thinning % cuts) ) THEN
practice = forest (k) % thinning
IF (time > practice % next .AND. practice % current < SIZE ( practice % cuts )) THEN
practice % current = practice % current + 1
IF ( practice % cuts ( practice % current ) % reforestation ) THEN
!set species parameters
cohort % species = species ( practice % cuts ( practice % current ) % species)
END IF
CALL ApplyPlantsManagement (time, practice, cohort % density, &
cohort % mass_root, cohort % mass_stem, &
cohort % mass_leaf, cohort % mass_total, &
cohort % lai, cohort % canopy_cover, &
cohort % age, cohort % height, cohort % dbh, &
cohort % stem_yield )
!update crown diameter
cohort % crown_diameter = CrownDiameter ( dbh = cohort % dbh, &
den = cohort % density, &
denmin = cohort % species % denmin, &
denmax = cohort % species % denmax, &
dbhdcmin = cohort % species % dbhdcmin, &
dbhdcmax = cohort % species % dbhdcmax )
!update canopy cover
cohort % canopy_cover = CanopyCover ( cohort % crown_diameter, cohort % density )
!update time of next cut
IF ( practice % current < SIZE ( practice % cuts ) ) THEN
practice % next = practice % cuts ( practice % current + 1 ) % time
END IF
!copy practice back
forest (k) % thinning = practice
END IF
END IF
END IF
!update age
IF ( DayOfYear (time) == 1 .AND. year_new /= year_prev ) THEN
is_new_year = .TRUE.
cohort % age = cohort % age + 1
cohort % mass_stem_year_previous = cohort % mass_stem
ELSE
is_new_year = .FALSE.
END IF
!compute APAR
cohort % apar = AparCalc (rad = radiation % mat (forest (k) % i, forest (k) % j) , &
lai = cohort % lai, &
k = cohort % species % k, &
alb = cohort % species % albedo, &
dt = dtPlants)
!compute CO2 modifier
IF ( useCO2modifier ) THEN
fCO2 = CO2mod (co2, cohort % age )
ELSE
fCO2 = 1.
END IF
!compute age modifier
fAGE = AGEmod ( cohort % age, cohort % species % agemax)
!compute temperature modifier
fTEMP = TEMPmod (Ta = temperature % mat (forest (k) % i, forest (k) % j), &
Tmin = cohort % species % Tmin, &
Tmax = cohort % species % Tmax, &
Topt = cohort % species % Topt )
!compute soil water content modifier
fSWC = SWCmod (swc = swc % mat (forest (k) % i, forest (k) % j), &
wp = swp % mat (forest (k) % i, forest (k) % j), &
fc = sfc % mat (forest (k) % i, forest (k) % j), &
theta = cohort % species % theta_fswc )
!compute vapor pressure deficit modifier
fVPD = VPDmod (Ta = temperature % mat (forest (k) % i, forest (k) % j), &
RH = rh % mat (forest (k) % i, forest (k) % j), &
kd = cohort % species % theta_fvpd)
!compute gross primary production
cohort % gpp = cohort % apar * & ! absorbed photosynthetically active radiation molPAR m-2
cohort % species % alpha * &! canopy quantum efficiency (molC/molPAR)
C_molar_mass * & !conversion to Kg
hectare / & ! m2 in one hectare
1000. * & !conversion to t
fAGE * & !age modifier
fTEMP * & !temperature modifier
fSWC * & !soil water content modifier
fVPD * &!vapor pressure deficit modifier
fCO2
!compute net primary production
cohort % npp = cohort % gpp * cohort % species % GPPtoNPP
!compute root allocation factor
rootaf = 0.5 / ( 1. + 2.5 * fAGE * fTEMP * fSWC )
!compute stem allocation factor
pfs = (cohort % species % fprn * cohort % species % fpra) / &
(cohort % species % sprn * cohort % species % spra) * &
(cohort % density * cohort % dbh / 100.) ** &
(cohort % species % fprn - cohort % species % sprn)
stemaf = ( 1. - rootaf ) / ( 1. + pfs )
!compute leaf allocation factor
leafaf = 1. - rootaf - stemaf
! update stem biomass
cohort % mass_stem = cohort % mass_stem + stemaf * cohort % npp
!update root biomass
cohort % mass_root = cohort % mass_root + & !current mass
rootaf * cohort % npp - & !mass increment
cohort % species % rtr * cohort % mass_root * dtPlants !turnover rate
! update leaf biomass and leaf area index
CALL GrowLeaf (npp = cohort % npp , &
af = leafaf, &
Ta = temperature % mat (forest (k) % i, forest (k) % j), &
Tcold = cohort % species % tcold_leaf, &
swc = swc % mat (forest (k) % i, forest (k) % j), &
swp = swp % mat (forest (k) % i, forest (k) % j), &
sfc = sfc % mat (forest (k) % i, forest (k) % j), &
tr = cohort % species % ltr, &
sla = cohort % species % sla, &
mleaf = cohort % mass_leaf, &
lai = cohort % lai )
!update total biomass
cohort % mass_total = cohort % mass_root + cohort % mass_stem + cohort % mass_leaf
!update dbh and height tree every new year
!IF (is_new_year) THEN
!CALL GrowDBH (cc = cohort % canopy_cover, &
! hdmin = cohort % species % hdmin, &
! hdmax = cohort % species % hdmax, &
! ws = cohort % mass_stem, &
! dws = cohort % mass_stem - cohort % mass_stem_year_previous, &
! !dws = stemaf * cohort % npp, &
! DBH = cohort % dbh, &
! height = cohort % height)
CALL GrowDBHech2o (cc = cohort % canopy_cover, &
hdmin = cohort % species % hdmin, &
hdmax = cohort % species % hdmax, &
ws = cohort % mass_stem, &
!dws = cohort % mass_stem - cohort % mass_stem_year_previous, &
dws = stemaf * cohort % npp, &
DBH = cohort % dbh, &
height = cohort % height, &
tree_density = cohort % density, &
wood_density = cohort % species % wood_density, &
age = cohort % age, &
maxage = cohort % species % agemax )
!END IF
!update crown diameter
cohort % crown_diameter = CrownDiameter ( dbh = cohort % dbh, den = cohort % density, &
denmin = cohort % species % denmin, &
denmax = cohort % species % denmax, &
dbhdcmin = cohort % species % dbhdcmin, &
dbhdcmax = cohort % species % dbhdcmax )
!update canopy cover
cohort % canopy_cover = CanopyCover ( cohort % crown_diameter, cohort % density )
!apply mortality
IF (mortality) THEN
CALL KillPlants (dtPlants, cohort % age, cohort % species % agemax, &
cohort % species % ms, cohort % species % mf, &
cohort % species % mr, cohort % species % wSx1000, &
cohort % crown_diameter, cohort % density, &
cohort % canopy_cover, cohort % mass_stem, &
cohort % mass_root, cohort % mass_leaf, &
cohort % mass_total)
END IF
!jump to next cohort
cohort => cohort % next
END DO
END DO
year_prev = year_new
!update state variable grids
CALL ForestToGrid (lai, 'lai')
CALL ForestToGrid (fvcover, 'fv')
CALL ForestToGrid (gpp, 'gpp')
CALL ForestToGrid (npp, 'npp')
CALL ForestToGrid (carbonroot, 'root')
CALL ForestToGrid (carbonstem, 'stem')
CALL ForestToGrid (carbonleaf, 'leaf')
CALL ForestToGrid (dbh, 'dbh')
CALL ForestToGrid (plantsHeight, 'height')
CALL ForestToGrid (density, 'density')
CALL ForestToGrid (stemyield, 'stemyield')
END IF
RETURN
END SUBROUTINE PlantsGrow
!==============================================================================
!| Description:
! read species parameters
SUBROUTINE ReadSpecies &
!
(inifile)
IMPLICIT NONE
CHARACTER (LEN = *), INTENT(in) :: inifile
!local declarations:
TYPE (IniList) :: speciesDB
INTEGER (KIND = short) :: nspecies
INTEGER (KIND = short) :: i
!------------------------------end of declarations----------------------------
! open and read configuration file
CALL IniOpen (inifile, speciesDB)
nspecies = IniReadInt ('species', speciesDB)
ALLOCATE (species (nspecies) )
DO i = 1, nspecies
species (i) % name = IniReadString ('name', speciesDB, section = ToString(i))
species (i) % phenology = IniReadString ('phenology', speciesDB, section = ToString(i))
species (i) % alpha = IniReadReal ('alpha', speciesDB, section = ToString(i))
species (i) % GPPtoNPP = IniReadReal ('GPP-NPP', speciesDB, section = ToString(i))
species (i) % k = IniReadReal ('k', speciesDB, section = ToString(i))
species (i) % cra = IniReadReal ('cra', speciesDB, section = ToString(i))
species (i) % crb = IniReadReal ('crb', speciesDB, section = ToString(i))
species (i) % crc = IniReadReal ('crc', speciesDB, section = ToString(i))
species (i) % as = IniReadReal ('as', speciesDB, section = ToString(i))
species (i) % ns = IniReadReal ('ns', speciesDB, section = ToString(i))
!species (i) % saf = IniReadReal ('stem-allocation-factor', speciesDB, section = ToString(i))
!species (i) % raf = IniReadReal ('root-allocation-factor', speciesDB, section = ToString(i))
!species (i) % laf = IniReadReal ('leaf-allocation-factor', speciesDB, section = ToString(i))
species (i) % dbhdcmin = IniReadReal ('dbhdcmin', speciesDB, section = ToString(i))
species (i) % dbhdcmax = IniReadReal ('dbhdcmax', speciesDB, section = ToString(i))
species (i) % denmin = IniReadReal ('denmin', speciesDB, section = ToString(i))
species (i) % denmax = IniReadReal ('denmax', speciesDB, section = ToString(i))
species (i) % agemax = IniReadReal ('agemax', speciesDB, section = ToString(i))
species (i) % tmin = IniReadReal ('tmin', speciesDB, section = ToString(i))
species (i) % tmax = IniReadReal ('tmax', speciesDB, section = ToString(i))
species (i) % topt = IniReadReal ('topt', speciesDB, section = ToString(i))
species (i) % theta_fswc = IniReadReal ('phi-theta', speciesDB, section = ToString(i))
species (i) % theta_fvpd = IniReadReal ('phi-ea', speciesDB, section = ToString(i))
species (i) % fpra = IniReadReal ('fpra', speciesDB, section = ToString(i))
species (i) % fprn = IniReadReal ('fprn', speciesDB, section = ToString(i))
species (i) % spra = IniReadReal ('spra', speciesDB, section = ToString(i))
species (i) % sprn = IniReadReal ('sprn', speciesDB, section = ToString(i))
species (i) % ltr = IniReadReal ('leaf-turnover', speciesDB, section = ToString(i))
species (i) % rtr = IniReadReal ('root-turnover', speciesDB, section = ToString(i))
species (i) % tcold_leaf = IniReadReal ('tcold-leaf', speciesDB, section = ToString(i))
species (i) % sla = IniReadReal ('sla', speciesDB, section = ToString(i))
species (i) % hdmin = IniReadReal ('hdmin', speciesDB, section = ToString(i))
species (i) % hdmax = IniReadReal ('hdmax', speciesDB, section = ToString(i))
species (i) % albedo = IniReadReal ('albedo', speciesDB, section = ToString(i))
species (i) % laimax = IniReadReal ('laimax', speciesDB, section = ToString(i))
species (i) % canopymax = IniReadReal ('canopymax', speciesDB, section = ToString(i))
species (i) % wood_density = IniReadReal ('wood-density', speciesDB, section = ToString(i))
species (i) % ms = IniReadReal ('ms', speciesDB, section = ToString(i))
species (i) % mr = IniReadReal ('mr', speciesDB, section = ToString(i))
species (i) % mf = IniReadReal ('mf', speciesDB, section = ToString(i))
species (i) % wSx1000 = IniReadReal ('wSx1000', speciesDB, section = ToString(i))
END DO
! species DB is complete. Deallocate ini database
CALL IniClose (speciesDB)
RETURN
END SUBROUTINE ReadSpecies
!==============================================================================
!| Description:
! set initial condition
SUBROUTINE SetIC &
!
(inifile)
IMPLICIT NONE
CHARACTER (LEN = *), INTENT(in) :: inifile
!local declarations:
TYPE (IniList) :: icDB
INTEGER (KIND = short) :: ncohorts
TYPE (grid_integer) :: cohort_map
INTEGER (KIND = short) :: i, j, k, l
INTEGER (KIND = short) :: ispecies
REAL (KIND = float) :: dbh
TYPE (PlantsCohort), POINTER :: cohort
!------------------------------end of declarations----------------------------
! open and read configuration file
CALL IniOpen (inifile, icDB)
!number of cohorts
ncohorts = IniReadInt ('cohorts', icDB)
!starting year
year_new = IniReadInt ('year', icDB)
year_prev = IniReadInt ('year', icDB)
!cohort map
CALL GridByIni (icDB, cohort_map, section = 'cohorts-map')
DO k = 1, count_stands
!aggiungere configurazione ricorsiva quando ci sono più coorti per cella
!al momento solo una coorte per stand (cella)
cohort => forest (k) % first
DO l = 1, forest (k) % lenght
ispecies = IniReadInt ('species', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % species = species (ispecies)
cohort % age = IniReadInt ('age', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % density = IniReadReal ('density', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % height = IniReadReal ('height', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % dbh = IniReadReal ('dbh', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % lai = IniReadReal ('lai', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % mass_stem = IniReadReal ('stem-biomass', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % mass_root = IniReadReal ('root-biomass', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % mass_leaf = IniReadReal ('leaf-biomass', icDB, section = ToString (cohort_map % mat (forest (k) % i, forest (k) % j ) ) )
cohort % mass_total = cohort % mass_stem + cohort % mass_root + cohort % mass_leaf
cohort % crown_diameter = CrownDiameter ( dbh = cohort % dbh, den = cohort % density, &
denmin = species (ispecies) % denmin, &
denmax = species (ispecies) % denmax, &
dbhdcmin = species (ispecies) % dbhdcmin, &
dbhdcmax = species (ispecies) % dbhdcmax )
cohort % canopy_cover = CanopyCover ( cohort % crown_diameter, cohort % density )
cohort => cohort % next
END DO
END DO
! Deallocate memory
CALL IniClose (icDB)
RETURN
END SUBROUTINE SetIC
!==============================================================================
!| Description:
! Computes the absorbed photosynthetically active radiation.
! The amount of light available for the plant that is going to define
! its growth rate. The light that the plant could absorb is determined according
! to the canopy cover. The amount of absorbed photosynthetically active radiation
! is usually computed following Lambert-Beer law .
!
! References:
!
! McCree, K.J.: Test of current definitions of photosynthetically active
! radiation against leaf photosynthesis data. Agr. Forest. Meteorol,
! 10 , 443-453, 1972.
FUNCTION AparCalc &
!
(rad, lai, k, alb, dt) &
!
RESULT (apar)
IMPLICIT NONE
!arguments with intent(in):
REAL (KIND = float), INTENT(IN) :: rad !! shortwave direct radiation (w/m2)
REAL (KIND = float), INTENT(IN) :: lai !! leaf area index (m2/m2)
REAL (KIND = float), INTENT(IN) :: k !! extinction coefficient for absorption of PAR by canopy
REAL (KIND = float), INTENT(IN) :: alb !! plant albedo (0-1)
INTEGER (KIND = short), INTENT(IN) :: dt !!time step (s)
!local declarations:
REAL (KIND = float) :: apar
REAL (KIND = float) :: par0 !!photosynthetically active radiation (molPAR m-2)
REAL (KIND = float), PARAMETER :: radToPAR = 4.57 !conversion factor 1 W m-2 = 4.57 µmol m-2 s-1 (McCree, 1972)
!------------------------------end of declarations----------------------------
!devo considerare l'albedo cioè è una short wave net radiation ? o quella incidente ?
par0 = rad * ( 1. - alb ) * radToPAR * dt ! (µmol m-2)
apar = par0 * ( 1. - EXP ( -k * lai) ) / 1000000. ! (molPAR m-2)
RETURN
END FUNCTION AparCalc
!==============================================================================
!| Description:
! update leaf biomass and leaf area index
!
! References:
!
!Maneta, M. P., and N. L. Silverman, 2013: A spatially distributed model to
! simulate water, energy, and vegetation dynamics using information from
! regional climate models. Earth Interact., 17
! doi:10.1175/2012EI000472.1.
!
! Arora, V. K., and G. J. Boer, 2005: A parameterization of leaf phenology
! for the terrestrial ecosystem component of climate models.
! Global Change Biol., 11, 39–59.
!
SUBROUTINE GrowLeaf &
!
(npp, af, Ta, Tcold, swc, swp, sfc, tr, sla, mleaf, lai)
IMPLICIT NONE
!arguments with intent(in):
REAL (KIND = float), INTENT(IN) :: npp !!net primary production [t/ha]
REAL (KIND = float), INTENT(IN) :: af !!allocation factor [0-1]
REAL (KIND = float), INTENT(IN) :: Ta !! air temperature [°C]
REAL (KIND = float), INTENT(IN) :: Tcold !! temperature threshold that accelerates leaf turnover (°C)
REAL (KIND = float), INTENT(IN) :: swc !! soil water content [m3/m3]
REAL (KIND = float), INTENT(IN) :: swp !! soil wilting point [m3/m3]
REAL (KIND = float), INTENT(IN) :: sfc !! soil field capacity [m3/m3]
REAL (KIND = float), INTENT(IN) :: tr !! leaf turnover rate [s-1]
REAL (KIND = float), INTENT(IN) :: sla !! specific leaf area [m2/Kg]
!arguments with intent(inout):
REAL (KIND = float), INTENT(INOUT) :: mleaf !!mass of leaf [t/ha]
REAL (KIND = float), INTENT(INOUT) :: lai !! leaf area index [m2/m2]
!local declarations:
REAL (KIND = float) :: deltaMleaf !! leaf mass increment
REAL (KIND = float) :: swc_stress !! soil water content stress that affects leaf increment [0-1]
REAL (KIND = float) :: temp_stress !! temperature stress that affects leaf increment [0-1]
REAL (KIND = float) :: actual_tr !! actual leaf tirnover rate with temperature and soil water content stresses
!------------------------------end of declarations----------------------------
!compute temperature stress
IF (Ta >= Tcold) THEN
temp_stress = 1.
ELSE IF ((Tcold - 5.) < Ta < Tcold) THEN
temp_stress = (Ta - Tcold - 5.) / 5.
ELSE IF (Ta <= (Tcold - 5.)) THEN
temp_stress = 0.
END IF
!temp_stress = MAX (0., MIN (1., ((Ta - (Tcold - 5.) / 5. ) ) ))
!compute hydrologic stress
swc_stress = MAX (0., MIN (1., (swc - swp) / (sfc - swp) ) )
!compute actual leaf turnover rate: base turnover + 0.001 hydrologic stress + temperature stress
actual_tr = tr * ( 1. + 0.001 * (1. - swc_stress)**3. + (1. - temp_stress)**3. )
!leaf mass increment
deltaMleaf = af * npp
!update leaf biomass
mleaf = mleaf + deltaMleaf
!update leaf area index
lai = lai + (deltaMleaf * sla/ 10.) - (actual_tr * dtPlants) *LAI !10 = conversion factor 1000 [kg/t] / 10000 [m2/hectare]
!check lower boundary
IF (mleaf < 0.) THEN
mleaf = 0.
END IF
IF (lai < 0.) THEN
lai = 0.
END IF
RETURN
END SUBROUTINE GrowLeaf
!==============================================================================
!| Description:
! update DBH and height tree according to ech2o model by Maneta
!
SUBROUTINE GrowDBHech2o &
!
(cc, hdmin, hdmax, ws, dws, DBH, height, tree_density, wood_density, age, maxage)
IMPLICIT NONE
!arguments with intent(in):
REAL (KIND = float), INTENT(IN) :: cc !! canopy cover
REAL (KIND = float), INTENT(IN) :: hdmin !! H/D ratio in carbon partitioning for low density
REAL (KIND = float), INTENT(IN) :: hdmax !! H/D ratio in carbon partitioning for high density
REAL (KIND = float), INTENT(IN) :: ws !! stem biomass (t/ha)
REAL (KIND = float), INTENT(IN) :: dws !! stem biomass increment (t/ha)
REAL (KIND = float), INTENT(IN) :: tree_density !! tree density (trees/ha)
REAL (KIND = float), INTENT(IN) :: wood_density !! wood density (kg/m3)
REAL (KIND = float), INTENT(IN) :: age !! tree age (year)
REAL (KIND = float), INTENT(IN) :: maxage !!tree max age (year)
!arguments with intent inout
REAL (KIND = float), INTENT(INOUT) :: DBH !diameter at brest height (cm)
REAL (KIND = float), INTENT(INOUT) :: height !tree height (m)
!local declarations
REAL (KIND = float) :: delta_tree_mass !!tree mass increment (kg/tree)
REAL (KIND = float) :: fhd !! grow factor that depends on the height-to-diameter ratio
REAL (KIND = float) :: dDBH !DBH increment (cm)
REAL (KIND = float) :: dheight !height increment (m)
!-------------------------------end of declarations----------------------------
!compute mass increment per tree
delta_tree_mass = dws / tree_density * 1000. ! mass increment per tree (kg)
!set grow factor
IF (height / DBH >= hdmin .AND. cc < 0.95) THEN
fhd = hdmin
ELSE IF (height / DBH <= hdmax .AND. cc >= 0.95 .AND. age < maxage / 2) THEN
fhd = hdmin
ELSE IF (height / DBH <= hdmax .AND. cc >= 0.95 .AND. age > maxage / 2 ) THEN
fhd = hdmax
ELSE IF (height / DBH < hdmin) THEN
fhd = hdmax
ELSE IF (height / DBH > hdmax) THEN
fhd = 0.5 * hdmin
ELSE IF ( age > 0.7 * maxage) THEN
fhd = 0.
END IF
!compute DBH increment
dDBH = 4. * delta_tree_mass / ( wood_density * pi * (DBH / 100.)**2. * ( 2. * height / (DBH / 100.) + fhd * 100. ) ) * 100.
!compute tree height increment
dheight = dDBH * fhd
!update dbh and height tree
DBH = DBH + dDBH
height = height + dheight
!write(*,*) dDBH, dheight
!pause
RETURN
END SUBROUTINE GrowDBHech2o
!==============================================================================
!| Description:
! update DBH and height tree every new year
!
SUBROUTINE GrowDBH &
!
(cc, hdmin, hdmax, ws, dws, DBH, height)
IMPLICIT NONE
!arguments with intent(in):
REAL (KIND = float), INTENT(IN) :: cc !! canopy cover
REAL (KIND = float), INTENT(IN) :: hdmin !! H/D ratio in carbon partitioning for low density
REAL (KIND = float), INTENT(IN) :: hdmax !! H/D ratio in carbon partitioning for high density
REAL (KIND = float), INTENT(IN) :: ws !! stem biomass (t/ha)
REAL (KIND = float), INTENT(IN) :: dws !! stem biomass increment (t/ha)
!arguments with intent inout
REAL (KIND = float), INTENT(INOUT) :: DBH !diameter at brest height (cm)
REAL (KIND = float), INTENT(INOUT) :: height !tree height (m)
!local declarations
REAL (KIND = float) :: hdeff
REAL (KIND = float) :: dDBH !DBH increment (cm)
REAL (KIND = float) :: dheight !height increment (m)
!-----------------------------end of declarations------------------------------
IF ( cc <= 0.95) THEN !low density
hdeff = hdmin + (hdmax - hdmin) * cc
ELSE ! high density
hdeff = hdmax
END IF
!compute height increment
!dheight = hdeff / ( hdeff / height + 200. / dbh ) * dws / ws
dheight = hdeff / ( hdeff / height) + (200. / dbh ) * dws / ws
!compute DBH increment
dDBH = ( height / hdeff ) + ( 200. / dbh ) * ( dws / ws )
!update dbh and height tree
DBH = DBH + dDBH
height = height + dheight
!write(*,*) dheight, hdeff, dws, ws
!pause
RETURN
END SUBROUTINE GrowDBH
!==============================================================================
!| Description:
! fill in a grid with state variable values in forest stands
!
SUBROUTINE ForestToGrid &
!
(grid, statevar)
IMPLICIT NONE
!arguments with intent(in):
CHARACTER (LEN = *), INTENT(IN) :: statevar
!arguments with intent inout
TYPE (grid_real), INTENT (INOUT) :: grid
!local declarations
INTEGER (KIND = short) :: i, j, k
!-----------------------------end of declarations------------------------------
DO k = 1, count_stands
i = forest (k) % i
j = forest (k) % j
SELECT CASE (statevar)
CASE ('lai') !leaf area index
grid % mat (i,j) = forest (k) % first % lai
CASE ('fv') !canopy cover
grid % mat (i,j) = forest (k) % first % canopy_cover
CASE ('gpp') !GPP
grid % mat (i,j) = forest (k) % first % gpp * &
CellArea (grid,i,j) / hectare
CASE ('npp') !NPP
grid % mat (i,j) = forest (k) % first % npp * &
CellArea (grid,i,j) / hectare
CASE ('root') !root mass
grid % mat (i,j) = forest (k) % first % mass_root * &
CellArea (grid,i,j) / hectare
CASE ('stem') !stem mass
grid % mat (i,j) = forest (k) % first % mass_stem * &
CellArea (grid,i,j) / hectare
CASE ('leaf') !foliage mass
grid % mat (i,j) = forest (k) % first % mass_leaf * &
CellArea (grid,i,j) / hectare
CASE ('stemyield') !stem mass
grid % mat (i,j) = forest (k) % first % stem_yield * &
CellArea (grid,i,j) / hectare
CASE ('dbh') !diameter at brest heigth (cm)
grid % mat (i,j) = forest (k) % first % dbh
CASE ('height') !tree height (m)
grid % mat (i,j) = forest (k) % first % height
CASE ('density') !tree density (trees/hectare)
grid % mat (i,j) = forest (k) % first % density
END SELECT
END DO
RETURN
END SUBROUTINE ForestToGrid
END MODULE Plants