Skip to content
Snippets Groups Projects
mode_util.f90 71.2 KiB
Newer Older
!MNH_LIC Copyright 1994-2020 CNRS, Meteo-France and Universite Paul Sabatier
!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt
!MNH_LIC for details. version 1.
!-----------------------------------------------------------------
! Modifications:
!  P. Wautelet 07/02/2019: force TYPE to a known value for IO_FILE_ADD2LIST
!  P. Wautelet 10/04/2019: use IO_Err_handle_nc4 to handle netCDF errors
!  P. Wautelet 25/06/2019: add support for 3D integer arrays
!  P. Wautelet 01/08/2019: allow merge of entire Z-split files
!  P. Wautelet 18/09/2019: correct support of 64bit integers (MNH_INT=8)
!  P. Wautelet 19/09/2019: add possibility to provide a fallback file if some information are not found in the input file
!  P. Wautelet 21/10/2019: add OPTDIR option to set directory for writing outfiles
!  P. Wautelet 21/10/2019: if DTMOD and DTCUR not found, try to read the time coordinate
!  P. Wautelet 10/11/2020: new data structures for netCDF dimensions
!-----------------------------------------------------------------
MODULE mode_util
  USE MODD_IO,         ONLY: TFILEDATA, TFILE_ELT
  USE MODD_NETCDF,     ONLY: CDFINT, tdimnc
  USE MODD_PARAMETERS, ONLY: NLFIMAXCOMMENTLENGTH, NMNHNAMELGTMAX
  use modd_precision,  only: LFIINT
  use mode_field,          only: Find_field_id_from_mnhname
  use mode_io_tools_nc4,   only: IO_Err_handle_nc4
  INTEGER,PARAMETER :: MAXFILES=100
  INTEGER,parameter :: MAXDATES=100
  TYPE workfield
     CHARACTER(LEN=NMNHNAMELGTMAX)         :: name   ! nom du champ
     LOGICAL                               :: found  ! T if found in the input file
     LOGICAL                               :: calc   ! T if computed from other variables
     LOGICAL                               :: tbw    ! to be written or not
     LOGICAL                               :: tbr    ! to be read or not
     LOGICAL                               :: LSPLIT = .FALSE. ! TRUE if variable is split by vertical level
     INTEGER                               :: NSIZE = 0 ! Size of the variable (in number of elements)
     INTEGER                               :: NSRC = 0 ! Number of variables used to compute the variable (needed only if calc=.true.)
     INTEGER(kind=CDFINT)                  :: NDIMS_FILE  ! Number of dims (as present in input file)
     INTEGER(kind=CDFINT),    DIMENSION(:),ALLOCATABLE :: NDIMSIZES_FILE  ! Dimensions sizes (as present in input file)
     CHARACTER(LEN=NF90_MAX_NAME),DIMENSION(:),ALLOCATABLE :: CDIMNAMES_FILE  ! Dimensions names (as present in input file)
     CHARACTER(LEN=40)                     :: CUNITS_FILE = '' ! Units (as present in input file)
     INTEGER                               :: NGRID_FILE  ! Grid  number (as present in input file)
     INTEGER(kind=CDFINT)                  :: NTYPE_FILE  ! netCDF datatype (NF90_CHAR, NF90_INT...) (as present in input file)
     INTEGER,DIMENSION(MAXRAW)             :: src    ! List of variables used to compute the variable (needed only if calc=.true.)
     INTEGER                               :: tgt    ! Target: id of the variable that use it (calc variable)
     TYPE(TFIELDDATA)                      :: TFIELD ! Metadata about the field
     TYPE(tdimnc),DIMENSION(:),ALLOCATABLE :: TDIMS  ! Dimensions of the field
  END TYPE workfield

  LOGICAL(KIND=LFIINT), PARAMETER :: ltrue  = .TRUE.
  LOGICAL(KIND=LFIINT), PARAMETER :: lfalse = .FALSE.
  SUBROUTINE parse_infiles(infiles, outfiles, KNFILES_OUT, nbvar_infile, nbvar_tbr, nbvar_calc, nbvar_tbw, &
                           tpreclist, options, runmode)
    USE MODD_PARAMETERS, ONLY: JPHEXT, JPVEXT, NGRIDUNKNOWN
    use mode_io_tools_nc4, only: IO_Dimids_guess_nc4
    TYPE(TFILE_ELT),DIMENSION(:),         INTENT(IN)  :: infiles
    TYPE(TFILE_ELT),DIMENSION(:),         INTENT(IN)  :: outfiles
    INTEGER,                              INTENT(IN)  :: KNFILES_OUT
    INTEGER,                              INTENT(IN)  :: nbvar_infile, nbvar_tbr, nbvar_calc, nbvar_tbw
    TYPE(workfield), DIMENSION(:),POINTER,INTENT(OUT) :: tpreclist
    TYPE(option),DIMENSION(:),            INTENT(IN)  :: options
    INTEGER,                              INTENT(IN)  :: runmode
    TYPE TLFIDATE
      CHARACTER(LEN=FM_FIELD_SIZE) :: CNAME = ''     !Name of the date variable
      INTEGER                      :: NIDX_DATE = -1 !Index of the date part
      INTEGER                      :: NIDX_TIME = -1 !Index of the time part
    END TYPE TLFIDATE

    CHARACTER(LEN=FM_FIELD_SIZE)             :: yrecfm, YDATENAME
    CHARACTER(LEN=FM_FIELD_SIZE)             :: var_calc
    CHARACTER(LEN=FM_FIELD_SIZE),dimension(MAXRAW) :: var_raw
    CHARACTER(LEN=1)                         :: YNDIMS
    CHARACTER(LEN=32)                        :: YTYPE
    INTEGER                                  :: ji,jj
    INTEGER                                  :: ndb, nde, ndey, idx, idx_out, idx_var, maxvar
    INTEGER                                  :: leng
    INTEGER                                  :: IID, IRESP, IDATES, ICURDATE
    INTEGER                                  :: IDXDATE, IDXTIME
    INTEGER(KIND=CDFINT)                     :: kcdf_id, kcdf_id2, var_id
    INTEGER(KIND=CDFINT)                     :: status
    TYPE(TLFIDATE),DIMENSION(MAXDATES)       :: TLFIDATES
    CALL PRINT_MSG(NVERB_DEBUG,'IO','parse_infiles','called')

    IF (options(OPTSPLIT)%set) THEN
      idx_out = 0
    ELSE
      idx_out = 1
    END IF
    IF (runmode==MODECDF2LFI) THEN
      !This file is a dummy one to manage netCDF dims
    IF (INFILES(1)%TFILE%CFORMAT == 'LFI') THEN
      ilu = INFILES(1)%TFILE%NLFIFLU
    ELSE IF (INFILES(1)%TFILE%CFORMAT == 'NETCDF4') THEN
      kcdf_id = INFILES(1)%TFILE%NNCID
    PRINT *,'MESONH 3D, 2D articles DIMENSIONS used :'
    PRINT *,'DIMX =',NIMAX_ll+2*JPHEXT
    PRINT *,'DIMY =',NJMAX_ll+2*JPHEXT
    PRINT *,'DIMZ =',NKMAX   +2*JPVEXT

    ! Phase 1 : build articles list to convert.
    !
    !    Pour l'instant tous les articles du fichier LFI sont
    !    convertis. On peut modifier cette phase pour prendre en
    !    compte un sous-ensemble d'article (liste definie par
    !    l'utilisateur par exemple)
      ALLOCATE(tpreclist(nbvar_tbr+nbvar_calc))
      DO ji=1,nbvar_tbr+nbvar_calc
        tpreclist(ji)%found  = .FALSE.
        tpreclist(ji)%calc   = .FALSE. !By default variables are not computed from others
        tpreclist(ji)%tbw    = .TRUE.  !By default variables are written
        tpreclist(ji)%tbr    = .TRUE.  !By default variables are read
        tpreclist(ji)%src(:) = -1
        tpreclist(ji)%tgt    = -1
      END DO

       ! A variable list is provided with -v var1,...
       ndb  = 1
          !crash compiler GCC 4.2.0: nde = INDEX(TRIM(options(OPTVAR)%cvalue(ndb:)),',')
          nde = INDEX(TRIM(options(OPTVAR)%cvalue(ndb:len(trim(options(OPTVAR)%cvalue)))),',')
          IF (nde == 0) nde = LEN( TRIM(options(OPTVAR)%cvalue(ndb:len(trim(options(OPTVAR)%cvalue)))) ) + 1
          yrecfm = options(OPTVAR)%cvalue(ndb:ndb+nde-2)
          !Detect operations on variables (only + is supported now)
          ndey = INDEX(TRIM(yrecfm),'=')
          idx = 1
          IF (ndey /= 0) THEN
            var_calc = yrecfm(1:ndey-1)
            DO WHILE (ndey /= 0)
              IF (idx>MAXRAW) THEN
                CALL PRINT_MSG(NVERB_FATAL,'IO','parse_infiles','MAXRAW exceeded (too many raw variables for 1 computed one)')
              END IF
              yrecfm = yrecfm(ndey+1:)
              ndey = INDEX(TRIM(yrecfm),'+')
              IF (ndey /= 0) THEN
                var_raw(idx) = yrecfm(1:ndey-1)
              ELSE
                var_raw(idx) = TRIM(yrecfm)
              END IF
              idx = idx + 1
            END DO

            tpreclist(idx_var)%name = trim(var_calc)
            tpreclist(idx_var)%calc = .TRUE.
            tpreclist(idx_var)%tbw  = .TRUE.
            tpreclist(idx_var)%tbr  = .FALSE.
            idx_var=idx_var+1
            DO jj = 1, idx-1
              tpreclist(idx_var-jj)%src(jj) = idx_var
              tpreclist(idx_var)%name = trim(var_raw(jj))
              tpreclist(idx_var)%calc = .FALSE.
              tpreclist(idx_var)%tbw  = .FALSE.
              tpreclist(idx_var)%tbr  = .TRUE.
              tpreclist(idx_var)%tgt  = idx_var-jj
              idx_var=idx_var+1
            END DO

          ELSE
            tpreclist(idx_var)%name = trim(yrecfm)
            tpreclist(idx_var)%calc = .FALSE.
            tpreclist(idx_var)%tbw  = .TRUE.
            idx_var=idx_var+1

       DO ji=1,nbvar_tbr+nbvar_calc
          IF (tpreclist(ji)%calc) CYCLE
          yrecfm = TRIM(tpreclist(ji)%name)
          IF (INFILES(1)%TFILE%CFORMAT == 'LFI') THEN
            CALL LFINFO(iresp2,ilu,trim(yrecfm),ileng,ipos)
            IF (iresp2 == 0 .AND. ileng /= 0) THEN
              tpreclist(ji)%found = .true.
              tpreclist(ji)%NSIZE = ileng - 2 - NLFIMAXCOMMENTLENGTH
            END IF

            IF (iresp2==0 .AND. ileng == 0 .AND. ipos==0 .AND. INFILES(1)%TFILE%NSUBFILES_IOZ>0) THEN
              !Variable not found with no error (iresp2==0 .AND. ileng == 0 .AND. ipos==0)
              !If we are merging, maybe it is one of the split variable
              !In that case, the 1st part of the variable is in the 1st split file with a 0001 suffix
              CALL LFINFO(iresp2,INFILES(1)%TFILE%TFILES_IOZ(1)%TFILE%NLFIFLU,trim(yrecfm)//'0001',ileng,ipos)
              IF (iresp2 == 0 .AND. ileng /= 0) THEN
                tpreclist(ji)%found  = .true.
                tpreclist(ji)%LSPLIT = .true.
                IF (tpreclist(ji)%tgt > 0) THEN !If this variable is used for a calculated one
                  tpreclist(tpreclist(ji)%tgt)%LSPLIT = .true.
                END IF
              END IF
              tpreclist(ji)%NSIZE = (ileng - 2 - NLFIMAXCOMMENTLENGTH) * (NKMAX+2*JPVEXT)
              ileng = tpreclist(ji)%NSIZE + 2 + NLFIMAXCOMMENTLENGTH
            leng = ileng
          ELSE IF (INFILES(1)%TFILE%CFORMAT == 'NETCDF4') THEN
            status = NF90_INQ_VARID(kcdf_id,trim(yrecfm),var_id)
            IF (status /= NF90_NOERR .AND. INFILES(1)%TFILE%NSUBFILES_IOZ>0) THEN
              !Variable probably not found (other error possible...)
              !If we are merging, maybe it is one of the split variable
              !In that case, the 1st part of the variable is in the 1st split file with a 0001 suffix
              kcdf_id2 = INFILES(1)%TFILE%TFILES_IOZ(1)%TFILE%NNCID
              tzfile = INFILES(1)%TFILE%TFILES_IOZ(1)%TFILE
              status = NF90_INQ_VARID(kcdf_id2,trim(yrecfm)//'0001',var_id)
              IF (status == NF90_NOERR) THEN
                tpreclist(ji)%LSPLIT = .true.
                IF (tpreclist(ji)%tgt > 0) THEN !If this variable is used for a calculated one
                  tpreclist(tpreclist(ji)%tgt)%LSPLIT = .true.
                END IF
                if ( status /= NF90_NOERR ) &
                  call IO_Err_handle_nc4( status, 'parse_infiles', 'NF90_INQ_VARID', trim(yrecfm)//'0001' )
            ELSE IF (status /= NF90_NOERR) THEN
              call IO_Err_handle_nc4( status, 'parse_infiles', 'NF90_INQ_VARID', trim(yrecfm) )
            IF (status == NF90_NOERR) THEN
              tpreclist(ji)%found = .true.
              CALL IO_Metadata_get_nc4(tzfile,var_id,tpreclist(ji))
            END IF
          END IF

          IF (.NOT.tpreclist(ji)%found) THEN
            CALL PRINT_MSG(NVERB_WARNING,'IO','parse_infiles','variable '//TRIM(yrecfm)//' not found => ignored')
             tpreclist(ji)%tbw   = .FAlSE.
             tpreclist(ji)%tbr   = .FAlSE.
          END IF
Loading
Loading full blame...