From 73a8606fbcf0c337073a709671c061586ad01d5c Mon Sep 17 00:00:00 2001 From: Philippe WAUTELET <philippe.wautelet@aero.obs-mip.fr> Date: Thu, 17 Dec 2020 14:45:48 +0100 Subject: [PATCH] Philippe 17/12/2020: Write_time_coord: generalize to vector of dates and add management of date intervals (conform to CF conventions) --- src/LIB/SURCOUCHE/src/modd_field.f90 | 4 +- src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 | 4 + src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 | 151 +++++++++++++------- 3 files changed, 108 insertions(+), 51 deletions(-) diff --git a/src/LIB/SURCOUCHE/src/modd_field.f90 b/src/LIB/SURCOUCHE/src/modd_field.f90 index 28558a41a..bdb77e321 100644 --- a/src/LIB/SURCOUCHE/src/modd_field.f90 +++ b/src/LIB/SURCOUCHE/src/modd_field.f90 @@ -81,7 +81,9 @@ integer, parameter :: NMNHDIM_FLYER_TIME = 36 ! Time dimension for air integer, parameter :: NMNHDIM_PROFILER_TIME = 37 ! Time dimension for profilers integer, parameter :: NMNHDIM_STATION_TIME = 38 ! Time dimension for stations -integer, parameter :: NMNHDIM_LASTDIM_DIACHRO = 38 ! Index of the last defined dimension for diachronic files +integer, parameter :: NMNHDIM_PAIR = 39 ! For values coming by pair (ie boundaries) + +integer, parameter :: NMNHDIM_LASTDIM_DIACHRO = 39 ! Index of the last defined dimension for diachronic files integer, parameter :: NMNHDIM_BUDGET_NGROUPS = 101 ! This is not a true dimension integer, parameter :: NMNHDIM_FLYER_PROC = 102 ! This is not a true dimension diff --git a/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 index aa479c9ef..8aed353ff 100644 --- a/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_tools_nc4.f90 @@ -263,6 +263,7 @@ use modd_field, only: NMNHDIM_NI, NMNHDIM_NJ, NMNHDIM_NI_U, NMNHDIM_NJ_U NMNHDIM_SPECTRA_SPEC_NI, NMNHDIM_SPECTRA_SPEC_NJ, NMNHDIM_SPECTRA_LEVEL, & NMNHDIM_SERIES_LEVEL, NMNHDIM_SERIES_LEVEL_W, & NMNHDIM_SERIES_TIME, NMNHDIM_PROFILER_TIME, NMNHDIM_STATION_TIME, & + NMNHDIM_PAIR, & NMNHDIM_ARAKAWA, & NMNHDIM_LASTDIM_NODIACHRO, NMNHDIM_LASTDIM_DIACHRO @@ -337,6 +338,9 @@ if ( tpfile%ctype == 'MNHDIACHRONIC' ) then !Dimension of size 2 used for NMNHDIM_COMPLEX call IO_Add_dim_nc4( tpfile, NMNHDIM_COMPLEX, 'real_imaginary', 2 ) + !Dimension pair is used ie for boundaries of time intervals + call IO_Add_dim_nc4( tpfile, NMNHDIM_PAIR, 'pair', 2 ) + !Dimensions for the budgets masks if ( cbutype == 'CART' .or. cbutype == 'SKIP' ) then if ( .not. lbu_icp ) call IO_Add_dim_nc4( tpfile, NMNHDIM_BUDGET_CART_NI, 'cart_ni', nbuimax_ll ) diff --git a/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 index 1bd9bd100..2b1d3f203 100644 --- a/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 +++ b/src/LIB/SURCOUCHE/src/mode_io_write_nc4.f90 @@ -1219,6 +1219,7 @@ USE MODD_GRID, ONLY: XLATORI, XLONORI USE MODD_GRID_n, ONLY: LSLEVE, XXHAT, XYHAT, XZHAT use modd_netcdf, only: tdimnc USE MODD_PARAMETERS, ONLY: JPHEXT, JPVEXT +use modd_time_n, only: tdtcur use mode_field, only: Find_field_id_from_mnhname USE MODE_GRIDPROJ @@ -1408,8 +1409,8 @@ END IF 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 - if ( tpfile%ctype /= 'MNHDIACHRONIC' ) & - CALL WRITE_TIME_COORD(tpfile%tncdims%tdims(NMNHDIM_TIME)) + if ( tpfile%ctype /= 'MNHDIACHRONIC' .and. Associated( tdtcur ) ) & + call Write_time_coord( tpfile%tncdims%tdims(NMNHDIM_TIME), [ tdtcur ] ) END IF END IF @@ -1677,66 +1678,116 @@ SUBROUTINE WRITE_VER_COORD(TDIM,HLONGNAME,HSTDNAME,HCOMPNAME,PSHIFT,KBOUNDLOW,KB END SUBROUTINE WRITE_VER_COORD -SUBROUTINE WRITE_TIME_COORD(TDIM) - use modd_field, only: tfieldlist - USE MODD_TIME_n, ONLY: TDTMOD, TDTCUR - USE MODD_TYPE_DATE +subroutine Write_time_coord( tdim, tpdates, tpdates_bound ) + use modd_field, only: NMNHDIM_PAIR, tfieldlist + use modd_time_n, only: tdtmod + use modd_type_date, only: date_time - USE MODE_DATETIME + use mode_datetime, only: Datetime_distance use mode_field, only: Find_field_id_from_mnhname - USE MODE_GRIDPROJ - TYPE(tdimnc), POINTER, INTENT(IN) :: TDIM + type(tdimnc), pointer, intent(in) :: tdim + type(date_time), dimension(:), intent(in) :: tpdates + type(date_time), dimension(:,:), optional, intent(in) :: tpdates_bound !Boundaries of the date intervals + + character(len=40) :: yunits + character(len=:), allocatable :: yvarname + integer :: jt + integer(kind=CDFINT) :: ivarid + integer(kind=CDFINT) :: ivdim + integer(kind=CDFINT) :: istatus + integer(kind=CDFINT), dimension(2) :: ivdims + real, dimension(:), allocatable :: zdeltatimes_1d + real, dimension(:,:), allocatable :: zdeltatimes_2d + type(date_time) :: tzref + + if ( Associated( tdtmod ) ) then + ! Model beginning date (tdtmod%tdate) is used as the reference date + ! Reference time is set to 0. + tzref = tdtmod + tzref%time = 0. + else + tzref%tdate%year = 2000 + tzref%tdate%month = 1 + tzref%tdate%day = 1 + tzref%time = 0. + end if - REAL :: ZDELTATIME - CHARACTER(LEN=40) :: YUNITS - CHARACTER(LEN=:),ALLOCATABLE :: YVARNAME - INTEGER(KIND=CDFINT) :: IVARID - INTEGER(KIND=CDFINT) :: IVDIM - INTEGER(KIND=CDFINT) :: istatus - TYPE(DATE_TIME) :: TZREF + yvarname = Trim( tdim%cname ) + ivdim = tdim%nid + istatus = NF90_INQ_VARID( incid, yvarname, ivarid ) + if ( istatus /= NF90_NOERR ) then + ! Define the coordinate variable + istatus = NF90_DEF_VAR( incid, yvarname, mnhreal_nf90, ivdim, ivarid ) + if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_DEF_VAR', Trim( yvarname ) ) + else + call Print_msg( NVERB_ERROR, 'IO', 'Write_time_coord', Trim( yvarname ) // ' already defined' ) + end if - IF (ASSOCIATED(TDTCUR) .AND. ASSOCIATED(TDTMOD)) THEN - yvarname = Trim( tdim%cname ) - ivdim = tdim%nid + ! Write metadata + istatus = NF90_PUT_ATT( incid, ivarid, 'long_name', 'time axis' ) + if ( istatus /= NF90_NOERR ) & + call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', 'long_name for ' // Trim( yvarname ) ) + istatus = NF90_PUT_ATT( incid, ivarid, 'standard_name','time' ) + IF ( istatus /= NF90_NOERR ) & + call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', 'standard_name for ' // Trim( yvarname ) ) + Write( yunits, '( "seconds since ", i4.4, "-", i2.2, "-", i2.2, " 00:00:00 +0:00" )' ) & + tzref%tdate%year, tzref%tdate%month, tzref%tdate%day + istatus = NF90_PUT_ATT( incid, ivarid, 'units', yunits ) + if ( istatus /= NF90_NOERR ) & + call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', 'units for ' // Trim( yvarname ) ) + istatus = NF90_PUT_ATT( incid, ivarid, 'axis', 'T' ) + if ( istatus /= NF90_NOERR ) & + call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', 'axis for ' // Trim( yvarname ) ) + istatus = NF90_PUT_ATT( incid, ivarid, 'calendar', 'standard' ) + if ( istatus /= NF90_NOERR ) & + call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', 'calendar for ' // Trim( yvarname ) ) + if ( Present( tpdates_bound ) ) then + istatus = NF90_PUT_ATT( incid, ivarid, 'bounds', Trim( yvarname ) // '_bounds' ) + if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_ATT', & + 'bounds for ' // Trim( yvarname ) ) + end if - istatus = NF90_INQ_VARID(INCID, YVARNAME, IVARID) - IF (istatus /= NF90_NOERR) THEN + ! Compute the temporal distance from reference + Allocate( zdeltatimes_1d(Size( tpdates )) ) + do jt = 1, Size( tpdates ) + call Datetime_distance( tzref, tpdates(jt), zdeltatimes_1d(jt) ) + end do + + ! Write the data + istatus = NF90_PUT_VAR( incid, ivarid, zdeltatimes_1d ) + if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_VAR', Trim( yvarname ) ) + + Deallocate( zdeltatimes_1d ) + + !Write the date interval boundaries (if provided) + if ( Present( tpdates_bound ) ) then + yvarname = Trim( tdim%cname ) // '_bounds' + istatus = NF90_INQ_VARID( incid, yvarname, ivarid ) + if ( istatus /= NF90_NOERR ) then ! Define the coordinate variable - istatus = NF90_DEF_VAR(INCID, YVARNAME, MNHREAL_NF90, IVDIM, IVARID) - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_DEF_VAR',trim(YVARNAME)) - ELSE - CALL PRINT_MSG(NVERB_ERROR,'IO','WRITE_TIME_COORD',TRIM(YVARNAME)//' already defined') - END IF + ivdims(1) = tpfile%tncdims%tdims(NMNHDIM_PAIR)%nid + ivdims(2) = tdim%nid + istatus = NF90_DEF_VAR( incid, yvarname, MNHREAL_NF90, ivdims, ivarid ) + if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_DEF_VAR', Trim( yvarname ) ) + else + call Print_msg( NVERB_ERROR, 'IO', 'Write_time_coord', Trim( yvarname ) // ' already defined' ) + end if - ! Write metadata - istatus = NF90_PUT_ATT(INCID, IVARID, 'long_name','time axis') - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_ATT','long_name for '//trim(YVARNAME)) - istatus = NF90_PUT_ATT(INCID, IVARID, 'standard_name','time') - IF (istatus /= NF90_NOERR) & - CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_ATT','standard_name for '//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 - istatus = NF90_PUT_ATT(INCID, IVARID, 'units',YUNITS) - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_ATT','units for '//trim(YVARNAME)) - istatus = NF90_PUT_ATT(INCID, IVARID, 'axis','T') - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_ATT','axis for '//trim(YVARNAME)) - istatus = NF90_PUT_ATT(INCID, IVARID,'calendar','standard') - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_ATT','calendar for '//trim(YVARNAME)) - - ! 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) + Allocate( zdeltatimes_2d(2, Size( tpdates_bound, 2 )) ) + do jt = 1, Size( tpdates_bound, 2 ) + call Datetime_distance( tzref, tpdates_bound(1, jt), zdeltatimes_2d(1, jt) ) + call Datetime_distance( tzref, tpdates_bound(2, jt), zdeltatimes_2d(2, jt) ) + end do + ! Write the data - istatus = NF90_PUT_VAR(INCID, IVARID, ZDELTATIME) - IF (istatus /= NF90_NOERR) CALL IO_Err_handle_nc4(istatus,'WRITE_TIME_COORD','NF90_PUT_VAR',trim(YVARNAME)) - END IF + istatus = NF90_PUT_VAR( incid, ivarid, zdeltatimes_2d(:,:) ) + if ( istatus /= NF90_NOERR ) call IO_Err_handle_nc4( istatus, 'Write_time_coord', 'NF90_PUT_VAR', Trim( yvarname ) ) + end if -END SUBROUTINE WRITE_TIME_COORD +end subroutine Write_time_coord END SUBROUTINE IO_Coordvar_write_nc4 -- GitLab