Skip to content

Commit 8d3ff3a

Browse files
authored
Merge pull request #620 from billsacks/refactor_med_methods_fb_init
Refactor med_methods_FB_init to allow handling of water tracer fields ### Description of changes Rather than having med_methods_FB_init accept one of fieldNameList or STflds, now it accepts an array of med_field_info_type objects. med_field_info_type is defined in a new module that also includes some creation methods, making calls to med_methods_FB_init a two-step process: first create field_info_array, then call med_methods_FB_init with this field_info_array. A key new feature is that the creation of a field_info_array from field_names will assume a single ungridded dimension with size given by shr_wtracers_get_num_tracers for any field with the water tracer suffix. This was the main motivation for the refactor here. Some specific notes about the changes in this commit: - Behavior change: if there are only scalar or blank fields, we do some unnecessary work now (retrieving the mesh that we won't end up ever using) - I think I got the gridToFieldMap right: before it was hard-coded to 2, but I think that was only right for a single ungridded dimension; here I'm generalizing that for multiple ungridded dimensions **This depends on the CESM_share changes in ESCOMP/CESM_share#78 and ESCOMP/CESM_share#80 ### Specific notes Contributors other than yourself, if any: CMEPS Issues Fixed (include github issue #): Are changes expected to change answers? (specify if bfb, different at roundoff, more substantial) No - bfb Any User Interface Changes (namelist or namelist defaults changes)? No ### Testing performed Please describe the tests along with the target model and machine(s) If possible, please also added hashes that were used in the testing Ran a subset of the CESM prealpha tests with baseline comparisons, using cesm3_0_alpha08a with this CMEPS branch and the share branch from ESCOMP/CESM_share#78: ``` ERS_D_Ld3.ne30pg3_t232.B1850C_LTso.derecho_intel.allactive-defaultio ERI.ne30pg3_t232.B1850C_LTso.derecho_intel.allactive-defaultio ERC_D_Ln9.ne30pg3_ne30pg3_mt232.FHISTC_LTso.derecho_intel.cam-outfrq9s ERS_Ly7.f09_g17_gris4.T1850Gg.derecho_intel SMS_Lm13.f10_f10_mg37.I1850Clm50SpG.derecho_intel MULTINOAIS_Ly2.f10_f10_ais8gris4_mg37.I1850Clm50SpRsGag.derecho_intel.cism-change_params SMS_D_Ld1.ne30pg3_t232.I1850Clm50BgcSpinup.derecho_intel.clm-cplhist ERI.TL319_t232.G_JRA.derecho_intel.cice-default SMS_D.TL319_t232.G_JRA_RYF.derecho_intel SMS_Ld40.TL319_t232.C_JRA.derecho_intel ``` All tests pass and are bit-for-bit with the baselines. There were NLCOMP failures in some tests; from spot-checking, the NLCOMP failures all seem to be in MOM files. Nothing in this PR or the accompanying share PR could change the namelists, so I assume these are a pre-existing issue: ``` FAIL ERI.ne30pg3_t232.B1850C_LTso.derecho_intel.allactive-defaultio NLCOMP FAIL ERI.TL319_t232.G_JRA.derecho_intel.cice-default NLCOMP FAIL ERS_D_Ld3.ne30pg3_t232.B1850C_LTso.derecho_intel.allactive-defaultio NLCOMP FAIL SMS_D.TL319_t232.G_JRA_RYF.derecho_intel NLCOMP FAIL SMS_Ld40.TL319_t232.C_JRA.derecho_intel NLCOMP ```
2 parents f477c33 + 43e4594 commit 8d3ff3a

15 files changed

Lines changed: 428 additions & 153 deletions
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module wtracers_mod
2+
3+
!-----------------------------------------------------------------------------
4+
! This module wraps shr_wtracers_mod from the CESM_share repository to avoid direct
5+
! dependencies on this share code from CMEPS.
6+
!
7+
! See also the version of wtracers_mod in the ufs directory for when we do not have
8+
! access to the CESM_share library.
9+
!-----------------------------------------------------------------------------
10+
11+
use shr_wtracers_mod, only : wtracers_is_wtracer_field => shr_wtracers_is_wtracer_field
12+
13+
implicit none
14+
private
15+
16+
public :: wtracers_is_wtracer_field ! return true if the given field name is a water tracer field
17+
18+
end module wtracers_mod

cime_config/buildexe

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def _main_func():
9494
if not skip_mediator:
9595
out.write(os.path.join(cmeps_dir, "mediator") + "\n")
9696
out.write(os.path.join(cmeps_dir, "cesm", "flux_atmocn") + "\n")
97+
out.write(os.path.join(cmeps_dir, "cesm", "share_wrappers") + "\n")
9798
out.write(os.path.join(cmeps_dir, "cesm", "driver") + "\n")
9899

99100
# build model executable

mediator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
project(cmeps Fortran)
22

33
set(SRCFILES esmFldsExchange_cesm_mod.F90 med_fraction_mod.F90
4+
med_field_info_mod.F90
45
med_methods_mod.F90 med_phases_prep_ice_mod.F90
56
med_phases_restart_mod.F90 esmFldsExchange_hafs_mod.F90
67
med_internalstate_mod.F90 med_phases_aofluxes_mod.F90

mediator/med.F90

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ module MED
3737
use med_methods_mod , only : FB_diagnose => med_methods_FB_diagnose
3838
use med_methods_mod , only : FB_getFieldN => med_methods_FB_getFieldN
3939
use med_methods_mod , only : clock_timeprint => med_methods_clock_timeprint
40+
use med_field_info_mod , only : med_field_info_type
41+
use med_field_info_mod , only : med_field_info_array_from_names_wtracers, med_field_info_array_from_state
4042
use med_utils_mod , only : memcheck => med_memcheck
4143
use med_internalstate_mod , only : InternalState, med_internalstate_init, med_internalstate_coupling
4244
use med_internalstate_mod , only : med_internalstate_defaultmasks, logunit, maintask
@@ -1636,6 +1638,7 @@ subroutine DataInitialize(gcomp, rc)
16361638

16371639
! local variables
16381640
type(InternalState) :: is_local
1641+
type(med_field_info_type), allocatable :: field_info_array(:)
16391642
type(ESMF_Clock) :: clock
16401643
type(ESMF_State) :: importState, exportState
16411644
type(ESMF_Time) :: time
@@ -1749,19 +1752,25 @@ subroutine DataInitialize(gcomp, rc)
17491752
trim(compname(n1))//'_'//trim(compname(n2))
17501753
end if
17511754

1755+
call med_field_info_array_from_state( &
1756+
state = is_local%wrap%NStateImp(n1), &
1757+
field_info_array = field_info_array, &
1758+
rc = rc)
1759+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
1760+
17521761
! Check import FB, if there is no field in it then use export FB
17531762
! to provide mesh information
17541763
call State_GetNumFields(is_local%wrap%NStateImp(n2), fieldCount, rc=rc)
17551764
if (ChkErr(rc,__LINE__,u_FILE_u)) return
17561765
if (fieldCount == 0) then
17571766
call FB_init(is_local%wrap%FBImp(n1,n2), is_local%wrap%flds_scalar_name, &
1767+
field_info_array=field_info_array, &
17581768
STgeom=is_local%wrap%NStateExp(n2), &
1759-
STflds=is_local%wrap%NStateImp(n1), &
17601769
name='FBImp'//trim(compname(n1))//'_'//trim(compname(n2)), rc=rc)
17611770
else
17621771
call FB_init(is_local%wrap%FBImp(n1,n2), is_local%wrap%flds_scalar_name, &
1772+
field_info_array=field_info_array, &
17631773
STgeom=is_local%wrap%NStateImp(n2), &
1764-
STflds=is_local%wrap%NStateImp(n1), &
17651774
name='FBImp'//trim(compname(n1))//'_'//trim(compname(n2)), rc=rc)
17661775
end if
17671776
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -1789,14 +1798,19 @@ subroutine DataInitialize(gcomp, rc)
17891798
allocate(fldnames(fieldCount))
17901799
call med_fldList_getfldnames(fldListMed_ocnalb%fields, fldnames, rc=rc)
17911800
if (ChkErr(rc,__LINE__,u_FILE_u)) return
1801+
call med_field_info_array_from_names_wtracers( &
1802+
field_names = fldnames, &
1803+
field_info_array = field_info_array, &
1804+
rc = rc)
1805+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
17921806
call FB_init(is_local%wrap%FBMed_ocnalb_a, is_local%wrap%flds_scalar_name, &
1793-
STgeom=is_local%wrap%NStateImp(compatm), fieldnamelist=fldnames, name='FBMed_ocnalb_a', rc=rc)
1807+
field_info_array=field_info_array, STgeom=is_local%wrap%NStateImp(compatm), name='FBMed_ocnalb_a', rc=rc)
17941808
if (ChkErr(rc,__LINE__,u_FILE_u)) return
17951809
if (maintask) then
17961810
write(logunit,'(a)') trim(subname)//' initializing FB FBMed_ocnalb_a'
17971811
end if
17981812
call FB_init(is_local%wrap%FBMed_ocnalb_o, is_local%wrap%flds_scalar_name, &
1799-
STgeom=is_local%wrap%NStateImp(compocn), fieldnamelist=fldnames, name='FBMed_ocnalb_o', rc=rc)
1813+
field_info_array = field_info_array, STgeom=is_local%wrap%NStateImp(compocn), name='FBMed_ocnalb_o', rc=rc)
18001814
if (ChkErr(rc,__LINE__,u_FILE_u)) return
18011815
if (maintask) then
18021816
write(logunit,'(a)') trim(subname)//' initializing FB FBMed_ocnalb_o'

mediator/med_field_info_mod.F90

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
module med_field_info_mod
2+
3+
!-----------------------------------------------------------------------------
4+
! Defines a type and related operations for storing metadata about fields that can be
5+
! used to create an ESMF FieldBundle.
6+
!-----------------------------------------------------------------------------
7+
8+
use ESMF , only : ESMF_MAXSTR, ESMF_SUCCESS
9+
use ESMF , only : ESMF_Field, ESMF_State, ESMF_AttributeGet, ESMF_StateGet
10+
use med_utils_mod , only : ChkErr => med_utils_ChkErr
11+
use shr_log_mod , only : shr_log_error
12+
use wtracers_mod , only : wtracers_is_wtracer_field
13+
14+
implicit none
15+
private
16+
17+
!-----------------------------------------------
18+
! Public methods
19+
!-----------------------------------------------
20+
21+
! Create a single field
22+
public :: med_field_info_create
23+
24+
! Create an array of field_info objects based on an array of names, where water tracers
25+
! are treated specially (being given an ungridded dimension)
26+
public :: med_field_info_array_from_names_wtracers
27+
28+
! Create an array of field_info objects based on the fields in an ESMF State
29+
public :: med_field_info_array_from_state
30+
31+
!-----------------------------------------------
32+
! Types
33+
!-----------------------------------------------
34+
35+
type, public :: med_field_info_type
36+
character(ESMF_MAXSTR) :: name
37+
integer :: n_ungridded ! number of ungridded dimensions
38+
39+
! These arrays will be allocated to be of size ungridded_count
40+
integer, allocatable :: ungridded_lbound(:)
41+
integer, allocatable :: ungridded_ubound(:)
42+
end type med_field_info_type
43+
44+
character(len=*),parameter :: u_FILE_u = &
45+
__FILE__
46+
47+
!================================================================================
48+
contains
49+
!================================================================================
50+
51+
function med_field_info_create(name, ungridded_lbound, ungridded_ubound, rc) result(field_info)
52+
! Create a single field
53+
54+
! input/output variables
55+
character(len=*), intent(in) :: name
56+
57+
! ungridded_lbound and ungridded_ubound must either both be present or both be absent;
58+
! if present, they must be the same size
59+
integer, intent(in), optional :: ungridded_lbound(:)
60+
integer, intent(in), optional :: ungridded_ubound(:)
61+
62+
integer, intent(out) :: rc
63+
type(med_field_info_type) :: field_info ! function result
64+
65+
! local variables
66+
integer :: n_ungridded
67+
character(len=*), parameter :: subname = '(med_field_info_create)'
68+
! ----------------------------------------------
69+
70+
rc = ESMF_SUCCESS
71+
72+
if (present(ungridded_lbound) .neqv. present(ungridded_ubound)) then
73+
call shr_log_error( &
74+
subname//": ERROR: ungridded_lbound and ungridded_ubound must both be present or both absent.", &
75+
line=__LINE__, file=u_FILE_u, rc=rc)
76+
return
77+
end if
78+
79+
field_info%name = name
80+
81+
if (present(ungridded_lbound)) then
82+
n_ungridded = size(ungridded_lbound)
83+
if (size(ungridded_ubound) /= n_ungridded) then
84+
call shr_log_error( &
85+
subname//": ERROR: ungridded_lbound and ungridded_ubound must have the same size.", &
86+
line=__LINE__, file=u_FILE_u, rc=rc)
87+
return
88+
end if
89+
field_info%n_ungridded = n_ungridded
90+
allocate(field_info%ungridded_lbound(n_ungridded))
91+
allocate(field_info%ungridded_ubound(n_ungridded))
92+
field_info%ungridded_lbound = ungridded_lbound
93+
field_info%ungridded_ubound = ungridded_ubound
94+
else
95+
field_info%n_ungridded = 0
96+
end if
97+
98+
end function med_field_info_create
99+
100+
!-----------------------------------------------------------------------------
101+
102+
subroutine med_field_info_array_from_names_wtracers(field_names, field_info_array, rc)
103+
! Create an array of field_info objects based on an array of names, where water
104+
! tracers are treated specially (being given an ungridded dimension).
105+
!
106+
! It is assumed that fields generally have no ungridded dimensions. However, for
107+
! fields ending with the water tracer suffix, it is instead assumed that they have a
108+
! single ungridded dimension of size given by shr_wtracers_get_num_tracers.
109+
!
110+
! field_info_array is allocated here (and, since it has intent(out), it is
111+
! automatically deallocated if it is already allocated on entry to this subroutine)
112+
113+
! input/output variables
114+
character(len=*), intent(in) :: field_names(:)
115+
type(med_field_info_type), allocatable, intent(out) :: field_info_array(:)
116+
integer, intent(out) :: rc
117+
118+
! local variables
119+
integer :: i, n_fields
120+
logical :: is_tracer
121+
integer :: n_tracers
122+
character(len=*), parameter :: subname = '(med_field_info_array_from_names_wtracers)'
123+
! ----------------------------------------------
124+
125+
rc = ESMF_SUCCESS
126+
127+
n_fields = size(field_names)
128+
allocate(field_info_array(n_fields))
129+
! For now, hard-code n_tracers, since we haven't set up the tracer information; we'll
130+
! fix this in an upcoming set of changes
131+
n_tracers = 0
132+
133+
do i = 1, n_fields
134+
is_tracer = wtracers_is_wtracer_field(field_names(i))
135+
if (is_tracer) then
136+
! Field is a water tracer; assume a single ungridded dimension
137+
field_info_array(i) = med_field_info_create( &
138+
name=field_names(i), &
139+
ungridded_lbound=[1], &
140+
ungridded_ubound=[n_tracers], &
141+
rc=rc)
142+
if (chkerr(rc,__LINE__,u_FILE_u)) return
143+
else
144+
! Not a water tracer; assume no ungridded dimensions
145+
field_info_array(i) = med_field_info_create( &
146+
name=field_names(i), &
147+
rc=rc)
148+
if (chkerr(rc,__LINE__,u_FILE_u)) return
149+
end if
150+
end do
151+
152+
end subroutine med_field_info_array_from_names_wtracers
153+
154+
!-----------------------------------------------------------------------------
155+
156+
subroutine med_field_info_array_from_state(state, field_info_array, rc)
157+
! Create an array of field_info objects based on the Fields in an ESMF State
158+
!
159+
! field_info_array is allocated here (and, since it has intent(out), it is
160+
! automatically deallocated if it is already allocated on entry to this subroutine)
161+
162+
! input/output variables
163+
type(ESMF_State), intent(in) :: state
164+
type(med_field_info_type), allocatable, intent(out) :: field_info_array(:)
165+
integer, intent(out) :: rc
166+
167+
! local variables
168+
integer :: i, n_fields
169+
character(ESMF_MAXSTR), allocatable :: field_names(:)
170+
type(ESMF_Field) :: field
171+
logical :: is_present
172+
integer :: n_ungridded
173+
integer, allocatable :: ungridded_lbound(:)
174+
integer, allocatable :: ungridded_ubound(:)
175+
character(len=*), parameter :: subname = '(med_field_info_array_from_state)'
176+
! ----------------------------------------------
177+
178+
rc = ESMF_SUCCESS
179+
180+
call ESMF_StateGet(state, itemCount=n_fields, rc=rc)
181+
if (chkerr(rc,__LINE__,u_FILE_u)) return
182+
allocate(field_names(n_fields))
183+
allocate(field_info_array(n_fields))
184+
call ESMF_StateGet(state, itemNameList=field_names, rc=rc)
185+
if (chkerr(rc,__LINE__,u_FILE_u)) return
186+
187+
do i = 1, n_fields
188+
call ESMF_StateGet(state, itemName=trim(field_names(i)), field=field, rc=rc)
189+
if (chkerr(rc,__LINE__,u_FILE_u)) return
190+
191+
call ESMF_AttributeGet(field, name="UngriddedUBound", convention="NUOPC", &
192+
purpose="Instance", itemCount=n_ungridded, isPresent=is_present, rc=rc)
193+
if (chkerr(rc,__LINE__,u_FILE_u)) return
194+
if (.not. is_present) then
195+
n_ungridded = 0
196+
end if
197+
198+
if (n_ungridded == 0) then
199+
field_info_array(i) = med_field_info_create( &
200+
name=field_names(i), &
201+
rc=rc)
202+
if (chkerr(rc,__LINE__,u_FILE_u)) return
203+
else
204+
allocate(ungridded_lbound(n_ungridded))
205+
allocate(ungridded_ubound(n_ungridded))
206+
call ESMF_AttributeGet(field, name="UngriddedLBound", convention="NUOPC", &
207+
purpose="Instance", valueList=ungridded_lbound, rc=rc)
208+
if (chkerr(rc,__LINE__,u_FILE_u)) return
209+
call ESMF_AttributeGet(field, name="UngriddedUBound", convention="NUOPC", &
210+
purpose="Instance", valueList=ungridded_ubound, rc=rc)
211+
if (chkerr(rc,__LINE__,u_FILE_u)) return
212+
field_info_array(i) = med_field_info_create( &
213+
name=field_names(i), &
214+
ungridded_lbound=ungridded_lbound, &
215+
ungridded_ubound=ungridded_ubound, &
216+
rc=rc)
217+
if (chkerr(rc,__LINE__,u_FILE_u)) return
218+
deallocate(ungridded_lbound)
219+
deallocate(ungridded_ubound)
220+
end if
221+
end do
222+
223+
end subroutine med_field_info_array_from_state
224+
225+
end module med_field_info_mod

mediator/med_fraction_mod.F90

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ module med_fraction_mod
135135
use med_methods_mod , only : fldbun_reset => med_methods_FB_reset
136136
use med_map_mod , only : med_map_field
137137
use med_internalstate_mod , only : ncomps, samegrid_atmlnd
138+
use med_field_info_mod , only : med_field_info_type
139+
use med_field_info_mod , only : med_field_info_array_from_names_wtracers, med_field_info_array_from_state
138140

139141
implicit none
140142
private
@@ -189,6 +191,7 @@ subroutine med_fraction_init(gcomp, rc)
189191
type(InternalState) :: is_local
190192
type(ESMF_Field) :: field_src
191193
type(ESMF_Field) :: field_dst
194+
type(med_field_info_type), allocatable :: field_info_array(:)
192195
real(R8), pointer :: frac(:)
193196
real(R8), pointer :: ofrac(:)
194197
real(R8), pointer :: aofrac(:)
@@ -255,13 +258,18 @@ subroutine med_fraction_init(gcomp, rc)
255258
if (ChkErr(rc,__LINE__,u_FILE_u)) return
256259

257260
! create FBFrac
261+
call med_field_info_array_from_names_wtracers( &
262+
field_names = fraclist(:,n1), &
263+
field_info_array = field_info_array, &
264+
rc = rc)
265+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
258266
if (fieldCount == 0) then
259267
call fldbun_init(is_local%wrap%FBfrac(n1), is_local%wrap%flds_scalar_name, &
260-
STgeom=is_local%wrap%NStateExp(n1), fieldNameList=fraclist(:,n1), &
268+
field_info_array=field_info_array, STgeom=is_local%wrap%NStateExp(n1), &
261269
name='FBfrac'//trim(compname(n1)), rc=rc)
262270
else
263271
call fldbun_init(is_local%wrap%FBfrac(n1), is_local%wrap%flds_scalar_name, &
264-
STgeom=is_local%wrap%NStateImp(n1), fieldNameList=fraclist(:,n1), &
272+
field_info_array=field_info_array, STgeom=is_local%wrap%NStateImp(n1), &
265273
name='FBfrac'//trim(compname(n1)), rc=rc)
266274
end if
267275
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -673,9 +681,14 @@ subroutine med_fraction_init(gcomp, rc)
673681
if (is_local%wrap%comp_present(compice) .and. is_local%wrap%comp_present(compocn)) then
674682
if (.not. med_map_RH_is_created(is_local%wrap%RH(compice,compocn,:),mapfcopy, rc=rc)) then
675683
if (.not. ESMF_FieldBundleIsCreated(is_local%wrap%FBImp(compice,compocn))) then
684+
call med_field_info_array_from_state( &
685+
state = is_local%wrap%NStateImp(compice), &
686+
field_info_array = field_info_array, &
687+
rc = rc)
688+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
676689
call fldbun_init(is_local%wrap%FBImp(compice,compocn), is_local%wrap%flds_scalar_name, &
690+
field_info_array=field_info_array, &
677691
STgeom=is_local%wrap%NStateImp(compocn), &
678-
STflds=is_local%wrap%NStateImp(compice), &
679692
name='FBImp'//trim(compname(compice))//'_'//trim(compname(compocn)), rc=rc)
680693
if (ChkErr(rc,__LINE__,u_FILE_u)) return
681694
end if
@@ -687,9 +700,14 @@ subroutine med_fraction_init(gcomp, rc)
687700
end if
688701
if (.not. med_map_RH_is_created(is_local%wrap%RH(compocn,compice,:),mapfcopy, rc=rc)) then
689702
if (.not. ESMF_FieldBundleIsCreated(is_local%wrap%FBImp(compocn,compice))) then
703+
call med_field_info_array_from_state( &
704+
state = is_local%wrap%NStateImp(compocn), &
705+
field_info_array = field_info_array, &
706+
rc = rc)
707+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
690708
call fldbun_init(is_local%wrap%FBImp(compocn,compice), is_local%wrap%flds_scalar_name, &
709+
field_info_array = field_info_array, &
691710
STgeom=is_local%wrap%NStateImp(compice), &
692-
STflds=is_local%wrap%NStateImp(compocn), &
693711
name='FBImp'//trim(compname(compocn))//'_'//trim(compname(compice)), rc=rc)
694712
if (ChkErr(rc,__LINE__,u_FILE_u)) return
695713
end if

0 commit comments

Comments
 (0)