LandscapeDNDC  1.36.0
ldndc::WatercycleDNDC Class Reference

Watercycle model WatercycleDNDC. More...

Inherits ldndc::MBE_LegacyModel.

Public Member Functions

lerr_t solve ()
 Kicks off computation for one time step.
 

Static Public Attributes

static const unsigned int IMAX_W = 24
 

Private Member Functions

lerr_t event_irrigate ()
 considers water input due to irrigation and/or liquid manure evetns
 
lerr_t event_flood ()
 sets hydrologic conditions during flooding events, e.g., More...
 
double balance_check (double *)
 checks each time step for correct water balance More...
 
void CalcRaining (unsigned int)
 apportion daily rainfall to subdaily rainfall
 
double rainfall_intensity ()
 
void CalcIrrigation (unsigned int)
 apportion daily irrigation to subdaily irrigation More...
 
lerr_t CalcIceContent ()
 Call of ice-content related processes.
 
lerr_t CalcPotEvapoTranspiration ()
 Potential evaporation. More...
 
void CalcInterception ()
 Calculates water quantity that is retained on leaf and stem bark surfaces. More...
 
double get_leaf_water ()
 Collects leaf water from all canopy layers. More...
 
double get_impedance_factor (size_t)
 Reduces water fluxes out of a layer if ice lenses have formed.
 
lerr_t CalcTranspiration ()
 
lerr_t CalcTranspirationCouvreur (double const &hr_potTransinm)
 
void CalcSnowEvaporation ()
 
void CalcSurfaceWaterEvaporation ()
 
void CalcSurfaceFlux ()
 
void WatercycleDNDC_preferential_flow ()
 
void CalcSoilEvapoPercolation ()
 
void SoilWaterEvaporation (size_t)
 
double WaterFlowCapillaryRise (size_t, double const &)
 Similar to WaterFlowBelowFieldCapacity(...) but restricts water flow by water availability from soil layer below.
 
double WaterFlowAboveFieldCapacity (size_t, double const &)
 
double WaterFlowSaturated (size_t, double const &)
 
double get_fsl (size_t)
 Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0.02 m has been assumed. Due to flexible layer depth, an additional factor has been introduced that accounts for a higher resistance of larger layers.
 
double get_time_step_duration ()
 Time fraction with regard to daily rates.
 

Private Attributes

double thornthwaite_heat_index
 heat index for potential evaporation using approach after Thornthwaite
 

Detailed Description

Watercycle model WatercycleDNDC.

Member Function Documentation

◆ balance_check()

double ldndc::WatercycleDNDC::balance_check ( double *  _balance)
private

checks each time step for correct water balance

Balance check of water.

2510 {
2511  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water;
2512  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2513  {
2514  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2515  }
2516  balance += ( - m_wc.accumulated_irrigation_event_executed
2517  - wc_.accumulated_irrigation_automatic
2518  - wc_.accumulated_irrigation_ggcmi
2519  - wc_.accumulated_irrigation_reservoir_withdrawal
2520  - wc_.accumulated_precipitation
2521  - wc_.accumulated_groundwater_access
2522  + wc_.accumulated_percolation
2523  + wc_.accumulated_runoff
2524  + wc_.accumulated_wateruptake_sl.sum()
2525  + wc_.accumulated_interceptionevaporation
2526  + wc_.accumulated_soilevaporation
2527  + wc_.accumulated_surfacewaterevaporation);
2528 
2529  if ( _balance)
2530  {
2531  double const balance_delta( std::abs( *_balance - balance));
2532  if ( balance_delta > cbm::DIFFMAX)
2533  {
2534  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2535  }
2536  }
2537 
2538  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2539  {
2540  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2541  {
2542  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2543  wc_.wc_sl[sl] = 0.0;
2544  }
2545  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2546  {
2547  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2548  wc_.ice_sl[sl] = 0.0;
2549  }
2550  }
2551 
2552  return balance;
2553 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1171

◆ CalcInterception()

void ldndc::WatercycleDNDC::CalcInterception ( )
private

Calculates water quantity that is retained on leaf and stem bark surfaces.

  • Rainfall and interception are assumed to happen at the end of the timestep and evaporation is realised at once at the start of the timestep.
  • The model assumes a homogeneous horizontal distribution of LAI although a non-linear dependency to crown cover (relative foliage clumping) has been reported (e.g. Teklehaimanot et al. 1991).
  • The default water-interception for foliage almost equal to the largest species specific value

◆ CalcIrrigation()

void ldndc::WatercycleDNDC::CalcIrrigation ( unsigned int  _i)
private

apportion daily irrigation to subdaily irrigation

Automatic irrigation to prevent water stress

GGCMI style irrigation

  • fill up the water content of each soil layer to field capacity at the start of each day
  • water supplied just injected into soil layer
  • no interception, no run off, no surface-water
  • only irrigate if a crop is present

Irrigation due to flooding

irrigation triggered by flooding management

Irrigation due to explicit irrigation event

643 {
644  //reset irrigation
645  m_wc.irrigation = 0.0;
646 
650  if ( cbm::flt_in_range_lu(0.0, m_cfg.automaticirrigation, 1.0))
651  {
652  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
653  {
654  // trigger irrigation events as soon as drought stress appears
655  double const wc_target( wc_.wc_wp_sl[l] + m_cfg.automaticirrigation * (wc_.wc_fc_sl[l] - wc_.wc_wp_sl[l]));
656  if ( cbm::flt_less( wc_.wc_sl[l], wc_target))
657  {
658  // irrigation assumed until target water content
659  double const irrigate_layer( (wc_target - wc_.wc_sl[l]) * sc_.h_sl[l]);
660  m_wc.irrigation += irrigate_layer;
661  wc_.accumulated_irrigation_automatic += irrigate_layer;
662  }
663  }
664  }
665 
666  if ( cbm::flt_in_range_lu( 0.0, m_eventflood.get_saturation_level(), 1.0) &&
667  cbm::is_valid( m_eventflood.get_irrigation_height()) &&
668  cbm::is_valid( m_eventflood.get_soil_depth()))
669  {
670  double wc_sum( 0.0);
671  double wc_fc_sum( 0.0);
672  double wc_wp_sum( 0.0);
673  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
674  {
675  wc_sum += wc_.wc_sl[l] * sc_.h_sl[l];
676  wc_fc_sum += wc_.wc_fc_sl[l] * sc_.h_sl[l];
677  wc_wp_sum += wc_.wc_wp_sl[l] * sc_.h_sl[l];
678 
679  if ( cbm::flt_greater_equal( sc_.depth_sl[l], m_eventflood.get_soil_depth()))
680  {
681  break;
682  }
683  }
684 
685  // trigger irrigation events as soon as drought stress appears
686  double const wc_target( wc_wp_sum + m_eventflood.get_saturation_level() * (wc_fc_sum - wc_wp_sum));
687  if ( cbm::flt_less( wc_sum, wc_target))
688  {
689  m_wc.irrigation += m_eventflood.get_irrigation_height();
690  wc_.accumulated_irrigation_automatic += m_eventflood.get_irrigation_height();
691  }
692  }
693 
701  if ( m_cfg.ggcmi_irrigation)
702  {
703  if( (lclock()->subday() == 1) && (_i == 0))
704  {
705  if( m_veg->size() > 0 ) //check crop is present
706  {
707  double water_supply( 0.0);
708  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
709  {
710  if ( cbm::flt_greater_zero( m_veg->mfrt_sl( l))) //only irrigate soil layers that contain roots
711  {
712  if( cbm::flt_less( wc_.wc_sl[l], wc_.wc_fc_sl[l]) &&
713  cbm::flt_equal_zero( wc_.ice_sl[l])) //only add water if no ice is present
714  {
715  water_supply += (wc_.wc_fc_sl[l] - wc_.wc_sl[l]) * sc_.h_sl[l]; //amount of water added (m)
716  wc_.wc_sl[l] = wc_.wc_fc_sl[l];
717  }
718  }
719  }
720  wc_.accumulated_irrigation_ggcmi += water_supply;
721  }
722  }
723  }
724 
728  if ( cbm::is_valid( m_eventflood.get_water_table()))
729  {
730  /* Dynamic flooding */
731  if ( cbm::is_valid( m_eventflood.get_irrigation_height()))
732  {
733  bool irrigate( false);
734 
735  /* Irrigate after surface water table drop */
736  if ( cbm::flt_greater_equal_zero( m_eventflood.get_water_table()))
737  {
738  if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
739  {
740  irrigate = true;
741  }
742  }
743  else
744  {
745  if ( !cbm::flt_greater_zero( wc_.surface_water))
746  {
747  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
748  {
749  if ( cbm::flt_greater_equal( sc_.depth_sl[sl], -m_eventflood.get_water_table()))
750  {
751  //check if water content below AWD_DEPTH is saturated
752  if ( cbm::flt_less( wc_.wc_sl[sl], 0.9 * sc_.poro_sl[sl]))
753  {
754  irrigate = true;
755  }
756  break;
757  }
758  }
759  }
760  }
761  // trigger AWD irrigation event
762  if ( irrigate)
763  {
764  double water_supply( cbm::bound_min( 0.0, m_eventflood.get_irrigation_height() - wc_.surface_water));
765  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
766  {
767  // set soil fully water saturated
768  if ( cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
769  {
770  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
771  }
772  }
773 
774  //remove rainfall (less irrigation water is supplied if it if raining)
775  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.rainfall);
776 
777  if ( m_eventflood.have_unlimited_water())
778  {
779  wc_.accumulated_irrigation_automatic += water_supply;
780  }
781  else
782  {
783  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
784  {
785  wc_.irrigation_reservoir -= water_supply;
786  }
787  else
788  {
789  water_supply = wc_.irrigation_reservoir;
790  wc_.irrigation_reservoir = 0.0;
791  }
792  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
793  }
794  m_wc.irrigation += water_supply;
795  }
796  }
797  /* Static flooding */
798  else
799  {
800  if ( !cbm::flt_greater_zero( m_eventflood.get_water_table()))
801  {
802  double water_supply( 0.0);
803  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
804  {
805  if ( cbm::flt_greater( sc_.depth_sl[sl], -m_eventflood.get_water_table()) &&
806  cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
807  {
808  double const scale( cbm::flt_less( sc_.depth_sl[sl] - sc_.h_sl[sl], -m_eventflood.get_water_table()) ?
809  (-m_eventflood.get_water_table() - (sc_.depth_sl[sl] - sc_.h_sl[sl])) / sc_.h_sl[sl] :
810  1.0);
811 
812  water_supply += scale * (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl];
813  }
814  }
815 
816  //remove rainfall (less irrigation water is supplied if it if raining)
817  water_supply = cbm::bound( 0.0, water_supply - m_mc.rainfall, wc_.sks_sl[0]);
818 
819  /* Surface water will be actively drained */
820  if ( cbm::flt_greater_equal( wc_.surface_water, water_supply))
821  {
822  wc_.accumulated_runoff += wc_.surface_water - water_supply;
823  wc_.surface_water = water_supply;
824  water_supply = 0.0;
825  }
826  else if ( cbm::flt_greater_zero( wc_.surface_water))
827  {
828  water_supply -= wc_.surface_water;
829  }
830 
831  if ( m_eventflood.have_unlimited_water())
832  {
833  wc_.accumulated_irrigation_automatic += water_supply;
834  }
835  else
836  {
837  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
838  {
839  wc_.irrigation_reservoir -= water_supply;
840  }
841  else
842  {
843  water_supply = wc_.irrigation_reservoir;
844  wc_.irrigation_reservoir = 0.0;
845  }
846  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
847  }
848 
849  m_wc.irrigation += water_supply;
850  }
854  else if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
855  {
856  //adjust surface and soil water in case of flooding event
857  //water required to fill up surface water
858  double water_supply( m_eventflood.get_water_table() - wc_.surface_water);
859 
860  //add water required to fill top x layers up to saturation
861  unsigned long no_layers(3);
862  if( no_layers > m_soillayers->soil_layer_cnt())
863  {
864  no_layers = m_soillayers->soil_layer_cnt();
865  }
866 
867  for ( size_t sl = 0; sl < no_layers; ++sl)
868  {
869  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
870  }
871 
872  //remove rainfall (less irrigation water is supplied if it if raining)
873  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.rainfall);
874 
875  if ( m_eventflood.have_unlimited_water())
876  {
877  wc_.accumulated_irrigation_automatic += water_supply;
878  }
879  else
880  {
881  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
882  {
883  wc_.irrigation_reservoir -= water_supply;
884  }
885  else
886  {
887  water_supply = wc_.irrigation_reservoir;
888  wc_.irrigation_reservoir = 0.0;
889  }
890  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
891  }
892  m_wc.irrigation += water_supply;
893  }
894  }
895  }
896 
900  double const irrigation_scheduled( cbm::bound_min( 0.0, wc_.accumulated_irrigation - m_wc.accumulated_irrigation_event_executed));
901 
902  if ( cbm::flt_greater( irrigation_scheduled, 24.0 * rainfall_intensity()))
903  {
904  m_wc.irrigation += irrigation_scheduled / 24.0;
905  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled / 24.0;
906  }
907  else if ( cbm::flt_greater( irrigation_scheduled, (double)hours_per_time_step() * rainfall_intensity()))
908  {
909  m_wc.irrigation += (double)hours_per_time_step() * rainfall_intensity();
910  m_wc.accumulated_irrigation_event_executed += (double)hours_per_time_step() * rainfall_intensity();
911  }
912  else
913  {
914  m_wc.irrigation += irrigation_scheduled;
915  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled;
916  }
917 }
double rainfall_intensity()
Definition: watercycle-dndc.cpp:115

◆ CalcPotEvapoTranspiration()

lerr_t ldndc::WatercycleDNDC::CalcPotEvapoTranspiration ( )
private

Potential evaporation.


there are two methods of calculating potential evaporation (choose via macro POTENTIAL_EVAPORATION above)

  • [0] Procedure according to Thornthwaite 1948 with modifications by Camargo et al. 1999 and Peireira and Pruitt 2004 (implemented from Pereira and Pruitt 2004) to better account for dry environments and daylength.
    NOTE:
    • monthly temperatures are assumed to be equal to daily average temperature of the middle of the month, calculated from continous equations equal to those used in the weather generator.
    • the model uses always daily average temperature as input even if it is run in sub-daily mode
    • the original PnET-N-DNDC code which contains modification that could not be found in the literature has been outcommented.
  • [1] uses the Priestley Taylor equation (Priestly and Taylor 1972) to calculate daily and hourly potential evapotranspiration (implemented from internet) vps calculation according to Allen et al. 1998, cit. in Cai et al. 2007

References ldndc::thornthwaite(), and ldndc::thornthwaite_heat_index().

1052 {
1053  day_potevapo = 0.0;
1054  if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
1055  {
1056  if ( lclock()->is_position( TMODE_PRE_YEARLY))
1057  {
1059  lclock()->days_in_year(),
1060  m_climate->annual_temperature_average(),
1061  m_climate->annual_temperature_amplitude());
1062  }
1063 
1064  double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
1065  double const avg_dayl(12.0);
1066 
1067  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1069  mc_.nd_airtemperature,
1070  daylength, avg_dayl, lclock()->days_in_month(),
1072  }
1073  else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
1074  (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
1075  {
1076  /* clock */
1077  cbm::sclock_t const & clk( this->lclock_ref());
1078 
1079  /* leaf area index */
1080  double lai( 0.0);
1081  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1082  {
1083  lai += (*vt)->lai();
1084  }
1085 
1086  /* vapour pressure [10^3:Pa] */
1087  double vps( 0.0);
1088  ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
1089  double vp( vps - m_climate->vpd_day( clk));
1090 
1091  if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
1092  {
1093  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1094  * ldndc::priestleytaylor( clk.yearday(),
1095  clk.days_in_year(),
1096  mc_.albedo,
1097  m_setup->latitude(),
1098  mc_.nd_airtemperature,
1099  mc_.nd_shortwaveradiation_in,
1100  vp,
1101  m_param->PT_ALPHA());
1102  }
1103  else if( m_cfg.potentialevapotranspiration_method == "penman")
1104  {
1105  ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
1106 
1107  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1108  * ldndc::penman( surface,
1109  clk.yearday(),
1110  clk.days_in_year(),
1111  mc_.albedo,
1112  m_setup->latitude(),
1113  mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
1114  mc_.nd_airtemperature,
1115  mc_.nd_windspeed,
1116  vp);
1117  }
1118  }
1119  else
1120  {
1121  KLOGERROR("[BUG] huh :o how did you get here? ",
1122  "tell the maintainers refering to this error message");
1123  return LDNDC_ERR_FAIL;
1124  }
1125 
1126  if ( m_cfg.evapotranspiration_method == "uniform")
1127  {
1128  // hourly evaporation demand is calculated from daily demand equally throughout the day
1129  hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
1130  }
1131  else if ( m_cfg.evapotranspiration_method == "previouspattern")
1132  {
1133 
1134  hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
1135  }
1136  else //if ( m_cfg.evapotranspiration_method === "nice name") // could be for example 'daytime_only'
1137  {
1138  double const hour(lclock()->subday());
1139  double const day(lclock()->yearday());
1140  double const hsun(0.833 * cbm::PI / 180.0);
1141  double const lat(m_setup->latitude() * cbm::PI / 180.0);
1142  double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
1143  double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
1144  double dayl(0.0);
1145  if (help < -0.999) dayl = 0.0;
1146  else if (help > 0.999) dayl = 24.0;
1147  else dayl = 24.0 - 24.0 / cbm::PI * std::acos((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
1148  if (dayl < 1.0) dayl = 0.0;
1149  double const rise(12.0 - dayl * 0.5);
1150 
1151  double factor(0.0);
1152  if (dayl > 0.0) factor = (-std::cos(2.0 * cbm::PI * (hour - rise) / (cbm::HR_IN_DAY - 2.0 * rise)) + 1.0) / (cbm::HR_IN_DAY - 2.0 * rise);
1153 
1154  double fday(0.0);
1155  if (hour > rise && hour < (24.0 - rise)) fday = factor;
1156 
1157  hr_pot_evapotrans = day_potevapo * fday;
1158  }
1159  // the evaporation limit for all timesteps is the daily demand
1160  wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
1161 
1162  return LDNDC_ERR_OK;
1163 }
double LDNDC_API thornthwaite_heat_index(double, size_t, double, double)
Thornthwaite heat index.
Definition: ld_thornthwaite.cpp:100
double thornthwaite_heat_index
heat index for potential evaporation using approach after Thornthwaite
Definition: watercycle-dndc.h:137
double LDNDC_API thornthwaite(double, double, double, double, double)
Potential evapotranspiration after .
Definition: ld_thornthwaite.cpp:41
Here is the call graph for this function:

◆ CalcSnowEvaporation()

void ldndc::WatercycleDNDC::CalcSnowEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1880 {
1881  //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
1882  double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
1883 
1884  if ( cbm::flt_greater_zero( wc_.surface_ice) &&
1885  cbm::flt_greater_zero( hr_potESnow))
1886  {
1887  //If there is a snowpack and there is a potential to evaporate
1888  if ( wc_.surface_ice > hr_potESnow)
1889  {
1890  //Partial evaporation from the snow
1891  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
1892  wc_.accumulated_surfacewaterevaporation += hr_potESnow;
1893  wc_.surface_ice -= hr_potESnow;
1894  }
1895  else
1896  {
1897  //Total evaporation of the snowpack
1898  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
1899  wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
1900  wc_.surface_ice = 0.0;
1901  }
1902  }
1903 }

◆ CalcSoilEvapoPercolation()

void ldndc::WatercycleDNDC::CalcSoilEvapoPercolation ( )
private
Parameters
[in]None
[out]None
Returns
None
2018 {
2019  /* Reset water fluxes */
2020  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2021  {
2022  m_wc.percolation_sl[sl] = 0.0;
2023  }
2024 
2025  /* Fill groundwater layer with water */
2026  for (int sl = m_soillayers->soil_layer_cnt() - 1; sl >= 0; --sl)
2027  {
2028  if (cbm::flt_greater_equal(sc_.depth_sl[sl], ground_water_table))
2029  {
2030  /* ensure that ice volume is less than porosity */
2031  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2032  if (cbm::flt_greater(sc_.poro_sl[sl], ice_vol))
2033  {
2034  //air filled porosity is filled with groundwater
2035  double const gw_access(cbm::bound_min(0.0,
2036  (sc_.poro_sl[sl] - ice_vol - wc_.wc_sl[sl]) * sc_.h_sl[sl]));
2037  wc_.wc_sl[sl] += gw_access / sc_.h_sl[sl];
2038  wc_.accumulated_groundwater_access += gw_access;
2039  }
2040  }
2041  else
2042  {
2043  break;
2044  }
2045  }
2046 
2047  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2048  {
2049  if (sl == 0)
2050  {
2051  wc_.accumulated_infiltration += wc_.surface_water;
2052  wc_.wc_sl[0] += wc_.surface_water / sc_.h_sl[0];
2053  wc_.surface_water = 0.0;
2054  }
2055  else
2056  {
2057  wc_.wc_sl[sl] += m_wc.percolation_sl[sl - 1] / sc_.h_sl[sl];
2058  }
2059 
2060  if (cbm::flt_greater(sc_.depth_sl[sl], ground_water_table))
2061  {
2062  //set constant flux for all ground water layers depending on last non-groundwater layer
2063  if (sl > 0)
2064  {
2065  m_wc.percolation_sl[sl] = m_wc.percolation_sl[sl - 1];
2066  }
2067 
2068  //in case of groundwater until soil surface first outflux is estimated by saturated water flow
2069  else
2070  {
2071  m_wc.percolation_sl[sl] = WaterFlowSaturated(sl, get_impedance_factor(sl));
2072  }
2073  }
2074  else if (sl + 1 == m_soillayers->soil_layer_cnt())
2075  {
2076  m_wc.percolation_sl[sl] = 0.0;
2077  if (cbm::flt_greater_zero(wc_.sks_sl[sl]))
2078  {
2079  if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2080  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl])) //security, should be always true if first condition is met
2081  {
2082  //maximum allowed flow until field capacity
2083  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2084  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)),
2085  max_flow);
2086  }
2087 
2088  //water flux above field capacity
2089  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2090  {
2091  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2092  }
2093 
2094  //water flux below field capacity and above wilting point
2095  else if (cbm::flt_greater_zero(m_wc.percolation_sl[sl - 1])
2096  && cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2097  {
2098  m_wc.percolation_sl[sl] = m_param->FPERCOL() * m_wc.percolation_sl[sl - 1];
2099  }
2100 
2101  //bound water flux by defined maximal percolation rate (e.g., during flooding events)
2102  m_wc.percolation_sl[sl] = cbm::bound_max(m_wc.percolation_sl[sl], max_percolation);
2103  }
2104  }
2105 
2106  //infiltrating water in current time step is exceeding available pore space of last time step
2107  //second condition: security, should be always true if first condition is met
2108  else if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2109  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl]))
2110  {
2111  //maximum allowed flow until field capacity
2112  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2113  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)),
2114  max_flow);
2115  }
2116  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2117  {
2118  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2119  }
2120  else if (cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2121  {
2122  m_wc.percolation_sl[sl] = WaterFlowCapillaryRise(sl, get_impedance_factor(sl));
2123  }
2124  else
2125  {
2126  m_wc.percolation_sl[sl] = 0.0;
2127  }
2128 
2129 
2130  // water content must be greater or equal wilting point
2131  if (cbm::flt_less((wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl] - m_wc.percolation_sl[sl], wc_.wc_wp_sl[sl] * sc_.h_sl[sl]) &&
2132  cbm::flt_greater_zero(m_wc.percolation_sl[sl]))
2133  {
2134  m_wc.percolation_sl[sl] = cbm::bound(0.0,
2135  (wc_.wc_sl[sl] + wc_.ice_sl[sl] - wc_.wc_wp_sl[sl]) * sc_.h_sl[sl],
2136  m_wc.percolation_sl[sl]);
2137  }
2138 
2139  // Update of the current soil layer water content
2140  wc_.wc_sl[sl] -= m_wc.percolation_sl[sl] / sc_.h_sl[sl];
2141 
2143  }
2144 
2145  /* Correct water content and percolation if water content is above porosity
2146  * If the layer below cannot take up all of the water assigned for percolation,
2147  * so if the air filled pore space is not sufficient,
2148  * the water remains in the upper layer.
2149  */
2150  for (size_t sl = m_soillayers->soil_layer_cnt() - 1; sl > 0; sl--)
2151  {
2152  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2153  if (cbm::flt_greater(wc_.wc_sl[sl] + ice_vol, sc_.poro_sl[sl]))
2154  {
2155  double delta_wc(wc_.wc_sl[sl] + ice_vol - sc_.poro_sl[sl]);
2156  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[sl]))
2157  {
2158  delta_wc = wc_.wc_sl[sl];
2159  wc_.wc_sl[sl] = 0.0;
2160  }
2161  else
2162  {
2163  wc_.wc_sl[sl] = sc_.poro_sl[sl] - ice_vol;
2164  }
2165  m_wc.percolation_sl[sl - 1] -= delta_wc * sc_.h_sl[sl];
2166  wc_.wc_sl[sl - 1] += delta_wc * sc_.h_sl[sl] / sc_.h_sl[sl - 1];
2167  }
2168  }
2169 
2170  double const ice_vol(wc_.ice_sl[0] / cbm::DICE);
2171  if (cbm::flt_greater(wc_.wc_sl[0] + ice_vol, sc_.poro_sl[0]))
2172  {
2173 
2174  double delta_wc(wc_.wc_sl[0] + ice_vol - sc_.poro_sl[0]);
2175  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[0]))
2176  {
2177  delta_wc = wc_.wc_sl[0];
2178  wc_.wc_sl[0] = 0.0;
2179  }
2180  else
2181  {
2182  wc_.wc_sl[0] = sc_.poro_sl[0] - ice_vol;
2183  }
2184  wc_.accumulated_infiltration -= delta_wc * sc_.h_sl[0];
2185  wc_.surface_water += delta_wc * sc_.h_sl[0];
2186  }
2187 
2188  if (cbm::flt_greater_zero(wc_.surface_water))
2189  {
2190  CalcSurfaceFlux();
2191  }
2192 
2193  wc_.accumulated_waterflux_sl += m_wc.percolation_sl;
2194  wc_.accumulated_percolation += m_wc.percolation_sl[ m_soillayers->soil_layer_cnt()-1];
2195 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2297
double get_impedance_factor(size_t)
Reduces water fluxes out of a layer if ice lenses have formed.
Definition: watercycle-dndc.cpp:2373
void SoilWaterEvaporation(size_t)
Definition: watercycle-dndc.cpp:1945
double WaterFlowAboveFieldCapacity(size_t, double const &)
Definition: watercycle-dndc.cpp:2208
void CalcSurfaceFlux()
Definition: watercycle-dndc.cpp:2422
double WaterFlowCapillaryRise(size_t, double const &)
Similar to WaterFlowBelowFieldCapacity(...) but restricts water flow by water availability from soil ...
Definition: watercycle-dndc.cpp:2267

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2423 {
2424  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2425  {
2426  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2427  {
2428  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2429  wc_.surface_water = m_eventflood.get_bund_height();
2430  }
2431  }
2432  else
2433  {
2434  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2435  double const runoff_fraction( m_param->FRUNOFF() * get_time_step_duration());
2436 
2437  // - not all surface water is removed within one timestep
2438  if ( cbm::flt_less( runoff_fraction, 1.0))
2439  {
2440  double const runoff( runoff_fraction * wc_.surface_water);
2441  wc_.surface_water -= runoff;
2442  wc_.accumulated_runoff += runoff;
2443  }
2444  // - all surface water is immediatly removed
2445  else
2446  {
2447  wc_.accumulated_runoff += wc_.surface_water;
2448  wc_.surface_water = 0.0;
2449  }
2450  }
2451 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2498

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1849 {
1850  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1851  cbm::flt_greater_zero( hr_pot_evapotrans))
1852  {
1853  if ( hr_pot_evapotrans > wc_.surface_water)
1854  {
1855  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1856  hr_pot_evapotrans -= wc_.surface_water;
1857  wc_.surface_water = 0.0;
1858  }
1859  else
1860  {
1861  wc_.surface_water -= hr_pot_evapotrans;
1862  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1863  hr_pot_evapotrans = 0.0;
1864  }
1865  }
1866 }

◆ CalcTranspiration()

lerr_t ldndc::WatercycleDNDC::CalcTranspiration ( )
private
Parameters
[in]None
[out]None
Returns
None

◆ CalcTranspirationCouvreur()

lerr_t ldndc::WatercycleDNDC::CalcTranspirationCouvreur ( double const &  hr_potTransinm)
private
Parameters
[in]None
[out]None
Returns
None
1704 {
1705  // hourly potential transpiration
1706  double const hr_potTrans( hr_potTransinm * cbm::CM_IN_M);
1707 
1708  // hourly water uptake
1709  double hr_uptake( 0.0);
1710 
1711  // Calculate the root water uptake and hence the transpiration for every plant individually
1712  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1713  {
1714  // split up the potential transpiration equally to the various plants
1715  // frt mass of the current species
1716  double const mfrt_species( (*vt)->mFrt);
1717  // total frt mass
1718  double const mfrt_sum( m_veg->dw_frt());
1719  double const hr_potTransspecies = hr_potTrans * mfrt_species/mfrt_sum; // in cm
1720 
1721  // If some soil layers are frozen and contain only ice, no fluid water is present and the water potential diverges.
1722  // The uptake from these layers is prevented by considering only roots in layers with more water than ice.
1723  // In this case the root distribution needs to be rescaled (otherwise the non-contributing layers would effectively contribute a potential = 0).
1724  double fFrt_unfrozen( 1.0);
1725 
1726  /* TODO: include icetowatercrit as proper parameter */
1727  double icetowatercrit( 0.1);
1728  double effsoilwatpot( 0.0);
1729  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1730  {
1731  // fine root conditions to prevent transpiration without uptake organs, wateruptake from frozen ground
1732  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1733  {
1734  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1735  {
1736  // overall water potential in this layer
1737  double const watpotl( Soillayerwaterhead( sl)); // negative
1738  effsoilwatpot += watpotl * (*vt)->fFrt_sl[sl]; // negative
1739  }
1740  else
1741  {
1742  fFrt_unfrozen -= (*vt)->fFrt_sl[sl];
1743  }
1744  }
1745  else
1746  {
1747  // roots are not wireless ;-)
1748  break;
1749  }
1750  }
1751  // normalize the root distribution in the potential, if some soil is frozen
1752  effsoilwatpot = effsoilwatpot / fFrt_unfrozen;
1753 
1754  // hydraulic conductivities of plant system
1755  double const Krs(vt->KRSINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1756  double const Kcomp(vt->KCOMPINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1757 
1758  // water potential in the leafs, depending on the potential transpiration
1759  double const leafwatpot( cbm::bound_min(vt->HLEAFCRIT(), effsoilwatpot - (hr_potTransspecies / Krs))); // cm
1760 
1761  if( cbm::flt_greater_zero( leafwatpot))
1762  {
1763  KLOGERROR( "leafwatpot is positive");
1764  return LDNDC_ERR_FAIL;
1765  }
1766  if( !cbm::flt_greater_zero( effsoilwatpot - leafwatpot))
1767  {
1768  KLOGERROR( "effsoilwatpot - leafwatpot is smaller 0: ", effsoilwatpot - leafwatpot, ", effsoilwatpot = ", effsoilwatpot, ", leafwatpot = ", leafwatpot, "\n-> Hourly transpiration ", hr_uptake, " is negative!\nPlant dies :-( Try with a smaller KRSINIT or different KCOMPINIT or different EXP_ROOT_DISTRIBUTION.\nOr wc_wp is to close to the residual water content.. increase it.");
1769  return LDNDC_ERR_FAIL;
1770  }
1771 
1772  double const effuptake( Krs * (effsoilwatpot - leafwatpot)); // cm/timestep
1773  double uptake_tot( 0.0);
1774  double uptakecomp_tot( 0.0);
1775 // double uptakecompabs_tot( 0.0);
1776 
1777  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1778  {
1779  // fine root condition to prevent transpiration without uptake organs
1780  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1781  {
1782  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1783  {
1784  double const watpotl( Soillayerwaterhead( sl));
1785  double const compuptake( Kcomp * (watpotl - effsoilwatpot));
1786  double uptake_layer( (effuptake + compuptake) * (*vt)->fFrt_sl[sl]); // absolute value in cm
1787 
1788  wc_.accumulated_wateruptake_sl[sl] += uptake_layer * cbm::M_IN_CM;
1789  uptake_tot += uptake_layer; // absolute value in cm
1790  uptakecomp_tot += compuptake * (*vt)->fFrt_sl[sl]; // absolute value in cm
1791 // uptakecompabs_tot += fabs(compuptake * (*vt)->fFrt_sl[sl]); // absolute value in cm
1792 
1793  wc_.wc_sl[sl] -= uptake_layer * cbm::M_IN_CM /sc_.h_sl[sl]; // fraction of water in this layer, in m
1794 
1795  if( !cbm::flt_greater_zero( wc_.wc_sl[sl]))
1796  {
1797  KLOGERROR( "In soil layer ", sl, " the water content is negative: ", wc_.wc_sl[sl]);
1798  return LDNDC_ERR_FAIL;
1799  }
1800  }
1801  }
1802  else
1803  {
1804  // roots are not wireless ;-)
1805  break;
1806  }
1807  }
1808 
1809  hr_uptake += uptake_tot * cbm::M_IN_CM; // absolute value in m for all species
1810 
1811 
1812  if( cbm::flt_greater_zero( fabs(uptakecomp_tot))){
1813  KLOGWARN( "Compensatory water uptake ", uptakecomp_tot, " > 0.");
1814  }
1815  if( cbm::flt_greater( uptake_tot, hr_potTransspecies, 0.0000000001))
1816  {
1817  KLOGERROR( "Total water uptake ", uptake_tot, " larger than potential transpiration ", hr_potTransspecies);
1818  }
1819  if(cbm::flt_equal_eps(fFrt_unfrozen, 1.0, 0.0000000001) && !cbm::flt_equal_eps( uptake_tot, hr_potTransspecies, 0.0000000001) && !cbm::flt_equal_eps( leafwatpot, vt->HLEAFCRIT(), 0.0000000001))
1820  {
1821  KLOGERROR( "T ", uptake_tot, "cm < Tpot ", hr_potTransspecies, "cm even though leafwatpot ", leafwatpot, " > HLEAFCRIT", vt->HLEAFCRIT());
1822  }
1823  }
1824 
1825  // total evaporation demand reduced to apply on other evaporating sources (ground, snow, surface water)
1826  hr_pot_evapotrans = cbm::bound_min(0.0, hr_pot_evapotrans - hr_uptake);
1827 
1828  return LDNDC_ERR_OK;
1829 }

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

sets hydrologic conditions during flooding events, e.g.,

  • surface water table
  • bund height
613 {
614  lerr_t rc = m_eventflood.solve();
615  if ( rc != LDNDC_ERR_OK)
616  {
617  KLOGERROR("Irrigation event not successful!");
618  return rc;
619  }
620 
621  /* max_percolation is gradually decreased after end of flooding event to inital value */
622  double const maximum_percolation = m_eventflood.get_maximum_percolation();
623  if ( cbm::is_valid( maximum_percolation))
624  {
625  if ( cbm::flt_greater_zero( maximum_percolation))
626  {
627  max_percolation = maximum_percolation * nhr / 24.0;
628  }
629  }
630  else
631  {
632  /* time rate for gradual recovery of max_percolation */
633  double const time_rate( get_time_step_duration() * 0.1);
634  max_percolation -= (max_percolation - WaterFlowSaturated( m_soillayers->soil_layer_cnt()-1, 1.0)) * time_rate;
635  }
636 
637  return LDNDC_ERR_OK;
638 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2297
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2498

◆ get_leaf_water()

double ldndc::WatercycleDNDC::get_leaf_water ( )
private

Collects leaf water from all canopy layers.

Parameters
[in]None
[out]None
Returns
Leaf water

References ldndc::site::site_info_t::pressure_at_field_capacity, and ldndc::rootdensityfortranspiration_sl().

1172 {
1173  if ( m_veg->size() > 0u)
1174  {
1175  return wc_.wc_fl.sum();
1176  }
1177  return 0.0;
1178 }
Here is the call graph for this function:

◆ rainfall_intensity()

double ldndc::WatercycleDNDC::rainfall_intensity ( )
private

fixed amount of maximum rainfall/irrigation triggered per time step

References ldndc::climate::climate_info_t::rainfall_intensity, and ldndc::thornthwaite_heat_index().

116 {
117  if ( m_iokcomm->get_input_class< input_class_climate_t >())
118  {
119  return m_iokcomm->get_input_class< climate::input_class_climate_t >()->station_info()->rainfall_intensity * cbm::M_IN_MM;
120  }
121  else
122  {
123  return ldndc::climate::climate_info_defaults.rainfall_intensity * cbm::M_IN_MM;
124  }
125 }
double rainfall_intensity
Definition: climatetypes.h:40
Here is the call graph for this function:

◆ SoilWaterEvaporation()

void ldndc::WatercycleDNDC::SoilWaterEvaporation ( size_t  _sl)
private
Parameters
[in]_slSoil layer
[out]None
Returns
None
1947 {
1948  //percolation and direct evaporation from the (upper) soil
1949  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1950  double const wc_min_evaporation( m_param->WCDNDC_EVALIM_FRAC_WCMIN() * wc_.wc_wp_sl[_sl]);
1951  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_param->EVALIM()) &&
1952  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
1953  cbm::flt_greater_zero( hr_pot_evapotrans))
1954  {
1955  //limiting factor for soil water infiltration
1956  double const f_clay( 1.0 + m_param->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
1957  double const f_water( cbm::bound( 0.0,
1958  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / wc_.wc_fc_sl[_sl], f_clay),
1959  1.0));
1960  double const h_rest( std::min( sc_.h_sl[_sl], m_param->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
1961  double const f_depth( h_rest / m_param->EVALIM() * std::max(0.0,
1962  1.0 - std::min((double)m_param->EVALIM(),
1963  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
1964  / m_param->EVALIM()));
1965  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
1966 
1967  double const soilevaporation( cbm::bound( 0.0,
1968  hr_pot_evapotrans * f_depth * f_water,
1969  soilevaporation_max));
1970 
1971  //update of the current soil layer water content
1972  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
1973  wc_.accumulated_soilevaporation += soilevaporation;
1974  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
1975  }
1976 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2312 {
2313  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2314  if ( cbm::flt_greater_zero( m_param->BY_PASSF()) &&
2315  cbm::flt_greater_zero( wc_.surface_water))
2316  {
2317 
2318  double water_def_total( 0.0);
2319  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2320  {
2321  //water flux that flow through macro pores can maximally store
2322  water_def_total += cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]);
2323  }
2324 
2325  //duration of timestep (hr-1)
2326  double const fhr( get_time_step_duration());
2327 
2328 
2329  //fraction of surface water that is put into bypass flow (m timestep-1)
2330  double const bypass_fraction( cbm::bound_max( m_param->BY_PASSF() * fhr, 0.99));
2331  double const bypass_water( wc_.surface_water * bypass_fraction);
2332  wc_.surface_water -= bypass_water;
2333  wc_.accumulated_infiltration += bypass_water;
2334 
2335  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2336  {
2337 
2338  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2339  {
2340  double const water_def( cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2341  double const water_add( water_def / water_def_total * bypass_water);
2342 
2343  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2344  }
2345  }
2346  else
2347  {
2348  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2349  {
2350  double const water_def( cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2351  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2352  }
2353  /* add surplus to percolation out of last soil layer */
2354  wc_.accumulated_percolation += bypass_water - water_def_total;
2355  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2356  }
2357  }
2358 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2498

◆ WaterFlowAboveFieldCapacity()

double ldndc::WatercycleDNDC::WaterFlowAboveFieldCapacity ( size_t  _sl,
double const &  _fact_impedance 
)
private

factor accounting for different water travelling characteristics in litter and mineral soil

2211 {
2212  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2213  double const fsl( get_fsl( _sl));
2214  double const fhr( get_time_step_duration());
2215 
2217  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_param->SLOPE_FF() : m_param->SLOPE_MS());
2218 
2219  //max 0.005 means that no sks values 9.88 cm min-1 are allowed !!
2220  /* TODO: reconsider maximum value for traveltime
2221  - no source is given for 9.88 cm min-1 (app. 0.0016 m s-1, 5.9 m h-1, 0.16 cm s-1) (this seems to refer to coarse sand 0.01-1 cm s-1)
2222  - if traveltime is in units m dayfraction-1, the limit value should also depend on fhr!! Thus, sks_sl should be directly limited
2223  - O.005 m h-1 is 0.0083 cm min-1, so how is this referring to 9.88 cm min-1??
2224  */
2225  double const travelTime( std::max( 0.005, 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr)));
2226  return( cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2227  * 0.5 * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * (1.0 - exp(-1.0 / travelTime)) * _fact_impedance,
2228  sks));
2229 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2297
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2498
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2394

◆ WaterFlowSaturated()

double ldndc::WatercycleDNDC::WaterFlowSaturated ( size_t  _sl,
double const &  _fact_impedance 
)
private

Returns saturated water flow per time step accounting for impedance

2299 {
2300  double const sks( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * get_time_step_duration() * _fact_impedance);
2301  return sks;
2302 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2498

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day