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.

2654 {
2655  double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water;
2656  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2657  {
2658  balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2659  }
2660  balance += ( - m_wc.accumulated_irrigation_event_executed
2661  - wc_.accumulated_irrigation_automatic
2662  - wc_.accumulated_irrigation_ggcmi
2663  - wc_.accumulated_irrigation_reservoir_withdrawal
2664  - wc_.accumulated_precipitation
2665  - wc_.accumulated_groundwater_access
2666  + wc_.accumulated_percolation
2667  + wc_.accumulated_runoff
2668  + wc_.accumulated_wateruptake_sl.sum()
2669  + wc_.accumulated_interceptionevaporation
2670  + wc_.accumulated_soilevaporation
2671  + wc_.accumulated_surfacewaterevaporation);
2672 
2673  if ( _balance)
2674  {
2675  double const balance_delta( std::abs( *_balance - balance));
2676  if ( balance_delta > cbm::DIFFMAX)
2677  {
2678  KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2679  }
2680  }
2681 
2682  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2683  {
2684  if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2685  {
2686  KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2687  wc_.wc_sl[sl] = 0.0;
2688  }
2689  if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2690  {
2691  KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2692  wc_.ice_sl[sl] = 0.0;
2693  }
2694  }
2695 
2696  return balance;
2697 }
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition: watercycle-dndc.cpp:1123

◆ 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

818 {
819  //reset irrigation
820  m_wc.irrigation = 0.0;
821 
825  if (cbm::flt_in_range_lu(0.0, m_cfg.automaticirrigation, 1.0))
826  {
827  if (m_veg->size() > 0) //check crop is present
828  {
829  if (cbm::flt_greater(mc_.nd_airtemperature,10.0)) // only add water if temperature > 10C)
830  {
831  for (size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
832  {
833  if (cbm::flt_greater_zero(m_veg->mfrt_sl(l))) //only count water need for soil layers that contain roots
834  {
835  // trigger irrigation events as soon as drought stress appears
836  double const wc_target(wc_.wc_wp_sl[l] + m_cfg.automaticirrigation * (wc_.wc_fc_sl[l] - wc_.wc_wp_sl[l]));
837  if (cbm::flt_less(wc_.wc_sl[l], wc_target) &&
838  cbm::flt_equal_zero(wc_.ice_sl[l])) //only add water if no ice is present
839  {
840  // irrigation assumed until target water content
841  double const irrigate_layer((wc_target - wc_.wc_sl[l]) * sc_.h_sl[l]);
842  m_wc.irrigation += irrigate_layer;
843  wc_.accumulated_irrigation_automatic += irrigate_layer;
844  }
845  }
846  }
847 
848  }
849  else
850  {
851  }
852 
853  }
854  }
855 
856  if ( cbm::flt_in_range_lu( 0.0, m_eventflood.get_saturation_level(), 1.0) &&
857  cbm::is_valid( m_eventflood.get_irrigation_height()) &&
858  cbm::is_valid( m_eventflood.get_soil_depth()))
859  {
860  double wc_sum( 0.0);
861  double wc_fc_sum( 0.0);
862  double wc_wp_sum( 0.0);
863  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
864  {
865  wc_sum += wc_.wc_sl[l] * sc_.h_sl[l];
866  wc_fc_sum += wc_.wc_fc_sl[l] * sc_.h_sl[l];
867  wc_wp_sum += wc_.wc_wp_sl[l] * sc_.h_sl[l];
868 
869  if ( cbm::flt_greater_equal( sc_.depth_sl[l], m_eventflood.get_soil_depth()))
870  {
871  break;
872  }
873  }
874 
875  // trigger irrigation events as soon as drought stress appears
876  double const wc_target( wc_wp_sum + m_eventflood.get_saturation_level() * (wc_fc_sum - wc_wp_sum));
877  if ( cbm::flt_less( wc_sum, wc_target))
878  {
879  m_wc.irrigation += m_eventflood.get_irrigation_height();
880  wc_.accumulated_irrigation_automatic += m_eventflood.get_irrigation_height();
881  }
882  }
883 
891  if ( m_cfg.ggcmi_irrigation)
892  {
893  if( (lclock()->subday() == 1) && (_i == 0))
894  {
895  if( m_veg->size() > 0 ) //check crop is present
896  {
897  double water_supply( 0.0);
898  for ( size_t l = 0; l < m_soillayers->soil_layer_cnt(); ++l)
899  {
900  if ( cbm::flt_greater_zero( m_veg->mfrt_sl( l))) //only irrigate soil layers that contain roots
901  {
902  if( cbm::flt_less( wc_.wc_sl[l], wc_.wc_fc_sl[l]) &&
903  cbm::flt_equal_zero( wc_.ice_sl[l])) //only add water if no ice is present
904  {
905  water_supply += (wc_.wc_fc_sl[l] - wc_.wc_sl[l]) * sc_.h_sl[l]; //amount of water added (m)
906  wc_.wc_sl[l] = wc_.wc_fc_sl[l];
907  }
908  }
909  }
910  wc_.accumulated_irrigation_ggcmi += water_supply;
911  }
912  }
913  }
914 
918  if ( cbm::is_valid( m_eventflood.get_water_table()))
919  {
920  /* Dynamic flooding */
921  if ( cbm::is_valid( m_eventflood.get_irrigation_height()))
922  {
923  bool irrigate( false);
924 
925  /* Irrigate after surface water table drop */
926  if ( cbm::flt_greater_equal_zero( m_eventflood.get_water_table()))
927  {
928  if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
929  {
930  irrigate = true;
931  }
932  }
933  else
934  {
935  if ( !cbm::flt_greater_zero( wc_.surface_water))
936  {
937  double water_tot_sum( 0.0);
938  double water_fc_sum( 0.0);
939  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
940  {
941  water_tot_sum += wc_.wc_sl[sl] * sc_.h_sl[sl];
942  water_fc_sum += wc_.wc_fc_sl[sl] * sc_.h_sl[sl];
943  if ( cbm::flt_greater_equal( sc_.depth_sl[sl], -m_eventflood.get_water_table()))
944  {
945  break;
946  }
947  }
948  // Note: The tipping bucket approach may block percolation into deeper soil layers
949  // if the upper layers have higher water content. This can lead to water reduction
950  // from evapotranspiration in deeper layers without replenishment from above.
951  // Workaround: AWD is triggered when the integrated topsoil water drops below
952  // 90% of the integrated topsoil field capacity.
953  if ( cbm::flt_less( water_tot_sum, 0.9 * water_fc_sum))
954  {
955  irrigate = true;
956  }
957  }
958  }
959  // trigger AWD irrigation event
960  if ( irrigate)
961  {
962  double water_supply( cbm::bound_min( 0.0, m_eventflood.get_irrigation_height() - wc_.surface_water));
963  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
964  {
965  // set soil fully water saturated
966  if ( cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
967  {
968  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
969  }
970  }
971 
972  //remove rainfall (less irrigation water is supplied if it if raining)
973  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
974 
975  if ( m_eventflood.have_unlimited_water())
976  {
977  wc_.accumulated_irrigation_automatic += water_supply;
978  }
979  else
980  {
981  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
982  {
983  wc_.irrigation_reservoir -= water_supply;
984  }
985  else
986  {
987  water_supply = wc_.irrigation_reservoir;
988  wc_.irrigation_reservoir = 0.0;
989  }
990  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
991  }
992  m_wc.irrigation += water_supply;
993  }
994  }
995  /* Static flooding */
996  else
997  {
998  if ( !cbm::flt_greater_zero( m_eventflood.get_water_table()))
999  {
1000  double water_supply( 0.0);
1001  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1002  {
1003  if ( cbm::flt_greater( sc_.depth_sl[sl], -m_eventflood.get_water_table()) &&
1004  cbm::flt_greater( sc_.poro_sl[sl], wc_.wc_sl[sl]))
1005  {
1006  double const scale( cbm::flt_less( sc_.depth_sl[sl] - sc_.h_sl[sl], -m_eventflood.get_water_table()) ?
1007  (-m_eventflood.get_water_table() - (sc_.depth_sl[sl] - sc_.h_sl[sl])) / sc_.h_sl[sl] :
1008  1.0);
1009 
1010  water_supply += scale * (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl];
1011  }
1012  }
1013 
1014  //remove rainfall (less irrigation water is supplied if it is raining)
1015  water_supply = cbm::bound( 0.0, water_supply - m_mc.precipitation, wc_.sks_sl[0]);
1016 
1017  /* Surface water will be actively drained */
1018  if ( cbm::flt_greater_equal( wc_.surface_water, water_supply))
1019  {
1020  wc_.accumulated_runoff += wc_.surface_water - water_supply;
1021  wc_.surface_water = water_supply;
1022  water_supply = 0.0;
1023  }
1024  else if ( cbm::flt_greater_zero( wc_.surface_water))
1025  {
1026  water_supply -= wc_.surface_water;
1027  }
1028 
1029  if ( m_eventflood.have_unlimited_water())
1030  {
1031  wc_.accumulated_irrigation_automatic += water_supply;
1032  }
1033  else
1034  {
1035  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1036  {
1037  wc_.irrigation_reservoir -= water_supply;
1038  }
1039  else
1040  {
1041  water_supply = wc_.irrigation_reservoir;
1042  wc_.irrigation_reservoir = 0.0;
1043  }
1044  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1045  }
1046 
1047  m_wc.irrigation += water_supply;
1048  }
1052  else if ( cbm::flt_greater( m_eventflood.get_water_table(), wc_.surface_water))
1053  {
1054  //adjust surface and soil water in case of flooding event
1055  //water required to fill up surface water
1056  double water_supply( m_eventflood.get_water_table() - wc_.surface_water);
1057 
1058  //add water required to fill top x layers up to saturation
1059  unsigned long no_layers(3);
1060  if( no_layers > m_soillayers->soil_layer_cnt())
1061  {
1062  no_layers = m_soillayers->soil_layer_cnt();
1063  }
1064 
1065  for ( size_t sl = 0; sl < no_layers; ++sl)
1066  {
1067  water_supply += ((sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]);
1068  }
1069 
1070  //remove rainfall (less irrigation water is supplied if it if raining)
1071  water_supply = cbm::bound_min( 0.0, water_supply - m_mc.precipitation);
1072 
1073  if ( m_eventflood.have_unlimited_water())
1074  {
1075  wc_.accumulated_irrigation_automatic += water_supply;
1076  }
1077  else
1078  {
1079  if ( cbm::flt_greater( wc_.irrigation_reservoir, water_supply))
1080  {
1081  wc_.irrigation_reservoir -= water_supply;
1082  }
1083  else
1084  {
1085  water_supply = wc_.irrigation_reservoir;
1086  wc_.irrigation_reservoir = 0.0;
1087  }
1088  wc_.accumulated_irrigation_reservoir_withdrawal += water_supply;
1089  }
1090  m_wc.irrigation += water_supply;
1091  }
1092  }
1093  }
1094 
1098  double const irrigation_scheduled( cbm::bound_min( 0.0, wc_.accumulated_irrigation - m_wc.accumulated_irrigation_event_executed));
1099 
1100  if ( cbm::flt_greater( irrigation_scheduled, 24.0 * rainfall_intensity()))
1101  {
1102  m_wc.irrigation += irrigation_scheduled / 24.0;
1103  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled / 24.0;
1104  }
1105  else if ( cbm::flt_greater( irrigation_scheduled, (double)hours_per_time_step() * rainfall_intensity()))
1106  {
1107  m_wc.irrigation += (double)hours_per_time_step() * rainfall_intensity();
1108  m_wc.accumulated_irrigation_event_executed += (double)hours_per_time_step() * rainfall_intensity();
1109  }
1110  else
1111  {
1112  m_wc.irrigation += irrigation_scheduled;
1113  m_wc.accumulated_irrigation_event_executed += irrigation_scheduled;
1114  }
1115 }
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  // Daily evaportation demand is derived from the Thornthwaite, the Penman, or the Priestley-Taylor method (standard is 'thornthwaite).
552  day_potevapo = 0.0;
553  if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
554  {
555  if ( lclock()->is_position( TMODE_PRE_YEARLY))
556  {
558  lclock()->days_in_year(),
559  m_climate->annual_temperature_average(),
560  m_climate->annual_temperature_amplitude());
561  }
562 
563  double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
564  double const avg_dayl(12.0);
565 
566  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
568  mc_.nd_airtemperature,
569  daylength, avg_dayl, lclock()->days_in_month(),
571  }
572  else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
573  (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
574  {
575  cbm::sclock_t const & clk( lclock_ref());
576 
577  /* vapour pressure [10^3:Pa] */
578  double vps( 0.0);
579  ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
580  double vp( vps - m_climate->vpd_day( clk));
581 
582  if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
583  {
584  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
585  * ldndc::priestleytaylor( clk.yearday(),
586  clk.days_in_year(),
587  mc_.albedo,
588  m_setup->latitude(),
589  mc_.nd_airtemperature,
590  mc_.nd_shortwaveradiation_in,
591  vp,
592  m_sipar->PT_ALPHA());
593  }
594  else if( m_cfg.potentialevapotranspiration_method == "penman")
595  {
596  /* leaf area index */
597  double const lai( m_veg->lai());
598  ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
599 
600  day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
601  * ldndc::penman( surface,
602  clk.yearday(),
603  clk.days_in_year(),
604  mc_.albedo,
605  m_setup->latitude(),
606  mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
607  mc_.nd_airtemperature,
608  mc_.nd_windspeed,
609  vp);
610  }
611  }
612  else
613  {
614  KLOGERROR("[BUG] huh : it seems that this potentialevapotranspiration method is not registered",
615  "tell the maintainers refering to this error message");
616  return LDNDC_ERR_FAIL;
617  }
618 
619  // The daily evaporation demand is distributed throughout the day (standard is 'previouspattern)
620  // TODO: design a routine that distributes evaporation demand according to temperature or humidity
621  if ( m_cfg.evapotranspiration_method == "uniform")
622  {
623  // hourly evaporation demand is calculated from daily demand equally throughout the day
624  hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
625  }
626  else if ( m_cfg.evapotranspiration_method == "previouspattern")
627  {
628  // hourly evaporation demand is derived from the weighted expression of previous values
629  hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
630  }
631  else if (m_cfg.evapotranspiration_method == "daytimeonly")
632  {
633  // hourly evaporation demand is distributed throughout the sunlight hours only (similar as radiation)
634  double const hour(lclock()->subday());
635  double const day(lclock()->yearday());
636  double const hsun(0.833 * cbm::PI / 180.0);
637  double const lat(m_setup->latitude() * cbm::PI / 180.0);
638  double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
639  double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
640  double dayl(0.0);
641  if (help < -0.999) dayl = 0.0;
642  else if (help > 0.999) dayl = 24.0;
643  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)));
644  if (dayl < 1.0) dayl = 0.0;
645  double const rise(12.0 - dayl * 0.5);
646 
647  double factor(0.0);
648  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);
649 
650  double fday(0.0);
651  if (hour > rise && hour < (24.0 - rise)) fday = factor;
652 
653  hr_pot_evapotrans = day_potevapo * fday;
654  }
655  else
656  {
657  KLOGERROR("[BUG] huh : it seems that this evapotranspiration method option is not registered ",
658  "tell the maintainers refering to this error message");
659  return LDNDC_ERR_FAIL;
660  }
661 
662  // the evaporation limit for all timesteps is the daily demand
663  wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
664 
665  return LDNDC_ERR_OK;
666 }
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
2017 {
2018  //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
2019  double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
2020 
2021  if ( cbm::flt_greater_zero( wc_.surface_ice) &&
2022  cbm::flt_greater_zero( hr_potESnow))
2023  {
2024  //If there is a snowpack and there is a potential to evaporate
2025  if ( wc_.surface_ice > hr_potESnow)
2026  {
2027  //Partial evaporation from the snow
2028  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
2029  wc_.accumulated_surfacewaterevaporation += hr_potESnow;
2030  wc_.surface_ice -= hr_potESnow;
2031  }
2032  else
2033  {
2034  //Total evaporation of the snowpack
2035  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
2036  wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
2037  wc_.surface_ice = 0.0;
2038  }
2039  }
2040 }

◆ CalcSoilEvapoPercolation()

void ldndc::WatercycleDNDC::CalcSoilEvapoPercolation ( )
private
Parameters
[in]None
[out]None
Returns
None
2154 {
2155  // reset all water fluxes
2156  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2157  {
2158  m_wc.percolation_sl[sl] = 0.0;
2159  }
2160 
2161  // fill groundwater layer with water
2162  for (int sl = m_soillayers->soil_layer_cnt() - 1; sl >= 0; --sl)
2163  {
2164  if (cbm::flt_greater_equal(sc_.depth_sl[sl], ground_water_table))
2165  {
2166  // ice volume is excepted from groundwater
2167  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2168  if (cbm::flt_greater(sc_.poro_sl[sl], ice_vol))
2169  {
2170  // new water in the layer is generated from groundwater
2171  double const gw_access(cbm::bound_min(0.0, (sc_.poro_sl[sl] - ice_vol - wc_.wc_sl[sl]) * sc_.h_sl[sl] ));
2172  wc_.wc_sl[sl] += gw_access / sc_.h_sl[sl];
2173  wc_.accumulated_groundwater_access += gw_access;
2174  }
2175  }
2176  else
2177  {
2178  break;
2179  }
2180  }
2181 
2182  for (size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2183  {
2184  // the first soil (litter) layer is filled with surface water up to its capacity
2185  if (sl == 0)
2186  {
2187  double delta_wc(0.0);
2188  double const wc_old(wc_.wc_sl[sl]);
2189  double const wc_cap( (sc_.poro_sl[sl] - wc_.wc_sl[sl]) * sc_.h_sl[sl]); // uptake capacity in first soil layer [mm]
2190 
2191  if (cbm::flt_greater(wc_.surface_water, wc_cap))
2192  {
2193  wc_.wc_sl[sl] = sc_.poro_sl[sl];
2194  delta_wc = cbm::bound_max(wc_.surface_water, (cbm::bound_min(0.0, wc_.wc_sl[sl] - wc_old) * sc_.h_sl[sl]));
2195  wc_.surface_water -= delta_wc;
2196  }
2197  else
2198  {
2199  wc_.wc_sl[sl] = (wc_.wc_sl[sl] * sc_.h_sl[sl] + wc_.surface_water) / sc_.h_sl[sl];
2200  delta_wc = cbm::bound_max(wc_.surface_water, (cbm::bound_min(0.0, wc_.wc_sl[sl] - wc_old) * sc_.h_sl[sl]));
2201  wc_.surface_water = 0.0;
2202  }
2203 
2204  wc_.accumulated_infiltration += delta_wc;
2205  }
2206  // other soil layers get updated by percolation rates from the layer above
2207  else
2208  {
2209  wc_.wc_sl[sl] += m_wc.percolation_sl[sl - 1] / sc_.h_sl[sl];
2210  }
2211 
2212  // percolation for all layers below groundwater
2213  if (cbm::flt_greater(sc_.depth_sl[sl], ground_water_table))
2214  {
2215 
2216  // in case groundwater reaches the soil surface, the first outflux is estimated by saturated water flow
2217  if (sl == 0)
2218  {
2219  m_wc.percolation_sl[sl] = WaterFlowSaturated(sl, get_impedance_factor(sl));
2220  }
2221  // other soil layers are assumed to percolate by the same rate as the last non-groundwater layer
2222  else
2223  {
2224  m_wc.percolation_sl[sl] = m_wc.percolation_sl[sl - 1];
2225  }
2226 
2227  }
2228  // in all other cases percolation
2229  else if (sl + 1 == m_soillayers->soil_layer_cnt())
2230  {
2231  m_wc.percolation_sl[sl] = 0.0;
2232  if (cbm::flt_greater_zero(wc_.sks_sl[sl]))
2233  {
2234  if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2235  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl])) //security, should be always true if first condition is met
2236  {
2237  //maximum allowed flow until field capacity
2238  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2239  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)), max_flow);
2240  }
2241 
2242  //water flux above field capacity
2243  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2244  {
2245  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2246  }
2247 
2248  //water flux below field capacity and above wilting point
2249  else if (cbm::flt_greater_zero(m_wc.percolation_sl[sl - 1]) &&
2250  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2251  {
2252  m_wc.percolation_sl[sl] = m_sipar->FPERCOL() * m_wc.percolation_sl[sl - 1];
2253  }
2254 
2255  //bound water flux by defined maximal percolation rate (e.g., during flooding events)
2256  m_wc.percolation_sl[sl] = cbm::bound_max(m_wc.percolation_sl[sl], max_percolation);
2257  }
2258  }
2259 
2260  //infiltrating water in current time step is exceeding available pore space of last time step
2261  //second condition: security, should be always true if first condition is met
2262  else if (cbm::flt_greater(wc_.wc_sl[sl], sc_.poro_sl[sl]) &&
2263  cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_fc_sl[sl]))
2264  {
2265  //maximum allowed flow until field capacity
2266  double const max_flow((wc_.wc_sl[sl] - wc_.wc_fc_sl[sl]) * sc_.h_sl[sl]);
2267  m_wc.percolation_sl[sl] = cbm::bound_max(WaterFlowSaturated(sl, get_impedance_factor(sl)),
2268  max_flow);
2269  }
2270  else if (cbm::flt_greater_equal(wc_.wc_sl[sl] + wc_.ice_sl[sl], wc_.wc_fc_sl[sl]))
2271  {
2272  m_wc.percolation_sl[sl] = WaterFlowAboveFieldCapacity(sl, get_impedance_factor(sl));
2273  }
2274  else if (cbm::flt_greater(wc_.wc_sl[sl], wc_.wc_wp_sl[sl]))
2275  {
2276  m_wc.percolation_sl[sl] = WaterFlowCapillaryRise(sl, get_impedance_factor(sl));
2277  }
2278  else
2279  {
2280  m_wc.percolation_sl[sl] = 0.0;
2281  }
2282 
2283 
2284  // water content must be greater or equal wilting point
2285  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]) &&
2286  cbm::flt_greater_zero(m_wc.percolation_sl[sl]))
2287  {
2288  m_wc.percolation_sl[sl] = cbm::bound(0.0,
2289  (wc_.wc_sl[sl] + wc_.ice_sl[sl] - wc_.wc_wp_sl[sl]) * sc_.h_sl[sl],
2290  m_wc.percolation_sl[sl]);
2291  }
2292 
2293  // Update of the current soil layer water content
2294  wc_.wc_sl[sl] -= m_wc.percolation_sl[sl] / sc_.h_sl[sl];
2295 
2297  }
2298 
2299  /* Correct water content and percolation if water content is above porosity
2300  * If the layer below cannot take up all of the water assigned for percolation,
2301  * so if the air filled pore space is not sufficient,
2302  * the water remains in the upper layer.
2303  */
2304  for (size_t sl = m_soillayers->soil_layer_cnt() - 1; sl > 0; sl--)
2305  {
2306  double const ice_vol(wc_.ice_sl[sl] / cbm::DICE);
2307  if (cbm::flt_greater(wc_.wc_sl[sl] + ice_vol, sc_.poro_sl[sl]))
2308  {
2309  double delta_wc(wc_.wc_sl[sl] + ice_vol - sc_.poro_sl[sl]);
2310  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[sl]))
2311  {
2312  delta_wc = wc_.wc_sl[sl];
2313  wc_.wc_sl[sl] = 0.0;
2314  }
2315  else
2316  {
2317  wc_.wc_sl[sl] = sc_.poro_sl[sl] - ice_vol;
2318  }
2319  m_wc.percolation_sl[sl - 1] -= delta_wc * sc_.h_sl[sl];
2320  wc_.wc_sl[sl - 1] += delta_wc * sc_.h_sl[sl] / sc_.h_sl[sl - 1];
2321  }
2322  }
2323 
2324  double const ice_vol(wc_.ice_sl[0] / cbm::DICE);
2325  if (cbm::flt_greater(wc_.wc_sl[0] + ice_vol, sc_.poro_sl[0]))
2326  {
2327 
2328  double delta_wc(wc_.wc_sl[0] + ice_vol - sc_.poro_sl[0]);
2329  if (cbm::flt_greater_equal(ice_vol, sc_.poro_sl[0]))
2330  {
2331  delta_wc = wc_.wc_sl[0];
2332  wc_.wc_sl[0] = 0.0;
2333  }
2334  else
2335  {
2336  wc_.wc_sl[0] = sc_.poro_sl[0] - ice_vol;
2337  }
2338  wc_.accumulated_infiltration -= delta_wc * sc_.h_sl[0];
2339  wc_.surface_water += delta_wc * sc_.h_sl[0];
2340  }
2341 
2342  if (cbm::flt_greater_zero(wc_.surface_water))
2343  {
2344  CalcSurfaceFlux();
2345  }
2346 
2347  wc_.accumulated_waterflux_sl += m_wc.percolation_sl;
2348  wc_.accumulated_percolation += m_wc.percolation_sl[ m_soillayers->soil_layer_cnt()-1];
2349 }
double get_impedance_factor(size_t)
Reduces water fluxes out of a layer if ice lenses have formed.
Definition: watercycle-dndc.cpp:2517
void SoilWaterEvaporation(size_t)
Definition: watercycle-dndc.cpp:2082
double WaterFlowAboveFieldCapacity(size_t, double const &)
Definition: watercycle-dndc.cpp:2362
void CalcSurfaceFlux()
Definition: watercycle-dndc.cpp:2566
double WaterFlowCapillaryRise(size_t, double const &)
Similar to WaterFlowBelowFieldCapacity(...) but restricts water flow by water availability from soil ...
Definition: watercycle-dndc.cpp:2411

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2567 {
2568  if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2569  {
2570  if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2571  {
2572  wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2573  wc_.surface_water = m_eventflood.get_bund_height();
2574  }
2575  }
2576  else
2577  {
2578  /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2579  double const runoff_fraction(m_sipar->FRUNOFF() * get_time_step_duration());
2580 
2581  // - not all surface water is removed within one timestep
2582  if ( cbm::flt_less( runoff_fraction, 1.0))
2583  {
2584  double const runoff( runoff_fraction * wc_.surface_water);
2585  wc_.surface_water -= runoff;
2586  wc_.accumulated_runoff += runoff;
2587  }
2588  // - all surface water is immediatly removed
2589  else
2590  {
2591  wc_.accumulated_runoff += wc_.surface_water;
2592  wc_.surface_water = 0.0;
2593  }
2594  }
2595 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2642

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
1986 {
1987  if ( cbm::flt_greater_zero( wc_.surface_water) &&
1988  cbm::flt_greater_zero( hr_pot_evapotrans))
1989  {
1990  if ( hr_pot_evapotrans > wc_.surface_water)
1991  {
1992  wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
1993  hr_pot_evapotrans -= wc_.surface_water;
1994  wc_.surface_water = 0.0;
1995  }
1996  else
1997  {
1998  wc_.surface_water -= hr_pot_evapotrans;
1999  wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
2000  hr_pot_evapotrans = 0.0;
2001  }
2002  }
2003 }

◆ 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
1841 {
1842  // hourly potential transpiration
1843  double const hr_potTrans( hr_potTransinm * cbm::CM_IN_M);
1844 
1845  // hourly water uptake
1846  double hr_uptake( 0.0);
1847 
1848  // Calculate the root water uptake and hence the transpiration for every plant individually
1849  for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1850  {
1851  // split up the potential transpiration equally to the various plants
1852  // frt mass of the current species
1853  double const mfrt_species( (*vt)->mFrt);
1854  // total frt mass
1855  double const mfrt_sum( m_veg->dw_frt());
1856  double const hr_potTransspecies = hr_potTrans * mfrt_species/mfrt_sum; // in cm
1857 
1858  // If some soil layers are frozen and contain only ice, no fluid water is present and the water potential diverges.
1859  // The uptake from these layers is prevented by considering only roots in layers with more water than ice.
1860  // In this case the root distribution needs to be rescaled (otherwise the non-contributing layers would effectively contribute a potential = 0).
1861  double fFrt_unfrozen( 1.0);
1862 
1863  /* TODO: include icetowatercrit as proper parameter */
1864  double icetowatercrit( 0.1);
1865  double effsoilwatpot( 0.0);
1866  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1867  {
1868  // fine root conditions to prevent transpiration without uptake organs, wateruptake from frozen ground
1869  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1870  {
1871  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1872  {
1873  // overall water potential in this layer
1874  double const watpotl( Soillayerwaterhead( sl)); // negative
1875  effsoilwatpot += watpotl * (*vt)->fFrt_sl[sl]; // negative
1876  }
1877  else
1878  {
1879  fFrt_unfrozen -= (*vt)->fFrt_sl[sl];
1880  }
1881  }
1882  else
1883  {
1884  // roots are not wireless ;-)
1885  break;
1886  }
1887  }
1888  // normalize the root distribution in the potential, if some soil is frozen
1889  effsoilwatpot = effsoilwatpot / fFrt_unfrozen;
1890 
1891  // hydraulic conductivities of plant system
1892  double const Krs(vt->KRSINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1893  double const Kcomp(vt->KCOMPINIT() * mfrt_species / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1894 
1895  // water potential in the leafs, depending on the potential transpiration
1896  double const leafwatpot( cbm::bound_min(vt->HLEAFCRIT(), effsoilwatpot - (hr_potTransspecies / Krs))); // cm
1897 
1898  if( cbm::flt_greater_zero( leafwatpot))
1899  {
1900  KLOGERROR( "leafwatpot is positive");
1901  return LDNDC_ERR_FAIL;
1902  }
1903  if( !cbm::flt_greater_zero( effsoilwatpot - leafwatpot))
1904  {
1905  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.");
1906  return LDNDC_ERR_FAIL;
1907  }
1908 
1909  double const effuptake( Krs * (effsoilwatpot - leafwatpot)); // cm/timestep
1910  double uptake_tot( 0.0);
1911  double uptakecomp_tot( 0.0);
1912 // double uptakecompabs_tot( 0.0);
1913 
1914  for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1915  {
1916  // fine root condition to prevent transpiration without uptake organs
1917  if( cbm::flt_greater_zero( (*vt)->fFrt_sl[sl] * mfrt_species))
1918  {
1919  if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], icetowatercrit))
1920  {
1921  double const watpotl( Soillayerwaterhead( sl));
1922  double const compuptake( Kcomp * (watpotl - effsoilwatpot));
1923  double uptake_layer( (effuptake + compuptake) * (*vt)->fFrt_sl[sl]); // absolute value in cm
1924 
1925  wc_.accumulated_wateruptake_sl[sl] += uptake_layer * cbm::M_IN_CM;
1926  uptake_tot += uptake_layer; // absolute value in cm
1927  uptakecomp_tot += compuptake * (*vt)->fFrt_sl[sl]; // absolute value in cm
1928 // uptakecompabs_tot += fabs(compuptake * (*vt)->fFrt_sl[sl]); // absolute value in cm
1929 
1930  wc_.wc_sl[sl] -= uptake_layer * cbm::M_IN_CM /sc_.h_sl[sl]; // fraction of water in this layer, in m
1931 
1932  if( !cbm::flt_greater_zero( wc_.wc_sl[sl]))
1933  {
1934  KLOGERROR( "In soil layer ", sl, " the water content is negative: ", wc_.wc_sl[sl]);
1935  return LDNDC_ERR_FAIL;
1936  }
1937  }
1938  }
1939  else
1940  {
1941  // roots are not wireless ;-)
1942  break;
1943  }
1944  }
1945 
1946  hr_uptake += uptake_tot * cbm::M_IN_CM; // absolute value in m for all species
1947 
1948 
1949  if( cbm::flt_greater_zero( fabs(uptakecomp_tot))){
1950  KLOGWARN( "Compensatory water uptake ", uptakecomp_tot, " > 0.");
1951  }
1952  if( cbm::flt_greater( uptake_tot, hr_potTransspecies, 0.0000000001))
1953  {
1954  KLOGERROR( "Total water uptake ", uptake_tot, " larger than potential transpiration ", hr_potTransspecies);
1955  }
1956  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))
1957  {
1958  KLOGERROR( "T ", uptake_tot, "cm < Tpot ", hr_potTransspecies, "cm even though leafwatpot ", leafwatpot, " > HLEAFCRIT", vt->HLEAFCRIT());
1959  }
1960  }
1961 
1962  // total evaporation demand reduced to apply on other evaporating sources (ground, snow, surface water)
1963  hr_pot_evapotrans = cbm::bound_min(0.0, hr_pot_evapotrans - hr_uptake);
1964 
1965  return LDNDC_ERR_OK;
1966 }

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

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

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

◆ 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
1124 {
1125  if ( m_veg->size() > 0u)
1126  {
1127  return wc_.wc_fl.sum();
1128  }
1129  return 0.0;
1130 }

◆ 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
2084 {
2085  //percolation and direct evaporation from the (upper) soil
2086  //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
2087  double const wc_min_evaporation(m_sipar->WCDNDC_EVALIM_FRAC_WCMIN() * wc_.wc_wp_sl[_sl]);
2088  if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_sipar->EVALIM()) &&
2089  cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
2090  cbm::flt_greater_zero( hr_pot_evapotrans))
2091  {
2092  //limiting factor for soil water infiltration
2093  double const f_clay( 1.0 + m_sipar->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
2094  double const f_water( cbm::bound( 0.0,
2095  pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / wc_.wc_fc_sl[_sl], f_clay),
2096  1.0));
2097  double const h_rest( std::min( sc_.h_sl[_sl], m_sipar->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
2098  double const f_depth( h_rest / m_sipar->EVALIM() * std::max(0.0,
2099  1.0 - std::min((double)m_sipar->EVALIM(),
2100  sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
2101  / m_sipar->EVALIM()));
2102  double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
2103 
2104  double const soilevaporation( cbm::bound( 0.0,
2105  hr_pot_evapotrans * f_depth * f_water,
2106  soilevaporation_max));
2107 
2108  //update of the current soil layer water content
2109  wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
2110  wc_.accumulated_soilevaporation += soilevaporation;
2111  hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
2112  }
2113 }

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2456 {
2457  //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2458  if ( cbm::flt_greater_zero(m_sipar->BY_PASSF()) &&
2459  cbm::flt_greater_zero( wc_.surface_water))
2460  {
2461 
2462  double water_def_total( 0.0);
2463  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2464  {
2465  //water flux that flow through macro pores can maximally store
2466  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]);
2467  }
2468 
2469  //duration of timestep (hr-1)
2470  double const fhr( get_time_step_duration());
2471 
2472 
2473  //fraction of surface water that is put into bypass flow (m timestep-1)
2474  double const bypass_fraction( cbm::bound_max(m_sipar->BY_PASSF() * fhr, 0.99));
2475  double const bypass_water( wc_.surface_water * bypass_fraction);
2476  wc_.surface_water -= bypass_water;
2477  wc_.accumulated_infiltration += bypass_water;
2478 
2479  if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2480  {
2481 
2482  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2483  {
2484  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]));
2485  double const water_add( water_def / water_def_total * bypass_water);
2486 
2487  wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2488  }
2489  }
2490  else
2491  {
2492  for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2493  {
2494  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]));
2495  wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2496  }
2497  /* add surplus to percolation out of last soil layer */
2498  wc_.accumulated_percolation += bypass_water - water_def_total;
2499  wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2500  }
2501  }
2502 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2642

◆ 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

2365 {
2366  double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2367  double const fsl( get_fsl( _sl));
2368  double const fhr( get_time_step_duration());
2369 
2371  double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_sipar->SLOPE_FF() : m_sipar->SLOPE_MS());
2372 
2373  double const travel_time( 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr));
2374  double const travel_time_factor( cbm::flt_greater_zero( travel_time) ? (1.0 - exp(-1.0 / travel_time)) : 1.0);
2375  return cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2376  * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * travel_time_factor * _fact_impedance,
2377  sks);
2378 }
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition: watercycle-dndc.cpp:2642
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0...
Definition: watercycle-dndc.cpp:2538

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day