diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f7d276e422..b9b8c7724fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added test case for regridding from CubedSphere to Loctream - Added regression test for Regrid\_Util.x - External pfio server GridComp and ctest: new `mapl_PfioServerGridComp_mod` provides an ESMF GridComp whose `run` phase creates and starts an `MpiServer` or diff --git a/gridcomps/componentDriverGridComp/componentDriverGridComp.F90 b/gridcomps/componentDriverGridComp/componentDriverGridComp.F90 index a7c6fc906b9..276f2bc4475 100644 --- a/gridcomps/componentDriverGridComp/componentDriverGridComp.F90 +++ b/gridcomps/componentDriverGridComp/componentDriverGridComp.F90 @@ -200,6 +200,36 @@ subroutine initialize_internal_state(internal_state, support, hconfig, rc) type(ESMF_HConfig), intent(in) :: hconfig integer, optional, intent(out) :: rc + integer :: status + type(ESMF_Field) :: field + type(ESMF_GeomType_Flag) :: geomtype + + ! The internal-state fields (rand, grid_lons, grid_lats, quarter_grid) + ! are built on this component's own geometry. That geometry is normally + ! an ESMF_Grid (rank-2 horizontal fields), but it may also be a + ! non-gridded geometry such as ESMF_LocStream (rank-1 fields). Dispatch + ! on the actual geom type of one of these fields to pick the correct + ! rank-specific implementation. + call ESMF_StateGet(internal_state, 'rand', field, _RC) + call ESMF_FieldGet(field, geomtype=geomtype, _RC) + + if (geomtype == ESMF_GEOMTYPE_GRID) then + call initialize_internal_state_grid(internal_state, hconfig, _RC) + else if (geomtype == ESMF_GEOMTYPE_LOCSTREAM) then + call initialize_internal_state_locstream(internal_state, hconfig, _RC) + else + _FAIL('componentDriverGridComp: unsupported geometry type for internal state') + end if + + _RETURN(_SUCCESS) + + end subroutine initialize_internal_state + + subroutine initialize_internal_state_grid(internal_state, hconfig, rc) + type(ESMF_State), intent(inout) :: internal_state + type(ESMF_HConfig), intent(in) :: hconfig + integer, optional, intent(out) :: rc + real, pointer :: ptr_2d(:, :) real(kind=ESMF_KIND_R8), pointer :: coords(:, :) integer :: status, seed_size, mypet, i, j @@ -253,7 +283,61 @@ subroutine initialize_internal_state(internal_state, support, hconfig, rc) _RETURN(_SUCCESS) - end subroutine initialize_internal_state + end subroutine initialize_internal_state_grid + + subroutine initialize_internal_state_locstream(internal_state, hconfig, rc) + type(ESMF_State), intent(inout) :: internal_state + type(ESMF_HConfig), intent(in) :: hconfig + integer, optional, intent(out) :: rc + + real, pointer :: ptr_1d(:) + real(kind=ESMF_KIND_R8), pointer :: coords(:) + integer :: status, seed_size, mypet, i + integer, allocatable :: seeds(:) + type(ESMF_Field) :: field + type(ESMF_LocStream) :: locstream + type(ESMF_VM) :: vm + logical :: is_present + real :: quarter_grid_fac1, quarter_grid_fac2 + + ! rand + call MAPL_StateGetPointer(internal_state, ptr_1d, 'rand', _RC) + call random_seed(size=seed_size) + allocate(seeds(seed_size)) + call ESMF_VMGetCurrent(vm, _RC) + call ESMF_VMGet(vm, localPet=mypet, _RC) + seeds = mypet + call random_seed(put=seeds) + call random_number(ptr_1d) + ! lons and lats + call MAPL_StateGetPointer(internal_state, ptr_1d, 'grid_lons', _RC) + call ESMF_StateGet(internal_state, 'grid_lons', field, _RC) + call ESMF_FieldGet(field, locstream=locstream, _RC) + call ESMF_LocStreamGetKey(locstream, keyName='ESMF:Lon', farray=coords, _RC) + ptr_1d = real(coords, kind=kind(ptr_1d)) + call MAPL_StateGetPointer(internal_state, ptr_1d, 'grid_lats', _RC) + call ESMF_LocStreamGetKey(locstream, keyName='ESMF:Lat', farray=coords, _RC) + ptr_1d = real(coords, kind=kind(ptr_1d)) + + quarter_grid_fac1 = 1.0 + quarter_grid_fac2 = 2.0 + is_present = ESMF_HConfigIsDefined(hconfig, keyString='quarter_grid_fac1', _RC) + if (is_present) then + quarter_grid_fac1 = ESMF_HConfigAsR4(hconfig, keyString='quarter_grid_fac1', _RC) + end if + is_present = ESMF_HConfigIsDefined(hconfig, keyString='quarter_grid_fac2', _RC) + if (is_present) then + quarter_grid_fac2 = ESMF_HConfigAsR4(hconfig, keyString='quarter_grid_fac2', _RC) + end if + call MAPL_StateGetPointer(internal_state, ptr_1d, 'quarter_grid', _RC) + ptr_1d = quarter_grid_fac2 + do i = 1, size(ptr_1d), 2 + ptr_1d(i) = quarter_grid_fac1 + end do + + _RETURN(_SUCCESS) + + end subroutine initialize_internal_state_locstream subroutine update_internal_state(internal_state, current_time, support, rc) type(ESMF_State), intent(inout) :: internal_state @@ -263,9 +347,28 @@ subroutine update_internal_state(internal_state, current_time, support, rc) integer :: status real, pointer :: ptr_2d(:, :) - - call MAPL_StateGetPointer(internal_state, ptr_2d, 'time_interval', _RC) - ptr_2d = support%tFunc%evaluate_time(current_time, _RC) + real, pointer :: ptr_1d(:) + type(ESMF_Field) :: field + type(ESMF_GeomType_Flag) :: geomtype + real :: time_value + + ! The 'time_interval' internal field is built on this component's own + ! geometry, which may be an ESMF_Grid (rank-2) or a non-gridded + ! geometry such as ESMF_LocStream (rank-1). + call ESMF_StateGet(internal_state, 'time_interval', field, _RC) + call ESMF_FieldGet(field, geomtype=geomtype, _RC) + + time_value = support%tFunc%evaluate_time(current_time, _RC) + + if (geomtype == ESMF_GEOMTYPE_GRID) then + call MAPL_StateGetPointer(internal_state, ptr_2d, 'time_interval', _RC) + ptr_2d = time_value + else if (geomtype == ESMF_GEOMTYPE_LOCSTREAM) then + call MAPL_StateGetPointer(internal_state, ptr_1d, 'time_interval', _RC) + ptr_1d = time_value + else + _FAIL('componentDriverGridComp: unsupported geometry type for internal state') + end if _RETURN(_SUCCESS) diff --git a/infrastructure/esmf/FieldPointerUtilities.F90 b/infrastructure/esmf/FieldPointerUtilities.F90 index 229bf04e6ad..d8b33c60b17 100644 --- a/infrastructure/esmf/FieldPointerUtilities.F90 +++ b/infrastructure/esmf/FieldPointerUtilities.F90 @@ -428,7 +428,9 @@ subroutine clone(x, y, name, rc) character(len=*), parameter :: CLONE_TAG = '_clone' !type(ESMF_ArraySpec) :: arrayspec + type(ESMF_Geom) :: geom type(ESMF_Grid) :: grid + type(ESMF_GeomType_Flag) :: geomtype type(ESMF_StaggerLoc) :: staggerloc integer, allocatable :: gridToFieldMap(:) integer, allocatable :: ungriddedLBound(:) @@ -436,22 +438,31 @@ subroutine clone(x, y, name, rc) type(ESMF_TypeKind_Flag) :: tk character(len=ESMF_MAXSTR) :: clone_name integer :: status - integer :: field_rank, grid_rank,ungrid_size + integer :: field_rank, geom_rank, ungrid_size + logical :: is_grid type(ESMF_Index_Flag) :: index_flag real(kind=ESMF_KIND_R4), pointer :: VR4_1D(:), VR4_2D(:,:), VR4_3D(:,:,:), VR4_4D(:,:,:,:) real(kind=ESMF_KIND_R8), pointer :: VR8_1D(:), VR8_2D(:,:), VR8_3D(:,:,:), VR8_4D(:,:,:,:) integer, allocatable :: lc(:) type(ESMF_Info) :: x_info, y_info - call ESMF_FieldGet(x,grid=grid,rank=field_rank,_RC) + call ESMF_FieldGet(x, geom=geom, rank=field_rank, _RC) lc = get_local_element_count(x,_RC) - call ESMF_GridGet(grid,dimCount=grid_rank,indexFlag=index_flag,_RC) - ungrid_size = field_rank-grid_rank - allocate(gridToFieldMap(grid_rank)) + call ESMF_GeomGet(geom, geomtype=geomtype, dimCount=geom_rank, indexFlag=index_flag, _RC) + is_grid = (geomtype == ESMF_GEOMTYPE_GRID) + if (is_grid) call ESMF_GeomGet(geom, grid=grid, _RC) + ungrid_size = field_rank-geom_rank + allocate(gridToFieldMap(geom_rank)) allocate(ungriddedLBound(ungrid_size),ungriddedUBound(ungrid_size)) - call ESMF_FieldGet(x, typekind=tk, name=clone_name, & - staggerloc=staggerloc, gridToFieldMap=gridToFieldMap, & - ungriddedLBound=ungriddedLBound, ungriddedUBound=ungriddedUBound, _RC) + if (is_grid) then + call ESMF_FieldGet(x, typekind=tk, name=clone_name, & + staggerloc=staggerloc, gridToFieldMap=gridToFieldMap, & + ungriddedLBound=ungriddedLBound, ungriddedUBound=ungriddedUBound, _RC) + else + call ESMF_FieldGet(x, typekind=tk, name=clone_name, & + gridToFieldMap=gridToFieldMap, & + ungriddedLBound=ungriddedLBound, ungriddedUBound=ungriddedUBound, _RC) + end if if (present(name)) then clone_name = name @@ -460,37 +471,73 @@ subroutine clone(x, y, name, rc) end if if (index_flag == ESMF_INDEX_USER) then - if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 1) then - allocate(VR4_1d(lc(1)),_STAT) - y = ESMF_FieldCreate(grid,VR4_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 1) then - allocate(VR8_1d(lc(1)),_STAT) - y = ESMF_FieldCreate(grid,VR8_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 2) then - allocate(VR4_2d(lc(1),lc(2)),_STAT) - y = ESMF_FieldCreate(grid,VR4_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 2) then - allocate(VR8_2d(lc(1),lc(2)),_STAT) - y = ESMF_FieldCreate(grid,VR8_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 3) then - allocate(VR4_3d(lc(1),lc(2),lc(3)),_STAT) - y = ESMF_FieldCreate(grid,VR4_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 3) then - allocate(VR8_3d(lc(1),lc(2),lc(3)),_STAT) - y = ESMF_FieldCreate(grid,VR8_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 4) then - allocate(VR4_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) - y = ESMF_FieldCreate(grid,VR4_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) - else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 4) then - allocate(VR8_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) - y = ESMF_FieldCreate(grid,VR8_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + if (is_grid) then + if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 1) then + allocate(VR4_1d(lc(1)),_STAT) + y = ESMF_FieldCreate(grid,VR4_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 1) then + allocate(VR8_1d(lc(1)),_STAT) + y = ESMF_FieldCreate(grid,VR8_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 2) then + allocate(VR4_2d(lc(1),lc(2)),_STAT) + y = ESMF_FieldCreate(grid,VR4_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 2) then + allocate(VR8_2d(lc(1),lc(2)),_STAT) + y = ESMF_FieldCreate(grid,VR8_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 3) then + allocate(VR4_3d(lc(1),lc(2),lc(3)),_STAT) + y = ESMF_FieldCreate(grid,VR4_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 3) then + allocate(VR8_3d(lc(1),lc(2),lc(3)),_STAT) + y = ESMF_FieldCreate(grid,VR8_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 4) then + allocate(VR4_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) + y = ESMF_FieldCreate(grid,VR4_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 4) then + allocate(VR8_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) + y = ESMF_FieldCreate(grid,VR8_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else + _FAIL( 'unsupported typekind+field_rank') + end if else - _FAIL( 'unsupported typekind+field_rank') + if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 1) then + allocate(VR4_1d(lc(1)),_STAT) + y = ESMF_FieldCreate(geom,VR4_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 1) then + allocate(VR8_1d(lc(1)),_STAT) + y = ESMF_FieldCreate(geom,VR8_1d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 2) then + allocate(VR4_2d(lc(1),lc(2)),_STAT) + y = ESMF_FieldCreate(geom,VR4_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 2) then + allocate(VR8_2d(lc(1),lc(2)),_STAT) + y = ESMF_FieldCreate(geom,VR8_2d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 3) then + allocate(VR4_3d(lc(1),lc(2),lc(3)),_STAT) + y = ESMF_FieldCreate(geom,VR4_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 3) then + allocate(VR8_3d(lc(1),lc(2),lc(3)),_STAT) + y = ESMF_FieldCreate(geom,VR8_3d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 4) then + allocate(VR4_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) + y = ESMF_FieldCreate(geom,VR4_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 4) then + allocate(VR8_4d(lc(1),lc(2),lc(3),lc(4)),_STAT) + y = ESMF_FieldCreate(geom,VR8_4d,gridToFieldMap=gridToFieldMap,name=clone_name,_RC) + else + _FAIL( 'unsupported typekind+field_rank') + end if end if else - y = ESMF_FieldCreate(grid, tk, staggerloc=staggerloc, & - gridToFieldMap=gridToFieldMap, ungriddedLBound=ungriddedLBound, & - ungriddedUBound=ungriddedUBound, name=clone_name, _RC) + if (is_grid) then + y = ESMF_FieldCreate(grid, tk, staggerloc=staggerloc, & + gridToFieldMap=gridToFieldMap, ungriddedLBound=ungriddedLBound, & + ungriddedUBound=ungriddedUBound, name=clone_name, _RC) + else + y = ESMF_FieldCreate(geom, tk, & + gridToFieldMap=gridToFieldMap, ungriddedLBound=ungriddedLBound, & + ungriddedUBound=ungriddedUBound, name=clone_name, _RC) + end if end if ! clone metadata diff --git a/infrastructure/field_bundle/FieldBundleGet.F90 b/infrastructure/field_bundle/FieldBundleGet.F90 index e75cea3ea46..dd63da359d7 100644 --- a/infrastructure/field_bundle/FieldBundleGet.F90 +++ b/infrastructure/field_bundle/FieldBundleGet.F90 @@ -141,6 +141,7 @@ subroutine get_geom(fieldBundle, geom, rc) integer :: status type(ESMF_GeomType_Flag) :: geomtype type(ESMF_Grid) :: grid + type(ESMF_LocStream) :: locstream call ESMF_FieldBundleGet(fieldBundle, geomtype=geomtype, _RC) if (geomtype == ESMF_GEOMTYPE_GRID) then @@ -148,6 +149,11 @@ subroutine get_geom(fieldBundle, geom, rc) ! probable memory leak geom = ESMF_GeomCreate(grid=grid, _RC) _RETURN(_SUCCESS) + else if (geomtype == ESMF_GEOMTYPE_LOCSTREAM) then + call ESMF_FieldBundleGet(fieldBundle, locstream=locstream, _RC) + ! probable memory leak + geom = ESMF_GeomCreate(locstream=locstream, _RC) + _RETURN(_SUCCESS) end if _FAIL('unsupported geomtype; needs simple extension') diff --git a/infrastructure/field_bundle/FieldBundleSet.F90 b/infrastructure/field_bundle/FieldBundleSet.F90 index 4573c3c214a..853066431f0 100644 --- a/infrastructure/field_bundle/FieldBundleSet.F90 +++ b/infrastructure/field_bundle/FieldBundleSet.F90 @@ -80,6 +80,7 @@ subroutine bundle_set(fieldBundle, unusable, & type(ESMF_GeomType_Flag) :: geomtype type(ESMF_Info) :: bundle_info type(ESMF_Grid) :: grid + type(ESMF_LocStream) :: locstream integer :: i type(ESMF_Field), allocatable :: fieldList(:) logical, allocatable :: has_geom @@ -96,6 +97,15 @@ subroutine bundle_set(fieldBundle, unusable, & call FieldBundleReset(fieldBundle) call ESMF_FieldBundleSet(fieldBundle, grid=grid, _RC) + call FieldBundleGet(fieldBundle, fieldList=fieldList, _RC) + do i = 1, size(fieldList) + call MAPL_FieldSet(fieldList(i), geom=geom, _RC) + end do + else if (geomtype == ESMF_GEOMTYPE_LOCSTREAM) then + call ESMF_GeomGet(geom, locstream=locstream, _RC) + call FieldBundleReset(fieldBundle) + call ESMF_FieldBundleSet(fieldBundle, locstream=locstream, _RC) + call FieldBundleGet(fieldBundle, fieldList=fieldList, _RC) do i = 1, size(fieldList) call MAPL_FieldSet(fieldList(i), geom=geom, _RC) diff --git a/infrastructure/geom/GeomManager/initialize.F90 b/infrastructure/geom/GeomManager/initialize.F90 index 557678e8a62..c8ccdcc1e18 100644 --- a/infrastructure/geom/GeomManager/initialize.F90 +++ b/infrastructure/geom/GeomManager/initialize.F90 @@ -9,6 +9,7 @@ module subroutine initialize(this) use mapl_LatLonGeomFactory_mod use mapl_CubedSphereGeomFactory_mod + use mapl_LocStreamGeomFactory_mod use mapl_XYGeomFactory_mod use mapl_EASEGeomFactory_mod class(GeomManager), intent(inout) :: this @@ -16,10 +17,12 @@ module subroutine initialize(this) ! Load default factories type(LatLonGeomFactory) :: latlon_factory type(CubedSphereGeomFactory) :: cs_factory + type(LocStreamGeomFactory) :: locstream_factory type(XYGeomFactory) :: xy_factory type(EASEGeomFactory) :: ease_factory call this%add_factory(cs_factory) + call this%add_factory(locstream_factory) call this%add_factory(latlon_factory) call this%add_factory(xy_factory) call this%add_factory(ease_factory) diff --git a/infrastructure/geom/LocStream/LocStreamGeomFactory.F90 b/infrastructure/geom/LocStream/LocStreamGeomFactory.F90 index a6cb7b88dbc..5742fb23c63 100644 --- a/infrastructure/geom/LocStream/LocStreamGeomFactory.F90 +++ b/infrastructure/geom/LocStream/LocStreamGeomFactory.F90 @@ -15,7 +15,8 @@ module mapl_LocStreamGeomFactory_mod use pFIO_AttributeMod, only: Attribute use pFIO_StringVariableMapMod use pFIO_NetCDF4_FileFormatterMod, only: NetCDF4_FileFormatter - use pFIO_ConstantsMod, only: pFIO_READ + use pFIO_ConstantsMod, only: pFIO_READ, PFIO_REAL64 + use pFIO_UnlimitedEntityMod, only: UnlimitedEntity use gftl2_StringVector, only: StringVector use mapl_StringDictionary_mod, only: StringDictionary use mapl_KeywordEnforcer_mod, only: KeywordEnforcer @@ -375,12 +376,41 @@ function make_file_metadata(this, geom_spec, unusable, chunksizes, rc) result(fi type(FileMetadata) :: file_metadata integer, optional, intent(out) :: rc - ! LocStream-specific file metadata generation can be added later. - file_metadata = FileMetadata() + integer :: status + integer :: npoints + real(kind=ESMF_KIND_R8), pointer :: lons(:) => null(), lats(:) => null() + type(Variable) :: v + _UNUSED_DUMMY(this) - _UNUSED_DUMMY(geom_spec) _UNUSED_DUMMY(unusable) - _UNUSED_DUMMY(chunksizes) + + file_metadata = FileMetadata() + + select type (geom_spec) + type is (LocStreamGeomSpec) + npoints = geom_spec%get_npoints() + call geom_spec%get_coordinates(lons, lats) + + call file_metadata%add_dimension('loc', npoints) + + v = Variable(type=PFIO_REAL64, dimensions='loc', chunksizes=chunksizes) + call v%add_attribute('long_name', 'longitude') + call v%add_attribute('units', 'degrees_east') + if (associated(lons)) then + call v%add_const_value(UnlimitedEntity(lons)) + end if + call file_metadata%add_variable('lon', v) + + v = Variable(type=PFIO_REAL64, dimensions='loc', chunksizes=chunksizes) + call v%add_attribute('long_name', 'latitude') + call v%add_attribute('units', 'degrees_north') + if (associated(lats)) then + call v%add_const_value(UnlimitedEntity(lats)) + end if + call file_metadata%add_variable('lat', v) + class default + _FAIL('geom_spec is not of dynamic type LocStreamGeomSpec.') + end select _RETURN(_SUCCESS) end function make_file_metadata diff --git a/infrastructure/regridder_mgr/RoutehandleParam.F90 b/infrastructure/regridder_mgr/RoutehandleParam.F90 index 3f7ec395069..538a62d5641 100644 --- a/infrastructure/regridder_mgr/RoutehandleParam.F90 +++ b/infrastructure/regridder_mgr/RoutehandleParam.F90 @@ -63,6 +63,7 @@ module mapl_RoutehandleParam_mod character(*), parameter :: BILINEAR = 'bilinear' character(*), parameter :: CONSERVE = 'conserve' + character(*), parameter :: NEAREST_STOD = 'nearest_stod' character(*), parameter :: KEY_REGRID_METHOD = 'regrid_method' contains @@ -300,6 +301,8 @@ function make_rh_param_from_info(info, rc) result(rh_param) regrid_method = ESMF_REGRIDMETHOD_BILINEAR case (CONSERVE) regrid_method = ESMF_REGRIDMETHOD_CONSERVE + case (NEAREST_STOD) + regrid_method = ESMF_REGRIDMETHOD_NEAREST_STOD case default _FAIL('unsupported regrid method:: ' // regrid_method_str) end select @@ -322,6 +325,8 @@ function make_info(this, rc) result(info) regrid_method_str = BILINEAR else if (this%regridMethod == ESMF_REGRIDMETHOD_CONSERVE) then regrid_method_str = CONSERVE + else if (this%regridMethod == ESMF_REGRIDMETHOD_NEAREST_STOD) then + regrid_method_str = NEAREST_STOD else _FAIL('unsupported esmf regrid method') end if diff --git a/tests/MAPL3G_Component_Testing_Framework/test_case_descriptions.md b/tests/MAPL3G_Component_Testing_Framework/test_case_descriptions.md index 15e381d5c33..ef8406c7b97 100644 --- a/tests/MAPL3G_Component_Testing_Framework/test_case_descriptions.md +++ b/tests/MAPL3G_Component_Testing_Framework/test_case_descriptions.md @@ -30,3 +30,4 @@ Note all test cases are in a numbered directory caseX, where a X is an integer a 41. Test History for ability to output daily averages 42. Test of Historys ability to output monthly and djf averages 43. Test of Historys ability to output daily averge and modify on a per-variable basis the units, averaging type, and precision +44. Test regridding from CubedSphere geom to LocStream geom using nearest-neighbor interpolation diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM1.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM1.yaml new file mode 100644 index 00000000000..02b35b0f780 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM1.yaml @@ -0,0 +1,25 @@ +FILL_DEF: + E_1: 17.0 + +RUN_MODE: GenerateExports + +REF_TIME: 2004-07-01T00:00:00 + +mapl: + + states: + export: + E_1: + standard_name: "NA" + units: "NA" + typekind: R4 + fill_value: 17. + vertical_dim_spec: NONE + + geometry: + esmf_geom: + class: CubedSphere + im_world: 12 + vertical_grid: + grid_type: basic + num_levels: 3 diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM2.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM2.yaml new file mode 100644 index 00000000000..d0ad6f1ed5c --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/GCM2.yaml @@ -0,0 +1,36 @@ +FILL_DEF: + E_1: 17.0 + +RUN_MODE: CompareImportsToReference + +REF_TIME: 2004-07-01T00:00:00 + +mapl: + + misc: + activate_all_exports: true + + states: + import: + E_1: + standard_name: "NA" + units: "NA" + typekind: R4 + fill_value: 17. + vertical_dim_spec: NONE + export: + E_1: + standard_name: "NA" + units: "NA" + typekind: R4 + fill_value: 17. + vertical_dim_spec: NONE + + geometry: + esmf_geom: + class: locstream + lon: [0.0, 15.0, 30.0, 45.0, 60.0, 75.0, 90.0, 105.0, 120.0, 135.0, 150.0, 165.0, 180.0, 195.0, 210.0, 225.0, 240.0, 255.0, 270.0, 285.0, 300.0, 315.0, 330.0, 345.0] + lat: [-75.0, -65.0, -55.0, -45.0, -35.0, -25.0, -15.0, -5.0, 5.0, 15.0, 25.0, 35.0, 45.0, 55.0, 65.0, 75.0, -70.0, -60.0, -50.0, -40.0, -30.0, -20.0, -10.0, 0.0] + vertical_grid: + grid_type: basic + num_levels: 3 diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap1.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap1.yaml new file mode 100644 index 00000000000..e841a38f39c --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap1.yaml @@ -0,0 +1,39 @@ +esmf: + logKindFlag: ESMF_LOGKIND_MULTI + logAppendFlag: false + +mapl: + model_petcount: 6 + pflogger_cfg_file: logging.yaml + +cap: + name: cap + restart: cap_restart1.yaml + + clock: + dt: PT1H + start: 2004-06-30T00:00:00 + stop: 2999-03-02T21:00:00 + segment_duration: P2D + + extdata_name: EXTDATA + history_name: HIST + root_name: GCM + run_extdata: true + run_history: true + + run_times: + - '2004-07-01T00:00:00' + + mapl: + children: + GCM: + dso: libMAPL.componentDriverGridComp + setServices: setservices_ + config_file: GCM1.yaml + EXTDATA: + dso: libMAPL.extdata + config_file: extdata1.yaml + HIST: + dso: libMAPL.history + config_file: history1.yaml diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap2.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap2.yaml new file mode 100644 index 00000000000..c19260a9706 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap2.yaml @@ -0,0 +1,36 @@ +esmf: + logKindFlag: ESMF_LOGKIND_MULTI + logAppendFlag: false + +mapl: + model_petcount: 6 + pflogger_cfg_file: logging.yaml + +cap: + name: cap + restart: cap_restart2.yaml + + clock: + dt: PT3H + start: 2004-01-20T00:00:00 + stop: 2999-03-02T21:00:00 + segment_duration: PT3H + + extdata_name: EXTDATA + history_name: HIST + root_name: GCM + run_extdata: true + run_history: true + + mapl: + children: + GCM: + dso: libMAPL.componentDriverGridComp + setServices: setservices_ + config_file: GCM2.yaml + EXTDATA: + dso: libMAPL.extdata + config_file: extdata2.yaml + HIST: + dso: libMAPL.history + config_file: history2.yaml diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart1.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart1.yaml new file mode 100644 index 00000000000..d633c3e7b27 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart1.yaml @@ -0,0 +1 @@ +currTime: 2004-06-30T00:00:00 diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart2.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart2.yaml new file mode 100644 index 00000000000..86bb0cfdac8 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/cap_restart2.yaml @@ -0,0 +1 @@ +currTime: 2004-06-30T12:00:00 diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata1.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata1.yaml new file mode 100644 index 00000000000..a052dd7aafa --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata1.yaml @@ -0,0 +1,4 @@ +Collections: + c1: + template: "test.nc4" +Exports: diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata2.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata2.yaml new file mode 100644 index 00000000000..14604998626 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/extdata2.yaml @@ -0,0 +1,13 @@ +Samplings: + sample_closest: + extrapolation: persist_closest + +Collections: + c1: + template: "test.nc4" +Exports: + E_1: + collection: c1 + variable: E_1 + sample: sample_closest + regrid: NEAREST_STOD diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history1.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history1.yaml new file mode 100644 index 00000000000..619a5988734 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history1.yaml @@ -0,0 +1,15 @@ +run_next_step: false + +active_collections: + - test + +time_specs: + one_hour: &one_hour + frequency: PT1H + +collections: + test: + template: "%c.nc4" + time_spec: *one_hour + var_list: + E_1: {source: E_1} diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history2.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history2.yaml new file mode 100644 index 00000000000..c19466cf026 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/history2.yaml @@ -0,0 +1 @@ +active_collections: diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/logging.yaml b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/logging.yaml new file mode 100755 index 00000000000..1fc0876b670 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/logging.yaml @@ -0,0 +1,123 @@ +schema_version: 1 + +# Example on how to use the logging.yaml file based on +# +# https://github.com/GEOS-ESM/MAPL/wiki/How-to-use-the-MAPL-logging-library,-aka-%22pFlogger%22 +# + +############################### +locks: + mpi: + class: MpiLock + comm: MPI_COMM_WORLD + +############################### +formatters: + plain: + class: Formatter + format: '%(message)a' + + basic: + class: Formatter + format: '%(short_name)a15~: %(level_name)a~: %(message)a' + + mpi: + class: MpiFormatter + format: '%(mpi_rank)i4.4~: %(name)~: %(level_name)a~: %(message)a' + comm: MPI_COMM_WORLD + + column: + class: Formatter + format: '(%(i)i3.3,%(j)i3.3): %(level_name)' + + # This makes an output like: + # AGCM Date: 2000/04/14 Time: 21:00:00 GENERIC: DEBUG: Message + simtime: + class: Formatter + format: '%(simtime)a~ %(short_name)a15~: %(level_name)a~: %(message)a' + datefmt: ' AGCM Date: %(Y)i4.4~/%(M)i2.2~/%(D)i2.2 Time: %(HH)i2.2~:%(MM)i2.2~:%(SS)i2.2' + +############################### +handlers: + + console: + class: streamhandler + formatter: basic + unit: OUTPUT_UNIT + level: DEBUG + + console_plain: + class: streamhandler + formatter: plain + unit: OUTPUT_UNIT + level: DEBUG + + console_simtime: + class: streamhandler + formatter: simtime + unit: OUTPUT_UNIT + level: DEBUG + + warnings: + class: FileHandler + filename: warnings_and_errors.log + lock: mpi + level: WARNING + formatter: basic + + errors: + class: StreamHandler + formatter: basic + unit: ERROR_UNIT + level: ERROR + + mpi_shared: + class: FileHandler + filename: allPEs.log + formatter: mpi + comm: MPI_COMM_WORLD + lock: mpi + rank_keyword: rank + level: DEBUG + + mpi_debug: + class: MpiFileHandler + formatter: basic + filename: debug_%(rank)i3.3~.log + comm: MPI_COMM_WORLD + rank_prefix: rank + level: DEBUG + +############################### +root: + handlers: [warnings,errors,console] + level: WARNING + root_level: WARNING + +############################### +loggers: + + errors: + handlers: [errors] + level: ERROR + + HIST: + level: INFO + root_level: INFO + EXTDATA: + level: INFO + root_level: INFO + cap: + level: INFO + root_level: INFO + + MAPL: + handlers: [mpi_shared] + level: WARNING + root_level: INFO + + MAPL.profiler: + handlers: [console_plain] + propagate: FALSE + level: WARNING + root_level: INFO diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/nproc.rc b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/nproc.rc new file mode 100644 index 00000000000..1e8b3149621 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/nproc.rc @@ -0,0 +1 @@ +6 diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/steps.rc b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/steps.rc new file mode 100644 index 00000000000..5c136635533 --- /dev/null +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/case44/steps.rc @@ -0,0 +1,2 @@ +cap1.yaml +cap2.yaml diff --git a/tests/MAPL3G_Component_Testing_Framework/test_cases/cases.txt b/tests/MAPL3G_Component_Testing_Framework/test_cases/cases.txt index 272203b68e0..7f23ebf18f0 100644 --- a/tests/MAPL3G_Component_Testing_Framework/test_cases/cases.txt +++ b/tests/MAPL3G_Component_Testing_Framework/test_cases/cases.txt @@ -25,3 +25,4 @@ case39 case41 case42 case43 +case44