LCOV - code coverage report
Current view: top level - mRM - mo_mrm_objective_function_runoff.F90 (source / functions) Hit Total Coverage
Test: mHM coverage Lines: 47 445 10.6 %
Date: 2024-04-15 17:48:09 Functions: 3 20 15.0 %

          Line data    Source code
       1             : !> \file mo_mrm_objective_function_runoff.f90
       2             : !> \brief \copybrief mo_mrm_objective_function_runoff
       3             : !> \details \copydetails mo_mrm_objective_function_runoff
       4             : 
       5             : !> \brief Objective Functions for Optimization of mHM/mRM against runoff.
       6             : !> \details This module provides a wrapper for several objective functions used to optimize mRM/mHM against
       7             : !> runoff.
       8             : !!
       9             : !> If the objective contains besides runoff another variable like TWS move it to mHM/mo_objective_function.f90.
      10             : !> If it is only regarding runoff implement it here.
      11             : !!
      12             : !! All the objective functions are supposed to be minimized!
      13             : !! 1.  SO: Q:        1.0 - NSE
      14             : !! 2.  SO: Q:        1.0 - lnNSE
      15             : !! 3.  SO: Q:        1.0 - 0.5*(NSE+lnNSE)
      16             : !! 4.  SO: Q:       -1.0 * loglikelihood with trend removed from absolute errors and then lag(1)-autocorrelation removed
      17             : !! 5.  SO: Q:        ((1-NSE)**6+(1-lnNSE)**6)**(1/6)
      18             : !! 6.  SO: Q:        SSE
      19             : !! 7.  SO: Q:       -1.0 * loglikelihood with trend removed from absolute errors
      20             : !! 8.  SO: Q:       -1.0 * loglikelihood with trend removed from the relative errors and then lag(1)-autocorrelation removed
      21             : !! 9.  SO: Q:        1.0 - KGE (Kling-Gupta efficiency measure)
      22             : !! 14. SO: Q:        sum[((1.0-KGE_i)/ nGauges)**6]**(1/6) > combination of KGE of every gauging station based on a power-6 norm
      23             : !! 16. MO: Q:        1st objective: 1.0 - NSE
      24             : !!         Q:        2nd objective: 1.0 - lnNSE
      25             : !! 18. MO: Q:        1st objective: 1.0 - lnNSE(Q_highflow)  (95% percentile)
      26             : !!         Q:        2nd objective: 1.0 - lnNSE(Q_lowflow)   (5% of data range)
      27             : !! 19. MO: Q:        1st objective: 1.0 - lnNSE(Q_highflow)  (non-low flow)
      28             : !!         Q:        2nd objective: 1.0 - lnNSE(Q_lowflow)   (5% of data range)eshold for Q
      29             : !! 20. MO: Q:        1st objective: absolute difference in FDC's low-segment volume
      30             : !!         Q:        2nd objective: 1.0 - NSE of discharge of months DJF
      31             : !! 31. SO: Q:        1.0 - wNSE - weighted NSE
      32             : !! 32. SO: Q:        SSE of boxcox-transformed streamflow
      33             : !> \changelog
      34             : !! - Stephan Thober             Oct 2015
      35             : !!   - adapted for mRM
      36             : !! - Juliane Mai                Nov 2015
      37             : !!   - introducing multi
      38             : !!   - and single-objective
      39             : !!   - first multi-objective function (16), but not used yet
      40             : !! - Juliane Mai                Feb 2016
      41             : !!   - multi-objective function (18) using lnNSE(highflows) and lnNSE(lowflows)
      42             : !!   - multi-objective function (19) using lnNSE(highflows) and lnNSE(lowflows)
      43             : !!   - multi-objective function (20) using FDC and discharge of months DJF
      44             : !! - Stephan Thober,Bjoern Guse May 2018
      45             : !!   - single objective function (21) using weighted NSE following (Hundecha and Bardossy, 2004)
      46             : !! - Robert Schweppe            Jun 2018
      47             : !!   - refactoring and reformatting
      48             : !! - Stephan Thober             Aug 2019
      49             : !!   - added OF 32: SSE of boxcox-transformed streamflow
      50             : !> \authors Juliane Mai
      51             : !> \date Dec 2012
      52             : !> \copyright Copyright 2005-\today, the mHM Developers, Luis Samaniego, Sabine Attinger: All rights reserved.
      53             : !! mHM is released under the LGPLv3+ license \license_note
      54             : !> \ingroup f_mrm
      55             : MODULE mo_mrm_objective_function_runoff
      56             : 
      57             :   ! This module provides objective functions for optimization of the UFZ CHS mesoscale hydrologic model mHM.
      58             : 
      59             :   ! Written  Juliane Mai, Dec 2012
      60             :   ! Modified Stephan Thober, Oct 2015 - removed all none runoff objectives,
      61             :   !                                     these can be found mo_objective_functions_sm
      62             : 
      63             :   USE mo_kind, ONLY : i4, dp
      64             :   use mo_optimization_utils, only : eval_interface
      65             :   use mo_message, only: message, error_message
      66             :   use mo_string_utils, only : num2str
      67             : 
      68             :   IMPLICIT NONE
      69             : 
      70             :   PRIVATE
      71             : 
      72             :   PUBLIC :: single_objective_runoff ! single-objective function wrapper
      73             :   PUBLIC :: multi_objective_runoff  ! multi-objective function wrapper
      74             :   PUBLIC :: extract_runoff          ! extract runoff period specified in mhm.nml from available runoff time series
      75             : #ifdef MPI
      76             :   PUBLIC :: single_objective_runoff_master, single_objective_runoff_subprocess ! objective function wrapper for soil moisture only
      77             : #endif
      78             : 
      79             :   ! ------------------------------------------------------------------
      80             : 
      81             : CONTAINS
      82             : 
      83             :   ! ------------------------------------------------------------------
      84             : 
      85             :   !    NAME
      86             :   !        single_objective_runoff
      87             : 
      88             :   !    PURPOSE
      89             :   !>       \brief Wrapper for objective functions optimizing agains runoff.
      90             : 
      91             :   !>       \details The functions selects the objective function case defined in a namelist,
      92             :   !>       i.e. the global variable \e opti\_function.
      93             :   !>       It return the objective function value for a specific parameter set.
      94             : 
      95             :   !    INTENT(IN)
      96             :   !>       \param[in] "REAL(dp), DIMENSION(:) :: parameterset"
      97             :   !>       \param[in] "procedure(eval_interface) :: eval"
      98             : 
      99             :   !    INTENT(IN), OPTIONAL
     100             :   !>       \param[in] "real(dp), optional :: arg1"
     101             : 
     102             :   !    INTENT(OUT), OPTIONAL
     103             :   !>       \param[out] "real(dp), optional :: arg2"
     104             :   !>       \param[out] "real(dp), optional :: arg3"
     105             : 
     106             :   !    RETURN
     107             :   !>       \return real(dp) :: objective — objective function value
     108             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
     109             : 
     110             :   !    HISTORY
     111             :   !>       \authors Juliane Mai
     112             : 
     113             :   !>       \date Dec 2012
     114             : 
     115             :   ! Modifications:
     116             :   ! Stephan Thober              Oct 2015 - only runoff objective functions
     117             :   ! Stephan Thober, Bjoern Guse May 2018 - added weighted objective function
     118             :   ! Robert Schweppe             Jun 2018 - refactoring and reformatting
     119             : 
     120             : 
     121           6 :   FUNCTION single_objective_runoff(parameterset, eval, arg1, arg2, arg3)
     122             : 
     123             :     use mo_common_mHM_mRM_variables, only : opti_function, opti_method
     124             : 
     125             :     implicit none
     126             : 
     127             :     REAL(dp), DIMENSION(:), INTENT(IN) :: parameterset
     128             : 
     129             :     procedure(eval_interface), INTENT(IN), POINTER :: eval
     130             : 
     131             :     real(dp), optional, intent(in) :: arg1
     132             : 
     133             :     real(dp), optional, intent(out) :: arg2
     134             : 
     135             :     real(dp), optional, intent(out) :: arg3
     136             : 
     137             :     REAL(dp) :: single_objective_runoff
     138             : 
     139             : 
     140             :     !write(*,*) 'parameterset: ',parameterset(:)
     141           0 :     select case (opti_function)
     142             :     case (1)
     143             :       ! 1.0-nse
     144           0 :       single_objective_runoff = objective_nse(parameterset, eval)
     145             :     case (2)
     146             :       ! 1.0-lnnse
     147           0 :       single_objective_runoff = objective_lnnse(parameterset, eval)
     148             :     case (3)
     149             :       ! 1.0-0.5*(nse+lnnse)
     150           6 :       single_objective_runoff = objective_equal_nse_lnnse(parameterset, eval)
     151             :     case (4)
     152           0 :       if (opti_method .eq. 0_i4) then
     153             :         ! MCMC
     154           0 :         single_objective_runoff = loglikelihood_stddev(parameterset, eval, arg1, arg2, arg3)
     155             :       else
     156             :         ! -loglikelihood with trend removed from absolute errors and then lag(1)-autocorrelation removed
     157           0 :         single_objective_runoff = - loglikelihood_stddev(parameterset, eval, 1.0_dp)
     158             :       end if
     159             :     case (5)
     160             :       ! ((1-NSE)**6+(1-lnNSE)**6)**(1/6)
     161           0 :       single_objective_runoff = objective_power6_nse_lnnse(parameterset, eval)
     162             :     case (6)
     163             :       ! SSE
     164           0 :       single_objective_runoff = objective_sse(parameterset, eval)
     165             :     case (7)
     166             :       ! -loglikelihood with trend removed from absolute errors
     167           0 :       single_objective_runoff = -loglikelihood_trend_no_autocorr(parameterset, eval, 1.0_dp)
     168             :     case (8)
     169           0 :       if (opti_method .eq. 0_i4) then
     170             :         ! MCMC
     171           0 :         single_objective_runoff = loglikelihood_evin2013_2(parameterset, eval, regularize = .true.)
     172             :       else
     173             :         ! -loglikelihood of approach 2 of Evin et al. (2013),
     174             :         !  i.e. linear error model with lag(1)-autocorrelation on relative errors
     175           0 :         single_objective_runoff = -loglikelihood_evin2013_2(parameterset, eval)
     176             :       end if
     177             : 
     178             :     case (9)
     179             :       ! KGE
     180           0 :       single_objective_runoff = objective_kge(parameterset, eval)
     181             :     case (14)
     182             :       ! combination of KGE of every gauging station based on a power-6 norm \n
     183             :       ! sum[((1.0-KGE_i)/ nGauges)**6]**(1/6)
     184           0 :       single_objective_runoff = objective_multiple_gauges_kge_power6(parameterset, eval)
     185             :     case (31)
     186             :       ! weighted NSE with observed streamflow
     187           0 :       single_objective_runoff = objective_weighted_nse(parameterset, eval)
     188             :     case (32)
     189             :       ! sum of squared errors (SSE) of boxcox_transformed streamflow
     190           0 :       single_objective_runoff = objective_sse_boxcox(parameterset, eval)
     191             :     case default
     192           6 :       call error_message("Error objective: This opti_function is either not implemented yet or is not a single-objective one.")
     193             :     end select
     194             : 
     195           6 :   END FUNCTION single_objective_runoff
     196             : 
     197             : 
     198             :   ! ------------------------------------------------------------------
     199             : 
     200             :   !    NAME
     201             :   !        single_objective_runoff_master
     202             : 
     203             :   !    PURPOSE
     204             :   !>       \brief Wrapper for objective functions optimizing agains runoff.
     205             : 
     206             :   !>       \details The functions selects the objective function case defined in a namelist,
     207             :   !>       i.e. the global variable \e opti\_function.
     208             :   !>       It return the objective function value for a specific parameter set.
     209             : 
     210             :   !    INTENT(IN)
     211             :   !>       \param[in] "REAL(dp), DIMENSION(:) :: parameterset"
     212             :   !>       \param[in] "procedure(eval_interface) :: eval"
     213             : 
     214             :   !    INTENT(IN), OPTIONAL
     215             :   !>       \param[in] "real(dp), optional :: arg1"
     216             : 
     217             :   !    INTENT(OUT), OPTIONAL
     218             :   !>       \param[out] "real(dp), optional :: arg2"
     219             :   !>       \param[out] "real(dp), optional :: arg3"
     220             : 
     221             :   !    RETURN
     222             :   !>       \return real(dp) :: objective — objective function value
     223             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
     224             : 
     225             :   !    HISTORY
     226             :   !>       \authors Juliane Mai
     227             : 
     228             :   !>       \date Dec 2012
     229             : 
     230             :   ! Modifications:
     231             :   ! Stephan Thober              Oct 2015 - only runoff objective functions
     232             :   ! Stephan Thober, Bjoern Guse May 2018 - added weighted objective function
     233             :   ! Robert Schweppe             Jun 2018 - refactoring and reformatting
     234             : 
     235             : #ifdef MPI
     236             :   FUNCTION single_objective_runoff_master(parameterset, eval, arg1, arg2, arg3)
     237             : 
     238             :     use mo_common_mHM_mRM_variables, only : opti_function, opti_method
     239             :     use mo_common_mpi_tools, only : distribute_parameterset
     240             :     use mo_mrm_global_variables, only: nGaugesTotal
     241             :     use mo_common_variables, only : domainMeta
     242             :     use mpi_f08
     243             : 
     244             :     implicit none
     245             : 
     246             :     REAL(dp), DIMENSION(:), INTENT(IN) :: parameterset
     247             : 
     248             :     procedure(eval_interface), INTENT(IN), POINTER :: eval
     249             : 
     250             :     real(dp), optional, intent(in) :: arg1
     251             : 
     252             :     real(dp), optional, intent(out) :: arg2
     253             : 
     254             :     real(dp), optional, intent(out) :: arg3
     255             : 
     256             :     REAL(dp) :: single_objective_runoff_master
     257             : 
     258             :     REAL(dp) :: partial_objective
     259             : 
     260             :     ! for sixth root
     261             :     real(dp), parameter :: onesixth = 1.0_dp / 6.0_dp
     262             : 
     263             :     integer(i4) :: iproc, nproc
     264             : 
     265             :     integer(i4) :: ierror
     266             : 
     267             :     type(MPI_Status) :: status
     268             : 
     269             :     !write(*,*) 'parameterset: ',parameterset(:)
     270             :     call distribute_parameterset(parameterset)
     271             :     select case (opti_function)
     272             :     case(1 : 3, 5, 6, 9, 31)
     273             :       call MPI_Comm_size(domainMeta%comMaster, nproc, ierror)
     274             :       single_objective_runoff_master = 0.0_dp
     275             :       do iproc = 1, nproc - 1
     276             :         call MPI_Recv(partial_objective, 1, MPI_DOUBLE_PRECISION, iproc, 0, domainMeta%comMaster, status, ierror)
     277             :         single_objective_runoff_master = single_objective_runoff_master + partial_objective
     278             :       end do
     279             :       single_objective_runoff_master = 1.0_dp - single_objective_runoff_master / real(nGaugesTotal, dp)
     280             :     case(14)
     281             :       call MPI_Comm_size(domainMeta%comMaster, nproc, ierror)
     282             :       single_objective_runoff_master = 0.0_dp
     283             :       do iproc = 1, nproc - 1
     284             :         call MPI_Recv(partial_objective, 1, MPI_DOUBLE_PRECISION, iproc, 0, domainMeta%comMaster, status, ierror)
     285             :         single_objective_runoff_master = single_objective_runoff_master + partial_objective
     286             :       end do
     287             :       single_objective_runoff_master = single_objective_runoff_master**onesixth
     288             :     case(4, 7, 8)
     289             :       call message("case 4, 7, 8 are not implemented in parallel yet")
     290             :     case default
     291             :       call error_message("Error single_objective_runoff_master:", raise=.false.)
     292             :       call error_message("This opti_function is either not implemented yet or is not a single-objective one.")
     293             :     end select
     294             : 
     295             :     select case (opti_function)
     296             :     case (1)
     297             :       ! 1.0-nse
     298             :       call message('objective_nse (i.e., 1 - NSE) = ', num2str(single_objective_runoff_master))
     299             :     case (2)
     300             :       ! 1.0-lnnse
     301             :       call message('objective_lnnse = ', num2str(single_objective_runoff_master))
     302             :     case (3)
     303             :       ! 1.0-0.5*(nse+lnnse)
     304             :       call message('objective_equal_nse_lnnse = ', num2str(single_objective_runoff_master))
     305             :     case (4)
     306             :       call error_message("case 4, loglikelihood_stddev not implemented in parallel yet")
     307             :     case (5)
     308             :       ! ((1-NSE)**6+(1-lnNSE)**6)**(1/6)
     309             :       call message('objective_power6_nse_lnnse = ', num2str(single_objective_runoff_master))
     310             :     case (6)
     311             :       ! SSE
     312             :       call message('objective_sse = ', num2str(single_objective_runoff_master))
     313             :     case (7)
     314             :       ! -loglikelihood with trend removed from absolute errors
     315             :       call error_message("case 7, single_objective_runoff_master not implemented in parallel yet")
     316             :     case (8)
     317             :       call error_message("case 8, loglikelihood_evin2013_2 not implemented in parallel yet")
     318             :     case (9)
     319             :       ! KGE
     320             :       call message('objective_kge (i.e., 1 - KGE) = ', num2str(single_objective_runoff_master))
     321             :     case (14)
     322             :       ! combination of KGE of every gauging station based on a power-6 norm \n
     323             :       ! sum[((1.0-KGE_i)/ nGauges)**6]**(1/6)
     324             :       call message('objective_multiple_gauges_kge_power6 = ', num2str(single_objective_runoff_master))
     325             :     case (31)
     326             :       ! weighted NSE with observed streamflow
     327             :       call message('objective_weighted_nse (i.e., 1 - wNSE) = ', num2str(single_objective_runoff_master))
     328             :     case (32)
     329             :       ! SSE of boxcox-transformed streamflow
     330             :       call message('sse_boxcox_streamflow = ', num2str(single_objective_runoff_master))
     331             :     case default
     332             :       call error_message("Error single_objective_runoff_master:", raise=.false.)
     333             :       call error_message("This opti_function is either not implemented yet or is not a single-objective one.", raise=.false.)
     334             :       call error_message("This part of the code should never be executed.")
     335             :     end select
     336             : 
     337             :   END FUNCTION single_objective_runoff_master
     338             : 
     339             : 
     340             :   ! ------------------------------------------------------------------
     341             : 
     342             :   !    NAME
     343             :   !        single_objective_runoff_subprocess
     344             : 
     345             :   !    PURPOSE
     346             :   !>       \brief Wrapper for objective functions optimizing agains runoff.
     347             : 
     348             :   !>       \details The functions selects the objective function case defined in a namelist,
     349             :   !>       i.e. the global variable \e opti\_function.
     350             :   !>       It return the objective function value for a specific parameter set.
     351             : 
     352             :   !    INTENT(IN)
     353             :   !>       \param[in] "REAL(dp), DIMENSION(:) :: parameterset"
     354             :   !>       \param[in] "procedure(eval_interface) :: eval"
     355             : 
     356             :   !    INTENT(IN), OPTIONAL
     357             :   !>       \param[in] "real(dp), optional :: arg1"
     358             : 
     359             :   !    INTENT(OUT), OPTIONAL
     360             :   !>       \param[out] "real(dp), optional :: arg2"
     361             :   !>       \param[out] "real(dp), optional :: arg3"
     362             : 
     363             :   !    RETURN
     364             :   !>       \return real(dp) :: objective — objective function value
     365             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
     366             : 
     367             :   !    HISTORY
     368             :   !>       \authors Juliane Mai
     369             : 
     370             :   !>       \date Dec 2012
     371             : 
     372             :   ! Modifications:
     373             :   ! Stephan Thober              Oct 2015 - only runoff objective functions
     374             :   ! Stephan Thober, Bjoern Guse May 2018 - added weighted objective function
     375             :   ! Robert Schweppe             Jun 2018 - refactoring and reformatting
     376             : 
     377             : 
     378             :   subroutine single_objective_runoff_subprocess(eval, arg1, arg2, arg3)
     379             : 
     380             :     use mo_common_mHM_mRM_variables, only : opti_function, opti_method
     381             :     use mo_common_mpi_tools, only : get_parameterset
     382             :     use mo_common_variables, only : domainMeta
     383             :     use mpi_f08
     384             : 
     385             :     implicit none
     386             : 
     387             :     procedure(eval_interface), INTENT(IN), POINTER :: eval
     388             : 
     389             :     real(dp), optional, intent(in) :: arg1
     390             : 
     391             :     real(dp), optional, intent(out) :: arg2
     392             : 
     393             :     real(dp), optional, intent(out) :: arg3
     394             : 
     395             :     REAL(dp) :: partial_single_objective_runoff
     396             : 
     397             :     REAL(dp), DIMENSION(:), allocatable :: parameterset
     398             : 
     399             :     integer(i4) :: ierror
     400             : 
     401             :     type(MPI_Status) :: status
     402             : 
     403             :     logical :: do_obj_loop
     404             : 
     405             : 
     406             :     do ! a do loop without condition runs until exit
     407             :       call MPI_Recv(do_obj_loop, 1, MPI_LOGICAL, 0, 0, domainMeta%comMaster, status, ierror)
     408             : 
     409             :       if (.not. do_obj_loop) exit
     410             :       !write(*,*) 'parameterset: ',parameterset(:)
     411             :       call get_parameterset(parameterset)
     412             :       select case (opti_function)
     413             :       case (1)
     414             :         ! 1.0-nse
     415             :         partial_single_objective_runoff = objective_nse(parameterset, eval)
     416             :       case (2)
     417             :         ! 1.0-lnnse
     418             :         partial_single_objective_runoff = objective_lnnse(parameterset, eval)
     419             :       case (3)
     420             :         ! 1.0-0.5*(nse+lnnse)
     421             :         partial_single_objective_runoff = objective_equal_nse_lnnse(parameterset, eval)
     422             :       case (4)
     423             :         if (opti_method .eq. 0_i4) then
     424             :           ! MCMC
     425             :           ! partial_single_objective_runoff = loglikelihood_stddev(parameterset, eval, arg1, arg2, arg3)
     426             :           call error_message("Error single_objective_runoff_subprocess: case 4 with optimethod 0 not supported")
     427             :         else
     428             :           ! -loglikelihood with trend removed from absolute errors and then lag(1)-autocorrelation removed
     429             :           partial_single_objective_runoff = - loglikelihood_stddev(parameterset, eval, 1.0_dp)
     430             :         end if
     431             :       case (5)
     432             :         ! ((1-NSE)**6+(1-lnNSE)**6)**(1/6)
     433             :         partial_single_objective_runoff = objective_power6_nse_lnnse(parameterset, eval)
     434             :       case (6)
     435             :         ! SSE
     436             :         partial_single_objective_runoff = objective_sse(parameterset, eval)
     437             :       case (7)
     438             :         ! -loglikelihood with trend removed from absolute errors
     439             :         ! partial_single_objective_runoff = -loglikelihood_trend_no_autocorr(parameterset, eval, 1.0_dp)
     440             :         call error_message("Error single_objective_runoff_subprocess: case 7 not supported")
     441             :       case (8)
     442             :         if (opti_method .eq. 0_i4) then
     443             :           ! MCMC
     444             :           ! partial_single_objective_runoff = loglikelihood_evin2013_2(parameterset, eval, regularize = .true.)
     445             :           call error_message("Error single_objective_runoff_subprocess: case 8 with optimethod 0 not supported")
     446             :         else
     447             :           ! -loglikelihood of approach 2 of Evin et al. (2013),
     448             :           !  i.e. linear error model with lag(1)-autocorrelation on relative errors
     449             :           partial_single_objective_runoff = -loglikelihood_evin2013_2(parameterset, eval)
     450             :         end if
     451             : 
     452             :       case (9)
     453             :         ! KGE
     454             :         partial_single_objective_runoff = objective_kge(parameterset, eval)
     455             :       case (14)
     456             :         ! combination of KGE of every gauging station based on a power-6 norm \n
     457             :         ! sum[((1.0-KGE_i)/ nGauges)**6]**(1/6)
     458             :         partial_single_objective_runoff = objective_multiple_gauges_kge_power6(parameterset, eval)
     459             :       case (31)
     460             :          ! weighted NSE with observed streamflow
     461             :          partial_single_objective_runoff = objective_weighted_nse(parameterset, eval)
     462             :       case (32)
     463             :          ! SSE of transformed streamflow
     464             :          partial_single_objective_runoff = objective_sse_boxcox(parameterset, eval)
     465             :       case default
     466             :         call error_message("Error single_objective_runoff_subprocess:", raise=.false.)
     467             :         call error_message("This opti_function is either not implemented yet or is not a single-objective one.")
     468             :       end select
     469             : 
     470             :       select case (opti_function)
     471             :       case (1 : 3, 5, 6, 9, 14, 31)
     472             :         call MPI_Send(partial_single_objective_runoff,1, MPI_DOUBLE_PRECISION,0,0,domainMeta%comMaster,ierror)
     473             :       case default
     474             :         call error_message("Error objective_subprocess: this part should not be executed -> error in the code.")
     475             :       end select
     476             :       deallocate(parameterset)
     477             :     end do
     478             : 
     479             :   END subroutine single_objective_runoff_subprocess
     480             : 
     481             : #endif
     482             : 
     483             :   ! ------------------------------------------------------------------
     484             : 
     485             :   !    NAME
     486             :   !        multi_objective_runoff
     487             : 
     488             :   !    PURPOSE
     489             :   !>       \brief Wrapper for multi-objective functions where at least one is regarding runoff.
     490             : 
     491             :   !>       \details The functions selects the objective function case defined in a namelist,
     492             :   !>       i.e. the global variable \e opti\_function.
     493             :   !>       It return the multiple objective function values for a specific parameter set.
     494             : 
     495             :   !    INTENT(IN)
     496             :   !>       \param[in] "REAL(dp), DIMENSION(:) :: parameterset"
     497             :   !>       \param[in] "procedure(eval_interface) :: eval"
     498             : 
     499             :   !    INTENT(OUT)
     500             :   !>       \param[out] "REAL(dp), DIMENSION(:) :: multi_objectives"
     501             : 
     502             :   !    HISTORY
     503             :   !>       \authors Juliane Mai
     504             : 
     505             :   !>       \date Oct 2015
     506             : 
     507             :   ! Modifications:
     508             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     509             : 
     510           0 :   SUBROUTINE multi_objective_runoff(parameterset, eval, multi_objectives)
     511             : 
     512           6 :     use mo_common_mHM_mRM_variables, only : opti_function
     513             : 
     514             :     implicit none
     515             : 
     516             :     REAL(dp), DIMENSION(:), INTENT(IN) :: parameterset
     517             : 
     518             :     procedure(eval_interface), INTENT(IN), pointer :: eval
     519             : 
     520             :     REAL(dp), DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: multi_objectives
     521             : 
     522             : 
     523           0 :     select case (opti_function)
     524             :     case (16)
     525             :       ! 1st objective: 1.0-nse
     526             :       ! 2nd objective: 1.0-lnnse
     527           0 :       multi_objectives = multi_objective_nse_lnnse(parameterset, eval)
     528             :     case (18)
     529             :       ! 1st objective: 1.0 - lnNSE(Q_highflow)  (95% percentile)
     530             :       ! 2nd objective: 1.0 - lnNSE(Q_lowflow)   (5% of data range)
     531           0 :       multi_objectives = multi_objective_lnnse_highflow_lnnse_lowflow(parameterset, eval)
     532             :     case (19)
     533             :       ! 1st objective: 1.0 - lnNSE(Q_highflow)  (non-low flow)
     534             :       ! 2nd objective: 1.0 - lnNSE(Q_lowflow)   (5% of data range)
     535           0 :       multi_objectives = multi_objective_lnnse_highflow_lnnse_lowflow_2(parameterset, eval)
     536             :     case (20)
     537             :       ! 1st objective: 1.0 - difference in FDC's low-segment volume
     538             :       ! 2nd objective: 1.0 - NSE of discharge of months DJF
     539           0 :       multi_objectives = multi_objective_ae_fdc_lsv_nse_djf(parameterset, eval)
     540             :     case default
     541           0 :       call error_message("Error objective: Either this opti_function is not implemented yet or it is not a multi-objective one.")
     542             :     end select
     543             : 
     544           0 :   END SUBROUTINE multi_objective_runoff
     545             : 
     546             :   ! ------------------------------------------------------------------
     547             : 
     548             :   !    NAME
     549             :   !        loglikelihood_stddev
     550             : 
     551             :   !    PURPOSE
     552             :   !>       \brief Logarithmic likelihood function with removed linear trend and Lag(1)-autocorrelation.
     553             : 
     554             :   !>       \details The logarithmis likelihood function is used when mHM runs in MCMC mode.
     555             :   !>       It can also be used for optimization when selecting the likelihood in the
     556             :   !>       namelist as \e opti\_function.
     557             : 
     558             :   !    INTENT(IN)
     559             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
     560             :   !>       \param[in] "procedure(eval_interface) :: eval"
     561             :   !>       \param[in] "real(dp) :: stddev"                     standard deviation of data
     562             : 
     563             :   !    INTENT(OUT), OPTIONAL
     564             :   !>       \param[out] "real(dp), optional :: stddev_new" standard deviation of errors with removed trend and
     565             :   !>       correlationbetween model run using parameter set and observation
     566             :   !>       \param[out] "real(dp), optional :: likeli_new" logarithmic likelihood determined with stddev_new instead of
     567             :   !>       stddev
     568             : 
     569             :   !    RETURN
     570             :   !>       \return real(dp) :: loglikelihood_stddev — logarithmic likelihood using given stddev
     571             :   !>       but remove optimal trend and lag(1)-autocorrelation in errors
     572             :   !>       (absolute between running model with parameterset and observation)
     573             : 
     574             :   !    HISTORY
     575             :   !>       \authors Juliane Mai
     576             : 
     577             :   !>       \date Dec 2012
     578             : 
     579             :   ! Modifications:
     580             :   ! Stephan Thober Jan 2015 - introduced extract_runoff
     581             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
     582             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     583             : 
     584           0 :   FUNCTION loglikelihood_stddev(parameterset, eval, stddev, stddev_new, likeli_new)
     585             : 
     586           0 :     use mo_append, only : append
     587             :     use mo_linfit, only : linfit
     588             :     use mo_moment, only : correlation, mean
     589             : 
     590             :     implicit none
     591             : 
     592             :     real(dp), dimension(:), intent(in) :: parameterset
     593             : 
     594             :     procedure(eval_interface), INTENT(IN), pointer :: eval
     595             : 
     596             :     ! standard deviation of data
     597             :     real(dp), intent(in) :: stddev
     598             : 
     599             :     ! standard deviation of errors with removed trend and correlationbetween model run using parameter set and
     600             :     ! observation
     601             :     real(dp), intent(out), optional :: stddev_new
     602             : 
     603             :     ! logarithmic likelihood determined with stddev_new instead of stddev
     604             :     real(dp), intent(out), optional :: likeli_new
     605             : 
     606             :     real(dp) :: loglikelihood_stddev
     607             : 
     608             :     ! modelled runoff for a given parameter set
     609             :     ! dim1=nTimeSteps, dim2=nGauges
     610           0 :     real(dp), dimension(:, :), allocatable :: runoff
     611             : 
     612             :     ! gauges counter
     613             :     integer(i4) :: gg
     614             : 
     615             :     ! aggregated simulated runoff
     616           0 :     real(dp), dimension(:), allocatable :: runoff_agg
     617             : 
     618             :     ! measured runoff
     619           0 :     real(dp), dimension(:), allocatable :: runoff_obs
     620             : 
     621             :     ! mask for aggregated measured runoff
     622           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
     623             : 
     624             :     integer(i4) :: nmeas
     625             : 
     626           0 :     real(dp), dimension(:), allocatable :: errors
     627             : 
     628           0 :     real(dp), dimension(:), allocatable :: obs, calc, out
     629             : 
     630           0 :     real(dp) :: a, b, c
     631             : 
     632           0 :     real(dp) :: stddev_tmp
     633             : 
     634             : 
     635           0 :     call eval(parameterset, runoff = runoff)
     636             : 
     637             :     ! extract runoff and append it to obs and calc
     638           0 :     do gg = 1, size(runoff, dim = 2) ! second dimension equals nGaugesTotal
     639             :       ! extract runoff
     640           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
     641             :       ! append it to variables
     642           0 :       call append(obs, runoff_obs)
     643           0 :       call append(calc, runoff_agg)
     644             : 
     645             :     end do
     646             :     ! ----------------------------------------
     647             : 
     648           0 :     nmeas = size(obs, dim = 1)
     649             : 
     650           0 :     allocate(out(nmeas), errors(nmeas))
     651           0 :     errors(:) = abs(calc(:) - obs(:))
     652             : 
     653             :     ! remove linear trend of errors - must be model NOT obs
     654             :     ! out = linfit(obs, errors, a=a, b=b, model2=.False.)
     655             :     ! errors(:) = errors(:) - (a + obs(:)*b)
     656           0 :     out = linfit(calc, errors, a = a, b = b, model2 = .False.)
     657           0 :     errors(:) = errors(:) - (a + calc(:) * b)
     658             : 
     659             :     ! remove lag(1)-autocorrelation of errors
     660           0 :     c = correlation(errors(2 : nmeas), errors(1 : nmeas - 1))
     661           0 :     errors(1 : nmeas - 1) = errors(2 : nmeas) - c * errors(1 : nmeas - 1)
     662           0 :     errors(nmeas) = 0.0_dp
     663             : 
     664             :     ! you have to take stddev=const because otherwise loglikelihood is always N
     665             :     ! in MCMC stddev gets updated only when a better likelihood is found.
     666           0 :     loglikelihood_stddev = sum(errors(:) * errors(:) / stddev**2)
     667           0 :     loglikelihood_stddev = -0.5_dp * loglikelihood_stddev
     668             : 
     669           0 :     call message('-loglikelihood_stddev = ', num2str(-loglikelihood_stddev))
     670             : 
     671           0 :     stddev_tmp = sqrt(sum((errors(:) - mean(errors)) * (errors(:) - mean(errors))) / real(nmeas - 1, dp))
     672           0 :     if (present(stddev_new)) then
     673           0 :       stddev_new = stddev_tmp
     674             :     end if
     675           0 :     if (present(likeli_new)) then
     676           0 :       likeli_new = sum(errors(:) * errors(:) / stddev_tmp**2)
     677           0 :       likeli_new = -0.5_dp * likeli_new
     678             :     end if
     679             : 
     680           0 :     deallocate(runoff, runoff_agg, runoff_obs_mask, runoff_obs)
     681           0 :     deallocate(obs, calc, out, errors)
     682             : 
     683           0 :   END FUNCTION loglikelihood_stddev
     684             : 
     685             :   ! ------------------------------------------------------------------
     686             : 
     687             :   !    NAME
     688             :   !        loglikelihood_evin2013_2
     689             : 
     690             :   !    PURPOSE
     691             :   !>       \brief Logarithmised likelihood with linear error model and lag(1)-autocorrelation
     692             :   !>       of the relative errors.
     693             : 
     694             :   !>       \details This loglikelihood uses a linear error model and a lag(1)-autocorrelation
     695             :   !>       on the relative errors. This is approach 2 of the paper Evin et al. (WRR, 2013).
     696             : 
     697             :   !>       This is opti_function = 8.
     698             : 
     699             :   !>       mHM then adds two extra (local) parameters for the error model in mhm_driver,
     700             :   !>       which get optimised together with the other, global parameters.
     701             :   !>       ADDITIONAL INFORMATION
     702             :   !>       Evin et al., WRR 49, 4518-4524, 2013
     703             : 
     704             :   !    INTENT(IN)
     705             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
     706             :   !>       \param[in] "procedure(eval_interface) :: eval"
     707             : 
     708             :   !    INTENT(IN), OPTIONAL
     709             :   !>       \param[in] "logical, optional :: regularize"
     710             : 
     711             :   !    RETURN
     712             :   !>       \return real(dp) :: loglikelihood_evin2013_2 — logarithmic likelihood using given stddev
     713             :   !>       but remove optimal trend and lag(1)-autocorrelation in errors
     714             :   !>       (absolute between running model with parameterset and observation)
     715             : 
     716             :   !    HISTORY
     717             :   !>       \authors Juliane Mai and Matthias Cuntz
     718             : 
     719             :   !>       \date Mar 2014
     720             : 
     721             :   ! Modifications:
     722             :   ! Stephan Thober Jan 2015 - introduced extract_runoff
     723             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
     724             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     725             : 
     726           0 :   FUNCTION loglikelihood_evin2013_2(parameterset, eval, regularize)
     727             : 
     728           0 :     use mo_append, only : append
     729             :     use mo_common_variables, only : global_parameters
     730             :     use mo_constants, only : pi_dp
     731             :     use mo_moment, only : correlation
     732             :     use mo_utils, only : eq
     733             : 
     734             :     implicit none
     735             : 
     736             :     real(dp), dimension(:), intent(in) :: parameterset
     737             : 
     738             :     procedure(eval_interface), INTENT(IN), pointer :: eval
     739             : 
     740             :     logical, optional, intent(in) :: regularize
     741             : 
     742             :     real(dp) :: loglikelihood_evin2013_2
     743             : 
     744             :     ! modelled runoff for a given parameter set
     745             :     ! dim1=nTimeSteps, dim2=nGauges
     746           0 :     real(dp), dimension(:, :), allocatable :: runoff
     747             : 
     748             :     ! penalty term due to a parmeter set out of bound
     749           0 :     real(dp) :: penalty
     750             : 
     751             :     ! gauges counter
     752             :     integer(i4) :: gg
     753             : 
     754             :     ! aggregated simulated runoff
     755           0 :     real(dp), dimension(:), allocatable :: runoff_agg
     756             : 
     757             :     ! measured runoff
     758           0 :     real(dp), dimension(:), allocatable :: runoff_obs
     759             : 
     760             :     ! mask for measured runoff
     761           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
     762             : 
     763             :     integer(i4) :: nmeas
     764             : 
     765           0 :     real(dp), dimension(:), allocatable :: errors, sigma, eta, y
     766             : 
     767           0 :     real(dp), dimension(:), allocatable :: obs, calc, out
     768             : 
     769           0 :     real(dp) :: a, b, c, vary, vary1, ln2pi, tmp
     770             : 
     771             :     integer(i4) :: npara
     772             : 
     773             :     logical :: iregularize
     774             : 
     775             : 
     776           0 :     iregularize = .false.
     777           0 :     if (present(regularize)) iregularize = regularize
     778             : 
     779           0 :     npara = size(parameterset)
     780           0 :     call eval(parameterset(1 : npara - 2), runoff = runoff)
     781             : 
     782             :     ! extract runoff and append it to obs and calc
     783           0 :     do gg = 1, size(runoff, dim = 2) ! second dimension equals nGaugesTotal
     784             :       ! extract runoff
     785           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
     786             :       ! append it to variables
     787           0 :       call append(obs, runoff_obs)
     788           0 :       call append(calc, runoff_agg)
     789             : 
     790             :     end do
     791             : 
     792             :     ! ----------------------------------------
     793             : 
     794           0 :     nmeas = size(obs, dim = 1)
     795             : 
     796           0 :     allocate(out(nmeas), errors(nmeas), sigma(nmeas), eta(nmeas), y(nmeas))
     797             :     ! residual errors
     798           0 :     errors(:) = calc(:) - obs(:)
     799             : 
     800             :     ! linear error model
     801           0 :     a = parameterset(npara - 1)
     802           0 :     b = parameterset(npara)
     803           0 :     sigma(:) = a + b * calc(:)
     804             :     ! standardized residual errors (SRE)
     805           0 :     eta(:) = errors(:) / sigma(:)
     806             : 
     807             :     ! remove lag(1)-autocorrelation of SRE
     808           0 :     c = correlation(eta(2 : nmeas), eta(1 : nmeas - 1))
     809           0 :     y(1) = 0.0_dp ! only for completeness
     810           0 :     y(2 : nmeas) = eta(2 : nmeas) - c * eta(1 : nmeas - 1)
     811             : 
     812             :     ! likelihood of residual errors
     813           0 :     ln2pi = log(sqrt(2.0_dp * pi_dp))
     814           0 :     vary = 1.0_dp - c * c
     815           0 :     vary1 = 1.0_dp / vary
     816             :     loglikelihood_evin2013_2 = -ln2pi - 0.5_dp * eta(1) * eta(1) - log(sigma(1)) & ! li(eta(1))/sigma(1)
     817             :             - real(nmeas - 1, dp) * log(sqrt(2.0_dp * pi_dp * vary)) &
     818           0 :             - sum(0.5_dp * y(2 : nmeas) * y(2 : nmeas) * vary1) - sum(log(sigma(2 : nmeas)))
     819             : 
     820           0 :     if (iregularize) then
     821             :       ! Regularistion term as deviation from initial parameter value
     822             :       penalty = parameter_regularization(&
     823             :               parameterset(1 : npara - 2), &        ! current parameter set
     824           0 :               global_parameters(1 : npara - 2, 3), &        ! prior/initial parameter set
     825           0 :               global_parameters(1 : npara - 2, 1 : 2), &        ! bounds
     826           0 :               eq(global_parameters(1 : npara - 2, 4), 1.0_dp)) ! used/unused
     827             : 
     828           0 :       tmp = loglikelihood_evin2013_2 + penalty
     829             :       call message( &
     830             :         '-loglikelihood_evin2013_2, + penalty, chi^2: ', &
     831             :         num2str(-loglikelihood_evin2013_2), &
     832             :         num2str(-tmp), &
     833           0 :         num2str(-tmp / real(nmeas, dp)))
     834           0 :       loglikelihood_evin2013_2 = tmp
     835             :     else
     836             :       call message( &
     837             :         '-loglikelihood_evin2013_2, chi^2: ', &
     838             :         num2str(-loglikelihood_evin2013_2), &
     839           0 :         num2str(-loglikelihood_evin2013_2 / real(nmeas, dp)))
     840             :     end if
     841             : 
     842           0 :     deallocate(runoff, runoff_agg, runoff_obs_mask, runoff_obs)
     843           0 :     deallocate(obs, calc, out, errors, sigma, eta, y)
     844             : 
     845           0 :   END FUNCTION loglikelihood_evin2013_2
     846             : 
     847             :   !    NAME
     848             :   !        parameter_regularization
     849             : 
     850             :   !    PURPOSE
     851             :   !>       \brief TODO: add description
     852             : 
     853             :   !>       \details TODO: add description
     854             : 
     855             :   !    INTENT(IN)
     856             :   !>       \param[in] "real(dp), dimension(:) :: paraset"
     857             :   !>       \param[in] "real(dp), dimension(size(paraset)) :: prior"
     858             :   !>       \param[in] "real(dp), dimension(size(paraset), 2) :: bounds" (min, max)
     859             :   !>       \param[in] "logical, dimension(size(paraset)) :: mask"
     860             : 
     861             :   !    HISTORY
     862             :   !>       \authors Robert Schweppe
     863             : 
     864             :   !>       \date Jun 2018
     865             : 
     866             :   ! Modifications:
     867             : 
     868           0 :   FUNCTION parameter_regularization(paraset, prior, bounds, mask)
     869             : 
     870           0 :     use mo_constants, only : pi_dp
     871             : 
     872             :     implicit none
     873             : 
     874             :     real(dp), dimension(:), intent(in) :: paraset
     875             : 
     876             :     real(dp), dimension(size(paraset)), intent(in) :: prior
     877             : 
     878             :     ! (min, max)
     879             :     real(dp), dimension(size(paraset), 2), intent(in) :: bounds
     880             : 
     881             :     logical, dimension(size(paraset)), intent(in) :: mask
     882             : 
     883             :     real(dp) :: parameter_regularization
     884             : 
     885             :     integer(i4) :: ipara
     886             : 
     887             :     integer(i4) :: npara
     888             : 
     889             :     real(dp), parameter :: onetwelveth = 1._dp / 12._dp
     890             : 
     891           0 :     real(dp), dimension(size(paraset)) :: sigma
     892             : 
     893             : 
     894           0 :     npara = size(paraset, 1)
     895             : 
     896           0 :     sigma = sqrt(onetwelveth * (bounds(:, 2) - bounds(:, 1))**2) ! standard deviation of uniform distribution
     897           0 :     parameter_regularization = -sum(log(sqrt(2.0_dp * pi_dp) * sigma), mask = mask)
     898             : 
     899           0 :     do ipara = 1, npara
     900           0 :       if (mask(ipara)) then
     901             :         ! if ((paraset(ipara) .lt. bounds(ipara,1)) .or. (paraset(ipara) .gt. bounds(ipara,2))) then
     902             :         !    ! outside bounds
     903             :         parameter_regularization = parameter_regularization - &
     904           0 :                 0.5_dp * ((paraset(ipara) - prior(ipara)) / sigma(ipara))**2
     905             :         ! else
     906             :         !    ! in bound
     907             :         !    parameter_regularization = 0.0_dp
     908             :         ! end if
     909             :       end if
     910             :     end do
     911             : 
     912           0 :   END FUNCTION parameter_regularization
     913             : 
     914             :   ! ------------------------------------------------------------------
     915             : 
     916             :   !    NAME
     917             :   !        loglikelihood_trend_no_autocorr
     918             : 
     919             :   !    PURPOSE
     920             :   !>       \brief Logarithmic likelihood function with linear trend removed.
     921             : 
     922             :   !>       \details The logarithmis likelihood function is used when mHM runs in MCMC mode.
     923             :   !>       It can also be used for optimization when selecting the likelihood in the
     924             :   !>       namelist as \e opti\_function.
     925             : 
     926             :   !    INTENT(IN)
     927             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
     928             :   !>       \param[in] "procedure(eval_interface) :: eval"
     929             :   !>       \param[in] "real(dp) :: stddev_old"                 standard deviation of data
     930             : 
     931             :   !    INTENT(OUT), OPTIONAL
     932             :   !>       \param[out] "real(dp), optional :: stddev_new" standard deviation of errors with removed trendbetween model
     933             :   !>       run using parameter set and observation
     934             :   !>       \param[out] "real(dp), optional :: likeli_new" logarithmic likelihood determined with stddev_new instead of
     935             :   !>       stddev
     936             : 
     937             :   !    RETURN
     938             :   !>       \return real(dp) :: loglikelihood_trend_no_autocorr — logarithmic likelihood using given stddev
     939             :   !>       but remove optimal trend in errors
     940             :   !>       (absolute between running model with parameterset and observation)
     941             : 
     942             :   !    HISTORY
     943             :   !>       \authors Juliane Mai and Matthias Cuntz
     944             : 
     945             :   !>       \date Mar 2014
     946             : 
     947             :   ! Modifications:
     948             :   ! Stephan Thober  Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2)
     949             :   !                            to not interfere with mRM
     950             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     951             : 
     952           0 :   FUNCTION loglikelihood_trend_no_autocorr(parameterset, eval, stddev_old, stddev_new, likeli_new)
     953             : 
     954           0 :     use mo_append, only : append
     955             :     use mo_linfit, only : linfit
     956             :     use mo_moment, only : stddev
     957             : 
     958             :     implicit none
     959             : 
     960             :     real(dp), dimension(:), intent(in) :: parameterset
     961             : 
     962             :     procedure(eval_interface), INTENT(IN), pointer :: eval
     963             : 
     964             :     ! standard deviation of data
     965             :     real(dp), intent(in) :: stddev_old
     966             : 
     967             :     ! standard deviation of errors with removed trendbetween model run using parameter set and observation
     968             :     real(dp), intent(out), optional :: stddev_new
     969             : 
     970             :     ! logarithmic likelihood determined with stddev_new instead of stddev
     971             :     real(dp), intent(out), optional :: likeli_new
     972             : 
     973             :     real(dp) :: loglikelihood_trend_no_autocorr
     974             : 
     975             :     ! modelled runoff for a given parameter set
     976             :     ! dim1=nTimeSteps, dim2=nGauges
     977           0 :     real(dp), dimension(:, :), allocatable :: runoff
     978             : 
     979             :     ! gauges counter
     980             :     integer(i4) :: gg
     981             : 
     982             :     ! aggregated simulated runoff
     983           0 :     real(dp), dimension(:), allocatable :: runoff_agg
     984             : 
     985             :     ! measured runoff
     986           0 :     real(dp), dimension(:), allocatable :: runoff_obs
     987             : 
     988             :     ! mask for aggregated measured runoff
     989           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
     990             : 
     991             :     integer(i4) :: nmeas
     992             : 
     993           0 :     real(dp), dimension(:), allocatable :: errors
     994             : 
     995           0 :     real(dp), dimension(:), allocatable :: obs, calc, out
     996             : 
     997           0 :     real(dp) :: a, b
     998             : 
     999           0 :     real(dp) :: stddev_tmp
    1000             : 
    1001             : 
    1002           0 :     call eval(parameterset, runoff = runoff)
    1003             : 
    1004             :     ! extract runoff and append it to obs and calc
    1005           0 :     do gg = 1, size(runoff, dim = 2) ! second dimension equals nGaugesTotal
    1006             :       ! extract runoff
    1007           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1008             :       ! append it to variables
    1009           0 :       call append(obs, runoff_obs)
    1010           0 :       call append(calc, runoff_agg)
    1011             : 
    1012             :     end do
    1013             : 
    1014             :     ! ----------------------------------------
    1015           0 :     nmeas = size(obs, dim = 1)
    1016             : 
    1017             :     ! allocate output variables
    1018           0 :     allocate(out(nmeas), errors(nmeas))
    1019           0 :     errors(:) = abs(calc(:) - obs(:))
    1020             : 
    1021             :     ! remove linear trend of errors - must be model NOT obs
    1022           0 :     out = linfit(calc, errors, a = a, b = b, model2 = .False.)
    1023           0 :     errors(:) = errors(:) - (a + calc(:) * b)
    1024             : 
    1025             :     ! you have to take stddev_old=const because otherwise loglikelihood_trend_no_autocorr is always N
    1026             :     ! in MCMC stddev_old gets updated only when a better likelihood is found.
    1027           0 :     loglikelihood_trend_no_autocorr = sum(errors(:) * errors(:) / stddev_old**2)
    1028           0 :     loglikelihood_trend_no_autocorr = -0.5_dp * loglikelihood_trend_no_autocorr
    1029             : 
    1030           0 :     call message('-loglikelihood_trend_no_autocorr = ', num2str(-loglikelihood_trend_no_autocorr))
    1031             : 
    1032           0 :     stddev_tmp = 1.0_dp  ! initialization
    1033           0 :     if (present(stddev_new) .or. present(likeli_new)) then
    1034           0 :       stddev_tmp = stddev(errors(:))
    1035             :     end if
    1036           0 :     if (present(stddev_new)) then
    1037           0 :       stddev_new = stddev_tmp
    1038             :     end if
    1039           0 :     if (present(likeli_new)) then
    1040           0 :       likeli_new = sum(errors(:) * errors(:) / stddev_tmp**2)
    1041           0 :       likeli_new = -0.5_dp * likeli_new
    1042             :     end if
    1043             : 
    1044           0 :     deallocate(runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1045           0 :     deallocate(obs, calc, out, errors)
    1046             : 
    1047           0 :   END FUNCTION loglikelihood_trend_no_autocorr
    1048             : 
    1049             :   ! ------------------------------------------------------------------
    1050             : 
    1051             :   !    NAME
    1052             :   !        objective_lnnse
    1053             : 
    1054             :   !    PURPOSE
    1055             :   !>       \brief Objective function of logarithmic NSE.
    1056             : 
    1057             :   !>       \details The objective function only depends on a parameter vector.
    1058             :   !>       The model will be called with that parameter vector and
    1059             :   !>       the model output is subsequently compared to observed data.
    1060             :   !>       Therefore, the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE \f$
    1061             :   !>       \f[ lnNSE = 1 - \frac{\sum_{i=1}^N (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1062             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f]
    1063             :   !>       is calculated.
    1064             :   !>       \f[ obj\_value = lnNSE \f]
    1065             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1066             : 
    1067             :   !    INTENT(IN)
    1068             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1069             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1070             : 
    1071             :   !    RETURN
    1072             :   !>       \return real(dp) :: objective_lnnse — objective function value
    1073             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    1074             : 
    1075             :   !    HISTORY
    1076             :   !>       \authors Juliane Mai
    1077             : 
    1078             :   !>       \date May 2013
    1079             : 
    1080             :   ! Modifications:
    1081             :   ! Stephan Thober  Jan 2015 - introduced extract_runoff
    1082             :   ! Stephan Thober  Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    1083             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1084             : 
    1085           0 :   FUNCTION objective_lnnse(parameterset, eval)
    1086             : 
    1087           0 :     use mo_errormeasures, only : lnnse
    1088             : 
    1089             :     implicit none
    1090             : 
    1091             :     real(dp), dimension(:), intent(in) :: parameterset
    1092             : 
    1093             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1094             : 
    1095             :     real(dp) :: objective_lnnse
    1096             : 
    1097             :     ! modelled runoff for a given parameter set
    1098             :     ! dim1=nTimeSteps, dim2=nGauges
    1099           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    1100             : 
    1101             :     ! gauges counter
    1102             :     integer(i4) :: gg
    1103             : 
    1104             :     integer(i4) :: nGaugesTotal
    1105             : 
    1106             :     ! aggregated simulated runoff
    1107           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1108             : 
    1109             :     ! measured runoff
    1110           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1111             : 
    1112             :     ! mask for measured runoff
    1113           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1114             : 
    1115             : 
    1116           0 :     call eval(parameterset, runoff = runoff)
    1117           0 :     nGaugesTotal = size(runoff, dim = 2)
    1118             : 
    1119           0 :     objective_lnnse = 0.0_dp
    1120           0 :     do gg = 1, nGaugesTotal
    1121             :       ! extract runoff
    1122           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1123             :       ! lnNSE
    1124             :       objective_lnnse = objective_lnnse + &
    1125           0 :               lnnse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1126             :     end do
    1127             : #ifndef MPI
    1128             :     ! objective function value which will be minimized
    1129           0 :     objective_lnnse = 1.0_dp - objective_lnnse / real(nGaugesTotal, dp)
    1130             : 
    1131           0 :     call message('objective_lnnse = ', num2str(objective_lnnse))
    1132             :     ! pause
    1133             : #endif
    1134             : 
    1135           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    1136             : 
    1137           0 :   END FUNCTION objective_lnnse
    1138             : 
    1139             :   ! ------------------------------------------------------------------
    1140             : 
    1141             :   !    NAME
    1142             :   !        objective_sse
    1143             : 
    1144             :   !    PURPOSE
    1145             :   !>       \brief Objective function of SSE.
    1146             : 
    1147             :   !>       \details The objective function only depends on a parameter vector.
    1148             :   !>       The model will be called with that parameter vector and
    1149             :   !>       the model output is subsequently compared to observed data.
    1150             :   !>       Therefore, the sum squared errors
    1151             :   !>       \f[ SSE = \sum_{i=1}^N (Q_{obs}(i) - Q_{model}(i))^2 \f]
    1152             :   !>       is calculated and the objective function is
    1153             :   !>       \f[ obj\_value = SSE \f]
    1154             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1155             : 
    1156             :   !    INTENT(IN)
    1157             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1158             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1159             : 
    1160             :   !    RETURN
    1161             :   !>       \return real(dp) :: objective_sse — objective function value
    1162             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    1163             : 
    1164             :   !    HISTORY
    1165             :   !>       \authors Juliane Mai and Matthias Cuntz
    1166             : 
    1167             :   !>       \date March 2014
    1168             : 
    1169             :   ! Modifications:
    1170             :   ! Stephan Thober Jan 2015 - introduced extract_runoff
    1171             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    1172             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1173             : 
    1174           0 :   FUNCTION objective_sse(parameterset, eval)
    1175             : 
    1176           0 :     use mo_errormeasures, only : sse
    1177             : 
    1178             :     implicit none
    1179             : 
    1180             :     real(dp), dimension(:), intent(in) :: parameterset
    1181             : 
    1182             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1183             : 
    1184             :     real(dp) :: objective_sse
    1185             : 
    1186             :     ! modelled runoff for a given parameter set
    1187             :     ! dim1=nTimeSteps, dim2=nGauges
    1188           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    1189             : 
    1190             :     ! gauges counter
    1191             :     integer(i4) :: gg
    1192             : 
    1193             :     integer(i4) :: nGaugesTotal
    1194             : 
    1195             :     ! aggregated simulated runoff
    1196           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1197             : 
    1198             :     ! measured runoff
    1199           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1200             : 
    1201             :     ! mask for measured runoff
    1202           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1203             : 
    1204             : 
    1205           0 :     call eval(parameterset, runoff = runoff)
    1206           0 :     nGaugesTotal = size(runoff, dim = 2)
    1207             : 
    1208           0 :     objective_sse = 0.0_dp
    1209           0 :     do gg = 1, nGaugesTotal
    1210             :       !
    1211           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1212             :       !
    1213             :       objective_sse = objective_sse + &
    1214           0 :               sse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1215             :     end do
    1216             : #ifndef MPI
    1217             :     ! objective_sse = objective_sse + sse(gauge%Q, runoff_model_agg) !, runoff_model_agg_mask)
    1218           0 :     objective_sse = objective_sse / real(nGaugesTotal, dp)
    1219             : 
    1220           0 :     call message('objective_sse = ', num2str(objective_sse))
    1221             :     ! pause
    1222             : #endif
    1223             : 
    1224           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    1225             : 
    1226           0 :   END FUNCTION objective_sse
    1227             : 
    1228             :   ! ------------------------------------------------------------------
    1229             : 
    1230             :   !    NAME
    1231             :   !        objective_nse
    1232             : 
    1233             :   !    PURPOSE
    1234             :   !>       \brief Objective function of NSE.
    1235             : 
    1236             :   !>       \details The objective function only depends on a parameter vector.
    1237             :   !>       The model will be called with that parameter vector and
    1238             :   !>       the model output is subsequently compared to observed data.
    1239             :   !>       Therefore, the Nash-Sutcliffe model efficiency coefficient \f$ NSE \f$
    1240             :   !>       \f[ NSE = 1 - \frac{\sum_{i=1}^N (Q_{obs}(i) - Q_{model}(i))^2}
    1241             :   !>       {\sum_{i=1}^N (Q_{obs}(i) - \bar{Q_{obs}})^2} \f]
    1242             :   !>       is calculated and the objective function is
    1243             :   !>       \f[ obj\_value = 1-NSE \f]
    1244             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1245             : 
    1246             :   !    INTENT(IN)
    1247             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1248             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1249             : 
    1250             :   !    RETURN
    1251             :   !>       \return real(dp) :: objective_nse — objective function value
    1252             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    1253             : 
    1254             :   !    HISTORY
    1255             :   !>       \authors Juliane Mai
    1256             : 
    1257             :   !>       \date May 2013
    1258             : 
    1259             :   ! Modifications:
    1260             :   ! Stephan Thober Jan 2015 - introduced extract runoff
    1261             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    1262             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1263             : 
    1264           0 :   FUNCTION objective_nse(parameterset, eval)
    1265             : 
    1266           0 :     use mo_errormeasures, only : nse
    1267             : 
    1268             :     implicit none
    1269             : 
    1270             :     real(dp), dimension(:), intent(in) :: parameterset
    1271             : 
    1272             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1273             : 
    1274             :     real(dp) :: objective_nse
    1275             : 
    1276             :     ! modelled runoff for a given parameter set
    1277             :     ! dim1=nTimeSteps, dim2=nGauges
    1278           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    1279             : 
    1280             :     ! gauges counter
    1281             :     integer(i4) :: gg
    1282             : 
    1283             :     integer(i4) :: nGaugesTotal
    1284             : 
    1285             :     ! aggregated simulated runoff
    1286           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1287             : 
    1288             :     ! measured runoff
    1289           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1290             : 
    1291             :     ! mask for aggregated measured runoff
    1292           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1293             : 
    1294             : 
    1295           0 :     call eval(parameterset, runoff = runoff)
    1296           0 :     nGaugesTotal = size(runoff, dim = 2)
    1297             : 
    1298           0 :     objective_nse = 0.0_dp
    1299           0 :     do gg = 1, nGaugesTotal
    1300             :       !
    1301           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1302             :       !
    1303             :       objective_nse = objective_nse + &
    1304           0 :               nse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1305             :     end do
    1306             : #ifndef MPI
    1307             :     ! objective_nse = objective_nse + nse(gauge%Q, runoff_model_agg) !, runoff_model_agg_mask)
    1308           0 :     objective_nse = 1.0_dp - objective_nse / real(nGaugesTotal, dp)
    1309             : 
    1310           0 :     call message('objective_nse (i.e., 1 - NSE) = ', num2str(objective_nse))
    1311             :     ! pause
    1312             : #endif
    1313             : 
    1314           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    1315             : 
    1316           0 :   END FUNCTION objective_nse
    1317             : 
    1318             :   ! ------------------------------------------------------------------
    1319             : 
    1320             :   !    NAME
    1321             :   !        objective_equal_nse_lnnse
    1322             : 
    1323             :   !    PURPOSE
    1324             :   !>       \brief Objective function equally weighting NSE and lnNSE.
    1325             : 
    1326             :   !>       \details The objective function only depends on a parameter vector.
    1327             :   !>       The model will be called with that parameter vector and
    1328             :   !>       the model output is subsequently compared to observed data.
    1329             :   !>       Therefore, the Nash-Sutcliffe model efficiency coefficient \f$ NSE \f$
    1330             :   !>       \f[ NSE = 1 - \frac{\sum_{i=1}^N (Q_{obs}(i) - Q_{model}(i))^2}
    1331             :   !>       {\sum_{i=1}^N (Q_{obs}(i) - \bar{Q_{obs}})^2} \f]
    1332             :   !>       and the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE \f$
    1333             :   !>       \f[ lnNSE = 1 - \frac{\sum_{i=1}^N (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1334             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f]
    1335             :   !>       are calculated and added up equally weighted:
    1336             :   !>       \f[ obj\_value = \frac{1}{2} (NSE + lnNSE) \f]
    1337             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1338             : 
    1339             :   !    INTENT(IN)
    1340             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1341             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1342             : 
    1343             :   !    RETURN
    1344             :   !>       \return real(dp) :: objective_equal_nse_lnnse — objective function value
    1345             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    1346             : 
    1347             :   !    HISTORY
    1348             :   !>       \authors Juliane Mai
    1349             : 
    1350             :   !>       \date May 2013
    1351             : 
    1352             :   ! Modifications:
    1353             :   ! Stephan Thober Jan 2015 - introduced extract_runoff
    1354             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    1355             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1356             : 
    1357           6 :   FUNCTION objective_equal_nse_lnnse(parameterset, eval)
    1358             : 
    1359           0 :     use mo_errormeasures, only : lnnse, nse
    1360             : 
    1361             :     implicit none
    1362             : 
    1363             :     real(dp), dimension(:), intent(in) :: parameterset
    1364             : 
    1365             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1366             : 
    1367             :     real(dp) :: objective_equal_nse_lnnse
    1368             : 
    1369             :     ! modelled runoff for a given parameter set
    1370             :     ! dim2=nGauges
    1371           6 :     real(dp), allocatable, dimension(:, :) :: runoff
    1372             : 
    1373             :     ! gauges counter
    1374             :     integer(i4) :: gg
    1375             : 
    1376             :     integer(i4) :: nGaugesTotal
    1377             : 
    1378             :     ! measured runoff
    1379           6 :     real(dp), dimension(:), allocatable :: runoff_obs
    1380             : 
    1381             :     ! aggregated simulated runoff
    1382           6 :     real(dp), dimension(:), allocatable :: runoff_agg
    1383             : 
    1384             :     ! mask for aggregated measured runoff
    1385           6 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1386             : 
    1387             : 
    1388           6 :     call eval(parameterset, runoff = runoff)
    1389           6 :     nGaugesTotal = size(runoff, dim = 2)
    1390             : 
    1391           6 :     objective_equal_nse_lnnse = 0.0_dp
    1392          12 :     do gg = 1, nGaugesTotal
    1393             :       ! extract runoff
    1394           6 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1395             :       !
    1396             :       ! NSE
    1397             :       objective_equal_nse_lnnse = objective_equal_nse_lnnse + &
    1398           6 :               0.5_dp * nse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1399             :       ! lnNSE
    1400             :       objective_equal_nse_lnnse = objective_equal_nse_lnnse + &
    1401          18 :               0.5_dp * lnnse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1402             :     end do
    1403             : #ifndef MPI
    1404             :     ! objective function value which will be minimized
    1405           6 :     objective_equal_nse_lnnse = 1.0_dp - objective_equal_nse_lnnse / real(nGaugesTotal, dp)
    1406             : 
    1407           6 :     call message('objective_equal_nse_lnnse = ', num2str(objective_equal_nse_lnnse))
    1408             : #endif
    1409             : 
    1410             :     ! clean up
    1411           6 :     deallocate(runoff_agg, runoff_obs)
    1412           6 :     deallocate(runoff_obs_mask)
    1413             : 
    1414           6 :   END FUNCTION objective_equal_nse_lnnse
    1415             : 
    1416             : 
    1417             :   ! ------------------------------------------------------------------
    1418             : 
    1419             :   !    NAME
    1420             :   !        multi_objective_nse_lnnse
    1421             : 
    1422             :   !    PURPOSE
    1423             :   !>       \brief Multi-objective function with NSE and lnNSE.
    1424             : 
    1425             :   !>       \details The objective function only depends on a parameter vector.
    1426             :   !>       The model will be called with that parameter vector and
    1427             :   !>       the model output is subsequently compared to observed data.
    1428             :   !>       Therefore, the Nash-Sutcliffe model efficiency coefficient \f$ NSE \f$
    1429             :   !>       \f[ NSE = 1 - \frac{\sum_{i=1}^N (Q_{obs}(i) - Q_{model}(i))^2}
    1430             :   !>       {\sum_{i=1}^N (Q_{obs}(i) - \bar{Q_{obs}})^2} \f]
    1431             :   !>       and the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE \f$
    1432             :   !>       \f[ lnNSE = 1 - \frac{\sum_{i=1}^N (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1433             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f]
    1434             :   !>       are calculated and both returned.
    1435             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1436             :   !>       To calibrate this objective you need a multi-objective optimizer like PA-DDS.
    1437             : 
    1438             :   !    INTENT(IN)
    1439             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1440             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1441             : 
    1442             :   !    RETURN
    1443             :   !>       \return real(dp), dimension(2) :: multi_objective_nse_lnnse — objective function value
    1444             :   !>       (which will be e.g. minimized by an optimization routine like PA-DDS)
    1445             : 
    1446             :   !    HISTORY
    1447             :   !>       \authors Juliane Mai
    1448             : 
    1449             :   !>       \date Oct 2015
    1450             : 
    1451             :   ! Modifications:
    1452             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1453             : 
    1454           0 :   FUNCTION multi_objective_nse_lnnse(parameterset, eval)
    1455             : 
    1456           6 :     use mo_errormeasures, only : lnnse, nse
    1457             : 
    1458             :     implicit none
    1459             : 
    1460             :     real(dp), dimension(:), intent(in) :: parameterset
    1461             : 
    1462             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1463             : 
    1464             :     real(dp), dimension(2) :: multi_objective_nse_lnnse
    1465             : 
    1466             :     ! modelled runoff for a given parameter set
    1467             :     ! dim2=nGauges
    1468           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    1469             : 
    1470             :     ! gauges counter
    1471             :     integer(i4) :: gg
    1472             : 
    1473             :     integer(i4) :: nGaugesTotal
    1474             : 
    1475             :     ! measured runoff
    1476           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1477             : 
    1478             :     ! aggregated simulated runoff
    1479           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1480             : 
    1481             :     ! mask for aggregated measured runoff
    1482           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1483             : 
    1484             : 
    1485             :     ! call mhm_eval(parameterset, runoff=runoff)
    1486           0 :     call eval(parameterset, runoff = runoff)
    1487           0 :     nGaugesTotal = size(runoff, dim = 2)
    1488             : 
    1489           0 :     multi_objective_nse_lnnse = 0.0_dp
    1490           0 :     do gg = 1, nGaugesTotal
    1491             :       ! extract runoff
    1492           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1493             :       !
    1494             :       ! NSE
    1495             :       multi_objective_nse_lnnse(1) = multi_objective_nse_lnnse(1) + &
    1496           0 :               nse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1497             :       ! lnNSE
    1498             :       multi_objective_nse_lnnse(2) = multi_objective_nse_lnnse(2) + &
    1499           0 :               lnnse(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    1500             :     end do
    1501             :     ! objective function value which will be minimized
    1502           0 :     multi_objective_nse_lnnse(:) = 1.0_dp - multi_objective_nse_lnnse(:) / real(nGaugesTotal, dp)
    1503             : 
    1504             :     ! write(*,*) 'multi_objective_nse_lnnse = ',multi_objective_nse_lnnse
    1505             : 
    1506             :     ! clean up
    1507           0 :     deallocate(runoff_agg, runoff_obs)
    1508           0 :     deallocate(runoff_obs_mask)
    1509             : 
    1510           0 :   END FUNCTION multi_objective_nse_lnnse
    1511             : 
    1512             :   ! ------------------------------------------------------------------
    1513             : 
    1514             :   !    NAME
    1515             :   !        multi_objective_lnnse_highflow_lnnse_lowflow
    1516             : 
    1517             :   !    PURPOSE
    1518             :   !>       \brief Multi-objective function with NSE and lnNSE.
    1519             : 
    1520             :   !>       \details The objective function only depends on a parameter vector.
    1521             :   !>       The model will be called with that parameter vector and
    1522             :   !>       the model output is subsequently compared to observed data.
    1523             : 
    1524             :   !>       A timepoint \f$t\f$ of the observed data is marked as a lowflow timepoint \f$t_{low}\f$ if
    1525             :   !>       \f[ Q_{obs}(t) < min(Q_{obs}) + 0.05 * ( max(Q_{obs}) - min(Q_{obs}) )\f]
    1526             :   !>       and a timepoint \f$t\f$ of the observed data is marked as a highflow timepoint \f$t_{high}\f$ if
    1527             :   !>       \f[ t_{high} if Q_{obs}(i) > percentile(Q_{obs},95.)\f]
    1528             :   !>       This timepoint identification is only performed for the observed data.
    1529             : 
    1530             :   !>       The first objective is the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE_{high} \f$
    1531             :   !>       of discharge values at high-flow timepoints
    1532             :   !>       \f[ lnNSE_{high} = 1 - \frac{\sum_{i=1}^{N_{high}} (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1533             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f] .
    1534             :   !>       The second objective is the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE_{low} \f$
    1535             :   !>       of discharge values at low-flow timepoints
    1536             :   !>       \f[ lnNSE_{low} = 1 - \frac{\sum_{i=1}^{N_{low}} (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1537             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f] .
    1538             :   !>       Both objectives are returned.
    1539             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1540             :   !>       To calibrate this objective you need a multi-objective optimizer like PA-DDS.
    1541             : 
    1542             :   !    INTENT(IN)
    1543             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1544             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1545             : 
    1546             :   !    RETURN
    1547             :   !>       \return real(dp), dimension(2) :: multi_objective_lnnse_highflow_lnnse_lowflow &mdash; objective function
    1548             :   !>       value
    1549             :   !>       (which will be e.g. minimized by an optimization routine like PA-DDS)
    1550             : 
    1551             :   !    HISTORY
    1552             :   !>       \authors Juliane Mai
    1553             : 
    1554             :   !>       \date Oct 2015
    1555             : 
    1556             :   ! Modifications:
    1557             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1558             : 
    1559           0 :   FUNCTION multi_objective_lnnse_highflow_lnnse_lowflow(parameterset, eval)
    1560             : 
    1561           0 :     use mo_errormeasures, only : lnnse
    1562             :     use mo_percentile, only : percentile
    1563             : 
    1564             :     implicit none
    1565             : 
    1566             :     real(dp), dimension(:), intent(in) :: parameterset
    1567             : 
    1568             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1569             : 
    1570             :     real(dp), dimension(2) :: multi_objective_lnnse_highflow_lnnse_lowflow
    1571             : 
    1572             :     ! modelled runoff for a given parameter set
    1573           0 :     real(dp), dimension(:, :), allocatable :: runoff
    1574             : 
    1575             :     ! gauges counter
    1576             :     integer(i4) :: gg
    1577             : 
    1578             :     integer(i4) :: nGaugesTotal
    1579             : 
    1580             :     ! measured runoff
    1581           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1582             : 
    1583             :     ! aggregated simulated runoff
    1584           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1585             : 
    1586             :     ! mask for aggregated measured runoff
    1587           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1588             : 
    1589             :     ! upper discharge value to determine lowflow timepoints
    1590           0 :     real(dp) :: q_low
    1591             : 
    1592             :     ! lower discharge value to determine highflow timepoints
    1593           0 :     real(dp) :: q_high
    1594             : 
    1595             :     ! total number of discharge values
    1596             :     integer(i4) :: nrunoff
    1597             : 
    1598             :     ! timepoint counter
    1599             :     integer(i4) :: tt
    1600             : 
    1601             :     ! mask to get lowflow values
    1602           0 :     logical, dimension(:), allocatable :: lowflow_mask
    1603             : 
    1604             :     ! mask to get highflow values
    1605           0 :     logical, dimension(:), allocatable :: highflow_mask
    1606             : 
    1607             : 
    1608             :     ! call mhm_eval(parameterset, runoff=runoff)
    1609           0 :     call eval(parameterset, runoff = runoff)
    1610           0 :     nGaugesTotal = size(runoff, dim = 2)
    1611             : 
    1612           0 :     multi_objective_lnnse_highflow_lnnse_lowflow = 0.0_dp
    1613           0 :     do gg = 1, nGaugesTotal
    1614             :       !
    1615             :       ! extract runoff
    1616           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1617           0 :       nrunoff = size(runoff_obs, dim = 1)
    1618             :       !print*, 'nrunoff = ',nrunoff
    1619             :       !
    1620             :       ! mask for highflow timepoints
    1621           0 :       if (allocated(highflow_mask)) deallocate(highflow_mask)
    1622           0 :       allocate(highflow_mask(nrunoff))
    1623           0 :       highflow_mask = .false.
    1624           0 :       q_high = percentile(runoff_obs, 95._dp, mask = runoff_obs_mask)
    1625           0 :       forall(tt = 1 : nrunoff) highflow_mask(tt) = (runoff_obs(tt) > q_high .and. runoff_obs_mask(tt))
    1626             :       !print*, 'nhigh = ',count(highflow_mask)
    1627             :       !
    1628             :       ! mask for lowflow timepoints
    1629           0 :       if (allocated(lowflow_mask)) deallocate(lowflow_mask)
    1630           0 :       allocate(lowflow_mask(nrunoff))
    1631           0 :       lowflow_mask = .false.
    1632           0 :       q_low = minval(runoff_obs, mask = runoff_obs_mask) &
    1633           0 :               + 0.05_dp * (maxval(runoff_obs, mask = runoff_obs_mask) - minval(runoff_obs, mask = runoff_obs_mask))
    1634           0 :       forall(tt = 1 : nrunoff) lowflow_mask(tt) = (runoff_obs(tt) < q_low .and. runoff_obs_mask(tt))
    1635             :       !print*, 'nlow  = ',count(lowflow_mask)
    1636             :       !
    1637             :       ! lnNSE highflows
    1638             :       multi_objective_lnnse_highflow_lnnse_lowflow(1) = multi_objective_lnnse_highflow_lnnse_lowflow(1) + &
    1639           0 :               lnnse(runoff_obs, runoff_agg, mask = highflow_mask)
    1640             :       !
    1641             :       ! lnNSE lowflows
    1642             :       multi_objective_lnnse_highflow_lnnse_lowflow(2) = multi_objective_lnnse_highflow_lnnse_lowflow(2) + &
    1643           0 :               lnnse(runoff_obs, runoff_agg, mask = lowflow_mask)
    1644             :     end do
    1645             :     ! objective function value which will be minimized
    1646             :     multi_objective_lnnse_highflow_lnnse_lowflow(:) = 1.0_dp &
    1647           0 :             - multi_objective_lnnse_highflow_lnnse_lowflow(:) / real(nGaugesTotal, dp)
    1648             : 
    1649             :     ! write(*,*) 'multi_objective_lnnse_highflow_lnnse_lowflow = ',multi_objective_lnnse_highflow_lnnse_lowflow
    1650             : 
    1651             :     ! clean up
    1652           0 :     deallocate(runoff_agg, runoff_obs)
    1653           0 :     deallocate(runoff_obs_mask)
    1654             : 
    1655           0 :   END FUNCTION multi_objective_lnnse_highflow_lnnse_lowflow
    1656             : 
    1657             :   ! ------------------------------------------------------------------
    1658             : 
    1659             :   !    NAME
    1660             :   !        multi_objective_lnnse_highflow_lnnse_lowflow_2
    1661             : 
    1662             :   !    PURPOSE
    1663             :   !>       \brief Multi-objective function with NSE and lnNSE.
    1664             : 
    1665             :   !>       \details The objective function only depends on a parameter vector.
    1666             :   !>       The model will be called with that parameter vector and
    1667             :   !>       the model output is subsequently compared to observed data.
    1668             : 
    1669             :   !>       A timepoint \f$t\f$ of the observed data is marked as a lowflow timepoint \f$t_{low}\f$ if
    1670             :   !>       \f[ Q_{obs}(t) < min(Q_{obs}) + 0.05 * ( max(Q_{obs}) - min(Q_{obs}) )\f]
    1671             :   !>       and all other timepoints are marked as a highflow timepoints \f$t_{high}\f$.
    1672             :   !>       This timepoint identification is only performed for the observed data.
    1673             : 
    1674             :   !>       The first objective is the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE_{high} \f$
    1675             :   !>       of discharge values at high-flow timepoints
    1676             :   !>       \f[ lnNSE_{high} = 1 - \frac{\sum_{i=1}^{N_{high}} (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1677             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f] .
    1678             :   !>       The second objective is the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE_{low} \f$
    1679             :   !>       of discharge values at low-flow timepoints
    1680             :   !>       \f[ lnNSE_{low} = 1 - \frac{\sum_{i=1}^{N_{low}} (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1681             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f] .
    1682             :   !>       Both objectives are returned.
    1683             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1684             :   !>       To calibrate this objective you need a multi-objective optimizer like PA-DDS.
    1685             : 
    1686             :   !    INTENT(IN)
    1687             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1688             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1689             : 
    1690             :   !    RETURN
    1691             :   !>       \return real(dp), dimension(2) :: multi_objective_lnnse_highflow_lnnse_lowflow_2 &mdash; objective function
    1692             :   !>       value
    1693             :   !>       (which will be e.g. minimized by an optimization routine like PA-DDS)
    1694             : 
    1695             :   !    HISTORY
    1696             :   !>       \authors Juliane Mai
    1697             : 
    1698             :   !>       \date Oct 2015
    1699             : 
    1700             :   ! Modifications:
    1701             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1702             : 
    1703           0 :   FUNCTION multi_objective_lnnse_highflow_lnnse_lowflow_2(parameterset, eval)
    1704             : 
    1705           0 :     use mo_errormeasures, only : lnnse
    1706             : 
    1707             :     implicit none
    1708             : 
    1709             :     real(dp), dimension(:), intent(in) :: parameterset
    1710             : 
    1711             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1712             : 
    1713             :     real(dp), dimension(2) :: multi_objective_lnnse_highflow_lnnse_lowflow_2
    1714             : 
    1715             :     ! modelled runoff for a given parameter set
    1716           0 :     real(dp), dimension(:, :), allocatable :: runoff
    1717             : 
    1718             :     ! gauges counter
    1719             :     integer(i4) :: gg
    1720             : 
    1721             :     integer(i4) :: nGaugesTotal
    1722             : 
    1723             :     ! measured runoff
    1724           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1725             : 
    1726             :     ! aggregated simulated runoff
    1727           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1728             : 
    1729             :     ! mask for aggregated measured runoff
    1730           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1731             : 
    1732             :     ! upper discharge value to determine lowflow timepoints
    1733           0 :     real(dp) :: q_low
    1734             : 
    1735             :     ! total number of discharge values
    1736             :     integer(i4) :: nrunoff
    1737             : 
    1738             :     ! timepoint counter
    1739             :     integer(i4) :: tt
    1740             : 
    1741             :     ! mask to get lowflow values
    1742           0 :     logical, dimension(:), allocatable :: lowflow_mask
    1743             : 
    1744             :     ! mask to get highflow values
    1745           0 :     logical, dimension(:), allocatable :: highflow_mask
    1746             : 
    1747             : 
    1748             :     ! call mhm_eval(parameterset, runoff=runoff)
    1749           0 :     call eval(parameterset, runoff = runoff)
    1750           0 :     nGaugesTotal = size(runoff, dim = 2)
    1751             : 
    1752           0 :     multi_objective_lnnse_highflow_lnnse_lowflow_2 = 0.0_dp
    1753           0 :     do gg = 1, nGaugesTotal
    1754             :       !
    1755             :       ! extract runoff
    1756           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1757           0 :       nrunoff = size(runoff_obs, dim = 1)
    1758             :       !print*, 'nrunoff = ',nrunoff
    1759             :       !
    1760             :       ! mask for lowflow timepoints
    1761           0 :       if (allocated(lowflow_mask)) deallocate(lowflow_mask)
    1762           0 :       allocate(lowflow_mask(nrunoff))
    1763           0 :       lowflow_mask = .false.
    1764           0 :       q_low = minval(runoff_obs, mask = runoff_obs_mask) &
    1765           0 :               + 0.05_dp * (maxval(runoff_obs, mask = runoff_obs_mask) - minval(runoff_obs, mask = runoff_obs_mask))
    1766           0 :       forall(tt = 1 : nrunoff) lowflow_mask(tt) = (runoff_obs(tt) < q_low .and. runoff_obs_mask(tt))
    1767             :       !print*, 'nlow  = ',count(lowflow_mask)
    1768             :       !
    1769             :       ! mask for highflow timepoints
    1770           0 :       if (allocated(highflow_mask)) deallocate(highflow_mask)
    1771           0 :       allocate(highflow_mask(nrunoff))
    1772           0 :       highflow_mask = (.not. lowflow_mask) .and. runoff_obs_mask
    1773             :       !print*, 'nhigh = ',count(highflow_mask)
    1774             :       !
    1775             :       ! lnNSE highflows
    1776             :       multi_objective_lnnse_highflow_lnnse_lowflow_2(1) = multi_objective_lnnse_highflow_lnnse_lowflow_2(1) + &
    1777           0 :               lnnse(runoff_obs, runoff_agg, mask = highflow_mask)
    1778             :       !
    1779             :       ! lnNSE lowflows
    1780             :       multi_objective_lnnse_highflow_lnnse_lowflow_2(2) = multi_objective_lnnse_highflow_lnnse_lowflow_2(2) + &
    1781           0 :               lnnse(runoff_obs, runoff_agg, mask = lowflow_mask)
    1782             :     end do
    1783             :     ! objective function value which will be minimized
    1784             :     multi_objective_lnnse_highflow_lnnse_lowflow_2(:) = 1.0_dp &
    1785           0 :             - multi_objective_lnnse_highflow_lnnse_lowflow_2(:) / real(nGaugesTotal, dp)
    1786             : 
    1787             :     ! write(*,*) 'multi_objective_lnnse_highflow_lnnse_lowflow_2 = ',multi_objective_lnnse_highflow_lnnse_lowflow_2
    1788             : 
    1789             :     ! clean up
    1790           0 :     deallocate(runoff_agg, runoff_obs)
    1791           0 :     deallocate(runoff_obs_mask)
    1792             : 
    1793           0 :   END FUNCTION multi_objective_lnnse_highflow_lnnse_lowflow_2
    1794             : 
    1795             :   ! ------------------------------------------------------------------
    1796             : 
    1797             :   !    NAME
    1798             :   !        multi_objective_ae_fdc_lsv_nse_djf
    1799             : 
    1800             :   !    PURPOSE
    1801             :   !>       \brief Multi-objective function with absolute error of Flow Duration Curves
    1802             :   !>       low-segment volume and nse of DJF's discharge.
    1803             : 
    1804             :   !>       \details The objective function only depends on a parameter vector.
    1805             :   !>       The model will be called with that parameter vector and
    1806             :   !>       the model output is subsequently compared to observed data.
    1807             : 
    1808             :   !>       The first objective is using the routine "FlowDurationCurves" from "mo_signatures" to determine the
    1809             :   !>       low-segment volume of the FDC. The objective is the absolute difference between the observed volume
    1810             :   !>       and the simulated volume.
    1811             : 
    1812             :   !>       For the second objective the discharge of the winter months December, January and February are extracted
    1813             :   !>       from the time series. The objective is then the Nash-Sutcliffe efficiency NSE of the observed winter
    1814             :   !>       discharge against the simulated winter discharge.
    1815             : 
    1816             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1817             :   !>       To calibrate this objective you need a multi-objective optimizer like PA-DDS.
    1818             : 
    1819             :   !    INTENT(IN)
    1820             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1821             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1822             : 
    1823             :   !    RETURN
    1824             :   !>       \return real(dp), dimension(2) :: multi_objective_ae_fdc_lsv_nse_djf &mdash; objective function value
    1825             :   !>       (which will be e.g. minimized by an optimization routine like PA-DDS)
    1826             : 
    1827             :   !    HISTORY
    1828             :   !>       \authors Juliane Mai
    1829             : 
    1830             :   !>       \date Feb 2016
    1831             : 
    1832             :   ! Modifications:
    1833             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1834             : 
    1835           0 :   FUNCTION multi_objective_ae_fdc_lsv_nse_djf(parameterset, eval)
    1836             : 
    1837           0 :     use mo_common_mhm_mrm_variables, only : evalPer
    1838             :     use mo_errormeasures, only : nse
    1839             :     use mo_julian, only : dec2date
    1840             :     use mo_mrm_global_variables, only : gauge, nMeasPerDay
    1841             :     use mo_mrm_signatures, only : FlowDurationCurve
    1842             : 
    1843             :     implicit none
    1844             : 
    1845             :     real(dp), dimension(:), intent(in) :: parameterset
    1846             : 
    1847             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    1848             : 
    1849             :     real(dp), dimension(2) :: multi_objective_ae_fdc_lsv_nse_djf
    1850             : 
    1851             :     ! modelled runoff for a given parameter set
    1852           0 :     real(dp), dimension(:, :), allocatable :: runoff
    1853             : 
    1854             :     ! gauges counter
    1855             :     integer(i4) :: gg
    1856             : 
    1857             :     ! total number of gauges
    1858             :     integer(i4) :: nGaugesTotal
    1859             : 
    1860             :     ! domain ID of gauge
    1861             :     integer(i4) :: iDomain
    1862             : 
    1863             :     ! measured runoff
    1864           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    1865             : 
    1866             :     ! aggregated simulated runoff
    1867           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    1868             : 
    1869             :     ! mask for aggregated measured runoff
    1870           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    1871             : 
    1872             :     ! total number of discharge values
    1873             :     integer(i4) :: nrunoff
    1874             : 
    1875             :     ! timepoint counter
    1876             :     integer(i4) :: tt
    1877             : 
    1878             :     ! month of current time step
    1879             :     integer(i4) :: month
    1880             : 
    1881             :     ! Fractional Julian day of current time step
    1882           0 :     real(dp) :: current_time
    1883             : 
    1884             :     ! mask to get lowflow values
    1885           0 :     logical, dimension(:), allocatable :: djf_mask
    1886             : 
    1887             :     ! quantiles for FDC
    1888           0 :     real(dp), dimension(10) :: quantiles
    1889             : 
    1890             :     ! number of quantiles
    1891             :     integer(i4) :: nquantiles
    1892             : 
    1893             :     ! FDC of simulated or observed discharge
    1894           0 :     real(dp), dimension(size(quantiles)) :: fdc
    1895             : 
    1896             :     ! low-segment volume of FDC of simulated discharge
    1897           0 :     real(dp) :: lsv_mod
    1898             : 
    1899             :     ! low-segment volume of FDC of observed  discharge
    1900           0 :     real(dp) :: lsv_obs
    1901             : 
    1902             : 
    1903             :     ! call mhm_eval(parameterset, runoff=runoff)
    1904           0 :     call eval(parameterset, runoff = runoff)
    1905           0 :     nGaugesTotal = size(runoff, dim = 2)
    1906           0 :     nquantiles = size(quantiles)
    1907           0 :     forall(tt = 1 : nquantiles) quantiles(tt) = real(tt, dp) / real(nquantiles, dp)
    1908             : 
    1909           0 :     multi_objective_ae_fdc_lsv_nse_djf = 0.0_dp
    1910           0 :     do gg = 1, nGaugesTotal
    1911             :       !
    1912             :       ! extract runoff
    1913           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    1914           0 :       nrunoff = size(runoff_obs, dim = 1)
    1915             :       !
    1916             :       ! mask DJF timepoints
    1917           0 :       if (allocated(djf_mask)) deallocate(djf_mask)
    1918           0 :       allocate(djf_mask(nrunoff))
    1919           0 :       djf_mask = .false.
    1920             : 
    1921           0 :       iDomain = gauge%domainId(gg)
    1922           0 :       do tt = 1, nrunoff
    1923           0 :         current_time = evalPer(iDomain)%julStart + (tt - 1) * 1.0_dp / real(nMeasPerDay, dp)
    1924           0 :         call dec2date(current_time, mm = month)
    1925           0 :         if ((month == 1 .or. month == 2 .or. month == 12) .and. runoff_obs_mask(tt)) djf_mask(tt) = .True.
    1926             :       end do
    1927             :       !
    1928             :       ! Absolute error of low-segment volume of FDC
    1929           0 :       fdc = FlowDurationCurve(runoff_obs, quantiles, mask = runoff_obs_mask, low_segment_volume = lsv_obs)
    1930           0 :       fdc = FlowDurationCurve(runoff_agg, quantiles, mask = runoff_obs_mask, low_segment_volume = lsv_mod)
    1931           0 :       fdc = fdc * 1.0_dp ! only to avoid warning of unused variable
    1932             :       !
    1933             :       ! Absolute distance between low-segment volumes
    1934             :       multi_objective_ae_fdc_lsv_nse_djf(1) = multi_objective_ae_fdc_lsv_nse_djf(1) + &
    1935           0 :               abs(lsv_obs - lsv_mod)
    1936             :       !
    1937             :       ! NSE of DJF discharge
    1938             :       multi_objective_ae_fdc_lsv_nse_djf(2) = multi_objective_ae_fdc_lsv_nse_djf(2) + &
    1939           0 :               nse(runoff_obs, runoff_agg, mask = djf_mask)
    1940             :     end do
    1941             :     ! objective function value which will be minimized
    1942             :     multi_objective_ae_fdc_lsv_nse_djf(1) = &
    1943           0 :             multi_objective_ae_fdc_lsv_nse_djf(1) / real(nGaugesTotal, dp)
    1944             :     multi_objective_ae_fdc_lsv_nse_djf(2) = 1.0_dp &
    1945           0 :             - multi_objective_ae_fdc_lsv_nse_djf(2) / real(nGaugesTotal, dp)
    1946             : 
    1947             :     call message('multi_objective_ae_fdc_lsv_nse_djf = [', &
    1948             :       num2str(multi_objective_ae_fdc_lsv_nse_djf(1)), ', ', &
    1949           0 :       num2str(multi_objective_ae_fdc_lsv_nse_djf(2)), ']')
    1950             : 
    1951             :     ! clean up
    1952           0 :     deallocate(runoff_agg, runoff_obs)
    1953           0 :     deallocate(runoff_obs_mask)
    1954             : 
    1955           0 :   END FUNCTION multi_objective_ae_fdc_lsv_nse_djf
    1956             : 
    1957             :   ! ------------------------------------------------------------------
    1958             : 
    1959             :   !    NAME
    1960             :   !        objective_power6_nse_lnnse
    1961             : 
    1962             :   !    PURPOSE
    1963             :   !>       \brief Objective function of combined NSE and lnNSE with power of 5
    1964             :   !>       i.e. the p-norm with p=5.
    1965             : 
    1966             :   !>       \details The objective function only depends on a parameter vector.
    1967             :   !>       The model will be called with that parameter vector and
    1968             :   !>       the model output is subsequently compared to observed data.
    1969             :   !>       Therefore, the Nash-Sutcliffe model efficiency coefficient \f$ NSE \f$
    1970             :   !>       \f[ NSE = 1 - \frac{\sum_{i=1}^N (Q_{obs}(i) - Q_{model}(i))^2}
    1971             :   !>       {\sum_{i=1}^N (Q_{obs}(i) - \bar{Q_{obs}})^2} \f]
    1972             :   !>       and the logarithmic Nash-Sutcliffe model efficiency coefficient \f$ lnNSE \f$
    1973             :   !>       \f[ lnNSE = 1 - \frac{\sum_{i=1}^N (\ln Q_{obs}(i) - \ln Q_{model}(i))^2}
    1974             :   !>       {\sum_{i=1}^N (\ln Q_{obs}(i) - \bar{\ln Q_{obs}})^2} \f]
    1975             :   !>       are calculated and added up equally weighted:
    1976             :   !>       \f[ obj\_value = \sqrt[6]{(1-NSE)^6 + (1-lnNSE)^6} \f]
    1977             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    1978             : 
    1979             :   !    INTENT(IN)
    1980             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    1981             :   !>       \param[in] "procedure(eval_interface) :: eval"
    1982             : 
    1983             :   !    RETURN
    1984             :   !>       \return real(dp) :: objective_power6_nse_lnnse &mdash; objective function value
    1985             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    1986             : 
    1987             :   !    HISTORY
    1988             :   !>       \authors Juliane Mai and Matthias Cuntz
    1989             : 
    1990             :   !>       \date March 2014
    1991             : 
    1992             :   ! Modifications:
    1993             :   ! Stephan Thober Jan 2015 - introduced extract_runoff
    1994             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    1995             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1996             : 
    1997           0 :   FUNCTION objective_power6_nse_lnnse(parameterset, eval)
    1998             : 
    1999           0 :     use mo_errormeasures, only : lnnse, nse
    2000             : 
    2001             :     implicit none
    2002             : 
    2003             :     real(dp), dimension(:), intent(in) :: parameterset
    2004             : 
    2005             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    2006             : 
    2007             :     real(dp) :: objective_power6_nse_lnnse
    2008             : 
    2009             :     ! modelled runoff for a given parameter set
    2010             :     ! dim1=nTimeSteps, dim2=nGauges
    2011           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    2012             : 
    2013             :     ! gauges counter
    2014             :     integer(i4) :: gg
    2015             : 
    2016             :     integer(i4) :: nGaugesTotal
    2017             : 
    2018             :     ! aggregated simulated runoff
    2019           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    2020             : 
    2021             :     ! measured runoff
    2022           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    2023             : 
    2024             :     ! mask for measured runoff
    2025           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    2026             : 
    2027             :     real(dp), parameter :: onesixth = 1.0_dp / 6.0_dp
    2028             : 
    2029             : 
    2030           0 :     call eval(parameterset, runoff = runoff)
    2031           0 :     nGaugesTotal = size(runoff, dim = 2)
    2032             : 
    2033           0 :     objective_power6_nse_lnnse = 0.0_dp
    2034           0 :     do gg = 1, nGaugesTotal
    2035             :       ! extract runoff
    2036           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    2037             :       ! NSE + lnNSE
    2038             :       objective_power6_nse_lnnse = objective_power6_nse_lnnse + &
    2039             :               ((1.0_dp - nse(runoff_obs, runoff_agg, mask = runoff_obs_mask))**6 + &
    2040           0 :                       (1.0_dp - lnnse(runoff_obs, runoff_agg, mask = runoff_obs_mask))**6)**onesixth
    2041             :     end do
    2042             : #ifndef MPI
    2043             :     ! objective function value which will be minimized
    2044           0 :     objective_power6_nse_lnnse = objective_power6_nse_lnnse / real(nGaugesTotal, dp)
    2045             : 
    2046           0 :     call message('objective_power6_nse_lnnse = ', num2str(objective_power6_nse_lnnse))
    2047             :     ! pause
    2048             : #endif
    2049             : 
    2050           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    2051             : 
    2052           0 :   END FUNCTION objective_power6_nse_lnnse
    2053             : 
    2054             :   ! ------------------------------------------------------------------
    2055             : 
    2056             :   !    NAME
    2057             :   !        objective_kge
    2058             : 
    2059             :   !    PURPOSE
    2060             :   !>       \brief Objective function of KGE.
    2061             : 
    2062             :   !>       \details The objective function only depends on a parameter vector.
    2063             :   !>       The model will be called with that parameter vector and
    2064             :   !>       the model output is subsequently compared to observed data.
    2065             : 
    2066             :   !>       Therefore, the Kling-Gupta model efficiency coefficient \f$ KGE \f$
    2067             :   !>       \f[ KGE = 1.0 - \sqrt{( (1-r)^2 + (1-\alpha)^2 + (1-\beta)^2 )} \f]
    2068             :   !>       where
    2069             :   !>       \f$ r \f$ = Pearson product-moment correlation coefficient
    2070             :   !>       \f$ \alpha \f$ = ratio of similated mean to observed mean
    2071             :   !>       \f$ \beta  \f$ = ratio of similated standard deviation to observed standard deviation
    2072             :   !>       is calculated and the objective function is
    2073             :   !>       \f[ obj\_value = 1.0 - KGE \f]
    2074             :   !>       \f$(1-KGE)\f$ is the objective since we always apply minimization methods.
    2075             :   !>       The minimal value of \f$(1-KGE)\f$ is 0 for the optimal KGE of 1.0.
    2076             : 
    2077             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    2078             : 
    2079             :   !    INTENT(IN)
    2080             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    2081             :   !>       \param[in] "procedure(eval_interface) :: eval"
    2082             : 
    2083             :   !    RETURN
    2084             :   !>       \return real(dp) :: objective_kge &mdash; objective function value
    2085             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    2086             : 
    2087             :   !    HISTORY
    2088             :   !>       \authors Rohini Kumar
    2089             : 
    2090             :   !>       \date August 2014
    2091             : 
    2092             :   ! Modifications:
    2093             :   ! Stephan Thober Jan  2015 - introduced extract_runoff
    2094             :   ! Stephan Thober Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2) to not interfere with mRM
    2095             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    2096             : 
    2097           0 :   FUNCTION objective_kge(parameterset, eval)
    2098             : 
    2099           0 :     use mo_errormeasures, only : kge
    2100             : 
    2101             :     implicit none
    2102             : 
    2103             :     real(dp), dimension(:), intent(in) :: parameterset
    2104             : 
    2105             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    2106             : 
    2107             :     real(dp) :: objective_kge
    2108             : 
    2109             :     ! modelled runoff for a given parameter set
    2110             :     ! dim1=nTimeSteps, dim2=nGauges
    2111           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    2112             : 
    2113             :     ! gauges counter
    2114             :     integer(i4) :: gg
    2115             : 
    2116             :     integer(i4) :: nGaugesTotal
    2117             : 
    2118             :     ! aggregated simulated runoff
    2119           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    2120             : 
    2121             :     ! measured runoff
    2122           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    2123             : 
    2124             :     ! mask for measured runoff
    2125           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    2126             : 
    2127             : 
    2128             :     !
    2129           0 :     call eval(parameterset, runoff = runoff)
    2130           0 :     nGaugesTotal = size(runoff, dim = 2)
    2131             : 
    2132           0 :     objective_kge = 0.0_dp
    2133           0 :     do gg = 1, nGaugesTotal
    2134             :       ! extract runoff
    2135           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    2136             :       ! KGE
    2137             :       objective_kge = objective_kge + &
    2138           0 :               kge(runoff_obs, runoff_agg, mask = runoff_obs_mask)
    2139             :     end do
    2140             : #ifndef MPI
    2141             :     ! objective_kge = objective_kge + kge(gauge%Q, runoff_model_agg, runoff_model_agg_mask)
    2142           0 :     objective_kge = 1.0_dp - objective_kge / real(nGaugesTotal, dp)
    2143             : 
    2144           0 :     call message('objective_kge (i.e., 1 - KGE) = ', num2str(objective_kge))
    2145             : #endif
    2146             :     ! pause
    2147             : 
    2148           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    2149             : 
    2150           0 :   END FUNCTION objective_kge
    2151             : 
    2152             :   ! ------------------------------------------------------------------
    2153             : 
    2154             :   !    NAME
    2155             :   !        objective_multiple_gauges_kge_power6
    2156             : 
    2157             :   !    PURPOSE
    2158             :   !>       \brief combined objective function based on KGE raised to the power 6
    2159             : 
    2160             :   !>       \details The objective function only depends on a parameter vector.
    2161             :   !>       The model will be called with that parameter vector and
    2162             :   !>       the model output is subsequently compared to observed data.
    2163             : 
    2164             :   !>       Therefore, the Kling-Gupta model efficiency coefficient \f$ KGE \f$ for a given gauging station
    2165             :   !>       \f[ KGE = 1.0 - \sqrt{( (1-r)^2 + (1-\alpha)^2 + (1-\beta)^2 )} \f]
    2166             :   !>       where
    2167             :   !>       \f$ r \f$ = Pearson product-moment correlation coefficient
    2168             :   !>       \f$ \alpha \f$ = ratio of similated mean to observed mean
    2169             :   !>       \f$ \beta  \f$ = ratio of similated standard deviation to observed standard deviation
    2170             :   !>       is calculated and the objective function for a given gauging station (\f$ i \f$) is
    2171             :   !>       \f[ \phi_{i} = 1.0 - KGE_{i} \f]
    2172             :   !>       \f$ \phi_{i} \f$ is the objective since we always apply minimization methods.
    2173             :   !>       The minimal value of \f$ \phi_{i} \f$ is 0 for the optimal KGE of 1.0.
    2174             : 
    2175             :   !>       Finally, the overall \f$ OF \f$ is estimated based on the power-6 norm to
    2176             :   !>       combine the \f$ \phi_{i} \f$ from all gauging stations (\f$ N \f$).
    2177             :   !>       \f[ OF = \sqrt[6]{\sum((1.0 - KGE_{i})/N)^6 }  \f].
    2178             : 
    2179             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    2180             : 
    2181             :   !    INTENT(IN)
    2182             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    2183             :   !>       \param[in] "procedure(eval_interface) :: eval"
    2184             : 
    2185             :   !    RETURN
    2186             :   !>       \return real(dp) :: objective_multiple_gauges_kge_power6 &mdash; objective function value
    2187             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    2188             : 
    2189             :   !    HISTORY
    2190             :   !>       \authors Rohini Kumar
    2191             : 
    2192             :   !>       \date March 2015
    2193             : 
    2194             :   ! Modifications:
    2195             :   ! Stephan Thober  Aug 2015 - substituted nGaugesTotal variable with size(runoff, dim=2)
    2196             :   !                            to not interfere with mRM
    2197             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    2198             : 
    2199           0 :   FUNCTION objective_multiple_gauges_kge_power6(parameterset, eval)
    2200             : 
    2201           0 :     use mo_errormeasures, only : kge
    2202             : 
    2203             :     implicit none
    2204             : 
    2205             :     real(dp), dimension(:), intent(in) :: parameterset
    2206             : 
    2207             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    2208             : 
    2209             :     real(dp) :: objective_multiple_gauges_kge_power6
    2210             : 
    2211             :     real(dp), parameter :: onesixth = 1.0_dp / 6.0_dp
    2212             : 
    2213             :     ! modelled runoff for a given parameter set
    2214             :     ! dim1=nTimeSteps, dim2=nGauges
    2215           0 :     real(dp), allocatable, dimension(:, :) :: runoff
    2216             : 
    2217             :     ! gauges counter
    2218             :     integer(i4) :: gg
    2219             : 
    2220             :     integer(i4) :: nGaugesTotal
    2221             : 
    2222             :     ! aggregated simulated runoff
    2223           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    2224             : 
    2225             :     ! measured runoff
    2226           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    2227             : 
    2228             :     ! mask for measured runoff
    2229           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    2230             : 
    2231             : 
    2232             :     !
    2233           0 :     call eval(parameterset, runoff = runoff)
    2234           0 :     nGaugesTotal = size(runoff, dim = 2)
    2235             : 
    2236           0 :     objective_multiple_gauges_kge_power6 = 0.0_dp
    2237           0 :     do gg = 1, nGaugesTotal
    2238             :       ! extract runoff
    2239           0 :       call extract_runoff(gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    2240             :       ! KGE
    2241             :       objective_multiple_gauges_kge_power6 = objective_multiple_gauges_kge_power6 + &
    2242           0 :               ((1.0_dp - kge(runoff_obs, runoff_agg, mask = runoff_obs_mask)) / real(nGaugesTotal, dp))**6
    2243             :     end do
    2244             : #ifndef MPI
    2245           0 :     objective_multiple_gauges_kge_power6 = objective_multiple_gauges_kge_power6**onesixth
    2246           0 :     call message('objective_multiple_gauges_kge_power6 = ', num2str(objective_multiple_gauges_kge_power6))
    2247             : #endif
    2248             : 
    2249           0 :     deallocate(runoff_agg, runoff_obs, runoff_obs_mask)
    2250             : 
    2251           0 :   END FUNCTION objective_multiple_gauges_kge_power6
    2252             : 
    2253             :   ! ------------------------------------------------------------------
    2254             : 
    2255             :   !    NAME
    2256             :   !        objective_weighted_nse
    2257             : 
    2258             :   !    PURPOSE
    2259             :   !>       \brief Objective function of weighted NSE.
    2260             : 
    2261             :   !>       \details The objective function only depends on a parameter vector.
    2262             :   !>       The model will be called with that parameter vector and
    2263             :   !>       the model output is subsequently compared to observed data.
    2264             :   !>       Therefore, the weighted Nash-Sutcliffe model efficiency coefficient \f$ NSE \f$
    2265             :   !>       \f[ wNSE = 1 - \frac{\sum_{i=1}^N Q_{obs}(i) * (Q_{obs}(i) - Q_{model}(i))^2}
    2266             :   !>       {\sum_{i=1}^N Q_{obs}(i) * (Q_{obs}(i) - \bar{Q_{obs}})^2} \f]
    2267             :   !>       is calculated and the objective function is
    2268             :   !>       \f[ obj\_value = 1- wNSE \f]
    2269             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    2270             : 
    2271             :   !    INTENT(IN)
    2272             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    2273             :   !>       \param[in] "procedure(eval_interface) :: eval"
    2274             : 
    2275             :   !    RETURN
    2276             :   !>       \return real(dp) :: objective_weighted_nse &mdash; objective function value
    2277             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    2278             : 
    2279             :   !    HISTORY
    2280             :   !>       \authors Stephan Thober, Bjoern Guse
    2281             : 
    2282             :   !>       \date May 2018
    2283             : 
    2284             :   ! Modifications:
    2285             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    2286             : 
    2287           0 :   FUNCTION objective_weighted_nse(parameterset, eval)
    2288             : 
    2289           0 :     use mo_errormeasures, only : wnse
    2290             : 
    2291             :     implicit none
    2292             : 
    2293             :     real(dp), dimension(:), intent(in) :: parameterset
    2294             : 
    2295             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    2296             : 
    2297             :     real(dp) :: objective_weighted_nse
    2298             : 
    2299             :     ! modelled runoff for a given parameter set
    2300             :     ! dim1=nTimeSteps, dim2=nGauges
    2301           0 :     real(dp), allocatable, dimension(:,:) :: runoff
    2302             : 
    2303             :     ! gauges counter
    2304             :     integer(i4) :: gg
    2305             : 
    2306             :     integer(i4) :: nGaugesTotal
    2307             : 
    2308             :     ! aggregated simulated runoff
    2309           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    2310             : 
    2311             :     ! measured runoff
    2312           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    2313             : 
    2314             :     ! mask for aggregated measured runoff
    2315           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    2316             : 
    2317             : 
    2318           0 :     call eval(parameterset, runoff=runoff)
    2319           0 :     nGaugesTotal = size(runoff, dim=2)
    2320             : 
    2321           0 :     objective_weighted_nse = 0.0_dp
    2322           0 :     do gg=1, nGaugesTotal
    2323             :        !
    2324           0 :        call extract_runoff( gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask )
    2325             :        !
    2326             :        objective_weighted_nse = objective_weighted_nse + &
    2327           0 :             wnse( runoff_obs, runoff_agg, mask=runoff_obs_mask)
    2328             :     end do
    2329             : #ifndef MPI
    2330             :     ! objective_nse = objective_nse + nse(gauge%Q, runoff_model_agg) !, runoff_model_agg_mask)
    2331           0 :     objective_weighted_nse = 1.0_dp - objective_weighted_nse / real(nGaugesTotal,dp)
    2332             : 
    2333           0 :     call message('objective_weighted_nse (i.e., 1 - wNSE) = ', num2str(objective_weighted_nse))
    2334             :     ! pause
    2335             : #endif
    2336             : 
    2337           0 :     deallocate( runoff_agg, runoff_obs, runoff_obs_mask )
    2338             : 
    2339           0 :   END FUNCTION objective_weighted_nse
    2340             : 
    2341             :   ! ------------------------------------------------------------------
    2342             : 
    2343             :   !    NAME
    2344             :   !        objective_sse_boxcox
    2345             : 
    2346             :   !    PURPOSE
    2347             :   !>       \brief Objective function of sum of squared errors of transformed streamflow.
    2348             : 
    2349             :   !>       \details The objective function only depends on a parameter vector.
    2350             :   !>       The model will be called with that parameter vector and
    2351             :   !>       the model output is subsequently compared to observed data.
    2352             :   !>       Therefore, the sum of squared error \f$ tSSE \f$
    2353             :   !>       \f[ tSSE = \sum_{i=1}^N (z(Q_{obs}(i), \lambda) - z(Q_{model}(i), \lambda))^2 \f]
    2354             :   !>       is calculated where \f$ z \f$ is the transform and given by
    2355             :   !>       \f[ z(x, \lambda) = \frac{x^\lambda -1}{\lambda} \f] for \f$ \lambda \f$ unequal to zero and
    2356             :   !>       \f[ z(x, \lambda) = log x \f] for \f$ \lambda \f$ equal to zero.
    2357             :   !>       The objective function is
    2358             :   !>       \f[ obj\_value = tSSE \f]
    2359             :   !>       The observed data \f$ Q_{obs} \f$ are global in this module.
    2360             :   !>
    2361             :   !>       The boxcox transformation uses a parameter of 0.2, suggested by
    2362             :   !>       Woldemeskel et al. Hydrol Earth Syst Sci, 2018 vol. 22 (12) pp. 6257-6278.
    2363             :   !>       "Evaluating post-processing approaches for monthly and seasonal streamflow forecasts."
    2364             :   !>       https://www.hydrol-earth-syst-sci.net/22/6257/2018/
    2365             : 
    2366             : 
    2367             :   !    INTENT(IN)
    2368             :   !>       \param[in] "real(dp), dimension(:) :: parameterset"
    2369             :   !>       \param[in] "procedure(eval_interface) :: eval"
    2370             : 
    2371             :   !    RETURN
    2372             :   !>       \return real(dp) :: objective_sse_boxcox &mdash; objective function value
    2373             :   !>       (which will be e.g. minimized by an optimization routine like DDS)
    2374             : 
    2375             :   !    HISTORY
    2376             :   !>       \authors Stephan Thober, Dmitri Kavetski
    2377             : 
    2378             :   !>       \date Aug 2019
    2379             : 
    2380           0 :   FUNCTION objective_sse_boxcox(parameterset, eval)
    2381             : 
    2382           0 :     use mo_errormeasures, only: SSE
    2383             :     use mo_boxcox, only: boxcox
    2384             : 
    2385             :     implicit none
    2386             : 
    2387             :     real(dp), dimension(:), intent(in) :: parameterset
    2388             : 
    2389             :     procedure(eval_interface), INTENT(IN), pointer :: eval
    2390             : 
    2391             :     real(dp) :: objective_sse_boxcox
    2392             : 
    2393             :     ! modelled runoff for a given parameter set
    2394             :     ! dim1=nTimeSteps, dim2=nGauges
    2395           0 :     real(dp), allocatable, dimension(:,:) :: runoff
    2396             : 
    2397             :     ! gauges counter
    2398             :     integer(i4) :: gg
    2399             : 
    2400             :     integer(i4) :: nGaugesTotal
    2401             : 
    2402             :     ! aggregated simulated runoff
    2403           0 :     real(dp), dimension(:), allocatable :: runoff_agg
    2404             : 
    2405             :     ! measured runoff
    2406           0 :     real(dp), dimension(:), allocatable :: runoff_obs
    2407             : 
    2408             :     ! mask for aggregated measured runoff
    2409           0 :     logical, dimension(:), allocatable :: runoff_obs_mask
    2410             : 
    2411             :     ! boxcox parameter
    2412           0 :     real(dp) :: lambda
    2413             : 
    2414             :     ! set box cox transformation to 0.2
    2415             :     ! suggested by:
    2416             :     ! Woldemeskel et al. Hydrol Earth Syst Sci, 2018 vol. 22 (12) pp. 6257-6278.
    2417             :     ! "Evaluating post-processing approaches for monthly and seasonal streamflow forecasts."
    2418             :     ! https://www.hydrol-earth-syst-sci.net/22/6257/2018/
    2419           0 :     lambda = 0.2_dp
    2420             : 
    2421           0 :     call eval(parameterset, runoff=runoff)
    2422           0 :     nGaugesTotal = size(runoff, dim=2)
    2423             : 
    2424           0 :     objective_sse_boxcox = 0.0_dp
    2425           0 :     do gg=1, nGaugesTotal
    2426             :        !
    2427           0 :        call extract_runoff( gg, runoff, runoff_agg, runoff_obs, runoff_obs_mask )
    2428             :        !
    2429             :        objective_sse_boxcox = objective_sse_boxcox + &
    2430           0 :             SSE( boxcox(runoff_obs, lambda, mask=runoff_obs_mask), boxcox(runoff_agg, lambda), mask=runoff_obs_mask)
    2431             :     end do
    2432             : #ifndef MPI
    2433             :     ! objective_nse = objective_nse + nse(gauge%Q, runoff_model_agg) !, runoff_model_agg_mask)
    2434           0 :     objective_sse_boxcox = objective_sse_boxcox / real(nGaugesTotal,dp)
    2435             : 
    2436           0 :     call message('objective_sse_boxcox = ', num2str(objective_sse_boxcox))
    2437             :     ! pause
    2438             : #endif
    2439             : 
    2440           0 :     deallocate( runoff_agg, runoff_obs, runoff_obs_mask )
    2441             : 
    2442           0 :   END FUNCTION objective_sse_boxcox
    2443             : 
    2444             : 
    2445             :   ! ------------------------------------------------------------------
    2446             : 
    2447             :   !    NAME
    2448             :   !        extract_runoff
    2449             : 
    2450             :   !    PURPOSE
    2451             :   !>       \brief extracts runoff data from global variables
    2452             : 
    2453             :   !>       \details extracts simulated and measured runoff from global variables,
    2454             :   !>       such that they overlay exactly. For measured runoff, only the runoff
    2455             :   !>       during the evaluation period are cut, not succeeding nodata values.
    2456             :   !>       For simulated runoff, warming days as well as succeeding nodata values
    2457             :   !>       are neglected and the simulated runoff is aggregated to the resolution
    2458             :   !>       of the observed runoff.
    2459             :   !>       see use in this module above
    2460             : 
    2461             :   !    INTENT(IN)
    2462             :   !>       \param[in] "integer(i4) :: gaugeId"              current gauge Id
    2463             :   !>       \param[in] "real(dp), dimension(:, :) :: runoff" simulated runoff
    2464             : 
    2465             :   !    INTENT(OUT)
    2466             :   !>       \param[out] "real(dp), dimension(:) :: runoff_agg"     aggregated simulated
    2467             :   !>       \param[out] "real(dp), dimension(:) :: runoff_obs"     extracted measured
    2468             :   !>       \param[out] "logical, dimension(:) :: runoff_obs_mask" mask of no data values
    2469             : 
    2470             :   !    HISTORY
    2471             :   !>       \authors Stephan Thober
    2472             : 
    2473             :   !>       \date Jan 2015
    2474             : 
    2475             :   ! Modifications:
    2476             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    2477             : 
    2478          25 :   subroutine extract_runoff(gaugeId, runoff, runoff_agg, runoff_obs, runoff_obs_mask)
    2479             : 
    2480           0 :     use mo_common_mhm_mrm_variables, only : evalPer, nTstepDay, warmingDays
    2481             :     use mo_mrm_global_variables, only : gauge, nMeasPerDay
    2482             :     use mo_utils, only : ge
    2483             : 
    2484             :     implicit none
    2485             : 
    2486             :     ! current gauge Id
    2487             :     integer(i4), intent(in) :: gaugeId
    2488             : 
    2489             :     ! simulated runoff
    2490             :     real(dp), dimension(:, :), intent(in) :: runoff
    2491             : 
    2492             :     ! aggregated simulated
    2493             :     real(dp), dimension(:), allocatable, intent(out) :: runoff_agg
    2494             : 
    2495             :     ! extracted measured
    2496             :     real(dp), dimension(:), allocatable, intent(out) :: runoff_obs
    2497             : 
    2498             :     ! mask of no data values
    2499             :     logical, dimension(:), allocatable, intent(out) :: runoff_obs_mask
    2500             : 
    2501             :     ! domain id
    2502             :     integer(i4) :: iDomain
    2503             : 
    2504             :     ! timestep counter
    2505             :     integer(i4) :: tt
    2506             : 
    2507             :     ! length of extracted time series
    2508             :     integer(i4) :: length
    2509             : 
    2510             :     ! between simulated and measured time scale
    2511             :     integer(i4) :: factor
    2512             : 
    2513             :     ! simulated Timesteps per Day
    2514             :     integer(i4) :: TPD_sim
    2515             : 
    2516             :     ! observed Timesteps per Day
    2517             :     integer(i4) :: TPD_obs
    2518             : 
    2519          25 :     real(dp), dimension(:), allocatable :: dummy
    2520             : 
    2521             : 
    2522             :     ! copy time resolution to local variables
    2523          25 :     TPD_sim = nTstepDay
    2524          25 :     TPD_obs = nMeasPerDay
    2525             : 
    2526             :     ! check if modelled timestep is an integer multiple of measured timesteps
    2527          25 :     if (modulo(TPD_sim, TPD_obs) .eq. 0) then
    2528          25 :       factor = TPD_sim / TPD_obs
    2529             :     else
    2530           0 :       call error_message(' Error: Number of modelled datapoints is no multiple of measured datapoints per day')
    2531             :     end if
    2532             : 
    2533             :     ! extract domain Id from gauge Id
    2534          25 :     iDomain = gauge%domainId(gaugeId)
    2535             : 
    2536             :     ! get length of evaluation period times TPD_obs
    2537          25 :     length = (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1) * TPD_obs
    2538             : 
    2539             :     ! extract measurements
    2540          25 :     if (allocated(runoff_obs)) deallocate(runoff_obs)
    2541          75 :     allocate(runoff_obs(length))
    2542       19037 :     runoff_obs = gauge%Q(1 : length, gaugeId)
    2543             : 
    2544             :     ! create mask of observed runoff
    2545          25 :     if (allocated(runoff_obs_mask)) deallocate(runoff_obs_mask)
    2546          75 :     allocate(runoff_obs_mask(length))
    2547       19012 :     runoff_obs_mask = .false.
    2548       19012 :     forall(tt = 1 : length) runoff_obs_mask(tt) = ge(runoff_obs(tt), 0.0_dp)
    2549             : 
    2550             :     ! extract and aggregate simulated runoff
    2551          25 :     if (allocated(runoff_agg)) deallocate(runoff_agg)
    2552          50 :     allocate(runoff_agg(length))
    2553             :     ! remove warming days
    2554          25 :     length = (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1) * TPD_sim
    2555          75 :     allocate(dummy(length))
    2556      455738 :     dummy = runoff(warmingDays(iDomain) * TPD_sim + 1 : warmingDays(iDomain) * TPD_sim + length, gaugeId)
    2557             :     ! aggregate runoff
    2558          25 :     length = (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1) * TPD_obs
    2559           0 :     forall(tt = 1 : length) runoff_agg(tt) = sum(dummy((tt - 1) * factor + 1 : tt * factor)) / &
    2560      474700 :             real(factor, dp)
    2561             :     ! clean up
    2562          25 :     deallocate(dummy)
    2563             : 
    2564          25 :   end subroutine extract_runoff
    2565             : 
    2566             : 
    2567             : END MODULE mo_mrm_objective_function_runoff

Generated by: LCOV version 1.16