LandscapeDNDC 1.37.0
Loading...
Searching...
No Matches
ldndc::WatercycleDNDC Class Reference

Watercycle model WatercycleDNDC. More...

#include <models/watercycle/dndc/watercycle-dndc.h>

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.,
 
double balance_check (double *)
 checks each time step for correct water balance
 
void CalcRaining (unsigned int)
 apportion daily rainfall to subdaily rainfall
 
double rainfall_intensity ()
 
void CalcIrrigation (unsigned int)
 apportion daily irrigation to subdaily irrigation
 
lerr_t CalcIceContent ()
 Call of ice-content related processes.
 
lerr_t CalcPotEvapoTranspiration ()
 Potential evaporation.
 
void CalcInterception ()
 Calculates water quantity that is retained on leaf and stem bark surfaces.
 
double get_leaf_water ()
 Collects leaf water from all canopy layers.
 
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.
 
double get_clay_limitation (size_t _sl, double _water_avail, double _water_ref)
 Restrains water availability due to clay content.
 

Private Attributes

double thornthwaite_heat_index
 heat index for potential evaporation using approach after Thornthwaite
 
double rainfall_intensity_cache
 

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.

2679{
2680 double balance = get_leaf_water() + wc_.surface_ice + wc_.surface_water;
2681 for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2682 {
2683 balance += (wc_.wc_sl[sl] + wc_.ice_sl[sl]) * sc_.h_sl[sl];
2684 }
2685 balance += ( - m_wc.accumulated_irrigation_event_executed
2686 - wc_.accumulated_irrigation_automatic
2687 - wc_.accumulated_irrigation_ggcmi
2688 - wc_.accumulated_irrigation_reservoir_withdrawal
2689 - wc_.accumulated_precipitation
2690 - wc_.accumulated_groundwater_access
2691 + wc_.accumulated_percolation
2692 + wc_.accumulated_runoff
2693 + wc_.accumulated_wateruptake_sl.sum()
2694 + wc_.accumulated_interceptionevaporation
2695 + wc_.accumulated_soilevaporation
2696 + wc_.accumulated_surfacewaterevaporation);
2697
2698 if ( _balance)
2699 {
2700 double const balance_delta( std::abs( *_balance - balance));
2701 if ( balance_delta > cbm::DIFFMAX)
2702 {
2703 KLOGWARN( "Water leakage: difference is ", balance - *_balance);
2704 }
2705 }
2706
2707 for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2708 {
2709 if ( cbm::flt_less( wc_.wc_sl[sl], 0.0))
2710 {
2711 KLOGWARN( "Negative water content of: ", wc_.wc_sl[sl], " in layer: ", sl, ". Water content set to zero.");
2712 wc_.wc_sl[sl] = 0.0;
2713 }
2714 if ( cbm::flt_less( wc_.ice_sl[sl], 0.0))
2715 {
2716 KLOGWARN( "Negative ice content of: ", wc_.ice_sl[sl], " in layer: ", sl, ". Ice content set to zero.");
2717 wc_.ice_sl[sl] = 0.0;
2718 }
2719 }
2720
2721 return balance;
2722}
double get_leaf_water()
Collects leaf water from all canopy layers.
Definition watercycle-dndc.cpp:1115

References balance_check(), and get_leaf_water().

Referenced by balance_check(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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

References get_impedance_factor(), and get_leaf_water().

Referenced by solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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

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

References CalcIrrigation(), and rainfall_intensity().

Referenced by CalcIrrigation(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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
542{
543 // Daily evaportation demand is derived from the Thornthwaite, the Penman, or the Priestley-Taylor method (standard is 'thornthwaite).
544 day_potevapo = 0.0;
545 if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
546 {
547 if ( lclock()->is_position( TMODE_PRE_YEARLY))
548 {
550 lclock()->days_in_year(),
551 m_climate->annual_temperature_average(),
552 m_climate->annual_temperature_amplitude());
553 }
554
555 double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
556 double const avg_dayl(12.0);
557
558 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
560 mc_.nd_airtemperature,
561 daylength, avg_dayl, lclock()->days_in_month(),
563 }
564 else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
565 (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
566 {
567 cbm::sclock_t const & clk( lclock_ref());
568
569 /* vapour pressure [10^3:Pa] */
570 double vps( 0.0);
571 ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
572 double vp( vps - m_climate->vpd_day( clk));
573
574 if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
575 {
576 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
577 * ldndc::priestleytaylor( clk.yearday(),
578 clk.days_in_year(),
579 mc_.albedo,
580 m_setup->latitude(),
581 mc_.nd_airtemperature,
582 mc_.nd_shortwaveradiation_in,
583 vp,
584 m_sipar->PT_ALPHA());
585 }
586 else if( m_cfg.potentialevapotranspiration_method == "penman")
587 {
588 /* leaf area index */
589 double const lai( m_veg->lai());
590 ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
591
592 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
593 * ldndc::penman( surface,
594 clk.yearday(),
595 clk.days_in_year(),
596 mc_.albedo,
597 m_setup->latitude(),
598 mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
599 mc_.nd_airtemperature,
600 mc_.nd_windspeed,
601 vp);
602 }
603 }
604 else
605 {
606 KLOGERROR("[BUG] huh : it seems that this potentialevapotranspiration method is not registered",
607 "tell the maintainers refering to this error message");
608 return LDNDC_ERR_FAIL;
609 }
610
611 // The daily evaporation demand is distributed throughout the day (standard is 'previouspattern)
612 // TODO: design a routine that distributes evaporation demand according to temperature or humidity
613 if ( m_cfg.evapotranspiration_method == "uniform")
614 {
615 // hourly evaporation demand is calculated from daily demand equally throughout the day
616 hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
617 }
618 else if ( m_cfg.evapotranspiration_method == "previouspattern")
619 {
620 // hourly evaporation demand is derived from the weighted expression of previous values
621 hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
622 }
623 else if (m_cfg.evapotranspiration_method == "daytimeonly")
624 {
625 // hourly evaporation demand is distributed throughout the sunlight hours only (similar as radiation)
626 double const hour(lclock()->subday());
627 double const day(lclock()->yearday());
628 double const hsun(0.833 * cbm::PI / 180.0);
629 double const lat(m_setup->latitude() * cbm::PI / 180.0);
630 double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
631 double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
632 double dayl(0.0);
633 if (help < -0.999) dayl = 0.0;
634 else if (help > 0.999) dayl = 24.0;
635 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)));
636 if (dayl < 1.0) dayl = 0.0;
637 double const rise(12.0 - dayl * 0.5);
638
639 double factor(0.0);
640 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);
641
642 double fday(0.0);
643 if (hour > rise && hour < (24.0 - rise)) fday = factor;
644
645 hr_pot_evapotrans = day_potevapo * fday;
646 }
647 else
648 {
649 KLOGERROR("[BUG] huh : it seems that this evapotranspiration method option is not registered ",
650 "tell the maintainers refering to this error message");
651 return LDNDC_ERR_FAIL;
652 }
653
654 // the evaporation limit for all timesteps is the daily demand
655 wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
656
657 return LDNDC_ERR_OK;
658}
double thornthwaite_heat_index
heat index for potential evaporation using approach after Thornthwaite
Definition watercycle-dndc.h:134
double LDNDC_API thornthwaite_heat_index(double, size_t, double, double)
Thornthwaite heat index.
Definition ld_thornthwaite.cpp:100
double LDNDC_API thornthwaite(double, double, double, double, double)
Potential evapotranspiration after thornthwaite:1948a.
Definition ld_thornthwaite.cpp:41

References CalcPotEvapoTranspiration(), ldndc::thornthwaite(), ldndc::thornthwaite_heat_index(), and thornthwaite_heat_index.

Referenced by CalcPotEvapoTranspiration(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcSnowEvaporation()

void ldndc::WatercycleDNDC::CalcSnowEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
2042{
2043 //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
2044 double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
2045
2046 if ( cbm::flt_greater_zero( wc_.surface_ice) &&
2047 cbm::flt_greater_zero( hr_potESnow))
2048 {
2049 //If there is a snowpack and there is a potential to evaporate
2050 if ( wc_.surface_ice > hr_potESnow)
2051 {
2052 //Partial evaporation from the snow
2053 hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
2054 wc_.accumulated_surfacewaterevaporation += hr_potESnow;
2055 wc_.surface_ice -= hr_potESnow;
2056 }
2057 else
2058 {
2059 //Total evaporation of the snowpack
2060 hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
2061 wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
2062 wc_.surface_ice = 0.0;
2063 }
2064 }
2065}

References CalcSnowEvaporation().

Referenced by CalcSnowEvaporation(), CalcTranspiration(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcSoilEvapoPercolation()

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

References CalcSoilEvapoPercolation(), CalcSurfaceFlux(), get_impedance_factor(), SoilWaterEvaporation(), WaterFlowAboveFieldCapacity(), and WaterFlowCapillaryRise().

Referenced by CalcSoilEvapoPercolation(), CalcTranspiration(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcSurfaceFlux()

void ldndc::WatercycleDNDC::CalcSurfaceFlux ( )
private
Parameters
[in]None
[out]None
Returns
None
2592{
2593 if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2594 {
2595 if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2596 {
2597 wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2598 wc_.surface_water = m_eventflood.get_bund_height();
2599 }
2600 }
2601 else
2602 {
2603 /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2604 double const runoff_fraction(m_sipar->FRUNOFF() * get_time_step_duration());
2605
2606 // - not all surface water is removed within one timestep
2607 if ( cbm::flt_less( runoff_fraction, 1.0))
2608 {
2609 double const runoff( runoff_fraction * wc_.surface_water);
2610 wc_.surface_water -= runoff;
2611 wc_.accumulated_runoff += runoff;
2612 }
2613 // - all surface water is immediatly removed
2614 else
2615 {
2616 wc_.accumulated_runoff += wc_.surface_water;
2617 wc_.surface_water = 0.0;
2618 }
2619 }
2620}
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition watercycle-dndc.cpp:2667

References CalcSurfaceFlux(), and get_time_step_duration().

Referenced by CalcSoilEvapoPercolation(), CalcSurfaceFlux(), and CalcTranspiration().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcSurfaceWaterEvaporation()

void ldndc::WatercycleDNDC::CalcSurfaceWaterEvaporation ( )
private
Parameters
[in]None
[out]None
Returns
None
2011{
2012 if ( cbm::flt_greater_zero( wc_.surface_water) &&
2013 cbm::flt_greater_zero( hr_pot_evapotrans))
2014 {
2015 if ( hr_pot_evapotrans > wc_.surface_water)
2016 {
2017 wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
2018 hr_pot_evapotrans -= wc_.surface_water;
2019 wc_.surface_water = 0.0;
2020 }
2021 else
2022 {
2023 wc_.surface_water -= hr_pot_evapotrans;
2024 wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
2025 hr_pot_evapotrans = 0.0;
2026 }
2027 }
2028}

References CalcSurfaceWaterEvaporation().

Referenced by CalcSurfaceWaterEvaporation(), CalcTranspiration(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalcTranspiration()

lerr_t ldndc::WatercycleDNDC::CalcTranspiration ( )
private

◆ CalcTranspirationCouvreur()

lerr_t ldndc::WatercycleDNDC::CalcTranspirationCouvreur ( double const & hr_potTransinm)
private
Parameters
[in]None
[out]None
Returns
None
1868{
1869 // hourly water uptake
1870 double hr_uptake( 0.0);
1871
1872 // Calculate the root water uptake and hence the transpiration for every plant individually
1873 for( PlantIterator vt = m_veg->begin(); vt != m_veg->end(); ++vt)
1874 {
1875 MoBiLE_Plant *p = *vt;
1876
1877 // split up the potential transpiration equally to the various plants
1878 double const transpiration_possible_vt( _transpiration_possible * p->mFrt / m_veg->dw_frt() * cbm::CM_IN_M); // in cm
1879
1880 // If some soil layers are frozen and contain only ice, no fluid water is present and the water potential diverges.
1881 // The uptake from these layers is prevented by considering only roots in layers with more water than ice.
1882 // In this case the root distribution needs to be rescaled (otherwise the non-contributing layers would effectively contribute a potential = 0).
1883 double unfrozen_root_fraction( 1.0);
1884
1885 /* TODO: include ice_water_ratio_critical as proper parameter */
1886 double const ice_water_ratio_critical( 0.1);
1887 double eff_soil_water_potential( 0.0);
1888 for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1889 {
1890 // fine root conditions to prevent transpiration without uptake organs, wateruptake from frozen ground
1891 if( cbm::flt_greater_zero( p->fFrt_sl[sl] * p->mFrt))
1892 {
1893 if( cbm::flt_greater_zero( wc_.wc_sl[sl]) &&
1894 cbm::flt_less( wc_.ice_sl[sl] / wc_.wc_sl[sl], ice_water_ratio_critical))
1895 {
1896 // overall water potential in this layer
1897 eff_soil_water_potential += Soillayerwaterhead( sl) * p->fFrt_sl[sl]; // negative
1898 }
1899 else
1900 {
1901 unfrozen_root_fraction -= p->fFrt_sl[sl];
1902 }
1903 }
1904 else
1905 {
1906 // roots are not wireless ;-)
1907 break;
1908 }
1909 }
1910 // normalize the root distribution in the potential, if some soil is frozen
1911 if( cbm::flt_greater_zero( unfrozen_root_fraction))
1912 {
1913 eff_soil_water_potential /= unfrozen_root_fraction;
1914 }
1915
1916 // hydraulic conductivities of plant system
1917 double const k_rs( vt->KRSINIT() * p->mFrt / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1918 double const k_comp( vt->KCOMPINIT() * p->mFrt / vt->FRTMASSINIT() * nhr); // cm(water)/cm(from pressure)/timestep
1919
1920 // water potential in the leafs, depending on the potential transpiration
1921 double const leaf_water_potential( cbm::bound_min( vt->HLEAFCRIT(),
1922 eff_soil_water_potential - (transpiration_possible_vt / k_rs))); // cm
1923
1924 if( cbm::flt_greater_zero( leaf_water_potential))
1925 {
1926 KLOGERROR( "Failed to determine transpiration: Non-negative leaf water potential!");
1927 return LDNDC_ERR_FAIL;
1928 }
1929 if( !cbm::flt_greater_zero( eff_soil_water_potential - leaf_water_potential))
1930 {
1931 KLOGERROR( "Failed to determine transpiration!");
1932 return LDNDC_ERR_FAIL;
1933 }
1934
1935 double const effuptake( k_rs * (eff_soil_water_potential - leaf_water_potential)); // cm/timestep
1936 double uptake_tot( 0.0);
1937 double uptakecomp_tot( 0.0);
1938 //double uptakecompabs_tot( 0.0);
1939
1940 for( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
1941 {
1942 // fine root condition to prevent transpiration without uptake organs
1943 if( cbm::flt_greater_zero( p->fFrt_sl[sl] * p->mFrt))
1944 {
1945 if(cbm::flt_less( wc_.ice_sl[sl]/wc_.wc_sl[sl], ice_water_ratio_critical))
1946 {
1947 double const soil_water_potential( Soillayerwaterhead( sl));
1948 double const compuptake( k_comp * (soil_water_potential - eff_soil_water_potential));
1949 double uptake_layer( (effuptake + compuptake) * p->fFrt_sl[sl]); // absolute value in cm
1950
1951 wc_.accumulated_wateruptake_sl[sl] += uptake_layer * cbm::M_IN_CM;
1952 uptake_tot += uptake_layer; // absolute value in cm
1953 uptakecomp_tot += compuptake * p->fFrt_sl[sl]; // absolute value in cm
1954 //uptakecompabs_tot += fabs(compuptake * p->fFrt_sl[sl]); // absolute value in cm
1955
1956 wc_.wc_sl[sl] -= uptake_layer * cbm::M_IN_CM /sc_.h_sl[sl]; // fraction of water in this layer, in m
1957
1958 if( !cbm::flt_greater_zero( wc_.wc_sl[sl]))
1959 {
1960 KLOGERROR( "In soil layer ", sl, " the water content is negative: ", wc_.wc_sl[sl]);
1961 return LDNDC_ERR_FAIL;
1962 }
1963 }
1964 }
1965 else
1966 {
1967 // roots are not wireless ;-)
1968 break;
1969 }
1970 }
1971
1972 hr_uptake += uptake_tot * cbm::M_IN_CM; // absolute value in m for all species
1973
1974 if( cbm::flt_greater_zero( fabs(uptakecomp_tot))){
1975 KLOGWARN( "Compensatory water uptake ", uptakecomp_tot, " > 0.");
1976 }
1977 if( cbm::flt_greater( uptake_tot, transpiration_possible_vt, 0.0000000001))
1978 {
1979 KLOGERROR( "Total water uptake ", uptake_tot, " larger than potential transpiration ", transpiration_possible_vt);
1980 }
1981 if(cbm::flt_equal_eps(unfrozen_root_fraction, 1.0, 0.0000000001) && !cbm::flt_equal_eps( uptake_tot, transpiration_possible_vt, 0.0000000001) && !cbm::flt_equal_eps( leaf_water_potential, vt->HLEAFCRIT(), 0.0000000001))
1982 {
1983 KLOGERROR( "T ", uptake_tot, "cm < Tpot ", transpiration_possible_vt, "cm even though leaf_water_potential ", leaf_water_potential, " > HLEAFCRIT", vt->HLEAFCRIT());
1984 }
1985 }
1986
1987 // total evaporation demand reduced to apply on other evaporating sources (ground, snow, surface water)
1988 hr_pot_evapotrans = cbm::bound_min(0.0, hr_pot_evapotrans - hr_uptake);
1989
1990 return LDNDC_ERR_OK;
1991}

References CalcTranspirationCouvreur().

Referenced by CalcTranspiration(), and CalcTranspirationCouvreur().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ event_flood()

lerr_t ldndc::WatercycleDNDC::event_flood ( )
private

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

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

References event_flood(), and get_time_step_duration().

Referenced by event_flood(), and solve().

Here is the call graph for this function:
Here is the caller graph for this function:

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

References get_leaf_water().

Referenced by balance_check(), CalcInterception(), and get_leaf_water().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rainfall_intensity()

double ldndc::WatercycleDNDC::rainfall_intensity ( )
private

fixed amount of maximum rainfall/irrigation triggered per time step

105{
106 if ( rainfall_intensity_cache < 0.0)
107 {
108 if ( m_iokcomm->get_input_class< input_class_climate_t >())
109 {
110 rainfall_intensity_cache = m_iokcomm->get_input_class< climate::input_class_climate_t >()->station_info()->rainfall_intensity * cbm::M_IN_MM;
111 }
112 else
113 {
114 rainfall_intensity_cache = ldndc::climate::climate_info_defaults.rainfall_intensity * cbm::M_IN_MM;
115 }
116 }
118}
double rainfall_intensity_cache
Definition watercycle-dndc.h:168
double rainfall_intensity
Definition climatetypes.h:40

References rainfall_intensity(), and rainfall_intensity_cache.

Referenced by CalcIrrigation(), CalcRaining(), and rainfall_intensity().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SoilWaterEvaporation()

void ldndc::WatercycleDNDC::SoilWaterEvaporation ( size_t _sl)
private
Parameters
[in]_slSoil layer
[out]None
Returns
None
2109{
2110 //percolation and direct evaporation from the (upper) soil
2111 //if there is snow cover, evaporation from soil will be set to 0, and only sublimation is allowed.
2112 double const wc_min_evaporation(m_sipar->WCDNDC_EVALIM_FRAC_WCMIN() * wc_.wc_wp_sl[_sl]);
2113 if ( cbm::flt_less( sc_.depth_sl[_sl] - sc_.h_sl[_sl], m_sipar->EVALIM()) &&
2114 cbm::flt_greater( wc_.wc_sl[_sl], wc_min_evaporation) &&
2115 cbm::flt_greater_zero( hr_pot_evapotrans))
2116 {
2117 //limiting factor for soil water infiltration
2118 double const f_clay( 1.0 + m_sipar->SLOPE_CLAYF() * std::min(1.0 - sc_.fcorg_sl[_sl] / cbm::CCORG, sc_.clay_sl[_sl]));
2119 double const f_water( cbm::bound( 0.0,
2120 pow( (wc_.wc_sl[_sl] - wc_min_evaporation) / wc_.wc_fc_sl[_sl], f_clay),
2121 1.0));
2122 double const h_rest( std::min( sc_.h_sl[_sl], m_sipar->EVALIM() - ( sc_.depth_sl[_sl] - sc_.h_sl[_sl])));
2123 double const f_depth( h_rest / m_sipar->EVALIM() * std::max(0.0,
2124 1.0 - std::min((double)m_sipar->EVALIM(),
2125 sc_.depth_sl[_sl] - ( 0.5 * sc_.h_sl[_sl]))
2126 / m_sipar->EVALIM()));
2127 double const soilevaporation_max( cbm::bound_max( f_water * wc_.wc_sl[_sl] * sc_.h_sl[_sl], hr_pot_evapotrans));
2128
2129 double const soilevaporation( cbm::bound( 0.0,
2130 hr_pot_evapotrans * f_depth * f_water,
2131 soilevaporation_max));
2132
2133 //update of the current soil layer water content
2134 wc_.wc_sl[_sl] -= soilevaporation / sc_.h_sl[_sl];
2135 wc_.accumulated_soilevaporation += soilevaporation;
2136 hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - soilevaporation);
2137 }
2138}

References SoilWaterEvaporation().

Referenced by CalcSoilEvapoPercolation(), CalcTranspiration(), and SoilWaterEvaporation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WatercycleDNDC_preferential_flow()

void ldndc::WatercycleDNDC::WatercycleDNDC_preferential_flow ( )
private
Parameters
[in]None
[out]None
Returns
None
2481{
2482 //BY_PASSF is defined as the fraction of surface water that passes per hour (0.0 by default)
2483 if ( cbm::flt_greater_zero(m_sipar->BY_PASSF()) &&
2484 cbm::flt_greater_zero( wc_.surface_water))
2485 {
2486
2487 double water_def_total( 0.0);
2488 for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2489 {
2490 //water flux that flow through macro pores can maximally store
2491 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]);
2492 }
2493
2494 //duration of timestep (hr-1)
2495 double const fhr( get_time_step_duration());
2496
2497
2498 //fraction of surface water that is put into bypass flow (m timestep-1)
2499 double const bypass_fraction( cbm::bound_max(m_sipar->BY_PASSF() * fhr, 0.99));
2500 double const bypass_water( wc_.surface_water * bypass_fraction);
2501 wc_.surface_water -= bypass_water;
2502 wc_.accumulated_infiltration += bypass_water;
2503
2504 if ( cbm::flt_greater_equal( water_def_total, bypass_water))
2505 {
2506
2507 for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2508 {
2509 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]));
2510 double const water_add( water_def / water_def_total * bypass_water);
2511
2512 wc_.wc_sl[sl] += water_add / sc_.h_sl[sl];
2513 }
2514 }
2515 else
2516 {
2517 for ( size_t sl = 0; sl < m_soillayers->soil_layer_cnt(); ++sl)
2518 {
2519 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]));
2520 wc_.wc_sl[sl] += water_def / sc_.h_sl[sl];
2521 }
2522 /* add surplus to percolation out of last soil layer */
2523 wc_.accumulated_percolation += bypass_water - water_def_total;
2524 wc_.accumulated_waterflux_sl[m_soillayers->soil_layer_cnt()-1] += bypass_water - water_def_total;
2525 }
2526 }
2527}

References get_time_step_duration(), and WatercycleDNDC_preferential_flow().

Referenced by CalcTranspiration(), solve(), and WatercycleDNDC_preferential_flow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ 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

2390{
2391 double const sks( WaterFlowSaturated( _sl, _fact_impedance));
2392 double const fsl( get_fsl( _sl));
2393 double const fhr( get_time_step_duration());
2394
2396 double slope(( _sl < m_soillayers->soil_layers_in_litter_cnt()) ? m_sipar->SLOPE_FF() : m_sipar->SLOPE_MS());
2397
2398 double const travel_time( 1.0 - log10( wc_.sks_sl[_sl] * cbm::M_IN_CM * cbm::MIN_IN_DAY * fhr));
2399 double const travel_time_factor( cbm::flt_greater_zero( travel_time) ? (1.0 - exp(-1.0 / travel_time)) : 1.0);
2400 return cbm::bound_max( cbm::sqr(1.0 - (wc_.wc_fc_sl[_sl] / ((wc_.wc_sl[_sl] + wc_.ice_sl[_sl]) * slope)))
2401 * wc_.wc_sl[_sl] * sc_.h_sl[_sl] * fsl * travel_time_factor * _fact_impedance,
2402 sks);
2403}
double get_fsl(size_t)
Returns factor accounting for soil layer depth. Originally, a constant soil layer depth of 0....
Definition watercycle-dndc.cpp:2563

References get_fsl(), get_time_step_duration(), and WaterFlowAboveFieldCapacity().

Referenced by CalcSoilEvapoPercolation(), CalcTranspiration(), and WaterFlowAboveFieldCapacity().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ IMAX_W

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

number of iteration steps within a day

◆ rainfall_intensity_cache

double ldndc::WatercycleDNDC::rainfall_intensity_cache
private

rainfall intensity (constant during a run), cached on first use (negative: not yet read) [m h-1]

Referenced by rainfall_intensity().