Forked from
4C / FORESEE
182 commits behind the upstream repository.
-
Petra Lasch-Born authoredPetra Lasch-Born authored
partitio.f 27.35 KiB
!*****************************************************************!
!* *!
!* 4C (FORESEE) Simulation Model *!
!* *!
!* *!
!* Subroutines for: *!
!* - Calculation of annual allocation of NPP (SR PARTITION) *!
!* - Calculation of annual allocation of NPP of soil *!
!* vegetation (PARTITION_SV *!
!* - Calculation of diameter at breast height (SR CALC_DBH) *!
!* *!
!* Copyright (C) 1996-2018 *!
!* Potsdam Institute for Climate Impact Reserach (PIK) *!
!* Authors and contributors see AUTHOR file *!
!* This file is part of 4C and is licensed under BSD-2-Clause *!
!* See LICENSE file or under: *!
!* http://www.https://opensource.org/licenses/BSD-2-Clause *!
!* Contact: *!
!* https://gitlab.pik-potsdam.de/foresee/4C *!
!* *!
!*****************************************************************!
!****************************!
!* SUBROUTINE PARTITION *!
!****************************!
SUBROUTINE PARTITION( p )
!*** Declaration part ***!
USE data_out
USE data_par
USE data_stand
USE data_species
USE data_simul
IMPLICIT NONE
REAL :: lambdaf = 0., & ! partitioning functions
lambdas = 0., &
lambdar = 0., &
lambdac = 0., &
lambdaSum = 0.,& ! sum of the above three lambdas
NPP = 0., & ! annual NPP
F = 0., & ! state variables: foliage,
S = 0., & ! sapwood,
H = 0., & ! heartwood
R = 0., & ! fine roots,
B = 0., & ! bole height,
Ahb = 0., & ! cross sectional area heartwood at tree base
hs = 0., & ! sapwood height
Ht = 0., & ! total tree height
Asw = 0., & ! cross sectional area of sapwood in bole
DBH = 0., & ! tree diameter at breast height (DBH)
FNew, SNew, & ! new states
RNew, BNew, &
HtNew, &
HNew, Ahbnew, &
sigmaf = 0., & ! current leaf activity rate
sigman = 0., & ! current root activity rate
ar = 0., & ! aux vars for partitioning functions
as = 0., &
ac = 0., &
betar = 0., &
betas = 0., &
aux = 0., &
Fmax, & ! determines whether height growth or not
rsap, & ! auxiliary variable for height growth determination
growthrate ! height growthrate depends on relative light regime in the middle of the canopy
REAL :: Sf, & ! senescence rates
Ss, &
Sr, &
Gf, & ! growth rates
Gs, &
Gr
real :: DBH_help
REAL :: leaf_N_conc, & ! last years N concentration in leaves gN kgDM
tbc_root_Ndemand, & ! N demand for ghrowth of fine roots, branches and coarse roots g tree-1
Nredfak ! reduction factor for N allocation to fine roots, branches and coarse roots
TYPE(Coh_Obj) :: p ! pointer to cohort list
REAL :: term1, &
a1, a2, a3, & ! coefficients of quadratic equation
x1 = 0., &
x2 = 0. ! solutions of quadratic equation
real :: Fmax_old
! if this cohort is mistletoe infected, reduce NPP by mistletoe-specific demand
! demand is defined in PARTITION_MI. as mistletoe is always 1st cohort, the demand of mistletoe is calculated before the reduction here
if (p%coh%mistletoe.eq.1) then
p%coh%NPP = p%coh%NPP-(NPP_demand_mistletoe/p%coh%ntreea)
endif
ns = p%coh%species
F = p%coh%x_fol
Fmax = p%coh%Fmax
S = p%coh%x_sap
R = p%coh%x_frt
H = p%coh%x_hrt
B = p%coh%x_hbole
NPP = p%coh%NPP
Ht = p%coh%height
Ahb = p%coh%x_Ahb
Sf = p%coh%sfol
Ss = p%coh%ssap
Sr = p%coh%sfrt
hs = p%coh%x_hsap
Asw = p%coh%Asapw
Fmax_old = Fmax
DBH_help = p%coh%diam
if (flag_end.eq.1) then
p%coh%notViable = .TRUE.
flag_end = 0
end if
if(p%coh%notViable.neqv..TRUE.) then
select case (flag_folhei)
case (1,4)
spar(ns)%pha = spar(ns)%pha_v1 * spar(ns)%pha_v3 * &
(F)**(-1-spar(ns)%pha_v3)/(spar(ns)%pha_v2+(F)**(-spar(ns)%pha_v3))**2.
case (2)
rsap=Asw/(Asw+Ahb)
spar(ns)%pha = 2.*spar(ns)%crown_a/(pi**0.5*(rsap*spar(ns)%pnus)**1.5*F**0.5)
case (3)
! this version only for tests and pine trees
spar(ns)%pha = (3500*(10.+F**0.9)-(0.9*3500.*F**0.9))/(10.+F**0.9)**2
end select ! flag_folhei
! only allocate if enough NPP is available
IF (NPP>1.0E-9) THEN
select case (flag_folhei)
case (0)
growthrate=spar(ns)%pha*spar(ns)%pha_coeff1 + spar(ns)%pha*spar(ns)%pha_coeff2*(1./p%coh%IrelCan-1.)
case (1,3)
growthrate=spar(ns)%pha + spar(ns)%pha*(1./MAX(p%coh%IrelCan,0.25)-1.)
case (2)
growthrate=spar(ns)%pha + spar(ns)%pha*(1.-p%coh%IrelCan)*5.
case (4)
growthrate=spar(ns)%pha *0.5/MAX(p%coh%IrelCan,0.25)
end select ! flag_folhei
sigmaf = NPP/F
! calculate root activity based on drought index
! test of a relationship which modifies fine root leaf ratio with shade tolerance:
IF (flag_sign.eq.1 .or. flag_sign.eq.11) THEN
term1 = spar(ns)%sigman * 10. * (((5.-spar(ns)%stol)*1.-p%coh%crown_area) / (5.-spar(ns)%stol)*1.)
sigman = amax1(term1,spar(ns)%sigman) * p%coh%drIndAl/p%coh%nDaysGr
ELSE
sigman = spar(ns)%sigman * p%coh%drIndAl / p%coh%nDaysGr
END IF
if (flag_sign .eq. 0 .or. flag_sign .eq. 1) then
! auxiliary variables for fine roots
ar = spar(ns)%pcnr * sigmaf / sigman
betar = (Sr - R + ar*(F-Sf)) / NPP
! auxiliary variables for sapwood
as = spar(ns)%prhos / spar(ns)%pnus
aux = 2.*(B+p%coh%deltaB) + Ht
betas = ( (as/3.)*(aux - growthrate*Sf) * (F-Sf) + Ss - S ) / NPP
! solve quadratic equation for lambdaf
term1 = (1.+spar(ns)%alphac)
a1 = term1 * as/3. * growthrate * NPP
a2 = 1.0 + ar + term1 * as/3. * (aux + growthrate*(F-2.*Sf))
a3 = term1*betas + betar - 1.
x1 = (-a2 + SQRT( a2*a2 - 4.*a1*a3) ) / (2.*a1)
x2 = (-a2 - SQRT( a2*a2 - 4.*a1*a3) ) / (2.*a1)
lambdaf = x1
if (lambdaf .le. 0. .or. lambdaf .gt. 1.) then
lambdaf = 0.5
lambdar = 0.5
lambdas = 0.
lambdac = 0.
else
! calculate coefficients for sapwood and roots
lambdar = ar * lambdaf + betar;
lambdas = as/3. * (aux + growthrate*(F+lambdaf*NPP-2.*Sf)) * lambdaf + betas
lambdac = spar(ns)%alphac * lambdas
! check consistency of calculation, i.e. no negative values
IF(lambdas < 0. .or. lambdas .gt. 1.) THEN
lambdas = 0.
lambdac = 0.
lambdaf = (1.-betar)/(ar+1)
lambdar = 1.-lambdaf
if (lambdaf .le. 0. .or. lambdaf .gt. 1.) then
lambdaf = 0.5
lambdar = 0.5
else if (lambdar<0) then
lambdar=0.
lambdaf=1.
end if
ELSE
! reduced allocation schemes for lamdaf<0. or lamdar<0. still to be added
lambdaf = AMAX1( lambdaf, 0. )
lambdar = AMAX1( lambdar, 0. )
! warrant that lambdaSum = 1 if balance can not be achieved this time step
lambdaSum = lambdaf + (1.+spar(ns)%alphac)*lambdas + lambdar
lambdaf = lambdaf / lambdaSum
lambdas = lambdas / lambdaSum
lambdar = lambdar / lambdaSum
lambdac = lambdac / lambdaSum
lambdaSum = lambdaf + (1.+spar(ns)%alphac)*lambdas + lambdar ! for debugging only
END IF
end if ! lambdaf .le. 0.
else ! flag_sign = 10, 11
! auxiliary variables for fine roots
ar = spar(ns)%pcnr * sigmaf / sigman
betar = (Sr - ar*Sf) / NPP
! auxiliary variables for sapwood
as = spar(ns)%prhos / spar(ns)%pnus
betas = (Ss - 2.*as*hs*Sf ) / NPP
! auxiliary variables for coarse roots, twigs and branches
ac = spar(ns)%alphac
! linear equation system in lamda(i)
term1 = 1. + ar + 2.*as*hs*(1+ac)
lambdaf = 1. - (1.+ac)*betas - betar
lambdaf = lambdaf / term1
lambdar = ar * lambdaf + betar
lambdas = 2.*as*hs * lambdaf + betas
lambdac = ac * lambdas
if (lambdaf .le. 0. .or. lambdaf .gt. 1.) then
lambdaf = 0.5
lambdar = 0.5
lambdas = 0.
lambdac = ac * lambdas
else
! calculate coefficients for sapwood and roots
lambdar = ar * lambdaf + betar;
lambdas = 2.*as*hs * lambdaf + betas
lambdac = ac * lambdas
! check consistency of calculation, i.e. no negative values
IF(lambdas < 0. .or. lambdas .gt. 1.) THEN
lambdas = 0.
lambdac = 0.
lambdaf = (1.-betar)/(ar+1)
lambdar = 1.-lambdaf
if (lambdaf .le. 0. .or. lambdaf .gt. 1.) then
lambdaf = 0.5
lambdar = 0.5
else if (lambdar<0) then
lambdar=0.
lambdaf=1.
end if
ELSE
! reduced allocation schemes for lamdaf<0. or lamdar<0. still to be added
lambdaf = AMAX1( lambdaf, 0. )
lambdar = AMAX1( lambdar, 0. )
! warrant that lambdaSum = 1 if balance can not be achieved this time step
lambdaSum = lambdaf + (1.+spar(ns)%alphac)*lambdas + lambdar
lambdaf = lambdaf / lambdaSum
lambdas = lambdas / lambdaSum
lambdar = lambdar / lambdaSum
lambdac = lambdac / lambdaSum
lambdaSum = lambdaf + (1.+spar(ns)%alphac)*lambdas + lambdar ! for debugging only
END IF
end if ! lambdaf .le. 0.
endif ! flag_sign
ELSE
lambdaf = 0.
lambdas = 0.
lambdar = 0.
END IF ! IF NPP < 1.0E-09
! gross growth rates of compartments
Gf = lambdaf * NPP
Gr = lambdar * NPP
Gs = lambdas * NPP
p%coh%gfol = Gf
p%coh%gfrt = Gr
p%coh%gsap = Gs
p%coh%x_crt = p%coh%x_crt + Gs*spar(ns)%alphac*spar(ns)%cr_frac
p%coh%x_tb = p%coh%x_tb + Gs*spar(ns)%alphac*(1.-spar(ns)%cr_frac)
! update of state vector
FNew = F + Gf - Sf
SNew = S + Gs - Ss
RNew = R + Gr - Sr
Hnew = H + Ss
AhbNew= Ahb + Asw*spar(ns)%pss
! check whether height growth or not
IF (lambdas == 0.OR.FNew<Fmax) THEN ! treat special case where there is no height growth
HtNew = Ht
ELSE
! height growth depending on the relative light regime in the middle of the canopy
HtNew = Ht + growthrate * (FNew-Fmax)
Fmax=FNew
ENDIF
BNew = B+p%coh%deltaB
! copy back to original variables
p%coh%Fmax = Fmax
p%coh%x_fol = FNew
p%coh%x_sap = SNew
p%coh%x_frt = RNew
p%coh%x_hrt = HNew
p%coh%height = HtNew
p%coh%x_hbole= BNew
p%coh%x_Ahb = AhbNew
CALL CALC_DBH(BNew,Htnew,Snew,Hnew,Ahbnew,p%coh%Ahc,p%coh%ident,DBH,p%coh%dcrb,hs,Asw)
if (flag_end.eq.1) then
DBH = p%coh%diam
p%coh%notViable = .TRUE.
flag_end = 0
end if
! Monitoring of current values
if (time_out .gt. 0 .and. flag_cohout .eq. 2) then
CALL OUT_ALL( p%coh%ident, p%coh%ntreea, NPP, DBH, growthrate,Fnew,Fmax_old,Htnew, lambdaf,lambdas,lambdar,lambdac,x1,x2)
endif
p%coh%x_hsap = hs
p%coh%diam = DBH ! This is the new value
p%coh%Asapw = Asw
p%coh%jrb = (DBH-DBH_help)*10/2
if(((DBH-DBH_help)*10/2).lt.0.) p%coh%jrb = 0.
! variables required by mortality submodel
p%coh%fol_inc = Gf - Sf
p%coh%bio_inc = NPP - Sf - (1.+spar(ns)%alphac)*Ss - Sr
p%coh%stem_inc = Gs ! deltaH + deltaS = Ss + Gs - Ss
p%coh%frt_inc = Gr - Sr ! fine root increment
p%coh%totBio = p%coh%x_fol + (1.+spar(ns)%alphac)*(p%coh%x_sap + p%coh%x_hrt) + p%coh%x_frt
p%coh%notViable = (FNew <= 0.) .OR. (SNew <= 0.) .OR. &
(RNew <= 0.) .OR. (Htnew <= Bnew)
! Nitrogen dynamics:
leaf_N_conc = p%coh%N_fol/F
! Simple model: all (sap)wood grows with CN-ratios of branches, twigs and coarse roots.
! When sapwood senesces N is reallocated and the new heart wood is at the level of stem CN-ratios.
! Branches, twigs and coarse roots do not senesce
! first step nitrogen related processes: N in litter, N-recallocation
p%coh%N_pool = p%coh%N_pool + Sf/F*p%coh%N_fol*spar(ns)%reallo_fol &
+ Sr*cpart/spar(ns)%cnr_frt*1000.* spar(ns)%reallo_frt &
+ Ss*cpart *1000. * (1/spar(ns)%cnr_tbc - 1/spar(ns)%cnr_stem)
p%coh%N_fol = p%coh%N_fol*(1-Sf/F)
p%coh%litC_fol = p%coh%litC_fol + p%coh%ntreea * Sf * cpart
p%coh%litC_frt = p%coh%litC_frt + p%coh%ntreea * Sr * cpart
! Species specific N content and reallocation factor (see species.par)
! Caution: tbc mortallity is not a litter compartment; it is assigned as heartwood
p%coh%litN_fol = p%coh%litN_fol + p%coh%ntreea * Sf * cpart * (1.-spar(ns)%reallo_fol) / spar(ns)%cnr_fol
p%coh%litN_frt = p%coh%litN_frt + p%coh%ntreea * Sr * cpart * (1.-spar(ns)%reallo_frt) / spar(ns)%cnr_frt
! second step: allocation of N to new growth
! before bud-break allocation to leaves is 50% of the N content of last years foliage
tbc_root_Ndemand = Gs*cpart *kg_in_g / spar(ns)%cnr_tbc + Gr* cpart/spar(ns)%cnr_frt*kg_in_g
IF(tbc_root_Ndemand + Gf*p%coh%med_sla*0.5 > p%coh%N_pool) THEN
if (tbc_root_Ndemand .gt. 1E-8) then
Nredfak = AMAX1((p%coh%N_pool-Gf*p%coh%med_sla*0.5) / tbc_root_Ndemand,0.) ! Division by zero possible
else
Nredfak = 0.
endif
tbc_root_Ndemand = tbc_root_Ndemand*Nredfak
ENDIF
p%coh%N_pool = p%coh%N_pool - tbc_root_Ndemand
IF(p%coh%N_pool < Gf*0.5*leaf_N_conc) THEN
p%coh%N_fol = p%coh%N_fol + p%coh%N_pool
p%coh%N_pool = 0.
ELSE
p%coh%N_fol = p%coh%N_fol + Gf*0.5*leaf_N_conc
p%coh%N_pool = p%coh%N_pool - Gf*0.5*leaf_N_conc
ENDIF
end if
END SUBROUTINE PARTITION
!*******************************!
!* SUBROUTINE PARTITION_SV *!
!*******************************!
SUBROUTINE PARTITION_SV( p )
!*** Declaration part ***!
USE data_par
USE data_stand
USE data_species
USE data_simul
IMPLICIT NONE
REAL :: lambdaf = 0., & ! partitioning functions
lambdas = 0., &
lambdar = 0., &
NPP = 0., & ! annual NPP
F = 0., & ! state variables: foliage,
S = 0., & ! sapwood,
R = 0., & ! fine roots,
Ht = 0., & ! total tree height
FNew, SNew, & ! new states
RNew, &
sigmaf = 0., & ! current leaf activity rate
sigman = 0. ! current root activity rate
REAL :: Sf, & ! senescence rates
Ss, &
Sr, &
Gf, & ! growth rates
Gs, &
Gr
REAL :: FRsum
REAL :: tbc_root_Ndemand, & ! N demand for ghrowth of fine roots, branches and coarse roots g tree-1
Nredfak ! reduction factor for N allocation to fine roots, branches and coarse roots
REAL, EXTERNAL :: f_lf, df_lf, ddf_lf
INTEGER :: flag_SV_allo, &
rnum
TYPE(Coh_Obj) :: p ! pointer to cohort list
ns = p%coh%species
F = p%coh%x_fol
S = p%coh%x_sap
R = p%coh%x_frt
NPP = p%coh%NPP
Ht = p%coh%height
Sf = p%coh%sfol
Ss = p%coh%ssap
Sr = p%coh%sfrt
! choice of allocation model. 0 = constant allocation factors, 1 = allometric model
flag_SV_allo = 1
! only allocate if enough NPP is available
IF (NPP>1.0E-9) THEN
! calculate leaf activity based on net PS and leaf mass
sigmaf = NPP/F
! calculate root activity based on drought index
! test of a relationship which modifies fine root leaf ratio with shade tolerance
IF (flag_sign.eq.1) THEN
sigman = amax1(spar(ns)%sigman*10*(((5.-spar(ns)%stol)*1.-p%coh%crown_area)/(5.-spar(ns)%stol)*1.),spar(ns)%sigman) * p%coh%drIndAl / p%coh%nDaysGr
ELSE
sigman = spar(ns)%sigman * p%coh%drIndAl / p%coh%nDaysGr
END IF
M_avail=(NPP+F-Sf+R-Sr+S-Ss)/kpatchsize
IF(flag_SV_allo==0) THEN
! the parameters pdiam in the species.par file are used for allocation fractions
lambdaf=spar(ns)%pdiam1
lambdar=spar(ns)%pdiam2
lambdas=spar(ns)%pdiam3
ELSE
FRsum=(F+R)/kpatchsize
CALL newt (FRsum, f_lf, df_lf, ddf_lf, 1.e-6, 100, rnum)
IF(FRsum>M_avail .and. .not.flag_mult8910) CALL error_mess(time,'no solution found for allocation for groundvegetation cohort, rnum: ',real(rnum))
IF(rnum==-1) THEN
if (.not.flag_mult8910) CALL error_mess(time,'no solution found for allocation for groundvegetation cohort: ',real(p%coh%ident))
lambdaf=0.4
lambdar=0.4
lambdas=0.2
ELSE
lambdaf=(FRsum)/M_avail/2.
lambdar=(FRsum)/M_avail/2.
lambdas=1.-lambdaf-lambdar
ENDIF
ENDIF
END IF ! IF NPP < 1.0E-09
! gross growth rates of compartments
Gf = lambdaf * M_avail*kpatchsize -F +Sf
Gr = lambdar * M_avail*kpatchsize -R +Sr
Gs = lambdas * M_avail*kpatchsize -S +Ss
! preliminary solution for permanent seeding
IF(lambdaf * M_avail < 1.e-4) THEN
Gf = Gf + 1.e-4*kpatchsize
ENDIF
p%coh%gfol = Gf
p%coh%gfrt = Gr
p%coh%gsap = Gs
! update of state vector
FNew = F + Gf - Sf
SNew = S + Gs - Ss
RNew = R + Gr - Sr
p%coh%x_fol = FNew
p%coh%x_sap = SNew
p%coh%x_frt = RNew
! determine litter production from plant turnover rates
! first step nitrogen related processes: N in litter, N-recallocation
p%coh%N_pool = p%coh%N_pool + Sf/F*p%coh%N_fol*spar(ns)%reallo_fol &
+ Sr*cpart/spar(ns)%cnr_frt*1000.* spar(ns)%reallo_frt &
+ Ss*cpart *1000. * (1/spar(ns)%cnr_tbc - 1/spar(ns)%cnr_stem)
p%coh%N_fol = p%coh%N_fol*(1-Sf/F)
! Summation, due to the filling of the pool at other points as well
p%coh%litC_fol = p%coh%litC_fol + p%coh%ntreea * Sf * cpart
p%coh%litC_frt = p%coh%litC_frt + p%coh%ntreea * Sr * cpart
! New version with species specific N content and reallocation factor (see species.par)
! changed to 1-reallo
p%coh%litN_fol = p%coh%litN_fol + p%coh%ntreea * Sf * cpart * (1.-spar(ns)%reallo_fol) / spar(ns)%cnr_fol
p%coh%litN_frt = p%coh%litN_frt + p%coh%ntreea * Sr * cpart * (1.-spar(ns)%reallo_frt) / spar(ns)%cnr_frt
! second step: allocation of N to new growth
! before bud-break allocation to leaves is 50% of the N content of last years foliage
tbc_root_Ndemand = Gs*cpart *kg_in_g / spar(ns)%cnr_tbc + Gr* cpart/spar(ns)%cnr_frt*kg_in_g
IF(tbc_root_Ndemand + Gf*p%coh%med_sla*0.5 > p%coh%N_pool) THEN
if (tbc_root_Ndemand .gt. 1E-8) then
Nredfak = AMAX1((p%coh%N_pool-Gf*p%coh%med_sla*0.5) / tbc_root_Ndemand,0.) ! Div. by zero possible !
else
Nredfak = 0.
endif
tbc_root_Ndemand = tbc_root_Ndemand*Nredfak
ENDIF
p%coh%N_pool = p%coh%N_pool - tbc_root_Ndemand
END SUBROUTINE PARTITION_SV
!*******************************!
!* SUBROUTINE PARTITION_MI *!
!*******************************!
SUBROUTINE PARTITION_MI( p )
!*** Declaration part ***!
USE data_par
USE data_stand
USE data_simul
IMPLICIT NONE
TYPE(Coh_Obj) :: p ! pointer to cohort list
!no partitioning, foliage mass keeps constant
p%coh%x_fol = p%coh%x_fol ! !FNew
p%coh%x_sap = 0.!SNew
p%coh%x_frt = 0.!RNew
END SUBROUTINE PARTITION_MI
!***************************!
! FUNCTION f_lf *!
!***************************!
REAL FUNCTION f_lf(x)
USE data_stand
USE data_plant
REAL :: x
f_lf = ksi*x**kappa + x - M_avail
END ! FUNCTION f_lf
!***************************!
! FUNCTION df_lf *!
!***************************!
REAL FUNCTION df_lf(x)
USE data_stand
USE data_plant
REAL :: x
df_lf = ksi*kappa*x**(kappa-1.) + 1.
END ! FUNCTION df_lf
!***************************!
! FUNCTION ddf_lf *!
!***************************!
REAL FUNCTION ddf_lf(x)
USE data_stand
USE data_plant
REAL :: x
ddf_lf = ksi*kappa*(kappa-1.)*x**(kappa-2.)
END ! FUNCTION ddf_lf
!***************************!
! SUBROUTINE CALC_DBH *!
!***************************!
SUBROUTINE CALC_DBH(B, Ht, S, H, Ahb, Ahc, ident, dbh, dc, hs, Asw)
!*** Declaration part ***!
USE data_par
USE data_species
USE data_simul
IMPLICIT NONE
INTEGER :: ident
REAL :: Dc ! diameter at crown base
REAL :: B, & ! bole height,
Ht, & ! total tree height
S, & ! sapwood
H, & ! heartwood
hs, & ! sapwood height
D, & ! stem diameter at forest floor
DBH, & ! tree diameter at breast height
Ahb, & ! cross sectional area heartwood at tree base
Ahc, & ! cross sectional area of heartwood at crown base
Asw, & ! cross sectional area of sapwood in bole
discr, func, help, hp1, hp2,hp3, hp4
REAL :: fp, fq, & ! coefficients of quadratic equation
w1, w2, & ! solutions of quadratic equation
precision ! criterion for acceptance of solution
real :: sprhos ! sapwood density [kg/cm3]
!*** Calculation part ***!
precision = 1.e-5
sprhos = spar(ns)%prhos
! calculate Diameters
hs = (2*B +Ht)/3.
Asw = S/(spar(ns)%prhos*hs)
! if Bole height >= height trees are dead and calculations not required
IF(B .lt. Ht) THEN
select case (flag_volfunc)
case (0)
D = SQRT( (S+H)*4. / (sprhos*hs*pi) )
IF (Ht<h_breast) THEN
DBH = 0.0
ELSEIF (Ht>h_breast.and.B<h_breast) then
DBH=D-(D/(Ht-B))*(h_breast-B)
ELSE
DBH=D
ENDIF
case (1)
D = SQRT((Ahb+Asw)*4./pi)
! if Bole height = 0 then there is no need to calulate Diameter at crown base and Dc = D
IF(B.EQ.0.) THEN
Dc = D
ELSE
fp = -2. * (B/Ht) * (3.*H/(sprhos*B)-Ahb)-Ahb*(B/Ht)**2.
fp = -2. * B/Ht * (3.*H/(sprhos*B)-Ahb)-Ahb*(B/Ht)**2.
fq = ((3.*H/(sprhos) - Ahb*B) / Ht)**2.
discr = fp**2./4.-fq
if (abs(discr) .lt. zero) then
discr = zero ! avoid small values
endif
! No solution
if(discr.lt.0) then
if (.not.flag_mult8910) then
CALL error_mess(time,'discriminant < 0 in calc_dbh for cohort: ',real(ident))
CALL stop_mess(time,'discriminant < 0 in calc_dbh ')
CALL error_mess(time,'stop in calc_dbh for stand No: ',real(ip))
CALL error_mess(time,'heart wood mass H: ',H)
CALL error_mess(time,'bole height b: ',b)
CALL error_mess(time,'height Ht: ',Ht)
CALL error_mess(time,'ave. sapwood height hs: ',hs)
CALL error_mess(time,'sapwood area Asw: ',Asw)
CALL error_mess(time,'heartwood area at stem base Ahb: ',Ahb)
endif
flag_end = 1
return
end if
discr = SQRT(discr)
w1 = -fp/2. + discr
w2 = -fp/2. - discr
1313 hp1 = SQRT(w1*Ahb)
hp2 = (Ahb+SQRT(w1*Ahb))*B
hp3 = (w1*Ht + (Ahb+SQRT(w1*Ahb))*B)
help = (sprhos/3.) * (w1*Ht + (Ahb+SQRT(w1*Ahb))*B)
func = (sprhos/3.) * (w1*Ht + (Ahb+SQRT(w1*Ahb))*B) - H
hp4= H* precision
IF(abs(func) <= H * precision) THEN
Ahc = w1
if (.not.flag_mult8910) then
CALL error_mess(time,' positive root is a solution in calc_dbh for cohort: ',real(ident))
CALL error_mess(time,'stop in calc_dbh for stand No: ',real(ip))
CALL error_mess(time,'function: ',func)
endif
flag_end = 1
return
ELSE
func = (sprhos/3.) * (w2*Ht + (Ahb+SQRT(w2*Ahb))*B) - H
IF(abs(func) <= H * precision) THEN
Ahc = w2
ELSE
IF(precision.LT.1e-2) THEN
precision = precision*10.
GOTO 1313
if (.not.flag_mult8910) then
CALL error_mess(time,'no valid solution found in calc_dbh for heartwood geometry for cohort: ',real(ident))
CALL error_mess(time,': heart wood mass, H = ',H)
CALL error_mess(time,': precision requirement = ',precision)
CALL error_mess(time,'iteration in stand No: ',real(ip))
endif
ELSE
if (.not.flag_mult8910) then
CALL error_mess(time,'no valid solution found in calc_dbh for heartwood geometry for cohort: ',real(ident))
CALL stop_mess(time,'no valid solution found in calc_dbh for heartwood geometry')
CALL error_mess(time,'species No: ',real(ns))
CALL error_mess(time,'stop in calc_dbh for stand No: ',real(ip))
CALL error_mess(time,'precision requirement H*precision ',H*precision)
CALL error_mess(time,'heart wood mass H: ',H)
CALL error_mess(time,'bole height b: ',b)
CALL error_mess(time,'height Ht: ',Ht)
CALL error_mess(time,'ave. sapwood height hs: ',hs)
CALL error_mess(time,'sapwood area Asw: ',Asw)
CALL error_mess(time,'heartwood area at stem base Ahb: ',Ahb)
endif
flag_end = 1
return
ENDIF
ENDIF
ENDIF
Dc = SQRT((Ahc+Asw)*4./pi)
END IF
if (Ht<=h_breast) then
DBH = 0.0
else if (Ht>h_breast.and.B<h_breast) then
DBH=Dc*(Ht-h_breast)/(Ht-B)
else
DBH=D-(D-Dc)*h_breast/B
end if
end select
ELSE
if (.not.flag_mult8910) then
CALL error_mess(time,'no calculation of heartwood geometry for cohort (Bole height >= height trees are dead): ',real(ident))
CALL error_mess(time,'bole height: ',b)
CALL error_mess(time,'height: ',Ht)
endif
END IF ! if B > Ht
END SUBROUTINE CALC_DBH