From 170d0ea0091a39343c1fd11c3fbbe3810a1f1d70 Mon Sep 17 00:00:00 2001 From: Philippe WAUTELET <philippe.wautelet@aero.obs-mip.fr> Date: Thu, 13 Dec 2018 17:11:15 +0100 Subject: [PATCH] Philippe 13/12/2018: split mode_netcdf module into multiple modules + add new subroutines to check if a file has been closed correctly This is done: *to reduce circular dependencies problems *to have cleaner code *to compile faster *to detect problems with not correctly closed netCDF files --- LIBTOOLS/tools/lfi2cdf/src/mode_util.f90 | 8 +- src/LIB/SURCOUCHE/src/fmread_ll.f90 | 4 +- src/LIB/SURCOUCHE/src/fmwrit_ll.f90 | 10 +- src/LIB/SURCOUCHE/src/mode_fm.f90 | 165 +- src/LIB/SURCOUCHE/src/mode_io.f90 | 132 +- src/LIB/SURCOUCHE/src/mode_io_file_nc4.f90 | 223 ++ src/LIB/SURCOUCHE/src/mode_io_read_nc4.f90 | 1272 +++++++ src/LIB/SURCOUCHE/src/mode_io_tools.f90 | 167 + src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 | 679 ++++ ...{mode_netcdf.f90 => mode_io_write_nc4.f90} | 3186 ++++------------- src/MNH/modeln.f90 | 1 - 11 files changed, 3115 insertions(+), 2732 deletions(-) create mode 100644 src/LIB/SURCOUCHE/src/mode_io_file_nc4.f90 create mode 100644 src/LIB/SURCOUCHE/src/mode_io_read_nc4.f90 create mode 100644 src/LIB/SURCOUCHE/src/mode_io_tools.f90 create mode 100644 src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 rename src/LIB/SURCOUCHE/src/{mode_netcdf.f90 => mode_io_write_nc4.f90} (50%) diff --git a/LIBTOOLS/tools/lfi2cdf/src/mode_util.f90 b/LIBTOOLS/tools/lfi2cdf/src/mode_util.f90 index e30ba71e1..0f55191e7 100644 --- a/LIBTOOLS/tools/lfi2cdf/src/mode_util.f90 +++ b/LIBTOOLS/tools/lfi2cdf/src/mode_util.f90 @@ -56,7 +56,7 @@ CONTAINS USE MODD_DIM_n, ONLY: NIMAX_ll, NJMAX_ll, NKMAX USE MODD_PARAMETERS, ONLY: JPHEXT, JPVEXT, NGRIDUNKNOWN - USE MODE_NETCDF, ONLY: IO_GUESS_DIMIDS_NC4 + use mode_io_tools_nc4, only: io_guess_dimids_nc4 TYPE(TFILE_ELT),DIMENSION(:), INTENT(IN) :: infiles TYPE(TFILE_ELT),DIMENSION(:), INTENT(IN) :: outfiles @@ -620,7 +620,7 @@ END DO SUBROUTINE def_ncdf(infiles,outfiles,KNFILES_OUT) USE MODD_CONF, ONLY: NMNHVERSION - USE MODE_NETCDF, ONLY: IO_WRITE_HEADER_NC4 + use mode_io_write_nc4, only: io_write_header_nc4 TYPE(TFILE_ELT),DIMENSION(:),INTENT(IN) :: infiles TYPE(TFILE_ELT),DIMENSION(:),INTENT(IN) :: outfiles @@ -1263,8 +1263,8 @@ END DO SUBROUTINE IO_FILL_DIMS_NC4(TPFILE,TPREC,KRESP) - USE MODD_IO_ll, ONLY: TFILEDATA - USE MODE_NETCDF, ONLY: GETDIMCDF, IO_FIND_DIM_BYNAME_NC4 + USE MODD_IO_ll, ONLY: TFILEDATA + use mode_io_tools_nc4, only: getdimcdf, io_find_dim_byname_nc4 TYPE(TFILEDATA),INTENT(IN) :: TPFILE TYPE(workfield),INTENT(INOUT) :: TPREC diff --git a/src/LIB/SURCOUCHE/src/fmread_ll.f90 b/src/LIB/SURCOUCHE/src/fmread_ll.f90 index 9a9a10420..047a96080 100644 --- a/src/LIB/SURCOUCHE/src/fmread_ll.f90 +++ b/src/LIB/SURCOUCHE/src/fmread_ll.f90 @@ -25,7 +25,7 @@ USE MODD_MPIF ! USE MODE_FIELD #if defined(MNH_IOCDF4) -USE MODE_NETCDF +USE MODE_IO_READ_NC4 #endif USE MODE_MSG USE MODE_READWRITE_LFI @@ -499,7 +499,7 @@ USE MODE_ALLOCBUFFER_ll #ifdef MNH_GA USE MODE_GA #endif -USE MODE_IO_ll, ONLY : IO_FILE +USE MODE_IO_TOOLS, ONLY : IO_FILE USE MODE_IO_MANAGE_STRUCT, ONLY : IO_FILE_FIND_BYNAME USE MODE_MNH_TIMING, ONLY : SECOND_MNH2 USE MODE_SCATTER_ll diff --git a/src/LIB/SURCOUCHE/src/fmwrit_ll.f90 b/src/LIB/SURCOUCHE/src/fmwrit_ll.f90 index 3c96575e5..d679b4915 100644 --- a/src/LIB/SURCOUCHE/src/fmwrit_ll.f90 +++ b/src/LIB/SURCOUCHE/src/fmwrit_ll.f90 @@ -166,7 +166,7 @@ MODULE MODE_FMWRIT USE MODE_FIELD #if defined(MNH_IOCDF4) - USE MODE_NETCDF + USE MODE_IO_WRITE_NC4 #endif USE MODE_READWRITE_LFI @@ -795,7 +795,7 @@ CONTAINS ! USE MODE_ALLOCBUFFER_ll USE MODE_GATHER_ll - USE MODE_IO_ll, ONLY : IO_FILE + USE MODE_IO_TOOLS, ONLY : IO_FILE USE MODE_IO_MANAGE_STRUCT, ONLY : IO_FILE_FIND_BYNAME USE MODE_MNH_TIMING, ONLY : SECOND_MNH2 #ifdef MNH_GA @@ -1150,7 +1150,7 @@ CONTAINS ! USE MODE_ALLOCBUFFER_ll USE MODE_GATHER_ll - USE MODE_IO_ll, ONLY : IO_FILE,IO_RANK + USE MODE_IO_TOOLS, ONLY : IO_FILE,IO_RANK USE MODE_MNH_TIMING, ONLY : SECOND_MNH2 USE MODD_VAR_ll, ONLY : MNH_STATUSES_IGNORE ! @@ -1288,7 +1288,7 @@ CONTAINS ! USE MODE_ALLOCBUFFER_ll USE MODE_GATHER_ll - USE MODE_IO_ll, ONLY : IO_FILE,IO_RANK + USE MODE_IO_TOOLS, ONLY : IO_FILE,IO_RANK USE MODE_MNH_TIMING, ONLY : SECOND_MNH2 USE MODD_VAR_ll, ONLY : MNH_STATUSES_IGNORE ! @@ -1426,7 +1426,7 @@ CONTAINS ! USE MODE_ALLOCBUFFER_ll USE MODE_GATHER_ll - USE MODE_IO_ll, ONLY : IO_FILE,IO_RANK + USE MODE_IO_TOOLS, ONLY : IO_FILE,IO_RANK USE MODE_MNH_TIMING, ONLY : SECOND_MNH2 USE MODD_VAR_ll, ONLY : MNH_STATUSES_IGNORE ! diff --git a/src/LIB/SURCOUCHE/src/mode_fm.f90 b/src/LIB/SURCOUCHE/src/mode_fm.f90 index 1c1a1813d..3f65f8482 100644 --- a/src/LIB/SURCOUCHE/src/mode_fm.f90 +++ b/src/LIB/SURCOUCHE/src/mode_fm.f90 @@ -8,6 +8,7 @@ ! P. Wautelet : may 2016: use NetCDF Fortran module ! Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O ! Philippe Wautelet: 29/10/2018: better detection of older MNH version numbers +! Philippe Wautelet: 13/12/2018: moved some operations to new mode_io_*_nc4 modules !----------------------------------------------------------------- MODULE MODE_FM @@ -45,9 +46,8 @@ END SUBROUTINE SET_FMPACK_ll SUBROUTINE IO_FILE_OPEN_ll(TPFILE,KRESP,OPARALLELIO,HPOSITION,HSTATUS,HPROGRAM_ORIG) ! -USE MODD_CONF, ONLY: CPROGRAM, NMNHVERSION +USE MODD_CONF, ONLY: CPROGRAM USE MODD_IO_ll, ONLY: TFILEDATA -USE MODE_FIELD, ONLY: TFIELDDATA,TYPEINT USE MODE_FMREAD USE MODE_IO_ll, ONLY : OPEN_ll USE MODE_IO_MANAGE_STRUCT, ONLY: IO_FILE_ADD2LIST,IO_FILE_FIND_BYNAME @@ -59,11 +59,7 @@ CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: HPOSITION CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: HSTATUS CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: HPROGRAM_ORIG !To emulate a file coming from this program ! -INTEGER :: IRESP,IRESP2 -INTEGER :: IMASDEV,IBUGFIX -INTEGER,DIMENSION(3) :: IMNHVERSION -CHARACTER(LEN=12) :: YMNHVERSION_FILE,YMNHVERSION_CURR -TYPE(TFIELDDATA) :: TZFIELD +INTEGER :: IRESP TYPE(TFILEDATA),POINTER :: TZFILE_DES TYPE(TFILEDATA),POINTER :: TZFILE_DUMMY ! @@ -152,91 +148,23 @@ SELECT CASE(TPFILE%CTYPE) ENDIF ! CALL FMOPEN_ll(TPFILE,IRESP,OPARALLELIO=OPARALLELIO,HPROGRAM_ORIG=HPROGRAM_ORIG) - ! - !Compare MNHVERSION of file with current version and store it in file metadata - IF (TRIM(TPFILE%CMODE) == 'READ') THEN - IMNHVERSION(:) = 0 - !Use TZFIELD because TFIELDLIST could be not initialised - TZFIELD%CMNHNAME = 'MNHVERSION' - TZFIELD%CSTDNAME = '' - TZFIELD%CLONGNAME = 'MesoNH version' - TZFIELD%CUNITS = '' - TZFIELD%CDIR = '--' - TZFIELD%CCOMMENT = '' - TZFIELD%NGRID = 0 - TZFIELD%NTYPE = TYPEINT - TZFIELD%NDIMS = 1 - TZFIELD%LTIMEDEP = .FALSE. - CALL IO_READ_FIELD(TPFILE,TZFIELD,IMNHVERSION,IRESP2) - IF (IRESP2/=0) THEN - TZFIELD%CMNHNAME = 'MASDEV' - TZFIELD%CLONGNAME = 'MesoNH version (without bugfix)' - TZFIELD%NDIMS = 0 - CALL IO_READ_FIELD(TPFILE,TZFIELD,IMASDEV,IRESP2) - IF (IRESP2/=0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FILE_OPEN_ll','unknown MASDEV version for '//TRIM(TPFILE%CNAME)) - ELSE - IF (IMASDEV<100) THEN - IMNHVERSION(1)=IMASDEV/10 - IMNHVERSION(2)=MOD(IMASDEV,10) - ELSE !for example for MNH 4.10 - IMNHVERSION(1)=IMASDEV/100 - IMNHVERSION(2)=MOD(IMASDEV,100) - END IF - END IF - ! - TZFIELD%CMNHNAME = 'BUGFIX' - TZFIELD%CLONGNAME = 'MesoNH bugfix number' - CALL IO_READ_FIELD(TPFILE,TZFIELD,IBUGFIX,IRESP2) - IF (IRESP2/=0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FILE_OPEN_ll','unknown BUGFIX version for '//TRIM(TPFILE%CNAME)) - ELSE - IMNHVERSION(3)=IBUGFIX - END IF - END IF - ! - WRITE(YMNHVERSION_FILE,"( I0,'.',I0,'.',I0 )" ) IMNHVERSION(1),IMNHVERSION(2),IMNHVERSION(3) - WRITE(YMNHVERSION_CURR,"( I0,'.',I0,'.',I0 )" ) NMNHVERSION(1),NMNHVERSION(2),NMNHVERSION(3) - ! - IF ( IMNHVERSION(1)==0 .AND. IMNHVERSION(2)==0 .AND. IMNHVERSION(3)==0 ) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FILE_OPEN_ll','file '//TRIM(TPFILE%CNAME)//& - ' was written with an unknown version of MesoNH') - ELSE IF ( IMNHVERSION(1)< NMNHVERSION(1) .OR. & - (IMNHVERSION(1)==NMNHVERSION(1) .AND. IMNHVERSION(2)< NMNHVERSION(2)) .OR. & - (IMNHVERSION(1)==NMNHVERSION(1) .AND. IMNHVERSION(2)==NMNHVERSION(2) .AND. IMNHVERSION(3)<NMNHVERSION(3)) ) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FILE_OPEN_ll','file '//TRIM(TPFILE%CNAME)//& - ' was written with an older version of MesoNH ('//TRIM(YMNHVERSION_FILE)//& - ' instead of '//TRIM(YMNHVERSION_CURR)//')') - ELSE IF ( IMNHVERSION(1)> NMNHVERSION(1) .OR. & - (IMNHVERSION(1)==NMNHVERSION(1) .AND. IMNHVERSION(2)> NMNHVERSION(2)) .OR. & - (IMNHVERSION(1)==NMNHVERSION(1) .AND. IMNHVERSION(2)==NMNHVERSION(2) .AND. IMNHVERSION(3)>NMNHVERSION(3)) ) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FILE_OPEN_ll','file '//TRIM(TPFILE%CNAME)//& - ' was written with a more recent version of MesoNH ('//TRIM(YMNHVERSION_FILE)//& - ' instead of '//TRIM(YMNHVERSION_CURR)//')') - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_FILE_OPEN_ll','file '//TRIM(TPFILE%CNAME)//& - ' was written with the same version of MesoNH ('//TRIM(YMNHVERSION_CURR)//')') - END IF - ! - TPFILE%NMNHVERSION(:) = IMNHVERSION(:) - END IF + END SELECT ! -IF (TRIM(TPFILE%CMODE) == 'WRITE') TPFILE%NMNHVERSION(:) = NMNHVERSION(:) -! IF (PRESENT(KRESP)) KRESP = IRESP ! END SUBROUTINE IO_FILE_OPEN_ll SUBROUTINE FMOPEN_ll(TPFILE,KRESP,OPARALLELIO,HPROGRAM_ORIG) -USE MODD_IO_ll, ONLY : ISTDOUT,TFILEDATA -USE MODE_IO_ll, ONLY : OPEN_ll,GCONFIO,IOFREEFLU,IONEWFLU +USE MODD_IO_ll, ONLY: ISTDOUT,TFILEDATA +USE MODE_IO_ll, ONLY: OPEN_ll,GCONFIO,IOFREEFLU,IONEWFLU +use mode_io_tools, only: io_get_mnhversion,io_set_mnhversion !JUANZ USE MODD_CONFZ,ONLY : NB_PROCIO_R,NB_PROCIO_W !JUANZ #if defined(MNH_IOCDF4) USE MODD_NETCDF, ONLY:IDCDF_KIND -USE MODE_NETCDF +use mode_io_file_nc4, only: io_create_file_nc4, io_open_file_nc4 #endif TYPE(TFILEDATA), INTENT(INOUT) :: TPFILE ! File structure INTEGER, INTENT(OUT) :: KRESP ! return-code @@ -263,9 +191,6 @@ INTEGER :: INB_PROCIO !JUAN LOGICAL :: GPARALLELIO LOGICAL :: GEXIST_LFI, GEXIST_NC4 -#if defined(MNH_IOCDF4) -INTEGER(KIND=IDCDF_KIND) :: INCERR -#endif YACTION = TPFILE%CMODE @@ -382,37 +307,22 @@ IF (TPFILE%LMASTER) THEN END IF END SELECT END IF +END IF #if defined(MNH_IOCDF4) - IF (TPFILE%CFORMAT=='NETCDF4' .OR. TPFILE%CFORMAT=='LFICDF4') THEN - IF (YACTION == 'READ') THEN - !! Open NetCDF File for reading - TPFILE%TNCDIMS => NEWIOCDF() - CALL PRINT_MSG(NVERB_DEBUG,'IO','FMOPEN_ll','NF90_OPEN for '//TRIM(YFILEM)//'.nc') - INCERR = NF90_OPEN(ADJUSTL(TRIM(YFILEM))//".nc", NF90_NOWRITE, TPFILE%NNCID) - IF (INCERR /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','FMOPEN_ll','NF90_OPEN for '//TRIM(YFILEM)//'.nc: '//NF90_STRERROR(INCERR)) - END IF - INCERR = NF90_INQUIRE(TPFILE%NNCID,NVARIABLES=TPFILE%NNCNAR) - IF (INCERR /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','FMOPEN_ll','NF90_INQUIRE for '//TRIM(YFILEM)//'.nc: '//NF90_STRERROR(INCERR)) - END IF - END IF - - IF (YACTION == 'WRITE') THEN - TPFILE%TNCDIMS => NEWIOCDF() - CALL PRINT_MSG(NVERB_DEBUG,'IO','FMOPEN_ll','NF90_CREATE for '//TRIM(YFILEM)//'.nc') - INCERR = NF90_CREATE(ADJUSTL(TRIM(YFILEM))//".nc", & - &IOR(NF90_CLOBBER,NF90_NETCDF4), TPFILE%NNCID) - IF (INCERR /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','FMOPEN_ll','NF90_CREATE for '//TRIM(YFILEM)//'.nc: '//NF90_STRERROR(INCERR)) - END IF - CALL IO_SET_KNOWNDIMS_NC4(TPFILE,HPROGRAM_ORIG=HPROGRAM_ORIG) - END IF - END IF +IF (TPFILE%CFORMAT=='NETCDF4' .OR. TPFILE%CFORMAT=='LFICDF4') THEN + IF (YACTION == 'READ') THEN + call io_open_file_nc4(tpfile) + END IF + + IF (YACTION == 'WRITE') THEN + call io_create_file_nc4(TPFILE, hprogram_orig=HPROGRAM_ORIG) + END IF +END IF #endif - - IF (TPFILE%CFORMAT=='LFI' .OR. TPFILE%CFORMAT=='LFICDF4') THEN + +IF (TPFILE%CFORMAT=='LFI' .OR. TPFILE%CFORMAT=='LFICDF4') THEN + IF (TPFILE%LMASTER) THEN ! LFI Case IRESOU = 0 GNAMFI = .TRUE. @@ -441,19 +351,23 @@ IF (TPFILE%LMASTER) THEN INPRAR, & ININAR) TPFILE%NLFININAR = ININAR - IF (IRESOU /= 0 ) THEN + IF (IRESOU /= 0 ) THEN IRESP = IRESOU ENDIF + ! + !* 6. TEST IF FILE IS NEWLY DEFINED + ! + GNEWFI=(ININAR==0).OR.(IMELEV<2) + IF (.NOT.GNEWFI) THEN + WRITE (ISTDOUT,*) ' file ',TRIM(YFILEM)//'.lfi',' previously created with LFI' + ENDIF END IF - - ! - !* 6. TEST IF FILE IS NEWLY DEFINED - ! - - GNEWFI=(ININAR==0).OR.(IMELEV<2) - IF (.NOT.GNEWFI) THEN - WRITE (ISTDOUT,*) ' file ',TRIM(YFILEM)//'.lfi',' previously created with LFI' - ENDIF + SELECT CASE (YACTION) + CASE('READ') + call io_get_mnhversion(tpfile) + CASE('WRITE') + call io_set_mnhversion(tpfile) + END SELECT END IF ! Broadcast ERROR @@ -625,7 +539,8 @@ USE MODE_IO_ll, ONLY : CLOSE_ll,UPCASE USE MODI_SYSTEM_MNH #endif #if defined(MNH_IOCDF4) -USE MODE_NETCDF + use mode_io_file_nc4, only: io_close_file_nc4 + use mode_io_write_nc4, only: io_write_coordvar_nc4 #endif TYPE(TFILEDATA), INTENT(IN) :: TPFILE ! File structure CHARACTER(LEN=*), INTENT(IN) :: HSTATU ! status for the closed file @@ -693,11 +608,7 @@ IF (TPFILE%LMASTER) THEN #if defined(MNH_IOCDF4) IF (TPFILE%NNCID/=-1) THEN ! Close Netcdf File - IRESP = NF90_CLOSE(TPFILE%NNCID) - IF (IRESP /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','FMCLOS_ll','NF90_CLOSE error: '//TRIM(NF90_STRERROR(IRESP))) - END IF - IF (ASSOCIATED(TPFILE%TNCDIMS)) CALL CLEANIOCDF(TPFILE%TNCDIMS) + call io_close_file_nc4(tpfile,iresp) END IF #endif IF (IRESP == 0 .AND. CPROGRAM/='LFICDF') THEN diff --git a/src/LIB/SURCOUCHE/src/mode_io.f90 b/src/LIB/SURCOUCHE/src/mode_io.f90 index 8c2277c3c..94a226353 100644 --- a/src/LIB/SURCOUCHE/src/mode_io.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io.f90 @@ -1,6 +1,6 @@ !MNH_LIC Copyright 1994-2018 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 version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt !MNH_LIC for details. version 1. !----------------------------------------------------------------- !! Authors @@ -13,10 +13,11 @@ ! J.Escobar 18/10/10 bug with PGI compiler on ADJUSTL ! P. Wautelet 04/02/2016: bug with DELIM='NONE' and GCC 5.2/5.3 ! D.Gazen : avril 2016 change error message -! P. Wautelet : may 2016: use NetCDF Fortran module +! P. Wautelet : may 2016: use netCDF Fortran module ! P. Wautelet : July 2016: added type OUTBAK ! Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O ! J. Pianezze 01/08/2016 add LOASIS flag +! Philippe Wautelet: 13/12/2018: moved some operations to new mode_io_*_nc4 modules ! MODULE MODE_IO_ll @@ -42,7 +43,6 @@ MODULE MODE_IO_ll PUBLIC IOFREEFLU,IONEWFLU,UPCASE,INITIO_ll,OPEN_ll,CLOSE_ll PUBLIC SET_CONFIO_ll,GCONFIO - PUBLIC io_file,IO_RANK CONTAINS @@ -72,9 +72,9 @@ CONTAINS END FUNCTION IONEWFLU SUBROUTINE IOFREEFLU(KOFLU) - + INTEGER :: KOFLU - + IF ((KOFLU .GE. JPRESERVED_UNIT) .AND. (KOFLU .LE. JPMAX_UNIT_NUMBER )) THEN GALLOC(KOFLU) = .FALSE. ELSE @@ -204,11 +204,13 @@ CONTAINS HPROGRAM_ORIG) #if defined(MNH_IOCDF4) - USE MODD_NETCDF, ONLY:IDCDF_KIND - USE MODE_NETCDF + USE MODD_NETCDF, ONLY:IDCDF_KIND + use mode_io_file_nc4, only: io_create_file_nc4, io_open_file_nc4 #endif USE MODD_IO_ll + USE MODE_IO_MANAGE_STRUCT, ONLY: IO_FILE_ADD2LIST, IO_FILE_FIND_BYNAME + use mode_io_tools, only: io_rank, io_get_mnhversion,io_set_mnhversion TYPE(TFILEDATA), INTENT(INOUT) :: TPFILE CHARACTER(len=*),INTENT(IN), OPTIONAL :: MODE @@ -253,7 +255,6 @@ CONTAINS CHARACTER(len=20) :: YMODE CHARACTER(LEN=256) :: YIOERRMSG INTEGER :: IOS,IERR,IRESP - INTEGER(KIND=IDCDF_KIND) :: IOSCDF INTEGER :: ICOMM INTEGER :: ICMPRES ! didier @@ -638,7 +639,7 @@ CONTAINS #endif TPFILE%NLFIFLU = IONEWFLU() ELSE - !! NON I/O processors OR NetCDF read case + !! NON I/O processors OR netCDF read case IOS = 0 TPFILE%NLFIFLU = -1 END IF @@ -686,45 +687,23 @@ CONTAINS TZSPLITFILE%LMULTIMASTERS = .FALSE. TZSPLITFILE%NSUBFILES_IOZ = 0 - IF ( TZSPLITFILE%LMASTER ) THEN -#if defined(MNH_IOCDF4) - IF (TZSPLITFILE%CFORMAT=='NETCDF4' .OR. TZSPLITFILE%CFORMAT=='LFICDF4') THEN - IF (YACTION == 'READ') THEN - ! Open NetCDF File for reading - TZSPLITFILE%TNCDIMS => NEWIOCDF() - CALL PRINT_MSG(NVERB_DEBUG,'IO','OPEN_ll','NF90_OPEN(IO_ZSPLIT) for '//TRIM(TZSPLITFILE%CNAME)//'.nc') - IOSCDF = NF90_OPEN(TRIM(YPREFILENAME)//".nc", NF90_NOWRITE, TZSPLITFILE%NNCID) - IF (IOSCDF /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','OPEN_ll','NF90_OPEN for '//TRIM(TZSPLITFILE%CNAME)//'.nc: '// & - NF90_STRERROR(IOSCDF)) - ELSE - IOS = 0 - END IF - IOSCDF = NF90_INQUIRE(TZSPLITFILE%NNCID,NVARIABLES=TZSPLITFILE%NNCNAR) - IF (IOSCDF /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','OPEN_ll','NF90_INQUIRE for '//TRIM(TZSPLITFILE%CNAME)//'.nc: ' & - //NF90_STRERROR(IOSCDF)) - END IF - END IF - - IF (YACTION == 'WRITE') THEN - ! YACTION == 'WRITE' - ! Create NetCDF File for writing - TZSPLITFILE%TNCDIMS => NEWIOCDF() - CALL PRINT_MSG(NVERB_DEBUG,'IO','OPEN_ll','NF90_CREATE(IO_ZSPLIT) for '//TRIM(TZSPLITFILE%CNAME)//'.nc') - IOSCDF = NF90_CREATE(TRIM(YPREFILENAME)//".nc", & - &IOR(NF90_CLOBBER,NF90_NETCDF4), TZSPLITFILE%NNCID) - IF (IOSCDF /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','OPEN_ll','NF90_CREATE for '//TRIM(TZSPLITFILE%CNAME)//'.nc: '// & - NF90_STRERROR(IOSCDF)) - ELSE - IOS = 0 - END IF - CALL IO_SET_KNOWNDIMS_NC4(TZSPLITFILE,HPROGRAM_ORIG=HPROGRAM_ORIG) - END IF +#if defined(MNH_IOCDF4) + IF (TZSPLITFILE%CFORMAT=='NETCDF4' .OR. TZSPLITFILE%CFORMAT=='LFICDF4') THEN + IF (YACTION == 'READ') THEN + ! Open netCDF File for reading + call io_open_file_nc4(tzsplitfile) + IOS = 0 + END IF + + IF (YACTION == 'WRITE') THEN + ! Create netCDF File for writing + call io_create_file_nc4(TZSPLITFILE, hprogram_orig=HPROGRAM_ORIG) + IOS = 0 END IF + END IF #endif - IF (TZSPLITFILE%CFORMAT=='LFI' .OR. TZSPLITFILE%CFORMAT=='LFICDF4') THEN + IF (TZSPLITFILE%CFORMAT=='LFI' .OR. TZSPLITFILE%CFORMAT=='LFICDF4') THEN + IF ( TZSPLITFILE%LMASTER ) THEN ! LFI case ! Open LFI File for reading !this proc must write on this file open it ... @@ -762,6 +741,13 @@ CONTAINS ININAR8) TZSPLITFILE%NLFININAR = ININAR8 END IF + ! + SELECT CASE (YACTION) + CASE('READ') + call io_get_mnhversion(tpfile) + CASE('WRITE') + call io_set_mnhversion(tpfile) + END SELECT ENDIF ! TZSPLITFILE%LOPENED = .TRUE. @@ -794,7 +780,8 @@ CONTAINS USE MODD_IO_ll USE MODE_IO_MANAGE_STRUCT, ONLY: IO_FILE_FIND_BYNAME #if defined(MNH_IOCDF4) - USE MODE_NETCDF + use mode_io_file_nc4, only: io_close_file_nc4 + use mode_io_write_nc4, only: io_write_coordvar_nc4 #endif TYPE(TFILEDATA), INTENT(IN) :: TPFILE INTEGER, INTENT(OUT), OPTIONAL :: IOSTAT @@ -841,7 +828,7 @@ CONTAINS DO IFILE=1,TPFILE%NSUBFILES_IOZ TZFILE => TPFILE%TFILES_IOZ(IFILE)%TFILE #if defined(MNH_IOCDF4) - !Write coordinates variables in NetCDF file + !Write coordinates variables in netCDF file IF (TZFILE%CMODE == 'WRITE' .AND. (TZFILE%CFORMAT=='NETCDF4' .OR. TZFILE%CFORMAT=='LFICDF4')) THEN CALL IO_WRITE_COORDVAR_NC4(TZFILE,HPROGRAM_ORIG=HPROGRAM_ORIG) END IF @@ -855,11 +842,7 @@ CONTAINS #if defined(MNH_IOCDF4) IF (TZFILE%NNCID/=-1) THEN ! Close Netcdf File - IRESP = NF90_CLOSE(TZFILE%NNCID) - IF (IRESP /= NF90_NOERR) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','CLOSE_ll','NF90_CLOSE error: '//TRIM(NF90_STRERROR(IRESP))) - END IF - IF (ASSOCIATED(TZFILE%TNCDIMS)) CALL CLEANIOCDF(TZFILE%TNCDIMS) + call io_close_file_nc4(tzfile) END IF #endif END IF @@ -879,49 +862,6 @@ CONTAINS END IF END SUBROUTINE CLOSE_ll - - FUNCTION io_file(k,nb_proc_io) - ! - ! return the file number where to write the K level of data - ! - IMPLICIT NONE - INTEGER(kind=MNH_MPI_RANK_KIND) :: k,nb_proc_io - INTEGER(kind=MNH_MPI_RANK_KIND) :: io_file - - io_file = MOD ((k-1) , nb_proc_io ) - - END FUNCTION io_file - - FUNCTION IO_RANK(IFILE,nb_proc,nb_proc_io,offset_rank) - ! - ! return the proc number which must write the 'IFILE' file - ! - IMPLICIT NONE - INTEGER(kind=MNH_MPI_RANK_KIND) :: IFILE,nb_proc,nb_proc_io - INTEGER(kind=MNH_MPI_RANK_KIND),OPTIONAL :: offset_rank - - INTEGER(kind=MNH_MPI_RANK_KIND) :: IO_RANK - - INTEGER(kind=MNH_MPI_RANK_KIND) :: ipas,irest - - ipas = nb_proc / nb_proc_io - irest = MOD ( nb_proc , nb_proc_io ) - - IF (ipas /= 0 ) THEN - IO_RANK=ipas * IFILE + MIN(IFILE , irest ) - ELSE - IO_RANK=MOD(IFILE , nb_proc ) - ENDIF - - ! - ! optional rank to shift for read test - ! - IF (PRESENT(offset_rank)) THEN - IF ( offset_rank .GT.0 ) IO_RANK=MOD(IO_RANK+offset_rank,nb_proc) - IF ( offset_rank .LT.0 ) IO_RANK=MOD(nb_proc-IO_RANK+offset_rank,nb_proc) - ENDIF - - END FUNCTION IO_RANK ! ! END MODULE MODE_IO_ll diff --git a/src/LIB/SURCOUCHE/src/mode_io_file_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_file_nc4.f90 new file mode 100644 index 000000000..f12b09bbf --- /dev/null +++ b/src/LIB/SURCOUCHE/src/mode_io_file_nc4.f90 @@ -0,0 +1,223 @@ +!MNH_LIC Copyright 2018-2018 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. +!----------------------------------------------------------------- +! Author: P. Wautelet 13/12/2018 +! +! Remarks: some of the code comes from mode_fm.f90 and mode_io.f90 +! (was duplicated in the 2 files) +! +! Modifications: +! +!----------------------------------------------------------------- +#if defined(MNH_IOCDF4) +module mode_io_file_nc4 + +use modd_io_ll, only: tfiledata +use modd_netcdf, only: idcdf_kind + +use mode_io_tools_nc4, only: handle_err, io_set_knowndims_nc4, newiocdf +use mode_msg + +use NETCDF, only: NF90_CLOBBER, NF90_GLOBAL, NF90_NETCDF4, NF90_NOERR, NF90_NOWRITE, & + NF90_CLOSE, NF90_CREATE, NF90_GET_ATT, NF90_INQUIRE, NF90_INQUIRE_ATTRIBUTE, & + NF90_OPEN, NF90_PUT_ATT, NF90_STRERROR + +implicit none + +private + +public :: io_create_file_nc4, io_close_file_nc4, io_open_file_nc4 + +contains + +subroutine io_create_file_nc4(tpfile,hprogram_orig) + use mode_io_tools, only: io_set_mnhversion + + type(tfiledata), intent(inout) :: tpfile + character(len=*),optional, intent(in) :: hprogram_orig !to emulate a file coming from this program + + character(len=:),allocatable :: yfilem ! name of the file + integer(kind=idcdf_kind) :: istatus + + if (tpfile%lmaster) then + if (allocated(tpfile%cdirname)) then + if(len_trim(tpfile%cdirname)>0) then + yfilem = trim(tpfile%cdirname)//'/'//trim(tpfile%cname) + else + yfilem = trim(tpfile%cname) + end if + else + yfilem = trim(tpfile%cname) + end if + + tpfile%tncdims => newiocdf() + call print_msg(NVERB_DEBUG, 'IO', 'io_create_file_nc4', 'NF90_CREATE for '//trim(yfilem)//'.nc') + istatus = NF90_CREATE(adjustl(trim(yfilem))//".nc", ior(NF90_CLOBBER,NF90_NETCDF4), tpfile%nncid) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_FATAL,'IO','io_create_file_nc4','NF90_CREATE for '//trim(yfilem)//'.nc: '//NF90_STRERROR(istatus)) + end if + call io_set_not_cleanly_closed_nc4(tpfile) + call io_set_mnhversion(tpfile) + call io_set_knowndims_nc4(tpfile, hprogram_orig=hprogram_orig) + end if +end subroutine io_create_file_nc4 + + +subroutine io_close_file_nc4(tpfile,kstatus) + use mode_io_tools_nc4, only: cleaniocdf + + type(tfiledata), intent(in) :: tpfile + integer(kind=idcdf_kind), optional, intent(out) :: kstatus + + integer(kind=idcdf_kind) :: istatus + + call print_msg(NVERB_DEBUG,'IO','io_close_file_nc4','called for '//trim(tpfile%cname)) + + istatus = 0 + + if (tpfile%lmaster) then + if (trim(tpfile%cmode) == 'WRITE') call io_set_cleanly_closed_nc4(tpfile) + istatus = NF90_CLOSE(tpfile%nncid) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_WARNING, 'IO', 'io_close_file_nc4', 'NF90_CLOSE error: '//trim(NF90_STRERROR(istatus))) + end if + if (associated(tpfile%tncdims)) call cleaniocdf(tpfile%tncdims) + end if + + if (present(kstatus)) kstatus = istatus +end subroutine io_close_file_nc4 + + +subroutine io_open_file_nc4(tpfile) + use mode_io_tools, only: io_get_mnhversion + + type(tfiledata), intent(inout) :: tpfile + + character(len=:),allocatable :: yfilem ! name of the file + integer(kind=idcdf_kind) :: istatus + + if (tpfile%lmaster) then + if (allocated(tpfile%cdirname)) then + if(len_trim(tpfile%cdirname)>0) then + yfilem = trim(tpfile%cdirname)//'/'//trim(tpfile%cname) + else + yfilem = trim(tpfile%cname) + end if + else + yfilem = trim(tpfile%cname) + end if + + tpfile%tncdims => newiocdf() + call print_msg(NVERB_DEBUG,'IO','io_open_file_nc4','NF90_OPEN for '//trim(yfilem)//'.nc') + istatus = NF90_OPEN(adjustl(trim(yfilem))//".nc", NF90_NOWRITE, tpfile%nncid) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_FATAL, 'IO', 'io_open_file_nc4', 'NF90_OPEN for '//trim(yfilem)//'.nc: '//NF90_STRERROR(istatus)) + end if + + istatus = NF90_INQUIRE(tpfile%nncid, nvariables=tpfile%nncnar) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_FATAL,'IO','io_open_file_nc4','NF90_INQUIRE for '//trim(yfilem)//'.nc: '//NF90_STRERROR(istatus)) + end if + end if + + if (trim(tpfile%cmode) == 'READ') then + call io_get_mnhversion(tpfile) + if (tpfile%lmaster) call io_check_cleanly_closed_nc4(tpfile) + end if + +end subroutine io_open_file_nc4 + + +subroutine io_check_cleanly_closed_nc4(tpfile) + type(tfiledata), intent(in) :: tpfile + + character(len=:), allocatable :: yclean + integer(kind=IDCDF_KIND) :: ilen, istatus + integer, dimension(3) :: imnhversion + + call print_msg(NVERB_DEBUG,'IO','io_check_cleanly_closed_nc4','called for '//trim(tpfile%cname)) + + imnhversion = tpfile%nmnhversion + if ( imnhversion(1)<5 .OR. & + (imnhversion(1)==5 .AND. imnhversion(2)<4) .OR. & + (imnhversion(1)==5 .AND. imnhversion(2)==4 .AND. imnhversion(3)<2) ) then + call print_msg(NVERB_DEBUG,'IO','io_check_cleanly_closed_nc4', & + 'file '//trim(tpfile%cname)//' is too old (before MNH 5.4.2) to check if cleanly closed') + return + end if + + istatus = NF90_INQUIRE_ATTRIBUTE(tpfile%nncid, NF90_GLOBAL, 'MNH_cleanly_closed', len = ilen) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_ERROR,'IO','io_check_cleanly_closed_nc4', & + 'MNH_cleanly_closed attribute not found in file '//trim(tpfile%cname)) + else + allocate( character(len=ilen) :: yclean ) + istatus = NF90_GET_ATT(tpfile%nncid, NF90_GLOBAL, 'MNH_cleanly_closed', yclean) + if (istatus /= NF90_NOERR) then + call print_msg(NVERB_WARNING,'IO','io_check_cleanly_closed_nc4', & + 'MNH_cleanly_closed attribute not found in file '//trim(tpfile%cname)) + else + if (yclean == 'yes') then + call print_msg(NVERB_DEBUG,'IO','io_check_cleanly_closed_nc4', & + 'file '//trim(tpfile%cname)//' was cleanly closed before opening') + else if (yclean == 'no') then + call print_msg(NVERB_ERROR,'IO','io_check_cleanly_closed_nc4', & + 'file '//trim(tpfile%cname)//' was not cleanly closed before opening') + else + call print_msg(NVERB_ERROR,'IO','io_check_cleanly_closed_nc4', & + 'invalid MNH_cleanly_closed attribute for file '//trim(tpfile%cname)) + end if + end if + end if +end subroutine io_check_cleanly_closed_nc4 + + +subroutine io_set_cleanly_closed_nc4(tpfile) + type(tfiledata), intent(in) :: tpfile + + integer(kind=IDCDF_KIND) :: istatus + + call print_msg(NVERB_DEBUG,'IO','io_set_cleanly_closed_nc4','called for '//trim(tpfile%cname)) + + istatus = NF90_PUT_ATT(tpfile%nncid, NF90_GLOBAL, 'MNH_cleanly_closed', 'yes') + if (istatus /= NF90_NOERR) call handle_err(istatus,__LINE__,'io_set_cleanly_closed_nc4[NF90_PUT_ATT]') +end subroutine io_set_cleanly_closed_nc4 + + +subroutine io_set_not_cleanly_closed_nc4(tpfile) + type(tfiledata), intent(in) :: tpfile + + integer(kind=IDCDF_KIND) :: istatus + + call print_msg(NVERB_DEBUG,'IO','io_set_not_cleanly_closed_nc4','called for '//trim(tpfile%cname)) + + istatus = NF90_PUT_ATT(tpfile%nncid, NF90_GLOBAL, 'MNH_cleanly_closed', 'no') + if (istatus /= NF90_NOERR) call handle_err(istatus,__LINE__,'io_set_not_cleanly_closed_nc4[NF90_PUT_ATT]') +end subroutine io_set_not_cleanly_closed_nc4 + +end module mode_io_file_nc4 +#else +! +! External dummy subroutines +! +subroutine io_create_file_nc4(a, b) +use mode_msg +integer :: a, b +CALL PRINT_MSG(NVERB_ERROR,'IO','io_create_file_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_create_file_nc4 +! +subroutine io_close_file_nc4(a) +use mode_msg +integer :: a +CALL PRINT_MSG(NVERB_ERROR,'IO','io_close_file_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_close_file_nc4 +! +subroutine io_open_file_nc4(a) +use mode_msg +integer :: a +CALL PRINT_MSG(NVERB_ERROR,'IO','io_open_file_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_open_file_nc4 +! +#endif diff --git a/src/LIB/SURCOUCHE/src/mode_io_read_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_read_nc4.f90 new file mode 100644 index 000000000..8176017be --- /dev/null +++ b/src/LIB/SURCOUCHE/src/mode_io_read_nc4.f90 @@ -0,0 +1,1272 @@ +!MNH_LIC Copyright 1994-2018 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 : may 2016 : use NetCDF Fortran module +! J.Escobar : 14/12/2017 : Correction for MNH_INT=8 +! Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O +! P. Wautelet : 13/12/2018 : split of mode_netcdf into multiple modules/files +!----------------------------------------------------------------- +#if defined(MNH_IOCDF4) +module mode_io_read_nc4 + +use modd_io_ll, only: tfiledata +use modd_netcdf, only: idcdf_kind + +use mode_field, only: tfielddata +use mode_io_tools_nc4, only: cleanmnhname, handle_err +use mode_msg + +use NETCDF, only: NF90_CHAR, NF90_DOUBLE, NF90_FLOAT, NF90_INT, NF90_INT1, NF90_INT64, & + NF90_MAX_VAR_DIMS, NF90_NOERR, & + NF90_GET_ATT, NF90_GET_VAR, NF90_INQ_VARID, & + NF90_INQUIRE_ATTRIBUTE, NF90_INQUIRE_DIMENSION, NF90_INQUIRE_VARIABLE + +implicit none + +private + +public :: io_read_field_nc4 + +INTERFACE IO_READ_FIELD_NC4 + MODULE PROCEDURE IO_READ_FIELD_NC4_X0,IO_READ_FIELD_NC4_X1, & + IO_READ_FIELD_NC4_X2,IO_READ_FIELD_NC4_X3, & + IO_READ_FIELD_NC4_X4,IO_READ_FIELD_NC4_X5, & + IO_READ_FIELD_NC4_X6, & + IO_READ_FIELD_NC4_N0,IO_READ_FIELD_NC4_N1, & + IO_READ_FIELD_NC4_N2, & + IO_READ_FIELD_NC4_L0,IO_READ_FIELD_NC4_L1, & + IO_READ_FIELD_NC4_C0, & + IO_READ_FIELD_NC4_T0 +END INTERFACE IO_READ_FIELD_NC4 + +contains + +SUBROUTINE IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,KVARID,KRESP,HCALENDAR) +! +USE MODD_PARAMETERS, ONLY: NGRIDUNKNOWN +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +INTEGER(KIND=IDCDF_KIND), INTENT(IN) :: KVARID +INTEGER, INTENT(OUT) :: KRESP ! return-code +CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HCALENDAR +! +INTEGER :: IERRLEVEL +INTEGER :: ILEN +INTEGER :: IGRID +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: STATUS +CHARACTER(LEN=12) :: YVAL_FILE, YVAL_MEM +CHARACTER(LEN=:),ALLOCATABLE :: YVALUE +LOGICAL :: GOLDMNH !if old version of MesoNH (<5.4, old files without complete and correct metadata) +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)//': called for field '//TRIM(TPFIELD%CMNHNAME)) +! +KRESP = 0 +INCID = TPFILE%NNCID +! +GOLDMNH = TPFILE%NMNHVERSION(1)<5 .OR. (TPFILE%NMNHVERSION(1)==5 .AND. TPFILE%NMNHVERSION(2)<4) +! +IF (GOLDMNH) THEN !Set a lower level of error if file comes from an old MesoNH version + IERRLEVEL = NVERB_WARNING +ELSE + IERRLEVEL = NVERB_ERROR +END IF +! +! GRID +! +STATUS = NF90_GET_ATT(INCID,KVARID,'grid',IGRID) +IF (STATUS /= NF90_NOERR) STATUS = NF90_GET_ATT(INCID,KVARID,'GRID',IGRID) +IF (STATUS == NF90_NOERR) THEN + IF (IGRID/=TPFIELD%NGRID) THEN + WRITE(YVAL_FILE,'(I12)') IGRID + WRITE(YVAL_MEM, '(I12)') TPFIELD%NGRID + CALL PRINT_MSG(IERRLEVEL,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected GRID value ('//TRIM(ADJUSTL(YVAL_MEM))// & + ') is different than found in file ('//TRIM(ADJUSTL(YVAL_FILE))//') for variable '//TRIM(TPFIELD%CMNHNAME)) + IF (.NOT.GOLDMNH) THEN !Do not modify probably incorrect grid number (to prevent problems later with other correct files) + TPFIELD%NGRID = IGRID + KRESP = -111 !Used later to broadcast modified metadata + END IF + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected GRID found in file for field '//TRIM(TPFIELD%CMNHNAME)) + ENDIF +ELSE !no GRID + IF (TPFIELD%NGRID==0 .OR. TPFIELD%NGRID==NGRIDUNKNOWN) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': no GRID (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(IERRLEVEL,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected GRID but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF +ENDIF +! +! COMMENT +! +STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'comment', LEN=ILEN) +IF (STATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) + STATUS = NF90_GET_ATT(INCID, KVARID, 'comment', YVALUE) + IF (LEN_TRIM(TPFIELD%CCOMMENT)==0 .AND. LEN_TRIM(YVALUE)>0) THEN + !Expected comment is empty, read comment is not + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': COMMENT found (unexpected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + TPFIELD%CCOMMENT=TRIM(YVALUE) + ELSE IF (TRIM(YVALUE)/=TRIM(TPFIELD%CCOMMENT)) THEN + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected COMMENT ('//TRIM(TPFIELD%CCOMMENT)// & + ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) + TPFIELD%CCOMMENT=TRIM(YVALUE) + KRESP = -111 !Used later to broadcast modified metadata + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected COMMENT found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF + DEALLOCATE(YVALUE) +ELSE !no COMMENT + IF (LEN_TRIM(TPFIELD%CCOMMENT)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': no COMMENT (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected COMMENT but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF +END IF +! +! STDNAME +! +STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'standard_name', LEN=ILEN) +IF (STATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) + STATUS = NF90_GET_ATT(INCID, KVARID, 'standard_name', YVALUE) + IF (TRIM(YVALUE)/=TRIM(TPFIELD%CSTDNAME)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected STDNAME ('//TRIM(TPFIELD%CSTDNAME)// & + ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) + TPFIELD%CSTDNAME=TRIM(YVALUE) + KRESP = -111 !Used later to broadcast modified metadata + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected STDNAME found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF + DEALLOCATE(YVALUE) +ELSE !no STDNAME + IF (LEN_TRIM(TPFIELD%CSTDNAME)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': no STDNAME (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected STDNAME but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF +END IF +! +! LONGNAME +! +STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'long_name', LEN=ILEN) +IF (STATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) + STATUS = NF90_GET_ATT(INCID, KVARID, 'long_name', YVALUE) + IF (TRIM(YVALUE)/=TRIM(TPFIELD%CLONGNAME)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected LONGNAME ('//TRIM(TPFIELD%CLONGNAME)// & + ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) + TPFIELD%CLONGNAME=TRIM(YVALUE) + KRESP = -111 !Used later to broadcast modified metadata + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected LONGNAME found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF + DEALLOCATE(YVALUE) +ELSE !no LONGNAME + IF (LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': no LONGNAME (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected LONGNAME but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF +END IF +! +! UNITS +! +STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'units', LEN=ILEN) +IF (STATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) + STATUS = NF90_GET_ATT(INCID, KVARID, 'units', YVALUE) + IF (TRIM(YVALUE)/=TRIM(TPFIELD%CUNITS)) THEN + IF(.NOT.PRESENT(HCALENDAR)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected UNITS ('//TRIM(TPFIELD%CUNITS)// & + ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) + KRESP = -111 !Used later to broadcast modified metadata + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': UNITS found in file for field '//TRIM(TPFIELD%CMNHNAME)//' (will be analysed later)') + END IF + TPFIELD%CUNITS=TRIM(YVALUE) + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected UNITS found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF + DEALLOCATE(YVALUE) +ELSE !no UNITS + IF (LEN_TRIM(TPFIELD%CUNITS)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': no UNITS (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + IF(.NOT.PRESENT(HCALENDAR)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected UNITS but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected UNITS but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) + KRESP = -3 + END IF + END IF +END IF +! +! CALENDAR +! +IF(PRESENT(HCALENDAR)) THEN +STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'calendar', LEN=ILEN) +IF (STATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) + STATUS = NF90_GET_ATT(INCID, KVARID, 'calendar', YVALUE) + IF (TRIM(YVALUE)/=TRIM(HCALENDAR)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected CALENDAR ('//TRIM(HCALENDAR)// & + ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) + ELSE + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected CALENDAR found in file for field '//TRIM(TPFIELD%CMNHNAME)) + END IF + DEALLOCATE(YVALUE) +ELSE !no CALENDAR + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & + ': expected CALENDAR but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) +END IF +ENDIF +! +END SUBROUTINE IO_READ_CHECK_FIELD_ATTR_NC4 + + +SUBROUTINE IO_READ_FIELD_NC4_X0(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL, INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 0 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size or type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X0 + + +SUBROUTINE IO_READ_FIELD_NC4_X1(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +CHARACTER(LEN=30) :: YVARNAME +INTEGER(KIND=IDCDF_KIND) :: IDIMLEN +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 1 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN == SIZE(PFIELD)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X1 + + +SUBROUTINE IO_READ_FIELD_NC4_X2(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:,:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +CHARACTER(LEN=30) :: YVARNAME +INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!Treat special case of a degenerated 3D array (3rd dimension size is 1) +IF (IDIMS==3) THEN + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + IF (IDIMLEN(3)==1) THEN + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)// & + ': reading 3D array with degenerated third dimension in 2D array for '//TRIM(YVARNAME)) + IDIMS = 2 + ELSE + CALL PRINT_MSG(NVERB_FATAL,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': wrong number of dimensions for '//TRIM(YVARNAME)) + END IF +END IF + +IF (IDIMS == 2 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X2 + + +SUBROUTINE IO_READ_FIELD_NC4_X3(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:,:,:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 3 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. IDIMLEN(3) == SIZE(PFIELD,3)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X3 + + +SUBROUTINE IO_READ_FIELD_NC4_X4(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:,:,:,:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +INTEGER(KIND=IDCDF_KIND),DIMENSION(4) :: IDIMLEN +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 4 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & + IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X4 + + +SUBROUTINE IO_READ_FIELD_NC4_X5(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:,:,:,:,:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +INTEGER(KIND=IDCDF_KIND),DIMENSION(5) :: IDIMLEN +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 5 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(5), LEN=IDIMLEN(5)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & + IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4) .AND. & + IDIMLEN(5) == SIZE(PFIELD,5) ) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X5 + + +SUBROUTINE IO_READ_FIELD_NC4_X6(TPFILE, TPFIELD, PFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +REAL,DIMENSION(:,:,:,:,:,:),INTENT(OUT) :: PFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +INTEGER(KIND=IDCDF_KIND),DIMENSION(6) :: IDIMLEN +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +IF (IDIMS == 6 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(5), LEN=IDIMLEN(5)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(6), LEN=IDIMLEN(6)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & + IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4) .AND. & + IDIMLEN(5) == SIZE(PFIELD,5) .AND. IDIMLEN(6) == SIZE(PFIELD,6) ) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_X6 + + +SUBROUTINE IO_READ_FIELD_NC4_N0(TPFILE, TPFIELD, KFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +INTEGER, INTENT(OUT) :: KFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!Can read either 4 or 8 byte integers +IF (IDIMS == 0 .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size or type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_N0 + + +SUBROUTINE IO_READ_FIELD_NC4_N1(TPFILE, TPFIELD, KFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +INTEGER, DIMENSION(:), INTENT(OUT) :: KFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +CHARACTER(LEN=30) :: YVARNAME +INTEGER(KIND=IDCDF_KIND) :: IDIMLEN +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!NF90_INT1 is for the case a boolean was written +IF (IDIMS == 1 .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64 .OR. ITYPE == NF90_INT1) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN == SIZE(KFIELD)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_N1 + + +SUBROUTINE IO_READ_FIELD_NC4_N2(TPFILE, TPFIELD, KFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +INTEGER, DIMENSION(:,:), INTENT(OUT) :: KFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +CHARACTER(LEN=30) :: YVARNAME +INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!Treat special case of a degenerated 3D array (3rd dimension size is 1) +IF (IDIMS==3) THEN + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + IF (IDIMLEN(3)==1) THEN + CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)// & + ': reading 3D array with degenerated third dimension in 2D array for '//TRIM(YVARNAME)) + IDIMS = 2 + ELSE + CALL PRINT_MSG(NVERB_FATAL,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': wrong number of dimensions for '//TRIM(YVARNAME)) + END IF +END IF + +!NF90_INT1 is for the case a boolean was written +IF (IDIMS == SIZE(SHAPE(KFIELD)) .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64 .OR. ITYPE == NF90_INT1) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN(1) == SIZE(KFIELD,1) .AND. IDIMLEN(2) == SIZE(KFIELD,2)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_N2 + +SUBROUTINE IO_READ_FIELD_NC4_L0(TPFILE, TPFIELD, OFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +LOGICAL, INTENT(OUT) :: OFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP +INTEGER :: IFIELD + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_L0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!NF90_INT1 is for the case a boolean was written +!Accept also INT and INT64 (for backward compatibility) +IF (IDIMS == 0 .AND. (ITYPE == NF90_INT1 .OR. ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, IFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + + IF (IFIELD==0) THEN + OFIELD = .FALSE. + ELSE IF (IFIELD==1) THEN + OFIELD = .TRUE. + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_LFI_L0',TRIM(TPFILE%CNAME)//': invalid value in file for ' & + //TRIM(TPFIELD%CMNHNAME)) + OFIELD = .TRUE. + IRESP = -112 + END IF + + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size or type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_L0 + + +SUBROUTINE IO_READ_FIELD_NC4_L1(TPFILE, TPFIELD, OFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +LOGICAL,DIMENSION(:),INTENT(OUT) :: OFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +INTEGER(KIND=IDCDF_KIND) :: IDIMLEN +CHARACTER(LEN=30) :: YVARNAME +INTEGER :: IRESP +INTEGER :: JI +INTEGER,DIMENSION(SIZE(OFIELD)) :: IFIELD + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +!Neglect the time dimension (of size 1) +IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + +!NF90_INT1 is for the case a boolean was written +!Accept also INT and INT64 (for backward compatibility) +IF (IDIMS == 1 .AND. (ITYPE == NF90_INT1 .OR. ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + + IF (IDIMLEN == SIZE(OFIELD)) THEN + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, IFIELD) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + + DO JI=1,IDIMLEN + IF (IFIELD(JI)==0) THEN + OFIELD(JI) = .FALSE. + ELSE IF (IFIELD(JI)==1) THEN + OFIELD(JI) = .TRUE. + ELSE + OFIELD(JI) = .TRUE. + IRESP = -112 + END IF + END DO + IF (IRESP==-112) THEN + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_LFI_L1',TRIM(TPFILE%CNAME)//': invalid value(s) in file for ' & + //TRIM(TPFIELD%CMNHNAME)) + END IF + + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size)') + IRESP = -3 + END IF +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong number of dimensions or wrong type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_L1 + + +SUBROUTINE IO_READ_FIELD_NC4_C0(TPFILE, TPFIELD, HFIELD, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +CHARACTER(LEN=*), INTENT(OUT) :: HFIELD +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS +CHARACTER(LEN=30) :: YVARNAME +CHARACTER(LEN=:),ALLOCATABLE :: YSTR +INTEGER(KIND=IDCDF_KIND) :: IDIMLEN +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +IF (IDIMS == 1 .AND. (ITYPE == NF90_CHAR) ) THEN + ! Check size of variable before reading + STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + ! + ALLOCATE(CHARACTER(LEN=IDIMLEN)::YSTR) + ! Read variable + STATUS = NF90_GET_VAR(INCID, IVARID, YSTR) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + IF (LEN_TRIM(YSTR) > LEN(HFIELD)) & + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)//' truncated') + HFIELD = TRIM(YSTR) + DEALLOCATE(YSTR) + + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size or type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_C0 + +SUBROUTINE IO_READ_FIELD_NC4_T0(TPFILE, TPFIELD, TPDATA, KRESP) +! +USE MODD_TYPE_DATE +! +USE MODE_DATETIME +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD +TYPE (DATE_TIME), INTENT(OUT) :: TPDATA +INTEGER, INTENT(OUT) :: KRESP ! return-code + +INTEGER(KIND=IDCDF_KIND) :: STATUS +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: IVARID +INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type +INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions +CHARACTER(LEN=30) :: YVARNAME +CHARACTER(LEN=:),ALLOCATABLE :: YSTR +INTEGER(KIND=IDCDF_KIND) :: IDIMLEN +INTEGER :: IDX,IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + +IRESP = 0 +! Get the Netcdf file ID +INCID = TPFILE%NNCID + +CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + +! Get variable ID, NDIMS and TYPE +STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_T0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) + GOTO 1000 +END IF +STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) +IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_T0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + +IF (IDIMS == 0 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN + ! Read time + STATUS = NF90_GET_VAR(INCID, IVARID, TPDATA%TIME) + IF (STATUS /= NF90_NOERR) THEN + CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) + GOTO 1000 + END IF + ! Read and check attributes of variable + CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP,HCALENDAR='standard') + ! Extract date from UNITS + IDX = INDEX(TPFIELD%CUNITS,'since ') + READ(TPFIELD%CUNITS(IDX+6 :IDX+9), '( I4.4 )') TPDATA%TDATE%YEAR + READ(TPFIELD%CUNITS(IDX+11:IDX+12),'( I2.2 )') TPDATA%TDATE%MONTH + READ(TPFIELD%CUNITS(IDX+14:IDX+15),'( I2.2 )') TPDATA%TDATE%DAY + ! Simple check (should catch most errors) + IF ( TPDATA%TDATE%DAY<1 .OR. TPDATA%TDATE%DAY>31 .OR. TPDATA%TDATE%MONTH<1 .OR. TPDATA%TDATE%MONTH>12 ) THEN + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' read date is invalid') + IRESP = -3 + END IF + ! Correct date and time (necessary for example if time is bigger than 86400 s) + CALL DATETIME_CORRECTDATE(TPDATA) +ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & + ' not read (wrong size or type)') + IRESP = -3 +END IF + +1000 CONTINUE +KRESP = IRESP + +END SUBROUTINE IO_READ_FIELD_NC4_T0 + + +end module mode_io_read_nc4 +#else +! +! External dummy subroutines +! +subroutine io_read_field_nc4(a, b, c, d, e, f, g) +use mode_msg +integer :: a, b, c, d, e, f, g +CALL PRINT_MSG(NVERB_ERROR,'IO','io_read_field_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_read_field_nc4 +! +#endif diff --git a/src/LIB/SURCOUCHE/src/mode_io_tools.f90 b/src/LIB/SURCOUCHE/src/mode_io_tools.f90 new file mode 100644 index 000000000..ed80dcbe6 --- /dev/null +++ b/src/LIB/SURCOUCHE/src/mode_io_tools.f90 @@ -0,0 +1,167 @@ +!MNH_LIC Copyright 1994-2018 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 : 13/12/2018 : extracted from mode_io.f90 +!----------------------------------------------------------------- +module mode_io_tools + +use mode_msg + +implicit none + +private + +public :: io_file, io_rank +public :: io_get_mnhversion, io_set_mnhversion + +contains + + FUNCTION io_file(k,nb_proc_io) + ! + ! return the file number where to write the K level of data + ! + IMPLICIT NONE + INTEGER(kind=MNH_MPI_RANK_KIND) :: k,nb_proc_io + INTEGER(kind=MNH_MPI_RANK_KIND) :: io_file + + io_file = MOD ((k-1) , nb_proc_io ) + + END FUNCTION io_file + + FUNCTION IO_RANK(IFILE,nb_proc,nb_proc_io,offset_rank) + ! + ! return the proc number which must write the 'IFILE' file + ! + IMPLICIT NONE + INTEGER(kind=MNH_MPI_RANK_KIND) :: IFILE,nb_proc,nb_proc_io + INTEGER(kind=MNH_MPI_RANK_KIND),OPTIONAL :: offset_rank + + INTEGER(kind=MNH_MPI_RANK_KIND) :: IO_RANK + + INTEGER(kind=MNH_MPI_RANK_KIND) :: ipas,irest + + ipas = nb_proc / nb_proc_io + irest = MOD ( nb_proc , nb_proc_io ) + + IF (ipas /= 0 ) THEN + IO_RANK=ipas * IFILE + MIN(IFILE , irest ) + ELSE + IO_RANK=MOD(IFILE , nb_proc ) + ENDIF + + ! + ! optional rank to shift for read test + ! + IF (PRESENT(offset_rank)) THEN + IF ( offset_rank .GT.0 ) IO_RANK=MOD(IO_RANK+offset_rank,nb_proc) + IF ( offset_rank .LT.0 ) IO_RANK=MOD(nb_proc-IO_RANK+offset_rank,nb_proc) + ENDIF + + END FUNCTION IO_RANK + + + subroutine io_get_mnhversion(tpfile) + !Compare MNHVERSION of file with current version and store it in file metadata + use modd_conf, only: nmnhversion + use modd_io_ll, only: tfiledata + use mode_field, only: tfielddata,typeint + use mode_fmread, only: io_read_field + + type(tfiledata), intent(inout) :: tpfile + + character(len=12) :: ymnhversion_file,ymnhversion_curr + integer :: imasdev,ibugfix + integer :: iresp + integer,dimension(3) :: imnhversion + type(tfielddata) :: tzfield + + call print_msg(NVERB_DEBUG,'IO','io_get_mnhversion','called for '//trim(tpfile%cname)) + + if ( trim(tpfile%cmode) /= 'READ' ) & + call print_msg(NVERB_FATAL,'IO','io_get_mnhversion',trim(tpfile%cname)// 'not opened in read mode') + + imnhversion(:) = 0 + !use tzfield because tfieldlist could be not initialised + tzfield%cmnhname = 'MNHVERSION' + tzfield%cstdname = '' + tzfield%clongname = 'MesoNH version' + tzfield%cunits = '' + tzfield%cdir = '--' + tzfield%ccomment = '' + tzfield%ngrid = 0 + tzfield%ntype = TYPEINT + tzfield%ndims = 1 + tzfield%ltimedep = .false. + call io_read_field(tpfile,tzfield,imnhversion,iresp) + if (iresp/=0) then + tzfield%cmnhname = 'MASDEV' + tzfield%clongname = 'MesoNH version (without bugfix)' + tzfield%ndims = 0 + call io_read_field(tpfile,tzfield,imasdev,iresp) + if (iresp/=0) then + call print_msg(NVERB_WARNING,'IO','io_get_mnhversion','unknown MASDEV version for '//trim(tpfile%cname)) + else + if (imasdev<100) then + imnhversion(1)=imasdev/10 + imnhversion(2)=mod(imasdev,10) + else !for example for mnh 4.10 + imnhversion(1)=imasdev/100 + imnhversion(2)=mod(imasdev,100) + end if + end if + ! + tzfield%cmnhname = 'BUGFIX' + tzfield%clongname = 'MesoNH bugfix number' + call io_read_field(tpfile,tzfield,ibugfix,iresp) + if (iresp/=0) then + call print_msg(NVERB_WARNING,'IO','io_get_mnhversion','unknown BUGFIX version for '//trim(tpfile%cname)) + else + imnhversion(3)=ibugfix + end if + end if + ! + write(ymnhversion_file,"( I0,'.',I0,'.',I0 )" ) imnhversion(1),imnhversion(2),imnhversion(3) + write(ymnhversion_curr,"( I0,'.',I0,'.',I0 )" ) nmnhversion(1),nmnhversion(2),nmnhversion(3) + ! + if ( imnhversion(1)==0 .and. imnhversion(2)==0 .and. imnhversion(3)==0 ) then + call print_msg(NVERB_WARNING,'IO','io_get_mnhversion','file '//trim(tpfile%cname)//& + ' was written with an unknown version of MesoNH') + else if ( imnhversion(1)< nmnhversion(1) .or. & + (imnhversion(1)==nmnhversion(1) .and. imnhversion(2)< nmnhversion(2)) .or. & + (imnhversion(1)==nmnhversion(1) .and. imnhversion(2)==nmnhversion(2) .and. imnhversion(3)<nmnhversion(3)) ) then + call print_msg(NVERB_WARNING,'IO','io_get_mnhversion','file '//trim(tpfile%cname)//& + ' was written with an older version of MesoNH ('//trim(ymnhversion_file)//& + ' instead of '//trim(ymnhversion_curr)//')') + else if ( imnhversion(1)> nmnhversion(1) .or. & + (imnhversion(1)==nmnhversion(1) .and. imnhversion(2)> nmnhversion(2)) .or. & + (imnhversion(1)==nmnhversion(1) .and. imnhversion(2)==nmnhversion(2) .and. imnhversion(3)>nmnhversion(3)) ) then + call print_msg(NVERB_WARNING,'IO','io_get_mnhversion','file '//trim(tpfile%cname)//& + ' was written with a more recent version of MesoNH ('//trim(ymnhversion_file)//& + ' instead of '//trim(ymnhversion_curr)//')') + else + call print_msg(NVERB_DEBUG,'IO','io_get_mnhversion','file '//trim(tpfile%cname)//& + ' was written with the same version of MesoNH ('//trim(ymnhversion_curr)//')') + end if + ! + tpfile%nmnhversion(:) = imnhversion(:) + end subroutine io_get_mnhversion + + + subroutine io_set_mnhversion(tpfile) + use modd_conf, only: nmnhversion + use modd_io_ll, only: tfiledata + + type(tfiledata), intent(inout) :: tpfile + + call print_msg(NVERB_DEBUG,'IO','io_set_mnhversion','called for '//trim(tpfile%cname)) + + if ( trim(tpfile%cmode) /= 'WRITE' ) & + call print_msg(NVERB_FATAL,'IO','io_set_mnhversion',trim(tpfile%cname)// 'not opened in write mode') + + tpfile%nmnhversion(:) = nmnhversion(:) + end subroutine io_set_mnhversion + +end module mode_io_tools diff --git a/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 new file mode 100644 index 000000000..4628accc3 --- /dev/null +++ b/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 @@ -0,0 +1,679 @@ +!MNH_LIC Copyright 1994-2018 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 : may 2016 : use NetCDF Fortran module +! J.Escobar : 14/12/2017 : Correction for MNH_INT=8 +! Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O +! P. Wautelet : 13/12/2018 : split of mode_netcdf into multiple modules/files +!----------------------------------------------------------------- +#if defined(MNH_IOCDF4) +module mode_io_tools_nc4 + +use modd_io_ll, only: tfiledata +use modd_netcdf, only: dimcdf, idcdf_kind, iocdf, tdim_dummy + +use mode_field, only: tfielddata +use mode_msg + +use NETCDF, only: NF90_NOERR, NF90_UNLIMITED, & + NF90_DEF_DIM, NF90_STRERROR + +implicit none + +private + +public :: io_find_dim_byname_nc4, io_guess_dimids_nc4, io_set_knowndims_nc4 +public :: cleaniocdf, cleanmnhname, fillvdims, getdimcdf, getstrdimid, handle_err, newiocdf + +contains + +SUBROUTINE IO_FIND_DIM_BYNAME_NC4(TPFILE, HDIMNAME, TPDIM, KRESP) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +CHARACTER(LEN=*), INTENT(IN) :: HDIMNAME +TYPE(DIMCDF), INTENT(OUT) :: TPDIM +INTEGER, INTENT(OUT) :: KRESP +! +TYPE(DIMCDF), POINTER :: TMP +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_FIND_DIM_BYNAME_NC4','called for dimension name '//TRIM(HDIMNAME)) +! +KRESP = -2 +! +IF(.NOT.ASSOCIATED(TPFILE%TNCDIMS%DIMLIST)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FIND_DIM_BYNAME_NC4','DIMLIST not associated for file '//TRIM(TPFILE%CNAME)) + KRESP = -1 + RETURN +END IF +! +TMP => TPFILE%TNCDIMS%DIMLIST +! +DO WHILE(ASSOCIATED(TMP)) + IF (TRIM(TMP%NAME)==TRIM(HDIMNAME)) THEN + TPDIM = TMP + KRESP = 0 + EXIT + END IF + TMP => TMP%NEXT +END DO +! +END SUBROUTINE IO_FIND_DIM_BYNAME_NC4 + + +SUBROUTINE IO_GUESS_DIMIDS_NC4(TPFILE, TPFIELD, KLEN, TPDIMS, KRESP) +! +USE MODE_FIELD, ONLY: TYPECHAR +! +!Used by LFI2CDF +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD +INTEGER, INTENT(IN) :: KLEN +TYPE(DIMCDF),DIMENSION(:), INTENT(OUT) :: TPDIMS +INTEGER, INTENT(OUT) :: KRESP +! +INTEGER :: IGRID +INTEGER :: ILEN, ISIZE +INTEGER :: JI +CHARACTER(LEN=32) :: YINT +CHARACTER(LEN=2) :: YDIR +TYPE(DIMCDF), POINTER :: PTDIM +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_GUESS_DIMIDS_NC4','called for '//TRIM(TPFIELD%CMNHNAME)) +! +IGRID = TPFIELD%NGRID +YDIR = TPFIELD%CDIR +! +KRESP = 0 +ILEN = 0 +PTDIM => NULL() +! +IF(IGRID<0 .OR. IGRID>8) THEN + WRITE(YINT,'( I0 )') IGRID + CALL PRINT_MSG(NVERB_FATAL,'IO','IO_GUESS_DIMIDS_NC4','invalid NGRID ('//TRIM(YINT)//') for field '//TRIM(TPFIELD%CMNHNAME)) +END IF +! +IF(IGRID==0 .AND. YDIR/='--' .AND. YDIR/='' ) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','invalid YDIR ('//TRIM(YDIR)//') with NGRID=0 for field '& + //TRIM(TPFIELD%CMNHNAME)) +END IF +! +IF (IGRID==0) THEN + SELECT CASE(TPFIELD%NDIMS) + CASE (0) + IF (TPFIELD%NTYPE == TYPECHAR) THEN + ILEN = KLEN + ELSE + ILEN = 1 + END IF + CASE (1) + PTDIM => GETDIMCDF(TPFILE,KLEN) + TPDIMS(1) = PTDIM + ILEN = PTDIM%LEN + CASE DEFAULT + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','NGRID=0 and NDIMS>1 not yet supported (field '& + //TRIM(TPFIELD%CMNHNAME)//')') + END SELECT +ELSE IF (TPFIELD%CLBTYPE/='NONE') THEN + IF (TPFIELD%NDIMS/=3) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','CLBTYPE/=NONE and NDIMS/=3 not supported (field '& + //TRIM(TPFIELD%CMNHNAME)//')') + END IF + ! + IF (TPFIELD%CLBTYPE=='LBX' .OR. TPFIELD%CLBTYPE=='LBXU') THEN + PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM + TPDIMS(2) = PTDIM + PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM + TPDIMS(3) = PTDIM + ILEN = TPDIMS(2)%LEN * TPDIMS(3)%LEN + ISIZE = KLEN/ILEN + IF (MOD(KLEN,ILEN)/=0) CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & + 'can not guess 1st dimension for field '//TRIM(TPFIELD%CMNHNAME)) + PTDIM => GETDIMCDF(TPFILE, ISIZE) + TPDIMS(1) = PTDIM + ILEN = ILEN * PTDIM%LEN + ELSE IF (TPFIELD%CLBTYPE=='LBY' .OR. TPFIELD%CLBTYPE=='LBYV') THEN + PTDIM => TPFILE%TNCCOORDS(1,IGRID)%TDIM + TPDIMS(1) = PTDIM + PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM + TPDIMS(3) = PTDIM + ILEN = TPDIMS(1)%LEN * TPDIMS(3)%LEN + ISIZE = KLEN/ILEN + IF (MOD(KLEN,ILEN)/=0) CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & + 'can not guess 2nd dimension for field '//TRIM(TPFIELD%CMNHNAME)) + PTDIM => GETDIMCDF(TPFILE, ISIZE) + TPDIMS(2) = PTDIM + ILEN = ILEN * PTDIM%LEN + ELSE + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','invalid CLBTYPE ('//TPFIELD%CLBTYPE//') for field '& + //TRIM(TPFIELD%CMNHNAME)) + END IF +ELSE + IF (TPFIELD%NDIMS==0) ILEN = 1 + ! + DO JI=1,TPFIELD%NDIMS + IF (JI == 1) THEN + IF ( (YDIR == 'XX' .OR. YDIR == 'XY') ) THEN + PTDIM => TPFILE%TNCCOORDS(1,IGRID)%TDIM + ELSE IF ( YDIR == 'YY' ) THEN + PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM + ELSE IF ( YDIR == 'ZZ' ) THEN + PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM + ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension + PTDIM => GETDIMCDF(TPFILE, KLEN) + END IF + ILEN = PTDIM%LEN + TPDIMS(JI) = PTDIM + ELSE IF (JI == 2) THEN + IF ( YDIR == 'XY') THEN + PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM + ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension + ISIZE = KLEN/ILEN + IF (MOD(KLEN,ILEN)/=0) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & + 'can not guess 2nd and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) + EXIT + END IF + PTDIM => GETDIMCDF(TPFILE, ISIZE) + ELSE + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess 2nd dimension for field '//TRIM(TPFIELD%CMNHNAME)) + EXIT + END IF + ILEN = ILEN * PTDIM%LEN + TPDIMS(JI) = PTDIM + ELSE IF (JI == 3) THEN + IF ( YDIR == 'XY' ) THEN + IF (JI==TPFIELD%NDIMS .AND. KLEN/ILEN==1 .AND. MOD(KLEN,ILEN)==0) THEN + !The last dimension is of size 1 => probably time dimension + ISIZE = 1 + PTDIM => GETDIMCDF(TPFILE,ISIZE) + ELSE + PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM + END IF + ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension + ISIZE = KLEN/ILEN + IF (MOD(KLEN,ILEN)/=0) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & + 'can not guess 3rd and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) + EXIT + END IF + PTDIM => GETDIMCDF(TPFILE, ISIZE) + ELSE + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess 3rd dimension for field '//TRIM(TPFIELD%CMNHNAME)) + EXIT + END IF + ILEN = ILEN * PTDIM%LEN + TPDIMS(JI) = PTDIM + ELSE IF (JI==4 .AND. JI==TPFIELD%NDIMS) THEN !Guess last dimension + ISIZE = KLEN/ILEN + IF (MOD(KLEN,ILEN)/=0) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & + 'can not guess 4th and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) + EXIT + END IF + PTDIM => GETDIMCDF(TPFILE, ISIZE) + ILEN = ILEN * PTDIM%LEN + TPDIMS(JI) = PTDIM + ELSE + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess dimension above 4 for field '& + //TRIM(TPFIELD%CMNHNAME)) + END IF + END DO +END IF +! +IF (KLEN /= ILEN) THEN + CALL PRINT_MSG(NVERB_INFO,'IO','IO_GUESS_DIMIDS_NC4','can not guess dimensions of field '& + //TRIM(TPFIELD%CMNHNAME)) + KRESP = 1 +END IF +! +END SUBROUTINE IO_GUESS_DIMIDS_NC4 + + +SUBROUTINE IO_SET_KNOWNDIMS_NC4(TPFILE,HPROGRAM_ORIG) + +USE MODD_CONF, ONLY: CPROGRAM +USE MODD_CONF_n, ONLY: CSTORAGE_TYPE +USE MODD_DIM_n, ONLY: NIMAX_ll, NJMAX_ll, NKMAX +USE MODD_PARAMETERS_ll, ONLY: JPHEXT, JPVEXT + +TYPE(TFILEDATA),INTENT(INOUT) :: TPFILE +CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HPROGRAM_ORIG !To emulate a file coming from this program + +CHARACTER(LEN=:),ALLOCATABLE :: YPROGRAM +INTEGER :: IIU_ll, IJU_ll, IKU +TYPE(IOCDF), POINTER :: PIOCDF + +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_SET_KNOWNDIMS_NC4','called for '//TRIM(TPFILE%CNAME)) + +PIOCDF => TPFILE%TNCDIMS + +IF (PRESENT(HPROGRAM_ORIG)) THEN + YPROGRAM = HPROGRAM_ORIG +ELSE + YPROGRAM = CPROGRAM +ENDIF + +IIU_ll = NIMAX_ll + 2*JPHEXT +IJU_ll = NJMAX_ll + 2*JPHEXT +IKU = NKMAX + 2*JPVEXT + +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI)) PIOCDF%DIM_NI => GETDIMCDF(TPFILE, IIU_ll, 'ni') +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ)) PIOCDF%DIM_NJ => GETDIMCDF(TPFILE, IJU_ll, 'nj') +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI_U)) PIOCDF%DIM_NI_U => GETDIMCDF(TPFILE, IIU_ll, 'ni_u') +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ_U)) PIOCDF%DIM_NJ_U => GETDIMCDF(TPFILE, IJU_ll, 'nj_u') +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI_V)) PIOCDF%DIM_NI_V => GETDIMCDF(TPFILE, IIU_ll, 'ni_v') +IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ_V)) PIOCDF%DIM_NJ_V => GETDIMCDF(TPFILE, IJU_ll, 'nj_v') +IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & + .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX + IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL)) PIOCDF%DIM_LEVEL => GETDIMCDF(TPFILE, IKU , 'level') + IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL_W)) PIOCDF%DIM_LEVEL_W => GETDIMCDF(TPFILE, IKU , 'level_w') + IF (.NOT. ASSOCIATED(PIOCDF%DIMTIME)) PIOCDF%DIMTIME => GETDIMCDF(TPFILE, NF90_UNLIMITED, 'time') +ELSE + !PGD and SURFEX files for MesoNH have no vertical levels or time scale + !These dimensions are allocated to default values + !(they need to be allocated when looking for dimensions of variables) + IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL)) ALLOCATE(PIOCDF%DIM_LEVEL) + IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL_W)) ALLOCATE(PIOCDF%DIM_LEVEL_W) + IF (.NOT. ASSOCIATED(PIOCDF%DIMTIME)) ALLOCATE(PIOCDF%DIMTIME) +END IF + +!Store X,Y,Z coordinates for the Arakawa points +!0 2nd-dimension is to treat NGRID=0 case without crash +IF (.NOT.ALLOCATED(TPFILE%TNCCOORDS)) ALLOCATE(TPFILE%TNCCOORDS(3,0:8)) +!Dummy point +TPFILE%TNCCOORDS(1,0)%TDIM => TDIM_DUMMY +TPFILE%TNCCOORDS(2,0)%TDIM => TDIM_DUMMY +TPFILE%TNCCOORDS(3,0)%TDIM => TDIM_DUMMY +! Mass point +TPFILE%TNCCOORDS(1,1)%TDIM => PIOCDF%DIM_NI +TPFILE%TNCCOORDS(2,1)%TDIM => PIOCDF%DIM_NJ +TPFILE%TNCCOORDS(3,1)%TDIM => PIOCDF%DIM_LEVEL +! u point +TPFILE%TNCCOORDS(1,2)%TDIM => PIOCDF%DIM_NI_U +TPFILE%TNCCOORDS(2,2)%TDIM => PIOCDF%DIM_NJ_U +TPFILE%TNCCOORDS(3,2)%TDIM => PIOCDF%DIM_LEVEL +! v point +TPFILE%TNCCOORDS(1,3)%TDIM => PIOCDF%DIM_NI_V +TPFILE%TNCCOORDS(2,3)%TDIM => PIOCDF%DIM_NJ_V +TPFILE%TNCCOORDS(3,3)%TDIM => PIOCDF%DIM_LEVEL +! w point +TPFILE%TNCCOORDS(1,4)%TDIM => PIOCDF%DIM_NI +TPFILE%TNCCOORDS(2,4)%TDIM => PIOCDF%DIM_NJ +TPFILE%TNCCOORDS(3,4)%TDIM => PIOCDF%DIM_LEVEL_W +! xi vorticity point (=f point =uv point) +TPFILE%TNCCOORDS(1,5)%TDIM => PIOCDF%DIM_NI_U +TPFILE%TNCCOORDS(2,5)%TDIM => PIOCDF%DIM_NJ_V +TPFILE%TNCCOORDS(3,5)%TDIM => PIOCDF%DIM_LEVEL +! eta vorticity point (=uw point) +TPFILE%TNCCOORDS(1,6)%TDIM => PIOCDF%DIM_NI_U +TPFILE%TNCCOORDS(2,6)%TDIM => PIOCDF%DIM_NJ_U +TPFILE%TNCCOORDS(3,6)%TDIM => PIOCDF%DIM_LEVEL_W +! zeta vorticity point (=vw point) +TPFILE%TNCCOORDS(1,7)%TDIM => PIOCDF%DIM_NI_V +TPFILE%TNCCOORDS(2,7)%TDIM => PIOCDF%DIM_NJ_V +TPFILE%TNCCOORDS(3,7)%TDIM => PIOCDF%DIM_LEVEL_W +! fw point (=uvw point) +TPFILE%TNCCOORDS(1,8)%TDIM => PIOCDF%DIM_NI_U +TPFILE%TNCCOORDS(2,8)%TDIM => PIOCDF%DIM_NJ_V +TPFILE%TNCCOORDS(3,8)%TDIM => PIOCDF%DIM_LEVEL_W + + +END SUBROUTINE IO_SET_KNOWNDIMS_NC4 + + +SUBROUTINE CLEANIOCDF(PIOCDF) +TYPE(IOCDF), POINTER :: PIOCDF + +INTEGER(KIND=IDCDF_KIND) :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','CLEANIOCDF','called') + +! Clean DIMLIST and DIMSTR +CALL CLEANLIST(PIOCDF%DIMLIST) +CALL CLEANLIST(PIOCDF%DIMSTR) +! Then free iocdf +DEALLOCATE(PIOCDF) + +CONTAINS + +SUBROUTINE CLEANLIST(PLIST) +TYPE(DIMCDF), POINTER :: PLIST,TZDIMCUR, TZDIMNEXT + +TZDIMCUR => PLIST +DO WHILE(ASSOCIATED(TZDIMCUR)) + TZDIMNEXT => TZDIMCUR%NEXT + DEALLOCATE(TZDIMCUR) + TZDIMCUR => TZDIMNEXT +END DO + +END SUBROUTINE CLEANLIST + +END SUBROUTINE CLEANIOCDF + + +SUBROUTINE FILLVDIMS(TPFILE, TPFIELD, KSHAPE, KVDIMS) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD +INTEGER(KIND=IDCDF_KIND),DIMENSION(:),INTENT(IN) :: KSHAPE +INTEGER(KIND=IDCDF_KIND),DIMENSION(:),ALLOCATABLE,INTENT(OUT) :: KVDIMS +! +INTEGER :: IGRID +INTEGER :: JI +CHARACTER(LEN=32) :: YINT +CHARACTER(LEN=2) :: YDIR +TYPE(DIMCDF), POINTER :: PTDIM +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','FILLVDIMS','called for '//TRIM(TPFIELD%CMNHNAME)) +! +IF (SIZE(KSHAPE) < 1 .AND. .NOT.TPFIELD%LTIMEDEP) CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','empty KSHAPE') +! +IGRID = TPFIELD%NGRID +YDIR = TPFIELD%CDIR +! +IF(SIZE(KSHAPE)/=TPFIELD%NDIMS) THEN + WRITE(YINT,'( I0,"/",I0 )') SIZE(KSHAPE),TPFIELD%NDIMS + CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','SIZE(KSHAPE)/=TPFIELD%NDIMS ('//TRIM(YINT)//') for field ' & + //TRIM(TPFIELD%CMNHNAME)) +END IF +! +IF (TPFIELD%LTIMEDEP) THEN + !Add time dimension + ALLOCATE(KVDIMS(TPFIELD%NDIMS+1)) + KVDIMS(TPFIELD%NDIMS+1) = TPFILE%TNCDIMS%DIMTIME%ID +ELSE + ALLOCATE(KVDIMS(TPFIELD%NDIMS)) +END IF +! +IF(IGRID<0 .OR. IGRID>8) THEN + WRITE(YINT,'( I0 )') IGRID + CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','invalid NGRID ('//TRIM(YINT)//') for field '//TRIM(TPFIELD%CMNHNAME)) +END IF +! +IF(IGRID==0 .AND. YDIR/='--' .AND. YDIR/='' ) THEN + CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','invalid YDIR ('//TRIM(YDIR)//') with NGRID=0 for field '//TRIM(TPFIELD%CMNHNAME)) +END IF +! +DO JI=1,SIZE(KSHAPE) + IF (JI == 1) THEN + IF ( (YDIR == 'XX' .OR. YDIR == 'XY') .AND. KSHAPE(1)==TPFILE%TNCCOORDS(1,IGRID)%TDIM%LEN) THEN + KVDIMS(1) = TPFILE%TNCCOORDS(1,IGRID)%TDIM%ID + ELSE IF ( YDIR == 'YY' .AND. KSHAPE(1)==TPFILE%TNCCOORDS(2,IGRID)%TDIM%LEN) THEN + KVDIMS(1) = TPFILE%TNCCOORDS(2,IGRID)%TDIM%ID + ELSE IF ( YDIR == 'ZZ' .AND. KSHAPE(1)==TPFILE%TNCCOORDS(3,IGRID)%TDIM%LEN) THEN + KVDIMS(1) = TPFILE%TNCCOORDS(3,IGRID)%TDIM%ID + ELSE + PTDIM => GETDIMCDF(TPFILE, KSHAPE(1)); KVDIMS(1) = PTDIM%ID + END IF + ELSE IF (JI == 2) THEN + IF ( YDIR == 'XY' .AND. KSHAPE(2)==TPFILE%TNCCOORDS(2,IGRID)%TDIM%LEN) THEN + KVDIMS(2) = TPFILE%TNCCOORDS(2,IGRID)%TDIM%ID + ELSE + PTDIM => GETDIMCDF(TPFILE, KSHAPE(2)); KVDIMS(2) = PTDIM%ID + END IF + ELSE IF (JI == 3) THEN + IF ( YDIR == 'XY' .AND. KSHAPE(3)==TPFILE%TNCCOORDS(3,IGRID)%TDIM%LEN) THEN + KVDIMS(3) = TPFILE%TNCCOORDS(3,IGRID)%TDIM%ID + ELSE + PTDIM => GETDIMCDF(TPFILE, KSHAPE(3)); KVDIMS(3) = PTDIM%ID + END IF + ELSE + PTDIM => GETDIMCDF(TPFILE, KSHAPE(JI)); KVDIMS(JI) = PTDIM%ID + END IF +END DO +! +END SUBROUTINE FILLVDIMS + + +FUNCTION GETDIMCDF(TPFILE, KLEN, HDIMNAME) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: KLEN +CHARACTER(LEN=*), OPTIONAL :: HDIMNAME ! When provided don't search but + ! simply create with name HDIMNAME +TYPE(DIMCDF), POINTER :: GETDIMCDF + +TYPE(DIMCDF), POINTER :: TMP +INTEGER :: COUNT +CHARACTER(LEN=16) :: YSUFFIX +CHARACTER(LEN=20) :: YDIMNAME +INTEGER(KIND=IDCDF_KIND) :: STATUS +LOGICAL :: GCHKLEN !Check if KLEN is valid +TYPE(IOCDF), POINTER :: PIOCDF + +CALL PRINT_MSG(NVERB_DEBUG,'IO','GETDIMCDF','called') + +PIOCDF => TPFILE%TNCDIMS + +GCHKLEN = .TRUE. +!Do not check KLEN if 'time' (because NF90_UNLIMITED = 0) +IF (PRESENT(HDIMNAME)) THEN + IF (TRIM(HDIMNAME)=='time') THEN + GCHKLEN = .FALSE. + END IF +END IF + +WRITE(YSUFFIX,'(I0)') KLEN + +IF (GCHKLEN .AND. KLEN < 1) THEN + CALL PRINT_MSG(NVERB_FATAL,'IO','GETDIMCDF','KLEN='//TRIM(YSUFFIX)) +END IF + +IF (PRESENT(HDIMNAME)) THEN + NULLIFY(TMP) + YDIMNAME = TRIM(HDIMNAME) +ELSE + ! Search dimension with KLEN length + COUNT = 1 + TMP => PIOCDF%DIMLIST + DO WHILE(ASSOCIATED(TMP)) + IF (TMP%LEN == KLEN .AND. TMP%NAME(1:4) /= 'char') EXIT + TMP=>TMP%NEXT + COUNT = COUNT+1 + END DO + YDIMNAME = 'size'//TRIM(YSUFFIX) +END IF + +IF (.NOT. ASSOCIATED(TMP)) THEN + ! Not found then define new dimension + ALLOCATE(TMP) + TMP%NAME = YDIMNAME + TMP%LEN = KLEN + STATUS = NF90_DEF_DIM(TPFILE%NNCID, TMP%NAME, KLEN, TMP%ID) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'GETDIMCDF[NF90_DEF_DIM]') + NULLIFY(TMP%NEXT) + TMP%NEXT => PIOCDF%DIMLIST + PIOCDF%DIMLIST => TMP +CALL PRINT_MSG(NVERB_DEBUG,'IO','GETDIMCDF','new dimension: '//TRIM(TMP%NAME)) +END IF + +GETDIMCDF => TMP + +END FUNCTION GETDIMCDF + + +FUNCTION GETSTRDIMID(TPFILE,KLEN) +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: KLEN +INTEGER(KIND=IDCDF_KIND) :: GETSTRDIMID + +TYPE(DIMCDF), POINTER :: TMP +TYPE(IOCDF), POINTER :: TZIOCDF +CHARACTER(LEN=16) :: YSUFFIX +INTEGER(KIND=IDCDF_KIND) :: STATUS + +CALL PRINT_MSG(NVERB_DEBUG,'IO','GETSTRDIMID','called') + +WRITE(YSUFFIX,'(I0)') KLEN + +IF (KLEN < 1) THEN + CALL PRINT_MSG(NVERB_FATAL,'IO','GETSTRDIMID','KLEN='//TRIM(YSUFFIX)) +END IF + +! Search string dimension with KLEN length +TMP => TPFILE%TNCDIMS%DIMSTR +DO WHILE(ASSOCIATED(TMP)) + IF (TMP%LEN == KLEN) EXIT + TMP=>TMP%NEXT +END DO + +IF (.NOT. ASSOCIATED(TMP)) THEN + ! Not found then define new dimension + ALLOCATE(TMP) + TMP%NAME = 'char'//TRIM(YSUFFIX) + TMP%LEN = KLEN + STATUS = NF90_DEF_DIM(TPFILE%NNCID, TMP%NAME, KLEN, TMP%ID) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'GETSTRDIMID[NF90_DEF_DIM]') + NULLIFY(TMP%NEXT) + TMP%NEXT => TPFILE%TNCDIMS%DIMSTR + TZIOCDF => TPFILE%TNCDIMS + TZIOCDF%DIMSTR => TMP +END IF + +GETSTRDIMID = TMP%ID + +END FUNCTION GETSTRDIMID + + +FUNCTION NEWIOCDF() +TYPE(IOCDF), POINTER :: NEWIOCDF +TYPE(IOCDF), POINTER :: TZIOCDF +INTEGER :: IRESP + +CALL PRINT_MSG(NVERB_DEBUG,'IO','NEWIOCDF','called') + +ALLOCATE(TZIOCDF, STAT=IRESP) +IF (IRESP > 0) THEN + CALL PRINT_MSG(NVERB_FATAL,'IO','NEWIOCDF','memory allocation error') + STOP +END IF + +NEWIOCDF=>TZIOCDF + +END FUNCTION NEWIOCDF + + +SUBROUTINE HANDLE_ERR(STATUS,LINE,TEXT,KRESP) +INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: STATUS +INTEGER, INTENT(IN) :: LINE +CHARACTER(LEN=*), INTENT(IN) :: TEXT +INTEGER, OPTIONAL, INTENT(OUT) :: KRESP + +CHARACTER(LEN=6) :: YLINE + +WRITE(YLINE,'( I6 )') LINE + +! Don't stop (by default) the code when KRESP is present +! and ensure KRESP is a negative integer +IF (STATUS /= NF90_NOERR) THEN + IF (PRESENT(KRESP)) THEN + IF (STATUS < 0) THEN + KRESP = STATUS + ELSE IF (STATUS == 0) THEN + KRESP = -1 + ELSE + KRESP = -STATUS + END IF + CALL PRINT_MSG(NVERB_WARNING,'IO',TRIM(TEXT),'netCDF error at line '//TRIM(YLINE)//': '//TRIM(NF90_STRERROR(STATUS))) + ELSE + CALL PRINT_MSG(NVERB_FATAL,'IO',TRIM(TEXT),'netCDF error at line '//TRIM(YLINE)//': '//TRIM(NF90_STRERROR(STATUS))) + END IF +END IF +END SUBROUTINE HANDLE_ERR + + +SUBROUTINE CLEANMNHNAME(HINNAME,HOUTNAME) + CHARACTER(LEN=*),INTENT(IN) :: HINNAME + CHARACTER(LEN=*),INTENT(OUT) :: HOUTNAME + + ! NetCDF var names can't contain '%' nor '.' + ! CF convention allows only letters, digits and underscores + HOUTNAME = str_replace(HINNAME, '%', '__') + HOUTNAME = str_replace(HOUTNAME, '.', '___') +END SUBROUTINE + + +FUNCTION str_replace(hstr, hold, hnew) +CHARACTER(LEN=*) :: hstr, hold, hnew +CHARACTER(LEN=LEN_TRIM(hstr)+MAX(0,LEN(hnew)-LEN(hold))) :: str_replace + +INTEGER :: pos + +pos = INDEX(hstr,hold) +IF (pos /= 0) THEN + str_replace = hstr(1:pos-1)//hnew//hstr(pos+LEN(hold):) +ELSE + str_replace = hstr +END IF + +END FUNCTION str_replace + + +end module mode_io_tools_nc4 +#else +! +! External dummy subroutines +! +subroutine io_find_dim_byname_nc4(a, b, c, d) +use mode_msg +integer :: a, b, c, d +CALL PRINT_MSG(NVERB_ERROR,'IO','io_find_dim_byname_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_find_dim_byname_nc4 +! +subroutine io_guess_dimids_nc4(a, b, c, d) +use mode_msg +integer :: a, b, c, d +CALL PRINT_MSG(NVERB_ERROR,'IO','io_guess_dimids_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_guess_dimids_nc4 +! +subroutine io_set_knowndims_nc4(a, b) +use mode_msg +integer :: a, b, +CALL PRINT_MSG(NVERB_ERROR,'IO','io_set_knowndims_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_set_knowndims_nc4 +! +subroutine cleaniocdf(a) +use mode_msg +integer :: a +CALL PRINT_MSG(NVERB_ERROR,'IO','cleaniocdf','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine cleaniocdf +! +subroutine cleanmnhname(a, b) +use mode_msg +integer :: a, b +CALL PRINT_MSG(NVERB_ERROR,'IO','cleanmnhname','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine cleanmnhname +! +subroutine fillvdims(a, b, c, d) +use mode_msg +integer :: a, b, c, d +CALL PRINT_MSG(NVERB_ERROR,'IO','fillvdims','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine fillvdims +! +function getdimcdf(a, b, c) +use mode_msg +integer :: getdimcdf +integer :: a, b, c +CALL PRINT_MSG(NVERB_ERROR,'IO','getdimcdf','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end function getdimcdf +! +function getstrdimid(a, b) +use mode_msg +integer :: getstrdimid +integer :: a, b +CALL PRINT_MSG(NVERB_ERROR,'IO','getstrdimid','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end function getstrdimid +! +subroutine handle_err(a, b, c, d) +use mode_msg +integer :: a, b, c, d +CALL PRINT_MSG(NVERB_ERROR,'IO','handle_err','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine handle_err +! +function newiocdf() +use mode_msg +integer :: newiocdf +CALL PRINT_MSG(NVERB_ERROR,'IO','newiocdf','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end function newiocdf() +! +#endif diff --git a/src/LIB/SURCOUCHE/src/mode_netcdf.f90 b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 similarity index 50% rename from src/LIB/SURCOUCHE/src/mode_netcdf.f90 rename to src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 index 9f5aa1ba5..ba49180c4 100644 --- a/src/LIB/SURCOUCHE/src/mode_netcdf.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 @@ -1,30 +1,34 @@ !MNH_LIC Copyright 1994-2018 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 version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt !MNH_LIC for details. version 1. !----------------------------------------------------------------- ! Modifications: ! P. Wautelet : may 2016 : use NetCDF Fortran module ! J.Escobar : 14/12/2017 : Correction for MNH_INT=8 ! Philippe Wautelet: 05/2016-04/2018: new data structures and calls for I/O +! P. Wautelet : 13/12/2018 : split of mode_netcdf into multiple modules/files !----------------------------------------------------------------- #if defined(MNH_IOCDF4) -MODULE MODE_NETCDF -USE MODD_NETCDF -USE NETCDF -USE MODD_IO_ll -USE MODE_FIELD, ONLY : TFIELDDATA -USE MODE_MSG +module mode_io_write_nc4 -IMPLICIT NONE +use modd_io_ll, only: gsmonoproc, tfiledata +use modd_netcdf, only: dimcdf, idcdf_kind, iocdf -PRIVATE +use mode_field, only: tfielddata +use mode_io_tools_nc4, only: cleanmnhname, fillvdims, getdimcdf, getstrdimid, handle_err +use mode_msg -INTEGER(KIND=IDCDF_KIND),PARAMETER :: SHUFFLE = 1 !Set to 1 for (usually) better compression -INTEGER(KIND=IDCDF_KIND),PARAMETER :: DEFLATE = 1 +use NETCDF, only: NF90_CHAR, NF90_DOUBLE, NF90_FLOAT, NF90_INT, NF90_INT1, NF90_INT64, & + NF90_GLOBAL, NF90_NOERR, & + NF90_DEF_VAR, NF90_DEF_VAR_DEFLATE, NF90_GET_ATT, NF90_INQ_VARID, & + NF90_INQUIRE_ATTRIBUTE, NF90_PUT_ATT, NF90_PUT_VAR -INTEGER,PARAMETER :: NSTRINGCHUNKSIZE = 16 !Dimension of the chunks of strings - !(to limit the number of dimensions for strings) +implicit none + +private + +public :: io_write_coordvar_nc4, io_write_field_nc4, io_write_header_nc4 INTERFACE IO_WRITE_FIELD_NC4 MODULE PROCEDURE IO_WRITE_FIELD_NC4_X0,IO_WRITE_FIELD_NC4_X1, & @@ -38,847 +42,99 @@ INTERFACE IO_WRITE_FIELD_NC4 IO_WRITE_FIELD_NC4_T0 END INTERFACE IO_WRITE_FIELD_NC4 -INTERFACE IO_READ_FIELD_NC4 - MODULE PROCEDURE IO_READ_FIELD_NC4_X0,IO_READ_FIELD_NC4_X1, & - IO_READ_FIELD_NC4_X2,IO_READ_FIELD_NC4_X3, & - IO_READ_FIELD_NC4_X4,IO_READ_FIELD_NC4_X5, & - IO_READ_FIELD_NC4_X6, & - IO_READ_FIELD_NC4_N0,IO_READ_FIELD_NC4_N1, & - IO_READ_FIELD_NC4_N2, & - IO_READ_FIELD_NC4_L0,IO_READ_FIELD_NC4_L1, & - IO_READ_FIELD_NC4_C0, & - IO_READ_FIELD_NC4_T0 -END INTERFACE IO_READ_FIELD_NC4 - -! Public from module netcdf -PUBLIC NF90_CLOSE,NF90_OPEN,NF90_CREATE, & - NF90_NOWRITE,NF90_CLOBBER,NF90_NETCDF4,NF90_NOERR,NF90_STRERROR, & - NF90_FILL_REAL,NF90_INQUIRE -! Public from this module : -PUBLIC GETDIMCDF,NEWIOCDF,CLEANIOCDF, & - IO_GUESS_DIMIDS_NC4,IO_FIND_DIM_BYNAME_NC4, & - IO_SET_KNOWNDIMS_NC4,IO_WRITE_COORDVAR_NC4, & - IO_WRITE_FIELD_NC4,IO_READ_FIELD_NC4,IO_WRITE_HEADER_NC4 - -CONTAINS - -SUBROUTINE CLEANMNHNAME(HINNAME,HOUTNAME) - CHARACTER(LEN=*),INTENT(IN) :: HINNAME - CHARACTER(LEN=*),INTENT(OUT) :: HOUTNAME - - ! NetCDF var names can't contain '%' nor '.' - ! CF convention allows only letters, digits and underscores - HOUTNAME = str_replace(HINNAME, '%', '__') - HOUTNAME = str_replace(HOUTNAME, '.', '___') -END SUBROUTINE - -FUNCTION NEWIOCDF() -TYPE(IOCDF), POINTER :: NEWIOCDF -TYPE(IOCDF), POINTER :: TZIOCDF -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','NEWIOCDF','called') - -ALLOCATE(TZIOCDF, STAT=IRESP) -IF (IRESP > 0) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','NEWIOCDF','memory allocation error') - STOP -END IF - -NEWIOCDF=>TZIOCDF - -END FUNCTION NEWIOCDF - -SUBROUTINE CLEANIOCDF(PIOCDF) -TYPE(IOCDF), POINTER :: PIOCDF - -INTEGER(KIND=IDCDF_KIND) :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','CLEANIOCDF','called') - -! Clean DIMLIST and DIMSTR -CALL CLEANLIST(PIOCDF%DIMLIST) -CALL CLEANLIST(PIOCDF%DIMSTR) -! Then free iocdf -DEALLOCATE(PIOCDF) - -CONTAINS - -SUBROUTINE CLEANLIST(PLIST) -TYPE(DIMCDF), POINTER :: PLIST,TZDIMCUR, TZDIMNEXT - -TZDIMCUR => PLIST -DO WHILE(ASSOCIATED(TZDIMCUR)) - TZDIMNEXT => TZDIMCUR%NEXT - DEALLOCATE(TZDIMCUR) - TZDIMCUR => TZDIMNEXT -END DO - -END SUBROUTINE CLEANLIST - -END SUBROUTINE CLEANIOCDF - - -SUBROUTINE IO_SET_KNOWNDIMS_NC4(TPFILE,HPROGRAM_ORIG) - -USE MODD_CONF, ONLY: CPROGRAM -USE MODD_CONF_n, ONLY: CSTORAGE_TYPE -USE MODD_DIM_n, ONLY: NIMAX_ll, NJMAX_ll, NKMAX -USE MODD_PARAMETERS_ll, ONLY: JPHEXT, JPVEXT - -TYPE(TFILEDATA),INTENT(INOUT) :: TPFILE -CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HPROGRAM_ORIG !To emulate a file coming from this program - -CHARACTER(LEN=:),ALLOCATABLE :: YPROGRAM -INTEGER :: IIU_ll, IJU_ll, IKU -TYPE(IOCDF), POINTER :: PIOCDF +integer,parameter :: NSTRINGCHUNKSIZE = 16 !Dimension of the chunks of strings + !(to limit the number of dimensions for strings) -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_SET_KNOWNDIMS_NC4','called for '//TRIM(TPFILE%CNAME)) +integer(kind=idcdf_kind),parameter :: SHUFFLE = 1 !Set to 1 for (usually) better compression +integer(kind=idcdf_kind),parameter :: DEFLATE = 1 -PIOCDF => TPFILE%TNCDIMS +contains -IF (PRESENT(HPROGRAM_ORIG)) THEN - YPROGRAM = HPROGRAM_ORIG -ELSE - YPROGRAM = CPROGRAM +SUBROUTINE IO_WRITE_FIELD_ATTR_NC4(TPFILE,TPFIELD,KVARID,OEXISTED,KSHAPE,HCALENDAR,OISCOORD) +! +USE MODD_CONF, ONLY: CPROGRAM, LCARTESIAN +USE MODD_CONF_n, ONLY: CSTORAGE_TYPE +! +USE MODE_FIELD, ONLY: TYPEINT, TYPEREAL +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD +INTEGER(KIND=IDCDF_KIND), INTENT(IN) :: KVARID +LOGICAL, INTENT(IN) :: OEXISTED !True if variable was already defined +INTEGER(KIND=IDCDF_KIND),DIMENSION(:),OPTIONAL,INTENT(IN) :: KSHAPE +CHARACTER(LEN=*), OPTIONAL,INTENT(IN) :: HCALENDAR +LOGICAL, OPTIONAL,INTENT(IN) :: OISCOORD ! Is a coordinate variable (->do not write coordinates attribute) +! +INTEGER(KIND=IDCDF_KIND) :: INCID +INTEGER(KIND=IDCDF_KIND) :: STATUS +CHARACTER(LEN=:),ALLOCATABLE :: YCOORDS +LOGICAL :: GISCOORD +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','called for field '//TRIM(TPFIELD%CMNHNAME)) +! +IF(LEN_TRIM(TPFIELD%CSTDNAME)==0 .AND. LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_ATTR_NC4','at least long_name or standard_name must be provided & + &to respect CF-convention for variable '//TRIM(TPFIELD%CMNHNAME)) ENDIF - -IIU_ll = NIMAX_ll + 2*JPHEXT -IJU_ll = NJMAX_ll + 2*JPHEXT -IKU = NKMAX + 2*JPVEXT - -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI)) PIOCDF%DIM_NI => GETDIMCDF(TPFILE, IIU_ll, 'ni') -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ)) PIOCDF%DIM_NJ => GETDIMCDF(TPFILE, IJU_ll, 'nj') -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI_U)) PIOCDF%DIM_NI_U => GETDIMCDF(TPFILE, IIU_ll, 'ni_u') -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ_U)) PIOCDF%DIM_NJ_U => GETDIMCDF(TPFILE, IJU_ll, 'nj_u') -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NI_V)) PIOCDF%DIM_NI_V => GETDIMCDF(TPFILE, IIU_ll, 'ni_v') -IF (.NOT. ASSOCIATED(PIOCDF%DIM_NJ_V)) PIOCDF%DIM_NJ_V => GETDIMCDF(TPFILE, IJU_ll, 'nj_v') -IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & - .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX - IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL)) PIOCDF%DIM_LEVEL => GETDIMCDF(TPFILE, IKU , 'level') - IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL_W)) PIOCDF%DIM_LEVEL_W => GETDIMCDF(TPFILE, IKU , 'level_w') - IF (.NOT. ASSOCIATED(PIOCDF%DIMTIME)) PIOCDF%DIMTIME => GETDIMCDF(TPFILE, NF90_UNLIMITED, 'time') +! +IF (TPFIELD%NDIMS>1 .AND. .NOT.PRESENT(KSHAPE)) & + CALL PRINT_MSG(NVERB_FATAL,'IO','IO_WRITE_FIELD_ATTR_NC4','KSHAPE not provided for '//TRIM(TPFIELD%CMNHNAME)) +! +IF (PRESENT(OISCOORD)) THEN + GISCOORD = OISCOORD ELSE - !PGD and SURFEX files for MesoNH have no vertical levels or time scale - !These dimensions are allocated to default values - !(they need to be allocated when looking for dimensions of variables) - IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL)) ALLOCATE(PIOCDF%DIM_LEVEL) - IF (.NOT. ASSOCIATED(PIOCDF%DIM_LEVEL_W)) ALLOCATE(PIOCDF%DIM_LEVEL_W) - IF (.NOT. ASSOCIATED(PIOCDF%DIMTIME)) ALLOCATE(PIOCDF%DIMTIME) + GISCOORD = .FALSE. END IF - -!Store X,Y,Z coordinates for the Arakawa points -!0 2nd-dimension is to treat NGRID=0 case without crash -IF (.NOT.ALLOCATED(TPFILE%TNCCOORDS)) ALLOCATE(TPFILE%TNCCOORDS(3,0:8)) -!Dummy point -TPFILE%TNCCOORDS(1,0)%TDIM => TDIM_DUMMY -TPFILE%TNCCOORDS(2,0)%TDIM => TDIM_DUMMY -TPFILE%TNCCOORDS(3,0)%TDIM => TDIM_DUMMY -! Mass point -TPFILE%TNCCOORDS(1,1)%TDIM => PIOCDF%DIM_NI -TPFILE%TNCCOORDS(2,1)%TDIM => PIOCDF%DIM_NJ -TPFILE%TNCCOORDS(3,1)%TDIM => PIOCDF%DIM_LEVEL -! u point -TPFILE%TNCCOORDS(1,2)%TDIM => PIOCDF%DIM_NI_U -TPFILE%TNCCOORDS(2,2)%TDIM => PIOCDF%DIM_NJ_U -TPFILE%TNCCOORDS(3,2)%TDIM => PIOCDF%DIM_LEVEL -! v point -TPFILE%TNCCOORDS(1,3)%TDIM => PIOCDF%DIM_NI_V -TPFILE%TNCCOORDS(2,3)%TDIM => PIOCDF%DIM_NJ_V -TPFILE%TNCCOORDS(3,3)%TDIM => PIOCDF%DIM_LEVEL -! w point -TPFILE%TNCCOORDS(1,4)%TDIM => PIOCDF%DIM_NI -TPFILE%TNCCOORDS(2,4)%TDIM => PIOCDF%DIM_NJ -TPFILE%TNCCOORDS(3,4)%TDIM => PIOCDF%DIM_LEVEL_W -! xi vorticity point (=f point =uv point) -TPFILE%TNCCOORDS(1,5)%TDIM => PIOCDF%DIM_NI_U -TPFILE%TNCCOORDS(2,5)%TDIM => PIOCDF%DIM_NJ_V -TPFILE%TNCCOORDS(3,5)%TDIM => PIOCDF%DIM_LEVEL -! eta vorticity point (=uw point) -TPFILE%TNCCOORDS(1,6)%TDIM => PIOCDF%DIM_NI_U -TPFILE%TNCCOORDS(2,6)%TDIM => PIOCDF%DIM_NJ_U -TPFILE%TNCCOORDS(3,6)%TDIM => PIOCDF%DIM_LEVEL_W -! zeta vorticity point (=vw point) -TPFILE%TNCCOORDS(1,7)%TDIM => PIOCDF%DIM_NI_V -TPFILE%TNCCOORDS(2,7)%TDIM => PIOCDF%DIM_NJ_V -TPFILE%TNCCOORDS(3,7)%TDIM => PIOCDF%DIM_LEVEL_W -! fw point (=uvw point) -TPFILE%TNCCOORDS(1,8)%TDIM => PIOCDF%DIM_NI_U -TPFILE%TNCCOORDS(2,8)%TDIM => PIOCDF%DIM_NJ_V -TPFILE%TNCCOORDS(3,8)%TDIM => PIOCDF%DIM_LEVEL_W - - -END SUBROUTINE IO_SET_KNOWNDIMS_NC4 - - -SUBROUTINE IO_WRITE_COORDVAR_NC4(TPFILE,HPROGRAM_ORIG) -USE MODD_CONF, ONLY: CPROGRAM, LCARTESIAN -USE MODD_CONF_n, ONLY: CSTORAGE_TYPE -USE MODD_GRID, ONLY: XLATORI, XLONORI -USE MODD_GRID_n, ONLY: LSLEVE, XXHAT, XYHAT, XZHAT -USE MODD_PARAMETERS, ONLY: JPHEXT, JPVEXT - -USE MODE_FIELD, ONLY: TFIELDLIST,FIND_FIELD_ID_FROM_MNHNAME -USE MODE_GRIDPROJ -USE MODE_NEST_ll, ONLY: GET_MODEL_NUMBER_ll, GO_TOMODEL_ll - -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HPROGRAM_ORIG !To emulate a file coming from this program - -CHARACTER(LEN=:),ALLOCATABLE :: YSTDNAMEPREFIX -CHARACTER(LEN=:),ALLOCATABLE :: YPROGRAM -INTEGER :: IIU, IJU, IKU -INTEGER :: ID, IID, IRESP -INTEGER :: IMI -INTEGER(KIND=IDCDF_KIND) :: INCID -LOGICAL :: GCHANGEMODEL -LOGICAL,POINTER :: GSLEVE -REAL,DIMENSION(:),POINTER :: ZXHAT, ZYHAT, ZZHAT -REAL,DIMENSION(:),ALLOCATABLE :: ZXHATM, ZYHATM,ZZHATM !Coordinates at mass points in the transformed space -REAL,DIMENSION(:,:),POINTER :: ZLAT, ZLON -TYPE(IOCDF), POINTER :: PIOCDF - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_COORDVAR_NC4','called for '//TRIM(TPFILE%CNAME)) - -ZXHAT => NULL() -ZYHAT => NULL() -ZZHAT => NULL() - -PIOCDF => TPFILE%TNCDIMS - -GCHANGEMODEL = .FALSE. - -IF (PRESENT(HPROGRAM_ORIG)) THEN - YPROGRAM = HPROGRAM_ORIG +! +INCID = TPFILE%NNCID +! +! Standard_name attribute definition (CF convention) +IF(LEN_TRIM(TPFIELD%CSTDNAME)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CSTDNAME not set for variable '//TRIM(TPFIELD%CMNHNAME)) ELSE - YPROGRAM = CPROGRAM + STATUS = NF90_PUT_ATT(INCID, KVARID,'standard_name', TRIM(TPFIELD%CSTDNAME)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') ENDIF - -! Get the Netcdf file ID -INCID = TPFILE%NNCID - -IF (TPFILE%NMODEL>0) THEN - CALL FIND_FIELD_ID_FROM_MNHNAME('XHAT',IID,IRESP) - ZXHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA - CALL FIND_FIELD_ID_FROM_MNHNAME('YHAT',IID,IRESP) - ZYHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA - CALL FIND_FIELD_ID_FROM_MNHNAME('ZHAT',IID,IRESP) - ZZHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA - CALL FIND_FIELD_ID_FROM_MNHNAME('SLEVE',IID,IRESP) - GSLEVE => TFIELDLIST(IID)%TFIELD_L0D(TPFILE%NMODEL)%DATA - ! - CALL GET_MODEL_NUMBER_ll(IMI) - IF (IMI/=TPFILE%NMODEL) THEN - !This is necessary to have correct domain sizes (used by GATHER_XXFIELD) - CALL GO_TOMODEL_ll(TPFILE%NMODEL,IRESP) - GCHANGEMODEL = .TRUE. - END IF +! +! Long_name attribute definition (CF convention) +IF(LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CLONGNAME not set for variable '//TRIM(TPFIELD%CMNHNAME)) ELSE - ZXHAT => XXHAT - ZYHAT => XYHAT - ZZHAT => XZHAT - GSLEVE => LSLEVE -END IF - -IIU = SIZE(ZXHAT) -IJU = SIZE(ZYHAT) -ALLOCATE(ZXHATM(IIU),ZYHATM(IJU)) -!ZXHATM(IIU) and ZYHATM(IJU) are correct only on some processes -!but it is OK due to the way GATHER_XXFIELD is done -ZXHATM(1:IIU-1) = 0.5*(ZXHAT(1:IIU-1)+ZXHAT(2:IIU)) -ZXHATM(IIU) = 2.*ZXHAT(IIU)-ZXHATM(IIU-1) -ZYHATM(1:IJU-1) = 0.5*(ZYHAT(1:IJU-1)+ZYHAT(2:IJU)) -ZYHATM(IJU) = 2.*ZYHAT(IJU)-ZYHATM(IJU-1) + STATUS = NF90_PUT_ATT(INCID, KVARID,'long_name', TRIM(TPFIELD%CLONGNAME)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') +ENDIF ! -IF (LCARTESIAN) THEN - YSTDNAMEPREFIX = 'plane' +! Canonical units attribute definition (CF convention) +IF(LEN_TRIM(TPFIELD%CUNITS)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CUNITS not set for variable '//TRIM(TPFIELD%CMNHNAME)) ELSE - YSTDNAMEPREFIX = 'projection' + STATUS = NF90_PUT_ATT(INCID, KVARID,'units', TRIM(TPFIELD%CUNITS)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') ENDIF -CALL WRITE_HOR_COORD(PIOCDF%DIM_NI,'x-dimension of the grid',TRIM(YSTDNAMEPREFIX)//'_x_coordinate','X',0.,JPHEXT,JPHEXT,ZXHATM) -CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ,'y-dimension of the grid',TRIM(YSTDNAMEPREFIX)//'_y_coordinate','Y',0.,JPHEXT,JPHEXT,ZYHATM) -CALL WRITE_HOR_COORD(PIOCDF%DIM_NI_U,'x-dimension of the grid at u location', & - TRIM(YSTDNAMEPREFIX)//'_x_coordinate_at_u_location','X',-0.5,JPHEXT,0, ZXHAT) -CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ_U,'y-dimension of the grid at u location', & - TRIM(YSTDNAMEPREFIX)//'_y_coordinate_at_u_location','Y', 0., JPHEXT,JPHEXT,ZYHATM) -CALL WRITE_HOR_COORD(PIOCDF%DIM_NI_V,'x-dimension of the grid at v location', & - TRIM(YSTDNAMEPREFIX)//'_x_coordinate_at_v_location','X', 0., JPHEXT,JPHEXT,ZXHATM) -CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ_V,'y-dimension of the grid at v location', & - TRIM(YSTDNAMEPREFIX)//'_y_coordinate_at_v_location','Y',-0.5,JPHEXT,0, ZYHAT) ! -IF (.NOT.LCARTESIAN) THEN - ALLOCATE(ZLAT(IIU,IJU),ZLON(IIU,IJU)) - ! - !Compute latitude/longitude for the Arakawa points - ! - ! Mass point - CALL WRITE_HOR_2DCOORD(ZXHATM,ZYHATM,'latitude', 'longitude') - ! u point - CALL WRITE_HOR_2DCOORD(ZXHAT, ZYHATM,'latitude_u','longitude_u') - ! v point - CALL WRITE_HOR_2DCOORD(ZXHATM,ZYHAT, 'latitude_v','longitude_v') - ! xi vorticity point (=f point =uv point) - CALL WRITE_HOR_2DCOORD(ZXHAT, ZYHAT, 'latitude_f','longitude_f') - ! - DEALLOCATE(ZLAT,ZLON) -END IF +! GRID attribute definition +IF(TPFIELD%NGRID<0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%NGRID not set for variable '//TRIM(TPFIELD%CMNHNAME)) +!Do not write GRID attribute if NGRID=0 +ELSE IF (TPFIELD%NGRID>0) THEN + STATUS = NF90_PUT_ATT(INCID, KVARID, 'grid', TPFIELD%NGRID) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') +ENDIF ! -DEALLOCATE(ZXHATM,ZYHATM) +! COMMENT attribute definition +IF(LEN_TRIM(TPFIELD%CCOMMENT)==0) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CCOMMENT not set for variable '//TRIM(TPFIELD%CMNHNAME)) +ELSE + STATUS = NF90_PUT_ATT(INCID, KVARID,'comment', TRIM(TPFIELD%CCOMMENT)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') +ENDIF ! -IF (TPFILE%LMASTER) THEN !vertical coordinates in the transformed space are the same on all processes - IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & - .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX - ! - IKU = SIZE(ZZHAT) - ALLOCATE(ZZHATM(IKU)) - ZZHATM(1:IKU-1) = 0.5 * (ZZHAT(2:IKU)+ZZHAT(1:IKU-1)) - ZZHATM(IKU) = 2.* ZZHAT(IKU) - ZZHATM(IKU-1) - ! - CALL WRITE_VER_COORD(PIOCDF%DIM_LEVEL, 'position z in the transformed space', '', & - 'altitude', 0., JPVEXT,JPVEXT,ZZHATM) - ! - CALL WRITE_VER_COORD(PIOCDF%DIM_LEVEL_W,'position z in the transformed space at w location','', & - 'altitude_at_w_location',-0.5,JPVEXT,0, ZZHAT) - ! - DEALLOCATE(ZZHATM) - END IF -END IF -! -!Write time scale -IF (TPFILE%LMASTER) THEN !Time scale is the same on all processes - IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & - .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX - CALL WRITE_TIME_COORD(PIOCDF%DIMTIME) - END IF -END IF - -IF (GCHANGEMODEL) CALL GO_TOMODEL_ll(IMI,IRESP) - -CONTAINS -SUBROUTINE WRITE_HOR_COORD(TDIM,HLONGNAME,HSTDNAME,HAXIS,PSHIFT,KBOUNDLOW,KBOUNDHIGH,PCOORDS) - USE MODE_ALLOCBUFFER_ll, ONLY: ALLOCBUFFER_ll - USE MODE_GATHER_ll, ONLY: GATHER_XXFIELD - - TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM - CHARACTER(LEN=*), INTENT(IN) :: HLONGNAME - CHARACTER(LEN=*), INTENT(IN) :: HSTDNAME - CHARACTER(LEN=*), INTENT(IN) :: HAXIS - REAL, INTENT(IN) :: PSHIFT - INTEGER, INTENT(IN) :: KBOUNDLOW - INTEGER, INTENT(IN) :: KBOUNDHIGH - REAL,DIMENSION(:),TARGET,OPTIONAL,INTENT(IN) :: PCOORDS - - CHARACTER(LEN=2) :: YDIR - CHARACTER(LEN=64) :: YRANGE - CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME - INTEGER :: IRESP - INTEGER :: ISIZE - INTEGER :: JI - INTEGER(KIND=IDCDF_KIND) :: IVARID - INTEGER(KIND=IDCDF_KIND) :: IVDIM - INTEGER(KIND=IDCDF_KIND) :: STATUS - LOGICAL :: GALLOC - REAL,DIMENSION(:),POINTER :: ZTAB - - GALLOC = .FALSE. - ZTAB => NULL() - - IF (HAXIS=='X') THEN - YDIR = 'XX' - ELSE IF (HAXIS=='Y') THEN - YDIR = 'YY' - ELSE - CALL PRINT_MSG(NVERB_FATAL,'IO','WRITE_HOR_COORD','invalid HAXIS ('//TRIM(HAXIS)//')') - END IF - - IF (.NOT.TPFILE%LMASTER) THEN - IF (PRESENT(PCOORDS)) THEN - ALLOCATE(ZTAB(0)) !To prevent false positive with valgrind - GALLOC = .TRUE. - CALL GATHER_XXFIELD(YDIR,PCOORDS,ZTAB,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - END IF - ELSE !TPFILE%LMASTER - ISIZE = TDIM%LEN - YVARNAME = TRIM(TDIM%NAME) - IVDIM = TDIM%ID - - IF (.NOT.PRESENT(PCOORDS)) THEN - ALLOCATE(ZTAB(ISIZE)) - GALLOC = .TRUE. - DO JI=1,ISIZE - ZTAB(JI) = REAL(JI,KIND=KIND(ZTAB(1)))+PSHIFT - END DO - ELSE - IF (GSMONOPROC) THEN ! sequential execution - ZTAB => PCOORDS - ELSE ! multiprocesses execution - CALL ALLOCBUFFER_ll(ZTAB,PCOORDS,YDIR,GALLOC) - CALL GATHER_XXFIELD(YDIR,PCOORDS,ZTAB,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - ENDIF - END IF - - STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) - IF (STATUS /= NF90_NOERR) THEN - ! Define the coordinate variable -#if (MNH_REAL == 8) - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) -#else - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) -#endif - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_DEF_VAR]') - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_NC_COORDS_VAR',TRIM(YVARNAME)//' already defined') - END IF - - ! Write metadata - STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name',HLONGNAME) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name',HSTDNAME) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - IF (PRESENT(PCOORDS)) THEN - STATUS = NF90_PUT_ATT(INCID, IVARID, 'units','m') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - END IF - STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis',HAXIS) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_axis_shift',PSHIFT) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - WRITE(YRANGE,'( I0,":",I0 )') 1+KBOUNDLOW,ISIZE-KBOUNDHIGH - STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_dynamic_range',TRIM(YRANGE)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - - ! Write the data - STATUS = NF90_PUT_VAR(INCID, IVARID, ZTAB) - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - END IF - - IF (GALLOC) DEALLOCATE(ZTAB) -END SUBROUTINE WRITE_HOR_COORD - -SUBROUTINE WRITE_HOR_2DCOORD(PX,PY,HLAT,HLON) - USE MODE_ALLOCBUFFER_ll, ONLY: ALLOCBUFFER_ll - USE MODE_GATHER_ll, ONLY: GATHER_XYFIELD - - REAL,DIMENSION(:), INTENT(IN) :: PX - REAL,DIMENSION(:), INTENT(IN) :: PY - CHARACTER(LEN=*), INTENT(IN) :: HLAT - CHARACTER(LEN=*), INTENT(IN) :: HLON - - LOGICAL :: GALLOC1, GALLOC2 - REAL,DIMENSION(:,:),POINTER :: ZTAB1, ZTAB2 - - GALLOC1 = .FALSE. - GALLOC2 = .FALSE. - ZTAB1 => NULL() - ZTAB2 => NULL() - - CALL SM_LATLON(XLATORI,XLONORI, & - SPREAD(SOURCE=PX,DIM=2,NCOPIES=IJU), & - SPREAD(SOURCE=PY,DIM=1,NCOPIES=IIU), & - ZLAT,ZLON) - - IF (.NOT.TPFILE%LMASTER) THEN - ALLOCATE(ZTAB1(0,0),ZTAB2(0,0)) !To prevent false positive with valgrind - GALLOC1 = .TRUE. ; GALLOC2 = .TRUE. - CALL GATHER_XYFIELD(ZLAT,ZTAB1,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - CALL GATHER_XYFIELD(ZLON,ZTAB2,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - ELSE !TPFILE%LMASTER - IF (GSMONOPROC) THEN ! sequential execution - ZTAB1 => ZLAT - ZTAB2 => ZLON - ELSE ! multiprocesses execution - CALL ALLOCBUFFER_ll(ZTAB1,ZLAT,'XY',GALLOC1) - CALL ALLOCBUFFER_ll(ZTAB2,ZLON,'XY',GALLOC2) - CALL GATHER_XYFIELD(ZLAT,ZTAB1,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - CALL GATHER_XYFIELD(ZLON,ZTAB2,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) - ENDIF - ! - CALL FIND_FIELD_ID_FROM_MNHNAME(HLAT,ID,IRESP) - CALL IO_WRITE_FIELD_NC4_X2(TPFILE,TFIELDLIST(ID),ZTAB1,IRESP,OISCOORD=.TRUE.) - CALL FIND_FIELD_ID_FROM_MNHNAME(HLON,ID,IRESP) - CALL IO_WRITE_FIELD_NC4_X2(TPFILE,TFIELDLIST(ID),ZTAB2,IRESP,OISCOORD=.TRUE.) - END IF - - IF (GALLOC1) DEALLOCATE(ZTAB1) - IF (GALLOC2) DEALLOCATE(ZTAB2) -END SUBROUTINE WRITE_HOR_2DCOORD - -SUBROUTINE WRITE_VER_COORD(TDIM,HLONGNAME,HSTDNAME,HCOMPNAME,PSHIFT,KBOUNDLOW,KBOUNDHIGH,PCOORDS) - TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM - CHARACTER(LEN=*), INTENT(IN) :: HLONGNAME - CHARACTER(LEN=*), INTENT(IN) :: HSTDNAME - CHARACTER(LEN=*), INTENT(IN) :: HCOMPNAME - REAL, INTENT(IN) :: PSHIFT - INTEGER, INTENT(IN) :: KBOUNDLOW - INTEGER, INTENT(IN) :: KBOUNDHIGH - REAL,DIMENSION(:), INTENT(IN) :: PCOORDS - - CHARACTER(LEN=64) :: YRANGE - CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME - INTEGER :: IRESP - INTEGER :: ISIZE - INTEGER :: JI - INTEGER(KIND=IDCDF_KIND) :: IVARID - INTEGER(KIND=IDCDF_KIND) :: IVDIM - INTEGER(KIND=IDCDF_KIND) :: STATUS - - ISIZE = TDIM%LEN - YVARNAME = TRIM(TDIM%NAME) - IVDIM = TDIM%ID - - STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) - IF (STATUS /= NF90_NOERR) THEN - ! Define the coordinate variable -#if (MNH_REAL == 8) - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) -#else - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) -#endif - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_DEF_VAR]') - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_NC_COORDS_VAR',TRIM(YVARNAME)//' already defined') - END IF - - ! Write metadata - STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name',HLONGNAME) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name',HSTDNAME) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'units','m') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis','Z') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'positive','up') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_axis_shift',PSHIFT) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - WRITE(YRANGE,'( I0,":",I0 )') 1+KBOUNDLOW,ISIZE-KBOUNDHIGH - STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_dynamic_range',TRIM(YRANGE)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - ! - IF (GSLEVE) THEN - !Remark: ZS, ZSMT and ZTOP in the formula are the same for mass point or flux point - STATUS = NF90_PUT_ATT(INCID, IVARID,'formula_terms','s: '//TRIM(YVARNAME)// & - ' height: ZTOP oro_ls: ZSMT oro: ZS len1: LEN1 len2: LEN2') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_definition','z(n,k,j,i)=s(k)'// & - '+ oro_ls(j,i)*sinh((height/len1)**1.35-(s(k)/len1)**1.35)/sinh((s(k)/len1)**1.35)'// & - '+(oro(j,i)-oro_ls(j,i))*sinh((height/len2)**1.35-(s(k)/len2)**1.35)/sinh((s(k)/len2)**1.35)') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - ELSE - !Remark: ZS and ZTOP in the formula are the same for mass point or flux point - STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_terms','s: '//TRIM(YVARNAME)//' height: ZTOP orog: ZS') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_definition','z(n,k,j,i)=s(k)*(height-orog(j,i))/height+orog(j,i)') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - ENDIF - ! - STATUS = NF90_PUT_ATT(INCID, IVARID, 'computed_standard_name',HCOMPNAME) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - - ! Write the data - STATUS = NF90_PUT_VAR(INCID, IVARID, PCOORDS) - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - -END SUBROUTINE WRITE_VER_COORD - -SUBROUTINE WRITE_TIME_COORD(TDIM) - USE MODD_TIME_n, ONLY: TDTMOD, TDTCUR - USE MODD_TYPE_DATE - - USE MODE_DATETIME - USE MODE_FIELD, ONLY: TFIELDLIST,FIND_FIELD_ID_FROM_MNHNAME - USE MODE_GRIDPROJ - - TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM - - REAL :: ZDELTATIME - CHARACTER(LEN=40) :: YUNITS - CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME - INTEGER(KIND=IDCDF_KIND) :: IVARID - INTEGER(KIND=IDCDF_KIND) :: IVDIM - INTEGER(KIND=IDCDF_KIND) :: STATUS - TYPE(DATE_TIME) :: TZREF - - - IF (ASSOCIATED(TDTCUR) .AND. ASSOCIATED(TDTMOD)) THEN - YVARNAME = TRIM(TDIM%NAME) - IVDIM = TDIM%ID - - STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) - IF (STATUS /= NF90_NOERR) THEN - ! Define the coordinate variable -#if (MNH_REAL == 8) - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) -#else - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) -#endif - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_TIME_COORD[NF90_DEF_VAR]') - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_TIME_COORD',TRIM(YVARNAME)//' already defined') - END IF - - ! Write metadata - STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name','time axis') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name','time') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - WRITE(YUNITS,'( "seconds since ",I4.4,"-",I2.2,"-",I2.2," 00:00:00 +0:00" )') & - TDTMOD%TDATE%YEAR,TDTMOD%TDATE%MONTH,TDTMOD%TDATE%DAY - STATUS = NF90_PUT_ATT(INCID, IVARID, 'units',YUNITS) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis','T') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - STATUS = NF90_PUT_ATT(INCID, IVARID,'calendar','standard') - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_ATT]') - - ! Model beginning date (TDTMOD%TDATE) is used as the reference date - ! Reference time is set to 0. - TZREF = TDTMOD - TZREF%TIME = 0. - ! Compute the temporal distance from reference - CALL DATETIME_DISTANCE(TZREF,TDTCUR,ZDELTATIME) - ! Write the data - STATUS = NF90_PUT_VAR(INCID, IVARID, ZDELTATIME) - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) - END IF - -END SUBROUTINE WRITE_TIME_COORD - -END SUBROUTINE IO_WRITE_COORDVAR_NC4 - - -SUBROUTINE HANDLE_ERR(STATUS,LINE,TEXT,KRESP) -INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: STATUS -INTEGER, INTENT(IN) :: LINE -CHARACTER(LEN=*), INTENT(IN) :: TEXT -INTEGER, OPTIONAL, INTENT(OUT) :: KRESP - -CHARACTER(LEN=6) :: YLINE - -WRITE(YLINE,'( I6 )') LINE - -! Don't stop (by default) the code when KRESP is present -! and ensure KRESP is a negative integer -IF (STATUS /= NF90_NOERR) THEN - IF (PRESENT(KRESP)) THEN - IF (STATUS < 0) THEN - KRESP = STATUS - ELSE IF (STATUS == 0) THEN - KRESP = -1 - ELSE - KRESP = -STATUS - END IF - CALL PRINT_MSG(NVERB_WARNING,'IO',TRIM(TEXT),'NetCDF error at line '//TRIM(YLINE)//': '//TRIM(NF90_STRERROR(STATUS))) - ELSE - CALL PRINT_MSG(NVERB_FATAL,'IO',TRIM(TEXT),'NetCDF error at line '//TRIM(YLINE)//': '//TRIM(NF90_STRERROR(STATUS))) - END IF -END IF -END SUBROUTINE HANDLE_ERR - -FUNCTION str_replace(hstr, hold, hnew) -CHARACTER(LEN=*) :: hstr, hold, hnew -CHARACTER(LEN=LEN_TRIM(hstr)+MAX(0,LEN(hnew)-LEN(hold))) :: str_replace - -INTEGER :: pos - -pos = INDEX(hstr,hold) -IF (pos /= 0) THEN - str_replace = hstr(1:pos-1)//hnew//hstr(pos+LEN(hold):) -ELSE - str_replace = hstr -END IF - -END FUNCTION str_replace - -SUBROUTINE IO_WRITE_HEADER_NC4(TPFILE) -! -USE MODD_IO_ll, ONLY: TFILEDATA -! -TYPE(TFILEDATA), INTENT(IN) :: TPFILE ! File structure -! -INTEGER(KIND=IDCDF_KIND) :: ISTATUS -! -IF (TRIM(TPFILE%CFORMAT)/='NETCDF4' .AND. TRIM(TPFILE%CFORMAT)/='LFICDF4') RETURN -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_HEADER_NC4','called for file '//TRIM(TPFILE%CNAME)) -! -IF (TPFILE%LMASTER) THEN - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'Conventions', 'CF-1.7 COMODO-1.4') - IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') - -#if (MNH_REAL == 8) - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_REAL', '8') -#else - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_REAL', '4') -#endif - IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') - -#if (MNH_INT == 4) - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_INT', '4') -#else - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_INT', '8') -#endif - IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') - -!title - - !history - CALL IO_APPEND_HISTORY_NC4(TPFILE) - -!institution - -!source - -!comment - -!references -END IF -! -END SUBROUTINE IO_WRITE_HEADER_NC4 - - -SUBROUTINE IO_APPEND_HISTORY_NC4(TPFILE) -! -USE MODD_IO_ll, ONLY: TFILEDATA -! -TYPE(TFILEDATA), INTENT(IN) :: TPFILE ! File structure -! -INTEGER,PARAMETER :: YEAR=1, MONTH=2, DAY=3, HH=5, MM=6, SS=7 -! -CHARACTER(len=5) :: YZONE -CHARACTER(LEN=:),ALLOCATABLE :: YCMD, YHISTORY, YHISTORY_NEW, YHISTORY_PREV -INTEGER :: ILEN_CMD, ILEN_PREV -INTEGER(KIND=IDCDF_KIND) :: ISTATUS -INTEGER,DIMENSION(8) :: IDATETIME -! -IF (TRIM(TPFILE%CFORMAT)/='NETCDF4' .AND. TRIM(TPFILE%CFORMAT)/='LFICDF4') RETURN -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_APPEND_HISTORY_NC4','called for file '//TRIM(TPFILE%CNAME)) -! -IF (TPFILE%LMASTER) THEN - !Check if history attribute already exists in file and read it - ISTATUS = NF90_INQUIRE_ATTRIBUTE(TPFILE%NNCID, NF90_GLOBAL, 'history', LEN=ILEN_PREV) - IF (ISTATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN_PREV) :: YHISTORY_PREV) - ISTATUS = NF90_GET_ATT(TPFILE%NNCID, NF90_GLOBAL, 'history', YHISTORY_PREV) - IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_APPEND_HISTORY_NC4[NF90_GET_ATT]') - YHISTORY_PREV = YHISTORY_PREV - ELSE - ILEN_PREV = 0 - END IF - - !Get date and time - call DATE_AND_TIME( VALUES=IDATETIME, ZONE=YZONE ) - call GET_COMMAND(lENGTH=ILEN_CMD) - IF (ILEN_CMD>0) THEN - ALLOCATE(CHARACTER(ILEN_CMD) :: YCMD) - CALL GET_COMMAND(COMMAND=YCMD) - END IF - - !Prepare new history entry - ALLOCATE(CHARACTER(26+ILEN_CMD) :: YHISTORY_NEW) - WRITE(YHISTORY_NEW, '( I4.4,"-",I2.2,"-",I2.2,"T",I2.2,":",I2.2,":",I2.2,A5,": ", A )') & - IDATETIME(YEAR),IDATETIME(MONTH),IDATETIME(DAY),IDATETIME(HH),IDATETIME(MM),IDATETIME(SS),YZONE, YCMD - - !Write full history - IF (ILEN_PREV == 0) THEN - YHISTORY = YHISTORY_NEW - ELSE - YHISTORY = YHISTORY_NEW//NEW_LINE('A')//YHISTORY_PREV - END IF - ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'history', YHISTORY ) - IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_APPEND_HISTORY_NC4[NF90_PUT_ATT]') -END IF - -END SUBROUTINE IO_APPEND_HISTORY_NC4 - - -SUBROUTINE IO_WRITE_FIELD_ATTR_NC4(TPFILE,TPFIELD,KVARID,OEXISTED,KSHAPE,HCALENDAR,OISCOORD) -! -USE MODD_CONF, ONLY: CPROGRAM, LCARTESIAN -USE MODD_CONF_n, ONLY: CSTORAGE_TYPE -! -USE MODE_FIELD, ONLY: TYPEINT, TYPEREAL -! -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD -INTEGER(KIND=IDCDF_KIND), INTENT(IN) :: KVARID -LOGICAL, INTENT(IN) :: OEXISTED !True if variable was already defined -INTEGER(KIND=IDCDF_KIND),DIMENSION(:),OPTIONAL,INTENT(IN) :: KSHAPE -CHARACTER(LEN=*), OPTIONAL,INTENT(IN) :: HCALENDAR -LOGICAL, OPTIONAL,INTENT(IN) :: OISCOORD ! Is a coordinate variable (->do not write coordinates attribute) -! -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: STATUS -CHARACTER(LEN=:),ALLOCATABLE :: YCOORDS -LOGICAL :: GISCOORD -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','called for field '//TRIM(TPFIELD%CMNHNAME)) -! -IF(LEN_TRIM(TPFIELD%CSTDNAME)==0 .AND. LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_ATTR_NC4','at least long_name or standard_name must be provided & - &to respect CF-convention for variable '//TRIM(TPFIELD%CMNHNAME)) -ENDIF -! -IF (TPFIELD%NDIMS>1 .AND. .NOT.PRESENT(KSHAPE)) & - CALL PRINT_MSG(NVERB_FATAL,'IO','IO_WRITE_FIELD_ATTR_NC4','KSHAPE not provided for '//TRIM(TPFIELD%CMNHNAME)) -! -IF (PRESENT(OISCOORD)) THEN - GISCOORD = OISCOORD -ELSE - GISCOORD = .FALSE. -END IF -! -INCID = TPFILE%NNCID -! -! Standard_name attribute definition (CF convention) -IF(LEN_TRIM(TPFIELD%CSTDNAME)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CSTDNAME not set for variable '//TRIM(TPFIELD%CMNHNAME)) -ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'standard_name', TRIM(TPFIELD%CSTDNAME)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -! Long_name attribute definition (CF convention) -IF(LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CLONGNAME not set for variable '//TRIM(TPFIELD%CMNHNAME)) -ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'long_name', TRIM(TPFIELD%CLONGNAME)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -! Canonical units attribute definition (CF convention) -IF(LEN_TRIM(TPFIELD%CUNITS)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CUNITS not set for variable '//TRIM(TPFIELD%CMNHNAME)) -ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'units', TRIM(TPFIELD%CUNITS)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -! GRID attribute definition -IF(TPFIELD%NGRID<0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%NGRID not set for variable '//TRIM(TPFIELD%CMNHNAME)) -!Do not write GRID attribute if NGRID=0 -ELSE IF (TPFIELD%NGRID>0) THEN - STATUS = NF90_PUT_ATT(INCID, KVARID, 'grid', TPFIELD%NGRID) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -! COMMENT attribute definition -IF(LEN_TRIM(TPFIELD%CCOMMENT)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','TPFIELD%CCOMMENT not set for variable '//TRIM(TPFIELD%CMNHNAME)) -ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'comment', TRIM(TPFIELD%CCOMMENT)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -! Calendar (CF convention) -IF(PRESENT(HCALENDAR)) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','CALENDAR provided for variable '//TRIM(TPFIELD%CMNHNAME)) - STATUS = NF90_PUT_ATT(INCID, KVARID,'calendar', TRIM(HCALENDAR)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF +! Calendar (CF convention) +IF(PRESENT(HCALENDAR)) THEN + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_FIELD_ATTR_NC4','CALENDAR provided for variable '//TRIM(TPFIELD%CMNHNAME)) + STATUS = NF90_PUT_ATT(INCID, KVARID,'calendar', TRIM(HCALENDAR)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') +ENDIF ! ! Coordinates (CF convention) IF (.NOT.GISCOORD) THEN @@ -943,425 +199,43 @@ IF(TPFIELD%NTYPE==TYPEINT .AND. TPFIELD%NDIMS>0) THEN ! STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_max',TPFIELD%NVALIDMAX) IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -IF(TPFIELD%NTYPE==TYPEREAL .AND. TPFIELD%NDIMS>0) THEN - IF (TPFIELD%XFILLVALUE>=TPFIELD%XVALIDMIN .AND. TPFIELD%XFILLVALUE<=TPFIELD%XVALIDMAX) & - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_ATTR_NC4','_FillValue is not outside of valid_min - valid_max'// & - 'interval for variable '//TRIM(TPFIELD%CMNHNAME)) - ! - ! Fillvalue (CF/COMODO convention) - ! Remarks: * the attribute '_FillValue' is also recognized by the netCDF library - ! and is used when pre-filling a variable - ! * it cannot be modified if some data has already been written (->check OEXISTED) - IF(.NOT.OEXISTED) THEN - IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN - STATUS = NF90_PUT_ATT(INCID, KVARID,'_FillValue', REAL(TPFIELD%XFILLVALUE,KIND=4)) - ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'_FillValue', TPFIELD%XFILLVALUE) - END IF - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') - END IF - ! - ! Valid_min/max (CF/COMODO convention) - IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN - STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_min', REAL(TPFIELD%XVALIDMIN,KIND=4)) - ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_min', TPFIELD%XVALIDMIN) - END IF - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') - ! - IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN - STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_max', REAL(TPFIELD%XVALIDMAX,KIND=4)) - ELSE - STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_max',TPFIELD%XVALIDMAX) - END IF - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') -ENDIF -! -END SUBROUTINE IO_WRITE_FIELD_ATTR_NC4 - -FUNCTION GETDIMCDF(TPFILE, KLEN, HDIMNAME) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: KLEN -CHARACTER(LEN=*), OPTIONAL :: HDIMNAME ! When provided don't search but - ! simply create with name HDIMNAME -TYPE(DIMCDF), POINTER :: GETDIMCDF - -TYPE(DIMCDF), POINTER :: TMP -INTEGER :: COUNT -CHARACTER(LEN=16) :: YSUFFIX -CHARACTER(LEN=20) :: YDIMNAME -INTEGER(KIND=IDCDF_KIND) :: STATUS -LOGICAL :: GCHKLEN !Check if KLEN is valid -TYPE(IOCDF), POINTER :: PIOCDF - -CALL PRINT_MSG(NVERB_DEBUG,'IO','GETDIMCDF','called') - -PIOCDF => TPFILE%TNCDIMS - -GCHKLEN = .TRUE. -!Do not check KLEN if 'time' (because NF90_UNLIMITED = 0) -IF (PRESENT(HDIMNAME)) THEN - IF (TRIM(HDIMNAME)=='time') THEN - GCHKLEN = .FALSE. - END IF -END IF - -WRITE(YSUFFIX,'(I0)') KLEN - -IF (GCHKLEN .AND. KLEN < 1) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','GETDIMCDF','KLEN='//TRIM(YSUFFIX)) -END IF - -IF (PRESENT(HDIMNAME)) THEN - NULLIFY(TMP) - YDIMNAME = TRIM(HDIMNAME) -ELSE - ! Search dimension with KLEN length - COUNT = 1 - TMP => PIOCDF%DIMLIST - DO WHILE(ASSOCIATED(TMP)) - IF (TMP%LEN == KLEN .AND. TMP%NAME(1:4) /= 'char') EXIT - TMP=>TMP%NEXT - COUNT = COUNT+1 - END DO - YDIMNAME = 'size'//TRIM(YSUFFIX) -END IF - -IF (.NOT. ASSOCIATED(TMP)) THEN - ! Not found then define new dimension - ALLOCATE(TMP) - TMP%NAME = YDIMNAME - TMP%LEN = KLEN - STATUS = NF90_DEF_DIM(TPFILE%NNCID, TMP%NAME, KLEN, TMP%ID) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'GETDIMCDF[NF90_DEF_DIM]') - NULLIFY(TMP%NEXT) - TMP%NEXT => PIOCDF%DIMLIST - PIOCDF%DIMLIST => TMP -CALL PRINT_MSG(NVERB_DEBUG,'IO','GETDIMCDF','new dimension: '//TRIM(TMP%NAME)) -END IF - -GETDIMCDF => TMP - -END FUNCTION GETDIMCDF - - -FUNCTION GETSTRDIMID(TPFILE,KLEN) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -INTEGER(KIND=IDCDF_KIND),INTENT(IN) :: KLEN -INTEGER(KIND=IDCDF_KIND) :: GETSTRDIMID - -TYPE(DIMCDF), POINTER :: TMP -TYPE(IOCDF), POINTER :: TZIOCDF -CHARACTER(LEN=16) :: YSUFFIX -INTEGER(KIND=IDCDF_KIND) :: STATUS - -CALL PRINT_MSG(NVERB_DEBUG,'IO','GETSTRDIMID','called') - -WRITE(YSUFFIX,'(I0)') KLEN - -IF (KLEN < 1) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','GETSTRDIMID','KLEN='//TRIM(YSUFFIX)) -END IF - -! Search string dimension with KLEN length -TMP => TPFILE%TNCDIMS%DIMSTR -DO WHILE(ASSOCIATED(TMP)) - IF (TMP%LEN == KLEN) EXIT - TMP=>TMP%NEXT -END DO - -IF (.NOT. ASSOCIATED(TMP)) THEN - ! Not found then define new dimension - ALLOCATE(TMP) - TMP%NAME = 'char'//TRIM(YSUFFIX) - TMP%LEN = KLEN - STATUS = NF90_DEF_DIM(TPFILE%NNCID, TMP%NAME, KLEN, TMP%ID) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'GETSTRDIMID[NF90_DEF_DIM]') - NULLIFY(TMP%NEXT) - TMP%NEXT => TPFILE%TNCDIMS%DIMSTR - TZIOCDF => TPFILE%TNCDIMS - TZIOCDF%DIMSTR => TMP -END IF - -GETSTRDIMID = TMP%ID - -END FUNCTION GETSTRDIMID - - -SUBROUTINE IO_FIND_DIM_BYNAME_NC4(TPFILE, HDIMNAME, TPDIM, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -CHARACTER(LEN=*), INTENT(IN) :: HDIMNAME -TYPE(DIMCDF), INTENT(OUT) :: TPDIM -INTEGER, INTENT(OUT) :: KRESP -! -TYPE(DIMCDF), POINTER :: TMP -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_FIND_DIM_BYNAME_NC4','called for dimension name '//TRIM(HDIMNAME)) -! -KRESP = -2 -! -IF(.NOT.ASSOCIATED(TPFILE%TNCDIMS%DIMLIST)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_FIND_DIM_BYNAME_NC4','DIMLIST not associated for file '//TRIM(TPFILE%CNAME)) - KRESP = -1 - RETURN -END IF -! -TMP => TPFILE%TNCDIMS%DIMLIST -! -DO WHILE(ASSOCIATED(TMP)) - IF (TRIM(TMP%NAME)==TRIM(HDIMNAME)) THEN - TPDIM = TMP - KRESP = 0 - EXIT - END IF - TMP => TMP%NEXT -END DO -! -END SUBROUTINE IO_FIND_DIM_BYNAME_NC4 - - -SUBROUTINE FILLVDIMS(TPFILE, TPFIELD, KSHAPE, KVDIMS) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD -INTEGER(KIND=IDCDF_KIND),DIMENSION(:),INTENT(IN) :: KSHAPE -INTEGER(KIND=IDCDF_KIND),DIMENSION(:),ALLOCATABLE,INTENT(OUT) :: KVDIMS -! -INTEGER :: IGRID -INTEGER :: JI -CHARACTER(LEN=32) :: YINT -CHARACTER(LEN=2) :: YDIR -TYPE(DIMCDF), POINTER :: PTDIM -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','FILLVDIMS','called for '//TRIM(TPFIELD%CMNHNAME)) -! -IF (SIZE(KSHAPE) < 1 .AND. .NOT.TPFIELD%LTIMEDEP) CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','empty KSHAPE') -! -IGRID = TPFIELD%NGRID -YDIR = TPFIELD%CDIR -! -IF(SIZE(KSHAPE)/=TPFIELD%NDIMS) THEN - WRITE(YINT,'( I0,"/",I0 )') SIZE(KSHAPE),TPFIELD%NDIMS - CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','SIZE(KSHAPE)/=TPFIELD%NDIMS ('//TRIM(YINT)//') for field ' & - //TRIM(TPFIELD%CMNHNAME)) -END IF -! -IF (TPFIELD%LTIMEDEP) THEN - !Add time dimension - ALLOCATE(KVDIMS(TPFIELD%NDIMS+1)) - KVDIMS(TPFIELD%NDIMS+1) = TPFILE%TNCDIMS%DIMTIME%ID -ELSE - ALLOCATE(KVDIMS(TPFIELD%NDIMS)) -END IF -! -IF(IGRID<0 .OR. IGRID>8) THEN - WRITE(YINT,'( I0 )') IGRID - CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','invalid NGRID ('//TRIM(YINT)//') for field '//TRIM(TPFIELD%CMNHNAME)) -END IF -! -IF(IGRID==0 .AND. YDIR/='--' .AND. YDIR/='' ) THEN - CALL PRINT_MSG(NVERB_FATAL,'IO','FILLVDIMS','invalid YDIR ('//TRIM(YDIR)//') with NGRID=0 for field '//TRIM(TPFIELD%CMNHNAME)) -END IF -! -DO JI=1,SIZE(KSHAPE) - IF (JI == 1) THEN - IF ( (YDIR == 'XX' .OR. YDIR == 'XY') .AND. KSHAPE(1)==TPFILE%TNCCOORDS(1,IGRID)%TDIM%LEN) THEN - KVDIMS(1) = TPFILE%TNCCOORDS(1,IGRID)%TDIM%ID - ELSE IF ( YDIR == 'YY' .AND. KSHAPE(1)==TPFILE%TNCCOORDS(2,IGRID)%TDIM%LEN) THEN - KVDIMS(1) = TPFILE%TNCCOORDS(2,IGRID)%TDIM%ID - ELSE IF ( YDIR == 'ZZ' .AND. KSHAPE(1)==TPFILE%TNCCOORDS(3,IGRID)%TDIM%LEN) THEN - KVDIMS(1) = TPFILE%TNCCOORDS(3,IGRID)%TDIM%ID - ELSE - PTDIM => GETDIMCDF(TPFILE, KSHAPE(1)); KVDIMS(1) = PTDIM%ID - END IF - ELSE IF (JI == 2) THEN - IF ( YDIR == 'XY' .AND. KSHAPE(2)==TPFILE%TNCCOORDS(2,IGRID)%TDIM%LEN) THEN - KVDIMS(2) = TPFILE%TNCCOORDS(2,IGRID)%TDIM%ID - ELSE - PTDIM => GETDIMCDF(TPFILE, KSHAPE(2)); KVDIMS(2) = PTDIM%ID - END IF - ELSE IF (JI == 3) THEN - IF ( YDIR == 'XY' .AND. KSHAPE(3)==TPFILE%TNCCOORDS(3,IGRID)%TDIM%LEN) THEN - KVDIMS(3) = TPFILE%TNCCOORDS(3,IGRID)%TDIM%ID +ENDIF +! +IF(TPFIELD%NTYPE==TYPEREAL .AND. TPFIELD%NDIMS>0) THEN + IF (TPFIELD%XFILLVALUE>=TPFIELD%XVALIDMIN .AND. TPFIELD%XFILLVALUE<=TPFIELD%XVALIDMAX) & + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_ATTR_NC4','_FillValue is not outside of valid_min - valid_max'// & + 'interval for variable '//TRIM(TPFIELD%CMNHNAME)) + ! + ! Fillvalue (CF/COMODO convention) + ! Remarks: * the attribute '_FillValue' is also recognized by the netCDF library + ! and is used when pre-filling a variable + ! * it cannot be modified if some data has already been written (->check OEXISTED) + IF(.NOT.OEXISTED) THEN + IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN + STATUS = NF90_PUT_ATT(INCID, KVARID,'_FillValue', REAL(TPFIELD%XFILLVALUE,KIND=4)) ELSE - PTDIM => GETDIMCDF(TPFILE, KSHAPE(3)); KVDIMS(3) = PTDIM%ID + STATUS = NF90_PUT_ATT(INCID, KVARID,'_FillValue', TPFIELD%XFILLVALUE) END IF - ELSE - PTDIM => GETDIMCDF(TPFILE, KSHAPE(JI)); KVDIMS(JI) = PTDIM%ID - END IF -END DO -! -END SUBROUTINE FILLVDIMS - - -SUBROUTINE IO_GUESS_DIMIDS_NC4(TPFILE, TPFIELD, KLEN, TPDIMS, KRESP) -! -USE MODE_FIELD, ONLY: TYPECHAR -! -!Used by LFI2CDF -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD -INTEGER, INTENT(IN) :: KLEN -TYPE(DIMCDF),DIMENSION(:), INTENT(OUT) :: TPDIMS -INTEGER, INTENT(OUT) :: KRESP -! -INTEGER :: IGRID -INTEGER :: ILEN, ISIZE -INTEGER :: JI -CHARACTER(LEN=32) :: YINT -CHARACTER(LEN=2) :: YDIR -TYPE(DIMCDF), POINTER :: PTDIM -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_GUESS_DIMIDS_NC4','called for '//TRIM(TPFIELD%CMNHNAME)) -! -IGRID = TPFIELD%NGRID -YDIR = TPFIELD%CDIR -! -KRESP = 0 -ILEN = 0 -PTDIM => NULL() -! -IF(IGRID<0 .OR. IGRID>8) THEN - WRITE(YINT,'( I0 )') IGRID - CALL PRINT_MSG(NVERB_FATAL,'IO','IO_GUESS_DIMIDS_NC4','invalid NGRID ('//TRIM(YINT)//') for field '//TRIM(TPFIELD%CMNHNAME)) -END IF -! -IF(IGRID==0 .AND. YDIR/='--' .AND. YDIR/='' ) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','invalid YDIR ('//TRIM(YDIR)//') with NGRID=0 for field '& - //TRIM(TPFIELD%CMNHNAME)) -END IF -! -IF (IGRID==0) THEN - SELECT CASE(TPFIELD%NDIMS) - CASE (0) - IF (TPFIELD%NTYPE == TYPECHAR) THEN - ILEN = KLEN - ELSE - ILEN = 1 - END IF - CASE (1) - PTDIM => GETDIMCDF(TPFILE,KLEN) - TPDIMS(1) = PTDIM - ILEN = PTDIM%LEN - CASE DEFAULT - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','NGRID=0 and NDIMS>1 not yet supported (field '& - //TRIM(TPFIELD%CMNHNAME)//')') - END SELECT -ELSE IF (TPFIELD%CLBTYPE/='NONE') THEN - IF (TPFIELD%NDIMS/=3) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','CLBTYPE/=NONE and NDIMS/=3 not supported (field '& - //TRIM(TPFIELD%CMNHNAME)//')') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') END IF ! - IF (TPFIELD%CLBTYPE=='LBX' .OR. TPFIELD%CLBTYPE=='LBXU') THEN - PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM - TPDIMS(2) = PTDIM - PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM - TPDIMS(3) = PTDIM - ILEN = TPDIMS(2)%LEN * TPDIMS(3)%LEN - ISIZE = KLEN/ILEN - IF (MOD(KLEN,ILEN)/=0) CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & - 'can not guess 1st dimension for field '//TRIM(TPFIELD%CMNHNAME)) - PTDIM => GETDIMCDF(TPFILE, ISIZE) - TPDIMS(1) = PTDIM - ILEN = ILEN * PTDIM%LEN - ELSE IF (TPFIELD%CLBTYPE=='LBY' .OR. TPFIELD%CLBTYPE=='LBYV') THEN - PTDIM => TPFILE%TNCCOORDS(1,IGRID)%TDIM - TPDIMS(1) = PTDIM - PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM - TPDIMS(3) = PTDIM - ILEN = TPDIMS(1)%LEN * TPDIMS(3)%LEN - ISIZE = KLEN/ILEN - IF (MOD(KLEN,ILEN)/=0) CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & - 'can not guess 2nd dimension for field '//TRIM(TPFIELD%CMNHNAME)) - PTDIM => GETDIMCDF(TPFILE, ISIZE) - TPDIMS(2) = PTDIM - ILEN = ILEN * PTDIM%LEN + ! Valid_min/max (CF/COMODO convention) + IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN + STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_min', REAL(TPFIELD%XVALIDMIN,KIND=4)) ELSE - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','invalid CLBTYPE ('//TPFIELD%CLBTYPE//') for field '& - //TRIM(TPFIELD%CMNHNAME)) + STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_min', TPFIELD%XVALIDMIN) END IF -ELSE - IF (TPFIELD%NDIMS==0) ILEN = 1 + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') ! - DO JI=1,TPFIELD%NDIMS - IF (JI == 1) THEN - IF ( (YDIR == 'XX' .OR. YDIR == 'XY') ) THEN - PTDIM => TPFILE%TNCCOORDS(1,IGRID)%TDIM - ELSE IF ( YDIR == 'YY' ) THEN - PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM - ELSE IF ( YDIR == 'ZZ' ) THEN - PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM - ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension - PTDIM => GETDIMCDF(TPFILE, KLEN) - END IF - ILEN = PTDIM%LEN - TPDIMS(JI) = PTDIM - ELSE IF (JI == 2) THEN - IF ( YDIR == 'XY') THEN - PTDIM => TPFILE%TNCCOORDS(2,IGRID)%TDIM - ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension - ISIZE = KLEN/ILEN - IF (MOD(KLEN,ILEN)/=0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & - 'can not guess 2nd and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) - EXIT - END IF - PTDIM => GETDIMCDF(TPFILE, ISIZE) - ELSE - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess 2nd dimension for field '//TRIM(TPFIELD%CMNHNAME)) - EXIT - END IF - ILEN = ILEN * PTDIM%LEN - TPDIMS(JI) = PTDIM - ELSE IF (JI == 3) THEN - IF ( YDIR == 'XY' ) THEN - IF (JI==TPFIELD%NDIMS .AND. KLEN/ILEN==1 .AND. MOD(KLEN,ILEN)==0) THEN - !The last dimension is of size 1 => probably time dimension - ISIZE = 1 - PTDIM => GETDIMCDF(TPFILE,ISIZE) - ELSE - PTDIM => TPFILE%TNCCOORDS(3,IGRID)%TDIM - END IF - ELSE IF (JI==TPFIELD%NDIMS) THEN !Guess last dimension - ISIZE = KLEN/ILEN - IF (MOD(KLEN,ILEN)/=0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & - 'can not guess 3rd and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) - EXIT - END IF - PTDIM => GETDIMCDF(TPFILE, ISIZE) - ELSE - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess 3rd dimension for field '//TRIM(TPFIELD%CMNHNAME)) - EXIT - END IF - ILEN = ILEN * PTDIM%LEN - TPDIMS(JI) = PTDIM - ELSE IF (JI==4 .AND. JI==TPFIELD%NDIMS) THEN !Guess last dimension - ISIZE = KLEN/ILEN - IF (MOD(KLEN,ILEN)/=0) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4', & - 'can not guess 4th and last dimension for field '//TRIM(TPFIELD%CMNHNAME)) - EXIT - END IF - PTDIM => GETDIMCDF(TPFILE, ISIZE) - ILEN = ILEN * PTDIM%LEN - TPDIMS(JI) = PTDIM - ELSE - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_GUESS_DIMIDS_NC4','can not guess dimension above 4 for field '& - //TRIM(TPFIELD%CMNHNAME)) - END IF - END DO -END IF -! -IF (KLEN /= ILEN) THEN - CALL PRINT_MSG(NVERB_INFO,'IO','IO_GUESS_DIMIDS_NC4','can not guess dimensions of field '& - //TRIM(TPFIELD%CMNHNAME)) - KRESP = 1 -END IF + IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN + STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_max', REAL(TPFIELD%XVALIDMAX,KIND=4)) + ELSE + STATUS = NF90_PUT_ATT(INCID, KVARID,'valid_max',TPFIELD%XVALIDMAX) + END IF + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_ATTR_NC4 [NF90_PUT_ATT]') +ENDIF ! -END SUBROUTINE IO_GUESS_DIMIDS_NC4 +END SUBROUTINE IO_WRITE_FIELD_ATTR_NC4 SUBROUTINE IO_WRITE_FIELD_NC4_X0(TPFILE,TPFIELD,PFIELD,KRESP) @@ -1422,7 +296,7 @@ CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,GEXISTED) ! Write the data STATUS = NF90_PUT_VAR(INCID, IVARID, PFIELD) IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_X0[NF90_PUT_VAR] '//TRIM(TPFIELD%CMNHNAME),IRESP) - + KRESP = IRESP END SUBROUTINE IO_WRITE_FIELD_NC4_X0 @@ -1464,7 +338,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1559,7 +433,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TZFILE, TZFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TZFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1585,7 +459,7 @@ CALL IO_WRITE_FIELD_ATTR_NC4(TZFILE,TZFIELD,IVARID,GEXISTED,KSHAPE=INT(SHAPE(PFI ! Write the data STATUS = NF90_PUT_VAR(INCID, IVARID, PFIELD) IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_X2[NF90_PUT_VAR] '//TRIM(TZFIELD%CMNHNAME),IRESP) - + IF(ALLOCATED(IVDIMS)) DEALLOCATE(IVDIMS) KRESP = IRESP @@ -1630,7 +504,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1701,7 +575,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1772,7 +646,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1843,7 +717,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(PFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable IF (TPFILE%LNCREDUCE_FLOAT_PRECISION) THEN STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIMS, IVARID) ELSE @@ -1960,7 +834,7 @@ IF (YVARNAME == 'KMAX' .AND. .NOT. ASSOCIATED(TPFILE%TNCDIMS%DIM_LEVEL)) THEN TZIOCDF => TPFILE%TNCDIMS TZIOCDF%DIM_LEVEL=>GETDIMCDF(TPFILE,INT(KFIELD+2*JPVEXT,KIND=IDCDF_KIND),'Z') END IF - + KRESP = IRESP END SUBROUTINE IO_WRITE_FIELD_NC4_N0 @@ -2008,7 +882,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(KFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable #if ( MNH_INT == 4 ) STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_INT, IVDIMS, IVARID) #else @@ -2070,7 +944,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(KFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable #if ( MNH_INT == 4 ) STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_INT, IVDIMS, IVARID) #else @@ -2136,7 +1010,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(KFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable #if ( MNH_INT == 4 ) STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_INT, IVDIMS, IVARID) #else @@ -2270,7 +1144,7 @@ IF (STATUS /= NF90_NOERR) THEN ! Get the netcdf dimensions CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(OFIELD),KIND=IDCDF_KIND), IVDIMS) - ! Define the variable + ! Define the variable ! Use of NF90_INT1 datatype (=NF90_BYTE) that is enough to store a boolean STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_INT1, IVDIMS, IVARID) IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_L1[NF90_DEF_VAR]') @@ -2337,9 +1211,9 @@ IF (TPFIELD%LTIMEDEP) & ! The variable should not already exist but who knows ? STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - ! Get the netcdf string dimensions id + ! Get the netcdf string dimensions id IVDIMS(1) = GETSTRDIMID(TPFILE,INT(ILEN,KIND=IDCDF_KIND)) - ! Define the variable + ! Define the variable STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_CHAR, IVDIMS, IVARID) IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_C0[NF90_DEF_VAR]') ELSE @@ -2405,11 +1279,11 @@ END IF ! The variable should not already exist but who knows ? STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - ! Get the netcdf string dimensions id + ! Get the netcdf string dimensions id IVDIMS(1) = GETSTRDIMID(TPFILE,ILEN) CALL FILLVDIMS(TPFILE, TPFIELD, (/ISIZE/), IVDIMSTMP) IVDIMS(2) = IVDIMSTMP(1) - ! Define the variable + ! Define the variable STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_CHAR, IVDIMS, IVARID) IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_C1[NF90_DEF_VAR]') ELSE @@ -2486,1345 +1360,663 @@ WRITE(YUNITS,'( "seconds since ",I4.4,"-",I2.2,"-",I2.2," 00:00:00 +0:00" )') & TZFIELD%CUNITS = TRIM(YUNITS) ! IF (TPFIELD%LTIMEDEP) & - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)// & - ': time dependent variable not (yet) possible for 0D variable '//TRIM(TPFIELD%CMNHNAME)) -! -! The variable should not already exist but who knows ? -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - ! Define the scalar variable -#if (MNH_REAL == 8) - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVARID) -#else - STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVARID) -#endif - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') -ELSE - GEXISTED = .TRUE. - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)//' already defined') -END IF - -! Write metadata -CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED,HCALENDAR='standard') -! -! Compute the temporal distance from reference -CALL DATETIME_DISTANCE(TZREF,TPDATA,ZDELTATIME) - -! Write the data -STATUS = NF90_PUT_VAR(INCID, IVARID, ZDELTATIME) -IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_X0[NF90_PUT_VAR] '//TRIM(TPFIELD%CMNHNAME),IRESP) - -IF (IRESP/=0) THEN - KRESP = IRESP - RETURN -END IF - -#if 0 -!This part is to keep backward compatibility with MesoNH files -!but date/time is not conform to CF convention -! -! Write date -! -TZFIELD%CMNHNAME = TRIM(YVARNAME)//'__TDATE' -TZFIELD%CLONGNAME = TRIM(TPFIELD%CLONGNAME)//'%TDATE' -TZFIELD%CUNITS = '' -TZFIELD%CCOMMENT = 'YYYYMMDD' - -! The variable should not already exist but who knows ? -STATUS = NF90_INQ_VARID(INCID, TZFIELD%CMNHNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - ! Get the netcdf dimensions - CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(ITDATE),KIND=IDCDF_KIND), IVDIMS) - - ! Define the variable - STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_INT, IVDIMS, IVARID) - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') - CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED) -ELSE - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(TZFIELD%CMNHNAME)//' already defined') -END IF - -! Write the data -STATUS = NF90_PUT_VAR(INCID, IVARID, ITDATE) -IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_PUT_VAR] '//TRIM(TZFIELD%CMNHNAME),IRESP) - -IF (IRESP/=0) THEN - KRESP = IRESP - RETURN -END IF -! -! Write time -! -TZFIELD%CMNHNAME = TRIM(YVARNAME)//'__TIME' -TZFIELD%CLONGNAME = TRIM(TPFIELD%CLONGNAME)//'%TIME' -TZFIELD%CUNITS = 's' -TZFIELD%CCOMMENT = 'SECONDS' - -! The variable should not already exist but who knows ? -STATUS = NF90_INQ_VARID(INCID, TZFIELD%CMNHNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - ! Define the scalar variable -#if (MNH_REAL == 8) - STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_DOUBLE, IVARID) -#else - STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_FLOAT, IVARID) -#endif - IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') - CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED) -ELSE - GEXISTED = .TRUE. - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(TZFIELD%CMNHNAME)//' already defined') -END IF - -! Write the data -STATUS = NF90_PUT_VAR(INCID, IVARID, TPDATA%TIME) -IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_PUT_VAR] '//TRIM(TZFIELD%CMNHNAME),IRESP) -#endif - -KRESP = IRESP -END SUBROUTINE IO_WRITE_FIELD_NC4_T0 -! -! -! Here come the NetCDF READ routines -! -! -SUBROUTINE IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,KVARID,KRESP,HCALENDAR) -! -USE MODD_PARAMETERS, ONLY: NGRIDUNKNOWN -! -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -INTEGER(KIND=IDCDF_KIND), INTENT(IN) :: KVARID -INTEGER, INTENT(OUT) :: KRESP ! return-code -CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HCALENDAR -! -INTEGER :: IERRLEVEL -INTEGER :: ILEN -INTEGER :: IGRID -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: STATUS -CHARACTER(LEN=12) :: YVAL_FILE, YVAL_MEM -CHARACTER(LEN=:),ALLOCATABLE :: YVALUE -LOGICAL :: GOLDMNH !if old version of MesoNH (<5.4, old files without complete and correct metadata) -! -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)//': called for field '//TRIM(TPFIELD%CMNHNAME)) -! -KRESP = 0 -INCID = TPFILE%NNCID -! -GOLDMNH = TPFILE%NMNHVERSION(1)<5 .OR. (TPFILE%NMNHVERSION(1)==5 .AND. TPFILE%NMNHVERSION(2)<4) -! -IF (GOLDMNH) THEN !Set a lower level of error if file comes from an old MesoNH version - IERRLEVEL = NVERB_WARNING -ELSE - IERRLEVEL = NVERB_ERROR -END IF -! -! GRID -! -STATUS = NF90_GET_ATT(INCID,KVARID,'grid',IGRID) -IF (STATUS /= NF90_NOERR) STATUS = NF90_GET_ATT(INCID,KVARID,'GRID',IGRID) -IF (STATUS == NF90_NOERR) THEN - IF (IGRID/=TPFIELD%NGRID) THEN - WRITE(YVAL_FILE,'(I12)') IGRID - WRITE(YVAL_MEM, '(I12)') TPFIELD%NGRID - CALL PRINT_MSG(IERRLEVEL,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected GRID value ('//TRIM(ADJUSTL(YVAL_MEM))// & - ') is different than found in file ('//TRIM(ADJUSTL(YVAL_FILE))//') for variable '//TRIM(TPFIELD%CMNHNAME)) - IF (.NOT.GOLDMNH) THEN !Do not modify probably incorrect grid number (to prevent problems later with other correct files) - TPFIELD%NGRID = IGRID - KRESP = -111 !Used later to broadcast modified metadata - END IF - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected GRID found in file for field '//TRIM(TPFIELD%CMNHNAME)) - ENDIF -ELSE !no GRID - IF (TPFIELD%NGRID==0 .OR. TPFIELD%NGRID==NGRIDUNKNOWN) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': no GRID (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(IERRLEVEL,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected GRID but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF -ENDIF -! -! COMMENT -! -STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'comment', LEN=ILEN) -IF (STATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) - STATUS = NF90_GET_ATT(INCID, KVARID, 'comment', YVALUE) - IF (LEN_TRIM(TPFIELD%CCOMMENT)==0 .AND. LEN_TRIM(YVALUE)>0) THEN - !Expected comment is empty, read comment is not - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': COMMENT found (unexpected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - TPFIELD%CCOMMENT=TRIM(YVALUE) - ELSE IF (TRIM(YVALUE)/=TRIM(TPFIELD%CCOMMENT)) THEN - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected COMMENT ('//TRIM(TPFIELD%CCOMMENT)// & - ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) - TPFIELD%CCOMMENT=TRIM(YVALUE) - KRESP = -111 !Used later to broadcast modified metadata - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected COMMENT found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF - DEALLOCATE(YVALUE) -ELSE !no COMMENT - IF (LEN_TRIM(TPFIELD%CCOMMENT)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': no COMMENT (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected COMMENT but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF -END IF -! -! STDNAME -! -STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'standard_name', LEN=ILEN) -IF (STATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) - STATUS = NF90_GET_ATT(INCID, KVARID, 'standard_name', YVALUE) - IF (TRIM(YVALUE)/=TRIM(TPFIELD%CSTDNAME)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected STDNAME ('//TRIM(TPFIELD%CSTDNAME)// & - ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) - TPFIELD%CSTDNAME=TRIM(YVALUE) - KRESP = -111 !Used later to broadcast modified metadata - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected STDNAME found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF - DEALLOCATE(YVALUE) -ELSE !no STDNAME - IF (LEN_TRIM(TPFIELD%CSTDNAME)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': no STDNAME (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected STDNAME but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF -END IF -! -! LONGNAME -! -STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'long_name', LEN=ILEN) -IF (STATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) - STATUS = NF90_GET_ATT(INCID, KVARID, 'long_name', YVALUE) - IF (TRIM(YVALUE)/=TRIM(TPFIELD%CLONGNAME)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected LONGNAME ('//TRIM(TPFIELD%CLONGNAME)// & - ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) - TPFIELD%CLONGNAME=TRIM(YVALUE) - KRESP = -111 !Used later to broadcast modified metadata - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected LONGNAME found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF - DEALLOCATE(YVALUE) -ELSE !no LONGNAME - IF (LEN_TRIM(TPFIELD%CLONGNAME)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': no LONGNAME (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected LONGNAME but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF -END IF -! -! UNITS -! -STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'units', LEN=ILEN) -IF (STATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) - STATUS = NF90_GET_ATT(INCID, KVARID, 'units', YVALUE) - IF (TRIM(YVALUE)/=TRIM(TPFIELD%CUNITS)) THEN - IF(.NOT.PRESENT(HCALENDAR)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected UNITS ('//TRIM(TPFIELD%CUNITS)// & - ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) - KRESP = -111 !Used later to broadcast modified metadata - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': UNITS found in file for field '//TRIM(TPFIELD%CMNHNAME)//' (will be analysed later)') - END IF - TPFIELD%CUNITS=TRIM(YVALUE) - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected UNITS found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF - DEALLOCATE(YVALUE) -ELSE !no UNITS - IF (LEN_TRIM(TPFIELD%CUNITS)==0) THEN - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': no UNITS (as expected) in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - IF(.NOT.PRESENT(HCALENDAR)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected UNITS but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected UNITS but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) - KRESP = -3 - END IF - END IF -END IF -! -! CALENDAR -! -IF(PRESENT(HCALENDAR)) THEN -STATUS = NF90_INQUIRE_ATTRIBUTE(INCID, KVARID, 'calendar', LEN=ILEN) -IF (STATUS == NF90_NOERR) THEN - ALLOCATE(CHARACTER(LEN=ILEN) :: YVALUE) - STATUS = NF90_GET_ATT(INCID, KVARID, 'calendar', YVALUE) - IF (TRIM(YVALUE)/=TRIM(HCALENDAR)) THEN - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected CALENDAR ('//TRIM(HCALENDAR)// & - ') is different than found ('//TRIM(YVALUE)//') in file for field '//TRIM(TPFIELD%CMNHNAME)) - ELSE - CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected CALENDAR found in file for field '//TRIM(TPFIELD%CMNHNAME)) - END IF - DEALLOCATE(YVALUE) -ELSE !no CALENDAR - CALL PRINT_MSG(NVERB_WARNING,'IO','IO_READ_CHECK_FIELD_ATTR_NC4',TRIM(TPFILE%CNAME)// & - ': expected CALENDAR but not found in file for field '//TRIM(TPFIELD%CMNHNAME)) -END IF -ENDIF -! -END SUBROUTINE IO_READ_CHECK_FIELD_ATTR_NC4 - - -SUBROUTINE IO_READ_FIELD_NC4_X0(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL, INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID - -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) - -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 0 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size or type)') - IRESP = -3 -END IF - -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_X0 - - -SUBROUTINE IO_READ_FIELD_NC4_X1(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -CHARACTER(LEN=30) :: YVARNAME -INTEGER(KIND=IDCDF_KIND) :: IDIMLEN -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID - -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) - -! Get variable ID, NDIMS and TYPE + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)// & + ': time dependent variable not (yet) possible for 0D variable '//TRIM(TPFIELD%CMNHNAME)) +! +! The variable should not already exist but who knows ? STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 1 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF (IDIMLEN == SIZE(PFIELD)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF + ! Define the scalar variable +#if (MNH_REAL == 8) + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVARID) +#else + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVARID) +#endif + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 + GEXISTED = .TRUE. + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)//' already defined') END IF -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_X1 - - -SUBROUTINE IO_READ_FIELD_NC4_X2(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:,:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -CHARACTER(LEN=30) :: YVARNAME -INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN -INTEGER :: IRESP +! Write metadata +CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED,HCALENDAR='standard') +! +! Compute the temporal distance from reference +CALL DATETIME_DISTANCE(TZREF,TPDATA,ZDELTATIME) -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) +! Write the data +STATUS = NF90_PUT_VAR(INCID, IVARID, ZDELTATIME) +IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_X0[NF90_PUT_VAR] '//TRIM(TPFIELD%CMNHNAME),IRESP) -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID +IF (IRESP/=0) THEN + KRESP = IRESP + RETURN +END IF -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) +#if 0 +!This part is to keep backward compatibility with MesoNH files +!but date/time is not conform to CF convention +! +! Write date +! +TZFIELD%CMNHNAME = TRIM(YVARNAME)//'__TDATE' +TZFIELD%CLONGNAME = TRIM(TPFIELD%CLONGNAME)//'%TDATE' +TZFIELD%CUNITS = '' +TZFIELD%CCOMMENT = 'YYYYMMDD' -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +! The variable should not already exist but who knows ? +STATUS = NF90_INQ_VARID(INCID, TZFIELD%CMNHNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -!Treat special case of a degenerated 3D array (3rd dimension size is 1) -IF (IDIMS==3) THEN - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - IF (IDIMLEN(3)==1) THEN - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)// & - ': reading 3D array with degenerated third dimension in 2D array for '//TRIM(YVARNAME)) - IDIMS = 2 - ELSE - CALL PRINT_MSG(NVERB_FATAL,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': wrong number of dimensions for '//TRIM(YVARNAME)) - END IF -END IF - -IF (IDIMS == 2 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + ! Get the netcdf dimensions + CALL FILLVDIMS(TPFILE, TPFIELD, INT(SHAPE(ITDATE),KIND=IDCDF_KIND), IVDIMS) - IF (IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X2[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF + ! Define the variable + STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_INT, IVDIMS, IVARID) + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') + CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED) ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(TZFIELD%CMNHNAME)//' already defined') END IF -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_X2 - - -SUBROUTINE IO_READ_FIELD_NC4_X3(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:,:,:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID +! Write the data +STATUS = NF90_PUT_VAR(INCID, IVARID, ITDATE) +IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_PUT_VAR] '//TRIM(TZFIELD%CMNHNAME),IRESP) -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) +IF (IRESP/=0) THEN + KRESP = IRESP + RETURN +END IF +! +! Write time +! +TZFIELD%CMNHNAME = TRIM(YVARNAME)//'__TIME' +TZFIELD%CLONGNAME = TRIM(TPFIELD%CLONGNAME)//'%TIME' +TZFIELD%CUNITS = 's' +TZFIELD%CCOMMENT = 'SECONDS' -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) +! The variable should not already exist but who knows ? +STATUS = NF90_INQ_VARID(INCID, TZFIELD%CMNHNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 3 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF (IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. IDIMLEN(3) == SIZE(PFIELD,3)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X3[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF + ! Define the scalar variable +#if (MNH_REAL == 8) + STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_DOUBLE, IVARID) +#else + STATUS = NF90_DEF_VAR(INCID, TZFIELD%CMNHNAME, NF90_FLOAT, IVARID) +#endif + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_DEF_VAR]') + CALL IO_WRITE_FIELD_ATTR_NC4(TPFILE,TZFIELD,IVARID,GEXISTED) ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X3',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 + GEXISTED = .TRUE. + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_WRITE_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(TZFIELD%CMNHNAME)//' already defined') END IF -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_X3 - - -SUBROUTINE IO_READ_FIELD_NC4_X4(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:,:,:,:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -INTEGER(KIND=IDCDF_KIND),DIMENSION(4) :: IDIMLEN -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP +! Write the data +STATUS = NF90_PUT_VAR(INCID, IVARID, TPDATA%TIME) +IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_WRITE_FIELD_NC4_T0[NF90_PUT_VAR] '//TRIM(TZFIELD%CMNHNAME),IRESP) +#endif -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) +KRESP = IRESP +END SUBROUTINE IO_WRITE_FIELD_NC4_T0 -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID +SUBROUTINE IO_WRITE_COORDVAR_NC4(TPFILE,HPROGRAM_ORIG) +USE MODD_CONF, ONLY: CPROGRAM, LCARTESIAN +USE MODD_CONF_n, ONLY: CSTORAGE_TYPE +USE MODD_GRID, ONLY: XLATORI, XLONORI +USE MODD_GRID_n, ONLY: LSLEVE, XXHAT, XYHAT, XZHAT +USE MODD_PARAMETERS, ONLY: JPHEXT, JPVEXT -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) +USE MODE_FIELD, ONLY: TFIELDLIST,FIND_FIELD_ID_FROM_MNHNAME +USE MODE_GRIDPROJ +USE MODE_NEST_ll, ONLY: GET_MODEL_NUMBER_ll, GO_TOMODEL_ll -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 4 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & - IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X4[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X4',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 -END IF +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +CHARACTER(LEN=*),OPTIONAL,INTENT(IN) :: HPROGRAM_ORIG !To emulate a file coming from this program -1000 CONTINUE -KRESP = IRESP +CHARACTER(LEN=:),ALLOCATABLE :: YSTDNAMEPREFIX +CHARACTER(LEN=:),ALLOCATABLE :: YPROGRAM +INTEGER :: IIU, IJU, IKU +INTEGER :: ID, IID, IRESP +INTEGER :: IMI +INTEGER(KIND=IDCDF_KIND) :: INCID +LOGICAL :: GCHANGEMODEL +LOGICAL,POINTER :: GSLEVE +REAL,DIMENSION(:),POINTER :: ZXHAT, ZYHAT, ZZHAT +REAL,DIMENSION(:),ALLOCATABLE :: ZXHATM, ZYHATM,ZZHATM !Coordinates at mass points in the transformed space +REAL,DIMENSION(:,:),POINTER :: ZLAT, ZLON +TYPE(IOCDF), POINTER :: PIOCDF -END SUBROUTINE IO_READ_FIELD_NC4_X4 +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_COORDVAR_NC4','called for '//TRIM(TPFILE%CNAME)) +ZXHAT => NULL() +ZYHAT => NULL() +ZZHAT => NULL() -SUBROUTINE IO_READ_FIELD_NC4_X5(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:,:,:,:,:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code +PIOCDF => TPFILE%TNCDIMS -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -INTEGER(KIND=IDCDF_KIND),DIMENSION(5) :: IDIMLEN -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP +GCHANGEMODEL = .FALSE. -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) +IF (PRESENT(HPROGRAM_ORIG)) THEN + YPROGRAM = HPROGRAM_ORIG +ELSE + YPROGRAM = CPROGRAM +ENDIF -IRESP = 0 ! Get the Netcdf file ID INCID = TPFILE%NNCID -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) +IF (TPFILE%NMODEL>0) THEN + CALL FIND_FIELD_ID_FROM_MNHNAME('XHAT',IID,IRESP) + ZXHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA + CALL FIND_FIELD_ID_FROM_MNHNAME('YHAT',IID,IRESP) + ZYHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA + CALL FIND_FIELD_ID_FROM_MNHNAME('ZHAT',IID,IRESP) + ZZHAT => TFIELDLIST(IID)%TFIELD_X1D(TPFILE%NMODEL)%DATA + CALL FIND_FIELD_ID_FROM_MNHNAME('SLEVE',IID,IRESP) + GSLEVE => TFIELDLIST(IID)%TFIELD_L0D(TPFILE%NMODEL)%DATA + ! + CALL GET_MODEL_NUMBER_ll(IMI) + IF (IMI/=TPFILE%NMODEL) THEN + !This is necessary to have correct domain sizes (used by GATHER_XXFIELD) + CALL GO_TOMODEL_ll(TPFILE%NMODEL,IRESP) + GCHANGEMODEL = .TRUE. + END IF +ELSE + ZXHAT => XXHAT + ZYHAT => XYHAT + ZZHAT => XZHAT + GSLEVE => LSLEVE +END IF -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 +IIU = SIZE(ZXHAT) +IJU = SIZE(ZYHAT) +ALLOCATE(ZXHATM(IIU),ZYHATM(IJU)) +!ZXHATM(IIU) and ZYHATM(IJU) are correct only on some processes +!but it is OK due to the way GATHER_XXFIELD is done +ZXHATM(1:IIU-1) = 0.5*(ZXHAT(1:IIU-1)+ZXHAT(2:IIU)) +ZXHATM(IIU) = 2.*ZXHAT(IIU)-ZXHATM(IIU-1) +ZYHATM(1:IJU-1) = 0.5*(ZYHAT(1:IJU-1)+ZYHAT(2:IJU)) +ZYHATM(IJU) = 2.*ZYHAT(IJU)-ZYHATM(IJU-1) +! +IF (LCARTESIAN) THEN + YSTDNAMEPREFIX = 'plane' +ELSE + YSTDNAMEPREFIX = 'projection' +ENDIF +CALL WRITE_HOR_COORD(PIOCDF%DIM_NI,'x-dimension of the grid',TRIM(YSTDNAMEPREFIX)//'_x_coordinate','X',0.,JPHEXT,JPHEXT,ZXHATM) +CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ,'y-dimension of the grid',TRIM(YSTDNAMEPREFIX)//'_y_coordinate','Y',0.,JPHEXT,JPHEXT,ZYHATM) +CALL WRITE_HOR_COORD(PIOCDF%DIM_NI_U,'x-dimension of the grid at u location', & + TRIM(YSTDNAMEPREFIX)//'_x_coordinate_at_u_location','X',-0.5,JPHEXT,0, ZXHAT) +CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ_U,'y-dimension of the grid at u location', & + TRIM(YSTDNAMEPREFIX)//'_y_coordinate_at_u_location','Y', 0., JPHEXT,JPHEXT,ZYHATM) +CALL WRITE_HOR_COORD(PIOCDF%DIM_NI_V,'x-dimension of the grid at v location', & + TRIM(YSTDNAMEPREFIX)//'_x_coordinate_at_v_location','X', 0., JPHEXT,JPHEXT,ZXHATM) +CALL WRITE_HOR_COORD(PIOCDF%DIM_NJ_V,'y-dimension of the grid at v location', & + TRIM(YSTDNAMEPREFIX)//'_y_coordinate_at_v_location','Y',-0.5,JPHEXT,0, ZYHAT) +! +IF (.NOT.LCARTESIAN) THEN + ALLOCATE(ZLAT(IIU,IJU),ZLON(IIU,IJU)) + ! + !Compute latitude/longitude for the Arakawa points + ! + ! Mass point + CALL WRITE_HOR_2DCOORD(ZXHATM,ZYHATM,'latitude', 'longitude') + ! u point + CALL WRITE_HOR_2DCOORD(ZXHAT, ZYHATM,'latitude_u','longitude_u') + ! v point + CALL WRITE_HOR_2DCOORD(ZXHATM,ZYHAT, 'latitude_v','longitude_v') + ! xi vorticity point (=f point =uv point) + CALL WRITE_HOR_2DCOORD(ZXHAT, ZYHAT, 'latitude_f','longitude_f') + ! + DEALLOCATE(ZLAT,ZLON) +END IF +! +DEALLOCATE(ZXHATM,ZYHATM) +! +IF (TPFILE%LMASTER) THEN !vertical coordinates in the transformed space are the same on all processes + IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & + .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX + ! + IKU = SIZE(ZZHAT) + ALLOCATE(ZZHATM(IKU)) + ZZHATM(1:IKU-1) = 0.5 * (ZZHAT(2:IKU)+ZZHAT(1:IKU-1)) + ZZHATM(IKU) = 2.* ZZHAT(IKU) - ZZHATM(IKU-1) + ! + CALL WRITE_VER_COORD(PIOCDF%DIM_LEVEL, 'position z in the transformed space', '', & + 'altitude', 0., JPVEXT,JPVEXT,ZZHATM) + ! + CALL WRITE_VER_COORD(PIOCDF%DIM_LEVEL_W,'position z in the transformed space at w location','', & + 'altitude_at_w_location',-0.5,JPVEXT,0, ZZHAT) + ! + DEALLOCATE(ZZHATM) + END IF END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 5 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(5), LEN=IDIMLEN(5)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & - IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4) .AND. & - IDIMLEN(5) == SIZE(PFIELD,5) ) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X5[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 +! +!Write time scale +IF (TPFILE%LMASTER) THEN !Time scale is the same on all processes + IF (TRIM(YPROGRAM)/='PGD' .AND. TRIM(YPROGRAM)/='NESPGD' .AND. TRIM(YPROGRAM)/='ZOOMPG' & + .AND. .NOT.(TRIM(YPROGRAM)=='REAL' .AND. CSTORAGE_TYPE=='SU') ) THEN !condition to detect PREP_SURFEX + CALL WRITE_TIME_COORD(PIOCDF%DIMTIME) END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X5',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 END IF -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_X5 - - -SUBROUTINE IO_READ_FIELD_NC4_X6(TPFILE, TPFIELD, PFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -REAL,DIMENSION(:,:,:,:,:,:),INTENT(OUT) :: PFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code +IF (GCHANGEMODEL) CALL GO_TOMODEL_ll(IMI,IRESP) -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -INTEGER(KIND=IDCDF_KIND),DIMENSION(6) :: IDIMLEN -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP +CONTAINS +SUBROUTINE WRITE_HOR_COORD(TDIM,HLONGNAME,HSTDNAME,HAXIS,PSHIFT,KBOUNDLOW,KBOUNDHIGH,PCOORDS) + USE MODE_ALLOCBUFFER_ll, ONLY: ALLOCBUFFER_ll + USE MODE_GATHER_ll, ONLY: GATHER_XXFIELD -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM + CHARACTER(LEN=*), INTENT(IN) :: HLONGNAME + CHARACTER(LEN=*), INTENT(IN) :: HSTDNAME + CHARACTER(LEN=*), INTENT(IN) :: HAXIS + REAL, INTENT(IN) :: PSHIFT + INTEGER, INTENT(IN) :: KBOUNDLOW + INTEGER, INTENT(IN) :: KBOUNDHIGH + REAL,DIMENSION(:),TARGET,OPTIONAL,INTENT(IN) :: PCOORDS -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID + CHARACTER(LEN=2) :: YDIR + CHARACTER(LEN=64) :: YRANGE + CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME + INTEGER :: IRESP + INTEGER :: ISIZE + INTEGER :: JI + INTEGER(KIND=IDCDF_KIND) :: IVARID + INTEGER(KIND=IDCDF_KIND) :: IVDIM + INTEGER(KIND=IDCDF_KIND) :: STATUS + LOGICAL :: GALLOC + REAL,DIMENSION(:),POINTER :: ZTAB -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + GALLOC = .FALSE. + ZTAB => NULL() -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -IF (IDIMS == 6 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(4), LEN=IDIMLEN(4)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(5), LEN=IDIMLEN(5)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(6), LEN=IDIMLEN(6)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF ( IDIMLEN(1) == SIZE(PFIELD,1) .AND. IDIMLEN(2) == SIZE(PFIELD,2) .AND. & - IDIMLEN(3) == SIZE(PFIELD,3) .AND. IDIMLEN(4) == SIZE(PFIELD,4) .AND. & - IDIMLEN(5) == SIZE(PFIELD,5) .AND. IDIMLEN(6) == SIZE(PFIELD,6) ) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, PFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X6[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) + IF (HAXIS=='X') THEN + YDIR = 'XX' + ELSE IF (HAXIS=='Y') THEN + YDIR = 'YY' ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 + CALL PRINT_MSG(NVERB_FATAL,'IO','WRITE_HOR_COORD','invalid HAXIS ('//TRIM(HAXIS)//')') END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_X6',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 -END IF - -1000 CONTINUE -KRESP = IRESP -END SUBROUTINE IO_READ_FIELD_NC4_X6 - - -SUBROUTINE IO_READ_FIELD_NC4_N0(TPFILE, TPFIELD, KFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -INTEGER, INTENT(OUT) :: KFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID - -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) - -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -!Can read either 4 or 8 byte integers -IF (IDIMS == 0 .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size or type)') - IRESP = -3 -END IF - -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_N0 - - -SUBROUTINE IO_READ_FIELD_NC4_N1(TPFILE, TPFIELD, KFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -INTEGER, DIMENSION(:), INTENT(OUT) :: KFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -CHARACTER(LEN=30) :: YVARNAME -INTEGER(KIND=IDCDF_KIND) :: IDIMLEN -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID - -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) - -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + IF (.NOT.TPFILE%LMASTER) THEN + IF (PRESENT(PCOORDS)) THEN + ALLOCATE(ZTAB(0)) !To prevent false positive with valgrind + GALLOC = .TRUE. + CALL GATHER_XXFIELD(YDIR,PCOORDS,ZTAB,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + END IF + ELSE !TPFILE%LMASTER + ISIZE = TDIM%LEN + YVARNAME = TRIM(TDIM%NAME) + IVDIM = TDIM%ID -!NF90_INT1 is for the case a boolean was written -IF (IDIMS == 1 .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64 .OR. ITYPE == NF90_INT1) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) + IF (.NOT.PRESENT(PCOORDS)) THEN + ALLOCATE(ZTAB(ISIZE)) + GALLOC = .TRUE. + DO JI=1,ISIZE + ZTAB(JI) = REAL(JI,KIND=KIND(ZTAB(1)))+PSHIFT + END DO + ELSE + IF (GSMONOPROC) THEN ! sequential execution + ZTAB => PCOORDS + ELSE ! multiprocesses execution + CALL ALLOCBUFFER_ll(ZTAB,PCOORDS,YDIR,GALLOC) + CALL GATHER_XXFIELD(YDIR,PCOORDS,ZTAB,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + ENDIF + END IF - IF (IDIMLEN == SIZE(KFIELD)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) + STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 + ! Define the coordinate variable +#if (MNH_REAL == 8) + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) +#else + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) +#endif + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_DEF_VAR]') + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_NC_COORDS_VAR',TRIM(YVARNAME)//' already defined') END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 -END IF - -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_N1 - - -SUBROUTINE IO_READ_FIELD_NC4_N2(TPFILE, TPFIELD, KFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -INTEGER, DIMENSION(:,:), INTENT(OUT) :: KFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -CHARACTER(LEN=30) :: YVARNAME -INTEGER(KIND=IDCDF_KIND),DIMENSION(3) :: IDIMLEN -INTEGER :: IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + ! Write metadata + STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name',HLONGNAME) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name',HSTDNAME) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + IF (PRESENT(PCOORDS)) THEN + STATUS = NF90_PUT_ATT(INCID, IVARID, 'units','m') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + END IF + STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis',HAXIS) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_axis_shift',PSHIFT) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + WRITE(YRANGE,'( I0,":",I0 )') 1+KBOUNDLOW,ISIZE-KBOUNDHIGH + STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_dynamic_range',TRIM(YRANGE)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -!Treat special case of a degenerated 3D array (3rd dimension size is 1) -IF (IDIMS==3) THEN - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(3), LEN=IDIMLEN(3)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - IF (IDIMLEN(3)==1) THEN - CALL PRINT_MSG(NVERB_INFO,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)// & - ': reading 3D array with degenerated third dimension in 2D array for '//TRIM(YVARNAME)) - IDIMS = 2 - ELSE - CALL PRINT_MSG(NVERB_FATAL,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': wrong number of dimensions for '//TRIM(YVARNAME)) + ! Write the data + STATUS = NF90_PUT_VAR(INCID, IVARID, ZTAB) + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) END IF -END IF -!NF90_INT1 is for the case a boolean was written -IF (IDIMS == SIZE(SHAPE(KFIELD)) .AND. (ITYPE == NF90_INT .OR. ITYPE == NF90_INT64 .OR. ITYPE == NF90_INT1) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN(1)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(2), LEN=IDIMLEN(2)) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF (IDIMLEN(1) == SIZE(KFIELD,1) .AND. IDIMLEN(2) == SIZE(KFIELD,2)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, KFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_N2[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 - END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_N2',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 -END IF + IF (GALLOC) DEALLOCATE(ZTAB) +END SUBROUTINE WRITE_HOR_COORD -1000 CONTINUE -KRESP = IRESP +SUBROUTINE WRITE_HOR_2DCOORD(PX,PY,HLAT,HLON) + USE MODE_ALLOCBUFFER_ll, ONLY: ALLOCBUFFER_ll + USE MODE_GATHER_ll, ONLY: GATHER_XYFIELD -END SUBROUTINE IO_READ_FIELD_NC4_N2 + REAL,DIMENSION(:), INTENT(IN) :: PX + REAL,DIMENSION(:), INTENT(IN) :: PY + CHARACTER(LEN=*), INTENT(IN) :: HLAT + CHARACTER(LEN=*), INTENT(IN) :: HLON -SUBROUTINE IO_READ_FIELD_NC4_L0(TPFILE, TPFIELD, OFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -LOGICAL, INTENT(OUT) :: OFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code + LOGICAL :: GALLOC1, GALLOC2 + REAL,DIMENSION(:,:),POINTER :: ZTAB1, ZTAB2 -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP -INTEGER :: IFIELD + GALLOC1 = .FALSE. + GALLOC2 = .FALSE. + ZTAB1 => NULL() + ZTAB2 => NULL() -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_L0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + CALL SM_LATLON(XLATORI,XLONORI, & + SPREAD(SOURCE=PX,DIM=2,NCOPIES=IJU), & + SPREAD(SOURCE=PY,DIM=1,NCOPIES=IIU), & + ZLAT,ZLON) -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID + IF (.NOT.TPFILE%LMASTER) THEN + ALLOCATE(ZTAB1(0,0),ZTAB2(0,0)) !To prevent false positive with valgrind + GALLOC1 = .TRUE. ; GALLOC2 = .TRUE. + CALL GATHER_XYFIELD(ZLAT,ZTAB1,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + CALL GATHER_XYFIELD(ZLON,ZTAB2,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + ELSE !TPFILE%LMASTER + IF (GSMONOPROC) THEN ! sequential execution + ZTAB1 => ZLAT + ZTAB2 => ZLON + ELSE ! multiprocesses execution + CALL ALLOCBUFFER_ll(ZTAB1,ZLAT,'XY',GALLOC1) + CALL ALLOCBUFFER_ll(ZTAB2,ZLON,'XY',GALLOC2) + CALL GATHER_XYFIELD(ZLAT,ZTAB1,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + CALL GATHER_XYFIELD(ZLON,ZTAB2,TPFILE%NMASTER_RANK,TPFILE%NMPICOMM) + ENDIF + ! + CALL FIND_FIELD_ID_FROM_MNHNAME(HLAT,ID,IRESP) + CALL IO_WRITE_FIELD_NC4_X2(TPFILE,TFIELDLIST(ID),ZTAB1,IRESP,OISCOORD=.TRUE.) + CALL FIND_FIELD_ID_FROM_MNHNAME(HLON,ID,IRESP) + CALL IO_WRITE_FIELD_NC4_X2(TPFILE,TFIELDLIST(ID),ZTAB2,IRESP,OISCOORD=.TRUE.) + END IF -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + IF (GALLOC1) DEALLOCATE(ZTAB1) + IF (GALLOC2) DEALLOCATE(ZTAB2) +END SUBROUTINE WRITE_HOR_2DCOORD -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) +SUBROUTINE WRITE_VER_COORD(TDIM,HLONGNAME,HSTDNAME,HCOMPNAME,PSHIFT,KBOUNDLOW,KBOUNDHIGH,PCOORDS) + TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM + CHARACTER(LEN=*), INTENT(IN) :: HLONGNAME + CHARACTER(LEN=*), INTENT(IN) :: HSTDNAME + CHARACTER(LEN=*), INTENT(IN) :: HCOMPNAME + REAL, INTENT(IN) :: PSHIFT + INTEGER, INTENT(IN) :: KBOUNDLOW + INTEGER, INTENT(IN) :: KBOUNDHIGH + REAL,DIMENSION(:), INTENT(IN) :: PCOORDS -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 + CHARACTER(LEN=64) :: YRANGE + CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME + INTEGER :: IRESP + INTEGER :: ISIZE + INTEGER :: JI + INTEGER(KIND=IDCDF_KIND) :: IVARID + INTEGER(KIND=IDCDF_KIND) :: IVDIM + INTEGER(KIND=IDCDF_KIND) :: STATUS -!NF90_INT1 is for the case a boolean was written -!Accept also INT and INT64 (for backward compatibility) -IF (IDIMS == 0 .AND. (ITYPE == NF90_INT1 .OR. ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, IFIELD) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF + ISIZE = TDIM%LEN + YVARNAME = TRIM(TDIM%NAME) + IVDIM = TDIM%ID - IF (IFIELD==0) THEN - OFIELD = .FALSE. - ELSE IF (IFIELD==1) THEN - OFIELD = .TRUE. + STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) + IF (STATUS /= NF90_NOERR) THEN + ! Define the coordinate variable +#if (MNH_REAL == 8) + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) +#else + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) +#endif + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_DEF_VAR]') ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_LFI_L0',TRIM(TPFILE%CNAME)//': invalid value in file for ' & - //TRIM(TPFIELD%CMNHNAME)) - OFIELD = .TRUE. - IRESP = -112 + CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_NC_COORDS_VAR',TRIM(YVARNAME)//' already defined') END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size or type)') - IRESP = -3 -END IF + ! Write metadata + STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name',HLONGNAME) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name',HSTDNAME) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'units','m') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis','Z') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'positive','up') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_axis_shift',PSHIFT) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + WRITE(YRANGE,'( I0,":",I0 )') 1+KBOUNDLOW,ISIZE-KBOUNDHIGH + STATUS = NF90_PUT_ATT(INCID, IVARID, 'c_grid_dynamic_range',TRIM(YRANGE)) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + ! + IF (GSLEVE) THEN + !Remark: ZS, ZSMT and ZTOP in the formula are the same for mass point or flux point + STATUS = NF90_PUT_ATT(INCID, IVARID,'formula_terms','s: '//TRIM(YVARNAME)// & + ' height: ZTOP oro_ls: ZSMT oro: ZS len1: LEN1 len2: LEN2') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_definition','z(n,k,j,i)=s(k)'// & + '+ oro_ls(j,i)*sinh((height/len1)**1.35-(s(k)/len1)**1.35)/sinh((s(k)/len1)**1.35)'// & + '+(oro(j,i)-oro_ls(j,i))*sinh((height/len2)**1.35-(s(k)/len2)**1.35)/sinh((s(k)/len2)**1.35)') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + ELSE + !Remark: ZS and ZTOP in the formula are the same for mass point or flux point + STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_terms','s: '//TRIM(YVARNAME)//' height: ZTOP orog: ZS') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'formula_definition','z(n,k,j,i)=s(k)*(height-orog(j,i))/height+orog(j,i)') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + ENDIF + ! + STATUS = NF90_PUT_ATT(INCID, IVARID, 'computed_standard_name',HCOMPNAME) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) -1000 CONTINUE -KRESP = IRESP + ! Write the data + STATUS = NF90_PUT_VAR(INCID, IVARID, PCOORDS) + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) -END SUBROUTINE IO_READ_FIELD_NC4_L0 +END SUBROUTINE WRITE_VER_COORD +SUBROUTINE WRITE_TIME_COORD(TDIM) + USE MODD_TIME_n, ONLY: TDTMOD, TDTCUR + USE MODD_TYPE_DATE -SUBROUTINE IO_READ_FIELD_NC4_L1(TPFILE, TPFIELD, OFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -LOGICAL,DIMENSION(:),INTENT(OUT) :: OFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code + USE MODE_DATETIME + USE MODE_FIELD, ONLY: TFIELDLIST,FIND_FIELD_ID_FROM_MNHNAME + USE MODE_GRIDPROJ -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -INTEGER(KIND=IDCDF_KIND) :: IDIMLEN -CHARACTER(LEN=30) :: YVARNAME -INTEGER :: IRESP -INTEGER :: JI -INTEGER,DIMENSION(SIZE(OFIELD)) :: IFIELD + TYPE(DIMCDF), POINTER, INTENT(IN) :: TDIM -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) + REAL :: ZDELTATIME + CHARACTER(LEN=40) :: YUNITS + CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME + INTEGER(KIND=IDCDF_KIND) :: IVARID + INTEGER(KIND=IDCDF_KIND) :: IVDIM + INTEGER(KIND=IDCDF_KIND) :: STATUS + TYPE(DATE_TIME) :: TZREF -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + IF (ASSOCIATED(TDTCUR) .AND. ASSOCIATED(TDTMOD)) THEN + YVARNAME = TRIM(TDIM%NAME) + IVDIM = TDIM%ID -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -!Neglect the time dimension (of size 1) -IF (TPFIELD%LTIMEDEP) IDIMS=IDIMS-1 - -!NF90_INT1 is for the case a boolean was written -!Accept also INT and INT64 (for backward compatibility) -IF (IDIMS == 1 .AND. (ITYPE == NF90_INT1 .OR. ITYPE == NF90_INT .OR. ITYPE == NF90_INT64) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - - IF (IDIMLEN == SIZE(OFIELD)) THEN - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, IFIELD) + STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_L1[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 + ! Define the coordinate variable +#if (MNH_REAL == 8) + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_DOUBLE, IVDIM, IVARID) +#else + STATUS = NF90_DEF_VAR(INCID, YVARNAME, NF90_FLOAT, IVDIM, IVARID) +#endif + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_TIME_COORD[NF90_DEF_VAR]') + ELSE + CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_TIME_COORD',TRIM(YVARNAME)//' already defined') END IF - DO JI=1,IDIMLEN - IF (IFIELD(JI)==0) THEN - OFIELD(JI) = .FALSE. - ELSE IF (IFIELD(JI)==1) THEN - OFIELD(JI) = .TRUE. - ELSE - OFIELD(JI) = .TRUE. - IRESP = -112 - END IF - END DO - IF (IRESP==-112) THEN - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_LFI_L1',TRIM(TPFILE%CNAME)//': invalid value(s) in file for ' & - //TRIM(TPFIELD%CMNHNAME)) - END IF + ! Write metadata + STATUS = NF90_PUT_ATT(INCID, IVARID, 'long_name','time axis') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'standard_name','time') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + WRITE(YUNITS,'( "seconds since ",I4.4,"-",I2.2,"-",I2.2," 00:00:00 +0:00" )') & + TDTMOD%TDATE%YEAR,TDTMOD%TDATE%MONTH,TDTMOD%TDATE%DAY + STATUS = NF90_PUT_ATT(INCID, IVARID, 'units',YUNITS) + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID, 'axis','T') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) + STATUS = NF90_PUT_ATT(INCID, IVARID,'calendar','standard') + IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_ATT]') - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size)') - IRESP = -3 + ! Model beginning date (TDTMOD%TDATE) is used as the reference date + ! Reference time is set to 0. + TZREF = TDTMOD + TZREF%TIME = 0. + ! Compute the temporal distance from reference + CALL DATETIME_DISTANCE(TZREF,TDTCUR,ZDELTATIME) + ! Write the data + STATUS = NF90_PUT_VAR(INCID, IVARID, ZDELTATIME) + IF (status /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'WRITE_NC_COORDS_VAR[NF90_PUT_VAR] '//TRIM(YVARNAME)) END IF -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_L1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong number of dimensions or wrong type)') - IRESP = -3 -END IF -1000 CONTINUE -KRESP = IRESP +END SUBROUTINE WRITE_TIME_COORD + +END SUBROUTINE IO_WRITE_COORDVAR_NC4 -END SUBROUTINE IO_READ_FIELD_NC4_L1 +SUBROUTINE IO_WRITE_HEADER_NC4(TPFILE) +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE ! File structure +! +INTEGER(KIND=IDCDF_KIND) :: ISTATUS +! +IF (TRIM(TPFILE%CFORMAT)/='NETCDF4' .AND. TRIM(TPFILE%CFORMAT)/='LFICDF4') RETURN +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_WRITE_HEADER_NC4','called for file '//TRIM(TPFILE%CNAME)) +! +IF (TPFILE%LMASTER) THEN + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'Conventions', 'CF-1.7 COMODO-1.4') + IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') -SUBROUTINE IO_READ_FIELD_NC4_C0(TPFILE, TPFIELD, HFIELD, KRESP) -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -CHARACTER(LEN=*), INTENT(OUT) :: HFIELD -INTEGER, INTENT(OUT) :: KRESP ! return-code +#if (MNH_REAL == 8) + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_REAL', '8') +#else + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_REAL', '4') +#endif + IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -INTEGER(KIND=IDCDF_KIND),DIMENSION(NF90_MAX_VAR_DIMS) :: IVDIMS -CHARACTER(LEN=30) :: YVARNAME -CHARACTER(LEN=:),ALLOCATABLE :: YSTR -INTEGER(KIND=IDCDF_KIND) :: IDIMLEN -INTEGER :: IRESP +#if (MNH_INT == 4) + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_INT', '4') +#else + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'MNH_INT', '8') +#endif + IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_FILE_WRITE_HEADER[NF90_PUT_ATT]') -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) +!title -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID + !history + CALL IO_APPEND_HISTORY_NC4(TPFILE) -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) +!institution -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS, DIMIDS=IVDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) - -IF (IDIMS == 1 .AND. (ITYPE == NF90_CHAR) ) THEN - ! Check size of variable before reading - STATUS = NF90_INQUIRE_DIMENSION(INCID, IVDIMS(1), LEN=IDIMLEN) - IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_INQUIRE_DIMENSION] '//TRIM(YVARNAME)) - ! - ALLOCATE(CHARACTER(LEN=IDIMLEN)::YSTR) - ! Read variable - STATUS = NF90_GET_VAR(INCID, IVARID, YSTR) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_C0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - IF (LEN_TRIM(YSTR) > LEN(HFIELD)) & - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)//' truncated') - HFIELD = TRIM(YSTR) - DEALLOCATE(YSTR) +!source - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP) -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_C0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size or type)') - IRESP = -3 -END IF +!comment -1000 CONTINUE -KRESP = IRESP +!references +END IF +! +END SUBROUTINE IO_WRITE_HEADER_NC4 -END SUBROUTINE IO_READ_FIELD_NC4_C0 -SUBROUTINE IO_READ_FIELD_NC4_T0(TPFILE, TPFIELD, TPDATA, KRESP) +SUBROUTINE IO_APPEND_HISTORY_NC4(TPFILE) ! -USE MODD_TYPE_DATE +USE MODD_IO_ll, ONLY: TFILEDATA ! -USE MODE_DATETIME +TYPE(TFILEDATA), INTENT(IN) :: TPFILE ! File structure ! -TYPE(TFILEDATA), INTENT(IN) :: TPFILE -TYPE(TFIELDDATA), INTENT(INOUT) :: TPFIELD -TYPE (DATE_TIME), INTENT(OUT) :: TPDATA -INTEGER, INTENT(OUT) :: KRESP ! return-code - -INTEGER(KIND=IDCDF_KIND) :: STATUS -INTEGER(KIND=IDCDF_KIND) :: INCID -INTEGER(KIND=IDCDF_KIND) :: IVARID -INTEGER(KIND=IDCDF_KIND) :: ITYPE ! variable type -INTEGER(KIND=IDCDF_KIND) :: IDIMS ! number of dimensions -CHARACTER(LEN=30) :: YVARNAME -CHARACTER(LEN=:),ALLOCATABLE :: YSTR -INTEGER(KIND=IDCDF_KIND) :: IDIMLEN -INTEGER :: IDX,IRESP - -CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': reading '//TRIM(TPFIELD%CMNHNAME)) - -IRESP = 0 -! Get the Netcdf file ID -INCID = TPFILE%NNCID +INTEGER,PARAMETER :: YEAR=1, MONTH=2, DAY=3, HH=5, MM=6, SS=7 +! +CHARACTER(len=5) :: YZONE +CHARACTER(LEN=:),ALLOCATABLE :: YCMD, YHISTORY, YHISTORY_NEW, YHISTORY_PREV +INTEGER :: ILEN_CMD, ILEN_PREV +INTEGER(KIND=IDCDF_KIND) :: ISTATUS +INTEGER,DIMENSION(8) :: IDATETIME +! +IF (TRIM(TPFILE%CFORMAT)/='NETCDF4' .AND. TRIM(TPFILE%CFORMAT)/='LFICDF4') RETURN +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_APPEND_HISTORY_NC4','called for file '//TRIM(TPFILE%CNAME)) +! +IF (TPFILE%LMASTER) THEN + !Check if history attribute already exists in file and read it + ISTATUS = NF90_INQUIRE_ATTRIBUTE(TPFILE%NNCID, NF90_GLOBAL, 'history', LEN=ILEN_PREV) + IF (ISTATUS == NF90_NOERR) THEN + ALLOCATE(CHARACTER(LEN=ILEN_PREV) :: YHISTORY_PREV) + ISTATUS = NF90_GET_ATT(TPFILE%NNCID, NF90_GLOBAL, 'history', YHISTORY_PREV) + IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_APPEND_HISTORY_NC4[NF90_GET_ATT]') + YHISTORY_PREV = YHISTORY_PREV + ELSE + ILEN_PREV = 0 + END IF -CALL CLEANMNHNAME(TPFIELD%CMNHNAME,YVARNAME) + !Get date and time + call DATE_AND_TIME( VALUES=IDATETIME, ZONE=YZONE ) + call GET_COMMAND(lENGTH=ILEN_CMD) + IF (ILEN_CMD>0) THEN + ALLOCATE(CHARACTER(ILEN_CMD) :: YCMD) + CALL GET_COMMAND(COMMAND=YCMD) + END IF -! Get variable ID, NDIMS and TYPE -STATUS = NF90_INQ_VARID(INCID, YVARNAME, IVARID) -IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_T0[NF90_INQ_VARID] '//TRIM(YVARNAME),IRESP) - GOTO 1000 -END IF -STATUS = NF90_INQUIRE_VARIABLE(INCID, IVARID, XTYPE=ITYPE, NDIMS=IDIMS) -IF (STATUS /= NF90_NOERR) CALL HANDLE_ERR(STATUS,__LINE__,'IO_READ_FIELD_NC4_T0[NF90_INQUIRE_VARIABLE] '//TRIM(YVARNAME)) + !Prepare new history entry + ALLOCATE(CHARACTER(26+ILEN_CMD) :: YHISTORY_NEW) + WRITE(YHISTORY_NEW, '( I4.4,"-",I2.2,"-",I2.2,"T",I2.2,":",I2.2,":",I2.2,A5,": ", A )') & + IDATETIME(YEAR),IDATETIME(MONTH),IDATETIME(DAY),IDATETIME(HH),IDATETIME(MM),IDATETIME(SS),YZONE, YCMD -IF (IDIMS == 0 .AND. (ITYPE == NF90_FLOAT .OR. ITYPE == NF90_DOUBLE) ) THEN - ! Read time - STATUS = NF90_GET_VAR(INCID, IVARID, TPDATA%TIME) - IF (STATUS /= NF90_NOERR) THEN - CALL HANDLE_ERR(status,__LINE__,'IO_READ_FIELD_NC4_X0[NF90_GET_VAR] '//TRIM(YVARNAME),IRESP) - GOTO 1000 - END IF - ! Read and check attributes of variable - CALL IO_READ_CHECK_FIELD_ATTR_NC4(TPFILE,TPFIELD,IVARID,IRESP,HCALENDAR='standard') - ! Extract date from UNITS - IDX = INDEX(TPFIELD%CUNITS,'since ') - READ(TPFIELD%CUNITS(IDX+6 :IDX+9), '( I4.4 )') TPDATA%TDATE%YEAR - READ(TPFIELD%CUNITS(IDX+11:IDX+12),'( I2.2 )') TPDATA%TDATE%MONTH - READ(TPFIELD%CUNITS(IDX+14:IDX+15),'( I2.2 )') TPDATA%TDATE%DAY - ! Simple check (should catch most errors) - IF ( TPDATA%TDATE%DAY<1 .OR. TPDATA%TDATE%DAY>31 .OR. TPDATA%TDATE%MONTH<1 .OR. TPDATA%TDATE%MONTH>12 ) THEN - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' read date is invalid') - IRESP = -3 + !Write full history + IF (ILEN_PREV == 0) THEN + YHISTORY = YHISTORY_NEW + ELSE + YHISTORY = YHISTORY_NEW//NEW_LINE('A')//YHISTORY_PREV END IF - ! Correct date and time (necessary for example if time is bigger than 86400 s) - CALL DATETIME_CORRECTDATE(TPDATA) -ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','IO_READ_FIELD_NC4_T0',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)// & - ' not read (wrong size or type)') - IRESP = -3 + ISTATUS = NF90_PUT_ATT(TPFILE%NNCID, NF90_GLOBAL, 'history', YHISTORY ) + IF (ISTATUS /= NF90_NOERR) CALL HANDLE_ERR(ISTATUS,__LINE__,'IO_APPEND_HISTORY_NC4[NF90_PUT_ATT]') END IF -1000 CONTINUE -KRESP = IRESP - -END SUBROUTINE IO_READ_FIELD_NC4_T0 +END SUBROUTINE IO_APPEND_HISTORY_NC4 -END MODULE MODE_NETCDF +end module mode_io_write_nc4 #else ! ! External dummy subroutines ! -SUBROUTINE IO_WRITE_FIELD_NC4(A,B,C,D) -INTEGER :: A,B,C,D -PRINT *, 'IO_WRITE_FIELD_NC4 empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF4 I/Os.' -END SUBROUTINE IO_WRITE_FIELD_NC4 - -SUBROUTINE IO_READ_FIELD_NC4(A,B,C,D) -INTEGER :: A,B,C,D -PRINT *, 'IO_READ_FIELD_NC4 empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF4 I/Os.' -END SUBROUTINE IO_READ_FIELD_NC4 - -SUBROUTINE IO_WRITE_HEADER_NC4(A,B) -INTEGER :: A,B -PRINT *, 'IO_WRITE_HEADER_NC4 empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF4 I/Os.' -END SUBROUTINE IO_WRITE_HEADER_NC4 - -SUBROUTINE CLEANIOCDF(A) -INTEGER :: A -PRINT *, 'CLEANIOCDF empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF4 I/Os.' -END SUBROUTINE CLEANIOCDF - +subroutine io_write_coordvar_nc4(a, b) +use mode_msg +integer :: a, b +CALL PRINT_MSG(NVERB_ERROR,'IO','io_write_coordvar_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_write_coordvar_nc4 +! +subroutine io_write_field_nc4(a, b, c, d, e, f, g) +use mode_msg +integer :: a, b, c, d, e, f, g +CALL PRINT_MSG(NVERB_ERROR,'IO','io_write_field_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_write_field_nc4 +! +subroutine io_write_header_nc4(a) +use mode_msg +integer :: a +CALL PRINT_MSG(NVERB_ERROR,'IO','io_write_header_nc4','empty call. Compile with -DMNH_IOCDF4 flag to enable NetCDF') +end subroutine io_write_header_nc4 +! #endif diff --git a/src/MNH/modeln.f90 b/src/MNH/modeln.f90 index 6836f74fa..f2c335258 100644 --- a/src/MNH/modeln.f90 +++ b/src/MNH/modeln.f90 @@ -345,7 +345,6 @@ USE MODE_ll USE MODE_MNH_TIMING USE MODE_MODELN_HANDLER USE MODE_MPPDB -USE MODE_NETCDF ! USE MODI_ADVECTION_METSV USE MODI_ADVECTION_UVW -- GitLab