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
 

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.

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

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

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

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
537{
538 // Daily evaportation demand is derived from the Thornthwaite, the Penman, or the Priestley-Taylor method (standard is 'thornthwaite).
539 day_potevapo = 0.0;
540 if ( m_cfg.potentialevapotranspiration_method == "thornthwaite")
541 {
542 if ( lclock()->is_position( TMODE_PRE_YEARLY))
543 {
545 lclock()->days_in_year(),
546 m_climate->annual_temperature_average(),
547 m_climate->annual_temperature_amplitude());
548 }
549
550 double const daylength(ldndc::meteo::daylength(m_setup->latitude(), lclock()->yearday()));
551 double const avg_dayl(12.0);
552
553 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
555 mc_.nd_airtemperature,
556 daylength, avg_dayl, lclock()->days_in_month(),
558 }
559 else if ( (m_cfg.potentialevapotranspiration_method == "penman") ||
560 (m_cfg.potentialevapotranspiration_method == "priestleytaylor"))
561 {
562 cbm::sclock_t const & clk( lclock_ref());
563
564 /* vapour pressure [10^3:Pa] */
565 double vps( 0.0);
566 ldndc::meteo::vps( mc_.nd_airtemperature, &vps);
567 double vp( vps - m_climate->vpd_day( clk));
568
569 if( m_cfg.potentialevapotranspiration_method == "priestleytaylor")
570 {
571 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
572 * ldndc::priestleytaylor( clk.yearday(),
573 clk.days_in_year(),
574 mc_.albedo,
575 m_setup->latitude(),
576 mc_.nd_airtemperature,
577 mc_.nd_shortwaveradiation_in,
578 vp,
579 m_sipar->PT_ALPHA());
580 }
581 else if( m_cfg.potentialevapotranspiration_method == "penman")
582 {
583 /* leaf area index */
584 double const lai( m_veg->lai());
585 ldndc::surface_type surface( cbm::flt_greater_zero( lai) ? short_grass : bare_soil);
586
587 day_potevapo = m_sipar->WCDNDC_INCREASE_POT_EVAPOTRANS()
588 * ldndc::penman( surface,
589 clk.yearday(),
590 clk.days_in_year(),
591 mc_.albedo,
592 m_setup->latitude(),
593 mc_.nd_shortwaveradiation_in * cbm::SEC_IN_DAY,
594 mc_.nd_airtemperature,
595 mc_.nd_windspeed,
596 vp);
597 }
598 }
599 else
600 {
601 KLOGERROR("[BUG] huh : it seems that this potentialevapotranspiration method is not registered",
602 "tell the maintainers refering to this error message");
603 return LDNDC_ERR_FAIL;
604 }
605
606 // The daily evaporation demand is distributed throughout the day (standard is 'previouspattern)
607 // TODO: design a routine that distributes evaporation demand according to temperature or humidity
608 if ( m_cfg.evapotranspiration_method == "uniform")
609 {
610 // hourly evaporation demand is calculated from daily demand equally throughout the day
611 hr_pot_evapotrans = day_potevapo * nhr / cbm::HR_IN_DAY;
612 }
613 else if ( m_cfg.evapotranspiration_method == "previouspattern")
614 {
615 // hourly evaporation demand is derived from the weighted expression of previous values
616 hr_pot_evapotrans = day_potevapo * pot_evapotranspiration_ts[lclock()->subday()-1] / nwc;
617 }
618 else if (m_cfg.evapotranspiration_method == "daytimeonly")
619 {
620 // hourly evaporation demand is distributed throughout the sunlight hours only (similar as radiation)
621 double const hour(lclock()->subday());
622 double const day(lclock()->yearday());
623 double const hsun(0.833 * cbm::PI / 180.0);
624 double const lat(m_setup->latitude() * cbm::PI / 180.0);
625 double const dec(-23.44 * (cbm::PI / 180.0) * std::cos(2.0 * cbm::PI * (day - 172.0) / lclock()->days_in_year()));
626 double const help((std::sin(hsun) - std::sin(lat) * std::sin(dec)) / (std::cos(lat) * std::cos(dec)));
627 double dayl(0.0);
628 if (help < -0.999) dayl = 0.0;
629 else if (help > 0.999) dayl = 24.0;
630 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)));
631 if (dayl < 1.0) dayl = 0.0;
632 double const rise(12.0 - dayl * 0.5);
633
634 double factor(0.0);
635 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);
636
637 double fday(0.0);
638 if (hour > rise && hour < (24.0 - rise)) fday = factor;
639
640 hr_pot_evapotrans = day_potevapo * fday;
641 }
642 else
643 {
644 KLOGERROR("[BUG] huh : it seems that this evapotranspiration method option is not registered ",
645 "tell the maintainers refering to this error message");
646 return LDNDC_ERR_FAIL;
647 }
648
649 // the evaporation limit for all timesteps is the daily demand
650 wc_.accumulated_potentialevaporation += hr_pot_evapotrans;
651
652 return LDNDC_ERR_OK;
653}
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
2037{
2038 //Average limit of snowEvaporation is 0.00013m day-1 (Granger and Male 1978)
2039 double hr_potESnow( cbm::bound(0.0, hr_pot_evapotrans, 0.00013 * nhr/24.0));
2040
2041 if ( cbm::flt_greater_zero( wc_.surface_ice) &&
2042 cbm::flt_greater_zero( hr_potESnow))
2043 {
2044 //If there is a snowpack and there is a potential to evaporate
2045 if ( wc_.surface_ice > hr_potESnow)
2046 {
2047 //Partial evaporation from the snow
2048 hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - hr_potESnow);
2049 wc_.accumulated_surfacewaterevaporation += hr_potESnow;
2050 wc_.surface_ice -= hr_potESnow;
2051 }
2052 else
2053 {
2054 //Total evaporation of the snowpack
2055 hr_pot_evapotrans = cbm::bound_min( 0.0, hr_pot_evapotrans - wc_.surface_ice);;
2056 wc_.accumulated_surfacewaterevaporation += wc_.surface_ice;
2057 wc_.surface_ice = 0.0;
2058 }
2059 }
2060}

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

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
2587{
2588 if ( cbm::flt_greater_zero( m_eventflood.get_bund_height()))
2589 {
2590 if ( cbm::flt_greater( wc_.surface_water, m_eventflood.get_bund_height()))
2591 {
2592 wc_.accumulated_runoff += wc_.surface_water - m_eventflood.get_bund_height();
2593 wc_.surface_water = m_eventflood.get_bund_height();
2594 }
2595 }
2596 else
2597 {
2598 /* runoff fraction per time step equals RO fraction per hour * length of a time step */
2599 double const runoff_fraction(m_sipar->FRUNOFF() * get_time_step_duration());
2600
2601 // - not all surface water is removed within one timestep
2602 if ( cbm::flt_less( runoff_fraction, 1.0))
2603 {
2604 double const runoff( runoff_fraction * wc_.surface_water);
2605 wc_.surface_water -= runoff;
2606 wc_.accumulated_runoff += runoff;
2607 }
2608 // - all surface water is immediatly removed
2609 else
2610 {
2611 wc_.accumulated_runoff += wc_.surface_water;
2612 wc_.surface_water = 0.0;
2613 }
2614 }
2615}
double get_time_step_duration()
Time fraction with regard to daily rates.
Definition watercycle-dndc.cpp:2662

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
2006{
2007 if ( cbm::flt_greater_zero( wc_.surface_water) &&
2008 cbm::flt_greater_zero( hr_pot_evapotrans))
2009 {
2010 if ( hr_pot_evapotrans > wc_.surface_water)
2011 {
2012 wc_.accumulated_surfacewaterevaporation += wc_.surface_water;
2013 hr_pot_evapotrans -= wc_.surface_water;
2014 wc_.surface_water = 0.0;
2015 }
2016 else
2017 {
2018 wc_.surface_water -= hr_pot_evapotrans;
2019 wc_.accumulated_surfacewaterevaporation += hr_pot_evapotrans;
2020 hr_pot_evapotrans = 0.0;
2021 }
2022 }
2023}

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

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
775{
776 lerr_t rc = m_eventflood.solve();
777 if ( rc != LDNDC_ERR_OK)
778 {
779 KLOGERROR("Irrigation event not successful!");
780 return rc;
781 }
782
783 /* max_percolation is gradually decreased after end of flooding event to inital value */
784 double const maximum_percolation = m_eventflood.get_maximum_percolation();
785 if ( cbm::is_valid( maximum_percolation))
786 {
787 if ( cbm::flt_greater_zero( maximum_percolation))
788 {
789 max_percolation = maximum_percolation * nhr / 24.0;
790 }
791 }
792 else
793 {
794 /* time rate for gradual recovery of max_percolation */
795 double const time_rate( get_time_step_duration() * 0.1);
796 max_percolation -= (max_percolation - WaterFlowSaturated( m_soillayers->soil_layer_cnt()-1, 1.0)) * time_rate;
797 }
798
799 return LDNDC_ERR_OK;
800}

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

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

104{
105 if ( m_iokcomm->get_input_class< input_class_climate_t >())
106 {
107 return m_iokcomm->get_input_class< climate::input_class_climate_t >()->station_info()->rainfall_intensity * cbm::M_IN_MM;
108 }
109 else
110 {
111 return ldndc::climate::climate_info_defaults.rainfall_intensity * cbm::M_IN_MM;
112 }
113}
double rainfall_intensity
Definition climatetypes.h:40

References rainfall_intensity().

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

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

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

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

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