LCOV - code coverage report
Current view: top level - mRM - mo_mrm_riv_temp_class.f90 (source / functions) Hit Total Coverage
Test: mHM coverage Lines: 237 248 95.6 %
Date: 2025-10-15 15:00:58 Functions: 17 19 89.5 %

          Line data    Source code
       1             : !> \file    mo_mrm_riv_temp_class.f90
       2             : !> \brief   \copybrief mo_mrm_riv_temp_class
       3             : !> \details \copydetails mo_mrm_riv_temp_class
       4             : 
       5             : !> \brief   Class for the river temperature calculations
       6             : !> \details River temperature routing on top of mRM.
       7             : !> \warning This feature is still experimental! River freezing is still missing.
       8             : !> \version 0.1
       9             : !> \authors Sebastian Mueller
      10             : !> \date    Sep 2020
      11             : !> \copyright Copyright 2005-\today, the mHM Developers, Luis Samaniego, Sabine Attinger: All rights reserved.
      12             : !! mHM is released under the LGPLv3+ license \license_note
      13             : !> \ingroup f_mrm
      14             : module mo_mrm_riv_temp_class
      15             : 
      16             :   use mo_kind, only: dp, i4
      17             : 
      18             :   implicit none
      19             : 
      20             :   private
      21             : 
      22             :   !> \class   riv_temp_type
      23             :   !> \brief   This is a container to define the river temperature routing in the current time step
      24             :   !> \details This class provides all procedures to rout river tmperature through the river network.
      25             :   !> \warning This feature is still experimental!
      26             :   !!          This first version doesn't provide ice covering, which means, that the river temperature
      27             :   !!          can drop below 0 [deg C] in winter.
      28             :   type, public :: riv_temp_type
      29             :     ! config settings
      30             :     logical :: active = .false. !< state if this process is active
      31             :     integer(i4) :: case = 0_i4 !< the selected process-case option
      32             :     character(256) :: nml_name = 'config_riv_temp' !< namelist name in mhm namelist
      33             :     ! riv geometry
      34             :     character(256), dimension(:), allocatable :: dir_riv_widths !< Directory where river widths are stored
      35             :     character(256) :: riv_widths_file !< file name for river widths
      36             :     character(256) :: riv_widths_name !< variable name for river widths
      37             :     real(dp), public, dimension(:), allocatable :: L11_riv_widths !< river widths in L11
      38             :     real(dp), public, dimension(:), allocatable :: L11_riv_areas !< river area in L11
      39             :     ! PET related vars
      40             :     real(dp) :: albedo_water !< albedo of open water
      41             :     real(dp) :: pt_a_water   !< priestley taylor alpha parameter for PET on open water
      42             :     ! sensible heat flux related
      43             :     real(dp) :: emissivity_water   !< emissivity of water
      44             :     real(dp) :: turb_heat_ex_coeff !< lateral heat exchange coefficient water <-> air
      45             :     !> cutoff value for temperature
      46             :     real(dp) :: delta_T = 0.1_dp
      47             :     ! controlling variables for iterative solver
      48             :     integer(i4) :: max_iter  !< input: maximal number of iterations done
      49             :     real(dp) :: delta_iter   !< input: convergence criteria for iterative solver
      50             :     real(dp) :: step_iter    !< input: step-size for linear search
      51             :     logical :: first_iter    !< whether it is at the first iteration (to determine search direction)
      52             :     logical :: up_iter       !< whether the search direction is upwards
      53             :     logical :: bisect_iter   !< whether to do the bisection search part (after the interval is found)
      54             :     real(dp) :: up_bnd_iter  !< upper bound for the current bisection step
      55             :     real(dp) :: low_bnd_iter !< lower bound for the current bisection step
      56             :     ! accumulated later fluxes (in current time-step)
      57             :     real(dp), dimension(:), allocatable :: L1_runoff_E !< runoff energy at L1 level
      58             :     real(dp), dimension(:), allocatable :: L1_acc_ssrd !< accumulated shortwave radiation at L1 level
      59             :     real(dp), dimension(:), allocatable :: L1_acc_strd !< accumulated longwave radiation at L1 level
      60             :     real(dp), dimension(:), allocatable :: L1_acc_temp !< accumulated air temperature at L1 level
      61             :     real(dp), dimension(:), allocatable :: L1_ssrd_calc !< current shortwave radiation at L1 level
      62             :     real(dp), dimension(:), allocatable :: L1_strd_calc !< current longwave radiation at L1 level
      63             :     real(dp), dimension(:), allocatable :: L1_tann_calc !< current mean air temperature at L1 level
      64             :     integer(i4) :: ts_cnt !< sub time-step counter for accumulation of meteo
      65             :     ! vars for routing
      66             :     integer(i4) :: s11 !< starting index for current L11 domain
      67             :     integer(i4) :: e11 !< ending index for current L11 domain
      68             :     real(dp), dimension(:,:), allocatable :: netNode_E_IN !< Total energy inputs at t-1 and t
      69             :     real(dp), dimension(:,:), allocatable :: netNode_E_R  !< energy leaving at t-1 and t
      70             :     real(dp), dimension(:), allocatable :: netNode_E_mod  !< Simulated routed energy
      71             :     real(dp), dimension(:), allocatable :: netNode_E_out  !< total energy source from cell in L11
      72             :     real(dp), dimension(:), allocatable :: L11_srad_net   !< net short wave radiation at L11
      73             :     real(dp), dimension(:), allocatable :: L11_lrad_in    !< incoming long wave radiation at L11
      74             :     real(dp), dimension(:), allocatable :: L11_air_temp   !< air temp at L11
      75             :     ! variable containing river temp for each domain at L11 level
      76             :     real(dp), dimension(:), allocatable :: river_temp !< resulting river temp at L11 in [deg C]
      77             :   contains
      78             :     ! config and inits
      79             :     !> \copydoc mo_mrm_riv_temp_class::config
      80             :     procedure :: config !< \see mo_mrm_riv_temp_class::config
      81             :     !> \copydoc mo_mrm_riv_temp_class::init
      82             :     procedure :: init !< \see mo_mrm_riv_temp_class::init
      83             :     !> \copydoc mo_mrm_riv_temp_class::init_area
      84             :     procedure :: init_area !< \see mo_mrm_riv_temp_class::init_area
      85             :     !> \copydoc mo_mrm_riv_temp_class::init_riv_temp
      86             :     procedure :: init_riv_temp !< \see mo_mrm_riv_temp_class::init_riv_temp
      87             : 
      88             :     ! source accumulations
      89             :     !> \copydoc mo_mrm_riv_temp_class::acc_source_e
      90             :     procedure :: acc_source_E !< \see mo_mrm_riv_temp_class::acc_source_e
      91             :     !> \copydoc mo_mrm_riv_temp_class::finalize_source_e
      92             :     procedure :: finalize_source_E !< \see mo_mrm_riv_temp_class::finalize_source_e
      93             : 
      94             :     ! temp-energy routing routines
      95             :     !> \copydoc mo_mrm_riv_temp_class::get_lrad_out
      96             :     procedure :: get_lrad_out !< \see mo_mrm_riv_temp_class::get_lrad_out
      97             :     !> \copydoc mo_mrm_riv_temp_class::get_lat_heat
      98             :     procedure :: get_lat_heat !< \see mo_mrm_riv_temp_class::get_lat_heat
      99             :     !> \copydoc mo_mrm_riv_temp_class::get_sens_heat
     100             :     procedure :: get_sens_heat !< \see mo_mrm_riv_temp_class::get_sens_heat
     101             :     !> \copydoc mo_mrm_riv_temp_class::get_e_io
     102             :     procedure :: get_E_IO !< \see mo_mrm_riv_temp_class::get_e_io
     103             :     !> \copydoc mo_mrm_riv_temp_class::l11_routing_e
     104             :     procedure :: L11_routing_E !< \see mo_mrm_riv_temp_class::l11_routing_e
     105             : 
     106             :     ! helper for iterative solver
     107             :     !> \copydoc mo_mrm_riv_temp_class::init_iter
     108             :     procedure :: init_iter !< \see mo_mrm_riv_temp_class::init_iter
     109             :     !> \copydoc mo_mrm_riv_temp_class::next_iter
     110             :     procedure :: next_iter !< \see mo_mrm_riv_temp_class::next_iter
     111             : 
     112             :     ! care taker
     113             :     !> \copydoc mo_mrm_riv_temp_class::reset_timestep
     114             :     procedure :: reset_timestep !< \see mo_mrm_riv_temp_class::reset_timestep
     115             :     !> \copydoc mo_mrm_riv_temp_class::alloc_lateral
     116             :     procedure :: alloc_lateral !< \see mo_mrm_riv_temp_class::alloc_lateral
     117             :     !> \copydoc mo_mrm_riv_temp_class::dealloc_lateral
     118             :     procedure :: dealloc_lateral !< \see mo_mrm_riv_temp_class::dealloc_lateral
     119             :     !> \copydoc mo_mrm_riv_temp_class::clean_up
     120             :     procedure :: clean_up !< \see mo_mrm_riv_temp_class::clean_up
     121             : 
     122             :   end type riv_temp_type
     123             : 
     124             : contains
     125             : 
     126             : 
     127             :   !> \brief clean up
     128          14 :   subroutine clean_up( &
     129             :     self &
     130             :   )
     131             :     implicit none
     132             : 
     133             :     class(riv_temp_type), intent(inout) :: self
     134             : 
     135           0 :     if ( allocated(self%L1_runoff_E) ) deallocate(self%L1_runoff_E)
     136          14 :     if ( allocated(self%L1_acc_strd) ) deallocate(self%L1_acc_strd)
     137          14 :     if ( allocated(self%L1_acc_ssrd) ) deallocate(self%L1_acc_ssrd)
     138          14 :     if ( allocated(self%L1_acc_temp) ) deallocate(self%L1_acc_temp)
     139          14 :     if ( allocated(self%dir_riv_widths) ) deallocate(self%dir_riv_widths)
     140          14 :     if ( allocated(self%L11_riv_widths) ) deallocate(self%L11_riv_widths)
     141          14 :     if ( allocated(self%L11_riv_areas) ) deallocate(self%L11_riv_areas)
     142          14 :     if ( allocated(self%netNode_E_IN) ) deallocate(self%netNode_E_IN)
     143          14 :     if ( allocated(self%netNode_E_R) ) deallocate(self%netNode_E_R)
     144          14 :     if ( allocated(self%netNode_E_mod) ) deallocate(self%netNode_E_mod)
     145          14 :     if ( allocated(self%netNode_E_out) ) deallocate(self%netNode_E_out)
     146          14 :     if ( allocated(self%L11_srad_net) ) deallocate(self%L11_srad_net)
     147          14 :     if ( allocated(self%L11_lrad_in) ) deallocate(self%L11_lrad_in)
     148          14 :     if ( allocated(self%L11_air_temp) ) deallocate(self%L11_air_temp)
     149          14 :     if ( allocated(self%river_temp) ) deallocate(self%river_temp)
     150             :     ! meteo arrays
     151          14 :     if ( allocated(self%L1_ssrd_calc) ) deallocate(self%L1_ssrd_calc)
     152          14 :     if ( allocated(self%L1_strd_calc) ) deallocate(self%L1_strd_calc)
     153          14 :     if ( allocated(self%L1_tann_calc) ) deallocate(self%L1_tann_calc)
     154             : 
     155          14 :   end subroutine clean_up
     156             : 
     157             :   !> \brief configure the \ref riv_temp_type class from the mhm namelist
     158           1 :   subroutine config( &
     159             :     self, &
     160             :     file_namelist, &
     161             :     file_namelist_param &
     162             :   )
     163             : 
     164          14 :     use mo_common_constants, only : maxNoDomains, nodata_i4
     165             :     use mo_common_variables, only : domainMeta
     166             :     use mo_check, only : check_dir
     167             :     USE mo_string_utils, ONLY : num2str
     168             :     use mo_namelists, only : nml_config_riv_temp
     169             : 
     170             :     implicit none
     171             : 
     172             :     class(riv_temp_type), intent(inout) :: self
     173             :     character(*), intent(in) :: file_namelist !< mhm namelist file
     174             :     character(*), intent(in) :: file_namelist_param !< mhm parameter namelist file
     175             : 
     176             :     integer(i4) :: iDomain, domainID
     177             : 
     178             :     ! allocate the directory arrays
     179           3 :     allocate(self%dir_riv_widths(domainMeta%nDomains))
     180             : 
     181           1 :     call nml_config_riv_temp%read(file_namelist)
     182           1 :     self%albedo_water = nml_config_riv_temp%albedo_water
     183           1 :     self%pt_a_water = nml_config_riv_temp%pt_a_water
     184           1 :     self%emissivity_water = nml_config_riv_temp%emissivity_water
     185           1 :     self%turb_heat_ex_coeff = nml_config_riv_temp%turb_heat_ex_coeff
     186           1 :     self%delta_iter = nml_config_riv_temp%delta_iter
     187           1 :     self%max_iter = nml_config_riv_temp%max_iter
     188           1 :     self%step_iter = nml_config_riv_temp%step_iter
     189           1 :     self%riv_widths_file = nml_config_riv_temp%riv_widths_file
     190           1 :     self%riv_widths_name = nml_config_riv_temp%riv_widths_name
     191           3 :     self%dir_riv_widths = nml_config_riv_temp%dir_riv_widths(1:domainMeta%nDomains)
     192             : 
     193           2 :     do iDomain = 1, domainMeta%nDomains
     194           1 :       domainID = domainMeta%indices(iDomain)
     195             :       call check_dir( &
     196           0 :         path=self%dir_riv_widths(iDomain), &
     197             :         text="(domain "//trim(num2str(domainID,'(I3)'))//") River widths directory:", &
     198             :         raise=.true., &
     199             :         tab=4, &
     200             :         text_length=40 &
     201           2 :       )
     202             :     end do
     203             : 
     204           1 :   end subroutine config
     205             : 
     206             :   !> \brief initalize the \ref riv_temp_type class for the current domain
     207           1 :   subroutine init( &
     208             :     self, &
     209             :     nCells &
     210             :   )
     211           1 :     use mo_append, only : append
     212             :     use mo_mrm_constants, only : nRoutingStates
     213             :     ! use mo_common_variables, only : level0, domainMeta
     214             : 
     215             :     implicit none
     216             : 
     217             :     class(riv_temp_type), intent(inout) :: self
     218             :     integer(i4), intent(in) :: nCells !< number of level-11 cells for the current domain
     219             : 
     220           1 :     real(dp), dimension(:), allocatable :: dummy_Vector11
     221           1 :     real(dp), dimension(:, :), allocatable :: dummy_Matrix11_IT
     222             : 
     223             :     ! dummy vector and matrix
     224           3 :     allocate(dummy_Vector11   (nCells))
     225           3 :     allocate(dummy_Matrix11_IT(nCells, nRoutingStates))
     226          35 :     dummy_Vector11(:) = 0.0_dp
     227          71 :     dummy_Matrix11_IT(:, :) = 0.0_dp
     228             : 
     229             :     ! simulated energy flux at each node
     230           1 :     call append(self%netNode_E_mod, dummy_Vector11)
     231             :     ! simulated river temperature at each node
     232           1 :     call append(self%river_temp, dummy_Vector11)
     233             :     ! Total outflow from cells L11 at time tt
     234           1 :     call append(self%netNode_E_out, dummy_Vector11)
     235             :     ! Total discharge inputs at t-1 and t
     236           1 :     call append(self%netNode_E_IN, dummy_Matrix11_IT)
     237             :     !  Routed outflow leaving a node
     238           1 :     call append(self%netNode_E_R, dummy_Matrix11_IT)
     239             : 
     240             :     ! free space
     241           1 :     deallocate(dummy_Vector11)
     242           1 :     deallocate(dummy_Matrix11_IT)
     243             : 
     244           1 :   end subroutine init
     245             : 
     246             :   !> \brief initialize the river area of \ref riv_temp_type class for the current domain
     247           1 :   subroutine init_area( &
     248             :     self, &
     249             :     iDomain, &
     250           2 :     L11_netPerm, &
     251           1 :     L11_fromN, &
     252           1 :     L11_length, &
     253             :     nLinks, &
     254             :     nCells, &
     255             :     nrows, &
     256             :     ncols, &
     257           1 :     L11_mask &
     258             :   )
     259           1 :     use mo_append, only : append
     260             :     use mo_read_nc, only: read_const_nc
     261             : 
     262             :     implicit none
     263             : 
     264             :     class(riv_temp_type), intent(inout) :: self
     265             :     integer(i4), intent(in) :: iDomain !< Domain ID
     266             :     integer(i4), dimension(:), intent(in) :: L11_netPerm !< L11 routing order
     267             :     integer(i4), dimension(:), intent(in) :: L11_fromN !< L11 source grid cell order
     268             :     real(dp), dimension(:), intent(in) :: L11_length !< L11 link length
     269             :     integer(i4), intent(in) :: nLinks !< number of L11 links in the current domain
     270             :     integer(i4), intent(in) :: nCells !< number of L11 cells of the current domain
     271             :     integer(i4), intent(in) :: ncols  !< Number of columns
     272             :     integer(i4), intent(in) :: nrows  !< Number of rows
     273             :     logical, dimension(:, :), intent(in) :: L11_mask !< the mask for valid cells in the original grid (nrows, ncols)
     274             : 
     275           1 :     real(dp), dimension(:,:), allocatable :: L11_data ! read data from file
     276           1 :     real(dp), dimension(:), allocatable :: L11_riv_widths, L11_riv_areas
     277             : 
     278             :     integer(i4) :: i, k, iNode
     279             : 
     280             :     call read_const_nc(&
     281           0 :       trim(self%dir_riv_widths(iDomain)), &
     282             :       nrows, &
     283             :       ncols, &
     284             :       self%riv_widths_name, &
     285             :       L11_data, &
     286             :       self%riv_widths_file &
     287           1 :     )
     288             : 
     289           3 :     allocate(L11_riv_widths(nCells))
     290           1 :     L11_riv_widths(:) = pack(L11_data(:,:), mask=L11_mask)
     291           1 :     call append(self%L11_riv_widths, L11_riv_widths)
     292             : 
     293           3 :     allocate(L11_riv_areas(nCells))
     294             :     ! at area at Outlet is 0
     295          36 :     L11_riv_areas = 0.0_dp
     296          34 :     do k = 1, nLinks
     297             :       ! get LINK routing order -> i
     298          33 :       i = L11_netPerm(k)
     299          33 :       iNode = L11_fromN(i)
     300          34 :       L11_riv_areas(iNode) = L11_length(i) * L11_riv_widths(iNode)
     301             :     end do
     302           1 :     call append(self%L11_riv_areas, L11_riv_areas)
     303             : 
     304           1 :     deallocate(L11_data)
     305           1 :     deallocate(L11_riv_widths)
     306           1 :     deallocate(L11_riv_areas)
     307             : 
     308           1 :   end subroutine init_area
     309             : 
     310             :   !> \brief initialize the river temperature of \ref riv_temp_type class for the current domain
     311           1 :   subroutine init_riv_temp( &
     312             :     self, &
     313           2 :     temp_air, &
     314           1 :     efecarea, &
     315           1 :     L1_L11_Id, &
     316           1 :     L11_areacell, &
     317           1 :     L11_L1_Id, &
     318             :     map_flag &
     319             :   )
     320             : 
     321           1 :     use mo_mrm_pre_routing, only : L11_meteo_acc
     322             : 
     323             :     implicit none
     324             : 
     325             :     class(riv_temp_type), intent(inout) :: self
     326             :     real(dp), dimension(:), intent(in) :: temp_air !< air temperature [degC] for current timestep
     327             :     real(dp), intent(in), dimension(:) :: efecarea !< effective area in [km2] at Level 1
     328             :     integer(i4), intent(in), dimension(:) :: L1_L11_Id !< L11 Ids mapped on L1
     329             :     real(dp), intent(in), dimension(:) :: L11_areacell !< effective area in [km2] at Level 11
     330             :     integer(i4), intent(in), dimension(:) :: L11_L1_Id !< L1 Ids mapped on L11
     331             :     logical, intent(in) :: map_flag !< Flag indicating whether routing resolution is higher than hydrologic one
     332             : 
     333             :     ! map temperature from L1 to L11
     334             :     call L11_meteo_acc( &
     335           1 :       temp_air, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%river_temp(self%s11 : self%e11))
     336             : 
     337             :     ! assure positive temperature
     338          35 :     self%river_temp(self%s11 : self%e11) = max(self%delta_T, self%river_temp(self%s11 : self%e11))
     339             : 
     340           1 :   end subroutine init_riv_temp
     341             : 
     342             :   !> \brief reset \ref riv_temp_type class for next timestep
     343        6553 :   subroutine reset_timestep(self)
     344             :     implicit none
     345             : 
     346             :     class(riv_temp_type), intent(inout) :: self
     347             : 
     348             :     ! set sub time-step counter to 0
     349        6553 :     self%ts_cnt = 0_i4
     350             : 
     351      229355 :     self%L1_runoff_E = 0.0_dp
     352      235908 :     self%L1_acc_strd = 0.0_dp
     353      235908 :     self%L1_acc_ssrd = 0.0_dp
     354      235908 :     self%L1_acc_temp = 0.0_dp
     355             : 
     356           1 :   end subroutine reset_timestep
     357             : 
     358             :   !> \brief allocate lateral temp components of \ref riv_temp_type class for current domain
     359           1 :   subroutine alloc_lateral( &
     360             :     self, &
     361             :     nCells &
     362             :   )
     363             :     implicit none
     364             : 
     365             :     class(riv_temp_type), intent(inout) :: self
     366             :     integer(i4), intent(in) :: nCells !< number of level-1 cells for the current domain
     367             : 
     368           3 :     allocate(self%L1_runoff_E(nCells))
     369           3 :     allocate(self%L1_acc_strd(nCells))
     370           3 :     allocate(self%L1_acc_ssrd(nCells))
     371           3 :     allocate(self%L1_acc_temp(nCells))
     372             :     ! meteo arrays
     373           3 :     allocate(self%L1_ssrd_calc(nCells))
     374           3 :     allocate(self%L1_strd_calc(nCells))
     375           3 :     allocate(self%L1_tann_calc(nCells))
     376             :     ! init these arrays to 0
     377           1 :     call self%reset_timestep()
     378             : 
     379        6553 :   end subroutine alloc_lateral
     380             : 
     381             :   !> \brief deallocate lateral temp components of \ref riv_temp_type
     382           1 :   subroutine dealloc_lateral( &
     383             :     self &
     384             :   )
     385             :     implicit none
     386             : 
     387             :     class(riv_temp_type), intent(inout) :: self
     388             : 
     389           0 :     deallocate(self%L1_runoff_E)
     390           1 :     deallocate(self%L1_acc_strd)
     391           1 :     deallocate(self%L1_acc_ssrd)
     392           1 :     deallocate(self%L1_acc_temp)
     393           1 :     deallocate(self%L1_ssrd_calc)
     394           1 :     deallocate(self%L1_strd_calc)
     395           1 :     deallocate(self%L1_tann_calc)
     396             : 
     397           1 :   end subroutine dealloc_lateral
     398             : 
     399             :   !> \brief accumulate energy sources of \ref riv_temp_type
     400       13104 :   subroutine acc_source_e( &
     401             :     self, &
     402       26208 :     fSealed_area_fraction, &
     403       13104 :     fast_interflow, &
     404       13104 :     slow_interflow, &
     405       13104 :     baseflow, &
     406       13104 :     direct_runoff, &
     407       13104 :     temp_air &
     408             :   )
     409             : 
     410           1 :     use mo_mrm_pre_routing, only : calc_L1_runoff_E
     411             : 
     412             :     implicit none
     413             : 
     414             :     class(riv_temp_type), intent(inout) :: self
     415             :     real(dp), dimension(:), intent(in) :: fSealed_area_fraction !< sealed area fraction [1]
     416             :     real(dp), dimension(:), intent(in) :: fast_interflow !< \f$ q_0 \f$ Fast runoff component [mm TS-1]
     417             :     real(dp), dimension(:), intent(in) :: slow_interflow !< \f$ q_1 \f$ Slow runoff component [mm TS-1]
     418             :     real(dp), dimension(:), intent(in) :: baseflow !< \f$ q_2 \f$ Baseflow [mm TS-1]
     419             :     real(dp), dimension(:), intent(in) :: direct_runoff !< \f$ q_D \f$ Direct runoff from impervious areas  [mm TS-1]
     420             :     real(dp), dimension(:), intent(in) :: temp_air !< air temperature [K]
     421             : 
     422             :     ! increase the sub time-step counter
     423       13104 :     self%ts_cnt = self%ts_cnt + 1_i4
     424             : 
     425             :     ! caclucate the temperature energy of the runoffs at L1 in [K mm]
     426             :     ! automatically accumulate them
     427             :     call calc_L1_runoff_E( &
     428             :       fSealed_area_fraction, &
     429             :       fast_interflow, slow_interflow, baseflow, direct_runoff, &
     430           0 :       temp_air, self%L1_tann_calc, &
     431           0 :       self%L1_runoff_E & ! will be added here
     432       13104 :     )
     433             :     ! accumulate meteo forcings (will be averaged with sub time-step counter later)
     434      471744 :     self%L1_acc_ssrd = self%L1_acc_ssrd + self%L1_ssrd_calc
     435      471744 :     self%L1_acc_strd = self%L1_acc_strd + self%L1_strd_calc
     436      471744 :     self%L1_acc_temp = self%L1_acc_temp + temp_air
     437             : 
     438       13104 :   end subroutine acc_source_e
     439             : 
     440             :   !> \brief finalize energy sources of \ref riv_temp_type
     441        6552 :   subroutine finalize_source_E( &
     442             :     self, &
     443       13104 :     efecarea, &
     444        6552 :     L1_L11_Id, &
     445        6552 :     L11_areacell, &
     446        6552 :     L11_L1_Id, &
     447             :     timestep, &
     448             :     map_flag &
     449             :   )
     450             : 
     451       13104 :     use mo_mrm_pre_routing, only : L11_meteo_acc, L11_runoff_acc
     452             : 
     453             :     implicit none
     454             : 
     455             :     class(riv_temp_type), intent(inout) :: self
     456             :     !> effective area in [km2] at Level 1
     457             :     real(dp), intent(in), dimension(:) :: efecarea
     458             :     !> L11 Ids mapped on L1
     459             :     integer(i4), intent(in), dimension(:) :: L1_L11_Id
     460             :     !> effective area in [km2] at Level 11
     461             :     real(dp), intent(in), dimension(:) :: L11_areacell
     462             :     !> L1 Ids mapped on L11
     463             :     integer(i4), intent(in), dimension(:) :: L11_L1_Id
     464             :     !> simulation timestep in [h]
     465             :     integer(i4), intent(in) :: timestep
     466             :     !> Flag indicating whether routing resolution is higher than hydrologic one
     467             :     logical, intent(in) :: map_flag
     468             : 
     469             :     ! prepare temporal variables for temp-routing
     470        6552 :     if ( allocated(self%L11_srad_net) ) deallocate(self%L11_srad_net)
     471        6552 :     if ( allocated(self%L11_lrad_in) ) deallocate(self%L11_lrad_in)
     472        6552 :     if ( allocated(self%L11_air_temp) ) deallocate(self%L11_air_temp)
     473       19656 :     allocate(self%L11_srad_net(size(L11_L1_Id, dim = 1)))
     474       13104 :     allocate(self%L11_lrad_in(size(L11_L1_Id, dim = 1)))
     475       13104 :     allocate(self%L11_air_temp(size(L11_L1_Id, dim = 1)))
     476             : 
     477             :     ! convert the L1 runoff temperature energy from [K mm] to [K m3 s-1] on L11
     478             :     call L11_runoff_acc( &
     479           0 :       self%L1_runoff_E, &
     480             :       efecarea, &
     481             :       L1_L11_Id, &
     482             :       L11_areacell, &
     483             :       L11_L1_Id, &
     484             :       timestep, &
     485             :       map_flag, &
     486           0 :       self%netNode_E_out(self%s11 : self%e11) &
     487        6552 :     )
     488             :     ! all meteo forcings are accumulated over sub time-steps and need to be divided by the sub time-step counter
     489             :     ! short wave radiation on L11
     490      229320 :     self%L1_acc_ssrd = self%L1_acc_ssrd / real(self%ts_cnt, dp)
     491        6552 :     call L11_meteo_acc(self%L1_acc_ssrd, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_srad_net)
     492             :     ! calculate the net-radiation from incoming/outging short radiation
     493      229320 :     self%L11_srad_net = self%L11_srad_net * (1._dp - self%albedo_water)
     494             :     ! long wave radiation on L11
     495      229320 :     self%L1_acc_strd = self%L1_acc_strd / real(self%ts_cnt, dp)
     496        6552 :     call L11_meteo_acc(self%L1_acc_strd, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_lrad_in)
     497             :     ! air temperature on L11
     498      229320 :     self%L1_acc_temp = self%L1_acc_temp / real(self%ts_cnt, dp)
     499        6552 :     call L11_meteo_acc(self%L1_acc_temp, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_air_temp)
     500             : 
     501        6552 :   end subroutine finalize_source_E
     502             : 
     503             :   !> \brief get outgoing longwave radiation of \ref riv_temp_type
     504             :   !> \return outgoing longwave radiation
     505     5550108 :   real(dp) function get_lrad_out(self, riv_temp) result(lrad_out)
     506             : 
     507        6552 :     use mo_constants, only: sigma_dp
     508             : 
     509             :     implicit none
     510             : 
     511             :     class(riv_temp_type), intent(in) :: self
     512             :     !> river temperature in K
     513             :     real(dp), intent(in) :: riv_temp
     514             : 
     515             :     ! outgoing longwave radiation from Boltzmann equation
     516     5550108 :     lrad_out = self%emissivity_water * sigma_dp * riv_temp ** 4_i4
     517             : 
     518     5550108 :   end function get_lrad_out
     519             : 
     520             :   !> \brief latent heat flux of \ref riv_temp_type
     521             :   !> \return latent heat flux
     522     5550108 :   real(dp) function get_lat_heat(self, air_temp, netrad) result(lat_heat)
     523             : 
     524     5550108 :     use mo_constants, only : Psychro_dp
     525             :     use mo_pet, only : slope_satpressure
     526             : 
     527             :     implicit none
     528             : 
     529             :     class(riv_temp_type), intent(in) :: self
     530             :     !> air temperature in deg C
     531             :     real(dp), intent(in) :: air_temp
     532             :     !> net radiation in W * m-2
     533             :     real(dp), intent(in) :: netrad
     534             : 
     535             :     ! save slope of saturation vapor pressure curve
     536     5550108 :     real(dp) :: delta
     537             : 
     538     5550108 :     delta = slope_satpressure(air_temp) ! slope of saturation vapor pressure curve
     539             :     ! latent heat for priestley taylor PET formula
     540     5550108 :     lat_heat = self%pt_a_water * delta / (Psychro_dp + delta) * max(netrad, 0._dp)
     541             : 
     542     5550108 :   end function get_lat_heat
     543             : 
     544             :   !> \brief sensible heat flux of \ref riv_temp_type
     545             :   !> \return sensible heat flux
     546     5550108 :   real(dp) function get_sens_heat(self, air_temp, riv_temp) result(sens_heat)
     547             : 
     548             :     implicit none
     549             : 
     550             :     class(riv_temp_type), intent(in) :: self
     551             :     real(dp), intent(in) :: air_temp !< air temperature in [deg C]
     552             :     real(dp), intent(in) :: riv_temp !< river temperature in [deg C]
     553             : 
     554             :     ! sensible heat flux resulting for temp. diff.: river <-> air
     555     5550108 :     sens_heat = self%turb_heat_ex_coeff * (riv_temp - air_temp)
     556             : 
     557    11100216 :   end function get_sens_heat
     558             : 
     559             :   !> \brief get complete energy source of \ref riv_temp_type at given cell
     560             :   !> \return energy IO
     561     5550108 :   real(dp) function get_E_IO(self, riv_temp, cell) result(E_IO)
     562             : 
     563     5550108 :     use mo_constants, only : T0_dp, cp_w_dp
     564             :     use mo_mhm_constants, only : H2Odens
     565             : 
     566             :     implicit none
     567             : 
     568             :     class(riv_temp_type), intent(in) :: self
     569             :     !> given river temperature in K to calculate heat fluxes
     570             :     real(dp), intent(in) :: riv_temp
     571             :     !> cell index in the current domain
     572             :     integer(i4), intent(in) :: cell
     573             :     !> net radiation calc from short and longwave radiation in/out
     574     5550108 :     real(dp) :: netrad, sens_heat, lat_heat
     575             : 
     576             :     ! net radiation
     577     5550108 :     netrad = self%L11_srad_net(cell) + self%L11_lrad_in(cell) - self%get_lrad_out(riv_temp)
     578             :     ! sensible heat flux
     579     5550108 :     sens_heat = self%get_sens_heat(self%L11_air_temp(cell), riv_temp - T0_dp)
     580             :     ! latent heat flux
     581     5550108 :     lat_heat = self%get_lat_heat(self%L11_air_temp(cell), netrad)
     582             : 
     583             :     ! convert energy flux [W m-2] to [K m s-1]
     584             :     ! needs to be multiplied with river-area to result in temp-energy flux [K m3 s-1]
     585     5550108 :     E_IO = (netrad - sens_heat - lat_heat) / (H2Odens * cp_w_dp)
     586             : 
     587     5550108 :   end function get_E_IO
     588             : 
     589             :   !> \brief execute the temperature routing of \ref riv_temp_type
     590        6552 :   subroutine L11_routing_E( &
     591             :     self, &
     592             :     nLinks, &
     593       13104 :     netPerm, &
     594        6552 :     netLink_fromN, &
     595        6552 :     netLink_toN, &
     596       13104 :     netLink_C1, &
     597        6552 :     netLink_C2, &
     598             :     nInflowGauges, &
     599       13104 :     InflowHeadwater, &
     600        6552 :     InflowNodeList, &
     601        6552 :     sink_cells, &
     602        6552 :     L11_qTR, &
     603        6552 :     L11_Qmod &
     604             :   )
     605     5550108 :     use mo_constants, only : T0_dp
     606             : 
     607             :     implicit none
     608             : 
     609             :     class(riv_temp_type), intent(inout) :: self
     610             :     !> number of stream segment (reaches)
     611             :     integer(i4), intent(in) :: nLinks
     612             :     !> routing order of a given domain (permutation)
     613             :     integer(i4), dimension(:), intent(in) :: netPerm
     614             :     !> from node
     615             :     integer(i4), dimension(:), intent(in) :: netLink_fromN
     616             :     !> to node
     617             :     integer(i4), dimension(:), intent(in) :: netLink_toN
     618             :     !> routing parameter  C1 (\cite CMM1988 p. 25-41)
     619             :     real(dp), dimension(:), intent(in) :: netLink_C1
     620             :     !> routing parameters C2 (id)
     621             :     real(dp), dimension(:), intent(in) :: netLink_C2
     622             :     !> [-]      number of inflow points
     623             :     integer(i4), intent(in) :: nInflowGauges
     624             :     !> [-]      if to consider headwater cells of inflow gauge
     625             :     logical, dimension(:), intent(in) :: InflowHeadwater
     626             :     !> [-]      L11 ID of inflow points
     627             :     integer(i4), dimension(:), intent(in) :: InflowNodeList
     628             :     ! [-]      sink nodes
     629             :     integer(i4), dimension(:), intent(in) :: sink_cells
     630             :     !> [m3 s-1] Transformed outflow leaving node I at current timestep(Muskingum)
     631             :     real(dp), intent(in), dimension(:) :: L11_qTR
     632             :     !> [m3 s-1] Simulated routed discharge
     633             :     real(dp), intent(in), dimension(:) :: L11_Qmod
     634             : 
     635             :     integer(i4) :: i, k, m, iNode, tNode, L11in, L11to
     636        6552 :     real(dp) :: E_IO_in, E_IO, T_est, T_rout
     637             : 
     638             :     ! initialize total input at point time (t+1) in all nodes
     639      229320 :     self%netNode_E_IN(self%s11 : self%e11, 2) = 0.0_dp
     640             : 
     641      222768 :     riv_loop: do k = 1, nLinks
     642             :       ! get LINK routing order -> i
     643      216216 :       i = netPerm(k)
     644      216216 :       iNode = netLink_fromN(i)
     645      216216 :       tNode = netLink_toN(i)
     646             :       ! indices for concaternated domains
     647      216216 :       L11in = iNode + self%s11 - 1_i4
     648      216216 :       L11to = tNode + self%s11 - 1_i4
     649             : 
     650             :       ! accumulate all inputs in iNode
     651      216216 :       self%netNode_E_IN(L11in, 2) = self%netNode_E_IN(L11in, 2) + self%netNode_E_out(L11in)
     652             :       ! calculate the river temp at the upstream node
     653      216216 :       self%river_temp(L11in) = self%netNode_E_IN(L11in, 2) / L11_Qmod(iNode) - T0_dp
     654             : 
     655             :       ! first guess for the routed temperature is the upstream temp
     656      216216 :       T_est = self%river_temp(L11in) + T0_dp
     657             :       ! calculate the meteo energy source at the upstream node
     658      216216 :       E_IO_in = self%get_E_IO(T_est, iNode)
     659             : 
     660             :       ! initialize iteration
     661      216216 :       call self%init_iter()
     662             :       ! perform iteration
     663     5333892 :       iterloop: do m=1, self%max_iter
     664             :         ! meteo energy flux depending on the estimated routed temperature (avg. IN- and OUT-node)
     665     5333892 :         E_IO = (E_IO_in + self%get_E_IO(T_est, tNode)) * 0.5_dp * self%L11_riv_areas(L11in)
     666             :         ! routing iNode
     667     5333892 :         self%netNode_E_R(L11in, 2) = self%netNode_E_R(L11in, 1) &
     668     5333892 :           + netLink_C1(i) * (self%netNode_E_IN(L11in, 1) - self%netNode_E_R(L11in, 1)) &
     669    10667784 :           + netLink_C2(i) * (self%netNode_E_IN(L11in, 2) + E_IO - self%netNode_E_IN(L11in, 1))
     670             :         ! calculate the routed temperature
     671     5333892 :         T_rout = self%netNode_E_R(L11in, 2) / L11_qTR(iNode)
     672             :         ! check for convergence
     673     5333892 :         if ( abs(T_rout - T_est) < self%delta_iter ) exit iterloop
     674             :         ! get new estimate for next iteration
     675     5333892 :         call self%next_iter(T_est, T_rout)
     676             :       end do iterloop
     677             : 
     678             :       ! add the meteo energy flux to the accumulated incoming energy at the IN-node
     679      216216 :       self%netNode_E_IN(L11in, 2) = self%netNode_E_IN(L11in, 2) + E_IO
     680             : 
     681             :       ! check if the inflow from upstream cells should be deactivated
     682      216216 :       if (nInflowGauges .GT. 0) then
     683           0 :         do i = 1, nInflowGauges
     684             :           ! check if downstream Node (tNode) is inflow gauge and headwaters should be ignored
     685           0 :           if ((tNode == InflowNodeList(i)) .AND. (.NOT. InflowHeadwater(i))) &
     686           0 :             self%netNode_E_R(L11in, 2) = 0.0_dp
     687             :         end do
     688             :       end if
     689             : 
     690             :       ! add routed temp energy to downstream node
     691      222768 :       self%netNode_E_IN(L11to, 2) = self%netNode_E_IN(L11to, 2) + self%netNode_E_R(L11in, 2)
     692             : 
     693             :     end do riv_loop
     694             : 
     695             :     ! Accumulate all inputs at sinks
     696             :     ! calculate riv temp at sinks
     697       13104 :     do k = 1, size(sink_cells)
     698        6552 :       tNode = sink_cells(k)
     699        6552 :       L11to = tNode + self%s11 - 1_i4
     700        6552 :       self%netNode_E_IN(L11to, 2) = self%netNode_E_IN(L11to, 2) + self%netNode_E_out(L11to)
     701       13104 :       self%river_temp(L11to) = self%netNode_E_IN(L11to, 2) / L11_Qmod(tNode) - T0_dp
     702             :     end do
     703             : 
     704             :     ! backflow t-> t-1
     705      229320 :     self%netNode_E_R(self%s11 : self%e11, 1) = self%netNode_E_R(self%s11 : self%e11, 2)
     706      229320 :     self%netNode_E_IN(self%s11 : self%e11, 1) = self%netNode_E_IN(self%s11 : self%e11, 2)
     707             : 
     708        6552 :   end subroutine L11_routing_E
     709             : 
     710             :   !> \brief initialize iterative solver of \ref riv_temp_type
     711      216216 :   subroutine init_iter(self)
     712             : 
     713             :     implicit none
     714             : 
     715             :     class(riv_temp_type), intent(inout) :: self
     716             : 
     717             :     ! first iteration is used to determine the search direction for the interval
     718      216216 :     self%first_iter = .true.
     719             :     ! after the interval is found, we will perform a biseciton to nail down the temperature
     720      216216 :     self%bisect_iter = .false.
     721             : 
     722        6552 :   end subroutine init_iter
     723             : 
     724             :   !> \brief execute next iteration with iterative solver of \ref riv_temp_type
     725     5117676 :   subroutine next_iter(self, T_est, T_rout)
     726             : 
     727             :     implicit none
     728             : 
     729             :     class(riv_temp_type), intent(inout) :: self
     730             :     real(dp), intent(inout) :: T_est !< estimated river temperature
     731             :     real(dp), intent(in) :: T_rout !< calculated (routed) river temperature
     732             : 
     733             :     ! before performing a bisection we need to search for the interval (with given step-size)
     734     5117676 :     if ( .not. self%bisect_iter ) then
     735             :       ! to determine the direction of interval search, we have to wait for the first iteration
     736      641761 :       if ( self%first_iter ) then
     737      216216 :         self%first_iter = .false.
     738             :         ! determine search direction
     739      216216 :         self%up_iter = ( T_rout > T_est )
     740             :       end if
     741             :       ! check if we need to take another step
     742      641761 :       if ( self%up_iter .eqv. ( T_rout > T_est ) ) then
     743      425545 :         if ( self%up_iter ) then
     744      203382 :           T_est = T_est + self%step_iter
     745             :         else
     746      222163 :           T_est = T_est - self%step_iter
     747             :         end if
     748             :       ! if direction changes, we have found the interval for bisection
     749             :       else
     750             :         ! start bisection in next iteration
     751      216216 :         self%bisect_iter = .true.
     752             :         ! set interval bounds for bisection
     753      216216 :         if ( self%up_iter ) then
     754      103220 :           self%up_bnd_iter = T_est
     755      103220 :           self%low_bnd_iter = T_est - self%step_iter
     756             :         else
     757      112996 :           self%up_bnd_iter = T_est + self%step_iter
     758      112996 :           self%low_bnd_iter = T_est
     759             :         end if
     760             :         ! set estimation to interval center
     761      216216 :         T_est = (self%up_bnd_iter + self%low_bnd_iter) / 2.0_dp
     762             :       end if
     763             :     ! perform bisection
     764             :     else
     765             :       ! if routed temp is lower than estimated, use lower interval
     766     4475915 :       if ( T_rout < T_est ) then
     767     2233019 :         self%up_bnd_iter = T_est
     768             :       ! if routed temp is higher than estimated, use upper interval
     769             :       else
     770     2242896 :         self%low_bnd_iter = T_est
     771             :       end if
     772             :       ! set estimation to interval center
     773     4475915 :       T_est = (self%up_bnd_iter + self%low_bnd_iter) / 2.0_dp
     774             :     end if
     775             : 
     776     5333892 :   end subroutine next_iter
     777             : 
     778     5117676 : end module mo_mrm_riv_temp_class

Generated by: LCOV version 1.16