LCOV - code coverage report
Current view: top level - src - mo_nml.f90 (source / functions) Hit Total Coverage
Test: forces coverage Lines: 43 54 79.6 %
Date: 2024-03-13 19:03:28 Functions: 3 3 100.0 %

          Line data    Source code
       1             : !> \file mo_nml.f90
       2             : !> \brief \copybrief mo_nml
       3             : !> \details \copydetails mo_nml
       4             : 
       5             : !> \brief Deal with namelist files.
       6             : !> \details This module provides routines to open, close and position namelist files.
       7             : !! - Adapted from Echam5, (C) MPI-MET, Hamburg, Germany
       8             : !> \author L. Kornblueh, MPI, March 2001, original source
       9             : !> \changelog
      10             : !! - Jan 2011, Matthias Cuntz
      11             : !!   - compatible with gfortran <= version 4.3
      12             : !!   - all integer(i4)
      13             : !!   - quiet
      14             : !! - Jan 2013, Matthias Cuntz
      15             : !!   - close_nml with unit, open_nml quiet=.true. default position_nml swap first and status
      16             : !> \authors Matthias Cuntz
      17             : !> \date Jan 2011
      18             : !> \copyright Copyright 2005-\today, the CHS Developers, Sabine Attinger: All rights reserved.
      19             : !! FORCES is released under the LGPLv3+ license \license_note
      20             : MODULE mo_nml
      21             : 
      22             :   USE mo_kind, ONLY : i4
      23             :   USE mo_string_utils, ONLY : tolower
      24             :   USE mo_message, ONLY : message, error_message
      25             : 
      26             :   IMPLICIT NONE
      27             : 
      28             :   PRIVATE
      29             : 
      30             :   PUBLIC :: open_nml                                      ! open namelist file
      31             :   PUBLIC :: close_nml                                     ! close namelist file
      32             :   PUBLIC :: position_nml                                  ! position namelist file
      33             :   PUBLIC :: nunitnml                                      ! namelist unit
      34             :   PUBLIC :: POSITIONED, MISSING, LENGTH_ERROR, READ_ERROR ! return values from position_nml
      35             : 
      36             :   ! return values in optinal status of function 'position_nml'
      37             :   !> Information: file pointer set to namelist group
      38             :   INTEGER(i4), PARAMETER :: POSITIONED = 0
      39             :   !> Error: namelist group is missing
      40             :   INTEGER(i4), PARAMETER :: MISSING = 1
      41             :   !> Error: namelist group name too long
      42             :   INTEGER(i4), PARAMETER :: LENGTH_ERROR = 2
      43             :   !> Error occured during read of namelist file
      44             :   INTEGER(i4), PARAMETER :: READ_ERROR = 3
      45             : 
      46             :   !> default namelist unit
      47             :   INTEGER, SAVE :: nunitnml = -1
      48             : 
      49             :   ! ------------------------------------------------------------------
      50             : 
      51             : CONTAINS
      52             : 
      53             :   ! ------------------------------------------------------------------
      54             : 
      55             :   !>    \brief Open a namelist file.
      56             : 
      57             :   !>    \details Open a namelist file.
      58             :   !!
      59             :   !!    \b Example
      60             :   !!
      61             :   !!    \code{.f90}
      62             :   !!    call open_nml('namelist.txt',nnml)
      63             :   !!    \endcode
      64             :   !!    See also example in test directory
      65             : 
      66             :   !>        \param[in] "character(len=*) :: file"   namelist filename
      67             :   !>        \param[in] "integer          :: unit"   namelist unit
      68             :   !>       \param[in] "logical, optional :: quiet"   Be verbose or not (default: .true.)\n
      69             :   !!                                                            .true.:  no messages\n
      70             :   !!                                                            .false.: write out messages
      71             : 
      72             :   !>    \author Matthias Cuntz
      73             :   !>    \date Dec 2011
      74             :   !!        - modified from Echam5, (C) MPI-MET, Hamburg, Germany
      75             :   !>    \date Jan 2013
      76             :   !!        - quiet=.true. default
      77             :   !>    \author Luis Samaniego
      78             :   !>    \date Nov 2013
      79             :   !!        - comparison statements == -> .eq., etc
      80             : 
      81           1 :   SUBROUTINE open_nml(file, unit, quiet)
      82             : 
      83             :     IMPLICIT NONE
      84             : 
      85             :     CHARACTER(len = *), INTENT(IN) :: file
      86             :     INTEGER, INTENT(IN) :: unit
      87             :     LOGICAL, INTENT(IN), OPTIONAL :: quiet
      88             :     INTEGER :: istat
      89             :     LOGICAL :: iquiet
      90             : 
      91           1 :     iquiet = .false.
      92           0 :     if (present(quiet)) iquiet = quiet
      93             : 
      94           1 :     nunitnml = unit
      95           1 :     if (.not. iquiet) CALL message('    This is namelist ', trim(file))
      96           1 :     OPEN (nunitnml, file = file, iostat = istat, status = 'old', action = 'read', delim = 'apostrophe')
      97             : 
      98           1 :     IF (istat .ne. 0) THEN
      99           0 :       CALL error_message('OPEN_NML: Could not open namelist file ', trim(file))
     100             :     END IF
     101             : 
     102           1 :   END SUBROUTINE open_nml
     103             : 
     104             :   ! ------------------------------------------------------------------
     105             : 
     106             :   !>    \brief Close a namelist file.
     107             : 
     108             :   !>    \details Close a namelist file.
     109             :   !!
     110             :   !!    \b Example
     111             :   !!
     112             :   !!    \code{.f90}
     113             :   !!    call close_nml()
     114             :   !!    ! or
     115             :   !!    call close_nml(unml)
     116             :   !!    \endcode
     117             :   !!    See also example in test directory
     118             : 
     119             :   !>    \param[in] "integer, optional :: unit"   namelist unit
     120             : 
     121             :   !>    \note
     122             :   !!    open_nml remembers the namelist unit in the public, save variable nunitnml.\n
     123             :   !!    close_nml uses nunitnml if unit is not given.
     124             : 
     125             :   !>    \author Matthias Cuntz
     126             :   !>    \date Dec 2011
     127             :   !!        - modified from Echam5, (C) MPI-MET, Hamburg, Germany
     128             :   !>    \date Jan 2013
     129             :   !!        - unit
     130           1 :   SUBROUTINE close_nml(unit)
     131             : 
     132             :     IMPLICIT NONE
     133             : 
     134             :     INTEGER, INTENT(IN), OPTIONAL :: unit
     135             : 
     136             :     INTEGER :: istat, nnml
     137             : 
     138           1 :     nnml = nunitnml
     139           0 :     if (present(unit)) nnml = unit
     140             : 
     141           1 :     IF (nnml .lt. 0) CALL error_message('CLOSE_NML: No namelist file opened.')
     142             : 
     143           1 :     CLOSE(nnml, IOSTAT = istat)
     144             : 
     145           1 :     IF (istat .ne. 0) CALL error_message('CLOSE_NML: Could not close namelist file.')
     146             : 
     147           1 :     if (.not. present(unit)) nunitnml = -1
     148             : 
     149           1 :   END SUBROUTINE close_nml
     150             : 
     151             :   ! ------------------------------------------------------------------
     152             : 
     153             :   !>    \brief Position a namlist file.
     154             : 
     155             :   !>    \details Position namelist file pointer for reading a new namelist next.\n
     156             :   !!    It positions the namelist file at the correct place for reading\n
     157             :   !!    namelist /name/ (case independent).
     158             :   !!
     159             :   !!    \b Example
     160             :   !!
     161             :   !!    \code{.f90}
     162             :   !!    call position_nml('myname',nnml)
     163             :   !!    \endcode
     164             : 
     165             :   !>    \param[in] "character(len=*) :: name"     namelist name (case independent)
     166             :   !>    \param[in] "integer, optional :: unit"    namelist unit (default: nunitnml)
     167             :   !>    \param[in] "logical, optional :: first"   start search at beginning,
     168             :   !!                                              i.e. rewind the namelist first (default: .true.)\n
     169             :   !!                                              .true.:  rewind\n
     170             :   !!                                              .false.: continue search from current file pointer
     171             :   !>    \param[out] "integer(i4), optional :: status"   Set on output to either of\n
     172             :   !!                                                    POSITIONED (0)   - correct\n
     173             :   !!                                                    MISSING (1)      - name not found\n
     174             :   !!                                                    LENGTH_ERROR (2) - namelist length longer then 256 characters\n
     175             :   !!                                                    READ_ERROR (3)   - error while reading namelist file
     176             : 
     177             :   !>    \author Matthias Cuntz
     178             :   !>    \date Dec 2011
     179             :   !!        - modified from Echam5, (C) MPI-MET, Hamburg, Germany
     180             :   !>    \date Jan 2013
     181             :   !!        - swap first and status in call list
     182           3 :   SUBROUTINE position_nml(name, unit, status, first)
     183             : 
     184             :     IMPLICIT NONE
     185             : 
     186             :     CHARACTER(len = *), INTENT(in) :: name   ! namelist group name
     187             :     INTEGER, INTENT(in), OPTIONAL :: unit   ! file unit number
     188             :     INTEGER(i4), INTENT(out), OPTIONAL :: status ! error return value
     189             :     LOGICAL, INTENT(in), OPTIONAL :: first  ! default: true
     190             : 
     191             :     CHARACTER(len = 256) :: yline    ! line read
     192             :     CHARACTER(len = 256) :: test     ! uppercase namelist group name
     193             :     INTEGER(i4) :: stat     ! local copy of status variable
     194             :     INTEGER :: ios      ! status variable from read operation
     195             :     LOGICAL :: lrew     ! local copy of rewind flag
     196             :     INTEGER(i4) :: iunit    ! local copy of unit number
     197             :     INTEGER(i4) :: len_name ! length of requested namelist group name
     198             :     CHARACTER :: ytest    ! character to test for delimiter
     199             :     CHARACTER(len = 12) :: code     ! error code printed
     200             :     INTEGER(i4) :: ind      ! index from index routine
     201             :     INTEGER(i4) :: indc     ! index of comment character (!)
     202             : 
     203           3 :     lrew = .TRUE.
     204           3 :     IF (PRESENT(first)) lrew = first
     205           3 :     iunit = nunitnml
     206           3 :     IF (PRESENT(unit)) iunit = unit
     207           3 :     stat = MISSING
     208           3 :     code = 'MISSING'
     209             : 
     210           3 :     len_name = LEN_TRIM(name)
     211             : 
     212           3 :     IF (len_name .gt. LEN(test)) THEN
     213           0 :       stat = LENGTH_ERROR
     214           0 :       code = 'LENGTH_ERROR'
     215             :     END IF
     216             : 
     217             :     !test = '&'//tolower(name)
     218           3 :     write(test, '(A,A)') '&', tolower(name)
     219             : 
     220             :     ! Reposition file at beginning:
     221           3 :     IF (lrew) REWIND(iunit)
     222             : 
     223             :     ! Search start of namelist
     224             :     DO
     225          24 :       IF (stat .ne. MISSING) EXIT
     226             : 
     227          24 :       yline = ' '
     228             : 
     229          24 :       READ (iunit, *, IOSTAT = ios) yline
     230          24 :       IF (ios .lt. 0) THEN
     231             :         EXIT  ! MISSING
     232          24 :       ELSE IF (ios .gt. 0) THEN
     233           0 :         stat = READ_ERROR
     234           0 :         code = 'READ_ERROR'
     235           0 :         EXIT
     236             :       END IF
     237             : 
     238          24 :       yline = tolower(yline)
     239             : 
     240          24 :       ind = INDEX(yline, TRIM(test))
     241             : 
     242          24 :       IF (ind .eq. 0) CYCLE
     243             : 
     244           3 :       indc = INDEX(yline, '!')
     245             : 
     246           3 :       IF (indc .gt. 0 .AND. indc .lt. ind) CYCLE
     247             : 
     248             :       ! test for delimiter
     249           3 :       ytest = yline(ind + len_name + 1 : ind + len_name + 1)
     250             : 
     251             :       IF ((LGE(ytest, '0') .AND. LLE(ytest, '9')) .OR. &
     252             :               (LGE(ytest, 'a') .AND. LLE(ytest, 'z')) .OR. &
     253           3 :               ytest .eq. '_'                         .OR. &
     254           0 :               (LGE(ytest, 'A') .AND. LLE(ytest, 'Z'))) THEN
     255             :         CYCLE
     256             :       ELSE
     257           3 :         stat = POSITIONED
     258           3 :         BACKSPACE(iunit)
     259          24 :         EXIT
     260             :       END IF
     261             :     END DO
     262             : 
     263           3 :     IF (PRESENT(status)) status = stat
     264             :     SELECT CASE (stat)
     265             :     CASE (POSITIONED)
     266           0 :       RETURN
     267             :     CASE (MISSING)
     268           3 :       IF (PRESENT(status)) RETURN
     269             :     END SELECT
     270             : 
     271             :     ! Error if it reaches here
     272           0 :     CALL error_message('POSITION_NML: namelist /', trim(name) , '/ ', trim(code))
     273             : 
     274           4 :   END SUBROUTINE position_nml
     275             : 
     276             : END MODULE mo_nml

Generated by: LCOV version 1.16