Skip to content
Snippets Groups Projects
npp.f 17 KiB
Newer Older
Petra Lasch-Born's avatar
Petra Lasch-Born committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
!*****************************************************************!
!*                                                               *!
!*                     4C (FORESEE)                              *!
!*                                                               *!
!*                                                               *!
!*                    Subroutines for:                           *!
!*                Calculation of daily NPP                       *!
!*                                                               *!
!*  SR OPT_PS: optimum photosynthesis & conductance calculation  *!
!*  SR NPP:    determination of realized net primary production  *!
!*                                                               *!
!*                  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 OPT_PS  *!
!***********************!

! calculates optimum photosynthesis following Haxeltine & Prentice (1996)

SUBROUTINE OPT_PS(temp, dayl, PAR, ApPa)

  !*** Declaration part ***!

  USE data_species
  USE data_stand
  USE data_simul
  USE data_climate
  USE data_par

  IMPLICIT NONE

  ! input variables
  REAL     :: temp,          & ! temperature
              dayl,          & ! day length
              PAR              ! total available PAR

  ! auxiliary variables
  REAL     :: ApPa,          & ! atmospheric pressure [Pa], input [hPa]
              VmOpt = 0.,    &
              VmMax = 0.,    & ! nitrogen limited carboxylation rate
              Jc = 0.,       & ! Rubisco limited rate of photosynthesis
              Je = 0.,       & ! photosynthetic response under light limitation
              assiSpe = 0.,  & ! specific gross photosynthesis [gC m-2 canopy projection d-1]
              respSpe = 0.,  & ! specific leaf respiration [gC m-2 canopy projection d-1]
              assDt,         & ! net daytime assimilation rate              
              PHIT = 0.,     &
              XHELP = 0.,    &
              kco2,          &    
              ko2,           &
              tau,           & ! Rubisco specificity
              piCO2,         & ! leaf internal CO2 partial pressure [Pa]
              gammas,        & ! CO2 compensation point in absence of mitochondrial respiration [Pa]
              delta,         &
              sigma,         &
              c1,            &
              c2,            &
              vmspe,         &
			  redn_h,        &
			  h_age    
                               
  ! variables required for technical reasons
  ! INTEGER  :: nl               ! loop variable for crown layers
  integer ntr, i, j
  
  TYPE(coh_obj), POINTER :: p


 !*** Calculation part ***!

! conversion of pressure from [kPa] to [P] 
  ApPa = ApPa * 100.   ! hPa ==> Pa

  ! initialization of canopy conductance
  gp_can = 0.
  gp_tot = 0.
  phot_C=0.
  ! polar night 
  if (dayl .lt. zero) then
      p => pt%first
      DO WHILE (ASSOCIATED(p))
        p%coh%LUE     = 0.0
        p%coh%assi    = 0.0
        p%coh%resp    = 0.0
        p%coh%gp      = 0.0
        p%coh%Ndemc_d = 0.0
      
        p => p%next
      enddo
      return
  endif
  
  
  ! Determination of photosynthesis nitrogen reduction factor RedN for species
    select case (flag_limi)   	       
    case (11)
         do j=1,anrspec
           i = nrspec(j)
           redn_h = svar(i)%RedN
           if(svar(i)%Ndem .gt. 0) then
               svar(i)%RedN = svar(i)%Nupt / svar(i)%Ndem
               if (svar(i)%RedN .gt. 1.) svar(i)%RedN=1.
           else
               svar(i)%RedN = redn_h
           endif
         enddo

	case (12)
         do j=1,anrspec
           i = nrspec(j)
           redn_h = svar(i)%RedN
           if(svar(i)%Ndem .gt. 0) then
               if (svar(i)%Nupt .gt. svar(i)%Ndem) then
                    svar(i)%RedN = 1
               else
                    svar(i)%RedN = exp((svar(i)%Nupt / svar(i)%Ndem) -1.)
               endif
           else
               svar(i)%RedN = redn_h
           endif
         enddo

	case (13,14)
         do j=1,anrspec
           i = nrspec(j)
           redn_h = svar(i)%RedN
           if(svar(i)%Ndem .gt. 0) then
               xhelp = svar(i)%Nupt / svar(i)%Ndem
                  svar(i)%RedN = 2.*(xhelp+0.01) / (xhelp+1.)
           else
               svar(i)%RedN = redn_h
           endif
           if(svar(i)%Nupt .le. zero) svar(i)%RedN = redn_h 
         enddo

	case (15)
         do j=1,anrspec
           i = nrspec(j)
           redn_h = svar(i)%RedN
           if(svar(i)%Ndem .gt. zero) then
               xhelp = svar(i)%Nupt / svar(i)%Ndem
               select case (i)    
               case (3)       ! pine   
                  if (xhelp .gt. 10.) then
                      svar(i)%RedN=1.
                  else
                      svar(i)%RedN = exp(xhelp -0.7) - 0.5
                  endif
               
               case (10, 14)      ! dougfir, ground vegetation
                  continue      ! annual calculation in RedN_calc
              
               case default 
                  svar(i)%RedN = 2.*(xhelp+0.01) / (xhelp+1.)
               
               end select
               if (svar(i)%RedN .gt. 1.) svar(i)%RedN=1.
               if (svar(i)%RedN .lt. 0.1) svar(i)%RedN=0.1
          else
               svar(i)%RedN = redn_h
           endif
           if(svar(i)%Nupt .le. zero) svar(i)%RedN = redn_h 
           if (i.eq.nspec_tree+2) then
             svar(i)%RedN=1.
           endif
         enddo
	
	case (16)
        svar%Ndemp = -1.*svar%Ndemp
        svar%Nuptp = -1.*svar%Nuptp
	    zeig => pt%first
        DO WHILE (ASSOCIATED(zeig))
          
            ns = zeig%coh%species
	        ntr = zeig%coh%ntreea
            svar(ns)%Ndemp = svar(ns)%Ndemp + ntr * zeig%coh%Ndemc_c
            svar(ns)%Nuptp = svar(ns)%Nuptp + ntr * zeig%coh%Nuptc_c

            zeig => zeig%next
        ENDDO
        
         do j=1,anrspec
           i = nrspec(j)
           redn_h = svar(i)%RedN
           if(svar(i)%Ndemp .gt. 0) then
               svar(i)%RedN = svar(i)%Nuptp / svar(i)%Ndemp
           else
               svar(i)%RedN = redn_h
           endif
         enddo

    end select   ! flag_limi

! internal partial pressure of CO2 (Eq A9)
piCO2 = ApPa * lambda * CO2

! temperature dependent damping function; orig pars: 0.2, 10.
PHIT  = 1. / ( 1.+exp(0.4*(7.-temp)) )

! loop over all cohorts
  p => pt%first
  DO WHILE (ASSOCIATED(p))

    ns   = p%coh%species

    ! parameter variations with temperature (Eq A14)            

    KCO2 = spar(ns)%kCO2_25 * spar(ns)%q10_kCO2 ** ( (temp - 25.) / 10.)
    KO2  = spar(ns)%kO2_25  * spar(ns)%q10_kO2  ** ( (temp - 25.) / 10.)
    tau  = spar(ns)%pc_25   * spar(ns)%q10_pc   ** ( (temp - 25.) / 10.)

    ! CO2 compensation point in absence of mitochondrial respiration, O2 converted from kPa to Pa
    gammas = O2*1000 / (2. * tau)
    
    ! slope for light response under PAR limitation (Eq A7)
    C1 = PHIT*spar(ns)%phic*Cmass*QCO2*QCO2a * (piCO2 - gammas) / (piCO2 + 2.*gammas) ! 0.35

    ! slope for light response under Rubisco limitation (Eq A11)
    C2 = (piCO2 - gammas) / ( piCO2 + KCO2 * (1. + O2 / KO2) )         

    ! daylength-dependent term (original: s)
    DELTA = (24. / dayL) * spar(ns)%pb                            

    ! optimal light use efficiency (Eq A17 and A17a)
    SIGMA = AMAX1 (0.0001, 1. - (C2 - DELTA) / (C2 - PS * DELTA) ) ** 0.5 ! 0.25 - 0.45
    VmSpe = (1. / spar(ns)%pb) * (C1 / C2) * ( (2.*PS - 1.) *   &
            DELTA - (2.*PS * DELTA - C2) * SIGMA)                  

    ! maximum carboxylation potential in gC m-2 d-1 ???
    VmOpt = p%coh%totFPAR * PAR * VmSpe                            

! Determination of photosynthesis nitrogen reduction factor RedN
    select case (flag_limi)
    case (0,1)
           p%coh%RedNc = 1.
    
    case (2,3,10)
           p%coh%RedNc = svar(ns)%RedN
    
    case (4,5)
           ! N effect on photosynthesis
           XHELP = PN * exp ( - 0.0693 * (temp - 25.) )
          ! calculate Vmax as function of metabolically active nitrogen per unit crown projection area first, is now in mymol m-2 s-1 
           VmMax = (p%coh%N_fol - Nc0*p%coh%x_fol) / p%coh%crown_area / XHELP 
           p%coh%RedNc = MIN (1., VmMax / VmOpt)
    
    case (6,7)
           if ((p%coh%Ndemc_d .gt. 1.E-6) .and. (p%coh%Nuptc_d .gt. 1.E-6)) then
               p%coh%RedNc = p%coh%Nuptc_c / p%coh%Ndemc_c
           else
               p%coh%RedNc = svar(ns)%RedN
           endif
    
    case (8,9)
	      h_age = p%coh%x_age
          if( h_age.lt.50.) then
              redn_h =svar(ns)%RedN
         else if( (h_age-time).lt.50) then

    ! age dependent reduction of redN
              redn_h = svar(ns)%RedN*(1-max(0.,(h_age-50)*0.002))
          else
              redn_h = svar(ns)%RedN*(1-max(0.,(time)*0.002))
         end if
	     p%coh%RedNc = redn_h
	       
    case (11,12,13,14,15,16)  ! calculation of cohort loop
         p%coh%RedNc = svar(p%coh%species)%RedN

    end select



    ! limiting rates
    Jc = C2 * VmSpe / 24.
    Je = C1 / dayL

    ! gross assimilation and leaf respiration in [g C/(day*m2)]
    p%coh%LUE = dayL * ( Je+Jc - SQRT( (Je+Jc) * (Je+Jc) - 4.*PS*Je*Jc) ) / (2.*PS) * p%coh%RedNc
    assiSpe = p%coh%LUE * p%coh%totFPAR * PAR
    if(p%coh%totFPAR.lt.0) then
	continue
	end if
    respSpe = spar(ns)%pb * VmOpt * p%coh%RedNc
     phot_C = phot_C + p%coh%ntreea*assiSpe !summation for output BE

        p%coh%assi = assiSpe * kPatchSize / 1000. * (1/cpart)    ! conversion g C/day*m2 -> kg DW/day*patch
        p%coh%resp = respSpe * kPatchSize / 1000. * (1/cpart)    ! conversion g C/day*m2 -> kg DW/day*patch

    ! optimum stomatal conductance (modified from Haxeltine & Prentice 1996) [mol/(m2*d)]
    assDt = assiSpe - dayL/24.*respSpe
    p%coh%gp = AMAX1( gmin, 1.56*assDt / (1.0-lambda) / CO2 / Cmass )
    
    ! update canopy conductance
    IF (p%coh%species.le.nspec_tree .or. p%coh%species.eq.nspec_tree+2 )  then
		gp_can = gp_can + p%coh%gp*p%coh%nTreeA
	else
		gp_tot = gp_tot + p%coh%gp*p%coh%nTreeA
	endif



    p => p%next
    
  END DO



    gp_tot = gp_tot + gp_can
 
END SUBROUTINE OPT_PS

!********************!
!*  SUBROUTINE NPP  *!
!********************!

! determines realized assimilation rate by taking into account water stress, and
! calculates growth and maintenance respiration, plus overall net primary production

SUBROUTINE NPP( temp, dayL, PAR, jx )

  !*** Declaration part ***!

  USE data_par
  USE data_stand
  USE data_species
  USE data_simul
  USE data_soil_cn

  IMPLICIT NONE

  ! input variables  
  REAL:: temp,  &
         dayL,  &
         PAR 

  ! auxiliary variables  
  REAL :: netAsspot,    & ! daily potential (= no water and nutrient limitation) net assimilation rate [= dimension of p%coh%assi]
          netAss,       & ! daily net assimilation rate  [= dimension of p%coh%assi]
          maintResp,    & ! daily maintenance respiration costs
          dailypotNPP,  & ! daily potential (= no water and nutrient limitation) net primary productivity per tree
          dailyNPP,     & ! daily net primary productivity per tree [gC tree-1]
          drLimF,       & ! drought factor limiting the assimilation rate 
          grass = 0,    & ! gross daily assimilation rate  
          respfol,      &
          prms,         &
          prmr,         &
          NPP_mistletoe,&                    ! NPP of mistletoe
          pq10,         &    ! q10 value for maint. respiration stem, fine root
          help, presp
  INTEGER :: jx        ! time step length of PS/NPP model

  TYPE(coh_obj), POINTER :: p
   pq10=2.0

!*** Calculation part ***!
   
  !extraction of theor. produced NPP of mistletoe cohort
    p => pt%first
    do while (associated(p))
     if (p%coh%species.eq.nspec_tree+2) then
         NPP_mistletoe=p%coh%NPP
           NPP_demand_mistletoe=0.3*NPP_mistletoe   ! NPP that  mistletoe demands from host (30% heterotroph carbon gain (Richter 1992)
           p%coh%NPP=0.7*NPP_mistletoe              ! rest of NPP stays with mistletoe (autotroph)
     end if
     p => p%next
    enddo

  dailypotNPP_C=0.
  dailyNPP_C=0.
  dailyautresp_C = 0.
  dailygrass_C = 0.
  dailynetass_C = 0.
  respr_day      = 0.
  dailyrespfol_C = 0.
  ! loop over all cohorts
  p => pt%first
  DO WHILE (ASSOCIATED(p))
   ! reduction of NPP of mistletoe infected tree cohort
    if (p%coh%mistletoe.eq.1) then
      p%coh%NPP = p%coh%NPP-NPP_demand_mistletoe
    endif
    ns   = p%coh%species
 IF ( p%coh%drIndPS .lt. 0.0 ) THEN
    continue
 endif
   
 ! drought index
    IF ( p%coh%nDaysPS /= 0. ) THEN
      p%coh%drIndPS = p%coh%drIndPS / p%coh%nDaysPS  
    ELSE
      p%coh%drIndPS = 0.  ! -> npp = 0
    END IF
    
 ! limiting function 
  select case(flag_limi)
   case(0,2,4,6,8,14)
      drLimF = 1.0

   case default    
      drLimF = p%coh%drIndPS
   
   end select  
  
    ! total net assimilation, maintenance respiration and NPP of this tree
    if (p%coh%RedNc .gt. 1.E-6) then
        netAsspot = (p%coh%assi - p%coh%resp) / p%coh%RedNc
    else
        netAsspot = 0.
    endif
    netAss    = drLimF * (p%coh%assi - p%coh%resp)   
    grass     = drLimF * p%coh%assi    
    p%coh%respfol = grass -netAss
    respfol = p%coh%respfol
 
    IF (flag_resp==1) THEN
       ! calculate temperature dependant rates
       prmr=spar(ns)%prmr*pq10**((temp-15)/10)
       prms=spar(ns)%prms*pq10**((temp-15)/10)
  ! leaf maintenance respiration added
       maintResp = prms * p%coh%x_sap + prmr * p%coh%x_frt + respfol
        
! for complete outputs of respiration components:
       p%coh%respsap =   prms * p%coh%x_sap
       p%coh%respfrt =   prmr * p%coh%x_frt
       p%coh%respbr  =   prms * p%coh%x_tb
       dailypotNPP  = (1.-spar(ns)%prg) * (netAsspot - maintResp)
       dailyNPP  = (1.-spar(ns)%prg) * (netAss - maintResp)
       help = spar(ns)%prg * (netAss - maintResp)

    ELSEIF (flag_resp==2) THEN

       presp=0.03
       maintResp = (p%coh%x_sap*cpart/spar(ns)%cnr_stem + p%coh%x_crt*cpart/spar(ns)%cnr_crt + p%coh%x_tb*cpart/spar(ns)%cnr_tbc + p%coh%x_frt*cpart/spar(ns)%cnr_frt)*presp
       maintresp=maintresp*exp(308.56*((1/56.02)-(1/(temp+46.02))))

       dailypotNPP  = (1.-spar(ns)%prg) * (netAsspot - maintResp)
       dailyNPP  = (1.-spar(ns)%prg) * (netAss - maintResp)
    ELSE
       dailypotNPP=netAsspot*(1-spar(ns)%respcoeff)
       dailyNPP=netAss*(1-spar(ns)%respcoeff)
       maintResp = netAss*spar(ns)%respcoeff
    ENDIF
    IF(p%coh%species <= nspec_tree) THEN
      dailypotNPP_C  = dailypotNPP_C + p%coh%ntreea*dailypotNPP*cpart*kg_in_g / (kPatchSize) !conversion in gC/m2
      dailyNPP_C     = dailyNPP_C + p%coh%ntreea*dailyNPP*cpart*kg_in_g / (kPatchSize) !conversion in gC/m2
      if (flag_resp.eq.1) then
         dailyautresp_C = dailyautresp_C + p%coh%ntreea*(maintresp+help)*cpart*kg_in_g / (kPatchSize)
      ELSE  ! flag_resp=0
         dailyautresp_C = dailyautresp_C + p%coh%ntreea*(respfol+maintresp)*cpart*kg_in_g / (kPatchSize)
      end if   
	  dailygrass_C = dailygrass_C + p%coh%ntreea*grass*cpart*kg_in_g / (kPatchSize)
	  dailynetass_C = dailynetass_C + p%coh%ntreea*netass*cpart*kg_in_g / (kPatchSize)
	  dailyrespfol_C = dailyrespfol_C + p%coh%ntreea*respfol*cpart*kg_in_g / (kPatchSize)
    ENDIF

if (dailyNPP .gt. 10000.) then    
    continue
end if  
 ! update annual net assimilation and NPP sum
    p%coh%netAss = p%coh%netAss + netAss * jx
    p%coh%grossass = p%coh%grossass  + grass * jx
    if (flag_resp.eq.1)then
        p%coh%maintres =  p%coh%maintres + (maintresp + help) * jx  
    else
        p%coh%maintres =  p%coh%maintres + (maintresp + respfol) * jx      
    end if
    
	select case (flag_dis)    !phloem disturbance 
     case (1,2)
     dailyNPP    = dailyNPP * phlo_feed
     case (0)
     dailyNPP    = dailyNPP 
     end select
	 
	p%coh%NPP    = p%coh%NPP  + dailyNPP * jx
    p%coh%weekNPP = dailyNPP * jx 
    IF (time_out .gt. 0 .and. flag_cohout .eq. 2) THEN
       CALL OUT_ASS( p%coh%ident, PAR, p%coh%NPP, p%coh%totFPAR, p%coh%LUE, p%coh%netAss, p%coh%grossass, p%coh%nDaysPS)
    ENDIF

!    remove Mistletoe from N demand calculation
     if (p%coh%species.ne.nspec_tree+2) then
        p%coh%Ndemc_d=dailyNPP*1000.*spar(ns)%pcnr
     end if
    IF((flag_limi==4 .OR. flag_limi==5) .AND. 1. > p%coh%RedNc .AND.     &
        p%coh%N_fol/p%coh%t_leaf <= 4.5 .AND. p%coh%N_pool > 0.) THEN
       IF(p%coh%N_pool > p%coh%N_fol*(1./p%coh%RedNc - 1.)) THEN
          p%coh%N_fol  = p%coh%N_fol / p%coh%RedNc
          p%coh%N_pool = p%coh%N_pool - p%coh%N_fol*(1./p%coh%RedNc - 1.)
       ELSE
          p%coh%N_fol  = p%coh%N_fol + p%coh%N_pool
          p%coh%N_pool = 0.0
       ENDIF   
    ENDIF
    p => p%next
  END DO 
END SUBROUTINE NPP