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.
 
double get_clay_limitation (size_t, double, double)
 
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.

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

◆ 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( sc_.wcmin_sl[l] + m_cfg.automaticirrigation * (sc_.wcmax_sl[l] - sc_.wcmin_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 wcmax_sum( 0.0);
672  double wcmin_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  wcmax_sum += sc_.wcmax_sl[l] * sc_.h_sl[l];
677  wcmin_sum += sc_.wcmin_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( wcmin_sum + m_eventflood.get_saturation_level() * (wcmax_sum - wcmin_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], sc_.wcmax_sl[l]) &&
713  cbm::flt_equal_zero( wc_.ice_sl[l])) //only add water if no ice is present
714  {
715  water_supply += (sc_.wcmax_sl[l] - wc_.wc_sl[l]) * sc_.h_sl[l]; //amount of water added (m)
716  wc_.wc_sl[l] = sc_.wcmax_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  water_supply += (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl];
809  }
810  }
811 
812  //remove rainfall (less irrigation water is supplied if it if raining)
813  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.rainfall);
814 
815  /* Surface water will be actively drained */
816  if ( cbm::flt_greater( wc_.surface_water, water_supply))
817  {
818  wc_.accumulated_runoff += wc_.surface_water - water_supply;
819  wc_.surface_water = water_supply;
820  }
821 
822  if ( m_eventflood.have_unlimited_water())
823  {
824  wc_.accumulated_irrigation_automatic += water_supply;
825  }
826  else
827  {
828  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
829  {
830  wc_.irrigation_reservoir -= water_supply;
831  }
832  else
833  {
834  water_supply = wc_.irrigation_reservoir;
835  wc_.irrigation_reservoir = 0.0;
836  }
837  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
838  }
839  m_wc.irrigation += water_supply;
840  }
844  else if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
845  {
846  //adjust surface and soil water in case of flooding event
847  //water required to fill up surface water
848  double water_supply( m_eventflood.get_water_table() - wc_.surface_water);
849 
850  //add water required to fill top x layers up to saturation
851  unsigned long no_layers(3);
852  if( no_layers > m_soillayers->soil_layer_cnt())
853  {
854  no_layers = m_soillayers->soil_layer_cnt();
855  }
856 
857  for ( size_t sl = 0; sl < no_layers; ++sl)
858  {
859  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
860  }
861 
862  //remove rainfall (less irrigation water is supplied if it if raining)
863  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.rainfall);
864 
865  if ( m_eventflood.have_unlimited_water())
866  {
867  wc_.accumulated_irrigation_automatic += water_supply;
868  }
869  else
870  {
871  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
872  {
873  wc_.irrigation_reservoir -= water_supply;
874  }
875  else
876  {
877  water_supply = wc_.irrigation_reservoir;
878  wc_.irrigation_reservoir = 0.0;
879  }
880  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
881  }
882  m_wc.irrigation += water_supply;
883  }
884  }
885  }
886 
890  double const irrigation_scheduled( cbm::bound_min( 0.0, wc_.accumulated_irrigation - m_wc.accumulated_irrigation_event_executed));
891 
892  if ( cbm::flt_greater( irrigation_scheduled, 24.0 * rainfall_intensity()))
893  {
894  m_wc.irrigation += irrigation_scheduled / 24.0;
895  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled / 24.0;
896  }
897  else if ( cbm::flt_greater( irrigation_scheduled, (double)hours_per_time_step() * rainfall_intensity()))
898  {
899  m_wc.irrigation += (double)hours_per_time_step() * rainfall_intensity();
900  m_wc.accumulated_irrigation_event_executed += (double)hours_per_time_step() * rainfall_intensity();
901  }
902  else
903  {
904  m_wc.irrigation += irrigation_scheduled;
905  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled;
906  }
907 }
double rainfall_intensity()
Definition: watercycle-dndc.cpp:114

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

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

◆ CalcSoilEvapoPercolation()

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

◆ CalcSurfaceFlux()

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

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1776 {
1777  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1778  cbm::flt_greater_zero( hr_pot_evapotrans))
1779  {
1780  if ( hr_pot_evapotrans > wc_.surface_water)
1781  {
1782  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1783  hr_pot_evapotrans -= wc_.surface_water;
1784  wc_.surface_water = 0.0;
1785  }
1786  else
1787  {
1788  wc_.surface_water -= hr_pot_evapotrans;
1789  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1790  hr_pot_evapotrans = 0.0;
1791  }
1792  }
1793 }

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

◆ 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:2215
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2415

◆ get_clay_limitation()

double ldndc::WatercycleDNDC::get_clay_limitation ( size_t  _sl,
double  _water_avail,
double  _water_ref 
)
private
Parameters
[in]_slSoil layer
[in]_water_availAvailable water content
[in]_water_refReference water content
[out]None
Returns
Clay limitation
1314 {
1315  // layer specific water availability
1316  // organic fraction [%]
1317  double const orgf( sc_.fcorg_sl[_sl] / cbm::CCORG);
1318  // clay factor "1" [-]
1319  double const clay_f1( pow(10.0, (-sc_.clay_sl[_sl] - m_param->RCLAY())));
1320  // clay factor "2" [-]
1321  double const clay_f2( std::max(0.0, 1.0 + std::min(1.0 - orgf, sc_.clay_sl[_sl])));
1322 
1323  // fraction of max uptake that can be used according to soil conditions [%]
1324  return cbm::bound(0.0, clay_f1 + pow( _water_avail / _water_ref, clay_f2), 1.0);
1325 }

◆ 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
1163 {
1164  if ( m_veg->size() > 0u)
1165  {
1166  return wc_.wc_fl.sum();
1167  }
1168  return 0.0;
1169 }

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

115 {
116  if ( m_iokcomm->get_input_class< input_class_climate_t >())
117  {
118  return m_iokcomm->get_input_class< climate::input_class_climate_t >()->station_info()->rainfall_intensity * cbm::M_IN_MM;
119  }
120  else
121  {
122  return ldndc::climate::climate_info_defaults.rainfall_intensity * cbm::M_IN_MM;
123  }
124 }
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
1874 {
1875  //percolation and direct evaporation from the (upper) soil
1876  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1877  double const wc_min_evaporation( m_param->WCDNDC_EVALIM_FRAC_WCMIN() * sc_.wcmin_sl[_sl]);
1878  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_param->EVALIM()) &&
1879  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
1880  cbm::flt_greater_zero( hr_pot_evapotrans))
1881  {
1882  //limiting factor for soil water infiltration
1883  double const f_clay( 1.0 + m_param->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
1884  double const f_water( cbm::bound( 0.0,
1885  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / sc_.wcmax_sl[_sl], f_clay),
1886  1.0));
1887  double const h_rest( std::min( sc_.h_sl[_sl], m_param->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
1888  double const f_depth( h_rest / m_param->EVALIM() * std::max(0.0,
1889  1.0 - std::min((double)m_param->EVALIM(),
1890  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
1891  / m_param->EVALIM()));
1892  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
1893 
1894  double const soilevaporation( cbm::bound( 0.0,
1895  hr_pot_evapotrans * f_depth * f_water,
1896  soilevaporation_max));
1897 
1898  //update of the current soil layer water content
1899  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
1900  wc_.accumulated_soilevaporation += soilevaporation;
1901  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
1902  }
1903 }

◆ WatercycleDNDC_preferential_flow()

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

◆ 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

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

◆ WaterFlowSaturated()

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

Returns saturated water flow per time step accounting for impedance

2217 {
2218  double const sks( sc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * get_time_step_duration() * _fact_impedance);
2219  return sks;
2220 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2415

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day