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.

2442 {
2443  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water + plant_waterdeficit_compensation;
2444  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2445  {
2446  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2447  }
2448  balance += ( - m_wc.accumulated_irrigation_event_executed
2449  - wc_.accumulated_irrigation_automatic
2450  - wc_.accumulated_irrigation_ggcmi
2451  - wc_.accumulated_irrigation_reservoir_withdrawal
2452  - wc_.accumulated_precipitation
2453  - wc_.accumulated_groundwater_access
2454  + wc_.accumulated_percolation
2455  + wc_.accumulated_runoff
2456  + wc_.accumulated_wateruptake_sl.sum()
2457  + wc_.accumulated_interceptionevaporation
2458  + wc_.accumulated_soilevaporation
2459  + wc_.accumulated_surfacewaterevaporation);
2460 
2461  if ( _balance)
2462  {
2463  double const balance_delta( std::abs( *_balance - balance));
2464  if ( balance_delta > cbm::DIFFMAX)
2465  {
2466  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2467  }
2468  }
2469 
2470  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2471  {
2472  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2473  {
2474  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2475  wc_.wc_sl[sl] = 0.0;
2476  }
2477  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2478  {
2479  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2480  wc_.ice_sl[sl] = 0.0;
2481  }
2482  }
2483 
2484  return balance;
2485 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1163

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

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

◆ CalcSoilEvapoPercolation()

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

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2356 {
2357  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2358  {
2359  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2360  {
2361  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2362  wc_.surface_water = m_eventflood.get_bund_height();
2363  }
2364  }
2365  else
2366  {
2367  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2368  double const runoff_fraction( m_param->FRUNOFF() * get_time_step_duration());
2369 
2370  // if frunoff_ts < 1
2371  if ( cbm::flt_less( runoff_fraction, 1.0))
2372  {
2373  double const runoff( runoff_fraction * wc_.surface_water);
2374  wc_.surface_water -= runoff;
2375  wc_.accumulated_runoff += runoff;
2376  }
2377  else
2378  {
2379  wc_.accumulated_runoff += wc_.surface_water;
2380  wc_.surface_water = 0.0;
2381  }
2382  }
2383 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2430

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1791 {
1792  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1793  cbm::flt_greater_zero( hr_pot_evapotrans))
1794  {
1795  if ( hr_pot_evapotrans > wc_.surface_water)
1796  {
1797  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1798  hr_pot_evapotrans -= wc_.surface_water;
1799  wc_.surface_water = 0.0;
1800  }
1801  else
1802  {
1803  wc_.surface_water -= hr_pot_evapotrans;
1804  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1805  hr_pot_evapotrans = 0.0;
1806  }
1807  }
1808 }

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

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

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

1164 {
1165  if ( m_veg->size() > 0u)
1166  {
1167  return wc_.wc_fl.sum();
1168  }
1169  return 0.0;
1170 }
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
1889 {
1890  //percolation and direct evaporation from the (upper) soil
1891  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1892  double const wc_min_evaporation( m_param->WCDNDC_EVALIM_FRAC_WCMIN() * sc_.wc_wp_sl[_sl]);
1893  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_param->EVALIM()) &&
1894  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
1895  cbm::flt_greater_zero( hr_pot_evapotrans))
1896  {
1897  //limiting factor for soil water infiltration
1898  double const f_clay( 1.0 + m_param->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
1899  double const f_water( cbm::bound( 0.0,
1900  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / sc_.wc_fc_sl[_sl], f_clay),
1901  1.0));
1902  double const h_rest( std::min( sc_.h_sl[_sl], m_param->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
1903  double const f_depth( h_rest / m_param->EVALIM() * std::max(0.0,
1904  1.0 - std::min((double)m_param->EVALIM(),
1905  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
1906  / m_param->EVALIM()));
1907  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
1908 
1909  double const soilevaporation( cbm::bound( 0.0,
1910  hr_pot_evapotrans * f_depth * f_water,
1911  soilevaporation_max));
1912 
1913  //update of the current soil layer water content
1914  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
1915  wc_.accumulated_soilevaporation += soilevaporation;
1916  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
1917  }
1918 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2245 {
2246  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2247  if ( cbm::flt_greater_zero( m_param->BY_PASSF()) &&
2248  cbm::flt_greater_zero( wc_.surface_water))
2249  {
2250 
2251  double water_def_total( 0.0);
2252  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2253  {
2254  //water flux that flow through macro pores can maximally store
2255  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]);
2256  }
2257 
2258  //duration of timestep (hr-1)
2259  double const fhr( get_time_step_duration());
2260 
2261 
2262  //fraction of surface water that is put into bypass flow (m timestep-1)
2263  double const bypass_fraction( cbm::bound_max( m_param->BY_PASSF() * fhr, 0.99));
2264  double const bypass_water( wc_.surface_water * bypass_fraction);
2265  wc_.surface_water -= bypass_water;
2266  wc_.accumulated_infiltration += bypass_water;
2267 
2268  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2269  {
2270 
2271  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2272  {
2273  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]));
2274  double const water_add( water_def / water_def_total * bypass_water);
2275 
2276  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2277  }
2278  }
2279  else
2280  {
2281  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2282  {
2283  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]));
2284  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2285  }
2286  /* add surplus to percolation out of last soil layer */
2287  wc_.accumulated_percolation += bypass_water - water_def_total;
2288  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2289  }
2290  }
2291 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2430

◆ 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

2154 {
2155  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2156  double const fsl( get_fsl( _sl));
2157  double const fhr( get_time_step_duration());
2158 
2160  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_param->SLOPE_FF() : m_param->SLOPE_MS());
2161 
2162  //max 0.005 means that no sks values up to 9.88 cm min-1 are allowed !!
2163  double const travelTime( std::max( 0.005, 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr)));
2164  return( cbm::bound_max( cbm::sqr(1.0 - (sc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2165  * 0.5 * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * (1.0 - exp(-1.0 / travelTime)) * _fact_impedance,
2166  sks));
2167 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2230
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2430
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2327

◆ WaterFlowSaturated()

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

Returns saturated water flow per time step accounting for impedance

2232 {
2233  double const sks( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * get_time_step_duration() * _fact_impedance);
2234  return sks;
2235 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2430

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day