LCOV - code coverage report
Current view: top level - mRM - mo_mrm_riv_temp_class.f90 (source / functions) Hit Total Coverage
Test: mHM coverage Lines: 251 262 95.8 %
Date: 2024-04-15 17:48:09 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             :     unamelist, &
     162             :     file_namelist_param, &
     163             :     unamelist_param &
     164             :   )
     165             : 
     166          14 :     use mo_common_constants, only : maxNoDomains, nodata_i4
     167             :     use mo_common_variables, only : domainMeta
     168             :     use mo_nml, only : close_nml, open_nml, position_nml
     169             :     use mo_check, only : check_dir
     170             :     USE mo_string_utils, ONLY : num2str
     171             : 
     172             :     implicit none
     173             : 
     174             :     class(riv_temp_type), intent(inout) :: self
     175             :     character(*), intent(in) :: file_namelist !< mhm namelist file
     176             :     character(*), intent(in) :: file_namelist_param !< mhm parameter namelist file
     177             :     integer, intent(in) :: unamelist
     178             :     integer, intent(in) :: unamelist_param
     179             : 
     180             :     ! parameter to read in
     181           1 :     real(dp) :: albedo_water ! albedo of open water
     182           1 :     real(dp) :: pt_a_water ! priestley taylor alpha parameter for PET on open water
     183           1 :     real(dp) :: emissivity_water ! emissivity of water
     184           1 :     real(dp) :: turb_heat_ex_coeff ! lateral heat exchange coefficient water <-> air
     185             :     ! controlling variables for iterative solver
     186             :     integer(i4) :: max_iter
     187           1 :     real(dp) :: delta_iter
     188           1 :     real(dp) :: step_iter
     189             :     ! files for river widths
     190             :     character(256), dimension(maxNoDomains) :: dir_riv_widths
     191             :     character(256) :: riv_widths_file ! file name for river widths
     192             :     character(256) :: riv_widths_name ! variable name for river widths
     193             : 
     194             :     integer(i4) :: iDomain, domainID
     195             : 
     196             :     ! namelist for river temperature configuration
     197             :     namelist /config_riv_temp/ &
     198             :       albedo_water, &
     199             :       pt_a_water, &
     200             :       emissivity_water, &
     201             :       turb_heat_ex_coeff, &
     202             :       max_iter, &
     203             :       delta_iter, &
     204             :       step_iter, &
     205             :       riv_widths_file, &
     206             :       riv_widths_name, &
     207             :       dir_riv_widths
     208             : 
     209             :     ! allocate the directory arrays
     210           3 :     allocate(self%dir_riv_widths(domainMeta%nDomains))
     211             : 
     212             :     ! default values
     213           1 :     albedo_water = 0.15_dp
     214           1 :     pt_a_water = 1.26_dp
     215           1 :     emissivity_water = 0.96_dp
     216           1 :     turb_heat_ex_coeff = 20.0_dp
     217           1 :     max_iter = 20_i4
     218           1 :     delta_iter = 1.0e-02_dp
     219           1 :     step_iter = 5.0_dp
     220             : 
     221             :     ! open the namelist file
     222           1 :     call open_nml(file_namelist, unamelist, quiet=.true.)
     223             :     ! find the river-temp config namelist
     224           1 :     call position_nml(self%nml_name, unamelist)
     225             :     ! read the river-temp config namelist
     226           1 :     read(unamelist, nml=config_riv_temp)
     227             : 
     228           1 :     self%albedo_water = albedo_water
     229           1 :     self%pt_a_water = pt_a_water
     230           1 :     self%emissivity_water = emissivity_water
     231           1 :     self%turb_heat_ex_coeff = turb_heat_ex_coeff
     232           1 :     self%delta_iter = delta_iter
     233           1 :     self%max_iter = max_iter
     234           1 :     self%step_iter = step_iter
     235           1 :     self%riv_widths_file = riv_widths_file
     236           1 :     self%riv_widths_name = riv_widths_name
     237          52 :     self%dir_riv_widths = dir_riv_widths
     238             : 
     239             :     ! closing the namelist file
     240           1 :     call close_nml(unamelist)
     241             : 
     242           2 :     do iDomain = 1, domainMeta%nDomains
     243           1 :       domainID = domainMeta%indices(iDomain)
     244             :       call check_dir( &
     245           0 :         path=self%dir_riv_widths(iDomain), &
     246             :         text="(domain "//trim(num2str(domainID,'(I3)'))//") River widths directory:", &
     247             :         raise=.true., &
     248             :         tab=4, &
     249             :         text_length=40 &
     250           2 :       )
     251             :     end do
     252             : 
     253           1 :   end subroutine config
     254             : 
     255             :   !> \brief initalize the \ref riv_temp_type class for the current domain
     256           1 :   subroutine init( &
     257             :     self, &
     258             :     nCells &
     259             :   )
     260           1 :     use mo_append, only : append
     261             :     use mo_mrm_constants, only : nRoutingStates
     262             :     ! use mo_common_variables, only : level0, domainMeta
     263             : 
     264             :     implicit none
     265             : 
     266             :     class(riv_temp_type), intent(inout) :: self
     267             :     integer(i4), intent(in) :: nCells !< number of level-11 cells for the current domain
     268             : 
     269           1 :     real(dp), dimension(:), allocatable :: dummy_Vector11
     270           1 :     real(dp), dimension(:, :), allocatable :: dummy_Matrix11_IT
     271             : 
     272             :     ! dummy vector and matrix
     273           3 :     allocate(dummy_Vector11   (nCells))
     274           3 :     allocate(dummy_Matrix11_IT(nCells, nRoutingStates))
     275          35 :     dummy_Vector11(:) = 0.0_dp
     276          71 :     dummy_Matrix11_IT(:, :) = 0.0_dp
     277             : 
     278             :     ! simulated energy flux at each node
     279           1 :     call append(self%netNode_E_mod, dummy_Vector11)
     280             :     ! simulated river temperature at each node
     281           1 :     call append(self%river_temp, dummy_Vector11)
     282             :     ! Total outflow from cells L11 at time tt
     283           1 :     call append(self%netNode_E_out, dummy_Vector11)
     284             :     ! Total discharge inputs at t-1 and t
     285           1 :     call append(self%netNode_E_IN, dummy_Matrix11_IT)
     286             :     !  Routed outflow leaving a node
     287           1 :     call append(self%netNode_E_R, dummy_Matrix11_IT)
     288             : 
     289             :     ! free space
     290           1 :     deallocate(dummy_Vector11)
     291           1 :     deallocate(dummy_Matrix11_IT)
     292             : 
     293           1 :   end subroutine init
     294             : 
     295             :   !> \brief initialize the river area of \ref riv_temp_type class for the current domain
     296           1 :   subroutine init_area( &
     297             :     self, &
     298             :     iDomain, &
     299           2 :     L11_netPerm, &
     300           1 :     L11_fromN, &
     301           1 :     L11_length, &
     302             :     nLinks, &
     303             :     nCells, &
     304             :     nrows, &
     305             :     ncols, &
     306           1 :     L11_mask &
     307             :   )
     308           1 :     use mo_append, only : append
     309             :     use mo_read_nc, only: read_const_nc
     310             : 
     311             :     implicit none
     312             : 
     313             :     class(riv_temp_type), intent(inout) :: self
     314             :     integer(i4), intent(in) :: iDomain !< Domain ID
     315             :     integer(i4), dimension(:), intent(in) :: L11_netPerm !< L11 routing order
     316             :     integer(i4), dimension(:), intent(in) :: L11_fromN !< L11 source grid cell order
     317             :     real(dp), dimension(:), intent(in) :: L11_length !< L11 link length
     318             :     integer(i4), intent(in) :: nLinks !< number of L11 links in the current domain
     319             :     integer(i4), intent(in) :: nCells !< number of L11 cells of the current domain
     320             :     integer(i4), intent(in) :: ncols  !< Number of columns
     321             :     integer(i4), intent(in) :: nrows  !< Number of rows
     322             :     logical, dimension(:, :), intent(in) :: L11_mask !< the mask for valid cells in the original grid (nrows, ncols)
     323             : 
     324           1 :     real(dp), dimension(:,:), allocatable :: L11_data ! read data from file
     325           1 :     real(dp), dimension(:), allocatable :: L11_riv_widths, L11_riv_areas
     326             : 
     327             :     integer(i4) :: i, k, iNode
     328             : 
     329             :     call read_const_nc(&
     330           0 :       trim(self%dir_riv_widths(iDomain)), &
     331             :       nrows, &
     332             :       ncols, &
     333             :       self%riv_widths_name, &
     334             :       L11_data, &
     335             :       self%riv_widths_file &
     336           1 :     )
     337             : 
     338           3 :     allocate(L11_riv_widths(nCells))
     339           1 :     L11_riv_widths(:) = pack(L11_data(:,:), mask=L11_mask)
     340           1 :     call append(self%L11_riv_widths, L11_riv_widths)
     341             : 
     342           3 :     allocate(L11_riv_areas(nCells))
     343             :     ! at area at Outlet is 0
     344          36 :     L11_riv_areas = 0.0_dp
     345          34 :     do k = 1, nLinks
     346             :       ! get LINK routing order -> i
     347          33 :       i = L11_netPerm(k)
     348          33 :       iNode = L11_fromN(i)
     349          34 :       L11_riv_areas(iNode) = L11_length(i) * L11_riv_widths(iNode)
     350             :     end do
     351           1 :     call append(self%L11_riv_areas, L11_riv_areas)
     352             : 
     353           1 :     deallocate(L11_data)
     354           1 :     deallocate(L11_riv_widths)
     355           1 :     deallocate(L11_riv_areas)
     356             : 
     357           1 :   end subroutine init_area
     358             : 
     359             :   !> \brief initialize the river temperature of \ref riv_temp_type class for the current domain
     360           1 :   subroutine init_riv_temp( &
     361             :     self, &
     362           2 :     temp_air, &
     363           1 :     efecarea, &
     364           1 :     L1_L11_Id, &
     365           1 :     L11_areacell, &
     366           1 :     L11_L1_Id, &
     367             :     map_flag &
     368             :   )
     369             : 
     370           1 :     use mo_mrm_pre_routing, only : L11_meteo_acc
     371             : 
     372             :     implicit none
     373             : 
     374             :     class(riv_temp_type), intent(inout) :: self
     375             :     real(dp), dimension(:), intent(in) :: temp_air !< air temperature [degC] for current timestep
     376             :     real(dp), intent(in), dimension(:) :: efecarea !< effective area in [km2] at Level 1
     377             :     integer(i4), intent(in), dimension(:) :: L1_L11_Id !< L11 Ids mapped on L1
     378             :     real(dp), intent(in), dimension(:) :: L11_areacell !< effective area in [km2] at Level 11
     379             :     integer(i4), intent(in), dimension(:) :: L11_L1_Id !< L1 Ids mapped on L11
     380             :     logical, intent(in) :: map_flag !< Flag indicating whether routing resolution is higher than hydrologic one
     381             : 
     382             :     ! map temperature from L1 to L11
     383             :     call L11_meteo_acc( &
     384           1 :       temp_air, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%river_temp(self%s11 : self%e11))
     385             : 
     386             :     ! assure positive temperature
     387          35 :     self%river_temp(self%s11 : self%e11) = max(self%delta_T, self%river_temp(self%s11 : self%e11))
     388             : 
     389           1 :   end subroutine init_riv_temp
     390             : 
     391             :   !> \brief reset \ref riv_temp_type class for next timestep
     392        6553 :   subroutine reset_timestep(self)
     393             :     implicit none
     394             : 
     395             :     class(riv_temp_type), intent(inout) :: self
     396             : 
     397             :     ! set sub time-step counter to 0
     398        6553 :     self%ts_cnt = 0_i4
     399             : 
     400      229355 :     self%L1_runoff_E = 0.0_dp
     401      235908 :     self%L1_acc_strd = 0.0_dp
     402      235908 :     self%L1_acc_ssrd = 0.0_dp
     403      235908 :     self%L1_acc_temp = 0.0_dp
     404             : 
     405           1 :   end subroutine reset_timestep
     406             : 
     407             :   !> \brief allocate lateral temp components of \ref riv_temp_type class for current domain
     408           1 :   subroutine alloc_lateral( &
     409             :     self, &
     410             :     nCells &
     411             :   )
     412             :     implicit none
     413             : 
     414             :     class(riv_temp_type), intent(inout) :: self
     415             :     integer(i4), intent(in) :: nCells !< number of level-1 cells for the current domain
     416             : 
     417           3 :     allocate(self%L1_runoff_E(nCells))
     418           3 :     allocate(self%L1_acc_strd(nCells))
     419           3 :     allocate(self%L1_acc_ssrd(nCells))
     420           3 :     allocate(self%L1_acc_temp(nCells))
     421             :     ! meteo arrays
     422           3 :     allocate(self%L1_ssrd_calc(nCells))
     423           3 :     allocate(self%L1_strd_calc(nCells))
     424           3 :     allocate(self%L1_tann_calc(nCells))
     425             :     ! init these arrays to 0
     426           1 :     call self%reset_timestep()
     427             : 
     428        6553 :   end subroutine alloc_lateral
     429             : 
     430             :   !> \brief deallocate lateral temp components of \ref riv_temp_type
     431           1 :   subroutine dealloc_lateral( &
     432             :     self &
     433             :   )
     434             :     implicit none
     435             : 
     436             :     class(riv_temp_type), intent(inout) :: self
     437             : 
     438           0 :     deallocate(self%L1_runoff_E)
     439           1 :     deallocate(self%L1_acc_strd)
     440           1 :     deallocate(self%L1_acc_ssrd)
     441           1 :     deallocate(self%L1_acc_temp)
     442           1 :     deallocate(self%L1_ssrd_calc)
     443           1 :     deallocate(self%L1_strd_calc)
     444           1 :     deallocate(self%L1_tann_calc)
     445             : 
     446           1 :   end subroutine dealloc_lateral
     447             : 
     448             :   !> \brief accumulate energy sources of \ref riv_temp_type
     449       13104 :   subroutine acc_source_e( &
     450             :     self, &
     451       26208 :     fSealed_area_fraction, &
     452       13104 :     fast_interflow, &
     453       13104 :     slow_interflow, &
     454       13104 :     baseflow, &
     455       13104 :     direct_runoff, &
     456       13104 :     temp_air &
     457             :   )
     458             : 
     459           1 :     use mo_mrm_pre_routing, only : calc_L1_runoff_E
     460             : 
     461             :     implicit none
     462             : 
     463             :     class(riv_temp_type), intent(inout) :: self
     464             :     real(dp), dimension(:), intent(in) :: fSealed_area_fraction !< sealed area fraction [1]
     465             :     real(dp), dimension(:), intent(in) :: fast_interflow !< \f$ q_0 \f$ Fast runoff component [mm TS-1]
     466             :     real(dp), dimension(:), intent(in) :: slow_interflow !< \f$ q_1 \f$ Slow runoff component [mm TS-1]
     467             :     real(dp), dimension(:), intent(in) :: baseflow !< \f$ q_2 \f$ Baseflow [mm TS-1]
     468             :     real(dp), dimension(:), intent(in) :: direct_runoff !< \f$ q_D \f$ Direct runoff from impervious areas  [mm TS-1]
     469             :     real(dp), dimension(:), intent(in) :: temp_air !< air temperature [K]
     470             : 
     471             :     ! increase the sub time-step counter
     472       13104 :     self%ts_cnt = self%ts_cnt + 1_i4
     473             : 
     474             :     ! caclucate the temperature energy of the runoffs at L1 in [K mm]
     475             :     ! automatically accumulate them
     476             :     call calc_L1_runoff_E( &
     477             :       fSealed_area_fraction, &
     478             :       fast_interflow, slow_interflow, baseflow, direct_runoff, &
     479           0 :       temp_air, self%L1_tann_calc, &
     480           0 :       self%L1_runoff_E & ! will be added here
     481       13104 :     )
     482             :     ! accumulate meteo forcings (will be averaged with sub time-step counter later)
     483      471744 :     self%L1_acc_ssrd = self%L1_acc_ssrd + self%L1_ssrd_calc
     484      471744 :     self%L1_acc_strd = self%L1_acc_strd + self%L1_strd_calc
     485      471744 :     self%L1_acc_temp = self%L1_acc_temp + temp_air
     486             : 
     487       13104 :   end subroutine acc_source_e
     488             : 
     489             :   !> \brief finalize energy sources of \ref riv_temp_type
     490        6552 :   subroutine finalize_source_E( &
     491             :     self, &
     492       13104 :     efecarea, &
     493        6552 :     L1_L11_Id, &
     494        6552 :     L11_areacell, &
     495        6552 :     L11_L1_Id, &
     496             :     timestep, &
     497             :     map_flag &
     498             :   )
     499             : 
     500       13104 :     use mo_mrm_pre_routing, only : L11_meteo_acc, L11_runoff_acc
     501             : 
     502             :     implicit none
     503             : 
     504             :     class(riv_temp_type), intent(inout) :: self
     505             :     !> effective area in [km2] at Level 1
     506             :     real(dp), intent(in), dimension(:) :: efecarea
     507             :     !> L11 Ids mapped on L1
     508             :     integer(i4), intent(in), dimension(:) :: L1_L11_Id
     509             :     !> effective area in [km2] at Level 11
     510             :     real(dp), intent(in), dimension(:) :: L11_areacell
     511             :     !> L1 Ids mapped on L11
     512             :     integer(i4), intent(in), dimension(:) :: L11_L1_Id
     513             :     !> simulation timestep in [h]
     514             :     integer(i4), intent(in) :: timestep
     515             :     !> Flag indicating whether routing resolution is higher than hydrologic one
     516             :     logical, intent(in) :: map_flag
     517             : 
     518             :     ! prepare temporal variables for temp-routing
     519        6552 :     if ( allocated(self%L11_srad_net) ) deallocate(self%L11_srad_net)
     520        6552 :     if ( allocated(self%L11_lrad_in) ) deallocate(self%L11_lrad_in)
     521        6552 :     if ( allocated(self%L11_air_temp) ) deallocate(self%L11_air_temp)
     522       19656 :     allocate(self%L11_srad_net(size(L11_L1_Id, dim = 1)))
     523       13104 :     allocate(self%L11_lrad_in(size(L11_L1_Id, dim = 1)))
     524       13104 :     allocate(self%L11_air_temp(size(L11_L1_Id, dim = 1)))
     525             : 
     526             :     ! convert the L1 runoff temperature energy from [K mm] to [K m3 s-1] on L11
     527             :     call L11_runoff_acc( &
     528           0 :       self%L1_runoff_E, &
     529             :       efecarea, &
     530             :       L1_L11_Id, &
     531             :       L11_areacell, &
     532             :       L11_L1_Id, &
     533             :       timestep, &
     534             :       map_flag, &
     535           0 :       self%netNode_E_out(self%s11 : self%e11) &
     536        6552 :     )
     537             :     ! all meteo forcings are accumulated over sub time-steps and need to be divided by the sub time-step counter
     538             :     ! short wave radiation on L11
     539      229320 :     self%L1_acc_ssrd = self%L1_acc_ssrd / real(self%ts_cnt, dp)
     540        6552 :     call L11_meteo_acc(self%L1_acc_ssrd, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_srad_net)
     541             :     ! calculate the net-radiation from incoming/outging short radiation
     542      229320 :     self%L11_srad_net = self%L11_srad_net * (1._dp - self%albedo_water)
     543             :     ! long wave radiation on L11
     544      229320 :     self%L1_acc_strd = self%L1_acc_strd / real(self%ts_cnt, dp)
     545        6552 :     call L11_meteo_acc(self%L1_acc_strd, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_lrad_in)
     546             :     ! air temperature on L11
     547      229320 :     self%L1_acc_temp = self%L1_acc_temp / real(self%ts_cnt, dp)
     548        6552 :     call L11_meteo_acc(self%L1_acc_temp, efecarea, L1_L11_Id, L11_areacell, L11_L1_Id, map_flag, self%L11_air_temp)
     549             : 
     550        6552 :   end subroutine finalize_source_E
     551             : 
     552             :   !> \brief get outgoing longwave radiation of \ref riv_temp_type
     553             :   !> \return outgoing longwave radiation
     554     5550108 :   real(dp) function get_lrad_out(self, riv_temp) result(lrad_out)
     555             : 
     556        6552 :     use mo_constants, only: sigma_dp
     557             : 
     558             :     implicit none
     559             : 
     560             :     class(riv_temp_type), intent(in) :: self
     561             :     !> river temperature in K
     562             :     real(dp), intent(in) :: riv_temp
     563             : 
     564             :     ! outgoing longwave radiation from Boltzmann equation
     565     5550108 :     lrad_out = self%emissivity_water * sigma_dp * riv_temp ** 4_i4
     566             : 
     567     5550108 :   end function get_lrad_out
     568             : 
     569             :   !> \brief latent heat flux of \ref riv_temp_type
     570             :   !> \return latent heat flux
     571     5550108 :   real(dp) function get_lat_heat(self, air_temp, netrad) result(lat_heat)
     572             : 
     573     5550108 :     use mo_constants, only : Psychro_dp
     574             :     use mo_pet, only : slope_satpressure
     575             : 
     576             :     implicit none
     577             : 
     578             :     class(riv_temp_type), intent(in) :: self
     579             :     !> air temperature in deg C
     580             :     real(dp), intent(in) :: air_temp
     581             :     !> net radiation in W * m-2
     582             :     real(dp), intent(in) :: netrad
     583             : 
     584             :     ! save slope of saturation vapor pressure curve
     585     5550108 :     real(dp) :: delta
     586             : 
     587     5550108 :     delta = slope_satpressure(air_temp) ! slope of saturation vapor pressure curve
     588             :     ! latent heat for priestley taylor PET formula
     589     5550108 :     lat_heat = self%pt_a_water * delta / (Psychro_dp + delta) * max(netrad, 0._dp)
     590             : 
     591     5550108 :   end function get_lat_heat
     592             : 
     593             :   !> \brief sensible heat flux of \ref riv_temp_type
     594             :   !> \return sensible heat flux
     595     5550108 :   real(dp) function get_sens_heat(self, air_temp, riv_temp) result(sens_heat)
     596             : 
     597             :     implicit none
     598             : 
     599             :     class(riv_temp_type), intent(in) :: self
     600             :     real(dp), intent(in) :: air_temp !< air temperature in [deg C]
     601             :     real(dp), intent(in) :: riv_temp !< river temperature in [deg C]
     602             : 
     603             :     ! sensible heat flux resulting for temp. diff.: river <-> air
     604     5550108 :     sens_heat = self%turb_heat_ex_coeff * (riv_temp - air_temp)
     605             : 
     606    11100216 :   end function get_sens_heat
     607             : 
     608             :   !> \brief get complete energy source of \ref riv_temp_type at given cell
     609             :   !> \return energy IO
     610     5550108 :   real(dp) function get_E_IO(self, riv_temp, cell) result(E_IO)
     611             : 
     612     5550108 :     use mo_constants, only : T0_dp, cp_w_dp
     613             :     use mo_mhm_constants, only : H2Odens
     614             : 
     615             :     implicit none
     616             : 
     617             :     class(riv_temp_type), intent(in) :: self
     618             :     !> given river temperature in K to calculate heat fluxes
     619             :     real(dp), intent(in) :: riv_temp
     620             :     !> cell index in the current domain
     621             :     integer(i4), intent(in) :: cell
     622             :     !> net radiation calc from short and longwave radiation in/out
     623     5550108 :     real(dp) :: netrad, sens_heat, lat_heat
     624             : 
     625             :     ! net radiation
     626     5550108 :     netrad = self%L11_srad_net(cell) + self%L11_lrad_in(cell) - self%get_lrad_out(riv_temp)
     627             :     ! sensible heat flux
     628     5550108 :     sens_heat = self%get_sens_heat(self%L11_air_temp(cell), riv_temp - T0_dp)
     629             :     ! latent heat flux
     630     5550108 :     lat_heat = self%get_lat_heat(self%L11_air_temp(cell), netrad)
     631             : 
     632             :     ! convert energy flux [W m-2] to [K m s-1]
     633             :     ! needs to be multiplied with river-area to result in temp-energy flux [K m3 s-1]
     634     5550108 :     E_IO = (netrad - sens_heat - lat_heat) / (H2Odens * cp_w_dp)
     635             : 
     636     5550108 :   end function get_E_IO
     637             : 
     638             :   !> \brief execute the temperature routing of \ref riv_temp_type
     639        6552 :   subroutine L11_routing_E( &
     640             :     self, &
     641             :     nLinks, &
     642       13104 :     netPerm, &
     643        6552 :     netLink_fromN, &
     644        6552 :     netLink_toN, &
     645       13104 :     netLink_C1, &
     646        6552 :     netLink_C2, &
     647             :     nInflowGauges, &
     648       13104 :     InflowHeadwater, &
     649        6552 :     InflowNodeList, &
     650        6552 :     L11_qTR, &
     651        6552 :     L11_Qmod &
     652             :   )
     653     5550108 :     use mo_constants, only : T0_dp
     654             : 
     655             :     implicit none
     656             : 
     657             :     class(riv_temp_type), intent(inout) :: self
     658             :     !> number of stream segment (reaches)
     659             :     integer(i4), intent(in) :: nLinks
     660             :     !> routing order of a given domain (permutation)
     661             :     integer(i4), dimension(:), intent(in) :: netPerm
     662             :     !> from node
     663             :     integer(i4), dimension(:), intent(in) :: netLink_fromN
     664             :     !> to node
     665             :     integer(i4), dimension(:), intent(in) :: netLink_toN
     666             :     !> routing parameter  C1 (\cite CMM1988 p. 25-41)
     667             :     real(dp), dimension(:), intent(in) :: netLink_C1
     668             :     !> routing parameters C2 (id)
     669             :     real(dp), dimension(:), intent(in) :: netLink_C2
     670             :     !> [-]      number of inflow points
     671             :     integer(i4), intent(in) :: nInflowGauges
     672             :     !> [-]      if to consider headwater cells of inflow gauge
     673             :     logical, dimension(:), intent(in) :: InflowHeadwater
     674             :     !> [-]      L11 ID of inflow points
     675             :     integer(i4), dimension(:), intent(in) :: InflowNodeList
     676             :     !> [m3 s-1] Transformed outflow leaving node I at current timestep(Muskingum)
     677             :     real(dp), intent(in), dimension(:) :: L11_qTR
     678             :     !> [m3 s-1] Simulated routed discharge
     679             :     real(dp), intent(in), dimension(:) :: L11_Qmod
     680             : 
     681             :     integer(i4) :: i, k, m, iNode, tNode, L11in, L11to
     682        6552 :     real(dp) :: E_IO_in, E_IO, T_est, T_rout
     683             : 
     684             :     ! initialize total input at point time (t+1) in all nodes
     685      229320 :     self%netNode_E_IN(self%s11 : self%e11, 2) = 0.0_dp
     686             : 
     687      222768 :     riv_loop: do k = 1, nLinks
     688             :       ! get LINK routing order -> i
     689      216216 :       i = netPerm(k)
     690      216216 :       iNode = netLink_fromN(i)
     691      216216 :       tNode = netLink_toN(i)
     692             :       ! indices for concaternated domains
     693      216216 :       L11in = iNode + self%s11 - 1_i4
     694      216216 :       L11to = tNode + self%s11 - 1_i4
     695             : 
     696             :       ! accumulate all inputs in iNode
     697      216216 :       self%netNode_E_IN(L11in, 2) = self%netNode_E_IN(L11in, 2) + self%netNode_E_out(L11in)
     698             :       ! calculate the river temp at the upstream node
     699      216216 :       self%river_temp(L11in) = self%netNode_E_IN(L11in, 2) / L11_Qmod(iNode) - T0_dp
     700             : 
     701             :       ! first guess for the routed temperature is the upstream temp
     702      216216 :       T_est = self%river_temp(L11in) + T0_dp
     703             :       ! calculate the meteo energy source at the upstream node
     704      216216 :       E_IO_in = self%get_E_IO(T_est, iNode)
     705             : 
     706             :       ! initialize iteration
     707      216216 :       call self%init_iter()
     708             :       ! perform iteration
     709     5333892 :       iterloop: do m=1, self%max_iter
     710             :         ! meteo energy flux depending on the estimated routed temperature (avg. IN- and OUT-node)
     711     5333892 :         E_IO = (E_IO_in + self%get_E_IO(T_est, tNode)) * 0.5_dp * self%L11_riv_areas(L11in)
     712             :         ! routing iNode
     713     5333892 :         self%netNode_E_R(L11in, 2) = self%netNode_E_R(L11in, 1) &
     714     5333892 :           + netLink_C1(i) * (self%netNode_E_IN(L11in, 1) - self%netNode_E_R(L11in, 1)) &
     715    10667784 :           + netLink_C2(i) * (self%netNode_E_IN(L11in, 2) + E_IO - self%netNode_E_IN(L11in, 1))
     716             :         ! calculate the routed temperature
     717     5333892 :         T_rout = self%netNode_E_R(L11in, 2) / L11_qTR(iNode)
     718             :         ! check for convergence
     719     5333892 :         if ( abs(T_rout - T_est) < self%delta_iter ) exit iterloop
     720             :         ! get new estimate for next iteration
     721     5333892 :         call self%next_iter(T_est, T_rout)
     722             :       end do iterloop
     723             : 
     724             :       ! add the meteo energy flux to the accumulated incoming energy at the IN-node
     725      216216 :       self%netNode_E_IN(L11in, 2) = self%netNode_E_IN(L11in, 2) + E_IO
     726             : 
     727             :       ! check if the inflow from upstream cells should be deactivated
     728      216216 :       if (nInflowGauges .GT. 0) then
     729           0 :         do i = 1, nInflowGauges
     730             :           ! check if downstream Node (tNode) is inflow gauge and headwaters should be ignored
     731           0 :           if ((tNode == InflowNodeList(i)) .AND. (.NOT. InflowHeadwater(i))) &
     732           0 :             self%netNode_E_R(L11in, 2) = 0.0_dp
     733             :         end do
     734             :       end if
     735             : 
     736             :       ! add routed temp energy to downstream node
     737      222768 :       self%netNode_E_IN(L11to, 2) = self%netNode_E_IN(L11to, 2) + self%netNode_E_R(L11in, 2)
     738             : 
     739             :     end do riv_loop
     740             : 
     741             :     ! Accumulate all inputs in tNode (netNode_E_out) ONLY for last link
     742        6552 :     tNode = netLink_toN(netPerm(nLinks))
     743        6552 :     L11to = tNode + self%s11 - 1_i4
     744        6552 :     self%netNode_E_IN(L11to, 2) = self%netNode_E_IN(L11to, 2) + self%netNode_E_out(L11to)
     745             :     ! calculate riv temp at last link
     746        6552 :     self%river_temp(L11to) = self%netNode_E_IN(L11to, 2) / L11_Qmod(tNode) - T0_dp
     747             : 
     748             :     ! backflow t-> t-1
     749      229320 :     self%netNode_E_R(self%s11 : self%e11, 1) = self%netNode_E_R(self%s11 : self%e11, 2)
     750      229320 :     self%netNode_E_IN(self%s11 : self%e11, 1) = self%netNode_E_IN(self%s11 : self%e11, 2)
     751             : 
     752        6552 :   end subroutine L11_routing_E
     753             : 
     754             :   !> \brief initialize iterative solver of \ref riv_temp_type
     755      216216 :   subroutine init_iter(self)
     756             : 
     757             :     implicit none
     758             : 
     759             :     class(riv_temp_type), intent(inout) :: self
     760             : 
     761             :     ! first iteration is used to determine the search direction for the interval
     762      216216 :     self%first_iter = .true.
     763             :     ! after the interval is found, we will perform a biseciton to nail down the temperature
     764      216216 :     self%bisect_iter = .false.
     765             : 
     766        6552 :   end subroutine init_iter
     767             : 
     768             :   !> \brief execute next iteration with iterative solver of \ref riv_temp_type
     769     5117676 :   subroutine next_iter(self, T_est, T_rout)
     770             : 
     771             :     implicit none
     772             : 
     773             :     class(riv_temp_type), intent(inout) :: self
     774             :     real(dp), intent(inout) :: T_est !< estimated river temperature
     775             :     real(dp), intent(in) :: T_rout !< calculated (routed) river temperature
     776             : 
     777             :     ! before performing a bisection we need to search for the interval (with given step-size)
     778     5117676 :     if ( .not. self%bisect_iter ) then
     779             :       ! to determine the direction of interval search, we have to wait for the first iteration
     780      641761 :       if ( self%first_iter ) then
     781      216216 :         self%first_iter = .false.
     782             :         ! determine search direction
     783      216216 :         self%up_iter = ( T_rout > T_est )
     784             :       end if
     785             :       ! check if we need to take another step
     786      641761 :       if ( self%up_iter .eqv. ( T_rout > T_est ) ) then
     787      425545 :         if ( self%up_iter ) then
     788      203382 :           T_est = T_est + self%step_iter
     789             :         else
     790      222163 :           T_est = T_est - self%step_iter
     791             :         end if
     792             :       ! if direction changes, we have found the interval for bisection
     793             :       else
     794             :         ! start bisection in next iteration
     795      216216 :         self%bisect_iter = .true.
     796             :         ! set interval bounds for bisection
     797      216216 :         if ( self%up_iter ) then
     798      103220 :           self%up_bnd_iter = T_est
     799      103220 :           self%low_bnd_iter = T_est - self%step_iter
     800             :         else
     801      112996 :           self%up_bnd_iter = T_est + self%step_iter
     802      112996 :           self%low_bnd_iter = T_est
     803             :         end if
     804             :         ! set estimation to interval center
     805      216216 :         T_est = (self%up_bnd_iter + self%low_bnd_iter) / 2.0_dp
     806             :       end if
     807             :     ! perform bisection
     808             :     else
     809             :       ! if routed temp is lower than estimated, use lower interval
     810     4475915 :       if ( T_rout < T_est ) then
     811     2233019 :         self%up_bnd_iter = T_est
     812             :       ! if routed temp is higher than estimated, use upper interval
     813             :       else
     814     2242896 :         self%low_bnd_iter = T_est
     815             :       end if
     816             :       ! set estimation to interval center
     817     4475915 :       T_est = (self%up_bnd_iter + self%low_bnd_iter) / 2.0_dp
     818             :     end if
     819             : 
     820     5333892 :   end subroutine next_iter
     821             : 
     822     5117676 : end module mo_mrm_riv_temp_class

Generated by: LCOV version 1.16