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

◆ PSIM_BiomassUpdate()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_BiomassUpdate ( )
protected

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

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

◆ PSIM_HydraulicConductance()

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

References ldndc::sap_wood_fraction().

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

◆ PSIM_Photosynthesis()

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

◆ 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())

rg 30.10.2024 substituted by the impact factor that reduces activity when the pool of free available carbon reserves is depleted (fsub_vt)

References ldndc::non_stomatal_water_limitation().

3275 {
3276  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3277  {
3278  MoBiLE_Plant *p = (*vt);
3279 
3280  // phenological state
3281  bool const evergreen( (p->nb_ageclasses() > 1) && cbm::flt_greater_zero( p->mFol));
3282  double const pstatus( evergreen ?
3283  (p->dvsFlush * p->mFol_na[0] + (1.0 - p->dvsMort) * (cbm::sum( p->mFol_na, p->nb_ageclasses()) - p->mFol_na[0])) / p->mFol :
3284  std::min( p->dvsFlush, 1.0 - p->dvsMort));
3285 
3286  // drought stress impact
3287  // NOTE: consideration of water potential effects is only warranted if the whole hydraulic model is used
3288  double fwat(1.0);
3289  if (m_photo.stomatalconductance_method == eller_2020 && p->dvsFlush > 0.99)
3290  {
3291  fwat = ldndc::non_stomatal_water_limitation( p->psi_pd, (*p)->A_REF(), (*p)->A_EXP() );
3292  }
3293 
3294  // - in case drought stress decreases, its decrease is limited by recovery rate (legacy effect)
3295  const double RECOVER(0.01); // fraction recovery per hour
3296  if (fwat > p->fwatOld)
3297  {
3298  double const tslength = double(cbm::HR_IN_DAY) / double(this->lclock_ref().time_resolution());
3299  fwat = std::min(fwat, p->fwatOld + RECOVER * tslength);
3300  }
3301  p->fwatOld = fwat;
3302 
3303  // enzyme activity
3304  // (activity of isoprene and monoterpene enzymes are unchanged during the dormant season)
3305  double nFolOpt(m_pf.optimum_nitrogen_content_foliage(p));
3306  double const ncFol_top = (p->mFol * p->ncFol / nFolOpt) * vt->NCFOLOPT();
3307 
3308  if ( cbm::flt_greater_zero( pstatus))
3309  {
3310  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3311  {
3312  if ( cbm::flt_greater_zero( p->m_fol_fl(fl)) &&
3313  cbm::flt_greater_zero( p->sla_fl[fl]))
3314  {
3315  // nitrogen supply in dependence on specific leaf area
3322  double const ncFol_fl( ncFol_top * pow( vt->SLAMIN() / p->sla_fl[fl], 0.3));
3323 
3324  // dependency of photosynthesis linearly related to nitrogen (Reynolds et al. 1992)
3325  double const fnit( cbm::bound( 0.0, (ncFol_fl - vt->NC_FOLIAGE_MIN()) / (vt->NCFOLOPT() - vt->NC_FOLIAGE_MIN()), 1.0));
3326 
3327  // seasonality factor
3328  double fdorm(0.0);
3329  // - deciduous
3330  if (p->nb_ageclasses() == 1)
3331  {
3332  if ( p->dvsFlush < 1.0)
3333  {
3334  fdorm = cbm::sqr( p->dvsFlush);
3335  }
3336  else
3337  {
3338  fdorm = 1.0 - cbm::sqr( p->dvsMort);
3339  }
3340  }
3341  // - evergreen (Maekelae et al. 2004 (S model))
3343  else
3344  {
3345  if (( mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl])) >= vt->PSNTFROST())
3346  {
3347 // fdorm = C1 * (mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl]) - vt->PSNTFROST());
3348  fdorm = fsub_vt[p->slot];
3349 // fdorm = 1.0;
3350  }
3351  else
3352  {
3353  fdorm = 0.0;
3354  }
3355  }
3356 
3357  fdorm = cbm::bound( 0.0, fdorm, 1.0);
3358 
3359  // activity of rubisco under standard conditions
3360  p->vcAct25_fl[fl] = vt->VCMAX25() * fnit * fdorm * fwat;
3361  // activity of maximum electron transport rate under standard conditions
3362  p->jAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QJVC();
3363  // activity of dark respiration under standard conditions
3364  p->rdAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QRD25();
3365  }
3366  else
3367  {
3368  p->vcAct25_fl[fl] = 0.0;
3369  p->jAct25_fl[fl] = 0.0;
3370  p->rdAct25_fl[fl] = 0.0;
3371  }
3372  }
3373  }
3374  else
3375  {
3376  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3377  {
3378  p->vcAct25_fl[fl] = 0.0;
3379  p->jAct25_fl[fl] = 0.0;
3380  p->rdAct25_fl[fl] = 0.0;
3381  }
3382  }
3383  }
3384 
3385  return LDNDC_ERR_OK;
3386 }
static const double TAU
Definition: psim.h:78
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
495 {
496  EventAttributes const * ev_plant = NULL;
497  while ( (ev_plant = this->m_PlantEvents.pop()) != NULL)
498  {
499  MoBiLE_Plant *vt = this->m_veg->get_plant( ev_plant->get( "/name", "?"));
500  if ( !vt)
501  {
502  KLOGERROR( "Handling plant event failed [species=", ev_plant->get( "/name", "?"),"]");
503  return LDNDC_ERR_RUNTIME_ERROR;
504  }
505  CBM_LogDebug( "Seed plant '",vt->name(),"'");
506 
507  species_t const * sp = NULL;
508  if ( m_species)
509  {
510  sp = m_species->get_species( vt->cname());
511  }
512 
513  root_system.insert( { vt->slot, RootSystemDNDC( m_state, io_kcomm) } );
514 
515  char const * group = ev_plant->get( "/group", "?");
516  if ( cbm::is_equal( group, "wood"))
517  {
518  lerr_t rc_plant = m_pf.initialize_tree( vt, sp->wood(), branchfraction_opt, crownlength_opt, competition_opt);
519  if ( rc_plant)
520  {
521  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
522  return LDNDC_ERR_FAIL;
523  }
524  }
525  else if ( cbm::is_equal( group, "grass")) // TODO could be done at "push-time"
526  {
527  lerr_t rc_plant = m_pf.initialize_grass( vt, sp->grass());
528  if ( rc_plant)
529  {
530  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
531  return LDNDC_ERR_FAIL;
532  }
533  }
534  else if ( cbm::is_equal( group, "crop")) // TODO could be done at "push-time"
535  {
536  lerr_t rc_plant = m_pf.initialize_crop( vt, sp->crop());
537  if ( rc_plant)
538  {
539  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
540  return LDNDC_ERR_FAIL;
541  }
542  }
543 
544  // initialize local state variables after planting
545  if ( vt->dEmerg > 0)
546  {
547  if ( (int)lclock()->yearday() > vt->dEmerg)
548  {
549  days_since_emergence[vt->slot] = (int)(lclock()->yearday()) - vt->dEmerg;
550  }
551  else
552  {
553  // use 366 on purpose to ensure always: days_since_emergence > 0
554  days_since_emergence[vt->slot] = (int)(lclock()->yearday()) + (366 - vt->dEmerg);
555  }
556  }
557  else
558  {
559  days_since_emergence[vt->slot] = 0;
560  }
561 
562  if ( lclock()->yearday() >= PSIM_YEAR_START)
563  {
564  phenological_year[vt->slot] = lclock()->year();
565  }
566  else
567  {
568  phenological_year[vt->slot] = lclock()->year() - 1;
569  }
570 
571  foliage_age_of_start_senescence[vt->slot] = m_pf.get_foliage_age_of_senescence( vt, 0.0);
572 
573  for ( size_t na = 0; na < vt->nb_ageclasses(); ++na)
574  {
575  foliage_age_na[vt->slot][na] = m_pf.get_foliage_age( PSIM_YEAR_START, lclock()->yearday(), na);
576  }
577  }
578 
579  return LDNDC_ERR_OK;
580 }
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().

3391 {
3392  for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3393  {
3394  MoBiLE_Plant *p = (*vt);
3395  if (vt->IS_WOOD())
3396  {
3397  if ( wc_.transpiration_method == substate_watercycle_t::WATERUSEEFFICIENCY)
3398  {
3399  wc_.accumulated_potentialtranspiration += potential_wood_transpiration(
3400  sl_,
3401  mc_.nd_watervaporsaturationdeficit,
3402  ph_.carbonuptake(m_veg, fl_cnt_),
3403  p->f_area,
3404  vt->WUECMAX(),
3405  vt->WUECMIN(),
3406  sc_.h_sl,
3407  wc_.wc_sl,
3408  wc_.wc_wp_sl,
3409  wc_.wc_fc_sl);
3410  }
3411  else // transpiration_method == "potentialtranspiration"
3412  {
3413  wc_.accumulated_potentialtranspiration += potential_transpiration(
3414  p->nb_foliagelayers(),
3415  vt->GSMIN(),
3416  vt->GSMAX(),
3417  p->lai_fl,
3418  mc_.vpd_fl,
3419  p->relativeconductance_fl) * cbm::HR_IN_DAY * lclock()->day_fraction();
3420  }
3421  }
3422  else
3423  {
3424  wc_.accumulated_potentialtranspiration += potential_crop_transpiration(
3425  ac_.nd_co2_concentration,
3426  ph_.carbonuptake( m_veg, fl_cnt_),
3427  vt->WUECMAX());
3428  }
3429  }
3430 
3431  return LDNDC_ERR_OK;
3432 }
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
378 {
379  // compare number of vegetation types
380  size_t const slot_cnt( m_veg->slot_cnt());
381  size_t const slot_cnt_old( additional_season.size());
382 
383  if ( slot_cnt <= slot_cnt_old)
384  {
385  return LDNDC_ERR_OK;
386  }
387 
388  matrix_2d_dbl_t::extent_type const vtsl[] =
389  { static_cast< matrix_2d_dbl_t::extent_type >( slot_cnt),
390  static_cast< matrix_2d_dbl_t::extent_type >( sl_.soil_layer_cnt())};
391 
392  additional_season.resize_and_preserve( slot_cnt, false);
393  phenological_year.resize_and_preserve( slot_cnt, 0);
394  foliage_age_of_start_senescence.resize_and_preserve( slot_cnt, 0);
395  days_since_emergence.resize_and_preserve( slot_cnt, 0);
396 
397  // average (effective) temperatures of all leaves of a vegetation type
398  ts_leaftemp_vt.resize_and_preserve( slot_cnt, 0.0);
399  nd_leaftemp_vt.resize_and_preserve( slot_cnt, 0.0);
400 
401  uptNH4Max_vt.resize_and_preserve( slot_cnt, 0.0); // max. ammonium uptake
402  uptNO3Max_vt.resize_and_preserve( slot_cnt, 0.0); // max. nitrate uptake
403  uptDONMax_vt.resize_and_preserve( slot_cnt, 0.0); // max. dissolved organic nitrogen uptake
404  uptNWetMax_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
405  uptNWet_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
406  uptNTot_vt.resize_and_preserve( slot_cnt, 0.0); // tot. nitrogen uptake
407 
408  rFolOld_vt.resize_and_preserve( slot_cnt, 0.0);
409  rBudOld_vt.resize_and_preserve( slot_cnt, 0.0);
410  rSapOld_vt.resize_and_preserve( slot_cnt, 0.0);
411  rFrtOld_vt.resize_and_preserve( slot_cnt, 0.0);
412  rTraOld_vt.resize_and_preserve( slot_cnt, 0.0);
413  exsuLossOld_vt.resize_and_preserve( slot_cnt, 0.0);
414 
415  uptNH4_vt.resize_and_preserve( slot_cnt, 0.0);
416  uptNO3_vt.resize_and_preserve( slot_cnt, 0.0);
417  uptNH3_vt.resize_and_preserve( slot_cnt, 0.0);
418  uptDON_vt.resize_and_preserve( slot_cnt, 0.0);
419 
420  uptNH4Old_vt.resize_and_preserve( slot_cnt, 0.0);
421  uptNO3Old_vt.resize_and_preserve( slot_cnt, 0.0);
422  uptNH3Old_vt.resize_and_preserve( slot_cnt, 0.0);
423  uptDONOld_vt.resize_and_preserve( slot_cnt, 0.0);
424 
425  uptN2Old_vt.resize_and_preserve( slot_cnt, 0.0);
426  uptNOxOld_vt.resize_and_preserve( slot_cnt, 0.0);
427 
428  while ( slot_cnt > uptNH4Max_vtsl.size())
429  {
430  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
431  uptNH4Max_vtsl.push_back( help_sl);
432  }
433  while ( slot_cnt > uptNO3Max_vtsl.size())
434  {
435  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
436  uptNO3Max_vtsl.push_back( help_sl);
437  }
438  while ( slot_cnt > uptDONMax_vtsl.size())
439  {
440  std::vector<double> help_sl( sl_.soil_layer_cnt(), 0.0);
441  uptDONMax_vtsl.push_back( help_sl);
442  }
443  while ( slot_cnt > foliage_age_na.size())
444  {
445  std::vector< int > help_sl( MoBiLE_MaximumAgeClasses, 0);
446  foliage_age_na.push_back( help_sl);
447  }
448 
449  carbonuptake_vt.resize_and_preserve( slot_cnt, 0.0);
450  //xylem_resistance_smoothed_vt.resize_and_preserve(slot_cnt, 0.0);
451  xylem_resistance_smoothed_old_vt.resize_and_preserve(slot_cnt, 0.0);
452  psidecline_cum_vt.resize_and_preserve(slot_cnt, 0.0);
453  psidecline_daycum_vt.resize_and_preserve(slot_cnt, 0.0);
454  rehydrationindex_cum_vt.resize_and_preserve(slot_cnt, 0.0);
455 
456  //do not initialize to zero!
457  mSapOpt_vt.resize_and_preserve( slot_cnt, 0.0);
458  mSapOld_vt.resize_and_preserve( slot_cnt, 0.0);
459  mCorOld_vt.resize_and_preserve( slot_cnt, 0.0);
460  qsaparea_vt.resize_and_preserve(slot_cnt, 0.0);
461  fsub_vt.resize_and_preserve(slot_cnt, 0.0);
462 
463  mBudLoss_vt.resize_and_preserve( slot_cnt, 0.0); // dry matter transfered from buds to foliage
464  mSapLoss_vt.resize_and_preserve( slot_cnt, 0.0); // dry matter transfered from sapwood to corewood
465  ncFolOpt.resize_and_preserve( slot_cnt, 0.0); // optimum nitrogen concentration of the whole foliage of one species (gN gDW-1)
466  ncBudOpt.resize_and_preserve( slot_cnt, 0.0); // optimum nitrogen concentration of the whole structural storage of one species (gN gDW-1)
467  nDem_vt.resize_and_preserve( slot_cnt, 0.0); // species specific nitrogen demand (kgN)
468  nFol_vt.resize_and_preserve( slot_cnt, 0.0); // last days foliage nitrogen content (kg)
469  nFrt_vt.resize_and_preserve( slot_cnt, 0.0); // last days fine root nitrogen content (kg)
470  nSap_vt.resize_and_preserve( slot_cnt, 0.0); // last days sapwood nitrogen content (kg)
471  nCor_vt.resize_and_preserve( slot_cnt, 0.0); // last days corwood nitrogen content (kg)
472  nBud_vt.resize_and_preserve( slot_cnt, 0.0); // last days bud nitrogen content (kg)
473 
474  n_bud_to_fol_vt.resize_and_preserve( vtsl, 0.0);
475  n_sap_to_cor_vt.resize_and_preserve( vtsl, 0.0);
476  n_bud_to_cor_vt.resize_and_preserve( vtsl, 0.0);
477  n_fol_to_cor_vt.resize_and_preserve( vtsl, 0.0);
478  n_frt_to_cor_vt.resize_and_preserve( vtsl, 0.0);
479  n_sap_to_litter_vt.resize_and_preserve( vtsl, 0.0);
480  n_sap_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
481  n_bud_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
482  n_fol_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
483  n_frt_to_redistribute_vt.resize_and_preserve( vtsl, 0.0);
484  n_sap_gain_vt.resize_and_preserve( vtsl, 0.0);
485  n_bud_gain_vt.resize_and_preserve( vtsl, 0.0);
486  n_fol_gain_vt.resize_and_preserve( vtsl, 0.0);
487  n_frt_gain_vt.resize_and_preserve( vtsl, 0.0);
488 
489  return LDNDC_ERR_OK;
490 }

◆ PSIM_StepInit()

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

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)