Skip to content
Snippets Groups Projects
mode_util.f90 71.2 KiB
Newer Older
  • Learn to ignore specific revisions
  •     integer                       :: inb_procio_r_save
        INTEGER(KIND=CDFINT)          :: ioldmode
        INTEGER(KIND=CDFINT)          :: istatus
        INTEGER(KIND=CDFINT)          :: ivar_id
        integer(kind=CDFINT)          :: ilen
        INTEGER(KIND=LFIINT)          :: ilu,iresp
        logical                       :: gok
    
        CALL PRINT_MSG(NVERB_DEBUG,'IO','OPEN_FILES','called')
    
    
        !
        ! Infiles
        !
        IF (runmode == MODECDF2CDF .OR. runmode == MODECDF2LFI) THEN
           !
           ! NetCDF
           !
    
           CALL IO_FILE_ADD2LIST(INFILES(1)%TFILE,HINFILE,'MNH','READ',HFORMAT='NETCDF4')
    
           nbvar_infile = INFILES(1)%TFILE%NNCNAR
    
    
           !Open fallback file if provided
           if ( options( OPTFALLBACK )%set ) then
             inb_procio_r_save = NB_PROCIO_R
             NB_PROCIO_R = 1
             CALL IO_FILE_ADD2LIST(INFILES(2)%TFILE,options( OPTFALLBACK )%cvalue,'UNKNOWN','READ',HFORMAT='NETCDF4')
    
             CALL IO_FILE_OPEN(INFILES(2)%TFILE)
    
           CALL IO_FILE_ADD2LIST(INFILES(1)%TFILE,HINFILE,'MNH','READ', &
    
           ilu = INFILES(1)%TFILE%NLFIFLU
    
           nbvar_infile = INFILES(1)%TFILE%NLFININAR
    
              CALL LFILAF(iresp,ilu,lfalse)
    
    
           !Open fallback file if provided
           if ( options( OPTFALLBACK )%set ) then
             inb_procio_r_save = NB_PROCIO_R
             NB_PROCIO_R = 1
             CALL IO_FILE_ADD2LIST(INFILES(2)%TFILE,options( OPTFALLBACK )%cvalue,'UNKNOWN','READ', &
                                   HFORMAT='LFI',KLFIVERB=0)
    
             CALL IO_FILE_OPEN(INFILES(2)%TFILE)
    
       !Read problem dimensions and some grid variables (needed to determine domain size and also by IO_FILE_OPEN to create netCDF files)
    
       CALL IO_Field_read(INFILES(1)%TFILE,'JPHEXT',JPHEXT,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'JPHEXT',JPHEXT,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'JPHEXT not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'IMAX',NIMAX_ll,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'IMAX',NIMAX_ll,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'IMAX not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'JMAX',NJMAX_ll,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'JMAX',NJMAX_ll,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'JMAX not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'KMAX',NKMAX,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'KMAX',NKMAX,IRESP2)
    
       CALL IO_Field_read(INFILES(1)%TFILE,'PROGRAM',CPROGRAM_ORIG,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'PROGRAM',CPROGRAM_ORIG,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'PROGRAM not found')
    
       CALL IO_Field_read(INFILES(1)%TFILE,'STORAGE_TYPE',CSTORAGE_TYPE,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'STORAGE_TYPE',CSTORAGE_TYPE,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'STORAGE_TYPE not found')
    
       CALL IO_Field_read(INFILES(1)%TFILE,'XHAT',XXHAT,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'XHAT',XXHAT,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'XHAT not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'YHAT',XYHAT,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'YHAT',XYHAT,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'YHAT not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'CARTESIAN',LCARTESIAN,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'CARTESIAN',LCARTESIAN,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'CARTESIAN not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'LAT0',XLAT0,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'LAT0',XLAT0,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'LAT0 not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'LON0',XLON0,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'LON0',XLON0,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'LON0 not found')
    
    
       CALL IO_Field_read(INFILES(1)%TFILE,'BETA',XBETA,IRESP2)
    
       !If not found in main file, try the fallback one
    
       if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'BETA',XBETA,IRESP2)
    
       if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'BETA not found')
    
    
         CALL IO_Field_read(INFILES(1)%TFILE,'RPK',   XRPK,   IRESP2)
    
        !If not found in main file, try the fallback one
    
        if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'RPK',   XRPK,IRESP2)
    
        if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'RPK not found')
    
    
         CALL IO_Field_read(INFILES(1)%TFILE,'LATORI',XLATORI,IRESP2)
    
        !If not found in main file, try the fallback one
    
        if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'LATORI',XLATORI,IRESP2)
    
        if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'LATORI not found')
    
    
         CALL IO_Field_read(INFILES(1)%TFILE,'LONORI',XLONORI,IRESP2)
    
        !If not found in main file, try the fallback one
    
        if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'LONORI',XLONORI,IRESP2)
    
        if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'LONORI not found')
    
       ENDIF
       !
       IF (TRIM(CPROGRAM_ORIG)/='PGD' .AND. TRIM(CPROGRAM_ORIG)/='NESPGD' .AND. TRIM(CPROGRAM_ORIG)/='ZOOMPG' &
           .AND. .NOT.(TRIM(CPROGRAM_ORIG)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX
         ALLOCATE(XZHAT(NKMAX+2*JPVEXT))
    
         CALL IO_Field_read(INFILES(1)%TFILE,'ZHAT',XZHAT,IRESP2)
    
         !If not found in main file, try the fallback one
    
         if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'ZHAT',XZHAT,IRESP2)
    
         if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'ZHAT not found')
    
    
         CALL IO_Field_read(INFILES(1)%TFILE,'SLEVE',LSLEVE,IRESP2)
    
         !If not found in main file, try the fallback one
    
         if ( options( OPTFALLBACK )%set .and. iresp2 /= 0 ) CALL IO_Field_read(INFILES(2)%TFILE,'SLEVE',LSLEVE,IRESP2)
    
         if ( iresp2 /= 0 ) call Print_msg( NVERB_ERROR, 'IO', 'OPEN_FILES', 'SLEVE not found')
    
    
         CALL IO_Field_read(INFILES(1)%TFILE,'DTMOD',TDTMOD,IRESP2)
    
         CALL IO_Field_read(INFILES(1)%TFILE,'DTCUR',TDTCUR,IRESP2)
    
    
         !If time values were not found, try to get it from the time coordinate
         if ( .not. associated( tdtcur ) .and. infiles(1)%tfile%cformat == 'NETCDF4' ) then
           gok = .false.
    
           istatus = NF90_INQ_VARID( infiles(1)%tfile%nncid, 'time', ivar_id )
           if ( istatus == NF90_NOERR ) then
             allocate( tdtcur )
    
             istatus = NF90_GET_VAR( infiles(1)%tfile%nncid, ivar_id, tdtcur%xtime )
    
             if ( istatus == NF90_NOERR ) then
               istatus = NF90_INQUIRE_ATTRIBUTE( infiles(1)%tfile%nncid, ivar_id, 'units', len = ilen )
               if ( istatus == NF90_NOERR ) then
                 allocate( character(len = ilen ) :: yunits )
                 istatus = NF90_GET_ATT( infiles(1)%tfile%nncid, ivar_id, 'units', yunits )
                 ! Extract date from yunits
                 idx =  INDEX( yunits, 'since ' )
    
                 Read( yunits(idx+6 :idx+9 ) , '( I4.4 )' ) tdtcur%nyear
                 Read( yunits(idx+11:idx+12 ), '( I2.2 )' ) tdtcur%nmonth
                 Read( yunits(idx+14:idx+15 ), '( I2.2 )' ) tdtcur%nday
    
    
                 if ( .not. associated( tdtmod ) ) then
                   allocate( tdtmod )
                   tdtmod = tdtcur
    
       ! Outfiles
       !
       IF (runmode == MODELFI2CDF .OR. runmode == MODECDF2CDF) THEN
    
             KNFILES_OUT = KNFILES_OUT + 1
    
               CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,HOUTFILE,'MNH','WRITE', &
    
                                     HFORMAT='NETCDF4',OOLD=.TRUE., hdirname = options(OPTDIR)%cvalue )
             else
    
               CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,HOUTFILE,'MNH','WRITE', &
    
             CALL IO_FILE_OPEN(outfiles(idx)%TFILE,HPROGRAM_ORIG=CPROGRAM_ORIG)
    
               outfiles(idx)%tfile%LNCCOMPRESS       = .TRUE.
               outfiles(idx)%tfile%NNCCOMPRESS_LEVEL = options(OPTCOMPRESS)%ivalue
    
               outfiles(idx)%tfile%LNCREDUCE_FLOAT_PRECISION = .TRUE.
    
             istatus = NF90_SET_FILL(outfiles(idx)%TFILE%NNCID,NF90_NOFILL,ioldmode)
             if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'OPEN_FILES', 'NF90_SET_FILL', '' )
    
           END IF ! .NOT.osplit
    
           KNFILES_OUT = KNFILES_OUT + 1
           idx = KNFILES_OUT
    
             CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,houtfile,'MNH','WRITE', &
    
                                   HFORMAT='LFI',KLFIVERB=0,OOLD=.TRUE., hdirname = options(OPTDIR)%cvalue )
           else
    
             CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,houtfile,'MNH','WRITE', &
    
           LIOCDF4 = .FALSE. !Necessary to open correctly the LFI file
    
           CALL IO_FILE_OPEN(outfiles(idx)%TFILE,HPROGRAM_ORIG=CPROGRAM_ORIG)
    
       END IF
       !
       ! Create a dummy netCDF file necessary to manage correctly the netCDF dims
       IF (runmode == MODECDF2LFI) THEN
    
         KNFILES_OUT = KNFILES_OUT + 1
    
           CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,'dummy_file','MNH','WRITE', &
    
                                 HFORMAT='NETCDF4',OOLD=.TRUE., hdirname = options(OPTDIR)%cvalue )
         else
    
           CALL IO_FILE_ADD2LIST(outfiles(idx)%TFILE,'dummy_file','MNH','WRITE', &
    
         CALL IO_FILE_OPEN(outfiles(idx)%TFILE,HPROGRAM_ORIG=CPROGRAM_ORIG)
    
       PRINT *,'--> Converted to file: ', TRIM(houtfile)
    
    
      END SUBROUTINE OPEN_FILES
    
      SUBROUTINE OPEN_SPLIT_NCFILES_OUT(outfiles,KNFILES_OUT,houtfile,nbvar,options)
    
        USE MODE_IO_MANAGE_STRUCT, ONLY: IO_FILE_ADD2LIST
    
    
        TYPE(TFILE_ELT),DIMENSION(:),  INTENT(INOUT) :: outfiles
        INTEGER,                       INTENT(OUT)   :: KNFILES_OUT
    
        CHARACTER(LEN=*),              INTENT(IN)    :: houtfile
        INTEGER,                       INTENT(IN)    :: nbvar
    
        TYPE(option),DIMENSION(:),     INTENT(IN)    :: options
    
        CHARACTER(LEN=:),ALLOCATABLE                   :: filename
        CHARACTER(LEN=:),ALLOCATABLE                   :: YLIST
    
        CHARACTER(LEN=NMNHNAMELGTMAX),DIMENSION(nbvar) :: YVARS
    
        INTEGER                  :: ji
        INTEGER                  :: idx1, idx2
    
        INTEGER(KIND=CDFINT)     :: status
    
        INTEGER(KIND=CDFINT)     :: ioldmode
    
        CALL PRINT_MSG(NVERB_DEBUG,'IO','OPEN_SPLIT_NCFILES_OUT','called')
    
    
        YLIST = TRIM(options(OPTVAR)%cvalue)
    
        DO ji = 1,nbvar-1
          idx1 = INDEX(YLIST,',')
          idx2 = INDEX(YLIST,'=')
          IF (idx1/=0) THEN
            IF (idx2/=0 .AND. idx2<idx1) THEN
              YVARS(ji) = YLIST(1:idx2-1)
            ELSE
              YVARS(ji) = YLIST(1:idx1-1)
            END IF
            YLIST = YLIST(idx1+1:)
          ELSE
            CALL PRINT_MSG(NVERB_FATAL,'IO','OPEN_SPLIT_NCFILES_OUT','problem separating variable names')
          END IF
    
        idx2 = INDEX(YLIST,'=')
        IF (idx2>0) THEN
          YVARS(nbvar) = YLIST(1:idx2-1)
        ELSE
          YVARS(nbvar) = YLIST
        END IF
    
          filename = trim(houtfile)//'.'//TRIM(YVARS(ji))
    
            CALL IO_FILE_ADD2LIST(outfiles(ji)%TFILE,filename,'MNH','WRITE', &
    
                                  HFORMAT='NETCDF4', hdirname = options(OPTDIR)%cvalue )
          else
    
            CALL IO_FILE_ADD2LIST(outfiles(ji)%TFILE,filename,'MNH','WRITE', &
    
          CALL IO_FILE_OPEN(outfiles(ji)%TFILE,HPROGRAM_ORIG=CPROGRAM_ORIG)
    
            outfiles(ji)%tfile%LNCCOMPRESS       = .TRUE.
            outfiles(ji)%tfile%NNCCOMPRESS_LEVEL = options(OPTCOMPRESS)%ivalue
    
            outfiles(ji)%tfile%LNCREDUCE_FLOAT_PRECISION = .TRUE.
    
          status = NF90_SET_FILL(outfiles(ji)%TFILE%NNCID,NF90_NOFILL,ioldmode)
    
          if ( status /= NF90_NOERR ) call IO_Err_handle_nc4( status, 'OPEN_SPLIT_NCFILES_OUT', 'NF90_SET_FILL', '' )
    
      END SUBROUTINE OPEN_SPLIT_NCFILES_OUT
    
      SUBROUTINE CLOSE_FILES(filelist,KNFILES)
    
        TYPE(TFILE_ELT),DIMENSION(:),INTENT(INOUT) :: filelist
        INTEGER,                     INTENT(IN)    :: KNFILES
    
        CALL PRINT_MSG(NVERB_DEBUG,'IO','CLOSE_FILES','called')
    
    
          IF (filelist(ji)%TFILE%LOPENED) CALL IO_FILE_CLOSE(filelist(ji)%TFILE,HPROGRAM_ORIG=CPROGRAM_ORIG)
    
      END SUBROUTINE CLOSE_FILES
    
      SUBROUTINE IO_Metadata_get_nc4(TPFILE,KVAR_ID,TPREC)
    
        USE MODD_DIM_n,      ONLY: NKMAX
        USE MODD_PARAMETERS, ONLY: JPVEXT
    
    
        TYPE(TFILEDATA),      INTENT(IN)    :: TPFILE
    
        INTEGER(KIND=CDFINT), INTENT(IN)    :: KVAR_ID
        TYPE(workfield),      INTENT(INOUT) :: TPREC
    
        character(len=:), allocatable            :: YSPLIT
        character(len=:), allocatable            :: YTIMEDEP
        integer                                  :: iblocks
    
        INTEGER(KIND=CDFINT)                     :: ISTATUS
    
        INTEGER(KIND=CDFINT)                     :: IFILE_ID
        INTEGER(KIND=CDFINT)                     :: IVAR_ID
    
        INTEGER(KIND=CDFINT),DIMENSION(NF90_MAX_VAR_DIMS) :: IDIMS_ID
    
        CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Metadata_get_nc4','called')
    
        !Necessary to know if we already are in a split file for determining correct number of dimensions
        GSPLIT_AT_ENTRY = TPREC%LSPLIT
    
        IFILE_ID = TPFILE%NNCID
    
        iblocks = -1
    
        ISTATUS = NF90_INQUIRE_VARIABLE(IFILE_ID, KVAR_ID, NDIMS = TPREC%NDIMS_FILE, &
    
                                        XTYPE = TPREC%NTYPE_FILE, DIMIDS = IDIMS_ID)
    
        if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_VARIABLE', '' )
    
        !split_variable and other attributes were added in MesoNH > 5.4.2
        ISTATUS = NF90_INQUIRE_ATTRIBUTE(IFILE_ID, KVAR_ID, 'split_variable', LEN=ILENG)
        IF (ISTATUS == NF90_NOERR) THEN
    
          IF (GSPLIT_AT_ENTRY) CALL PRINT_MSG(NVERB_ERROR,'IO','IO_Metadata_get_nc4','split variable delcaration inside a split file')
    
    
          ALLOCATE(CHARACTER(LEN=ILENG) :: YSPLIT)
          ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'split_variable', YSPLIT)
          IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'split_variable' )
          IF ( YSPLIT == 'yes' ) then
            TPREC%LSPLIT = .true.
    
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'ndims', TPREC%NDIMS_FILE)
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'ndims' )
    
            IF ( TPREC%NDIMS_FILE/=3 ) CALL PRINT_MSG(NVERB_ERROR,'IO','IO_Metadata_get_nc4', &
    
                                                      'split variable with ndims/=3 not supported')
    
            ISTATUS = NF90_INQUIRE_ATTRIBUTE(IFILE_ID, KVAR_ID, 'time_dependent', LEN=ILENG)
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_ATTRIBUTE', &
                                                               'time_dependent' )
            ALLOCATE(CHARACTER(LEN=ILENG) :: YTIMEDEP)
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'time_dependent', YTIMEDEP)
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'time_dependent' )
            IF ( YTIMEDEP == 'yes' ) then
              TPREC%TFIELD%LTIMEDEP = .TRUE.
            ELSE IF ( YTIMEDEP == 'no' ) THEN
              TPREC%TFIELD%LTIMEDEP = .FALSE.
            ELSE
    
              CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Metadata_get_nc4','unknown value '//trim(YTIMEDEP)// &
    
                                                                      ' for time_dependent attribute' )
            END IF
    
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'split_nblocks', iblocks)
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'split_nblocks' )
    
    !PW: todo:check tfiles_ioz exist
            IFILE_ID = TPFILE%TFILES_IOZ(1)%TFILE%NNCID
    
            istatus = NF90_INQ_VARID(IFILE_ID,trim(TPREC%NAME)//'0001',ivar_id)
            IF (ISTATUS /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQ_VARID', &
                                                               trim(TPREC%NAME)//'0001' )
            ISTATUS = NF90_INQUIRE_VARIABLE(IFILE_ID, IVAR_ID, DIMIDS = IDIMS_ID)
            IF (ISTATUS /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_VARIABLE',&
                                                               trim(TPREC%NAME)//'0001' )
    
            DEALLOCATE(YTIMEDEP)
          ELSE IF ( YSPLIT /= 'no' ) THEN
    
            CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Metadata_get_nc4','unknown value '//trim(YSPLIT)//' for split_variable attribute' )
          END IF
    
          DEALLOCATE(YSPLIT)
        END IF
    
        ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'grid',TPREC%NGRID_FILE)
        !On MesoNH versions < 5.4.0, the grid number was stored in 'GRID' instead of 'grid'
        IF (ISTATUS /= NF90_NOERR) ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'GRID',TPREC%NGRID_FILE)
        IF (ISTATUS /= NF90_NOERR) TPREC%NGRID_FILE = 0
    
        ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'units',TPREC%CUNITS_FILE)
        IF (ISTATUS /= NF90_NOERR) TPREC%CUNITS_FILE = ''
    
        !split_variable and other attributes were added in MesoNH > 5.4.2
        ISTATUS = NF90_INQUIRE_ATTRIBUTE(IFILE_ID, KVAR_ID, 'split_variable', LEN=ILENG)
        IF (ISTATUS == NF90_NOERR) THEN
    
          IF (GSPLIT_AT_ENTRY) CALL PRINT_MSG(NVERB_ERROR,'IO','IO_Metadata_get_nc4','split variable declaration inside a split file')
    
    
          ALLOCATE(CHARACTER(LEN=ILENG) :: YSPLIT)
          ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'split_variable', YSPLIT)
    
          IF (istatus /= NF90_NOERR) call IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'split_variable' )
    
          IF ( YSPLIT == 'yes' ) then
            TPREC%LSPLIT = .true.
    
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'ndims', TPREC%NDIMS_FILE)
    
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'ndims' )
            IF ( TPREC%NDIMS_FILE/=3 ) CALL PRINT_MSG(NVERB_ERROR,'IO','IO_Metadata_get_nc4', &
    
                                                      'split variable with ndims/=3 not supported')
    
            ISTATUS = NF90_INQUIRE_ATTRIBUTE(IFILE_ID, KVAR_ID, 'time_dependent', LEN=ILENG)
    
            IF (istatus /= NF90_NOERR) &
              CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_ATTRIBUTE', 'time_dependent' )
    
            ALLOCATE(CHARACTER(LEN=ILENG) :: YTIMEDEP)
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'time_dependent', YTIMEDEP)
    
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'time_dependent' )
    
            IF ( YTIMEDEP == 'yes' ) then
              TPREC%TFIELD%LTIMEDEP = .TRUE.
            ELSE IF ( YTIMEDEP == 'no' ) THEN
              TPREC%TFIELD%LTIMEDEP = .FALSE.
            ELSE
    
              CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Metadata_get_nc4','unknown value '//trim(YTIMEDEP)// &
    
                                                                      ' for time_dependent attribute' )
            END IF
    
            ISTATUS = NF90_GET_ATT(IFILE_ID, KVAR_ID, 'split_nblocks', iblocks)
    
            IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_GET_ATT', 'split_nblocks' )
    
    
    !PW: todo:check tfiles_ioz exist
            IFILE_ID = TPFILE%TFILES_IOZ(1)%TFILE%NNCID
    
            istatus = NF90_INQ_VARID(IFILE_ID,trim(TPREC%NAME)//'0001',ivar_id)
    
            IF (ISTATUS /= NF90_NOERR) &
              CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQ_VARID', trim(TPREC%NAME)//'0001' )
    
            ISTATUS = NF90_INQUIRE_VARIABLE(IFILE_ID, IVAR_ID, DIMIDS = IDIMS_ID)
    
            IF (ISTATUS /= NF90_NOERR) &
              CALL IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_VARIABLE', trim(TPREC%NAME)//'0001' )
    
    
            DEALLOCATE(YTIMEDEP)
          ELSE IF ( YSPLIT /= 'no' ) THEN
    
            CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Metadata_get_nc4','unknown value '//trim(YSPLIT)//' for split_variable attribute' )
    
          END IF
    
          DEALLOCATE(YSPLIT)
        END IF
    
        ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'grid',TPREC%NGRID_FILE)
        !On MesoNH versions < 5.4.0, the grid number was stored in 'GRID' instead of 'grid'
        IF (ISTATUS /= NF90_NOERR) ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'GRID',TPREC%NGRID_FILE)
        IF (ISTATUS /= NF90_NOERR) TPREC%NGRID_FILE = 0
    
        ISTATUS = NF90_GET_ATT(IFILE_ID,KVAR_ID,'units',TPREC%CUNITS_FILE)
        IF (ISTATUS /= NF90_NOERR) TPREC%CUNITS_FILE = ''
    
    
        IF (.NOT.TPREC%LSPLIT) THEN
          ALLOCATE(TPREC%NDIMSIZES_FILE(TPREC%NDIMS_FILE))
          ALLOCATE(TPREC%CDIMNAMES_FILE(TPREC%NDIMS_FILE))
        ELSE
    
          IF ( GSPLIT_AT_ENTRY ) THEN
            ALLOCATE(TPREC%NDIMSIZES_FILE(TPREC%NDIMS_FILE+1))
            ALLOCATE(TPREC%CDIMNAMES_FILE(TPREC%NDIMS_FILE+1))
          ELSE
            IF (TPREC%TFIELD%LTIMEDEP) THEN
              ALLOCATE(TPREC%NDIMSIZES_FILE(TPREC%NDIMS_FILE+1))
              ALLOCATE(TPREC%CDIMNAMES_FILE(TPREC%NDIMS_FILE+1))
            ELSE
              ALLOCATE(TPREC%NDIMSIZES_FILE(TPREC%NDIMS_FILE))
              ALLOCATE(TPREC%CDIMNAMES_FILE(TPREC%NDIMS_FILE))
            END IF
          END IF
    
        END IF
    
        IF (TPREC%NDIMS_FILE == 0) THEN
          ! Scalar variable
          ILENG = 1
        ELSE
          ! Fill dimensions info
          ILENG = 1
          DO JDIM=1,TPREC%NDIMS_FILE
    
            ISTATUS = NF90_INQUIRE_DIMENSION(IFILE_ID,IDIMS_ID(JDIM),                    &
    
                                                       len =  TPREC%NDIMSIZES_FILE(JDIM), &
                                                       name = TPREC%CDIMNAMES_FILE(JDIM)  )
    
            if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'IO_Metadata_get_nc4', 'NF90_INQUIRE_DIMENSION', '' )
    
            ILENG = ILENG*TPREC%NDIMSIZES_FILE(JDIM)
          END DO
    
          IF (TPREC%NDIMS_FILE>0) THEN
            IF (TPREC%CDIMNAMES_FILE(TPREC%NDIMS_FILE)=='time') THEN
              TPREC%TFIELD%LTIMEDEP = .TRUE.
            ELSE
              TPREC%TFIELD%LTIMEDEP = .FALSE.
            END IF
          ELSE
            TPREC%TFIELD%LTIMEDEP = .FALSE.
          END IF
    
          IF (TPREC%LSPLIT) THEN
            IF(     (.NOT.TPREC%TFIELD%LTIMEDEP .AND.  TPREC%NDIMS_FILE/=2)   &
                .OR. (     TPREC%TFIELD%LTIMEDEP .AND.  TPREC%NDIMS_FILE/=3) ) &
    
              CALL PRINT_MSG(NVERB_FATAL,'IO','IO_Metadata_get_nc4',trim(TPREC%NAME)//': split variables can only be 3D')
    
            !Split variables are Z-split
            !Move time dimension to last (4th) position
            IF (TPREC%TFIELD%LTIMEDEP) THEN
              TPREC%NDIMSIZES_FILE(4) = TPREC%NDIMSIZES_FILE(3)
              TPREC%CDIMNAMES_FILE(4) = TPREC%CDIMNAMES_FILE(3)
    
            !Add vertical/3rd dimension
            SELECT CASE(TPREC%NGRID_FILE)
              CASE (1, 2, 3, 5)
                TPREC%CDIMNAMES_FILE(3) = 'level'
              CASE (4, 6, 7, 8)
                TPREC%CDIMNAMES_FILE(3) = 'level_w'
              CASE DEFAULT
                TPREC%CDIMNAMES_FILE(3) = 'unknown'
            END SELECT
    
            IF (iblocks == -1 ) then
              TPREC%NDIMSIZES_FILE(3) = NKMAX+2*JPVEXT
            else
    
              if (TPREC%NGRID_FILE/=0 .and. iblocks/=NKMAX+2*JPVEXT) THEN
                !If size is not as expected, reset its name
    
                CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Metadata_get_nc4',trim(TPREC%NAME)//': strange nblocks size')
    
                TPREC%CDIMNAMES_FILE(3) = 'unknown'
              end if
              TPREC%NDIMSIZES_FILE(3) = iblocks
            end if
    
            ILENG = ILENG * TPREC%NDIMSIZES_FILE(3)
          END IF
        END IF
    
      SUBROUTINE IO_Dims_fill_nc4(TPFILE,TPREC,KRESP)
        USE MODD_IO,           ONLY: TFILEDATA
    
        use mode_io_tools_nc4, only: IO_Dim_find_create_nc4, IO_Dim_find_byname_nc4
    
        TYPE(workfield),INTENT(INOUT) :: TPREC
        INTEGER,        INTENT(OUT)   :: KRESP
    
    
        CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Dims_fill_nc4','called')
    
        IF (TPREC%NDIMS_FILE<TPREC%TFIELD%NDIMS) THEN
    
          CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Dims_fill_nc4','less dimensions than expected for '//TRIM(TPREC%TFIELD%CMNHNAME)// &
    
                                            ' => ignored')
          TPREC%tbw   = .FALSE.
          TPREC%tbr   = .FALSE.
          TPREC%found = .FALSE.
          RETURN
        END IF
    
    
        ALLOCATE(TPREC%TDIMS(TPREC%TFIELD%NDIMS))
    
        DO JJ=1,TPREC%TFIELD%NDIMS
        !DO JJ=1,TPREC%NDIMS_FILE !NDIMS_FILE can be bigger than NDIMS due to time dimension (it can be ignored here)
    
          CALL IO_Dim_find_byname_nc4(TPFILE,TPREC%CDIMNAMES_FILE(JJ),TPREC%TDIMS(JJ),KRESP)
    
          !If dimension not found => create it
          IF (KRESP/=0)  THEN
    
            call IO_Dim_find_create_nc4( tpfile, tprec%ndimsizes_file(jj), iidx )
            tprec%tdims(jj) = tpfile%tncdims%tdims(iidx)
    
          IF (TRIM(TPREC%TDIMS(JJ)%cname)/='time' .AND. &
            TPREC%TDIMS(JJ)%nlen /= TPREC%NDIMSIZES_FILE(JJ)) THEN
    
            CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Dims_fill_nc4','problem with dimensions for '//TPREC%TFIELD%CMNHNAME)
    
    END MODULE mode_util