diff --git a/src/LIB/SURCOUCHE/src/mode_field.f90 b/src/LIB/SURCOUCHE/src/mode_field.f90 index c6eca9e5cb6ead4f09a051774327023c7d67cb5b..f7dc6bd264745bbbe45f3c5533d51a8d492025dc 100644 --- a/src/LIB/SURCOUCHE/src/mode_field.f90 +++ b/src/LIB/SURCOUCHE/src/mode_field.f90 @@ -14,6 +14,7 @@ ! P. Wautelet 12/04/2019: added pointers for C1D, L1D, N1D, X5D and X6D structures in TFIELDDATA ! P. Wautelet 06/06/2019: bug correction in FIELDLIST_GOTO_MODEL (XLSTHM was overwritten if LUSERV=.FALSE. due to wrong IF block) ! P. Wautelet 19/06/2019: add Fieldlist_nmodel_resize subroutine + provide KMODEL to INI_FIELD_LIST when known +! P. Wautelet 12/07/2019: add pointers for T1D structure in TFIELDDATA !----------------------------------------------------------------- MODULE MODE_FIELD ! @@ -110,6 +111,10 @@ TYPE TFIELDPTR_T0D TYPE(DATE_TIME), POINTER :: DATA => NULL() END TYPE TFIELDPTR_T0D ! +TYPE TFIELDPTR_T1D + TYPE(DATE_TIME), DIMENSION(:), POINTER :: DATA => NULL() +END TYPE TFIELDPTR_T1D +! !Structure describing the characteristics of a field TYPE TFIELDDATA CHARACTER(LEN=NMNHNAMELGTMAX) :: CMNHNAME = '' !Name of the field (for MesoNH, non CF convention) @@ -159,6 +164,7 @@ TYPE TFIELDDATA TYPE(TFIELDPTR_X6D),DIMENSION(:),ALLOCATABLE :: TFIELD_X6D !Pointer to the real 6D fields (one per nested mesh) ! TYPE(TFIELDPTR_T0D),DIMENSION(:),ALLOCATABLE :: TFIELD_T0D !Pointer to the scalar date/time fields (one per nested mesh) + TYPE(TFIELDPTR_T1D),DIMENSION(:),ALLOCATABLE :: TFIELD_T1D !Pointer to the date/time 1D fields (one per nested mesh) END TYPE TFIELDDATA ! integer, save :: NMODEL_ALLOCATED diff --git a/src/LIB/SURCOUCHE/src/mode_io_field_write.f90 b/src/LIB/SURCOUCHE/src/mode_io_field_write.f90 index 3d37d58583d72d6e1377ac451d1a01c253d243b7..835c60cc5745a34a5aee6822e59fbc32a739ea40 100644 --- a/src/LIB/SURCOUCHE/src/mode_io_field_write.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_field_write.f90 @@ -12,6 +12,7 @@ ! P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg ! P. Wautelet 12/04/2019: added pointers for C1D, L1D, N1D, X5D and X6D structures in TFIELDDATA ! P. Wautelet 12/04/2019: use MNHTIME for time measurement variables +! P. Wautelet 12/07/2019: add support for 1D array of dates !----------------------------------------------------------------- #define MNH_SCALARS_IN_SPLITFILES 0 @@ -47,7 +48,7 @@ MODULE MODE_IO_FIELD_WRITE IO_Field_write_byname_N2, IO_Field_write_byname_N3, & IO_Field_write_byname_L0, IO_Field_write_byname_L1, & IO_Field_write_byname_C0, IO_Field_write_byname_C1, & - IO_Field_write_byname_T0, & + IO_Field_write_byname_T0, IO_Field_write_byname_T1, & IO_Field_write_byfield_X0,IO_Field_write_byfield_X1, & IO_Field_write_byfield_X2,IO_Field_write_byfield_X3, & IO_Field_write_byfield_X4,IO_Field_write_byfield_X5, & @@ -56,7 +57,7 @@ MODULE MODE_IO_FIELD_WRITE IO_Field_write_byfield_N2,IO_Field_write_byfield_N3, & IO_Field_write_byfield_L0,IO_Field_write_byfield_L1, & IO_Field_write_byfield_C0,IO_Field_write_byfield_C1, & - IO_Field_write_byfield_T0 + IO_Field_write_byfield_T0,IO_Field_write_byfield_T1 END INTERFACE INTERFACE IO_Field_write_box @@ -2352,6 +2353,88 @@ CONTAINS END SUBROUTINE IO_Field_write_byfield_T0 + SUBROUTINE IO_Field_write_byname_T1(TPFILE,HNAME,TFIELD,KRESP) + USE MODD_TYPE_DATE, only: DATE_TIME + ! + !* 0.1 Declarations of arguments + ! + TYPE(TFILEDATA), INTENT(IN) :: TPFILE + CHARACTER(LEN=*), INTENT(IN) :: HNAME ! name of the field to write + TYPE (DATE_TIME),DIMENSION(:), INTENT(IN) :: TFIELD ! array containing the data field + INTEGER,OPTIONAL, INTENT(OUT):: KRESP ! return-code + ! + !* 0.2 Declarations of local variables + ! + INTEGER :: ID ! Index of the field + INTEGER :: IRESP ! return_code + ! + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Field_write_byname_T1',TRIM(TPFILE%CNAME)//': writing '//TRIM(HNAME)) + ! + CALL FIND_FIELD_ID_FROM_MNHNAME(HNAME,ID,IRESP) + ! + IF(IRESP==0) CALL IO_Field_write(TPFILE,TFIELDLIST(ID),TFIELD,IRESP) + ! + IF (PRESENT(KRESP)) KRESP = IRESP + ! + END SUBROUTINE IO_Field_write_byname_T1 + + + SUBROUTINE IO_Field_write_byfield_T1(TPFILE,TPFIELD,TFIELD,KRESP) + USE MODD_IO, ONLY: GSMONOPROC, ISP + USE MODD_TYPE_DATE, only: DATE_TIME + ! + !* 0. DECLARATIONS + ! ------------ + ! + ! + !* 0.1 Declarations of arguments + ! + TYPE(TFILEDATA), INTENT(IN) :: TPFILE + TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD + TYPE (DATE_TIME),DIMENSION(:), INTENT(IN) :: TFIELD ! array containing the data field + INTEGER,OPTIONAL, INTENT(OUT):: KRESP ! return-code + ! + !* 0.2 Declarations of local variables + ! + INTEGER :: IERR + INTEGER :: IRESP + LOGICAL :: GLFI, GNC4 + CHARACTER(LEN=:),ALLOCATABLE :: YMSG + CHARACTER(LEN=6) :: YRESP + ! + CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Field_write_byfield_T1',TRIM(TPFILE%CNAME)//': writing '//TRIM(TPFIELD%CMNHNAME)) + ! + CALL IO_Field_metadata_check(TPFIELD,TYPEDATE,1,'IO_Field_write_byfield_T1') + ! + IRESP = 0 + ! + CALL IO_File_write_check(TPFILE,'IO_Field_write_byfield_T1',IRESP) + ! + CALL IO_Format_write_select(TPFILE,GLFI,GNC4) + ! + IF (IRESP==0) THEN + IF (GSMONOPROC) THEN ! sequential execution + IF (GLFI) CALL IO_Field_write_lfi(TPFILE,TPFIELD,TFIELD,IRESP) + IF (GNC4) CALL IO_Field_write_nc4(TPFILE,TPFIELD,TFIELD,IRESP) + ELSE + IF (ISP == TPFILE%NMASTER_RANK) THEN + IF (GLFI) CALL IO_Field_write_lfi(TPFILE,TPFIELD,TFIELD,IRESP) + IF (GNC4) CALL IO_Field_write_nc4(TPFILE,TPFIELD,TFIELD,IRESP) + END IF + ! + CALL MPI_BCAST(IRESP,1,MNHINT_MPI,TPFILE%NMASTER_RANK-1,TPFILE%NMPICOMM,IERR) + END IF + END IF + ! + IF (IRESP.NE.0) THEN + WRITE(YRESP, '( I6 )') IRESP + YMSG = 'RESP='//YRESP//' when writing '//TRIM(TPFIELD%CMNHNAME)//' in '//TRIM(TPFILE%CNAME) + CALL PRINT_MSG(NVERB_ERROR,'IO','IO_Field_write_byfield_T1',YMSG) + END IF + IF (PRESENT(KRESP)) KRESP = IRESP + END SUBROUTINE IO_Field_write_byfield_T1 + + SUBROUTINE IO_Field_write_byname_lb(TPFILE,HNAME,KL3D,PLB,KRESP) ! !* 0.1 Declarations of arguments @@ -2804,6 +2887,24 @@ DO JI = 1,SIZE(TPOUTPUT%NFIELDLIST) ': CLBTYPE/=NONE not allowed for 1D character fields' ) END IF ! + !1D date/time + ! + CASE (TYPEDATE) + IF ( .NOT.ALLOCATED(TFIELDLIST(IDX)%TFIELD_T1D) ) THEN + call Print_msg( NVERB_ERROR, 'IO', 'IO_Fieldlist_write', trim(tfieldlist(idx)%cmnhname)// & + ': TFIELD_T1D is NOT allocated ' ) + END IF + IF ( .NOT.ASSOCIATED(TFIELDLIST(IDX)%TFIELD_T1D(IMI)%DATA) ) THEN + call Print_msg( NVERB_ERROR, 'IO', 'IO_Fieldlist_write', trim(tfieldlist(idx)%cmnhname)// & + ': TFIELD_T1D%DATA is NOT associated' ) + END IF + IF ( TFIELDLIST(IDX)%CLBTYPE == 'NONE' ) THEN + CALL IO_Field_write(TPOUTPUT%TFILE,TFIELDLIST(IDX),TFIELDLIST(IDX)%TFIELD_T1D(IMI)%DATA) + ELSE + call Print_msg( NVERB_ERROR, 'IO', 'IO_Fieldlist_write', trim(tfieldlist(idx)%cmnhname)// & + ': CLBTYPE/=NONE not allowed for 1D date/time fields' ) + END IF + ! !1D other types ! CASE DEFAULT diff --git a/src/LIB/SURCOUCHE/src/mode_io_write_lfi.f90 b/src/LIB/SURCOUCHE/src/mode_io_write_lfi.f90 index 26f18bc04cee5ec685bbc4d1d07d1c83964aa6fa..2e56fdc99dbd30f9e7f3359efaec87e1d29e02b9 100644 --- a/src/LIB/SURCOUCHE/src/mode_io_write_lfi.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_write_lfi.f90 @@ -9,6 +9,7 @@ ! P. Wautelet 14/12/2018: split fmreadwrit.f90 ! P. Wautelet 11/01/2019: do not write variables with a zero size ! P. Wautelet 05/03/2019: rename IO subroutines and modules +! P. Wautelet 12/07/2019: add support for 1D array of dates !----------------------------------------------------------------- module mode_io_write_lfi ! @@ -37,7 +38,7 @@ INTERFACE IO_Field_write_lfi IO_Field_write_lfi_N2,IO_Field_write_lfi_N3, & IO_Field_write_lfi_L0,IO_Field_write_lfi_L1, & IO_Field_write_lfi_C0, & - IO_Field_write_lfi_T0 + IO_Field_write_lfi_T0,IO_Field_write_lfi_T1 END INTERFACE IO_Field_write_lfi ! CONTAINS @@ -781,6 +782,97 @@ IF (ALLOCATED(IWORK)) DEALLOCATE(IWORK) ! END SUBROUTINE IO_Field_write_lfi_T0 ! +SUBROUTINE IO_Field_write_lfi_T1(TPFILE,TPFIELD,TPDATA,KRESP) +! +USE MODD_TYPE_DATE +! +IMPLICIT NONE +! +!* 0.1 Declarations of arguments +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD +TYPE (DATE_TIME), DIMENSION(:), INTENT(IN) :: TPDATA ! array containing the data field +INTEGER, INTENT(OUT):: KRESP ! return-code if problems araised +! +!* 0.2 Declarations of local variables +! +INTEGER :: ILENG, IPOS +INTEGER :: JI +INTEGER(kind=LFIINT) :: IRESP, ITOTAL +TYPE(TFIELDDATA) :: TZFIELD +INTEGER, DIMENSION(:), ALLOCATABLE :: ITDATE ! date array +INTEGER(KIND=8),DIMENSION(:),ALLOCATABLE :: IWORK +CHARACTER(LEN=LEN_HREC) :: YRECFM +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Field_write_lfi_T1','writing '//TRIM(TPFIELD%CMNHNAME)) +! +ILENG = 3 * SIZE( TPDATA ) +! +IF ( ILENG==0 ) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_lfi_T1','ignoring variable with a zero size ('//TRIM(TPFIELD%CMNHNAME)//')') + KRESP = 0 + RETURN +END IF +! +ALLOCATE( ITDATE( ILENG ) ) +! +TZFIELD = TPFIELD +! +! Write date +! +TZFIELD%CMNHNAME = TRIM(TPFIELD%CMNHNAME)//'%TDATE' +TZFIELD%CCOMMENT = 'YYYYMMDD' +! +DO JI = 1, SIZE( TPDATA ) + IPOS = 1 + 3 * ( JI - 1 ) + ITDATE(IPOS ) = TPDATA(JI)%TDATE%YEAR + ITDATE(IPOS + 1 ) = TPDATA(JI)%TDATE%MONTH + ITDATE(IPOS + 2 ) = TPDATA(JI)%TDATE%DAY +END DO +! +CALL WRITE_PREPARE(TZFIELD,ILENG,IWORK,ITOTAL,IRESP) +! +IF (IRESP==0) THEN + IWORK(LEN(TZFIELD%CCOMMENT)+3:)=ITDATE(:) + YRECFM=TRIM(TZFIELD%CMNHNAME) + IF( LEN_TRIM(TZFIELD%CMNHNAME) > LEN(YRECFM) ) & + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_lfi_T1','field name was truncated to '& + //YRECFM//' for '//TRIM(TZFIELD%CMNHNAME)) + CALL LFIECR(IRESP,TPFILE%NLFIFLU,YRECFM,IWORK,ITOTAL) +ENDIF +! +IF (ALLOCATED(IWORK)) DEALLOCATE(IWORK) +! +IF (IRESP/=0) THEN + KRESP = IRESP + RETURN +END IF +! +! Write time +! +TZFIELD%CMNHNAME = TRIM(TPFIELD%CMNHNAME)//'%TIME' +TZFIELD%CCOMMENT = 'SECONDS' +ILENG = SIZE( TPDATA ) +! +CALL WRITE_PREPARE(TZFIELD,ILENG,IWORK,ITOTAL,IRESP) +! +IF (IRESP==0) THEN + CALL TRANSFER_R_I8(TPDATA(:)%TIME,IWORK(LEN(TPFIELD%CCOMMENT)+3:)) + YRECFM=TRIM(TZFIELD%CMNHNAME) + IF( LEN_TRIM(TZFIELD%CMNHNAME) > LEN(YRECFM) ) & + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_lfi_T1','field name was truncated to '& + //YRECFM//' for '//TRIM(TZFIELD%CMNHNAME)) + CALL LFIECR(IRESP,TPFILE%NLFIFLU,YRECFM,IWORK,ITOTAL) +ENDIF +! +KRESP=IRESP +! +IF (ALLOCATED(IWORK)) DEALLOCATE(IWORK) +DEALLOCATE( ITDATE ) +! +END SUBROUTINE IO_Field_write_lfi_T1 +! SUBROUTINE WRITE_PREPARE(TPFIELD,KLENG,KWORK,KTOTAL,KRESP) ! TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD diff --git a/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 index aff7f36a2a0f708223db3bca817a6bd02b0e33c2..dfbe8b26f22f9eaf24bbbde0914a8a5ab704cdb6 100644 --- a/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 @@ -12,6 +12,7 @@ ! P. Wautelet 11/01/2019: NVERB_INFO->NVERB_WARNING for zero size fields ! P. Wautelet 01/02/2019: IO_Coordvar_write_nc4: bug: use of non-associated pointers (PIOCDF%DIM_Nx_y) ! P. Wautelet 05/03/2019: rename IO subroutines and modules +! P. Wautelet 12/07/2019: add support for 1D array of dates !----------------------------------------------------------------- #if defined(MNH_IOCDF4) module mode_io_write_nc4 @@ -45,7 +46,7 @@ INTERFACE IO_Field_write_nc4 IO_Field_write_nc4_N2,IO_Field_write_nc4_N3, & IO_Field_write_nc4_L0,IO_Field_write_nc4_L1, & IO_Field_write_nc4_C0,IO_Field_write_nc4_C1, & - IO_Field_write_nc4_T0 + IO_Field_write_nc4_T0,IO_Field_write_nc4_T1 END INTERFACE IO_Field_write_nc4 integer,parameter :: NSTRINGCHUNKSIZE = 16 !Dimension of the chunks of strings @@ -1371,7 +1372,7 @@ INTEGER(KIND=CDFINT) :: STATUS INTEGER(KIND=CDFINT) :: INCID CHARACTER(LEN=LEN(TPFIELD%CMNHNAME)) :: YVARNAME INTEGER(KIND=CDFINT) :: IVARID -INTEGER(KIND=CDFINT), DIMENSION(1) :: IVDIMS +INTEGER(KIND=CDFINT), DIMENSION(:), ALLOCATABLE :: IVDIMS INTEGER :: IRESP TYPE(TFIELDDATA) :: TZFIELD CHARACTER(LEN=40) :: YUNITS @@ -1502,6 +1503,112 @@ IF (status /= NF90_NOERR) CALL IO_Err_handle_nc4(status,'IO_Field_write_nc4_T0', KRESP = IRESP END SUBROUTINE IO_Field_write_nc4_T0 +SUBROUTINE IO_Field_write_nc4_T1(TPFILE,TPFIELD,TPDATA,KRESP) +! +USE MODD_TIME_n, ONLY: TDTMOD +USE MODD_TYPE_DATE +! +USE MODE_DATETIME +! +TYPE(TFILEDATA), INTENT(IN) :: TPFILE +TYPE(TFIELDDATA), INTENT(IN) :: TPFIELD +TYPE (DATE_TIME), DIMENSION(:), INTENT(IN) :: TPDATA +INTEGER, INTENT(OUT):: KRESP +! +INTEGER :: JI +INTEGER(KIND=CDFINT) :: STATUS +INTEGER(KIND=CDFINT) :: INCID +CHARACTER(LEN=LEN(TPFIELD%CMNHNAME)) :: YVARNAME +INTEGER(KIND=CDFINT) :: IVARID +INTEGER(KIND=CDFINT), DIMENSION(:), ALLOCATABLE :: IVDIMS +INTEGER :: IRESP +TYPE(TFIELDDATA) :: TZFIELD +CHARACTER(LEN=40) :: YUNITS +LOGICAL :: GEXISTED !True if variable was already defined +REAL, DIMENSION(:), ALLOCATABLE :: ZDELTATIME !Distance in seconds since reference date and time +TYPE(DATE_TIME) :: TZREF +! +CALL PRINT_MSG(NVERB_DEBUG,'IO','IO_Field_write_nc4_T1',TRIM(TPFILE%CNAME)//': writing '//TRIM(TPFIELD%CMNHNAME)) +! +IRESP = 0 +! +TZFIELD = TPFIELD +! +! Get the Netcdf file ID +INCID = TPFILE%NNCID +! +GEXISTED = .FALSE. +! +CALL IO_Mnhname_clean(TPFIELD%CMNHNAME,YVARNAME) +! +TZFIELD%CMNHNAME = TRIM(YVARNAME) +! +! Model beginning date (TDTMOD%TDATE) is used as the reference date +! Reference time is set to 0. +IF (.NOT.ASSOCIATED(TDTMOD)) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_nc4_T1',TRIM(TPFILE%CNAME)// & + ': '//TRIM(TZFIELD%CMNHNAME)//': DTMOD is not associated and not known. Reference date set to 2000/01/01') + TZREF%TDATE%YEAR = 2000 + TZREF%TDATE%MONTH = 1 + TZREF%TDATE%DAY = 1 + TZREF%TIME = 0. +ELSE + TZREF = TDTMOD + TZREF%TIME = 0. +END IF +WRITE(YUNITS,'( "seconds since ",I4.4,"-",I2.2,"-",I2.2," 00:00:00 +0:00" )') & + TZREF%TDATE%YEAR, TZREF%TDATE%MONTH, TZREF%TDATE%DAY +TZFIELD%CUNITS = TRIM(YUNITS) +! +IF (TPFIELD%LTIMEDEP) & + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_nc4_T1',TRIM(TPFILE%CNAME)// & + ': time dependent variable not (yet) possible for 1D 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 + IF (SIZE(TPDATA)==0) THEN + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_nc4_T1','ignoring variable with a zero size ('//TRIM(YVARNAME)//')') + KRESP = 0 + RETURN + END IF + + ! Get the netcdf dimensions + CALL IO_Vdims_fill_nc4(TPFILE, TPFIELD, INT(SHAPE(TPDATA),KIND=CDFINT), IVDIMS) + + ! Define the variable + STATUS = NF90_DEF_VAR(INCID, YVARNAME, MNHREAL_NF90, IVDIMS, IVARID) + IF (status /= NF90_NOERR) CALL IO_Err_handle_nc4(status,'IO_Field_write_nc4_T1','NF90_DEF_VAR',trim(YVARNAME)) +ELSE + GEXISTED = .TRUE. + CALL PRINT_MSG(NVERB_WARNING,'IO','IO_Field_write_nc4_N1',TRIM(TPFILE%CNAME)//': '//TRIM(YVARNAME)//' already defined') +END IF + +! Write metadata +CALL IO_Field_attr_write_nc4(TPFILE,TZFIELD,IVARID,GEXISTED,HCALENDAR='standard') +! +! Compute the temporal distances from reference +ALLOCATE( ZDELTATIME( SIZE( TPDATA ) ) ) + +DO JI = 1, SIZE( TPDATA ) + CALL DATETIME_DISTANCE( TZREF, TPDATA(JI ), ZDELTATIME(JI) ) +END DO + +! Write the data +STATUS = NF90_PUT_VAR( INCID, IVARID, ZDELTATIME(:) ) +IF (status /= NF90_NOERR) CALL IO_Err_handle_nc4(status,'IO_Field_write_nc4_T1','NF90_PUT_VAR',trim(YVARNAME),IRESP) + +IF( ALLOCATED( IVDIMS ) ) DEALLOCATE( IVDIMS ) +DEALLOCATE( ZDELTATIME ) + +IF (IRESP/=0) THEN + KRESP = IRESP + RETURN +END IF + +KRESP = IRESP +END SUBROUTINE IO_Field_write_nc4_T1 + SUBROUTINE IO_Coordvar_write_nc4(TPFILE,HPROGRAM_ORIG) USE MODD_CONF, ONLY: CPROGRAM, LCARTESIAN USE MODD_CONF_n, ONLY: CSTORAGE_TYPE