LandscapeDNDC 1.37.0
ldndc::PhysiologyGrowthPSIM Class Reference

Vegetation model GrowthPSIM. More...

#include <models/physiology/psim/psim.h>

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)
1456{
1457 m_eventgraze.update_available_freshfood_c( m_veg, species_groups_select_t< species::grass >());
1458
1459 for ( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1460 {
1461 MoBiLE_Plant *p = (*vt);
1462 if ( p->group() == "grass")
1463 {
1464 lerr_t rc_graze = m_eventgraze.event_graze_physiology( *vt);
1465 if ( (rc_graze != LDNDC_ERR_EVENT_MATCH) &&
1466 (rc_graze != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1467 {
1468 LOGERROR("Grazing not successful");
1469 return rc_graze;
1470 }
1471 }
1472 }
1473
1474 // cutting event by external module
1475 lerr_t rc_cut = m_eventcut.event_cut_physiology( m_veg, species_groups_select_t< species::grass >());
1476 if ( (rc_cut != LDNDC_ERR_EVENT_MATCH) &&
1477 (rc_cut != LDNDC_ERR_EVENT_EMPTY_QUEUE))
1478 {
1479 LOGERROR("Cutting not successful");
1480 return rc_cut;
1481 }
1482 else if (rc_cut == LDNDC_ERR_EVENT_MATCH)
1483 {
1484 for (PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1485 {
1486 MoBiLE_Plant* p = (*vt);
1487 m_treedyn.OnStructureChange(p);
1488 }
1489 }
1490
1491 return LDNDC_ERR_OK;
1492}

◆ PSIM_BiomassUpdate()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_BiomassUpdate ( )
protected

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

3154{
3155 for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3156 {
3157 MoBiLE_Plant *p = (*vt);
3158
3159 // remembering starting values
3160 double const fFacOld = p->f_fac;
3161
3162 double const mFolOld = p->mFol;
3163 double const mBudOld = p->mBud;
3164 double const mFrtOld = p->mFrt;
3165 double const mSapOld = p->mSap;
3166 double const mLivOld = mFolOld + mBudOld + mFrtOld + mSapOld;
3167
3168 // increase of dry matter
3169 double const groFol = p->dcFol / cbm::CCDM;
3170 double const groBud = p->dcBud / cbm::CCDM;
3171 double const groFrt = p->dcFrt / cbm::CCDM;
3172 double const groSap = p->dcSap / cbm::CCDM;
3173 double const groSum = groBud + groFrt + groSap;
3174
3175 /* biomass adjustment according to the shift in free available carbon
3176 * following the basic assumption that free available carbon is proportionally
3177 * distributed between or taken from the compartments but leaving reserves unchanged.*/
3178 if ( cbm::flt_greater_zero( mLivOld))
3179 {
3180 double const redistribC( p->dcFac / cbm::CCDM);
3181 p->mFol += (redistribC * mFolOld / mLivOld);
3182 p->mBud += (redistribC * mBudOld / mLivOld);
3183 p->mFrt += (redistribC * mFrtOld / mLivOld);
3184 p->mSap += (redistribC * mSapOld / mLivOld);
3185 }
3186
3187 // considering growth and loss effects on compartment biomasses
3188 p->mFol += (groFol - p->sFol + mBudLoss_vt[p->slot]);
3189 p->mBud += (groBud - p->sBud - mBudLoss_vt[p->slot]);
3190 p->mFrt += (groFrt - cbm::sum( p->sFrt_sl, sl_.soil_layer_cnt()));
3191 p->mSap += (groSap - mSapLoss_vt[p->slot]);
3192 p->mCor += (mSapLoss_vt[p->slot] * (1.0 - p->f_branch));
3193
3194 if ( !cbm::flt_greater_zero( p->mFol)) p->mFol = 0.0;
3195 if ( !cbm::flt_greater_zero( p->mBud)) p->mBud = 0.0;
3196 if ( !cbm::flt_greater_zero( p->mFrt)) p->mFrt = 0.0;
3197 if ( !cbm::flt_greater_zero( p->mSap)) p->mSap = 0.0;
3198
3199 // biomass and foliage area in layers
3200 m_pf.update_foliage_layer_biomass_and_lai((*vt), fl_cnt_, 0.0);
3201
3202 // change foliage biomass in age classes due to growth and senescence
3203 if ( p->nb_ageclasses() == 1)
3204 {
3205 p->mFol_na[0] = p->mFol;
3206 }
3207 else
3208 {
3209 // allowing foliage mass increase in plants with non-annual growth behaviour
3210 p->mFol_na[0] += cbm::bound_min( 0.0, groFol + mBudLoss_vt[p->slot] - p->sFol_na[0]);
3211 for ( size_t na = 1; na < p->nb_ageclasses(); ++na)
3212 {
3213 p->mFol_na[na] = cbm::bound_min( 0.0, p->mFol_na[na] - p->sFol_na[na]);
3214 }
3215 }
3216
3217 // total living biomass after growth (kgDM)
3218 double const mLivNew( p->mFol + p->mBud + p->mFrt + p->mSap);
3219
3223 if ( cbm::flt_greater( mLivNew, 0.001))
3224 {
3225 // ratio of free available carbohydrates
3226 double const senSum = cbm::sum( p->sFrt_sl, sl_.soil_layer_cnt()) + mSapLoss_vt[p->slot] + p->sFol;
3227 p->f_fac = (fFacOld * (mLivOld - senSum) * cbm::CCDM + vt->FFACMAX() * groSum * cbm::CCDM + p->dcFac ) / (mLivNew * cbm::CCDM);
3228
3229 if ( !cbm::flt_greater_zero( p->f_fac)) p->f_fac = 0.0;
3230 }
3231 else
3232 {
3233 p->f_fac = 0.0;
3234 }
3235
3236 // peak foliage amount
3237 if ( cbm::flt_greater( p->mFol, p->mFolMax))
3238 {
3239 p->mFolMax = p->mFol;
3240 }
3241 }
3242
3243 return LDNDC_ERR_OK;
3244}

◆ PSIM_HydraulicConductance()

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

◆ PSIM_Photosynthesis()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_Photosynthesis ( )
protected
Returns
error code
833{
834 for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
835 {
836 MoBiLE_Plant *p = *vt;
837
838 for (size_t fl = 0; fl < p->nb_foliagelayers(); ++fl)
839 {
840 m_photo.vpd_fl[fl] = mc_.vpd_fl[fl];
841 m_photo.rh_fl[fl] = cl_.rel_humidity_subday( lclock_ref());
842 m_photo.temp_fl[fl] = mc_.temp_fl[fl];
843 m_photo.parsun_fl[fl] = mc_.parsun_fl[fl];
844 m_photo.parshd_fl[fl] = mc_.parshd_fl[fl];
845 m_photo.tFol_fl[fl] = mc_.tFol_fl[fl];
846 m_photo.co2_concentration_fl[fl] = ac_.ts_co2_concentration_fl[fl];
847 m_photo.sunlitfoliagefraction_fl[fl] = mc_.ts_sunlitfoliagefraction_fl[fl];
848 }
849 m_photo.nd_airpressure = mc_.nd_airpressure;
850
851 m_photo.set_vegetation_base_state( p);
852
853 m_photo.set_vegetation_non_stomatal_water_limitation_state( p->xylem_resistance, p->psi_mean, p->psi_sr, p->psi_pd);
854
855 m_photo.solve();
856
857 m_photo.get_vegetation_state( p);
858 }
859
860 return LDNDC_ERR_OK;
861}

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

3303{
3304 for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3305 {
3306 MoBiLE_Plant *p = (*vt);
3307
3308 // phenological state
3309 bool const evergreen( (p->nb_ageclasses() > 1) && cbm::flt_greater_zero( p->mFol));
3310 double const pstatus( evergreen ?
3311 (p->dvsFlush * p->mFol_na[0] + (1.0 - p->dvsMort) * (cbm::sum( p->mFol_na, p->nb_ageclasses()) - p->mFol_na[0])) / p->mFol :
3312 std::min( p->dvsFlush, 1.0 - p->dvsMort));
3313
3314 // drought stress impact
3315 // NOTE: consideration of water potential effects is only warranted if the whole hydraulic model is used
3316 double fwat(1.0);
3317 if (m_photo.stomatalconductance_method == eller_2020 && p->dvsFlush > 0.99)
3318 {
3319 fwat = ldndc::non_stomatal_water_limitation( p->psi_pd, (*p)->A_REF(), (*p)->A_EXP() );
3320 }
3321
3322 // - in case drought stress decreases, its decrease is limited by recovery rate (legacy effect)
3323 const double RECOVER(0.01); // fraction recovery per hour
3324 if (fwat > p->fwatOld)
3325 {
3326 double const tslength = double(cbm::HR_IN_DAY) / double(this->lclock_ref().time_resolution());
3327 fwat = std::min(fwat, p->fwatOld + RECOVER * tslength);
3328 }
3329 p->fwatOld = fwat;
3330
3331 // enzyme activity
3332 // (activity of isoprene and monoterpene enzymes are unchanged during the dormant season)
3333 double nFolOpt(m_pf.optimum_nitrogen_content_foliage(p));
3334 double const ncFol_top = (p->mFol * p->ncFol / nFolOpt) * vt->NCFOLOPT();
3335
3336 if ( cbm::flt_greater_zero( pstatus))
3337 {
3338 for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3339 {
3340 if ( cbm::flt_greater_zero( p->m_fol_fl(fl)) &&
3341 cbm::flt_greater_zero( p->sla_fl[fl]))
3342 {
3343 // nitrogen supply in dependence on specific leaf area
3350 double const ncFol_fl( ncFol_top * pow( vt->SLAMIN() / p->sla_fl[fl], 0.3));
3351
3352 // dependency of photosynthesis linearly related to nitrogen (Reynolds et al. 1992)
3353 double const fnit( cbm::bound( 0.0, (ncFol_fl - vt->NC_FOLIAGE_MIN()) / (vt->NCFOLOPT() - vt->NC_FOLIAGE_MIN()), 1.0));
3354
3355 // seasonality factor
3356 double fdorm(0.0);
3357 // - deciduous
3358 if (p->nb_ageclasses() == 1)
3359 {
3360 if ( p->dvsFlush < 1.0)
3361 {
3362 fdorm = cbm::sqr( p->dvsFlush);
3363 }
3364 else
3365 {
3366 fdorm = 1.0 - cbm::sqr( p->dvsMort);
3367 }
3368 }
3369 // - evergreen
3370 else
3371 {
3372 // - equal to the relative pool size of free available carbon reserves (fsub_vt)*/
3373 fdorm = fsub_vt[p->slot];
3374
3375 // - temperature dependent according to Maekelae et al. 2004 (S model)
3376/* if ((mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * (mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl])) >= vt->PSNTFROST())
3377 {
3378// fdorm = C1 * (mc_.tFol24_fl[fl] + cbm::HR_IN_DAY / TAU * ( mc_.nd_temp_fl[fl] - mc_.tFol24_fl[fl]) - vt->PSNTFROST());
3379// fdorm = 1.0;
3380 }
3381 else
3382 {
3383 fdorm = 0.0;
3384 }
3385*/
3386 }
3387
3388 fdorm = cbm::bound( 0.0, fdorm, 1.0);
3389
3390 // activity of rubisco under standard conditions
3391 p->vcAct25_fl[fl] = vt->VCMAX25() * fnit * fdorm * fwat;
3392 // activity of maximum electron transport rate under standard conditions
3393 p->jAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QJVC();
3394 // activity of dark respiration under standard conditions
3395 p->rdAct25_fl[fl] = p->vcAct25_fl[fl] * vt->QRD25();
3396 }
3397 else
3398 {
3399 p->vcAct25_fl[fl] = 0.0;
3400 p->jAct25_fl[fl] = 0.0;
3401 p->rdAct25_fl[fl] = 0.0;
3402 }
3403 }
3404 }
3405 else
3406 {
3407 for ( size_t fl = 0; fl < fl_cnt_; ++fl)
3408 {
3409 p->vcAct25_fl[fl] = 0.0;
3410 p->jAct25_fl[fl] = 0.0;
3411 p->rdAct25_fl[fl] = 0.0;
3412 }
3413 }
3414 }
3415
3416 return LDNDC_ERR_OK;
3417}
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

References ldndc::non_stomatal_water_limitation().

Here is the call graph for this function:

◆ PSIM_PlantingEvent()

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

◆ PSIM_Potentialtranspiration()

lerr_t ldndc::PhysiologyGrowthPSIM::PSIM_Potentialtranspiration ( )
protected
Returns
error code
3422{
3423 double potential_transpiration_vt(0.0);
3424 double potential_transpiration_sum (0.0);
3425
3426 for ( PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3427 {
3428 MoBiLE_Plant *p = (*vt);
3429 if (vt->IS_WOOD())
3430 {
3431 if ( wc_.transpiration_method == substate_watercycle_t::WATERUSEEFFICIENCY)
3432 {
3433 potential_transpiration_vt += potential_wood_transpiration(
3434 sl_,
3435 mc_.nd_watervaporsaturationdeficit,
3436 ph_.carbonuptake(m_veg, fl_cnt_),
3437 p->f_area,
3438 vt->WUECMAX(),
3439 vt->WUECMIN(),
3440 sc_.h_sl,
3441 wc_.wc_sl,
3442 wc_.wc_wp_sl,
3443 wc_.wc_fc_sl);
3444 }
3445 else // transpiration_method == "treewaterdeficit", "potentialtranspiration"
3446 {
3447 potential_transpiration_vt += potential_transpiration(
3448 p->nb_foliagelayers(),
3449 vt->GSMIN(),
3450 vt->GSMAX(),
3451 p->lai_fl,
3452 mc_.vpd_fl,
3453 p->relativeconductance_fl) * cbm::HR_IN_DAY * lclock()->day_fraction();
3454 }
3455 }
3456 else
3457 {
3458 potential_transpiration_vt += potential_crop_transpiration(
3459 ac_.nd_co2_concentration,
3460 ph_.carbonuptake( m_veg, fl_cnt_),
3461 vt->WUECMAX());
3462 }
3463
3464 potential_transpiration_sum += potential_transpiration_vt;
3465 wc_.accumulated_potentialtranspiration += potential_transpiration_vt;
3466 }
3467
3468 for (PlantIterator vt = this->m_veg->begin(); vt != this->m_veg->end(); ++vt)
3469 {
3470 MoBiLE_Plant* p = (*vt);
3471 if (cbm::flt_greater_zero(potential_transpiration_sum))
3472 {
3473 p->f_ptransp = potential_transpiration_vt / potential_transpiration_sum;
3474 }
3475 else
3476 {
3477 p->f_ptransp = 0.0;
3478 }
3479 }
3480
3481 return LDNDC_ERR_OK;
3482}
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
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_crop_transpiration(double _co2, double _carbon_uptake, double _wuecmax)
Returns potential transpiration in [m] for crops and grass.
Definition: ld_transpiration.cpp:45

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

Here is the call graph for this function:

◆ PSIM_ResizeVegetationVectors()

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

◆ PSIM_StepInit()

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

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)