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
 ...
 
cbm::string_t transpiration_method
 Transpiration method used by PSIM.
 

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 FAGE
 
static const double FRFRT = 0.5
 
static const double FMIN = 0.05
 
static const double FYIELD
 
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)
1436 {
1437  m_eventgraze.update_available_freshfood_c( m_veg, species_groups_select_t< species::grass >());
1438 
1439  for ( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1440  {
1441  MoBiLE_Plant *p = (*vt);
1442  if ( p->group() == "grass")
1443  {
1444  lerr_t rc_graze = m_eventgraze.event_graze_physiology( *vt);
1445  if ( (rc_graze != LDNDC_ERR_EVENT_MATCH) &&
1446  (rc_graze != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1447  {
1448  LOGERROR("Grazing not successful");
1449  return rc_graze;
1450  }
1451  }
1452  }
1453 
1454  // cutting event by external module
1455  lerr_t rc_cut = m_eventcut.event_cut_physiology( m_veg, species_groups_select_t< species::grass >());
1456  if ( (rc_cut != LDNDC_ERR_EVENT_MATCH) &&
1457  (rc_cut != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1458  {
1459  LOGERROR("Cutting not successful");
1460  return rc_cut;
1461  }
1462  else if (rc_cut == LDNDC_ERR_EVENT_MATCH)
1463  {
1464  for (PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1465  {
1466  MoBiLE_Plant* p = (*vt);
1467  m_treedyn.OnStructureChange(p);
1468  }
1469  }
1470 
1471  return LDNDC_ERR_OK;
1472 }

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

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

◆ PSIM_Photosynthesis()

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

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

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 (Maekelae et al. 2004 (S model))
3335  else
3336  {
3337  if (( mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl])) >= vt->PSNTFROST())
3338  {
3339 // fdorm = C1 * (mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl]) - vt->PSNTFROST());
3340  fdorm = fsub_vt[p->slot];
3341 // fdorm = 1.0;
3342  }
3343  else
3344  {
3345  fdorm = 0.0;
3346  }
3347  }
3348 
3349  fdorm = cbm::bound( 0.0, fdorm, 1.0);
3350 
3351  // activity of rubisco under standard conditions
3352  p->vcAct25_fl[fl] = vt->VCMAX25() * fnit * fdorm * fwat;
3353  // activity of maximum electron transport rate under standard conditions
3354  p->jAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QJVC();
3355  // activity of dark respiration under standard conditions
3356  p->rdAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QRD25();
3357  }
3358  else
3359  {
3360  p->vcAct25_fl[fl] = 0.0;
3361  p->jAct25_fl[fl] = 0.0;
3362  p->rdAct25_fl[fl] = 0.0;
3363  }
3364  }
3365  }
3366  else
3367  {
3368  for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3369  {
3370  p->vcAct25_fl[fl] = 0.0;
3371  p->jAct25_fl[fl] = 0.0;
3372  p->rdAct25_fl[fl] = 0.0;
3373  }
3374  }
3375  }
3376 
3377  return LDNDC_ERR_OK;
3378 }
static const double TAU
Definition: psim.h:82
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
487 {
488  EventAttributes const * ev_plant = NULL;
489  while ( (ev_plant = this->m_PlantEvents.pop()) != NULL)
490  {
491  MoBiLE_Plant *vt = this->m_veg->get_plant( ev_plant->get( "/name", "?"));
492  if ( !vt)
493  {
494  KLOGERROR( "Handling plant event failed [species=", ev_plant->get( "/name", "?"),"]");
495  return LDNDC_ERR_RUNTIME_ERROR;
496  }
497  CBM_LogDebug( "Seed plant '",vt->name(),"'");
498 
499  species_t const * sp = NULL;
500  if ( m_species)
501  {
502  sp = m_species->get_species( vt->cname());
503  }
504 
505  root_system.insert( { vt->slot, RootSystemDNDC( m_state, io_kcomm) } );
506 
507  char const * group = ev_plant->get( "/group", "?");
508  if ( cbm::is_equal( group, "wood"))
509  {
510  lerr_t rc_plant = m_pf.initialize_tree( vt, sp->wood(), branchfraction_opt, crownlength_opt, competition_opt);
511  if ( rc_plant)
512  {
513  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
514  return LDNDC_ERR_FAIL;
515  }
516  }
517  else if ( cbm::is_equal( group, "grass")) // TODO could be done at "push-time"
518  {
519  lerr_t rc_plant = m_pf.initialize_grass( vt, sp->grass());
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, "crop")) // TODO could be done at "push-time"
527  {
528  lerr_t rc_plant = m_pf.initialize_crop( vt, sp->crop());
529  if ( rc_plant)
530  {
531  KLOGERROR( "Plant initialization failed [species=", vt->name(),"]");
532  return LDNDC_ERR_FAIL;
533  }
534  }
535 
536  // initialize local state variables after planting
537  if ( vt->dEmerg > 0)
538  {
539  if ( (int)lclock()->yearday() > vt->dEmerg)
540  {
541  days_since_emergence[vt->slot] = lclock()->yearday() - vt->dEmerg;
542  }
543  else
544  {
545  // use 366 on purpose to ensure always: days_since_emergence > 0
546  days_since_emergence[vt->slot] = lclock()->yearday() + (366 - vt->dEmerg);
547  }
548  }
549  else
550  {
551  days_since_emergence[vt->slot] = 0;
552  }
553 
554  if ( lclock()->yearday() >= PSIM_YEAR_START)
555  {
556  phenological_year[vt->slot] = lclock()->year();
557  }
558  else
559  {
560  phenological_year[vt->slot] = lclock()->year() - 1;
561  }
562 
563  foliage_age_of_start_senescence[vt->slot] = m_pf.get_foliage_age_of_senescence( vt, 0.0);
564 
565  for ( size_t na = 0; na < vt->nb_ageclasses(); ++na)
566  {
567  foliage_age_na[vt->slot][na] = m_pf.get_foliage_age( PSIM_YEAR_START, lclock()->yearday(), na);
568  }
569  }
570 
571  return LDNDC_ERR_OK;
572 }
cbm::string_t branchfraction_opt
...
Definition: psim.h:117
bool competition_opt
...
Definition: psim.h:129
std::map< int, RootSystemDNDC > root_system
Root system.
Definition: psim.h:388
cbm::string_t crownlength_opt
...
Definition: psim.h:123

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

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

◆ PSIM_StepInit()

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

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]

◆ FAGE

const double ldndc::PhysiologyGrowthPSIM::FAGE
static

power coefficient that reduces specific sapwood respiration with age

◆ 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

◆ FYIELD

const double ldndc::PhysiologyGrowthPSIM::FYIELD
static

fraction of growth respiration relative to gross assimilation

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