LCOV - code coverage report
Current view: top level - mRM - mo_mrm_write.f90 (source / functions) Hit Total Coverage
Test: mHM coverage Lines: 109 405 26.9 %
Date: 2024-04-15 17:48:09 Functions: 2 6 33.3 %

          Line data    Source code
       1             : !> \file mo_mrm_write.f90
       2             : !> \brief   \copybrief mo_mrm_write
       3             : !> \details \copydetails mo_mrm_write
       4             : 
       5             : !> \brief write of discharge and restart files
       6             : !> \details This module contains the subroutines for writing the discharge files and optionally the restart files.
       7             : !> \authors Stephan Thober
       8             : !> \date Aug 2015
       9             : !> \copyright Copyright 2005-\today, the mHM Developers, Luis Samaniego, Sabine Attinger: All rights reserved.
      10             : !! mHM is released under the LGPLv3+ license \license_note
      11             : !> \ingroup f_mrm
      12             : module mo_mrm_write
      13             : 
      14             :   use mo_kind, only : i4, dp
      15             :   use mo_mrm_write_fluxes_states, only : OutputDataset
      16             :   use mo_mrm_global_variables, only : output_time_reference_mrm
      17             :   use mo_message, only : message, error_message
      18             : 
      19             :   implicit none
      20             : 
      21             :   public :: mrm_write
      22             :   public :: mrm_write_optinamelist
      23             :   public :: mrm_write_optifile
      24             : 
      25             :   private
      26             : 
      27             : contains
      28             : 
      29             :   ! ------------------------------------------------------------------
      30             : 
      31             :   !    NAME
      32             :   !        mrm_write
      33             : 
      34             :   !    PURPOSE
      35             :   !>       \brief write discharge and restart files
      36             : 
      37             :   !>       \details First, this subroutine calls the writing or restart files that only
      38             :   !>       succeeds if it happens after the write of mHM restart files because
      39             :   !>       mHM restart files must exist. Second, simulated discharge is aggregated to the daily
      40             :   !>       scale and then written to file jointly with observed discharge
      41             : 
      42             :   !    HISTORY
      43             :   !>       \authors Juliane Mai, Rohini Kumar & Stephan Thober
      44             : 
      45             :   !>       \date Aug 2015
      46             : 
      47             :   ! Modifications:
      48             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
      49             :   ! Pallav Shrestha, Husain Najafi Mar 2022 - refactoring for measured timestep output
      50             : 
      51          13 :   subroutine mrm_write
      52             : 
      53             :     use mo_common_constants, only : nodata_dp
      54             :     use mo_common_mhm_mrm_variables, only : evalPer, mrm_coupling_mode, nTstepDay, simPer, warmingDays
      55             :     use mo_common_variables, only : mrmFileRestartOut, domainMeta, write_restart
      56             :     use mo_mrm_global_variables, only : domain_mrm, &
      57             :                                         gauge, mRM_runoff, nGaugesTotal, nMeasPerDay
      58             :     use mo_mrm_restart, only : mrm_write_restart
      59             : 
      60             :     implicit none
      61             : 
      62             :     integer(i4) :: domainID, iDomain
      63             : 
      64             :     integer(i4) :: iDay, iSubDay, iS, iE
      65             : 
      66             :     integer(i4) :: maxDailyTimeSteps, maxMeasTimeSteps
      67             : 
      68             :     integer(i4) :: tt
      69             : 
      70             :     integer(i4) :: gg
      71             : 
      72             :     integer(i4) :: nTimeSteps
      73             : 
      74          13 :     real(dp), dimension(:, :), allocatable :: d_Qmod, subd_Qmod ! Sim discharge at daily and subdaily time step
      75          13 :     real(dp), dimension(:, :), allocatable :: d_Qobs, subd_Qobs ! Obs discharge at daily and subdaily time step
      76             : 
      77             :     ! between simulated and measured time scale
      78             :     integer(i4) :: factor
      79             : 
      80             :     ! simulated Timesteps per Day
      81             :     integer(i4) :: TPD_sim
      82             : 
      83             :     ! observed Timesteps per Day
      84             :     integer(i4) :: TPD_obs
      85             : 
      86             :     ! --------------------------------------------------------------------------
      87             :     ! WRITE CONFIG FILE
      88             :     ! --------------------------------------------------------------------------
      89           0 :     if (mrm_coupling_mode .eq. 0_i4) call write_configfile()
      90             : 
      91             :     ! --------------------------------------------------------------------------
      92             :     ! WRITE RESTART
      93             :     ! --------------------------------------------------------------------------
      94          13 :     if (write_restart) then
      95          38 :       do iDomain = 1, domainMeta%nDomains
      96          25 :         domainID = domainMeta%indices(iDomain)
      97          38 :         if (domainMeta%doRouting(iDomain)) call mrm_write_restart(iDomain, domainID, mrmFileRestartOut)
      98             :       end do
      99             :     end if
     100             : 
     101             :     ! --------------------------------------------------------------------------
     102             :     ! STORE DAILY DISCHARGE TIMESERIES OF EACH GAUGING STATION
     103             :     ! FOR SIMULATIONS DURING THE EVALUATION PERIOD
     104             :     !
     105             :     !  **** AT DAILY TIME STEPS ****
     106             :     ! Note:: Observed Q are stored only for the evaluation period and not for
     107             :     !        the warming days
     108             :     ! --------------------------------------------------------------------------
     109             : 
     110             :     ! copy time resolution to local variables
     111          13 :     TPD_sim = nTstepDay
     112          13 :     TPD_obs = nMeasPerDay
     113             : 
     114             :     ! check if modelled timestep is an integer multiple of measured timesteps
     115          13 :     if (modulo(TPD_sim, TPD_obs) .eq. 0) then
     116          13 :       factor = TPD_sim / TPD_obs
     117             :     else
     118           0 :       call error_message(' Error: Number of modelled datapoints is no multiple of measured datapoints per day')
     119             :     end if
     120             : 
     121             : 
     122          51 :     maxDailyTimeSteps = maxval(evalPer(1 : domainMeta%nDomains)%julEnd - evalPer(1 : domainMeta%nDomains)%julStart + 1)
     123          38 :     maxMeasTimeSteps  = maxval(evalPer(1 : domainMeta%nDomains)%julEnd - evalPer(1 : domainMeta%nDomains)%julStart + 1) * TPD_obs
     124          52 :     allocate(d_Qmod     (maxDailyTimeSteps, nGaugesTotal))
     125          39 :     allocate(d_Qobs     (maxDailyTimeSteps, nGaugesTotal))
     126          52 :     allocate(subd_Qmod  ( maxMeasTimeSteps, nGaugesTotal))
     127          39 :     allocate(subd_Qobs  ( maxMeasTimeSteps, nGaugesTotal))
     128       12101 :     d_Qmod     = nodata_dp
     129       12101 :     d_Qobs     = nodata_dp
     130       12101 :     subd_Qmod  = nodata_dp
     131       12101 :     subd_Qobs  = nodata_dp
     132             : 
     133             : 
     134             :     ! loop over domains
     135          38 :     do iDomain = 1, domainMeta%nDomains
     136          38 :       if (domainMeta%doRouting(iDomain)) then
     137          20 :         domainID = domainMeta%indices(iDomain)
     138             : 
     139             :         ! Convert simulated values to daily
     140          20 :         nTimeSteps = (simPer(iDomain)%julEnd - simPer(iDomain)%julStart + 1) * nTstepDay
     141          20 :         iDay  = 0
     142        8786 :         do tt = warmingDays(iDomain) * nTstepDay + 1, nTimeSteps, nTstepDay
     143        8766 :           iS = tt
     144        8766 :           iE = tt + nTstepDay - 1
     145        8766 :           iDay = iDay + 1
     146             :           ! over gauges
     147       18282 :           do gg = 1, domain_mrm(iDomain)%nGauges
     148             :             ! simulation
     149       18992 :             d_Qmod(iDay, domain_mrm(iDomain)%gaugeIndexList(gg)) = &
     150      265158 :                     sum(mRM_runoff(iS : iE, domain_mrm(iDomain)%gaugeIndexList(gg))) / real(nTstepDay, dp)
     151             :           end do
     152             :         end do
     153             : 
     154          20 :         dailycheck: if (nMeasPerDay > 1) then
     155             :           ! Convert observed values to daily
     156           0 :           nTimeSteps = (simPer(iDomain)%julEnd - simPer(iDomain)%julStart + 1) * nMeasPerDay
     157           0 :           iDay  = 0
     158           0 :           do tt = 1, nTimeSteps, nMeasPerDay
     159           0 :             iS = tt
     160           0 :             iE = tt + nMeasPerDay - 1
     161           0 :             iDay = iDay + 1
     162             :             ! over gauges
     163           0 :             do gg = 1, domain_mrm(iDomain)%nGauges
     164             :               ! when -9999 value/s are present in current day, daily value remain -9999.
     165           0 :               if (.not.(any(gauge%Q(iS : iE, domain_mrm(iDomain)%gaugeIndexList(gg)) == nodata_dp))) then
     166             :                 ! observation
     167           0 :                 d_Qobs(iDay, domain_mrm(iDomain)%gaugeIndexList(gg)) = &
     168           0 :                         sum( gauge%Q(iS : iE, domain_mrm(iDomain)%gaugeIndexList(gg))) / real(nMeasPerDay, dp)
     169             :               end if
     170             :             end do
     171             :           end do
     172             :         else
     173             :           ! observed values are already at daily (nMeasPerDay = 1) and stored for evalper
     174             :           ! over gauges
     175          42 :           do gg = 1, domain_mrm(iDomain)%nGauges
     176             :             ! observation
     177       11363 :             d_Qobs(:, domain_mrm(iDomain)%gaugeIndexList(gg)) = gauge%Q(:, domain_mrm(iDomain)%gaugeIndexList(gg))
     178             :           end do
     179             :         end if dailycheck
     180             : 
     181             : 
     182          20 :         subdailycheck: if (nMeasPerDay > 1) then
     183             : 
     184             :           ! Convert simulated values to subdaily
     185           0 :           nTimeSteps = (simPer(iDomain)%julEnd - simPer(iDomain)%julStart + 1) * nTstepDay
     186           0 :           iSubDay = 0
     187           0 :           do tt = warmingDays(iDomain) * nTstepDay + 1, nTimeSteps, factor
     188           0 :             iS = tt
     189           0 :             iE = tt + factor - 1
     190           0 :             iSubDay = iSubDay + 1
     191             :             ! over gauges
     192           0 :             do gg = 1, domain_mrm(iDomain)%nGauges
     193             :               ! simulation
     194           0 :               subd_Qmod(iSubDay, domain_mrm(iDomain)%gaugeIndexList(gg)) = &
     195           0 :                       sum(mRM_runoff(iS : iE, domain_mrm(iDomain)%gaugeIndexList(gg))) / real(factor, dp)
     196             :             end do
     197             :           end do
     198             : 
     199             :           ! Convert observed values to subdaily
     200             : 
     201             :           ! observed values are already at subdaily (nMeasPerDay) and stored for evalper
     202             :           ! over gauges
     203           0 :           do gg = 1, domain_mrm(iDomain)%nGauges
     204             :             ! observation
     205           0 :             subd_Qobs(:, domain_mrm(iDomain)%gaugeIndexList(gg)) = gauge%Q(:, domain_mrm(iDomain)%gaugeIndexList(gg))
     206             :           end do
     207             : 
     208             :         end if subdailycheck
     209             : 
     210             :       end if
     211             :     end do
     212             : 
     213             : 
     214             :     ! write in an ASCII file          ! OBS[nModeling_days X nGauges_total] , SIM[nModeling_days X nGauges_total]
     215             :     ! ToDo: is this if statement reasonable
     216          13 :     if (allocated(gauge%Q)) call write_daily_obs_sim_discharge(d_Qobs(:, :), d_Qmod(:, :))
     217             : 
     218             :     ! write in an ASCII file          ! OBS[nMeasPerDay X nGauges_total] , SIM[nMeasPerDay X nGauges_total]
     219          13 :     if (nMeasPerDay > 1 .and. allocated(gauge%Q)) call write_subdaily_obs_sim_discharge(subd_Qobs(:, :), subd_Qmod(:, :), factor)
     220             :     ! The subdaily routine is only called if subdaily Q data is provided
     221             : 
     222             :     ! free space
     223          13 :     deallocate(d_Qmod, d_Qobs, subd_Qmod, subd_Qobs)
     224          13 :   end subroutine mrm_write
     225             :   ! ------------------------------------------------------------------
     226             : 
     227             :   !    NAME
     228             :   !        write_configfile
     229             : 
     230             :   !    PURPOSE
     231             :   !>       \brief This modules writes the results of the configuration into an ASCII-file
     232             : 
     233             :   !>       \details TODO: add description
     234             : 
     235             :   !    HISTORY
     236             :   !>       \authors Christoph Schneider
     237             : 
     238             :   !>       \date May 2013
     239             : 
     240             :   ! Modifications:
     241             :   ! Juliane Mai    May 2013 - module version and documentation
     242             :   ! Stephan Thober Jun 2014 - bug fix in L11 config print out
     243             :   ! Stephan Thober Jun 2014 - updated read_restart
     244             :   ! Rohini, Luis   Jul 2015 - updated version, L1 level prints
     245             :   ! Stephan Thober Sep 2015 - updated write of stream network
     246             :   ! Stephan Thober Nov 2016 - adapted write to selected case for routing process
     247             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     248             : 
     249           0 :   Subroutine write_configfile
     250             : 
     251          13 :     use mo_common_constants, only : nodata_dp
     252             :     use mo_common_file, only : file_config, uconfig
     253             :     use mo_common_mHM_mRM_variables, only : LCyearId, SimPer, evalPer, mrm_coupling_mode, read_restart, &
     254             :                                             resolutionRouting, timeStep, warmPer
     255             :     use mo_common_variables, only : LC_year_end, LC_year_start, LCfilename, &
     256             :                                     dirConfigOut, dirLCover, dirMorpho, dirOut, mrmFileRestartOut, global_parameters, &
     257             :                                     global_parameters_name, level0, level1, domainMeta, nLCoverScene, processMatrix, &
     258             :                                     resolutionHydrology, write_restart
     259             :     use mo_kind, only : dp, i4
     260             :     use mo_mrm_file, only : version
     261             :     use mo_mrm_global_variables, only : InflowGauge, L11_L1_Id, L11_fromN, L11_label, &
     262             :                                         L11_length, L11_netPerm, L11_rOrder, L11_slope, L11_toN, L1_L11_Id, domain_mrm, &
     263             :                                         dirGauges, dirTotalRunoff, gauge, level11, nGaugesTotal, nInflowGaugesTotal
     264             :     use mo_string_utils, only : num2str
     265             :     use mo_utils, only : ge
     266             :     use mo_os, only : check_path_isdir
     267             : 
     268             :     implicit none
     269             : 
     270             :     character(256) :: fName
     271             : 
     272             :     integer(i4) :: i, iDomain, domainID, j
     273             : 
     274             :     integer(i4) :: err
     275             : 
     276             : 
     277           0 :     fName = trim(adjustl(dirConfigOut)) // trim(adjustl(file_config))
     278           0 :     call message()
     279           0 :     call message('  Log-file written to ', trim(fName))
     280             :     !checking whether the directory exists where the file shall be created or opened
     281           0 :     call check_path_isdir(trim(adjustl(dirConfigOut)), raise=.true.)
     282           0 :     open(uconfig, file = fName, status = 'unknown', action = 'write', iostat = err)
     283           0 :     if (err .ne. 0) then
     284           0 :       call error_message('  Problems while creating File. Error-Code ', num2str(err))
     285             :     end if
     286           0 :     write(uconfig, 200)
     287           0 :     write(uconfig, 100) 'mRM-UFZ v-' // trim(version)
     288           0 :     write(uconfig, 100) 'S. Thober, L. Samaniego & R. Kumar, UFZ'
     289           0 :     write(uconfig, 200)
     290           0 :     write(uconfig, 100)
     291           0 :     write(uconfig, 201) '         M A I N  mRM  C O N F I G U R A T I O N  I N F O R M A T I O N         '
     292           0 :     write(uconfig, 100)
     293           0 :     write(uconfig, 103) 'Number of domains            ', domainMeta%nDomains
     294           0 :     write(uconfig, 103) 'Total No. of gauges         ', nGaugesTotal
     295           0 :     write(uconfig, 103)    'Time Step [h]               ', timeStep
     296           0 :     do iDomain = 1, domainMeta%nDomains
     297           0 :       domainID = domainMeta%indices(iDomain)
     298           0 :       write(uconfig, 103) 'Total No. of nodes          ', level11(iDomain)%nCells
     299           0 :       write(uconfig, 103) 'No. of cells L0             ', level0(domainMeta%L0DataFrom(iDomain))%nCells
     300           0 :       write(uconfig, 103) 'No. of cells L1             ', level1(iDomain)%nCells
     301           0 :       write(uconfig, 103) 'No. of cells L11            ', level11(iDomain)%nCells
     302             : 
     303             :       !    select case (iFlag_cordinate_sys)
     304             :       !    case (0)
     305           0 :       write(uconfig, 301)      'domain  ', domainID, '   Hydrology Resolution [m]      ', resolutionHydrology(iDomain)
     306           0 :       write(uconfig, 301)   'domain  ', domainID, '   Routing Resolution [m]        ', resolutionRouting(iDomain)
     307             :       !    case(1)
     308             :       !      write(uconfig, 302)       'domain  ',domainID, '   Hydrology Resolution [o]      ', resolutionHydrology(iDomain)
     309             :       !      write(uconfig, 302)   'domain  ',domainID, '   Routing Resolution [o]        ', resolutionRouting(iDomain)
     310             :       !    end select
     311             :     end do
     312           0 :     write(uconfig, 126)    'Flag READ  restart            ', read_restart
     313           0 :     write(uconfig, 126)    'Flag WRITE restart            ', write_restart
     314             :     !
     315             :     !******************
     316             :     ! Model Run period
     317             :     !******************
     318           0 :     do iDomain = 1, domainMeta%nDomains
     319           0 :       domainID = domainMeta%indices(iDomain)
     320           0 :       write(uconfig, 115) '                      Model Run Periods for domain ', num2str(domainID)
     321             :       write(uconfig, 116) &
     322           0 :               'From                To', &
     323           0 :               '   Day Month  Year   Day Month  Year'
     324             :       write(uconfig, 117)  &
     325           0 :               'Warming Period (1)            ', &
     326           0 :               warmPer(iDomain)%dStart, warmPer(iDomain)%mStart, warmPer(iDomain)%yStart, &
     327           0 :               warmPer(iDomain)%dEnd, warmPer(iDomain)%mEnd, warmPer(iDomain)%yEnd
     328             :       write(uconfig, 117)  &
     329           0 :               'Evaluation Period (2)         ', &
     330           0 :               evalPer(iDomain)%dStart, evalPer(iDomain)%mStart, evalPer(iDomain)%yStart, &
     331           0 :               evalPer(iDomain)%dEnd, evalPer(iDomain)%mEnd, evalPer(iDomain)%yEnd
     332             :       write(uconfig, 117)  &
     333           0 :               'Simulation Period (1)+(2)     ', &
     334           0 :               SimPer(iDomain)%dStart, SimPer(iDomain)%mStart, SimPer(iDomain)%yStart, &
     335           0 :               SimPer(iDomain)%dEnd, SimPer(iDomain)%mEnd, SimPer(iDomain)%yEnd
     336             :     end do
     337             : 
     338             :     !*********************************
     339             :     ! Model Land Cover Observations
     340             :     !*********************************
     341           0 :     if (processMatrix(8, 1) .eq. 1) then
     342           0 :       do iDomain = 1, domainMeta%nDomains
     343           0 :         domainID = domainMeta%indices(iDomain)
     344           0 :         write(uconfig, 118) '       Land Cover Observations for domain ', num2str(domainID)
     345           0 :         write(uconfig, 119) ' Start Year', ' End Year', '    Land cover scene', 'Land Cover File'
     346           0 :         do i = 1, nLCoverScene
     347           0 :           write(uconfig, 120) LC_year_start(i), LC_year_end(i), &
     348           0 :                   LCyearId(max(evalPer(iDomain)%yStart, LC_year_start(i)), iDomain), trim(LCfilename(i))
     349             :         end do
     350             :       end do
     351             :     end if
     352             :     !*********************************
     353             :     ! Initial Parameter Ranges
     354             :     !*********************************
     355           0 :     write(uconfig, 121) '  Initial Transfer Function Parameter Ranges (gammas)  '
     356             :     !
     357             :     ! Transfer functions
     358             :     write(uconfig, 122)      &
     359           0 :             '         i', '            min', '            max', '        current', &
     360           0 :             '                               name'
     361           0 :     do i = 1, size(global_parameters, 1)
     362             :       write(uconfig, 123) &
     363           0 :               i, global_parameters(i, 1), global_parameters(i, 2), global_parameters(i, 3), &
     364           0 :               trim(adjustl(global_parameters_name(i)))
     365             :     end do
     366             :     ! domain runoff data
     367           0 :     write(uconfig, 202) '                domain Runoff Data                '
     368           0 :     write(uconfig, 107) ' Gauge No.', '  domain Id', '     Qmax[m3/s]', '     Qmin[m3/s]'
     369           0 :     do i = 1, nGaugesTotal
     370           0 :       if(any(gauge%Q(:, i) > nodata_dp)) then
     371           0 :         write(uconfig, 108) i, gauge%domainId(i), maxval(gauge%Q(:, i), gauge%Q(:, i) > nodata_dp), &
     372           0 :                 minval(gauge%Q(:, i), gauge%Q(:, i) > nodata_dp)
     373             :       else
     374           0 :         write(uconfig, 108) i, gauge%domainId(i), nodata_dp, nodata_dp
     375             :       end if
     376             :     end do
     377             :     ! inflow gauge data
     378           0 :     if (nInflowGaugesTotal .GT. 0) then
     379           0 :       write(uconfig, 202) '                domain Inflow Data                 '
     380           0 :       write(uconfig, 107) ' Gauge No.', '  domain Id', '     Qmax[m3/s]', '     Qmin[m3/s]'
     381           0 :       do i = 1, nInflowGaugesTotal
     382           0 :         if(all(InflowGauge%Q(:, i) > nodata_dp)) then
     383           0 :           write(uconfig, 108) i, InflowGauge%domainId(i), maxval(InflowGauge%Q(:, i), InflowGauge%Q(:, i) > nodata_dp), &
     384           0 :                   minval(InflowGauge%Q(:, i), InflowGauge%Q(:, i) > nodata_dp)
     385             :         else
     386           0 :           write(uconfig, 108) i, InflowGauge%domainId(i), nodata_dp, nodata_dp
     387             :         end if
     388             :       end do
     389             :     end if
     390             :     ! domain config
     391           0 :     write(uconfig, 218) 'domain-wise Configuration'
     392           0 :     do iDomain = 1, domainMeta%nDomains
     393           0 :       domainID = domainMeta%indices(iDomain)
     394           0 :       write(uconfig, 103) 'domain No.                   ', domainID, &
     395           0 :               'No. of gauges               ', domain_mrm(iDomain)%nGauges
     396             : 
     397           0 :       write(uconfig, 222)   'Directory list'
     398             : 
     399           0 :       write(uconfig, 224) 'Directory to morphological input         ', dirMorpho(iDomain)
     400           0 :       write(uconfig, 224) 'Directory to land cover input            ', dirLCover(iDomain)
     401           0 :       write(uconfig, 224) 'Directory to gauging station input       ', dirGauges(iDomain)
     402           0 :       if (mrm_coupling_mode .eq. 0) then
     403           0 :         write(uconfig, 224) 'Directory to simulated runoff input      ', dirTotalRunoff(iDomain)
     404             :       end if
     405           0 :       write(uconfig, 224) 'Directory to write output by default     ', dirOut(iDomain)
     406           0 :       write(uconfig, 224) 'File to write mRM output when restarted  ', mrmFileRestartOut(iDomain)
     407             : 
     408           0 :       write(uconfig, 102) 'River Network  (Routing level)'
     409           0 :       write(uconfig, 100) 'Label 0 = intermediate draining cell '
     410           0 :       write(uconfig, 100) 'Label 1 = headwater cell             '
     411           0 :       write(uconfig, 100) 'Label 2 = sink cell                  '
     412             : 
     413           0 :       if (processMatrix(8, 1) .eq. 1_i4) then
     414           0 :         write(uconfig, 104) '   Overall', &
     415           0 :                 '      From', &
     416           0 :                 '        To', &
     417           0 :                 '   Routing', &
     418           0 :                 '     Label', &
     419           0 :                 '    Length', &
     420           0 :                 '      Mean', &
     421           0 :                 '      Link', &
     422           0 :                 '   Routing', &
     423           0 :                 '   Routing', &
     424           0 :                 '  Sequence', &
     425           0 :                 '          ', &
     426           0 :                 '          ', &
     427           0 :                 '     Slope'
     428             :         !
     429           0 :         write(uconfig, 105) '        Id', &
     430           0 :                 '      Node', &
     431           0 :                 '      Node', &
     432           0 :                 '', &
     433           0 :                 '', &
     434           0 :                 '      [km]', &
     435           0 :                 '    [o/oo]'
     436             :         !
     437           0 :         do j = level11(iDomain)%iStart, level11(iDomain)%iEnd - 1
     438           0 :           i = L11_netPerm(j) + level11(iDomain)%iStart - 1 ! adjust permutation for multi-domain option
     439           0 :           write(uconfig, 106) i, L11_fromN(i), L11_toN(i), L11_rOrder(i), L11_label(i), &
     440           0 :                   L11_length(i) / 1000.0_dp, L11_slope(i) * 1.0e3_dp
     441             :         end do
     442             : 
     443           0 :       else if (processMatrix(8, 1) .eq. 2_i4) then
     444           0 :         write(uconfig, 134) '   Overall', &
     445           0 :                 '      From', &
     446           0 :                 '        To', &
     447           0 :                 '   Routing', &
     448           0 :                 '     Label', &
     449           0 :                 '      Link', &
     450           0 :                 '   Routing', &
     451           0 :                 '   Routing', &
     452           0 :                 '  Sequence', &
     453           0 :                 '          '
     454             :         !
     455           0 :         write(uconfig, 135) '        Id', &
     456           0 :                 '      Node', &
     457           0 :                 '      Node', &
     458           0 :                 '', &
     459           0 :                 ''
     460             :         !
     461           0 :         do j = level11(iDomain)%iStart, level11(iDomain)%iEnd - 1
     462           0 :           i = L11_netPerm(j) + level11(iDomain)%iStart - 1 ! adjust permutation for multi-domain option
     463           0 :           write(uconfig, 136) i, L11_fromN(i), L11_toN(i), L11_rOrder(i), L11_label(i)
     464             :         end do
     465             :       end if
     466             :       ! draining node at L11
     467           0 :       write(uconfig, 109)  '   Overall', '     domain', &
     468           0 :               '      Cell', '   Routing', &
     469           0 :               '        Id', '   Node Id'
     470           0 :       do i = level11(iDomain)%Id(1), level11(iDomain)%Id(level11(iDomain)%nCells)
     471           0 :         write(uconfig, 110) i + level11(iDomain)%iStart - 1, i
     472             :       end do
     473             : 
     474             :       ! L1 level information
     475           0 :       write(uconfig, 111)  '  Modeling', '   Routing', ' Effective', &
     476           0 :               '      Cell', '   Cell Id', '      Area', &
     477           0 :               '        Id', '       [-]', '     [km2]'
     478           0 :       if (ge(resolutionRouting(iDomain), resolutionHydrology(iDomain))) then
     479           0 :         do i = level1(iDomain)%Id(1), level1(iDomain)%Id(level1(iDomain)%nCells)
     480           0 :           write(uconfig, 113) i + level1(iDomain)%iStart - 1, L1_L11_Id (i + level1(iDomain)%iStart - 1), &
     481           0 :             level1(iDomain)%CellArea(i) * 1.E-6_dp
     482           0 :       domainID = domainMeta%indices(iDomain)
     483             :         end do
     484             :       else
     485           0 :         do i = level11(iDomain)%Id(1), level11(iDomain)%Id(level11(iDomain)%nCells)
     486           0 :           write(uconfig, 110) i + level11(iDomain)%iStart - 1, L11_L1_Id (i + level11(iDomain)%iStart - 1)
     487             :         end do
     488             :       end if
     489           0 :       write(uconfig, 114)  ' Total[km2]', sum(level1(iDomain)%CellArea) * 1.E-6_dp
     490             :     end do
     491             : 
     492           0 :     write(uconfig, *)
     493           0 :     close(uconfig)
     494             : 
     495             :     !! Formats
     496             :     100 format (a80)
     497             :     102 format (/ 30('-') / a30 / 30('-'))
     498             :     103 format (a20, 10x, i10)
     499             :     104 format (/ 75('-') / 5a10, 5x, 2a10 / 5a10, 5x, 2a10)
     500             :     105 format (5a10, 5x, 2a10 / 75('-'))
     501             :     106 format (5i10, 5x, 2f10.3)
     502             :     107 format (2a10, 2a15)
     503             :     108 format (2i10, 2f15.3)
     504             :     !
     505             :     109 format (/ 20('-') / 2a10 / 2a10 / 2a10 / 20('-'))
     506             :     110 format (2i10)
     507             :     !
     508             :     111 format (/ 30('-') / 3a10 / 3a10 / 3a10 /  30('-'))
     509             :     113 format (            2i10,   1f10.3         )
     510             :     114 format (30('-') / a15, 5x, 1f10.3 /)
     511             :     !
     512             :     115 format (/61('-')/ a50, a10 /61('-'))
     513             :     116 format (39x, a22 / 25x, a36)
     514             :     117 format (3(a25, 6(i6)))
     515             :     !
     516             :     118 format (/50('-')/ a40, a10  /50('-'))
     517             :     119 format (a10, a10, a20, a20/)
     518             :     120 format (i10, i10, 10x, i10, a20)
     519             :     !
     520             :     121 format (/55('-')/ a55 /55('-'))
     521             :     122 format (a10, 3a15, a35)
     522             :     123 format (i10, 3f15.3, a35)
     523             :     !
     524             :     126 format (a30, 9x, L1)
     525             :     !
     526             :     134 format (/ 50('-') / 5a10 / 5a10)
     527             :     135 format (5a10 / 50('-'))
     528             :     136 format (5i10)
     529             :     !
     530             :     200 format (80('-'))
     531             :     201 format (a80)
     532             :     202 format (/50('-')/ a50 /50('-'))
     533             :     !
     534             :     218 format (/ 80('-')/ 26x, a24, 26x, /80('-'))
     535             :     222 format (/80('-')/ 26x, a21 /80('-'))
     536             :     224 format (a40, 5x, a256)
     537             : 
     538             :     301 format (a7, i2, a32, f15.0)
     539             :     ! 302 format (a7, i2, a32,es20.8)
     540           0 :   end Subroutine write_configfile
     541             : 
     542             :   ! ------------------------------------------------------------------
     543             : 
     544             :   !    NAME
     545             :   !        write_daily_obs_sim_discharge
     546             : 
     547             :   !    PURPOSE
     548             :   !>       \brief Write a file for the daily observed and simulated discharge timeseries
     549             :   !>       during the evaluation period for each gauging station
     550             : 
     551             :   !>       \details Write a file for the daily observed and simulated discharge timeseries
     552             :   !>       during the evaluation period for each gauging station
     553             : 
     554             :   !    INTENT(IN)
     555             :   !>       \param[in] "real(dp), dimension(:, :) :: Qobs" daily time series of observed dischargedims = (nModeling_days
     556             :   !>       , nGauges_total)
     557             :   !>       \param[in] "real(dp), dimension(:, :) :: Qsim" daily time series of modeled dischargedims = (nModeling_days ,
     558             :   !>       nGauges_total)
     559             : 
     560             :   !    HISTORY
     561             :   !>       \authors Rohini Kumar
     562             : 
     563             :   !>       \date August 2013
     564             : 
     565             :   ! Modifications:
     566             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     567             : 
     568          26 :   subroutine write_daily_obs_sim_discharge(Qobs, Qsim)
     569             : 
     570           0 :     use mo_common_constants, only : nodata_dp
     571             :     use mo_common_mhm_mrm_variables, only : evalPer
     572             :     use mo_common_variables, only : dirOut, domainMeta
     573             :     use mo_errormeasures, only : kge, nse
     574             :     use mo_julian, only : dec2date
     575             :     use mo_mrm_file, only : file_daily_discharge, ncfile_discharge, udaily_discharge
     576             :     use mo_mrm_global_variables, only : domain_mrm, gauge
     577             :     use mo_string_utils, only : num2str
     578             :     use mo_utils, only : ge
     579             :     use mo_netcdf, only : NcDataset, NcDimension, NcVariable
     580             : 
     581             :     implicit none
     582             : 
     583             :     ! daily time series of observed dischargedims = (nModeling_days , nGauges_total)
     584             :     real(dp), dimension(:, :), intent(in) :: Qobs
     585             : 
     586             :     ! daily time series of modeled dischargedims = (nModeling_days , nGauges_total)
     587             :     real(dp), dimension(:, :), intent(in) :: Qsim
     588             : 
     589             :     character(256) :: fName, formHeader, formData, dummy
     590             : 
     591             :     integer(i4) :: domainID, iDomain, gg, tt, err
     592             : 
     593             :     integer(i4) :: igauge_start, igauge_end
     594             : 
     595             :     integer(i4) :: day, month, year
     596             : 
     597             :     integer(i4) :: tlength
     598             : 
     599             :     ! time axis
     600          13 :     integer(i4), allocatable, dimension(:) :: taxis
     601             : 
     602          13 :     real(dp) :: newTime
     603             : 
     604             :     ! nc related variables
     605             :     type(NcDataset) :: nc_out
     606             :     type(NcDimension) :: dim, dim_bnd
     607             :     type(NcVariable) :: var
     608             : 
     609             :     ! initalize igauge_start
     610          13 :     igauge_start = 1
     611             : 
     612             :     ! domain loop
     613          38 :     do iDomain = 1, domainMeta%nDomains
     614          25 :       domainID = domainMeta%indices(iDomain)
     615          25 :       if(domain_mrm(iDomain)%nGauges .lt. 1) cycle
     616             : 
     617             :       ! estimate igauge_end
     618          19 :       igauge_end = igauge_start + domain_mrm(iDomain)%nGauges - 1
     619             : 
     620             :       ! check the existance of file
     621          19 :       fName = trim(adjustl(dirOut(iDomain))) // trim(adjustl(file_daily_discharge))
     622          19 :       open(udaily_discharge, file = trim(fName), status = 'unknown', action = 'write', iostat = err)
     623          19 :       if(err .ne. 0) then
     624           0 :         call error_message('  IOError while openening "', trim(fName), '". Error-Code ', num2str(err))
     625             :       end if
     626             : 
     627             :       ! header
     628          19 :       write(formHeader, *) '( 4a8, ', domain_mrm(iDomain)%nGauges, '(2X, a5, i10.10, 2X, a5, i10.10) )'
     629          19 :       write(udaily_discharge, formHeader) 'No', 'Day', 'Mon', 'Year', &
     630          22 :               ('Qobs_', gauge%gaugeId(gg), &
     631          60 :                       'Qsim_', gauge%gaugeId(gg), gg = igauge_start, igauge_end)
     632             : 
     633             :       ! form data
     634          19 :       write(formData, *) '( 4I8, ', domain_mrm(iDomain)%nGauges, '(2X,   f15.7 , 2X,  f15.7  ) )'
     635             : 
     636             :       ! write data
     637          19 :       newTime = real(evalPer(iDomain)%julStart, dp) - 0.5_dp
     638             : 
     639        8420 :       do tt = 1, (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1)
     640        8401 :         call dec2date(newTime, yy = year, mm = month, dd = day)
     641       17897 :         write(udaily_discharge, formData) tt, day, month, year, (Qobs(tt, gg), Qsim(tt, gg), gg = igauge_start, igauge_end)
     642        8420 :         newTime = newTime + 1.0_dp
     643             :       end do
     644             : 
     645             :       ! close file
     646          19 :       close(udaily_discharge)
     647             : 
     648             :       ! ======================================================================
     649             :       ! write netcdf file
     650             :       ! ======================================================================
     651          19 :       fName = trim(adjustl(dirOut(iDomain))) // trim(adjustl(ncfile_discharge))
     652          19 :       nc_out = NcDataset(trim(fName), "w")
     653          19 :       tlength = evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1
     654             :       ! write time
     655          57 :       allocate(taxis(tlength))
     656             : 
     657             :       ! tt is dependent on the unit of the time axis and is set to hours in mRM
     658             :       select case( output_time_reference_mrm)
     659             :         case(0)
     660        8420 :           forall(tt = 1 : tlength) taxis(tt) = (tt-1) * 24
     661             :         case(1)
     662           0 :           forall(tt = 1 : tlength) taxis(tt) = tt * 24 - 12
     663             :         case(2)
     664          19 :           forall(tt = 1 : tlength) taxis(tt) = tt * 24
     665             :       end select
     666             : 
     667          19 :       call dec2date(real(evalPer(iDomain)%julStart, dp) - 0.5_dp, yy = year, mm = month, dd = day)
     668          19 :       dim = nc_out%setDimension("time", tlength)
     669          38 :       var = nc_out%setVariable("time", "i32", [dim])
     670          19 :       call var%setData(taxis)
     671             :       call var%setAttribute( &
     672             :         "units", &
     673             :         'hours since '//trim(num2str(year))//'-'//trim(num2str(month, '(i2.2)'))//'-'//trim(num2str(day, '(i2.2)'))//' 00:00:00' &
     674          19 :       )
     675          19 :       call var%setAttribute("long_name", "time in hours")
     676          19 :       call var%setAttribute("bounds", "time_bnds")
     677          19 :       call var%setAttribute("axis", "T")
     678          19 :       dim_bnd = nc_out%setDimension("bnds", 2)
     679          57 :       var = nc_out%setVariable("time_bnds", "i32", [dim_bnd, dim])
     680        8420 :       do tt = 1, tlength
     681       25203 :         call var%setData((tt - 1) * 24, (/1, tt/))
     682       25222 :         call var%setData(tt * 24, (/2, tt/))
     683             :       end do
     684          19 :       deallocate(taxis)
     685             :       ! write gauges
     686          41 :       do gg = igauge_start, igauge_end
     687          44 :         var = nc_out%setVariable('Qsim_' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')), "f64", [dim])
     688          22 :         call var%setFillValue(nodata_dp)
     689          22 :         call var%setData(Qsim(1 : tlength, gg))
     690          22 :         call var%setAttribute("units", "m3 s-1")
     691          22 :         call var%setAttribute("long_name", 'simulated discharge at gauge ' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')))
     692          22 :         call var%setAttribute("missing_value", nodata_dp)
     693             :         ! write observed discharge at that gauge
     694          44 :         var = nc_out%setVariable('Qobs_' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')), "f64", [dim])
     695          22 :         call var%setFillValue(nodata_dp)
     696          22 :         call var%setData(Qobs(1 : tlength, gg))
     697          22 :         call var%setAttribute("units", "m3 s-1")
     698          22 :         call var%setAttribute("long_name", 'observed discharge at gauge ' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')))
     699          41 :         call var%setAttribute("missing_value", nodata_dp)
     700             :       end do
     701          19 :       call nc_out%close()
     702             : 
     703             :       ! ======================================================================
     704             :       ! screen output
     705             :       ! ======================================================================
     706             : 
     707             :       ! if ( nMeasPerDay == 1_i4 ) then ! only print daily stats for daily Qobs
     708             : 
     709          19 :       call message()
     710          19 :       write(dummy, '(I3)') domainID
     711          19 :       call message('  OUTPUT: saved daily discharge file for domain ', trim(adjustl(dummy)))
     712          19 :       call message('    to ', trim(fname))
     713          41 :       do gg = igauge_start, igauge_end
     714       11362 :         if (count(ge(Qobs(:, gg), 0.0_dp)) > 1)  then
     715             :           call message('    KGE of daily discharge (gauge #', trim(adjustl(num2str(gg))), '): ', &
     716       10611 :                   trim(adjustl(num2str(kge(Qobs(:, gg), Qsim(:, gg), mask = (ge(Qobs(:, gg), 0.0_dp)))))))
     717             :           call message('    NSE of daily discharge (gauge #', trim(adjustl(num2str(gg))), '): ', &
     718       10611 :                   trim(adjustl(num2str(nse(Qobs(:, gg), Qsim(:, gg), mask = (ge(Qobs(:, gg), 0.0_dp)))))))
     719             :         end if
     720             :       end do
     721             : 
     722             :       ! end if
     723             : 
     724             :       ! update igauge_start
     725          19 :       igauge_start = igauge_end + 1
     726             :       !
     727             :     end do
     728             :     !
     729          13 :   end subroutine write_daily_obs_sim_discharge
     730             : 
     731             : 
     732             :   ! ------------------------------------------------------------------
     733             : 
     734             :   !    NAME
     735             :   !        write_subdaily_obs_sim_discharge
     736             : 
     737             :   !    PURPOSE
     738             :   !>       \brief Write a file for the simulated discharge timeseries
     739             :   !>       during the evaluation period for each gauging station
     740             : 
     741             :   !>       \details Write a file for the simulated discharge timeseries
     742             :   !>       during the evaluation period for each gauging station
     743             : 
     744             :   !    INTENT(IN)
     745             :   !>       \param[in] "real(dp), dimension(:, :) :: Qobs"  time series of observed discharge dims = (nMeasTimeSteps ,
     746             :   !>       nGauges_total)
     747             :   !>       \param[in] "real(dp), dimension(:, :) :: Qsim"  time series of modeled discharge dims = (nMeasTimeSteps ,
     748             :   !>       nGauges_total)
     749             :   !>       \param[in] "integer(i4),              :: factor" ratio of modelled time steps per day to observation time steps per day
     750             : 
     751             :   !    HISTORY
     752             :   !>       \authors Rohini Kumar
     753             : 
     754             :   !>       \date August 2013
     755             : 
     756             :   ! Modifications:
     757             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     758             :   ! Pallav Shrestha Jul 2021 - ported for printing out simulations at hourly time step
     759             :   ! Pallav Shrestha, Husain Najafi Mar 2022 - refactoring for subdaily timestep output
     760             : 
     761           0 :   subroutine write_subdaily_obs_sim_discharge(Qobs, Qsim, factor)
     762             : 
     763          13 :     use mo_common_constants, only : nodata_dp
     764             :     use mo_common_mhm_mrm_variables, only : evalPer
     765             :     use mo_common_variables, only : dirOut, domainMeta
     766             :     use mo_errormeasures, only : kge, nse
     767             :     use mo_julian, only : dec2date
     768             :     use mo_mrm_file, only : ncfile_subdaily_discharge, file_subdaily_discharge, &
     769             :                             usubdaily_discharge
     770             :     use mo_mrm_global_variables, only : domain_mrm, gauge, nMeasPerDay
     771             :     use mo_string_utils, only : num2str
     772             :     use mo_utils, only : ge
     773             :     use mo_netcdf, only : NcDataset, NcDimension, NcVariable
     774             : 
     775             :     implicit none
     776             : 
     777             :     ! time series of observed discharge. dims = (nMeasTimeSteps , nGauges_total)
     778             :     real(dp), dimension(:, :), intent(in) :: Qobs
     779             : 
     780             :     ! time series of modeled discharge. dims = (nMeasTimeSteps , nGauges_total)
     781             :     real(dp), dimension(:, :), intent(in) :: Qsim
     782             : 
     783             :     ! ratio of modelled time steps per day to observation time steps per day
     784             :     integer(i4),               intent(in) :: factor
     785             : 
     786             :     character(256) :: fName, formHeader, formData, dummy
     787             : 
     788             :     integer(i4) :: domainID, iDomain, gg, tt, err
     789             : 
     790             :     integer(i4) :: igauge_start, igauge_end
     791             : 
     792             :     integer(i4) :: hour, day, month, year
     793             : 
     794             :     integer(i4) :: tlength
     795             : 
     796             :     ! time axis
     797           0 :     integer(i4), allocatable, dimension(:) :: taxis
     798             : 
     799           0 :     real(dp) :: newTime
     800             : 
     801             :     ! nc related variables
     802             :     type(NcDataset) :: nc_out
     803             :     type(NcDimension) :: dim, dim_bnd
     804             :     type(NcVariable) :: var
     805             : 
     806             :     ! use minutes if needed
     807             :     logical :: use_minutes
     808             :     integer(i4) :: time_unit_factor
     809             : 
     810             :     ! initalize igauge_start
     811           0 :     igauge_start = 1
     812             : 
     813             :     ! domain loop
     814           0 :     do iDomain = 1, domainMeta%nDomains
     815           0 :       domainID = domainMeta%indices(iDomain)
     816           0 :       if(domain_mrm(iDomain)%nGauges .lt. 1) cycle
     817             : 
     818             :       ! estimate igauge_end
     819           0 :       igauge_end = igauge_start + domain_mrm(iDomain)%nGauges - 1
     820             : 
     821             : 
     822             :       ! ======================================================================
     823             :       ! write text file
     824             :       ! ======================================================================
     825             : 
     826             :       ! check the existance of file
     827           0 :       fName = trim(adjustl(dirOut(iDomain))) // trim(adjustl(file_subdaily_discharge))
     828           0 :       open(usubdaily_discharge, file = trim(fName), status = 'unknown', action = 'write', iostat = err)
     829           0 :       if(err .ne. 0) then
     830           0 :         call error_message('  IOError while openening "', trim(fName), '". Error-Code ', num2str(err))
     831             :       end if
     832             : 
     833             :       ! header
     834           0 :       write(formHeader, *) '( 5a8, ', domain_mrm(iDomain)%nGauges, '(2X, a5, i10.10, 2X, a5, i10.10) )'
     835           0 :       write(usubdaily_discharge, formHeader) 'No', 'Hour', 'Day', 'Mon', 'Year', &
     836           0 :               ('Qobs_', gauge%gaugeId(gg), &
     837           0 :                       'Qsim_', gauge%gaugeId(gg), gg = igauge_start, igauge_end)
     838             : 
     839             :       ! form data
     840           0 :       write(formData, *) '( 5I8, ', domain_mrm(iDomain)%nGauges, '(2X,   f15.7 , 2X,  f15.7  ) )'
     841             : 
     842             :       ! write data
     843           0 :       newTime = real(evalPer(iDomain)%julStart, dp) - 0.5_dp
     844             : 
     845           0 :       do tt = 1, (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1) * nMeasPerDay
     846           0 :         call dec2date(newTime, yy = year, mm = month, dd = day, hh = hour)
     847           0 :         write(usubdaily_discharge, formData) tt, hour, day, month, year, (Qobs(tt, gg), Qsim(tt, gg), gg = igauge_start, igauge_end)
     848           0 :         newTime = newTime + 1.0_dp / real(nMeasPerDay, dp)
     849             :       end do
     850             : 
     851             :       ! close file
     852           0 :       close(usubdaily_discharge)
     853             : 
     854             :       ! ======================================================================
     855             :       ! write netcdf file
     856             :       ! ======================================================================
     857           0 :       fName = trim(adjustl(dirOut(iDomain))) // trim(adjustl(ncfile_subdaily_discharge))
     858           0 :       nc_out = NcDataset(trim(fName), "w")
     859           0 :       tlength = (evalPer(iDomain)%julEnd - evalPer(iDomain)%julStart + 1) * nMeasPerDay
     860             :       ! write time
     861           0 :       allocate(taxis(tlength))
     862             : 
     863           0 :       use_minutes = .false.
     864           0 :       time_unit_factor = 1
     865           0 :       if ( mod(factor, 2) == 1 ) then
     866           0 :         use_minutes = .true.
     867           0 :         time_unit_factor = 60
     868             :       end if
     869             : 
     870             :       ! tt is dependent on the unit of the time axis and is set to hours in mRM
     871             :       select case( output_time_reference_mrm)
     872             :         case(0)
     873           0 :           forall(tt = 1 : tlength) taxis(tt) = (tt-1) * factor * time_unit_factor
     874             :         case(1)
     875           0 :           forall(tt = 1 : tlength) taxis(tt) = tt * factor - factor * time_unit_factor / 2
     876             :         case(2)
     877           0 :           forall(tt = 1 : tlength) taxis(tt) = tt * factor * time_unit_factor
     878             :       end select
     879             : 
     880           0 :       call dec2date(real(evalPer(iDomain)%julStart, dp) - 0.5_dp, yy = year, mm = month, dd = day, hh = hour)
     881           0 :       dim = nc_out%setDimension("time", tlength)
     882           0 :       var = nc_out%setVariable("time", "i32", [dim])
     883           0 :       call var%setData(taxis)
     884           0 :       if (use_minutes) then
     885             :         call var%setAttribute( &
     886             :           "units", &
     887             :           'minutes since '//trim(num2str(year))//'-'//trim(num2str(month, '(i2.2)'))//'-'//trim(num2str(day, '(i2.2)'))//' '// &
     888             :           trim(num2str(hour, '(i2.2)'))//':00:00' &
     889           0 :         )
     890           0 :         call var%setAttribute("long_name", "time in minutes")
     891             :       else
     892             :         call var%setAttribute( &
     893             :           "units", &
     894             :           'hours since '//trim(num2str(year))//'-'//trim(num2str(month, '(i2.2)'))//'-'//trim(num2str(day, '(i2.2)'))//' '// &
     895             :           trim(num2str(hour, '(i2.2)'))//':00:00' &
     896           0 :         )
     897           0 :         call var%setAttribute("long_name", "time in hours")
     898             :       end if
     899           0 :       call var%setAttribute("bounds", "time_bnds")
     900           0 :       call var%setAttribute("axis", "T")
     901           0 :       dim_bnd = nc_out%setDimension("bnds", 2)
     902           0 :       var = nc_out%setVariable("time_bnds", "i32", [dim_bnd, dim])
     903           0 :       do tt = 1, tlength
     904           0 :         call var%setData((tt - 1) * factor * time_unit_factor, (/1, tt/))
     905           0 :         call var%setData(tt * factor * time_unit_factor, (/2, tt/))
     906             :       end do
     907           0 :       deallocate(taxis)
     908             :       ! write gauges
     909           0 :       do gg = igauge_start, igauge_end
     910           0 :         var = nc_out%setVariable('Qsim_' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')), "f64", [dim])
     911           0 :         call var%setFillValue(nodata_dp)
     912           0 :         call var%setData(Qsim(1 : tlength, gg))
     913           0 :         call var%setAttribute("units", "m3 s-1")
     914           0 :         call var%setAttribute("long_name", 'simulated discharge at gauge ' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')))
     915           0 :         call var%setAttribute("missing_value", nodata_dp)
     916             :         ! write observed discharge at that gauge
     917           0 :         var = nc_out%setVariable('Qobs_' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')), "f64", [dim])
     918           0 :         call var%setFillValue(nodata_dp)
     919           0 :         call var%setData(Qobs(1 : tlength, gg))
     920           0 :         call var%setAttribute("units", "m3 s-1")
     921           0 :         call var%setAttribute("long_name", 'observed discharge at gauge ' // trim(num2str(gauge%gaugeID(gg), '(i10.10)')))
     922           0 :         call var%setAttribute("missing_value", nodata_dp)
     923             :       end do
     924           0 :       call nc_out%close()
     925             : 
     926             :       ! ======================================================================
     927             :       ! screen output
     928             :       ! ======================================================================
     929           0 :       call message()
     930           0 :       write(dummy, '(I3)') domainID
     931           0 :       call message('  OUTPUT: saved subdaily discharge file for domain ', trim(adjustl(dummy)))
     932           0 :       call message('    to ', trim(fname))
     933           0 :       do gg = igauge_start, igauge_end
     934           0 :         if (count(ge(Qobs(:, gg), 0.0_dp)) > 1)  then
     935             :           call message('    KGE of subdaily discharge (gauge #', trim(adjustl(num2str(gg))), '): ', &
     936           0 :                   trim(adjustl(num2str(kge(Qobs(:, gg), Qsim(:, gg), mask = (ge(Qobs(:, gg), 0.0_dp)))))))
     937             :           call message('    NSE of subdaily discharge (gauge #', trim(adjustl(num2str(gg))), '): ', &
     938           0 :                   trim(adjustl(num2str(nse(Qobs(:, gg), Qsim(:, gg), mask = (ge(Qobs(:, gg), 0.0_dp)))))))
     939             :         end if
     940             :       end do
     941             : 
     942             :       ! update igauge_start
     943           0 :       igauge_start = igauge_end + 1
     944             :       !
     945             :     end do
     946             :     !
     947           0 :   end subroutine write_subdaily_obs_sim_discharge
     948             : 
     949             :   ! ------------------------------------------------------------------
     950             : 
     951             :   !    NAME
     952             :   !        mrm_write_optifile
     953             : 
     954             :   !    PURPOSE
     955             :   !>       \brief Write briefly final optimization results.
     956             : 
     957             :   !>       \details Write overall best objective function and the best optimized parameter set to a file_opti.
     958             : 
     959             :   !    INTENT(IN)
     960             :   !>       \param[in] "real(dp) :: best_OF"                             best objective function value as returnedby the
     961             :   !>       optimization routine
     962             :   !>       \param[in] "real(dp), dimension(:) :: best_paramSet"         best associated global parameter setCalled only
     963             :   !>       when optimize is .TRUE.
     964             :   !>       \param[in] "character(len = *), dimension(:) :: param_names"
     965             : 
     966             :   !    HISTORY
     967             :   !>       \authors David Schaefer
     968             : 
     969             :   !>       \date July 2013
     970             : 
     971             :   ! Modifications:
     972             :   ! Rohini Kumar   Aug 2013 - change in structure of the code including call statements
     973             :   ! Juliane Mai    Oct 2013 - clear parameter names added
     974             :   !                         - double precision written
     975             :   ! Stephan Thober Oct 2015 - ported to mRM
     976             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
     977             : 
     978           0 :   subroutine mrm_write_optifile(best_OF, best_paramSet, param_names)
     979             : 
     980           0 :     use mo_common_mhm_mrm_file, only : file_opti, uopti
     981             :     use mo_common_variables, only : dirConfigOut
     982             :     use mo_string_utils, only : num2str
     983             : 
     984             :     implicit none
     985             : 
     986             :     ! best objective function value as returnedby the optimization routine
     987             :     real(dp), intent(in) :: best_OF
     988             : 
     989             :     ! best associated global parameter setCalled only when optimize is .TRUE.
     990             :     real(dp), dimension(:), intent(in) :: best_paramSet
     991             : 
     992             :     character(len = *), dimension(:), intent(in) :: param_names
     993             : 
     994             :     character(256) :: fName, formHeader, formParams
     995             : 
     996             :     integer(i4) :: ii, err, n_params
     997             : 
     998             : 
     999             :     ! number of parameters
    1000           0 :     n_params = size(best_paramSet)
    1001             : 
    1002             :     ! open file
    1003           0 :     fName = trim(adjustl(dirConfigOut)) // trim(adjustl(file_opti))
    1004           0 :     open(uopti, file = fName, status = 'unknown', action = 'write', iostat = err, recl = (n_params + 1) * 40)
    1005           0 :     if(err .ne. 0) then
    1006           0 :       call error_message('  IOError while openening "', trim(fName), '" Error-Code ', num2str(err))
    1007             :     end if
    1008             : 
    1009             :     ! header
    1010           0 :     write(formHeader, *) '(a40,', n_params, 'a40)'
    1011             :     ! len(param_names(1))=256 but only 39 characters taken here
    1012             :     ! write(uopti, formHeader) 'OF', (trim(adjustl(param_names(ii))), ii=1, n_params)
    1013           0 :     write(uopti, formHeader) 'OF', (trim(adjustl(param_names(ii)(1 : 39))), ii = 1, n_params)
    1014             : 
    1015             :     ! output
    1016           0 :     write(formParams, *) '( es40.14, ', n_params, '(es40.14) )'
    1017           0 :     write(uopti, formParams) best_OF, (best_paramSet(ii), ii = 1, n_params)
    1018             : 
    1019             :     ! close file
    1020           0 :     close(uopti)
    1021             : 
    1022             :     ! screen output
    1023           0 :     call message()
    1024           0 :     call message(' Optimized parameters written to ', trim(fName))
    1025             : 
    1026           0 :   end subroutine mrm_write_optifile
    1027             : 
    1028             :   ! ------------------------------------------------------------------
    1029             : 
    1030             :   !    NAME
    1031             :   !        mrm_write_optinamelist
    1032             : 
    1033             :   !    PURPOSE
    1034             :   !>       \brief Write final, optimized parameter set in a namelist format.
    1035             : 
    1036             :   !>       \details Write final, optimized parameter set in a namelist format.
    1037             : 
    1038             :   !    INTENT(IN)
    1039             :   !>       \param[in] "real(dp), dimension(:, :) :: parameters"                               (min, max, opti)
    1040             :   !>       \param[in] "logical, dimension(size(parameters, 1)) :: maskpara"                   .true. if parameter was
    1041             :   !>       calibrated
    1042             :   !>       \param[in] "character(len = *), dimension(size(parameters, 1)) :: parameters_name" clear names of parameters
    1043             : 
    1044             :   !    HISTORY
    1045             :   !>       \authors Juliane Mai
    1046             : 
    1047             :   !>       \date Dec 2013
    1048             : 
    1049             :   ! Modifications:
    1050             :   ! Stephan Thober Oct 2015 - adapted to mRM
    1051             :   ! Stephan Thober Nov 2016 - adapt header to routing process
    1052             :   ! Robert Schweppe Jun 2018 - refactoring and reformatting
    1053             : 
    1054           0 :   subroutine mrm_write_optinamelist(parameters, maskpara, parameters_name)
    1055             : 
    1056           0 :     use mo_common_mhm_mrm_file, only : file_opti_nml, uopti_nml
    1057             :     use mo_common_variables, only : dirConfigOut, processMatrix
    1058             :     use mo_string_utils, only : num2str
    1059             : 
    1060             :     implicit none
    1061             : 
    1062             :     ! (min, max, opti)
    1063             :     real(dp), dimension(:, :), intent(in) :: parameters
    1064             : 
    1065             :     ! .true. if parameter was calibrated
    1066             :     logical, dimension(size(parameters, 1)), intent(in) :: maskpara
    1067             : 
    1068             :     ! clear names of parameters
    1069             :     character(len = *), dimension(size(parameters, 1)), intent(in) :: parameters_name
    1070             : 
    1071             :     character(256) :: fName
    1072             : 
    1073             :     character(3) :: flag
    1074             : 
    1075             :     integer(i4) :: err
    1076             : 
    1077             :     integer(i4) :: iPar
    1078             : 
    1079             : 
    1080             :     ! open file
    1081           0 :     fName = trim(adjustl(dirConfigOut)) // trim(adjustl(file_opti_nml))
    1082           0 :     open(uopti_nml, file = fName, status = 'unknown', action = 'write', iostat = err)
    1083           0 :     if(err .ne. 0) then
    1084           0 :       call message ('  IOError while openening "', trim(fName), '" Error-Code ', num2str(err))
    1085             :     end if
    1086             : 
    1087           0 :     write(uopti_nml, *) '!global_parameters'
    1088           0 :     write(uopti_nml, *) '!PARAMETER                       lower_bound  upper_bound          value   FLAG  SCALING'
    1089             : 
    1090           0 :     write(uopti_nml, *) '! ', trim(adjustl('routing'))
    1091             : 
    1092           0 :     if (processMatrix(8, 1) .eq. 1_i4) write(uopti_nml, *) '&routing1'
    1093           0 :     if (ProcessMatrix(8, 1) .eq. 2_i4) write(uopti_nml, *) '&routing2'
    1094           0 :     if (ProcessMatrix(8, 1) .eq. 3_i4) write(uopti_nml, *) '&routing3'
    1095             : 
    1096           0 :     do iPar = 1, size(parameters, 1)
    1097           0 :       if (maskpara(iPar)) then
    1098           0 :         flag = ' 1 '
    1099             :       else
    1100           0 :         flag = ' 0 '
    1101             :       end if
    1102           0 :       write(uopti_nml, *) trim(adjustl(parameters_name(iPar))), ' = ', &
    1103           0 :               parameters(iPar, 1), ' , ', &
    1104           0 :               parameters(iPar, 2), ' , ', &
    1105           0 :               parameters(iPar, 3), ' , ', &
    1106           0 :               flag, ', 1 '
    1107             :     end do
    1108             : 
    1109           0 :     write(uopti_nml, *) '/'
    1110           0 :     write(uopti_nml, *) ' '
    1111             : 
    1112             :     ! close file
    1113           0 :     close(uopti_nml)
    1114             : 
    1115             :     ! screen output
    1116           0 :     call message()
    1117           0 :     call message(' Optimized parameters written in namelist format to ', trim(fName))
    1118             : 
    1119           0 :   end subroutine mrm_write_optinamelist
    1120             : 
    1121             : 
    1122             : end module mo_mrm_write

Generated by: LCOV version 1.16