LandscapeDNDC  1.37.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 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.

2566 {
2567  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water;
2568  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2569  {
2570  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2571  }
2572  balance += ( - m_wc.accumulated_irrigation_event_executed
2573  - wc_.accumulated_irrigation_automatic
2574  - wc_.accumulated_irrigation_ggcmi
2575  - wc_.accumulated_irrigation_reservoir_withdrawal
2576  - wc_.accumulated_precipitation
2577  - wc_.accumulated_groundwater_access
2578  + wc_.accumulated_percolation
2579  + wc_.accumulated_runoff
2580  + wc_.accumulated_wateruptake_sl.sum()
2581  + wc_.accumulated_interceptionevaporation
2582  + wc_.accumulated_soilevaporation
2583  + wc_.accumulated_surfacewaterevaporation);
2584 
2585  if ( _balance)
2586  {
2587  double const balance_delta( std::abs( *_balance - balance));
2588  if ( balance_delta > cbm::DIFFMAX)
2589  {
2590  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2591  }
2592  }
2593 
2594  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2595  {
2596  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2597  {
2598  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2599  wc_.wc_sl[sl] = 0.0;
2600  }
2601  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2602  {
2603  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2604  wc_.ice_sl[sl] = 0.0;
2605  }
2606  }
2607 
2608  return balance;
2609 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1113

◆ 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

808 {
809  //reset irrigation
810  m_wc.irrigation = 0.0;
811 
815  if (cbm::flt_in_range_lu(0.0, m_cfg.automaticirrigation, 1.0))
816  {
817  if (m_veg->size() > 0) //check crop is present
818  {
819  if (cbm::flt_greater(mc_.nd_airtemperature,10.0)) // only add water if temperature > 10C)
820  {
821  for (size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
822  {
823  if (cbm::flt_greater_zero(m_veg->mfrt_sl(l))) //only count water need for soil layers that contain roots
824  {
825  // trigger irrigation events as soon as drought stress appears
826  double const wc_target(wc_.wc_wp_sl[l] + m_cfg.automaticirrigation * (wc_.wc_fc_sl[l] - wc_.wc_wp_sl[l]));
827  if (cbm::flt_less(wc_.wc_sl[l], wc_target) &&
828  cbm::flt_equal_zero(wc_.ice_sl[l])) //only add water if no ice is present
829  {
830  // irrigation assumed until target water content
831  double const irrigate_layer((wc_target - wc_.wc_sl[l]) * sc_.h_sl[l]);
832  m_wc.irrigation += irrigate_layer;
833  wc_.accumulated_irrigation_automatic += irrigate_layer;
834  }
835  }
836  }
837 
838  }
839  else
840  {
841  }
842 
843  }
844  }
845 
846  if ( cbm::flt_in_range_lu( 0.0, m_eventflood.get_saturation_level(), 1.0) &&
847  cbm::is_valid( m_eventflood.get_irrigation_height()) &&
848  cbm::is_valid( m_eventflood.get_soil_depth()))
849  {
850  double wc_sum( 0.0);
851  double wc_fc_sum( 0.0);
852  double wc_wp_sum( 0.0);
853  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
854  {
855  wc_sum += wc_.wc_sl[l] * sc_.h_sl[l];
856  wc_fc_sum += wc_.wc_fc_sl[l] * sc_.h_sl[l];
857  wc_wp_sum += wc_.wc_wp_sl[l] * sc_.h_sl[l];
858 
859  if ( cbm::flt_greater_equal( sc_.depth_sl[l], m_eventflood.get_soil_depth()))
860  {
861  break;
862  }
863  }
864 
865  // trigger irrigation events as soon as drought stress appears
866  double const wc_target( wc_wp_sum + m_eventflood.get_saturation_level() * (wc_fc_sum - wc_wp_sum));
867  if ( cbm::flt_less( wc_sum, wc_target))
868  {
869  m_wc.irrigation += m_eventflood.get_irrigation_height();
870  wc_.accumulated_irrigation_automatic += m_eventflood.get_irrigation_height();
871  }
872  }
873 
881  if ( m_cfg.ggcmi_irrigation)
882  {
883  if( (lclock()->subday() == 1) && (_i == 0))
884  {
885  if( m_veg->size() > 0 ) //check crop is present
886  {
887  double water_supply( 0.0);
888  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
889  {
890  if ( cbm::flt_greater_zero( m_veg->mfrt_sl( l))) //only irrigate soil layers that contain roots
891  {
892  if( cbm::flt_less( wc_.wc_sl[l], wc_.wc_fc_sl[l]) &&
893  cbm::flt_equal_zero( wc_.ice_sl[l])) //only add water if no ice is present
894  {
895  water_supply += (wc_.wc_fc_sl[l] - wc_.wc_sl[l]) * sc_.h_sl[l]; //amount of water added (m)
896  wc_.wc_sl[l] = wc_.wc_fc_sl[l];
897  }
898  }
899  }
900  wc_.accumulated_irrigation_ggcmi += water_supply;
901  }
902  }
903  }
904 
908  if ( cbm::is_valid( m_eventflood.get_water_table()))
909  {
910  /* Dynamic flooding */
911  if ( cbm::is_valid( m_eventflood.get_irrigation_height()))
912  {
913  bool irrigate( false);
914 
915  /* Irrigate after surface water table drop */
916  if ( cbm::flt_greater_equal_zero( m_eventflood.get_water_table()))
917  {
918  if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
919  {
920  irrigate = true;
921  }
922  }
923  else
924  {
925  if ( !cbm::flt_greater_zero( wc_.surface_water))
926  {
927  double water_tot_sum( 0.0);
928  double water_fc_sum( 0.0);
929  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
930  {
931  water_tot_sum += wc_.wc_sl[sl] * sc_.h_sl[sl];
932  water_fc_sum += wc_.wc_fc_sl[sl] * sc_.h_sl[sl];
933  if ( cbm::flt_greater_equal( sc_.depth_sl[sl], -m_eventflood.get_water_table()))
934  {
935  break;
936  }
937  }
938  // Note: The tipping bucket approach may block percolation into deeper soil layers
939  // if the upper layers have higher water content. This can lead to water reduction
940  // from evapotranspiration in deeper layers without replenishment from above.
941  // Workaround: AWD is triggered when the integrated topsoil water drops below
942  // 90% of the integrated topsoil field capacity.
943  if ( cbm::flt_less( water_tot_sum, 0.9 * water_fc_sum))
944  {
945  irrigate = true;
946  }
947  }
948  }
949  // trigger AWD irrigation event
950  if ( irrigate)
951  {
952  double water_supply( cbm::bound_min( 0.0, m_eventflood.get_irrigation_height() - wc_.surface_water));
953  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
954  {
955  // set soil fully water saturated
956  if ( cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
957  {
958  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
959  }
960  }
961 
962  //remove rainfall (less irrigation water is supplied if it if raining)
963  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
964 
965  if ( m_eventflood.have_unlimited_water())
966  {
967  wc_.accumulated_irrigation_automatic += water_supply;
968  }
969  else
970  {
971  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
972  {
973  wc_.irrigation_reservoir -= water_supply;
974  }
975  else
976  {
977  water_supply = wc_.irrigation_reservoir;
978  wc_.irrigation_reservoir = 0.0;
979  }
980  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
981  }
982  m_wc.irrigation += water_supply;
983  }
984  }
985  /* Static flooding */
986  else
987  {
988  if ( !cbm::flt_greater_zero( m_eventflood.get_water_table()))
989  {
990  double water_supply( 0.0);
991  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
992  {
993  if ( cbm::flt_greater( sc_.depth_sl[sl], -m_eventflood.get_water_table()) &&
994  cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
995  {
996  double const scale( cbm::flt_less( sc_.depth_sl[sl] - sc_.h_sl[sl], -m_eventflood.get_water_table()) ?
997  (-m_eventflood.get_water_table() - (sc_.depth_sl[sl] - sc_.h_sl[sl])) / sc_.h_sl[sl] :
998  1.0);
999 
1000  water_supply += scale * (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl];
1001  }
1002  }
1003 
1004  //remove rainfall (less irrigation water is supplied if it is raining)
1005  water_supply = cbm::bound( 0.0, water_supply - m_mc.precipitation, wc_.sks_sl[0]);
1006 
1007  /* Surface water will be actively drained */
1008  if ( cbm::flt_greater_equal( wc_.surface_water, water_supply))
1009  {
1010  wc_.accumulated_runoff += wc_.surface_water - water_supply;
1011  wc_.surface_water = water_supply;
1012  water_supply = 0.0;
1013  }
1014  else if ( cbm::flt_greater_zero( wc_.surface_water))
1015  {
1016  water_supply -= wc_.surface_water;
1017  }
1018 
1019  if ( m_eventflood.have_unlimited_water())
1020  {
1021  wc_.accumulated_irrigation_automatic += water_supply;
1022  }
1023  else
1024  {
1025  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1026  {
1027  wc_.irrigation_reservoir -= water_supply;
1028  }
1029  else
1030  {
1031  water_supply = wc_.irrigation_reservoir;
1032  wc_.irrigation_reservoir = 0.0;
1033  }
1034  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1035  }
1036 
1037  m_wc.irrigation += water_supply;
1038  }
1042  else if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
1043  {
1044  //adjust surface and soil water in case of flooding event
1045  //water required to fill up surface water
1046  double water_supply( m_eventflood.get_water_table() - wc_.surface_water);
1047 
1048  //add water required to fill top x layers up to saturation
1049  unsigned long no_layers(3);
1050  if( no_layers > m_soillayers->soil_layer_cnt())
1051  {
1052  no_layers = m_soillayers->soil_layer_cnt();
1053  }
1054 
1055  for ( size_t sl = 0; sl < no_layers; ++sl)
1056  {
1057  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
1058  }
1059 
1060  //remove rainfall (less irrigation water is supplied if it if raining)
1061  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
1062 
1063  if ( m_eventflood.have_unlimited_water())
1064  {
1065  wc_.accumulated_irrigation_automatic += water_supply;
1066  }
1067  else
1068  {
1069  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1070  {
1071  wc_.irrigation_reservoir -= water_supply;
1072  }
1073  else
1074  {
1075  water_supply = wc_.irrigation_reservoir;
1076  wc_.irrigation_reservoir = 0.0;
1077  }
1078  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1079  }
1080  m_wc.irrigation += water_supply;
1081  }
1082  }
1083  }
1084 
1088  double const irrigation_scheduled( cbm::bound_min( 0.0, wc_.accumulated_irrigation - m_wc.accumulated_irrigation_event_executed));
1089 
1090  if ( cbm::flt_greater( irrigation_scheduled, 24.0 * rainfall_intensity()))
1091  {
1092  m_wc.irrigation += irrigation_scheduled / 24.0;
1093  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled / 24.0;
1094  }
1095  else if ( cbm::flt_greater( irrigation_scheduled, (double)hours_per_time_step() * rainfall_intensity()))
1096  {
1097  m_wc.irrigation += (double)hours_per_time_step() * rainfall_intensity();
1098  m_wc.accumulated_irrigation_event_executed += (double)hours_per_time_step() * rainfall_intensity();
1099  }
1100  else
1101  {
1102  m_wc.irrigation += irrigation_scheduled;
1103  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled;
1104  }
1105 }
double rainfall_intensity()
Definition: watercycle-dndc.cpp:116

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

550 {
551  day_potevapo = 0.0;
552  if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
553  {
554  if ( lclock()->is_position( TMODE_PRE_YEARLY))
555  {
557  lclock()->days_in_year(),
558  m_climate->annual_temperature_average(),
559  m_climate->annual_temperature_amplitude());
560  }
561 
562  double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
563  double const avg_dayl(12.0);
564 
565  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
567  mc_.nd_airtemperature,
568  daylength, avg_dayl, lclock()->days_in_month(),
570  }
571  else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
572  (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
573  {
574  cbm::sclock_t const & clk( lclock_ref());
575 
576  /* vapour pressure [10^3:Pa] */
577  double vps( 0.0);
578  ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
579  double vp( vps - m_climate->vpd_day( clk));
580 
581  if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
582  {
583  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
584  * ldndc::priestleytaylor( clk.yearday(),
585  clk.days_in_year(),
586  mc_.albedo,
587  m_setup->latitude(),
588  mc_.nd_airtemperature,
589  mc_.nd_shortwaveradiation_in,
590  vp,
591  m_sipar->PT_ALPHA());
592  }
593  else if( m_cfg.potentialevapotranspiration_method == "penman")
594  {
595  /* leaf area index */
596  double const lai( m_veg->lai());
597  ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
598 
599  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
600  * ldndc::penman( surface,
601  clk.yearday(),
602  clk.days_in_year(),
603  mc_.albedo,
604  m_setup->latitude(),
605  mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
606  mc_.nd_airtemperature,
607  mc_.nd_windspeed,
608  vp);
609  }
610  }
611  else
612  {
613  KLOGERROR("[BUG] huh :o how did you get here? ",
614  "tell the maintainers refering to this error message");
615  return LDNDC_ERR_FAIL;
616  }
617 
618  if ( m_cfg.evapotranspiration_method == "uniform")
619  {
620  // hourly evaporation demand is calculated from daily demand equally throughout the day
621  hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
622  }
623  else if ( m_cfg.evapotranspiration_method == "previouspattern")
624  {
625 
626  hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
627  }
628  else
629  {
630  double const hour(lclock()->subday());
631  double const day(lclock()->yearday());
632  double const hsun(0.833 * cbm::PI / 180.0);
633  double const lat(m_setup->latitude() * cbm::PI / 180.0);
634  double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
635  double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
636  double dayl(0.0);
637  if (help < -0.999) dayl = 0.0;
638  else if (help > 0.999) dayl = 24.0;
639  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)));
640  if (dayl < 1.0) dayl = 0.0;
641  double const rise(12.0 - dayl * 0.5);
642 
643  double factor(0.0);
644  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);
645 
646  double fday(0.0);
647  if (hour > rise && hour < (24.0 - rise)) fday = factor;
648 
649  hr_pot_evapotrans = day_potevapo * fday;
650  }
651 
652  // the evaporation limit for all timesteps is the daily demand
653  wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
654 
655  return LDNDC_ERR_OK;
656 }
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:134
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
1929 {
1930  //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
1931  double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
1932 
1933  if ( cbm::flt_greater_zero( wc_.surface_ice) &&
1934  cbm::flt_greater_zero( hr_potESnow))
1935  {
1936  //If there is a snowpack and there is a potential to evaporate
1937  if ( wc_.surface_ice > hr_potESnow)
1938  {
1939  //Partial evaporation from the snow
1940  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
1941  wc_.accumulated_surfacewaterevaporation += hr_potESnow;
1942  wc_.surface_ice -= hr_potESnow;
1943  }
1944  else
1945  {
1946  //Total evaporation of the snowpack
1947  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
1948  wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
1949  wc_.surface_ice = 0.0;
1950  }
1951  }
1952 }

◆ CalcSoilEvapoPercolation()

void ldndc::WatercycleDNDC::CalcSoilEvapoPercolation ( )
private
Parameters
[in]None
[out]None
Returns
None
2066 {
2067  // reset all water fluxes
2068  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2069  {
2070  m_wc.percolation_sl[sl] = 0.0;
2071  }
2072 
2073  // fill groundwater layer with water
2074  for (int sl = m_soillayers->soil_layer_cnt() - 1; sl >= 0; --sl)
2075  {
2076  if (cbm::flt_greater_equal(sc_.depth_sl[sl], ground_water_table))
2077  {
2078  // ice volume is excepted from groundwater
2079  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2080  if (cbm::flt_greater(sc_.poro_sl[sl], ice_vol))
2081  {
2082  // new water in the layer is generated from groundwater
2083  double const gw_access(cbm::bound_min(0.0, (sc_.poro_sl[sl] - ice_vol - wc_.wc_sl[sl]) * sc_.h_sl[sl] ));
2084  wc_.wc_sl[sl] += gw_access / sc_.h_sl[sl];
2085  wc_.accumulated_groundwater_access += gw_access;
2086  }
2087  }
2088  else
2089  {
2090  break;
2091  }
2092  }
2093 
2094  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2095  {
2096  // the first soil (litter) layer is filled with surface water up to its capacity
2097  if (sl == 0)
2098  {
2099  double delta_wc(0.0);
2100  double const wc_old(wc_.wc_sl[sl]);
2101  double const wc_cap( (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]); // uptake capacity in first soil layer [mm]
2102 
2103  if (cbm::flt_greater(wc_.surface_water, wc_cap))
2104  {
2105  wc_.wc_sl[sl] = sc_.poro_sl[sl];
2106  delta_wc = cbm::bound_max(wc_.surface_water, (cbm::bound_min(0.0, wc_.wc_sl[sl] - wc_old) * sc_.h_sl[sl]));
2107  wc_.surface_water -= delta_wc;
2108  }
2109  else
2110  {
2111  wc_.wc_sl[sl] = (wc_.wc_sl[sl] * sc_.h_sl[sl] + wc_.surface_water) / sc_.h_sl[sl];
2112  delta_wc = cbm::bound_max(wc_.surface_water, (cbm::bound_min(0.0, wc_.wc_sl[sl] - wc_old) * sc_.h_sl[sl]));
2113  wc_.surface_water = 0.0;
2114  }
2115 
2116  wc_.accumulated_infiltration += delta_wc;
2117  }
2118  // other soil layers get updated by percolation rates from the layer above
2119  else
2120  {
2121  wc_.wc_sl[sl] += m_wc.percolation_sl[sl - 1] / sc_.h_sl[sl];
2122  }
2123 
2124  // percolation for all layers below groundwater
2125  if (cbm::flt_greater(sc_.depth_sl[sl], ground_water_table))
2126  {
2127 
2128  // in case groundwater reaches the soil surface, the first outflux is estimated by saturated water flow
2129  if (sl == 0)
2130  {
2131  m_wc.percolation_sl[sl] = WaterFlowSaturated(sl, get_impedance_factor(sl));
2132  }
2133  // other soil layers are assumed to percolate by the same rate as the last non-groundwater layer
2134  else
2135  {
2136  m_wc.percolation_sl[sl] = m_wc.percolation_sl[sl - 1];
2137  }
2138 
2139  }
2140  // in all other cases percolation
2141  else if (sl + 1 == m_soillayers->soil_layer_cnt())
2142  {
2143  m_wc.percolation_sl[sl] = 0.0;
2144  if (cbm::flt_greater_zero(wc_.sks_sl[sl]))
2145  {
2146  if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2147  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl])) //security, should be always true if first condition is met
2148  {
2149  //maximum allowed flow until field capacity
2150  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2151  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)), max_flow);
2152  }
2153 
2154  //water flux above field capacity
2155  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2156  {
2157  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2158  }
2159 
2160  //water flux below field capacity and above wilting point
2161  else if (cbm::flt_greater_zero(m_wc.percolation_sl[sl - 1]) &&
2162  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2163  {
2164  m_wc.percolation_sl[sl] = m_sipar->FPERCOL() * m_wc.percolation_sl[sl - 1];
2165  }
2166 
2167  //bound water flux by defined maximal percolation rate (e.g., during flooding events)
2168  m_wc.percolation_sl[sl] = cbm::bound_max(m_wc.percolation_sl[sl], max_percolation);
2169  }
2170  }
2171 
2172  //infiltrating water in current time step is exceeding available pore space of last time step
2173  //second condition: security, should be always true if first condition is met
2174  else if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2175  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl]))
2176  {
2177  //maximum allowed flow until field capacity
2178  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2179  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)),
2180  max_flow);
2181  }
2182  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2183  {
2184  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2185  }
2186  else if (cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2187  {
2188  m_wc.percolation_sl[sl] = WaterFlowCapillaryRise(sl, get_impedance_factor(sl));
2189  }
2190  else
2191  {
2192  m_wc.percolation_sl[sl] = 0.0;
2193  }
2194 
2195 
2196  // water content must be greater or equal wilting point
2197  if (cbm::flt_less((wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl] - m_wc.percolation_sl[sl], wc_.wc_wp_sl[sl] * sc_.h_sl[sl]) &&
2198  cbm::flt_greater_zero(m_wc.percolation_sl[sl]))
2199  {
2200  m_wc.percolation_sl[sl] = cbm::bound(0.0,
2201  (wc_.wc_sl[sl] + wc_.ice_sl[sl] - wc_.wc_wp_sl[sl]) * sc_.h_sl[sl],
2202  m_wc.percolation_sl[sl]);
2203  }
2204 
2205  // Update of the current soil layer water content
2206  wc_.wc_sl[sl] -= m_wc.percolation_sl[sl] / sc_.h_sl[sl];
2207 
2209  }
2210 
2211  /* Correct water content and percolation if water content is above porosity
2212  * If the layer below cannot take up all of the water assigned for percolation,
2213  * so if the air filled pore space is not sufficient,
2214  * the water remains in the upper layer.
2215  */
2216  for (size_t sl = m_soillayers->soil_layer_cnt() - 1; sl > 0; sl--)
2217  {
2218  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2219  if (cbm::flt_greater(wc_.wc_sl[sl] + ice_vol, sc_.poro_sl[sl]))
2220  {
2221  double delta_wc(wc_.wc_sl[sl] + ice_vol - sc_.poro_sl[sl]);
2222  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[sl]))
2223  {
2224  delta_wc = wc_.wc_sl[sl];
2225  wc_.wc_sl[sl] = 0.0;
2226  }
2227  else
2228  {
2229  wc_.wc_sl[sl] = sc_.poro_sl[sl] - ice_vol;
2230  }
2231  m_wc.percolation_sl[sl - 1] -= delta_wc * sc_.h_sl[sl];
2232  wc_.wc_sl[sl - 1] += delta_wc * sc_.h_sl[sl] / sc_.h_sl[sl - 1];
2233  }
2234  }
2235 
2236  double const ice_vol(wc_.ice_sl[0] / cbm::DICE);
2237  if (cbm::flt_greater(wc_.wc_sl[0] + ice_vol, sc_.poro_sl[0]))
2238  {
2239 
2240  double delta_wc(wc_.wc_sl[0] + ice_vol - sc_.poro_sl[0]);
2241  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[0]))
2242  {
2243  delta_wc = wc_.wc_sl[0];
2244  wc_.wc_sl[0] = 0.0;
2245  }
2246  else
2247  {
2248  wc_.wc_sl[0] = sc_.poro_sl[0] - ice_vol;
2249  }
2250  wc_.accumulated_infiltration -= delta_wc * sc_.h_sl[0];
2251  wc_.surface_water += delta_wc * sc_.h_sl[0];
2252  }
2253 
2254  if (cbm::flt_greater_zero(wc_.surface_water))
2255  {
2256  CalcSurfaceFlux();
2257  }
2258 
2259  wc_.accumulated_waterflux_sl += m_wc.percolation_sl;
2260  wc_.accumulated_percolation += m_wc.percolation_sl[ m_soillayers->soil_layer_cnt()-1];
2261 }
double get_impedance_factor(size_t)
Reduces water fluxes out of a layer if ice lenses have formed.
Definition: watercycle-dndc.cpp:2429
void SoilWaterEvaporation(size_t)
Definition: watercycle-dndc.cpp:1994
double WaterFlowAboveFieldCapacity(size_t, double const &)
Definition: watercycle-dndc.cpp:2274
void CalcSurfaceFlux()
Definition: watercycle-dndc.cpp:2478
double WaterFlowCapillaryRise(size_t, double const &)
Similar to WaterFlowBelowFieldCapacity(...) but restricts water flow by water availability from soil ...
Definition: watercycle-dndc.cpp:2323

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2479 {
2480  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2481  {
2482  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2483  {
2484  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2485  wc_.surface_water = m_eventflood.get_bund_height();
2486  }
2487  }
2488  else
2489  {
2490  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2491  double const runoff_fraction(m_sipar->FRUNOFF() * get_time_step_duration());
2492 
2493  // - not all surface water is removed within one timestep
2494  if ( cbm::flt_less( runoff_fraction, 1.0))
2495  {
2496  double const runoff( runoff_fraction * wc_.surface_water);
2497  wc_.surface_water -= runoff;
2498  wc_.accumulated_runoff += runoff;
2499  }
2500  // - all surface water is immediatly removed
2501  else
2502  {
2503  wc_.accumulated_runoff += wc_.surface_water;
2504  wc_.surface_water = 0.0;
2505  }
2506  }
2507 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2554

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1898 {
1899  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1900  cbm::flt_greater_zero( hr_pot_evapotrans))
1901  {
1902  if ( hr_pot_evapotrans > wc_.surface_water)
1903  {
1904  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1905  hr_pot_evapotrans -= wc_.surface_water;
1906  wc_.surface_water = 0.0;
1907  }
1908  else
1909  {
1910  wc_.surface_water -= hr_pot_evapotrans;
1911  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1912  hr_pot_evapotrans = 0.0;
1913  }
1914  }
1915 }

◆ 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
1753 {
1754  // hourly potential transpiration
1755  double const hr_potTrans( hr_potTransinm * cbm::CM_IN_M);
1756 
1757  // hourly water uptake
1758  double hr_uptake( 0.0);
1759 
1760  // Calculate the root water uptake and hence the transpiration for every plant individually
1761  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1762  {
1763  // split up the potential transpiration equally to the various plants
1764  // frt mass of the current species
1765  double const mfrt_species( (*vt)->mFrt);
1766  // total frt mass
1767  double const mfrt_sum( m_veg->dw_frt());
1768  double const hr_potTransspecies = hr_potTrans * mfrt_species/mfrt_sum; // in cm
1769 
1770  // If some soil layers are frozen and contain only ice, no fluid water is present and the water potential diverges.
1771  // The uptake from these layers is prevented by considering only roots in layers with more water than ice.
1772  // In this case the root distribution needs to be rescaled (otherwise the non-contributing layers would effectively contribute a potential = 0).
1773  double fFrt_unfrozen( 1.0);
1774 
1775  /* TODO: include icetowatercrit as proper parameter */
1776  double icetowatercrit( 0.1);
1777  double effsoilwatpot( 0.0);
1778  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1779  {
1780  // fine root conditions to prevent transpiration without uptake organs, wateruptake from frozen ground
1781  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1782  {
1783  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1784  {
1785  // overall water potential in this layer
1786  double const watpotl( Soillayerwaterhead( sl)); // negative
1787  effsoilwatpot += watpotl * (*vt)->fFrt_sl[sl]; // negative
1788  }
1789  else
1790  {
1791  fFrt_unfrozen -= (*vt)->fFrt_sl[sl];
1792  }
1793  }
1794  else
1795  {
1796  // roots are not wireless ;-)
1797  break;
1798  }
1799  }
1800  // normalize the root distribution in the potential, if some soil is frozen
1801  effsoilwatpot = effsoilwatpot / fFrt_unfrozen;
1802 
1803  // hydraulic conductivities of plant system
1804  double const Krs(vt->KRSINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1805  double const Kcomp(vt->KCOMPINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1806 
1807  // water potential in the leafs, depending on the potential transpiration
1808  double const leafwatpot( cbm::bound_min(vt->HLEAFCRIT(), effsoilwatpot - (hr_potTransspecies / Krs))); // cm
1809 
1810  if( cbm::flt_greater_zero( leafwatpot))
1811  {
1812  KLOGERROR( "leafwatpot is positive");
1813  return LDNDC_ERR_FAIL;
1814  }
1815  if( !cbm::flt_greater_zero( effsoilwatpot - leafwatpot))
1816  {
1817  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.");
1818  return LDNDC_ERR_FAIL;
1819  }
1820 
1821  double const effuptake( Krs * (effsoilwatpot - leafwatpot)); // cm/timestep
1822  double uptake_tot( 0.0);
1823  double uptakecomp_tot( 0.0);
1824 // double uptakecompabs_tot( 0.0);
1825 
1826  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1827  {
1828  // fine root condition to prevent transpiration without uptake organs
1829  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1830  {
1831  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1832  {
1833  double const watpotl( Soillayerwaterhead( sl));
1834  double const compuptake( Kcomp * (watpotl - effsoilwatpot));
1835  double uptake_layer( (effuptake + compuptake) * (*vt)->fFrt_sl[sl]); // absolute value in cm
1836 
1837  wc_.accumulated_wateruptake_sl[sl] += uptake_layer * cbm::M_IN_CM;
1838  uptake_tot += uptake_layer; // absolute value in cm
1839  uptakecomp_tot += compuptake * (*vt)->fFrt_sl[sl]; // absolute value in cm
1840 // uptakecompabs_tot += fabs(compuptake * (*vt)->fFrt_sl[sl]); // absolute value in cm
1841 
1842  wc_.wc_sl[sl] -= uptake_layer * cbm::M_IN_CM /sc_.h_sl[sl]; // fraction of water in this layer, in m
1843 
1844  if( !cbm::flt_greater_zero( wc_.wc_sl[sl]))
1845  {
1846  KLOGERROR( "In soil layer ", sl, " the water content is negative: ", wc_.wc_sl[sl]);
1847  return LDNDC_ERR_FAIL;
1848  }
1849  }
1850  }
1851  else
1852  {
1853  // roots are not wireless ;-)
1854  break;
1855  }
1856  }
1857 
1858  hr_uptake += uptake_tot * cbm::M_IN_CM; // absolute value in m for all species
1859 
1860 
1861  if( cbm::flt_greater_zero( fabs(uptakecomp_tot))){
1862  KLOGWARN( "Compensatory water uptake ", uptakecomp_tot, " > 0.");
1863  }
1864  if( cbm::flt_greater( uptake_tot, hr_potTransspecies, 0.0000000001))
1865  {
1866  KLOGERROR( "Total water uptake ", uptake_tot, " larger than potential transpiration ", hr_potTransspecies);
1867  }
1868  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))
1869  {
1870  KLOGERROR( "T ", uptake_tot, "cm < Tpot ", hr_potTransspecies, "cm even though leafwatpot ", leafwatpot, " > HLEAFCRIT", vt->HLEAFCRIT());
1871  }
1872  }
1873 
1874  // total evaporation demand reduced to apply on other evaporating sources (ground, snow, surface water)
1875  hr_pot_evapotrans = cbm::bound_min(0.0, hr_pot_evapotrans - hr_uptake);
1876 
1877  return LDNDC_ERR_OK;
1878 }

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

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

  • surface water table
  • bund height
778 {
779  lerr_t rc = m_eventflood.solve();
780  if ( rc != LDNDC_ERR_OK)
781  {
782  KLOGERROR("Irrigation event not successful!");
783  return rc;
784  }
785 
786  /* max_percolation is gradually decreased after end of flooding event to inital value */
787  double const maximum_percolation = m_eventflood.get_maximum_percolation();
788  if ( cbm::is_valid( maximum_percolation))
789  {
790  if ( cbm::flt_greater_zero( maximum_percolation))
791  {
792  max_percolation = maximum_percolation * nhr / 24.0;
793  }
794  }
795  else
796  {
797  /* time rate for gradual recovery of max_percolation */
798  double const time_rate( get_time_step_duration() * 0.1);
799  max_percolation -= (max_percolation - WaterFlowSaturated( m_soillayers->soil_layer_cnt()-1, 1.0)) * time_rate;
800  }
801 
802  return LDNDC_ERR_OK;
803 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2554

◆ 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
1114 {
1115  if ( m_veg->size() > 0u)
1116  {
1117  return wc_.wc_fl.sum();
1118  }
1119  return 0.0;
1120 }

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

117 {
118  if ( m_iokcomm->get_input_class< input_class_climate_t >())
119  {
120  return m_iokcomm->get_input_class< climate::input_class_climate_t >()->station_info()->rainfall_intensity * cbm::M_IN_MM;
121  }
122  else
123  {
124  return ldndc::climate::climate_info_defaults.rainfall_intensity * cbm::M_IN_MM;
125  }
126 }
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
1996 {
1997  //percolation and direct evaporation from the (upper) soil
1998  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1999  double const wc_min_evaporation(m_sipar->WCDNDC_EVALIM_FRAC_WCMIN() * wc_.wc_wp_sl[_sl]);
2000  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_sipar->EVALIM()) &&
2001  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
2002  cbm::flt_greater_zero( hr_pot_evapotrans))
2003  {
2004  //limiting factor for soil water infiltration
2005  double const f_clay( 1.0 + m_sipar->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
2006  double const f_water( cbm::bound( 0.0,
2007  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / wc_.wc_fc_sl[_sl], f_clay),
2008  1.0));
2009  double const h_rest( std::min( sc_.h_sl[_sl], m_sipar->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
2010  double const f_depth( h_rest / m_sipar->EVALIM() * std::max(0.0,
2011  1.0 - std::min((double)m_sipar->EVALIM(),
2012  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
2013  / m_sipar->EVALIM()));
2014  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
2015 
2016  double const soilevaporation( cbm::bound( 0.0,
2017  hr_pot_evapotrans * f_depth * f_water,
2018  soilevaporation_max));
2019 
2020  //update of the current soil layer water content
2021  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
2022  wc_.accumulated_soilevaporation += soilevaporation;
2023  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
2024  }
2025 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2368 {
2369  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2370  if ( cbm::flt_greater_zero(m_sipar->BY_PASSF()) &&
2371  cbm::flt_greater_zero( wc_.surface_water))
2372  {
2373 
2374  double water_def_total( 0.0);
2375  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2376  {
2377  //water flux that flow through macro pores can maximally store
2378  water_def_total += cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]);
2379  }
2380 
2381  //duration of timestep (hr-1)
2382  double const fhr( get_time_step_duration());
2383 
2384 
2385  //fraction of surface water that is put into bypass flow (m timestep-1)
2386  double const bypass_fraction( cbm::bound_max(m_sipar->BY_PASSF() * fhr, 0.99));
2387  double const bypass_water( wc_.surface_water * bypass_fraction);
2388  wc_.surface_water -= bypass_water;
2389  wc_.accumulated_infiltration += bypass_water;
2390 
2391  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2392  {
2393 
2394  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2395  {
2396  double const water_def( cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2397  double const water_add( water_def / water_def_total * bypass_water);
2398 
2399  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2400  }
2401  }
2402  else
2403  {
2404  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2405  {
2406  double const water_def( cbm::bound_min( 0.0, (wc_.wc_fc_sl[sl] - wc_.wc_sl[sl] - wc_.ice_sl[sl]) * sc_.h_sl[sl]));
2407  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2408  }
2409  /* add surplus to percolation out of last soil layer */
2410  wc_.accumulated_percolation += bypass_water - water_def_total;
2411  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2412  }
2413  }
2414 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2554

◆ 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

2277 {
2278  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2279  double const fsl( get_fsl( _sl));
2280  double const fhr( get_time_step_duration());
2281 
2283  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_sipar->SLOPE_FF() : m_sipar->SLOPE_MS());
2284 
2285  double const travel_time( 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr));
2286  double const travel_time_factor( cbm::flt_greater_zero( travel_time) ? (1.0 - exp(-1.0 / travel_time)) : 1.0);
2287  return cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2288  * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * travel_time_factor * _fact_impedance,
2289  sks);
2290 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2554
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2450

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day