diff --git a/.github/actions/deploy-ford-docs/action.yml b/.github/actions/deploy-ford-docs/action.yml index 94dee1da508a..b4fd656f4920 100644 --- a/.github/actions/deploy-ford-docs/action.yml +++ b/.github/actions/deploy-ford-docs/action.yml @@ -49,14 +49,14 @@ runs: repository: Goddard-Fortran-Ecosystem/gFTL path: gFTL fetch-depth: 1 - ref: v1.13.0 + ref: v1.14.0 - name: Build gFTL run: | cd gFTL mkdir -p build cd build - cmake .. -DCMAKE_Fortran_COMPILER=gfortran-10 -DCMAKE_INSTALL_PREFIX=../install + cmake .. -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_INSTALL_PREFIX=../install make -j$(nproc) install shell: bash diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c1a585eef8..51e7b7f1b511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,12 +74,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added optional start_date and start_time to control the output window for each History collection. No output will be written before then. If not specified, these default to the beginning of the experiment. - Added utility to prepare inputs for ExtDatDriver.x so that ExtData can simulate a real GEOS run - Added loggers when writing or reading weight files - Added new option to AGCM.rc `overwrite_checkpoint` to allow checkpoint files to be overwritten. By default still will not overwrite checkpoints ### Changed +- Changed MAPL_ESMFRegridder to require the dstMaskValues to be added as grid attribute to use fixed masking, fixes UFS issue - Increased formatting width of time index in ExtData2G diagnostic print ### Fixed diff --git a/base/MAPL_EsmfRegridder.F90 b/base/MAPL_EsmfRegridder.F90 index b3b41a730a4c..65437ace4ad8 100644 --- a/base/MAPL_EsmfRegridder.F90 +++ b/base/MAPL_EsmfRegridder.F90 @@ -1431,13 +1431,13 @@ subroutine create_route_handle(this, kind, rc) real(real64), pointer :: src_dummy_r8(:,:), dst_dummy_r8(:,:) type (ESMF_Field) :: src_field, dst_field - integer :: srcTermProcessing + integer :: srcTermProcessing, num_mask_values integer, pointer :: factorIndexList(:,:) integer, allocatable :: dstMaskValues(:) real(ESMF_KIND_R8), pointer :: factorList(:) type(ESMF_RouteHandle) :: dummy_rh type(ESMF_UnmappedAction_Flag) :: unmappedaction - logical :: global, isPresent, has_mask + logical :: global, isPresent, has_mask, has_dstMaskValues type(RegridderSpecRouteHandleMap), pointer :: route_handles, transpose_route_handles type(ESMF_RouteHandle) :: route_handle, transpose_route_handle character(len=ESMF_MAXPATHLEN) :: rh_file,rh_trans_file @@ -1513,6 +1513,14 @@ subroutine create_route_handle(this, kind, rc) end if call ESMF_GridGetItem(spec%grid_out,itemflag=ESMF_GRIDITEM_MASK, & staggerloc=ESMF_STAGGERLOC_CENTER, isPresent = has_mask, _RC) + call ESMF_InfoGetFromHost(spec%grid_out,infoh,_RC) + has_dstMaskValues = ESMF_InfoIsPresent(infoh,MAPL_DESTINATIONMASK,_RC) + if (has_dstMaskValues) then + _ASSERT(has_mask, "masking destination values when no masks is present") + call ESMF_InfoGet(infoh,MAPL_DESTINATIONMASK,num_mask_values,_RC) + allocate(dstMaskValues(num_mask_values), _STAT) + call ESMF_InfoGet(infoh,MAPL_DESTINATIONMASK,dstMaskValues,_RC) + end if counter = counter + 1 @@ -1523,7 +1531,6 @@ subroutine create_route_handle(this, kind, rc) call ESMF_InfoGet(infoh,'Global',global,_RC) if (.not.global) unmappedaction=ESMF_UNMAPPEDACTION_IGNORE end if - if (has_mask) dstMaskValues = [MAPL_MASK_OUT] ! otherwise unallocated select case (spec%regrid_method) case (REGRID_METHOD_BILINEAR, REGRID_METHOD_BILINEAR_MONOTONIC) diff --git a/base/MAPL_XYGridFactory.F90 b/base/MAPL_XYGridFactory.F90 index 35be375a77c5..5af32a373019 100644 --- a/base/MAPL_XYGridFactory.F90 +++ b/base/MAPL_XYGridFactory.F90 @@ -1020,6 +1020,7 @@ subroutine add_mask(this,grid,rc) integer :: status type(ESMF_VM) :: vm integer :: has_undef, local_has_undef + type(ESMF_Info) :: infoh call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, & staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=fptr, _RC) @@ -1041,6 +1042,9 @@ subroutine add_mask(this,grid,rc) mask = MAPL_MASK_IN where(fptr==MAPL_UNDEF) mask = MAPL_MASK_OUT + call ESMF_InfoGetFromHost(grid,infoh,_RC) + call ESMF_InfoSet(infoh,key=MAPL_DESTINATIONMASK,values=[MAPL_MASK_OUT],_RC) + _RETURN(_SUCCESS) end subroutine add_mask diff --git a/docs/Ford/docs-with-remote-esmf.md b/docs/Ford/docs-with-remote-esmf.md index 85b147f629ea..289ec6802aea 100644 --- a/docs/Ford/docs-with-remote-esmf.md +++ b/docs/Ford/docs-with-remote-esmf.md @@ -7,8 +7,8 @@ coloured_edges: true graph_maxdepth: 4 graph_maxnodes: 32 include: ../../include/ - ../../gFTL/install/GFTL-1.13/include/v1 - ../../gFTL/install/GFTL-1.13/include/v2 + ../../gFTL/install/GFTL-1.14/include/v1 + ../../gFTL/install/GFTL-1.14/include/v2 exclude: **/EsmfRegridder.F90 **/FieldBLAS_IntrinsicFunctions.F90 **/GeomManager.F90 diff --git a/docs/Ford/docs-with-remote-esmf.public_private_protected.md b/docs/Ford/docs-with-remote-esmf.public_private_protected.md index 639e51d78cd8..bec05b34b96f 100644 --- a/docs/Ford/docs-with-remote-esmf.public_private_protected.md +++ b/docs/Ford/docs-with-remote-esmf.public_private_protected.md @@ -8,8 +8,8 @@ coloured_edges: true graph_maxdepth: 4 graph_maxnodes: 32 include: ../../include/ - ../../gFTL/install/GFTL-1.13/include/v1 - ../../gFTL/install/GFTL-1.13/include/v2 + ../../gFTL/install/GFTL-1.14/include/v1 + ../../gFTL/install/GFTL-1.14/include/v2 exclude: **/EsmfRegridder.F90 **/FieldBLAS_IntrinsicFunctions.F90 **/GeomManager.F90 diff --git a/docs/Ford/ford-ci.md b/docs/Ford/ford-ci.md index 0a799b023563..b02c131f76f1 100644 --- a/docs/Ford/ford-ci.md +++ b/docs/Ford/ford-ci.md @@ -8,8 +8,8 @@ coloured_edges: true graph_maxdepth: 4 graph_maxnodes: 32 include: ../../include/ - ../../gFTL/install/GFTL-1.13/include/v1 - ../../gFTL/install/GFTL-1.13/include/v2 + ../../gFTL/install/GFTL-1.14/include/v1 + ../../gFTL/install/GFTL-1.14/include/v2 exclude: **/EsmfRegridder.F90 **/FieldBLAS_IntrinsicFunctions.F90 **/GeomManager.F90 diff --git a/docs/Ford/mapl3docs-with-remote-esmf.md b/docs/Ford/mapl3docs-with-remote-esmf.md index 7f55982528ed..a6006529aaaa 100644 --- a/docs/Ford/mapl3docs-with-remote-esmf.md +++ b/docs/Ford/mapl3docs-with-remote-esmf.md @@ -8,8 +8,8 @@ coloured_edges: true graph_maxdepth: 4 graph_maxnodes: 32 include: ../../include/ - ../../gFTL/install/GFTL-1.13/include/v1 - ../../gFTL/install/GFTL-1.13/include/v2 + ../../gFTL/install/GFTL-1.14/include/v1 + ../../gFTL/install/GFTL-1.14/include/v2 exclude: **/EsmfRegridder.F90 **/FieldBLAS_IntrinsicFunctions.F90 **/GeomManager.F90 diff --git a/docs/Ford/mapl3docs-with-remote-esmf.public_private_protected.md b/docs/Ford/mapl3docs-with-remote-esmf.public_private_protected.md index e67f1adfe622..89fd00787dd7 100644 --- a/docs/Ford/mapl3docs-with-remote-esmf.public_private_protected.md +++ b/docs/Ford/mapl3docs-with-remote-esmf.public_private_protected.md @@ -8,8 +8,8 @@ coloured_edges: true graph_maxdepth: 4 graph_maxnodes: 32 include: ../../include/ - ../../gFTL/install/GFTL-1.13/include/v1 - ../../gFTL/install/GFTL-1.13/include/v2 + ../../gFTL/install/GFTL-1.14/include/v1 + ../../gFTL/install/GFTL-1.14/include/v2 exclude: **/EsmfRegridder.F90 **/FieldBLAS_IntrinsicFunctions.F90 **/GeomManager.F90 diff --git a/gridcomps/History/MAPL_HistoryCollection.F90 b/gridcomps/History/MAPL_HistoryCollection.F90 index 336773e0400d..1a6827e7c985 100644 --- a/gridcomps/History/MAPL_HistoryCollection.F90 +++ b/gridcomps/History/MAPL_HistoryCollection.F90 @@ -47,12 +47,15 @@ module MAPL_HistoryCollectionMod integer :: acc_offset integer :: ref_date integer :: ref_time + integer :: start_date + integer :: start_time integer :: end_date integer :: end_time integer :: duration type(ESMF_Alarm) :: his_alarm ! when to write file type(ESMF_Alarm) :: seg_alarm ! segment alarm controls when to write to new file type(ESMF_Alarm) :: mon_alarm + type(ESMF_Alarm) :: start_alarm type(ESMF_Alarm) :: end_alarm integer,pointer :: expSTATE (:) integer :: unit @@ -70,6 +73,7 @@ module MAPL_HistoryCollectionMod integer :: verbose integer :: xyoffset logical :: disabled + logical :: skipWriting logical :: subVm logical :: backwards ! Adds support for clock running in reverse direction logical :: useNewFormat diff --git a/gridcomps/History/MAPL_HistoryGridComp.F90 b/gridcomps/History/MAPL_HistoryGridComp.F90 index 75d47a792710..7eefc9e39bc8 100644 --- a/gridcomps/History/MAPL_HistoryGridComp.F90 +++ b/gridcomps/History/MAPL_HistoryGridComp.F90 @@ -56,7 +56,7 @@ module MAPL_HistoryGridCompMod use MaskSamplerGeosatMod use MAPL_StringTemplate use regex_module - use MAPL_TimeUtilsMod, only: is_valid_time, is_valid_date + use MAPL_TimeUtilsMod, only: is_valid_time, is_valid_date, MAPL_UndefInt use gFTL_StringStringMap !use ESMF_CFIOMOD use MAPL_EpochSwathMod @@ -812,16 +812,19 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) label=trim(string) // 'ref_time:',_RC ) _ASSERT(is_valid_time(list(n)%ref_time),'Invalid ref_time') - call ESMF_ConfigGetAttribute ( cfg, list(n)%end_date, default=-999, & + call ESMF_ConfigGetAttribute ( cfg, list(n)%start_date, default=MAPL_UndefInt, & + label=trim(string) // 'start_date:',_RC ) + _ASSERT(is_valid_date(list(n)%start_date),'Invalid start_date') + call ESMF_ConfigGetAttribute ( cfg, list(n)%start_time, default=MAPL_UndefInt, & + label=trim(string) // 'start_time:',_RC ) + _ASSERT(is_valid_time(list(n)%start_time),'Invalid start_time') + + call ESMF_ConfigGetAttribute ( cfg, list(n)%end_date, default=MAPL_UndefInt, & label=trim(string) // 'end_date:',_RC ) - if (list(n)%end_date /= -999) then - _ASSERT(is_valid_date(list(n)%end_date),'Invalid end_date') - end if - call ESMF_ConfigGetAttribute ( cfg, list(n)%end_time, default=-999, & + _ASSERT(is_valid_date(list(n)%end_date),'Invalid end_date') + call ESMF_ConfigGetAttribute ( cfg, list(n)%end_time, default=MAPL_UndefInt, & label=trim(string) // 'end_time:',_RC ) - if (list(n)%end_time /= -999) then - _ASSERT(is_valid_time(list(n)%end_time),'Invalid end_time') - end if + _ASSERT(is_valid_time(list(n)%end_time),'Invalid end_time') call ESMF_ConfigGetAttribute ( cfg, list(n)%duration, default=list(n)%frequency, & label=trim(string) // 'duration:' ,_RC ) @@ -1350,9 +1353,41 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) intState%stampOffset(n) = Frequency ! we go to the beginning of the month end if +! End Alarm based on start_date and start_time +! ---------------------------------------- + if( list(n)%start_date.ne.MAPL_UndefInt .and. list(n)%start_time.ne.MAPL_UndefInt ) then + REF_TIME(1) = list(n)%start_date/10000 + REF_TIME(2) = mod(list(n)%start_date,10000)/100 + REF_TIME(3) = mod(list(n)%start_date,100) + REF_TIME(4) = list(n)%start_time/10000 + REF_TIME(5) = mod(list(n)%start_time,10000)/100 + REF_TIME(6) = mod(list(n)%start_time,100) + + call ESMF_TimeSet( RingTime, YY = REF_TIME(1), & + MM = REF_TIME(2), & + DD = REF_TIME(3), & + H = REF_TIME(4), & + M = REF_TIME(5), & + S = REF_TIME(6), calendar=cal, rc=rc ) + else + RingTime = CurrTime + end if + list(n)%start_alarm = ESMF_AlarmCreate( clock=clock, RingTime=RingTime, sticky=.false., _RC ) + + list(n)%skipWriting = .true. + if (RingTime == CurrTime) then + call ESMF_AlarmRingerOn(list(n)%start_alarm, _RC ) + list(n)%skipWriting = .false. + else + if (RingTime < CurrTime .NEQV. list(n)%backwards) then + list(n)%skipWriting = .false. + endif + end if + + ! End Alarm based on end_date and end_time ! ---------------------------------------- - if( list(n)%end_date.ne.-999 .and. list(n)%end_time.ne.-999 ) then + if( list(n)%end_date.ne.MAPL_UndefInt .and. list(n)%end_time.ne.MAPL_UndefInt ) then REF_TIME(1) = list(n)%end_date/10000 REF_TIME(2) = mod(list(n)%end_date,10000)/100 REF_TIME(3) = mod(list(n)%end_date,100) @@ -2532,9 +2567,13 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) else print *, ' Duration: ', list(n)%duration end if - if( list(n)%end_date.ne.-999 ) then - print *, ' End_Date: ', list(n)%end_date - print *, ' End_Time: ', list(n)%end_time + if( list(n)%start_date.ne.MAPL_UndefInt ) then + print *, ' Start_Date: ', list(n)%start_date + print *, ' Start_Time: ', list(n)%start_time + endif + if( list(n)%end_date.ne.MAPL_UndefInt ) then + print *, ' End_Date: ', list(n)%end_date + print *, ' End_Time: ', list(n)%end_time endif if (trim(list(n)%output_grid_label)/='') then print *, ' Regrid Mthd: ', regrid_method_int_to_string(list(n)%regrid_method) @@ -3433,6 +3472,14 @@ subroutine Run ( gc, import, export, clock, rc ) ! decide if we are writing based on alarms + do n=1,nlist + if (list(n)%skipWriting) then + if (ESMF_AlarmIsRinging(list(n)%start_alarm)) then + list(n)%skipWriting = .false. + endif + endif + end do + do n=1,nlist if (list(n)%disabled .or. ESMF_AlarmIsRinging(list(n)%end_alarm) ) then list(n)%disabled = .true. @@ -3460,6 +3507,8 @@ subroutine Run ( gc, import, export, clock, rc ) end if end if + if (list(n)%skipWriting) writing(n) = .false. + if (writing(n) .and. .not.IntState%average(n)) then ! R8 to R4 copy (if needed!) do m=1,list(n)%field_set%nfields diff --git a/shared/Constants/InternalConstants.F90 b/shared/Constants/InternalConstants.F90 index 3cad2914e86f..bd02f1fe51d3 100644 --- a/shared/Constants/InternalConstants.F90 +++ b/shared/Constants/InternalConstants.F90 @@ -23,6 +23,7 @@ module MAPL_InternalConstantsMod character(len=*), parameter :: MAPL_GRID_NAME_DEFAULT = 'UNKNOWN' character(len=*), parameter :: MAPL_GRID_FILE_NAME_DEFAULT = 'UNKNOWN' character(len=*), parameter :: MAPL_CF_COMPONENT_SEPARATOR = '.' + character(len=*), parameter :: MAPL_DESTINATIONMASK = "MAPL_DestinationMask" enum, bind(c) enumerator MAPL_TimerModeOld diff --git a/shared/TimeUtils.F90 b/shared/TimeUtils.F90 index 57fe47f15301..460670adcdde 100644 --- a/shared/TimeUtils.F90 +++ b/shared/TimeUtils.F90 @@ -7,6 +7,8 @@ module MAPL_TimeUtilsMod public :: is_valid_time public :: is_valid_datetime + integer, public, parameter :: MAPL_UndefInt = -999 + contains logical function is_valid_date(date) result(is_valid) @@ -19,6 +21,11 @@ logical function is_valid_date(date) result(is_valid) integer :: year, month, day logical :: is_leap_year + if (date == MAPL_UndefInt) then + is_valid = .true. + return + end if + year = date/10000 month = mod(date,10000)/100 day = mod(date,100) @@ -66,6 +73,11 @@ logical function is_valid_time(time) result(is_valid) integer :: hours, minutes, seconds + if (time == MAPL_UndefInt) then + is_valid = .true. + return + end if + hours = time/10000 minutes = mod(time,10000)/100 seconds = mod(time,100)