LandscapeDNDC  1.37.0
ldndc::PhysiologyGrowthPSIM Class Reference

Vegetation model GrowthPSIM. More...

Inherits ldndc::MBE_LegacyModel.

Public Attributes

cbm::string_t branchfraction_opt
 ...
 
cbm::string_t crownlength_opt
 ...
 
bool competition_opt
 ...
 
cbm::string_t timemode_opt
 ...
 
int stand_structure_opt
 ...
 

Static Public Attributes

static const unsigned int IMAX_W = 24
 
static const double C1 = 0.0367
 
static const double CCOMNOX = 1.0
 
static const double CSATNH3 = 50.0
 
static const double CSATNOX = 5.0
 
static const double EPOTNOX = 1.0
 
static const double FRFRT = 0.5
 
static const double FMIN = 0.05
 
static const double KMMM = 0.0
 
static const double PAMM = 0.17
 
static const double PGDD = 0.0075
 
static const double PMIN = 0.06
 
static const double PNIT = 0.34
 
static const double PPHLOE = 0.06
 
static const double PREDFRT = 1.72
 
static const double PREDSAP = 0.855
 
static const double PTW = 0.29
 
static const double TAU = 330.0
 
static const double TGLIM = 6.0
 
static const double TRMAX = 45.0
 
static const double TRMIN = -7.0
 
static const double TROPT = 20.0
 
static const double UPOTNH3 = 10000.0
 

Protected Member Functions

lerr_t PSIM_ResizeVegetationVectors ()
 
lerr_t PSIM_StepInit ()
 
lerr_t PSIM_PlantingEvent ()
 
lerr_t PSIM_HydraulicConductance ()
 
lerr_t PSIM_Photosynthesis ()
 
lerr_t PSIM_Potentialtranspiration ()
 
lerr_t PSIM_AgriculturalManagement ()
 
lerr_t PSIM_NitrogenFixation ()
 Nitrogen fixation described similar to agricultural routines. Noted under PSIM_NitrogenUptake.
 
lerr_t PSIM_BiomassUpdate ()
 Biomass growth according to allocation gains and respiration losses in different plant compartments. More...
 
lerr_t PSIM_PhotosynthesisRates ()
 

Private Attributes

std::map< int, RootSystemDNDC > root_system
 Root system. More...
 

Detailed Description

Vegetation model GrowthPSIM.

Author
Ruediger Grote

Member Function Documentation

◆ PSIM_AgriculturalManagement()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_AgriculturalManagement ( )
protected

PSIM considers:

  • grazing (for grasses)
  • cutting (for grasses) (for other management options on trees, see ref@ ld_treeDyn:treedyn_events)
1445 {
1446  m_eventgraze.update_available_freshfood_c( m_veg, species_groups_select_t< species::grass >());
1447 
1448  for ( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1449  {
1450  MoBiLE_Plant *p = (*vt);
1451  if ( p->group() == "grass")
1452  {
1453  lerr_t rc_graze = m_eventgraze.event_graze_physiology( *vt);
1454  if ( (rc_graze != LDNDC_ERR_EVENT_MATCH) &&
1455  (rc_graze != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1456  {
1457  LOGERROR("Grazing not successful");
1458  return rc_graze;
1459  }
1460  }
1461  }
1462 
1463  // cutting event by external module
1464  lerr_t rc_cut = m_eventcut.event_cut_physiology( m_veg, species_groups_select_t< species::grass >());
1465  if ( (rc_cut != LDNDC_ERR_EVENT_MATCH) &&
1466  (rc_cut != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1467  {
1468  LOGERROR("Cutting not successful");
1469  return rc_cut;
1470  }
1471  else if (rc_cut == LDNDC_ERR_EVENT_MATCH)
1472  {
1473  for (PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1474  {
1475  MoBiLE_Plant* p = (*vt);
1476  m_treedyn.OnStructureChange(p);
1477  }
1478  }
1479 
1480  return LDNDC_ERR_OK;
1481 }

◆ PSIM_BiomassUpdate()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_BiomassUpdate ( )
protected

Biomass growth according to allocation gains and respiration losses in different plant compartments.

3118 {
3119  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3120  {
3121  MoBiLE_Plant *p = (*vt);
3122 
3123  // remembering starting values
3124  double const fFacOld = p->f_fac;
3125 
3126  double const mFolOld = p->mFol;
3127  double const mBudOld = p->mBud;
3128  double const mFrtOld = p->mFrt;
3129  double const mSapOld = p->mSap;
3130  double const mLivOld = mFolOld + mBudOld + mFrtOld + mSapOld;
3131 
3132  // increase of dry matter
3133  double const groFol = p->dcFol / cbm::CCDM;
3134  double const groBud = p->dcBud / cbm::CCDM;
3135  double const groFrt = p->dcFrt / cbm::CCDM;
3136  double const groSap = p->dcSap / cbm::CCDM;
3137  double const groSum = groBud + groFrt + groSap;
3138 
3139  /* biomass adjustment according to the shift in free available carbon
3140  * following the basic assumption that free available carbon is proportionally
3141  * distributed between or taken from the compartments but leaving reserves unchanged.*/
3142  if ( cbm::flt_greater_zero( mLivOld))
3143  {
3144  double const redistribC( p->dcFac / cbm::CCDM);
3145  p->mFol += (redistribC * mFolOld / mLivOld);
3146  p->mBud += (redistribC * mBudOld / mLivOld);
3147  p->mFrt += (redistribC * mFrtOld / mLivOld);
3148  p->mSap += (redistribC * mSapOld / mLivOld);
3149  }
3150 
3151  // considering growth and loss effects on compartment biomasses
3152  p->mFol += (groFol - p->sFol + mBudLoss_vt[p->slot]);
3153  p->mBud += (groBud - p->sBud - mBudLoss_vt[p->slot]);
3154  p->mFrt += (groFrt - cbm::sum( p->sFrt_sl, sl_.soil_layer_cnt()));
3155  p->mSap += (groSap - mSapLoss_vt[p->slot]);
3156  p->mCor += (mSapLoss_vt[p->slot] * (1.0 - p->f_branch));
3157 
3158  if ( !cbm::flt_greater_zero( p->mFol)) p->mFol = 0.0;
3159  if ( !cbm::flt_greater_zero( p->mBud)) p->mBud = 0.0;
3160  if ( !cbm::flt_greater_zero( p->mFrt)) p->mFrt = 0.0;
3161  if ( !cbm::flt_greater_zero( p->mSap)) p->mSap = 0.0;
3162 
3163  // biomass and foliage area in layers
3164  m_pf.update_foliage_layer_biomass_and_lai((*vt), fl_cnt_, 0.0);
3165 
3166  // change foliage biomass in age classes due to growth and senescence
3167  if ( p->nb_ageclasses() == 1)
3168  {
3169  p->mFol_na[0] = p->mFol;
3170  }
3171  else
3172  {
3173  // allowing foliage mass increase in plants with non-annual growth behaviour
3174  p->mFol_na[0] += cbm::bound_min( 0.0, groFol + mBudLoss_vt[p->slot] - p->sFol_na[0]);
3175  for ( size_t na = 1; na < p->nb_ageclasses(); ++na)
3176  {
3177  p->mFol_na[na] = cbm::bound_min( 0.0, p->mFol_na[na] - p->sFol_na[na]);
3178  }
3179  }
3180 
3181  // total living biomass after growth (kgDM)
3182  double const mLivNew( p->mFol + p->mBud + p->mFrt + p->mSap);
3183 
3187  if ( cbm::flt_greater( mLivNew, 0.001))
3188  {
3189  // ratio of free available carbohydrates
3190  double const senSum = cbm::sum( p->sFrt_sl, sl_.soil_layer_cnt()) + mSapLoss_vt[p->slot] + p->sFol;
3191  p->f_fac = (fFacOld * (mLivOld - senSum) * cbm::CCDM + vt->FFACMAX() * groSum * cbm::CCDM + p->dcFac ) / (mLivNew * cbm::CCDM);
3192 
3193  if ( !cbm::flt_greater_zero( p->f_fac)) p->f_fac = 0.0;
3194  }
3195  else
3196  {
3197  p->f_fac = 0.0;
3198  }
3199 
3200  // peak foliage amount
3201  if ( cbm::flt_greater( p->mFol, p->mFolMax))
3202  {
3203  p->mFolMax = p->mFol;
3204  }
3205  }
3206 
3207  return LDNDC_ERR_OK;
3208 }

◆ PSIM_HydraulicConductance()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_HydraulicConductance ( )
protected
Returns
error code

References ldndc::sap_wood_fraction().

1527 {
1528  // realized (soil water limited) transpiration (per ground area) in m per time step (should vary per hour) and vegetation type
1529  accumulated_wateruptake_old = wc_.accumulated_wateruptake_sl.sum();
1530 
1531  // transpiration demand given from potential demand derived from different stomata methods
1532  double transpiration_demand(wc_.accumulated_potentialtranspiration - accumulated_potentialtranspiration_old);
1533  accumulated_potentialtranspiration_old = wc_.accumulated_potentialtranspiration;
1534 
1535  // relative recovery of plant water deficit from the last time step
1536  double rehydrationindex(0.0);
1537  if (cbm::flt_greater_zero(plant_waterdeficit_old))
1538  {
1539  rehydrationindex = cbm::bound(0.0,
1540  (plant_waterdeficit_old - wc_.plant_waterdeficit) / plant_waterdeficit_old,
1541  1.0);
1542  }
1543  plant_waterdeficit_old = wc_.plant_waterdeficit;
1544 
1545  // number of hours per day
1546  double const daylength_hours(meteo::daylength(m_setup->latitude(), this->lclock()->yearday()));
1547 
1548  // setting soil to root hydraulic conductance equal to soil conductance
1549  double const lai_sum(m_veg->lai());
1550  for (PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
1551  {
1552  MoBiLE_Plant* p = *vt;
1553 
1554  // length of timestep [s]
1555  double const tslength = double(cbm::SEC_IN_HR) * double(cbm::HR_IN_DAY) / double(this->lclock_ref().time_resolution());
1556 
1557  // transform transpiration units from m timestep-1 to mol m-2leaf s-1 and relate it to daylength
1558  // TODO: find a better way to differentiate transpiration into vegetation classes
1559  double transp_mol(0.0);
1560  double const dayl(meteo::daylength(m_setup->latitude(), this->lclock()->yearday()));
1561  if ( cbm::flt_greater_zero( lai_sum))
1562  {
1563  double transp_vt = transpiration_demand * p->lai() / lai_sum;
1564  if (cbm::flt_greater_zero( dayl))
1565  {
1566  transp_mol = transp_vt * cbm::MM_IN_M * cbm::G_IN_KG / (tslength * cbm::MH2O * p->lai())
1567  / (dayl / cbm::HR_IN_DAY);
1568  }
1569  }
1570 
1571  // soil layer water potential at which roots get detached (in MPa, positive units)
1572  double psi_detach(m_sipar->CP_WP() * cbm::MPA_IN_MH2O); // 150 mWS (1.5 MPa) is the predefined value for the water content at wilting point
1573 
1574  // plant (root) hydraulic conductance calculated from soil water potential, weighted by fine root abundance
1575  double const SCALE_WP(1.2);
1576  p->psi_sr = 0.0;
1577  for (size_t sl = 0; sl < sl_.soil_layer_cnt(); ++sl)
1578  {
1579  double const wc( cbm::bound( 1.001 * wc_.wc_res_sl[sl],
1580  wc_.wc_sl[sl],
1581  0.999 * wc_.wc_sat_sl[sl]));
1582 
1583  // soil layer water potential (in MPa, positive units)
1584  double const psi_sl( ldndc::capillary_pressure( wc, wc_.vga_sl[sl], wc_.vgn_sl[sl], wc_.vgm_sl[sl],
1585  wc_.wc_sat_sl[sl], wc_.wc_res_sl[sl] ) * cbm::MPA_IN_MH2O );
1586 
1587  // soil to root water potential (MPa) weighted by fine root abundance
1588  p->psi_sr += ( std::min(SCALE_WP * m_sipar->CP_WP() * cbm::MPA_IN_MH2O, psi_sl) * p->fFrt_sl[sl] );
1589  }
1590 
1591  p->psi_sr *= -1.0;
1592  psi_detach *= -1.0;
1593 
1594  // plant water potential calculated considering previous declines (without gravitational impact)
1595  double psi_vt(std::max(p->psi_sr, psi_detach) + psidecline_cum_vt[p->slot]);
1596 
1597  // canopy water potential
1598  // (calculated in a lumped fashion, alternatively define psi for each canopy layer separately)
1599  // - average canopy height
1600  double h_weighted(0.0); // [m]
1601  double height_cum(0.0); // [m]
1602  for (size_t fl = 0; fl < p->nb_foliagelayers(); ++fl)
1603  {
1604  height_cum += 0.5 * ph_.h_fl[fl];
1605  h_weighted += height_cum * p->fFol_fl[fl];
1606  height_cum += 0.5 * ph_.h_fl[fl];
1607  }
1608 
1609  // - increase of water potential due to vertical transport (gravitational impact)
1610  double const dpsi = h_weighted * cbm::MPA_IN_KPA * cbm::KPA_IN_PA * cbm::DWAT * cbm::DM3_IN_M3 * cbm::G;
1611 
1612  // decrease and recovery of plant water potential
1613  int night(1); // 1=false, 0=true
1614  // - state determination after daytime
1615  if (cbm::flt_equal_zero(mc_.shortwaveradiation_in)) // nighttime without radiaiton (NOTE: problems occur if there is radiation input during night)
1616  {
1617  // in the night, the multiplier for psi that accounts for increasing tension is set to zero
1618  night = 0;
1619 
1620  if (daytime == true)
1621  {
1622  // weighting by leaf/wood ratio as proxy for capacitance change
1623  // NOTE1: assuming that the degree of capacitance deficit (if it occurs) is the same in all compartments
1624  // NOTE2: doesn't consider a possible capacitance change with relative water content
1625  double const qcapacitance = (p->mFol + p->f_branch * p->mSap) / (p->mFol + p->mSap + p->mFrt); // assuming that transpiration affects primarily the crown tissue relation to all living tissue
1626 // double const qcapacitance = p->mFol / (p->mFol + p->mSap + p->mFrt); // assuming that transpiration only affects foliage tissue in relation to all living tissue
1627 // double const qcapacitance = p->mFol / (p->mFol + p->mSap + p->mCor + p->mFrt); // assuming that transpiration only affects foliage tissue in relation to all tissues including core wood
1628 // double const qcapacitance = 1.0; // assuming that only transpiration affects tree water potential
1629 // double const qcapacitanc = p->mFol / (p->mFol + p->mSap * (*vt)->wc_rel + p->mFrt); // assuming that transpiration only affects foliage tissue in relation to all living tissues reduced by water content
1630 
1631  // recovery of cumulative plant water potential due to rehydration during the previous day
1632  psidecline_cum_vt[p->slot] *= std::min(1.0, (1.0 - rehydrationindex_cum_vt[p->slot])); // assumes that relative rehydration and plant water potential recovers in parallel
1633 // psidecline_cum_vt[p->slot] *= std::min(1.0, (1.0 - qcapacitance)); // assumes that the recovery is slowed down according to the relation between affected and total tissue
1634 
1635  // in case of root detachment (soil water potential below wilting point) plant water potential decline is accumulated
1636  if (cbm::flt_greater_equal(psi_detach, p->psi_sr))
1637  {
1638  psidecline_cum_vt[p->slot] += std::min(0.0, (psidecline_daycum_vt[p->slot] / daylength_hours) * qcapacitance);
1639  }
1640 
1641  // reset of the cumulative rehydration index
1642  rehydrationindex_cum_vt[p->slot] = 0.0;
1643 
1644  // reset the cumulative water potential deficit
1645  psidecline_daycum_vt[p->slot] = 0.0;
1646  }
1647 
1648  daytime = false;
1649  }
1650  // - state determination during daytime
1651  else
1652  {
1653  // calculations directly after nighttime
1654  if (daytime == false)
1655  {
1656  // predawn canopy water potential
1657  p->psi_pd = psi_vt - dpsi;
1658 
1659  // predawn (minimum) tree water deficit = maximum diurnal radius
1660  (*vt)->twd_pd_vt = (*vt)->stem_shrinkage;
1661  (*vt)->twd_max_vt = 0.0;
1662  }
1663 
1664  daytime = true;
1665 
1666  // minimum shrinkage (maximum tree water deficit) during the day
1667  if ((*vt)->stem_shrinkage > (*vt)->twd_max_vt)
1668  {
1669  (*vt)->twd_max_vt = (*vt)->stem_shrinkage;
1670  }
1671 
1672  }
1673 
1674  // relative xylem conductivity based on current plant water potential
1675  double krc_rel_vt = 1.0 - (1.0 - std::exp(-std::pow(psi_vt / vt->PSI_REF(), vt->PSI_EXP())));
1676  krc_rel_vt = std::max(0.001, krc_rel_vt);
1677 
1678  // canopy hydraulic potential in MPa (negative) due to water loss (only at daytime) considering height induced gradient
1679  p->psi_cr = psi_vt;
1680  if (cbm::flt_greater_zero(krc_rel_vt))
1681  {
1682  p->psi_cr = psi_vt - (transp_mol * double(night) / (vt->CWP_REF() * krc_rel_vt)) - dpsi; // CWP_REF is the conductance of the whole pathlength
1683  }
1684 
1685  // mean canopy water potential (not important, but smoothing between timesteps)
1686  p->psi_mean = (p->psi_pd + p->psi_cr) * 0.5;
1687 
1688  // drop in plant water potential (!) due to evaporative demand cumulated over the day
1689  psidecline_daycum_vt[p->slot] += std::min(0.0, (p->psi_cr + dpsi - psi_vt));
1690 
1691  // daily cumulative reduction of drop in water potential after refilling (rehydration_index is in fraction per hour, needed in fraction per day)
1692  rehydrationindex_cum_vt[p->slot] += rehydrationindex;
1693  rehydrationindex_cum_vt[p->slot] = cbm::bound(0.0, rehydrationindex_cum_vt[p->slot], 1.0);
1694 
1695  // overall root-to-canopy (plant hydraulic) conductance considering current day demands (in mol MPa-1 s-1 m-2)
1696  double k_rc_rel_mean = 1.0 - (1.0 - std::exp(-std::pow(p->psi_mean / vt->PSI_REF(), vt->PSI_EXP())));
1697  k_rc_rel_mean = std::max(0.001, k_rc_rel_mean);
1698 
1699  // whole plant resistances (in MPa s m2 mol-1)
1700  // NOTE: resistance is reversible and is not affected by xylem senescence (e.g. embolism). Possible solutions would be to increase
1701  // a) proportionally to the difference between qsaparea_vt[p->slot] and p->qsfa, or b) to the deficit of sapwood demand (RPMIN / (k_rc_rel * qsaparea_vt[p->slot]) )
1702  p->xylem_resistance = vt->RPMIN(); // 1/RPMIN is the conductance in the crown area
1703  if (cbm::flt_greater_zero(k_rc_rel_mean))
1704  {
1705  p->xylem_resistance /= k_rc_rel_mean;
1706  }
1707 
1708  } // vegetation type loop end
1709 
1710  return LDNDC_ERR_OK;
1711 }
Here is the call graph for this function:

◆ PSIM_Photosynthesis()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_Photosynthesis ( )
protected
Returns
error code
822 {
823  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
824  {
825  MoBiLE_Plant *p = *vt;
826 
827  for (size_t fl = 0; fl < p->nb_foliagelayers(); ++fl)
828  {
829  m_photo.vpd_fl[fl] = mc_.vpd_fl[fl];
830  m_photo.rh_fl[fl] = cl_.rel_humidity_subday( lclock_ref());
831  m_photo.temp_fl[fl] = mc_.temp_fl[fl];
832  m_photo.parsun_fl[fl] = mc_.parsun_fl[fl];
833  m_photo.parshd_fl[fl] = mc_.parshd_fl[fl];
834  m_photo.tFol_fl[fl] = mc_.tFol_fl[fl];
835  m_photo.co2_concentration_fl[fl] = ac_.ts_co2_concentration_fl[fl];
836  m_photo.sunlitfoliagefraction_fl[fl] = mc_.ts_sunlitfoliagefraction_fl[fl];
837  }
838  m_photo.nd_airpressure = mc_.nd_airpressure;
839 
840  m_photo.set_vegetation_base_state( p);
841 
842  m_photo.set_vegetation_non_stomatal_water_limitation_state( p->xylem_resistance, p->psi_mean, p->psi_sr, p->psi_pd);
843 
844  m_photo.solve();
845 
846  m_photo.get_vegetation_state( p);
847  }
848 
849  return LDNDC_ERR_OK;
850 }

◆ PSIM_PhotosynthesisRates()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_PhotosynthesisRates ( )
protected

Nitrogen concentration is related to specific leaf area but declines generally not linear. Therefore, an exponential relationship with a parameter of 0.3 is used, fitted to various canopy gradient studies (e.g. Meir et al. 2002, Al Afas et al. 2007, Ellsworth and Reich 1993) (parameter should be consistent with the one used in m_pf.optimum_nitrogen_content_foliage())

References ldndc::non_stomatal_water_limitation().

3267 {
3268  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3269  {
3270  MoBiLE_Plant *p = (*vt);
3271 
3272  // phenological state
3273  bool const evergreen( (p->nb_ageclasses() > 1) && cbm::flt_greater_zero( p->mFol));
3274  double const pstatus( evergreen ?
3275  (p->dvsFlush * p->mFol_na[0] + (1.0 - p->dvsMort) * (cbm::sum( p->mFol_na, p->nb_ageclasses()) - p->mFol_na[0])) / p->mFol :
3276  std::min( p->dvsFlush, 1.0 - p->dvsMort));
3277 
3278  // drought stress impact
3279  // NOTE: consideration of water potential effects is only warranted if the whole hydraulic model is used
3280  double fwat(1.0);
3281  if (m_photo.stomatalconductance_method == eller_2020 && p->dvsFlush > 0.99)
3282  {
3283  fwat = ldndc::non_stomatal_water_limitation( p->psi_pd, (*p)->A_REF(), (*p)->A_EXP() );
3284  }
3285 
3286  // - in case drought stress decreases, its decrease is limited by recovery rate (legacy effect)
3287  const double RECOVER(0.01); // fraction recovery per hour
3288  if (fwat > p->fwatOld)
3289  {
3290  double const tslength = double(cbm::HR_IN_DAY) / double(this->lclock_ref().time_resolution());
3291  fwat = std::min(fwat, p->fwatOld + RECOVER * tslength);
3292  }
3293  p->fwatOld = fwat;
3294 
3295  // enzyme activity
3296  // (activity of isoprene and monoterpene enzymes are unchanged during the dormant season)
3297  double nFolOpt(m_pf.optimum_nitrogen_content_foliage(p));
3298  double const ncFol_top = (p->mFol * p->ncFol / nFolOpt) * vt->NCFOLOPT();
3299 
3300  if ( cbm::flt_greater_zero( pstatus))
3301  {
3302  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3303  {
3304  if ( cbm::flt_greater_zero( p->m_fol_fl(fl)) &&
3305  cbm::flt_greater_zero( p->sla_fl[fl]))
3306  {
3307  // nitrogen supply in dependence on specific leaf area
3314  double const ncFol_fl( ncFol_top * pow( vt->SLAMIN() / p->sla_fl[fl], 0.3));
3315 
3316  // dependency of photosynthesis linearly related to nitrogen (Reynolds et al. 1992)
3317  double const fnit( cbm::bound( 0.0, (ncFol_fl - vt->NC_FOLIAGE_MIN()) / (vt->NCFOLOPT() - vt->NC_FOLIAGE_MIN()), 1.0));
3318 
3319  // seasonality factor
3320  double fdorm(0.0);
3321  // - deciduous
3322  if (p->nb_ageclasses() == 1)
3323  {
3324  if ( p->dvsFlush < 1.0)
3325  {
3326  fdorm = cbm::sqr( p->dvsFlush);
3327  }
3328  else
3329  {
3330  fdorm = 1.0 - cbm::sqr( p->dvsMort);
3331  }
3332  }
3333  // - evergreen
3334  else
3335  {
3336  // - equal to the relative pool size of free available carbon reserves (fsub_vt)*/
3337  fdorm = fsub_vt[p->slot];
3338 
3339  // - temperature dependent according to Maekelae et al. 2004 (S model)
3340 /* if ((mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * (mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl])) >= vt->PSNTFROST())
3341  {
3342 // fdorm = C1 * (mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl]) - vt->PSNTFROST());
3343 // fdorm = 1.0;
3344  }
3345  else
3346  {
3347  fdorm = 0.0;
3348  }
3349 */
3350  }
3351 
3352  fdorm = cbm::bound( 0.0, fdorm, 1.0);
3353 
3354  // activity of rubisco under standard conditions
3355  p->vcAct25_fl[fl] = vt->VCMAX25() * fnit * fdorm * fwat;
3356  // activity of maximum electron transport rate under standard conditions
3357  p->jAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QJVC();
3358  // activity of dark respiration under standard conditions
3359  p->rdAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QRD25();
3360  }
3361  else
3362  {
3363  p->vcAct25_fl[fl] = 0.0;
3364  p->jAct25_fl[fl] = 0.0;
3365  p->rdAct25_fl[fl] = 0.0;
3366  }
3367  }
3368  }
3369  else
3370  {
3371  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3372  {
3373  p->vcAct25_fl[fl] = 0.0;
3374  p->jAct25_fl[fl] = 0.0;
3375  p->rdAct25_fl[fl] = 0.0;
3376  }
3377  }
3378  }
3379 
3380  return LDNDC_ERR_OK;
3381 }
double non_stomatal_water_limitation(double const &_var, double const &_var_ref, double const &_var_scale)
Non stomatal water limitation.
Definition: ld_droughtstress.cpp:136
Here is the call graph for this function:

◆ PSIM_PlantingEvent()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_PlantingEvent ( )
protected
Returns
error code
496 {
497  EventAttributes const * ev_plant = NULL;
498  while ( (ev_plant = this->m_PlantEvents.pop()) != NULL)
499  {
500  MoBiLE_Plant *vt = this->m_veg->get_plant( ev_plant->get( "/name", "?"));
501  if ( !vt)
502  {
503  KLOGERROR( "Handling plant event failed [species=", ev_plant->get( "/name", "?"),"]");
504  return LDNDC_ERR_RUNTIME_ERROR;
505  }
506  CBM_LogDebug( "Seed plant '",vt->name(),"'");
507 
508  species_t const * sp = NULL;
509  if ( m_species)
510  {
511  sp = m_species->get_species( vt->cname());
512  }
513 
514  root_system.insert( { vt->slot, RootSystemDNDC( m_state, io_kcomm) } );
515 
516  char const * group = ev_plant->get( "/group", "?");
517  if ( cbm::is_equal( group, "wood"))
518  {
519  lerr_t rc_plant = m_pf.initialize_tree( vt, sp->wood(), branchfraction_opt, crownlength_opt, competition_opt);
520  if ( rc_plant)
521  {
522  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
523  return LDNDC_ERR_FAIL;
524  }
525  }
526  else if ( cbm::is_equal( group, "grass")) // TODO could be done at "push-time"
527  {
528  lerr_t rc_plant = m_pf.initialize_grass( vt, sp->grass());
529  if ( rc_plant)
530  {
531  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
532  return LDNDC_ERR_FAIL;
533  }
534  }
535  else if ( cbm::is_equal( group, "crop")) // TODO could be done at "push-time"
536  {
537  lerr_t rc_plant = m_pf.initialize_crop( vt, sp->crop());
538  if ( rc_plant)
539  {
540  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
541  return LDNDC_ERR_FAIL;
542  }
543  }
544 
545  // initialize local state variables after planting
546  if ( vt->dEmerg > 0)
547  {
548  if ( (int)lclock()->yearday() > vt->dEmerg)
549  {
550  days_since_emergence[vt->slot] = (int)(lclock()->yearday()) - vt->dEmerg;
551  }
552  else
553  {
554  // use 366 on purpose to ensure always: days_since_emergence > 0
555  days_since_emergence[vt->slot] = (int)(lclock()->yearday()) + (366 - vt->dEmerg);
556  }
557  }
558  else
559  {
560  days_since_emergence[vt->slot] = 0;
561  }
562 
563  if ( lclock()->yearday() >= PSIM_YEAR_START)
564  {
565  phenological_year[vt->slot] = lclock()->year();
566  }
567  else
568  {
569  phenological_year[vt->slot] = lclock()->year() - 1;
570  }
571 
572  foliage_age_of_start_senescence[vt->slot] = m_pf.get_foliage_age_of_senescence( vt, 0.0);
573 
574  for ( size_t na = 0; na < vt->nb_ageclasses(); ++na)
575  {
576  foliage_age_na[vt->slot][na] = m_pf.get_foliage_age( PSIM_YEAR_START, lclock()->yearday(), na);
577  }
578  }
579 
580  return LDNDC_ERR_OK;
581 }
cbm::string_t branchfraction_opt
...
Definition: psim.h:113
bool competition_opt
...
Definition: psim.h:125
std::map< int, RootSystemDNDC > root_system
Root system.
Definition: psim.h:377
cbm::string_t crownlength_opt
...
Definition: psim.h:119

◆ PSIM_Potentialtranspiration()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_Potentialtranspiration ( )
protected
Returns
error code

References ldndc::potential_crop_transpiration(), ldndc::potential_transpiration(), and ldndc::potential_wood_transpiration().

3386 {
3387  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3388  {
3389  MoBiLE_Plant *p = (*vt);
3390  if (vt->IS_WOOD())
3391  {
3392  if ( wc_.transpiration_method == substate_watercycle_t::WATERUSEEFFICIENCY)
3393  {
3394  wc_.accumulated_potentialtranspiration += potential_wood_transpiration(
3395  sl_,
3396  mc_.nd_watervaporsaturationdeficit,
3397  ph_.carbonuptake(m_veg, fl_cnt_),
3398  p->f_area,
3399  vt->WUECMAX(),
3400  vt->WUECMIN(),
3401  sc_.h_sl,
3402  wc_.wc_sl,
3403  wc_.wc_wp_sl,
3404  wc_.wc_fc_sl);
3405  }
3406  else // transpiration_method == "treewaterdeficit", "potentialtranspiration"
3407  {
3408  wc_.accumulated_potentialtranspiration += potential_transpiration(
3409  p->nb_foliagelayers(),
3410  vt->GSMIN(),
3411  vt->GSMAX(),
3412  p->lai_fl,
3413  mc_.vpd_fl,
3414  p->relativeconductance_fl) * cbm::HR_IN_DAY * lclock()->day_fraction();
3415  }
3416  }
3417  else
3418  {
3419  wc_.accumulated_potentialtranspiration += potential_crop_transpiration(
3420  ac_.nd_co2_concentration,
3421  ph_.carbonuptake( m_veg, fl_cnt_),
3422  vt->WUECMAX());
3423  }
3424  }
3425 
3426  return LDNDC_ERR_OK;
3427 }
double potential_crop_transpiration(double _co2, double _carbon_uptake, double _wuecmax)
Returns potential transpiration in [m] for crops and grass.
Definition: ld_transpiration.cpp:45
double potential_wood_transpiration(soillayers::input_class_soillayers_t const &, double _vpd, double _carbon_uptake, double _f_area, double _wuecmax, double _wuecmin, lvector_t< double > _h_sl, lvector_t< double > _wc, lvector_t< double > _wc_min, lvector_t< double > _wc_max)
Returns potential transpiration in [m] for trees.
Definition: ld_transpiration.cpp:144
double potential_transpiration(size_t, double gsmin, double gsmax, double *_lai_fl, lvector_t< double > _vpd_fl, double *_relative_conductance_fl)
Returns potential transpiration in [m] for any species type.
Definition: ld_transpiration.cpp:225
Here is the call graph for this function:

◆ PSIM_ResizeVegetationVectors()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_ResizeVegetationVectors ( )
protected
Returns
error code
379 {
380  // compare number of vegetation types
381  size_t const slot_cnt( m_veg->slot_cnt());
382  size_t const slot_cnt_old( additional_season.size());
383 
384  if ( slot_cnt <= slot_cnt_old)
385  {
386  return LDNDC_ERR_OK;
387  }
388 
389  matrix_2d_dbl_t::extent_type const vtsl[] =
390  { static_cast< matrix_2d_dbl_t::extent_type >( slot_cnt),
391  static_cast< matrix_2d_dbl_t::extent_type >( sl_.soil_layer_cnt())};
392 
393  additional_season.resize_and_preserve( slot_cnt, false);
394  phenological_year.resize_and_preserve( slot_cnt, 0);
395  foliage_age_of_start_senescence.resize_and_preserve( slot_cnt, 0);
396  days_since_emergence.resize_and_preserve( slot_cnt, 0);
397 
398  // average (effective) temperatures of all leaves of a vegetation type
399  ts_leaftemp_vt.resize_and_preserve( slot_cnt, 0.0);
400  nd_leaftemp_vt.resize_and_preserve( slot_cnt, 0.0);
401 
402  uptNH4Max_vt.resize_and_preserve( slot_cnt, 0.0); // max. ammonium uptake
403  uptNO3Max_vt.resize_and_preserve( slot_cnt, 0.0); // max. nitrate uptake
404  uptDONMax_vt.resize_and_preserve( slot_cnt, 0.0); // max. dissolved organic nitrogen uptake
405  uptNWetMax_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
406  uptNWet_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
407  uptNTot_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
408 
409  rFolOld_vt.resize_and_preserve( slot_cnt, 0.0);
410  rBudOld_vt.resize_and_preserve( slot_cnt, 0.0);
411  rSapOld_vt.resize_and_preserve( slot_cnt, 0.0);
412  rFrtOld_vt.resize_and_preserve( slot_cnt, 0.0);
413  rTraOld_vt.resize_and_preserve( slot_cnt, 0.0);
414  exsuLossOld_vt.resize_and_preserve( slot_cnt, 0.0);
415 
416  uptNH4_vt.resize_and_preserve( slot_cnt, 0.0);
417  uptNO3_vt.resize_and_preserve( slot_cnt, 0.0);
418  uptNH3_vt.resize_and_preserve( slot_cnt, 0.0);
419  uptDON_vt.resize_and_preserve( slot_cnt, 0.0);
420 
421  uptNH4Old_vt.resize_and_preserve( slot_cnt, 0.0);
422  uptNO3Old_vt.resize_and_preserve( slot_cnt, 0.0);
423  uptNH3Old_vt.resize_and_preserve( slot_cnt, 0.0);
424  uptDONOld_vt.resize_and_preserve( slot_cnt, 0.0);
425 
426  uptN2Old_vt.resize_and_preserve( slot_cnt, 0.0);
427  uptNOxOld_vt.resize_and_preserve( slot_cnt, 0.0);
428 
429  while ( slot_cnt > uptNH4Max_vtsl.size())
430  {
431  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
432  uptNH4Max_vtsl.push_back( help_sl);
433  }
434  while ( slot_cnt > uptNO3Max_vtsl.size())
435  {
436  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
437  uptNO3Max_vtsl.push_back( help_sl);
438  }
439  while ( slot_cnt > uptDONMax_vtsl.size())
440  {
441  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
442  uptDONMax_vtsl.push_back( help_sl);
443  }
444  while ( slot_cnt > foliage_age_na.size())
445  {
446  std::vector< int > help_sl( MoBiLE_MaximumAgeClasses, 0);
447  foliage_age_na.push_back( help_sl);
448  }
449 
450  carbonuptake_vt.resize_and_preserve( slot_cnt, 0.0);
451  //xylem_resistance_smoothed_vt.resize_and_preserve(slot_cnt, 0.0);
452  xylem_resistance_smoothed_old_vt.resize_and_preserve(slot_cnt, 0.0);
453  psidecline_cum_vt.resize_and_preserve(slot_cnt, 0.0);
454  psidecline_daycum_vt.resize_and_preserve(slot_cnt, 0.0);
455  rehydrationindex_cum_vt.resize_and_preserve(slot_cnt, 0.0);
456 
457  //do not initialize to zero!
458  mSapOpt_vt.resize_and_preserve( slot_cnt, 0.0);
459  mSapOld_vt.resize_and_preserve( slot_cnt, 0.0);
460  mCorOld_vt.resize_and_preserve( slot_cnt, 0.0);
461  qsaparea_vt.resize_and_preserve(slot_cnt, 0.0);
462  fsub_vt.resize_and_preserve(slot_cnt, 0.0);
463 
464  mBudLoss_vt.resize_and_preserve( slot_cnt, 0.0); // dry matter transfered from buds to foliage
465  mSapLoss_vt.resize_and_preserve( slot_cnt, 0.0); // dry matter transfered from sapwood to corewood
466  ncFolOpt.resize_and_preserve( slot_cnt, 0.0); // optimum nitrogen concentration of the whole foliage of one species (gN gDW-1)
467  ncBudOpt.resize_and_preserve( slot_cnt, 0.0); // optimum nitrogen concentration of the whole structural storage of one species (gN gDW-1)
468  nDem_vt.resize_and_preserve( slot_cnt, 0.0); // species specific nitrogen demand (kgN)
469  nFol_vt.resize_and_preserve( slot_cnt, 0.0); // last days foliage nitrogen content (kg)
470  nFrt_vt.resize_and_preserve( slot_cnt, 0.0); // last days fine root nitrogen content (kg)
471  nSap_vt.resize_and_preserve( slot_cnt, 0.0); // last days sapwood nitrogen content (kg)
472  nCor_vt.resize_and_preserve( slot_cnt, 0.0); // last days corwood nitrogen content (kg)
473  nBud_vt.resize_and_preserve( slot_cnt, 0.0); // last days bud nitrogen content (kg)
474 
475  n_bud_to_fol_vt.resize_and_preserve( vtsl, 0.0);
476  n_sap_to_cor_vt.resize_and_preserve( vtsl, 0.0);
477  n_bud_to_cor_vt.resize_and_preserve( vtsl, 0.0);
478  n_fol_to_cor_vt.resize_and_preserve( vtsl, 0.0);
479  n_frt_to_cor_vt.resize_and_preserve( vtsl, 0.0);
480  n_sap_to_litter_vt.resize_and_preserve( vtsl, 0.0);
481  n_sap_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
482  n_bud_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
483  n_fol_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
484  n_frt_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
485  n_sap_gain_vt.resize_and_preserve( vtsl, 0.0);
486  n_bud_gain_vt.resize_and_preserve( vtsl, 0.0);
487  n_fol_gain_vt.resize_and_preserve( vtsl, 0.0);
488  n_frt_gain_vt.resize_and_preserve( vtsl, 0.0);
489 
490  return LDNDC_ERR_OK;
491 }

◆ PSIM_StepInit()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_StepInit ( )
protected
Returns
error code
586 {
587  for ( size_t sl = 0; sl < sl_.soil_layer_cnt(); ++sl)
588  {
589  nh4_sl[sl] = sc_.nh4_sl[sl];
590  no3_sl[sl] = sc_.no3_sl[sl] + sc_.an_no3_sl[sl];
591  don_sl[sl] = sc_.don_sl[sl];
592  }
593 
594  fl_cnt_ = m_veg->canopy_layers_used();
595 
596  if ( subdaily_timemode())
597  {
598  temp_sl.reference( mc_.temp_sl);
599  ts_temp_fl.reference( mc_.temp_fl);
600 
601  no_concentration_fl.reference( ac_.ts_no_concentration_fl);
602  no2_concentration_fl.reference( ac_.ts_no2_concentration_fl);
603  nh3_concentration_fl.reference( ac_.ts_nh3_concentration_fl);
604  nh3_uptake_fl.reference( ph_.ts_nh3_uptake_fl);
605  nox_uptake_fl.reference( ph_.ts_nox_uptake_fl);
606 
607  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
608  {
609  MoBiLE_Plant *p = *vt;
610  carbonuptake_vt[p->slot] = 0.0;
611  for ( size_t fl = 0; fl < p->nb_foliagelayers(); ++fl)
612  {
613  carbonuptake_vt[p->slot] += p->carbonuptake_fl[fl];
614  }
615  }
616 
617  // grazing event by external module
618  if ( lclock()->subday() == 1)
619  {
620  m_eventgraze.reset_daily_food_consumption();
621  }
622  }
623  else
624  {
625  temp_sl.reference( mc_.nd_temp_sl);
626  ts_temp_fl.reference( mc_.nd_temp_fl); // fw: both the same ...
627 
628  no_concentration_fl.reference( ac_.nd_no_concentration_fl);
629  no2_concentration_fl.reference( ac_.nd_no2_concentration_fl);
630  nh3_concentration_fl.reference( ac_.nd_nh3_concentration_fl);
631  nh3_uptake_fl.reference( ph_.nd_nh3_uptake_fl);
632  nox_uptake_fl.reference( ph_.nd_nox_uptake_fl);
633 
634  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
635  {
636  MoBiLE_Plant *p = *vt;
637  carbonuptake_vt[p->slot] = 0.0;
638  for ( size_t fl = 0; fl < p->nb_foliagelayers(); ++fl)
639  {
640  carbonuptake_vt[p->slot] += p->d_carbonuptake_fl[fl];
641  }
642  }
643 
644  m_eventgraze.reset_daily_food_consumption();
645  }
646 
647  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
648  {
649  MoBiLE_Plant *p = *vt;
650 
651  PSIM_Reset( p);
652 
653  // leaf temperature
654  ts_leaftemp_vt[p->slot] = m_pf.leaf_temperature_( ts_temp_fl, p);
655  nd_leaftemp_vt[p->slot] = m_pf.leaf_temperature_( mc_.nd_temp_fl, p);
656  }
657 
658  // nitrous oxygen concentration in the air
659  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
660  {
661  cNOx_fl[fl] = no_concentration_fl[fl] + no2_concentration_fl[fl];
662  }
663 
664  return LDNDC_ERR_OK;
665 }

Member Data Documentation

◆ C1

const double ldndc::PhysiologyGrowthPSIM::C1 = 0.0367
static

second parameter for temperature influence on vcmax activity

◆ CCOMNOX

const double ldndc::PhysiologyGrowthPSIM::CCOMNOX = 1.0
static

compensation NOx concentration without gas exchange [ppb]

◆ CSATNH3

const double ldndc::PhysiologyGrowthPSIM::CSATNH3 = 50.0
static

saturation NH3 concentration [ppb]

◆ CSATNOX

const double ldndc::PhysiologyGrowthPSIM::CSATNOX = 5.0
static

saturation NOx concentration [ppb]

◆ EPOTNOX

const double ldndc::PhysiologyGrowthPSIM::EPOTNOX = 1.0
static

potential specific emission rate of NOx [ppb]

◆ FMIN

const double ldndc::PhysiologyGrowthPSIM::FMIN = 0.05
static

average concentration of minerals others than nitrogen [kg/kgDW]

◆ FRFRT

const double ldndc::PhysiologyGrowthPSIM::FRFRT = 0.5
static

fraction of nitrate that is reduced in the roots

◆ IMAX_W

const int unsigned ldndc::PhysiologyGrowthPSIM::IMAX_W = 24
static

number of iteration steps within a day

◆ KMMM

const double ldndc::PhysiologyGrowthPSIM::KMMM = 0.0
static

Michaelis Menten constant

◆ PAMM

const double ldndc::PhysiologyGrowthPSIM::PAMM = 0.17
static

carbon costs for ammonia uptake

◆ PGDD

const double ldndc::PhysiologyGrowthPSIM::PGDD = 0.0075
static

parameter for GDD relation to temperature related site conditions

◆ PMIN

const double ldndc::PhysiologyGrowthPSIM::PMIN = 0.06
static

carbon costs for minerals

◆ PNIT

const double ldndc::PhysiologyGrowthPSIM::PNIT = 0.34
static

carbon costs for nitrate uptake

◆ PPHLOE

const double ldndc::PhysiologyGrowthPSIM::PPHLOE = 0.06
static

carbon costs for carbon transport from the leafs

◆ PREDFRT

const double ldndc::PhysiologyGrowthPSIM::PREDFRT = 1.72
static

carbon costs for nitrate reduction in the roots

◆ PREDSAP

const double ldndc::PhysiologyGrowthPSIM::PREDSAP = 0.855
static

carbon costs for nitrate reduction in the shoot

◆ PTW

const double ldndc::PhysiologyGrowthPSIM::PTW = 0.29
static

weighting factor for maximum temperature

◆ root_system

std::map< int, RootSystemDNDC > ldndc::PhysiologyGrowthPSIM::root_system
private

Root system.

  • rooting depth
  • root distribution

◆ TAU

const double ldndc::PhysiologyGrowthPSIM::TAU = 330.0
static

first parameter for temperature influence on vcmax activity

◆ TGLIM

const double ldndc::PhysiologyGrowthPSIM::TGLIM = 6.0
static

soil temperature below which no fine root growth occurs (oC)

◆ TRMAX

const double ldndc::PhysiologyGrowthPSIM::TRMAX = 45.0
static

maximum temperature for maintanence respiration

◆ TRMIN

const double ldndc::PhysiologyGrowthPSIM::TRMIN = -7.0
static

minimum temperature for maintanence respiration

◆ TROPT

const double ldndc::PhysiologyGrowthPSIM::TROPT = 20.0
static

temperature for optimum maintanence respiration

◆ UPOTNH3

const double ldndc::PhysiologyGrowthPSIM::UPOTNH3 = 10000.0
static

potential specific uptake rate of NH3 (ppb)