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.

2533 {
2534  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water;
2535  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2536  {
2537  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2538  }
2539  balance += ( - m_wc.accumulated_irrigation_event_executed
2540  - wc_.accumulated_irrigation_automatic
2541  - wc_.accumulated_irrigation_ggcmi
2542  - wc_.accumulated_irrigation_reservoir_withdrawal
2543  - wc_.accumulated_precipitation
2544  - wc_.accumulated_groundwater_access
2545  + wc_.accumulated_percolation
2546  + wc_.accumulated_runoff
2547  + wc_.accumulated_wateruptake_sl.sum()
2548  + wc_.accumulated_interceptionevaporation
2549  + wc_.accumulated_soilevaporation
2550  + wc_.accumulated_surfacewaterevaporation);
2551 
2552  if ( _balance)
2553  {
2554  double const balance_delta( std::abs( *_balance - balance));
2555  if ( balance_delta > cbm::DIFFMAX)
2556  {
2557  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2558  }
2559  }
2560 
2561  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2562  {
2563  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2564  {
2565  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2566  wc_.wc_sl[sl] = 0.0;
2567  }
2568  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2569  {
2570  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2571  wc_.ice_sl[sl] = 0.0;
2572  }
2573  }
2574 
2575  return balance;
2576 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1097

◆ 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

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

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

◆ CalcSoilEvapoPercolation()

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

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2446 {
2447  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2448  {
2449  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2450  {
2451  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2452  wc_.surface_water = m_eventflood.get_bund_height();
2453  }
2454  }
2455  else
2456  {
2457  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2458  double const runoff_fraction(m_sipar->FRUNOFF() * get_time_step_duration());
2459 
2460  // - not all surface water is removed within one timestep
2461  if ( cbm::flt_less( runoff_fraction, 1.0))
2462  {
2463  double const runoff( runoff_fraction * wc_.surface_water);
2464  wc_.surface_water -= runoff;
2465  wc_.accumulated_runoff += runoff;
2466  }
2467  // - all surface water is immediatly removed
2468  else
2469  {
2470  wc_.accumulated_runoff += wc_.surface_water;
2471  wc_.surface_water = 0.0;
2472  }
2473  }
2474 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2521

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1865 {
1866  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1867  cbm::flt_greater_zero( hr_pot_evapotrans))
1868  {
1869  if ( hr_pot_evapotrans > wc_.surface_water)
1870  {
1871  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1872  hr_pot_evapotrans -= wc_.surface_water;
1873  wc_.surface_water = 0.0;
1874  }
1875  else
1876  {
1877  wc_.surface_water -= hr_pot_evapotrans;
1878  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1879  hr_pot_evapotrans = 0.0;
1880  }
1881  }
1882 }

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

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

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

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

◆ 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
1098 {
1099  if ( m_veg->size() > 0u)
1100  {
1101  return wc_.wc_fl.sum();
1102  }
1103  return 0.0;
1104 }

◆ 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
1963 {
1964  //percolation and direct evaporation from the (upper) soil
1965  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
1966  double const wc_min_evaporation(m_sipar->WCDNDC_EVALIM_FRAC_WCMIN() * wc_.wc_wp_sl[_sl]);
1967  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_sipar->EVALIM()) &&
1968  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
1969  cbm::flt_greater_zero( hr_pot_evapotrans))
1970  {
1971  //limiting factor for soil water infiltration
1972  double const f_clay( 1.0 + m_sipar->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
1973  double const f_water( cbm::bound( 0.0,
1974  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / wc_.wc_fc_sl[_sl], f_clay),
1975  1.0));
1976  double const h_rest( std::min( sc_.h_sl[_sl], m_sipar->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
1977  double const f_depth( h_rest / m_sipar->EVALIM() * std::max(0.0,
1978  1.0 - std::min((double)m_sipar->EVALIM(),
1979  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
1980  / m_sipar->EVALIM()));
1981  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
1982 
1983  double const soilevaporation( cbm::bound( 0.0,
1984  hr_pot_evapotrans * f_depth * f_water,
1985  soilevaporation_max));
1986 
1987  //update of the current soil layer water content
1988  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
1989  wc_.accumulated_soilevaporation += soilevaporation;
1990  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
1991  }
1992 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2335 {
2336  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2337  if ( cbm::flt_greater_zero(m_sipar->BY_PASSF()) &&
2338  cbm::flt_greater_zero( wc_.surface_water))
2339  {
2340 
2341  double water_def_total( 0.0);
2342  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2343  {
2344  //water flux that flow through macro pores can maximally store
2345  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]);
2346  }
2347 
2348  //duration of timestep (hr-1)
2349  double const fhr( get_time_step_duration());
2350 
2351 
2352  //fraction of surface water that is put into bypass flow (m timestep-1)
2353  double const bypass_fraction( cbm::bound_max(m_sipar->BY_PASSF() * fhr, 0.99));
2354  double const bypass_water( wc_.surface_water * bypass_fraction);
2355  wc_.surface_water -= bypass_water;
2356  wc_.accumulated_infiltration += bypass_water;
2357 
2358  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2359  {
2360 
2361  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2362  {
2363  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]));
2364  double const water_add( water_def / water_def_total * bypass_water);
2365 
2366  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2367  }
2368  }
2369  else
2370  {
2371  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2372  {
2373  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]));
2374  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2375  }
2376  /* add surplus to percolation out of last soil layer */
2377  wc_.accumulated_percolation += bypass_water - water_def_total;
2378  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2379  }
2380  }
2381 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2521

◆ 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

2244 {
2245  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2246  double const fsl( get_fsl( _sl));
2247  double const fhr( get_time_step_duration());
2248 
2250  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_sipar->SLOPE_FF() : m_sipar->SLOPE_MS());
2251 
2252  double const travel_time( 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr));
2253  double const travel_time_factor( cbm::flt_greater_zero( travel_time) ? (1.0 - exp(-1.0 / travel_time)) : 1.0);
2254  return cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2255  * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * travel_time_factor * _fact_impedance,
2256  sks);
2257 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2521
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2417

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day