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.

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

◆ 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  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
912  {
913  if ( cbm::flt_greater_equal( sc_.depth_sl[sl], -m_eventflood.get_water_table()))
914  {
915  //check if water content below AWD_DEPTH is saturated
916  if ( cbm::flt_less( wc_.wc_sl[sl], 0.9 * sc_.poro_sl[sl]))
917  {
918  irrigate = true;
919  }
920  break;
921  }
922  }
923  }
924  }
925  // trigger AWD irrigation event
926  if ( irrigate)
927  {
928  double water_supply( cbm::bound_min( 0.0, m_eventflood.get_irrigation_height() - wc_.surface_water));
929  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
930  {
931  // set soil fully water saturated
932  if ( cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
933  {
934  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
935  }
936  }
937 
938  //remove rainfall (less irrigation water is supplied if it if raining)
939  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
940 
941  if ( m_eventflood.have_unlimited_water())
942  {
943  wc_.accumulated_irrigation_automatic += water_supply;
944  }
945  else
946  {
947  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
948  {
949  wc_.irrigation_reservoir -= water_supply;
950  }
951  else
952  {
953  water_supply = wc_.irrigation_reservoir;
954  wc_.irrigation_reservoir = 0.0;
955  }
956  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
957  }
958  m_wc.irrigation += water_supply;
959  }
960  }
961  /* Static flooding */
962  else
963  {
964  if ( !cbm::flt_greater_zero( m_eventflood.get_water_table()))
965  {
966  double water_supply( 0.0);
967  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
968  {
969  if ( cbm::flt_greater( sc_.depth_sl[sl], -m_eventflood.get_water_table()) &&
970  cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
971  {
972  double const scale( cbm::flt_less( sc_.depth_sl[sl] - sc_.h_sl[sl], -m_eventflood.get_water_table()) ?
973  (-m_eventflood.get_water_table() - (sc_.depth_sl[sl] - sc_.h_sl[sl])) / sc_.h_sl[sl] :
974  1.0);
975 
976  water_supply += scale * (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl];
977  }
978  }
979 
980  //remove rainfall (less irrigation water is supplied if it is raining)
981  water_supply = cbm::bound( 0.0, water_supply - m_mc.precipitation, wc_.sks_sl[0]);
982 
983  /* Surface water will be actively drained */
984  if ( cbm::flt_greater_equal( wc_.surface_water, water_supply))
985  {
986  wc_.accumulated_runoff += wc_.surface_water - water_supply;
987  wc_.surface_water = water_supply;
988  water_supply = 0.0;
989  }
990  else if ( cbm::flt_greater_zero( wc_.surface_water))
991  {
992  water_supply -= wc_.surface_water;
993  }
994 
995  if ( m_eventflood.have_unlimited_water())
996  {
997  wc_.accumulated_irrigation_automatic += water_supply;
998  }
999  else
1000  {
1001  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1002  {
1003  wc_.irrigation_reservoir -= water_supply;
1004  }
1005  else
1006  {
1007  water_supply = wc_.irrigation_reservoir;
1008  wc_.irrigation_reservoir = 0.0;
1009  }
1010  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1011  }
1012 
1013  m_wc.irrigation += water_supply;
1014  }
1018  else if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
1019  {
1020  //adjust surface and soil water in case of flooding event
1021  //water required to fill up surface water
1022  double water_supply( m_eventflood.get_water_table() - wc_.surface_water);
1023 
1024  //add water required to fill top x layers up to saturation
1025  unsigned long no_layers(3);
1026  if( no_layers > m_soillayers->soil_layer_cnt())
1027  {
1028  no_layers = m_soillayers->soil_layer_cnt();
1029  }
1030 
1031  for ( size_t sl = 0; sl < no_layers; ++sl)
1032  {
1033  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
1034  }
1035 
1036  //remove rainfall (less irrigation water is supplied if it if raining)
1037  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
1038 
1039  if ( m_eventflood.have_unlimited_water())
1040  {
1041  wc_.accumulated_irrigation_automatic += water_supply;
1042  }
1043  else
1044  {
1045  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1046  {
1047  wc_.irrigation_reservoir -= water_supply;
1048  }
1049  else
1050  {
1051  water_supply = wc_.irrigation_reservoir;
1052  wc_.irrigation_reservoir = 0.0;
1053  }
1054  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1055  }
1056  m_wc.irrigation += water_supply;
1057  }
1058  }
1059  }
1060 
1064  double const irrigation_scheduled( cbm::bound_min( 0.0, wc_.accumulated_irrigation - m_wc.accumulated_irrigation_event_executed));
1065 
1066  if ( cbm::flt_greater( irrigation_scheduled, 24.0 * rainfall_intensity()))
1067  {
1068  m_wc.irrigation += irrigation_scheduled / 24.0;
1069  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled / 24.0;
1070  }
1071  else if ( cbm::flt_greater( irrigation_scheduled, (double)hours_per_time_step() * rainfall_intensity()))
1072  {
1073  m_wc.irrigation += (double)hours_per_time_step() * rainfall_intensity();
1074  m_wc.accumulated_irrigation_event_executed += (double)hours_per_time_step() * rainfall_intensity();
1075  }
1076  else
1077  {
1078  m_wc.irrigation += irrigation_scheduled;
1079  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled;
1080  }
1081 }
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
1888 {
1889  //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
1890  double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
1891 
1892  if ( cbm::flt_greater_zero( wc_.surface_ice) &&
1893  cbm::flt_greater_zero( hr_potESnow))
1894  {
1895  //If there is a snowpack and there is a potential to evaporate
1896  if ( wc_.surface_ice > hr_potESnow)
1897  {
1898  //Partial evaporation from the snow
1899  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
1900  wc_.accumulated_surfacewaterevaporation += hr_potESnow;
1901  wc_.surface_ice -= hr_potESnow;
1902  }
1903  else
1904  {
1905  //Total evaporation of the snowpack
1906  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
1907  wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
1908  wc_.surface_ice = 0.0;
1909  }
1910  }
1911 }

◆ CalcSoilEvapoPercolation()

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

◆ CalcSurfaceFlux()

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

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1857 {
1858  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1859  cbm::flt_greater_zero( hr_pot_evapotrans))
1860  {
1861  if ( hr_pot_evapotrans > wc_.surface_water)
1862  {
1863  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1864  hr_pot_evapotrans -= wc_.surface_water;
1865  wc_.surface_water = 0.0;
1866  }
1867  else
1868  {
1869  wc_.surface_water -= hr_pot_evapotrans;
1870  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
1871  hr_pot_evapotrans = 0.0;
1872  }
1873  }
1874 }

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

◆ 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 WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2312
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2513

◆ 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
1090 {
1091  if ( m_veg->size() > 0u)
1092  {
1093  return wc_.wc_fl.sum();
1094  }
1095  return 0.0;
1096 }

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

◆ WatercycleDNDC_preferential_flow()

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

◆ 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

2236 {
2237  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2238  double const fsl( get_fsl( _sl));
2239  double const fhr( get_time_step_duration());
2240 
2242  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_sipar->SLOPE_FF() : m_sipar->SLOPE_MS());
2243 
2244  double const travel_time( 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr));
2245  double const travel_time_factor( cbm::flt_greater_zero( travel_time) ? (1.0 - exp(-1.0 / travel_time)) : 1.0);
2246  return cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2247  * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * travel_time_factor * _fact_impedance,
2248  sks);
2249 }
double WaterFlowSaturated(size_t, double const &)
Definition: watercycle-dndc.cpp:2312
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2513
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2409

◆ WaterFlowSaturated()

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

Returns saturated water flow per time step accounting for impedance

2314 {
2315  double const sks( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * get_time_step_duration() * _fact_impedance);
2316  return sks;
2317 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2513

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day