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.

2420 {
2421  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water + plant_waterdeficit_compensation;
2422  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2423  {
2424  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2425  }
2426  balance += ( - m_wc.accumulated_irrigation_event_executed
2427  - wc_.accumulated_irrigation_automatic
2428  - wc_.accumulated_irrigation_ggcmi
2429  - wc_.accumulated_irrigation_reservoir_withdrawal
2430  - wc_.accumulated_precipitation
2431  - wc_.accumulated_groundwater_access
2432  + wc_.accumulated_percolation
2433  + wc_.accumulated_runoff
2434  + wc_.accumulated_wateruptake_sl.sum()
2435  + wc_.accumulated_interceptionevaporation
2436  + wc_.accumulated_soilevaporation
2437  + wc_.accumulated_surfacewaterevaporation);
2438 
2439  if ( _balance)
2440  {
2441  double const balance_delta( std::abs( *_balance - balance));
2442  if ( balance_delta > cbm::DIFFMAX)
2443  {
2444  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2445  }
2446  }
2447 
2448  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2449  {
2450  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2451  {
2452  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2453  wc_.wc_sl[sl] = 0.0;
2454  }
2455  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2456  {
2457  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2458  wc_.ice_sl[sl] = 0.0;
2459  }
2460  }
2461 
2462  return balance;
2463 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1164

◆ 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

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

1045 {
1046  day_potevapo = 0.0;
1047  if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
1048  {
1049  if ( lclock()->is_position( TMODE_PRE_YEARLY))
1050  {
1052  lclock()->days_in_year(),
1053  m_climate->annual_temperature_average(),
1054  m_climate->annual_temperature_amplitude());
1055  }
1056 
1057  double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
1058  double const avg_dayl(12.0);
1059 
1060  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1062  mc_.nd_airtemperature,
1063  daylength, avg_dayl, lclock()->days_in_month(),
1065  }
1066  else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
1067  (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
1068  {
1069  /* clock */
1070  cbm::sclock_t const & clk( this->lclock_ref());
1071 
1072  /* leaf area index */
1073  double lai( 0.0);
1074  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1075  {
1076  lai += (*vt)->lai();
1077  }
1078 
1079  /* vapour pressure [10^3:Pa] */
1080  double vps( 0.0);
1081  ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
1082  double vp( vps - m_climate->vpd_day( clk));
1083 
1084  if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
1085  {
1086  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1087  * ldndc::priestleytaylor( clk.yearday(),
1088  clk.days_in_year(),
1089  mc_.albedo,
1090  m_setup->latitude(),
1091  mc_.nd_airtemperature,
1092  mc_.nd_shortwaveradiation_in,
1093  vp,
1094  m_param->PT_ALPHA());
1095  }
1096  else if( m_cfg.potentialevapotranspiration_method == "penman")
1097  {
1098  ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
1099 
1100  day_potevapo = m_param->WCDNDC_INCREASE_POT_EVAPOTRANS()
1101  * ldndc::penman( surface,
1102  clk.yearday(),
1103  clk.days_in_year(),
1104  mc_.albedo,
1105  m_setup->latitude(),
1106  mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
1107  mc_.nd_airtemperature,
1108  mc_.nd_windspeed,
1109  vp);
1110  }
1111  }
1112  else
1113  {
1114  KLOGERROR("[BUG] huh :o how did you get here? ",
1115  "tell the maintainers refering to this error message");
1116  return LDNDC_ERR_FAIL;
1117  }
1118 
1119  if ( m_cfg.evapotranspiration_method == "uniform")
1120  {
1121  // hourly evaporation demand is calculated from daily demand equally throughout the day
1122  hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
1123  }
1124  else if ( m_cfg.evapotranspiration_method == "previouspattern")
1125  {
1126 
1127  hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
1128  }
1129  else //if ( m_cfg.evapotranspiration_method === "nice name") // could be for example 'daytime_only'
1130  {
1131  double const hour(lclock()->subday());
1132  double const day(lclock()->yearday());
1133  double const hsun(0.833 * cbm::PI / 180.0);
1134  double const lat(m_setup->latitude() * cbm::PI / 180.0);
1135  double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
1136  double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
1137  double dayl(0.0);
1138  if (help < -0.999) dayl = 0.0;
1139  else if (help > 0.999) dayl = 24.0;
1140  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)));
1141  if (dayl < 1.0) dayl = 0.0;
1142  double const rise(12.0 - dayl * 0.5);
1143 
1144  double factor(0.0);
1145  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);
1146 
1147  double fday(0.0);
1148  if (hour > rise && hour < (24.0 - rise)) fday = factor;
1149 
1150  hr_pot_evapotrans = day_potevapo * fday;
1151  }
1152  // the evaporation limit for all timesteps is the daily demand
1153  wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
1154 
1155  return LDNDC_ERR_OK;
1156 }
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:138
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
1800 {
1801  //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
1802  double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
1803 
1804  if ( cbm::flt_greater_zero( wc_.surface_ice) &&
1805  cbm::flt_greater_zero( hr_potESnow))
1806  {
1807  //If there is a snowpack and there is a potential to evaporate
1808  if ( wc_.surface_ice > hr_potESnow)
1809  {
1810  //Partial evaporation from the snow
1811  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
1812  wc_.accumulated_surfacewaterevaporation += hr_potESnow;
1813  wc_.surface_ice -= hr_potESnow;
1814  }
1815  else
1816  {
1817  //Total evaporation of the snowpack
1818  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
1819  wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
1820  wc_.surface_ice = 0.0;
1821  }
1822  }
1823 }

◆ CalcSoilEvapoPercolation()

void ldndc::WatercycleDNDC::CalcSoilEvapoPercolation ( )
private
Parameters
[in]None
[out]None
Returns
None
1938 {
1939  /* Reset water fluxes */
1940  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1941  {
1942  m_wc.percolation_sl[sl] = 0.0;
1943  }
1944 
1945  /* Fill groundwater layer with water */
1946  for ( int sl = m_soillayers->soil_layer_cnt()-1; sl >= 0; --sl)
1947  {
1948  if ( cbm::flt_greater_equal( sc_.depth_sl[sl], ground_water_table))
1949  {
1950  /* ensure that ice volume is less than porosity */
1951  double const ice_vol( wc_.ice_sl[sl] / cbm::DICE);
1952  if ( cbm::flt_greater( sc_.poro_sl[sl], ice_vol))
1953  {
1954  //air filled porosity is filled with groundwater
1955  double const gw_access( cbm::bound_min( 0.0,
1956  (sc_.poro_sl[sl] - ice_vol - wc_.wc_sl[sl]) * sc_.h_sl[sl]));
1957  wc_.wc_sl[sl] += gw_access / sc_.h_sl[sl];
1958  wc_.accumulated_groundwater_access += gw_access;
1959  }
1960  }
1961  else
1962  {
1963  break;
1964  }
1965  }
1966 
1967  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1968  {
1969  if ( sl == 0)
1970  {
1971  wc_.accumulated_infiltration += wc_.surface_water;
1972  wc_.wc_sl[0] += wc_.surface_water / sc_.h_sl[0];
1973  wc_.surface_water = 0.0;
1974  }
1975  else
1976  {
1977  wc_.wc_sl[sl] += m_wc.percolation_sl[sl-1] / sc_.h_sl[sl];
1978  }
1979 
1980  if ( cbm::flt_greater( sc_.depth_sl[sl], ground_water_table))
1981  {
1982  //set constant flux for all ground water layers depending on last non-groundwater layer
1983  if ( sl > 0)
1984  {
1985  m_wc.percolation_sl[sl] = m_wc.percolation_sl[sl-1];
1986  }
1987 
1988  //in case of groundwater until soil surface first outflux is estimated by saturated water flow
1989  else
1990  {
1991  m_wc.percolation_sl[sl] = WaterFlowSaturated( sl, get_impedance_factor( sl));
1992  }
1993  }
1994  else if ( sl + 1 == m_soillayers->soil_layer_cnt())
1995  {
1996  m_wc.percolation_sl[sl] = 0.0;
1997  if ( cbm::flt_greater_zero( wc_.sks_sl[sl]))
1998  {
1999  if ( cbm::flt_greater( wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2000  cbm::flt_greater( wc_.wc_sl[sl], sc_.wc_fc_sl[sl])) //security, should be always true if first condition is met
2001  {
2002  //maximum allowed flow until field capacity
2003  double const max_flow( (wc_.wc_sl[sl] - sc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2004  m_wc.percolation_sl[sl] = cbm::bound_max( WaterFlowSaturated( sl, get_impedance_factor( sl)),
2005  max_flow);
2006  }
2007 
2008  //water flux above field capacity
2009  else if ( cbm::flt_greater_equal( wc_.wc_sl[sl] + wc_.ice_sl[sl], sc_.wc_fc_sl[sl]))
2010  {
2011  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity( sl, get_impedance_factor( sl));
2012  }
2013 
2014  //water flux below field capacity and above wilting point
2015  else if ( cbm::flt_greater_zero( m_wc.percolation_sl[sl-1])
2016  && cbm::flt_greater( wc_.wc_sl[sl], sc_.wc_wp_sl[sl]))
2017  {
2018  m_wc.percolation_sl[sl] = m_param->FPERCOL() * m_wc.percolation_sl[sl-1];
2019  }
2020 
2021  //bound water flux by defined maximal percolation rate (e.g., during flooding events)
2022  m_wc.percolation_sl[sl] = cbm::bound_max( m_wc.percolation_sl[sl], max_percolation);
2023  }
2024  }
2025 
2026  //infiltrating water in current time step is exceeding available pore space of last time step
2027  //second condition: security, should be always true if first condition is met
2028  else if ( cbm::flt_greater( wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2029  cbm::flt_greater( wc_.wc_sl[sl], sc_.wc_fc_sl[sl]))
2030  {
2031  //maximum allowed flow until field capacity
2032  double const max_flow( (wc_.wc_sl[sl] - sc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2033  m_wc.percolation_sl[sl] = cbm::bound_max( WaterFlowSaturated( sl, get_impedance_factor( sl)),
2034  max_flow);
2035  }
2036  else if ( cbm::flt_greater_equal( wc_.wc_sl[sl] + wc_.ice_sl[sl], sc_.wc_fc_sl[sl]))
2037  {
2038  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity( sl, get_impedance_factor( sl));
2039  }
2040  else if ( cbm::flt_greater( wc_.wc_sl[sl], sc_.wc_wp_sl[sl]))
2041  {
2042  m_wc.percolation_sl[sl] = WaterFlowCapillaryRise( sl, get_impedance_factor( sl));
2043  }
2044  else
2045  {
2046  m_wc.percolation_sl[sl] = 0.0;
2047  }
2048 
2049 
2050  // water content must be greater or equal wilting point
2051  if ( cbm::flt_less( (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl] - m_wc.percolation_sl[sl],
2052  sc_.wc_wp_sl[sl] * sc_.h_sl[sl]) &&
2053  cbm::flt_greater_zero( m_wc.percolation_sl[sl]))
2054  {
2055  m_wc.percolation_sl[sl] = cbm::bound( 0.0,
2056  (wc_.wc_sl[sl] + wc_.ice_sl[sl] - sc_.wc_wp_sl[sl]) * sc_.h_sl[sl],
2057  m_wc.percolation_sl[sl]);
2058  }
2059 
2060  // Update of the current soil layer water content
2061  wc_.wc_sl[sl] -= m_wc.percolation_sl[sl] / sc_.h_sl[sl];
2062 
2063  SoilWaterEvaporation( sl);
2064  }
2065 
2066  /* Correct water content and percolation if water content is above porosity
2067  * If the layer below cannot take up all of the water assigned for percolation,
2068  * so if the air filled pore space is not sufficient,
2069  * the water remains in the upper layer.
2070  */
2071  for ( size_t sl = m_soillayers->soil_layer_cnt()-1; sl > 0; sl--)
2072  {
2073  double const ice_vol( wc_.ice_sl[sl] / cbm::DICE);
2074  if ( cbm::flt_greater( wc_.wc_sl[sl] + ice_vol,
2075  sc_.poro_sl[sl]))
2076  {
2077  double delta_wc( wc_.wc_sl[sl] + ice_vol - sc_.poro_sl[sl]);
2078  if ( cbm::flt_greater_equal( ice_vol, sc_.poro_sl[sl]))
2079  {
2080  delta_wc = wc_.wc_sl[sl];
2081  wc_.wc_sl[sl] = 0.0;
2082  }
2083  else
2084  {
2085  wc_.wc_sl[sl] = sc_.poro_sl[sl] - ice_vol;
2086  }
2087  m_wc.percolation_sl[sl-1] -= delta_wc * sc_.h_sl[sl];
2088  wc_.wc_sl[sl-1] += delta_wc * sc_.h_sl[sl] / sc_.h_sl[sl-1];
2089  }
2090  }
2091 
2092  double const ice_vol( wc_.ice_sl[0] / cbm::DICE);
2093  if ( cbm::flt_greater( wc_.wc_sl[0] + ice_vol,
2094  sc_.poro_sl[0]))
2095  {
2096 
2097  double delta_wc( wc_.wc_sl[0] + ice_vol - sc_.poro_sl[0]);
2098  if ( cbm::flt_greater_equal( ice_vol, sc_.poro_sl[0]))
2099  {
2100  delta_wc = wc_.wc_sl[0];
2101  wc_.wc_sl[0] = 0.0;
2102  }
2103  else
2104  {
2105  wc_.wc_sl[0] = sc_.poro_sl[0] - ice_vol;
2106  }
2107  wc_.accumulated_infiltration -= delta_wc * sc_.h_sl[0];
2108  wc_.surface_water += delta_wc * sc_.h_sl[0];
2109  }
2110 
2111 
2112  CalcSurfaceFlux();
2113 
2114  wc_.accumulated_waterflux_sl += m_wc.percolation_sl;
2115  wc_.accumulated_percolation += m_wc.percolation_sl[ m_soillayers->soil_layer_cnt()-1];
2116 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2208
double get_impedance_factor(size_t)
Reduces water fluxes out of a layer if ice lenses have formed.
Definition: watercycle-dndc.cpp:2284
void SoilWaterEvaporation(size_t)
Definition: watercycle-dndc.cpp:1865
double WaterFlowAboveFieldCapacity(size_t, double const &)
Definition: watercycle-dndc.cpp:2129
void CalcSurfaceFlux()
Definition: watercycle-dndc.cpp:2333
double WaterFlowCapillaryRise(size_t, double const &)
Similar to WaterFlowBelowFieldCapacity(...) but restricts water flow by water availability from soil ...
Definition: watercycle-dndc.cpp:2178

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2334 {
2335  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2336  {
2337  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2338  {
2339  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2340  wc_.surface_water = m_eventflood.get_bund_height();
2341  }
2342  }
2343  else
2344  {
2345  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2346  double const runoff_fraction( m_param->FRUNOFF() * get_time_step_duration());
2347 
2348  // if frunoff_ts < 1
2349  if ( cbm::flt_less( runoff_fraction, 1.0))
2350  {
2351  double const runoff( runoff_fraction * wc_.surface_water);
2352  wc_.surface_water -= runoff;
2353  wc_.accumulated_runoff += runoff;
2354  }
2355  else
2356  {
2357  wc_.accumulated_runoff += wc_.surface_water;
2358  wc_.surface_water = 0.0;
2359  }
2360  }
2361 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2408

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1769 {
1770  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1771  cbm::flt_greater_zero( hr_pot_evapotrans))
1772  {
1773  if ( hr_pot_evapotrans > wc_.surface_water)
1774  {
1775  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1776  hr_pot_evapotrans -= wc_.surface_water;
1777  wc_.surface_water = 0.0;
1778  }
1779  else
1780  {
1781  wc_.surface_water -= hr_pot_evapotrans;
1782  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1783  hr_pot_evapotrans = 0.0;
1784  }
1785  }
1786 }

◆ 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
1625 {
1626  // hourly potential transpiration
1627  double const hr_potTrans( hr_potTransinm * cbm::CM_IN_M);
1628  // hourly transpiration
1629  double hr_uptake( 0.0);
1630 
1631  // Calculate the root water uptake and hence the transpiration for every plant individually
1632  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1633  {
1634  // split up the potential transpiration equally to the various plants
1635  // frt mass of the current species
1636  double const mfrt_species( (*vt)->mFrt);
1637  // total frt mass
1638  double const mfrt_sum( m_veg->dw_frt());
1639  double const hr_potTransspecies = hr_potTrans * mfrt_species/mfrt_sum; // in cm
1640 
1641  // If some soil layers are frozen and contain only ice, no fluid water is present and the water potential diverges.
1642  // The uptake from these layers is prevented by considering only roots in layers with more water than ice.
1643  // In this case the root distribution needs to be rescaled (otherwise the non-contributing layers would effectively contribute a potential = 0).
1644  double fFrt_unfrozen( 1.0);
1645 
1646  /* TODO: include icetowatercrit as proper parameter */
1647  double icetowatercrit( 0.1);
1648  double effsoilwatpot( 0.0);
1649  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1650  {
1651  // fine root conditions to prevent transpiration without uptake organs, wateruptake from frozen ground
1652  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1653  {
1654  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1655  {
1656  // overall water potential in this layer
1657  double const watpotl( Soillayerwaterhead( sl)); // negative
1658  effsoilwatpot += watpotl * (*vt)->fFrt_sl[sl]; // negative
1659  }
1660  else
1661  {
1662  fFrt_unfrozen -= (*vt)->fFrt_sl[sl];
1663  }
1664  }
1665  else
1666  {
1667  // roots are not wireless ;-)
1668  break;
1669  }
1670  }
1671  // normalize the root distribution in the potential, if some soil is frozen
1672  effsoilwatpot = effsoilwatpot / fFrt_unfrozen;
1673 
1674  // hydraulic conductivities of plant system
1675  double const Krs(vt->KRSINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1676  double const Kcomp(vt->KCOMPINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1677 
1678  // water potential in the leafs, depending on the potential transpiration
1679  double const leafwatpot( cbm::bound_min(vt->HLEAFCRIT(), effsoilwatpot - (hr_potTransspecies / Krs))); // cm
1680 
1681  if( cbm::flt_greater_zero( leafwatpot))
1682  {
1683  KLOGERROR( "leafwatpot is positive");
1684  return LDNDC_ERR_FAIL;
1685  }
1686  if( !cbm::flt_greater_zero( effsoilwatpot - leafwatpot))
1687  {
1688  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.");
1689  return LDNDC_ERR_FAIL;
1690  }
1691 
1692  double const effuptake( Krs * (effsoilwatpot - leafwatpot)); // cm/timestep
1693  double uptake_tot( 0.0);
1694  double uptakecomp_tot( 0.0);
1695 // double uptakecompabs_tot( 0.0);
1696 
1697  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1698  {
1699  // fine root condition to prevent transpiration without uptake organs
1700  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1701  {
1702  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1703  {
1704  double const watpotl( Soillayerwaterhead( sl));
1705  double const compuptake( Kcomp * (watpotl - effsoilwatpot));
1706  double uptake_layer( (effuptake + compuptake) * (*vt)->fFrt_sl[sl]); // absolute value in cm
1707 
1708  wc_.accumulated_wateruptake_sl[sl] += uptake_layer * cbm::M_IN_CM;
1709  uptake_tot += uptake_layer; // absolute value in cm
1710  uptakecomp_tot += compuptake * (*vt)->fFrt_sl[sl]; // absolute value in cm
1711 // uptakecompabs_tot += fabs(compuptake * (*vt)->fFrt_sl[sl]); // absolute value in cm
1712 
1713  wc_.wc_sl[sl] -= uptake_layer * cbm::M_IN_CM /sc_.h_sl[sl]; // fraction of water in this layer, in m
1714 
1715  if( !cbm::flt_greater_zero( wc_.wc_sl[sl]))
1716  {
1717  KLOGERROR( "In soil layer ", sl, " the water content is negative: ", wc_.wc_sl[sl]);
1718  return LDNDC_ERR_FAIL;
1719  }
1720  }
1721  }
1722  else
1723  {
1724  // roots are not wireless ;-)
1725  break;
1726  }
1727  }
1728 
1729  hr_uptake += uptake_tot * cbm::M_IN_CM; // absolute value in m for all species
1730 
1731 
1732  if( cbm::flt_greater_zero( fabs(uptakecomp_tot))){
1733  KLOGWARN( "Compensatory water uptake ", uptakecomp_tot, " > 0.");
1734  }
1735  if( cbm::flt_greater( uptake_tot, hr_potTransspecies, 0.0000000001))
1736  {
1737  KLOGERROR( "Total water uptake ", uptake_tot, " larger than potential transpiration ", hr_potTransspecies);
1738  }
1739  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))
1740  {
1741  KLOGERROR( "T ", uptake_tot, "cm < Tpot ", hr_potTransspecies, "cm even though leafwatpot ", leafwatpot, " > HLEAFCRIT", vt->HLEAFCRIT());
1742  }
1743  }
1744 
1745  // total evaporation demand reduced to apply on other evaporating sources (ground, snow, surface water)
1746  hr_pot_evapotrans = cbm::bound_min(0.0, hr_pot_evapotrans - hr_uptake);
1747 
1748  return LDNDC_ERR_OK;
1749 }

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

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

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

◆ 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::get_clay_limitation(), and ldndc::rootdensityfortranspiration_sl().

1165 {
1166  if ( m_veg->size() > 0u)
1167  {
1168  return wc_.wc_fl.sum();
1169  }
1170  return 0.0;
1171 }
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
1867 {
1868  //percolation and direct evaporation from the (upper) soil
1869  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1870  double const wc_min_evaporation( m_param->WCDNDC_EVALIM_FRAC_WCMIN() * sc_.wc_wp_sl[_sl]);
1871  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_param->EVALIM()) &&
1872  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
1873  cbm::flt_greater_zero( hr_pot_evapotrans))
1874  {
1875  //limiting factor for soil water infiltration
1876  double const f_clay( 1.0 + m_param->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
1877  double const f_water( cbm::bound( 0.0,
1878  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / sc_.wc_fc_sl[_sl], f_clay),
1879  1.0));
1880  double const h_rest( std::min( sc_.h_sl[_sl], m_param->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
1881  double const f_depth( h_rest / m_param->EVALIM() * std::max(0.0,
1882  1.0 - std::min((double)m_param->EVALIM(),
1883  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
1884  / m_param->EVALIM()));
1885  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
1886 
1887  double const soilevaporation( cbm::bound( 0.0,
1888  hr_pot_evapotrans * f_depth * f_water,
1889  soilevaporation_max));
1890 
1891  //update of the current soil layer water content
1892  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
1893  wc_.accumulated_soilevaporation += soilevaporation;
1894  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
1895  }
1896 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2223 {
2224  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2225  if ( cbm::flt_greater_zero( m_param->BY_PASSF()) &&
2226  cbm::flt_greater_zero( wc_.surface_water))
2227  {
2228 
2229  double water_def_total( 0.0);
2230  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2231  {
2232  //water flux that flow through macro pores can maximally store
2233  water_def_total += cbm::bound_min( 0.0, (sc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]);
2234  }
2235 
2236  //duration of timestep (hr-1)
2237  double const fhr( get_time_step_duration());
2238 
2239 
2240  //fraction of surface water that is put into bypass flow (m timestep-1)
2241  double const bypass_fraction( cbm::bound_max( m_param->BY_PASSF() * fhr, 0.99));
2242  double const bypass_water( wc_.surface_water * bypass_fraction);
2243  wc_.surface_water -= bypass_water;
2244  wc_.accumulated_infiltration += bypass_water;
2245 
2246  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2247  {
2248 
2249  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2250  {
2251  double const water_def( cbm::bound_min( 0.0, (sc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2252  double const water_add( water_def / water_def_total * bypass_water);
2253 
2254  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2255  }
2256  }
2257  else
2258  {
2259  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2260  {
2261  double const water_def( cbm::bound_min( 0.0, (sc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2262  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2263  }
2264  /* add surplus to percolation out of last soil layer */
2265  wc_.accumulated_percolation += bypass_water - water_def_total;
2266  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2267  }
2268  }
2269 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2408

◆ 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

2132 {
2133  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2134  double const fsl( get_fsl( _sl));
2135  double const fhr( get_time_step_duration());
2136 
2138  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_param->SLOPE_FF() : m_param->SLOPE_MS());
2139 
2140  //max 0.005 means that no sks values up to 9.88 cm min-1 are allowed !!
2141  double const travelTime( std::max( 0.005, 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr)));
2142  return( cbm::bound_max( cbm::sqr(1.0 - (sc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2143  * 0.5 * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * (1.0 - exp(-1.0 / travelTime)) * _fact_impedance,
2144  sks));
2145 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2208
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2408
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2305

◆ WaterFlowSaturated()

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

Returns saturated water flow per time step accounting for impedance

2210 {
2211  double const sks( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * get_time_step_duration() * _fact_impedance);
2212  return sks;
2213 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2408

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day