Skip to content

Commit 4e38ed5

Browse files
committed
Allow generic tracers in NUOPC cap (#8)
These changes provide an initial implementation to allow use of coupled generic tracers with NUOPC-coupled MOM6. This is a bit of a hack as coupling in generic tracers effectively assumes the use of FMScoupler. Broadly, the changes to the NUOPC cap in this commit do the following: - Initialisation phase: Initialise the FMS coupler type data structures used by generic tracers for handling surface fluxes. Register with NUOPC the additional import fields required by the generic tracer package being used. Export of additional fields is not currently handled. - Advance phase: Populate the relevant FMS coupler type data structure with fields received from the atmosphere. Calculate the surface fluxes using a modified version of the routine used by FMScoupler. Restart read/write for the FMS coupler types is also handled. Fields in the FMS coupler types can be overridden using the data_table
1 parent 94e4117 commit 4e38ed5

6 files changed

Lines changed: 912 additions & 11 deletions

File tree

config_src/drivers/nuopc_cap/mom_cap.F90

Lines changed: 149 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
module MOM_cap_mod
44

5+
use field_manager_mod, only: field_manager_init, field_manager_end
56
use MOM_domains, only: get_domain_extent
6-
use MOM_io, only: stdout, io_infra_end
7+
use MOM_io, only: stdout, io_infra_end, slasher
78
use mpp_domains_mod, only: mpp_get_compute_domains
89
use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_pelist, mpp_get_global_domain
910
use mpp_domains_mod, only: mpp_get_domain_npes
@@ -30,13 +31,23 @@ module MOM_cap_mod
3031
use MOM_cap_methods, only: ChkErr
3132
use MOM_ensemble_manager, only: ensemble_manager_init
3233
use MOM_coms, only: sum_across_PEs
34+
use MOM_coupler_types, only: coupler_1d_bc_type, coupler_2d_bc_type
3335

3436
#ifdef CESMCOUPLED
3537
use shr_log_mod, only: shr_log_setLogUnit
3638
use nuopc_shr_methods, only: get_component_instance
3739
#endif
3840
use time_utils_mod, only: esmf2fms_time
3941

42+
#ifdef _USE_GENERIC_TRACER
43+
use MOM_coupler_types, only: coupler_type_spawn, coupler_type_destructor
44+
use MOM_coupler_types, only: coupler_type_set_diags, coupler_type_send_data, coupler_type_data_override
45+
use MOM_data_override, only: data_override_init, data_override
46+
use MOM_cap_gtracer_flux, only: gas_exchange_init, gas_fields_restore, gas_fields_restart
47+
use MOM_cap_gtracer_flux, only: get_coupled_field_name, add_gas_fluxes_param, UNKNOWN_CMEPS_FIELD
48+
use MOM_cap_gtracer_flux, only: atmos_ocean_fluxes_calc
49+
#endif
50+
4051
use, intrinsic :: iso_fortran_env, only: output_unit
4152

4253
use ESMF, only: ESMF_ClockAdvance, ESMF_ClockGet, ESMF_ClockPrint, ESMF_VMget
@@ -100,11 +111,14 @@ module MOM_cap_mod
100111
public SetServices
101112
public SetVM
102113

103-
!> Internal state type with pointers to three types defined by MOM.
114+
!> Internal state type with pointers to types defined by MOM.
104115
type ocean_internalstate_type
105116
type(ocean_public_type), pointer :: ocean_public_type_ptr
106117
type(ocean_state_type), pointer :: ocean_state_type_ptr
107118
type(ice_ocean_boundary_type), pointer :: ice_ocean_boundary_type_ptr
119+
#ifdef _USE_GENERIC_TRACER
120+
type(coupler_2d_bc_type), pointer :: coupler_2d_bc_type_ptr
121+
#endif
108122
end type
109123

110124
!> Wrapper-derived type required to associate an internal state instance
@@ -420,6 +434,10 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
420434
type (ocean_public_type), pointer :: ocean_public => NULL()
421435
type (ocean_state_type), pointer :: ocean_state => NULL()
422436
type(ice_ocean_boundary_type), pointer :: Ice_ocean_boundary => NULL()
437+
type(coupler_1d_bc_type), pointer :: gas_fields_atm => NULL()
438+
type(coupler_1d_bc_type), pointer :: gas_fields_ocn => NULL()
439+
type(coupler_1d_bc_type), pointer :: gas_fluxes => NULL()
440+
type(coupler_2d_bc_type), pointer :: atm_fields => NULL()
423441
type(ocean_internalstate_wrapper) :: ocean_internalstate
424442
type(ocean_grid_type), pointer :: ocean_grid => NULL()
425443
type(directories) :: dirs
@@ -452,6 +470,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
452470
character(len=512) :: restartfile ! Path/Name of restart file
453471
character(len=2048) :: restartfiles ! Path/Name of restart files
454472
! (same as restartfile if single restart file)
473+
character(240) :: additional_restart_dir
455474
character(len=*), parameter :: subname='(MOM_cap:InitializeAdvertise)'
456475
character(len=32) :: calendar
457476
character(len=17) :: timestamp
@@ -548,6 +567,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
548567
if (chkerr(rc,__LINE__,u_FILE_u)) return
549568
call MOM_infra_init(mpi_comm_mom)
550569

570+
call field_manager_init
571+
551572
! determine the calendar
552573
if (cesm_coupled) then
553574
call NUOPC_CompAttributeGet(gcomp, name="calendar", value=cvalue, &
@@ -706,13 +727,44 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
706727

707728
endif
708729

730+
! Set NUOPC attribute additional_restart_dir to RESTART/ if not defined
731+
additional_restart_dir = "RESTART/"
732+
call NUOPC_CompAttributeGet(gcomp, name="additional_restart_dir", value=cvalue, &
733+
isPresent=isPresent, isSet=isSet, rc=rc)
734+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
735+
if (isPresent .and. isSet) then
736+
additional_restart_dir = slasher(cvalue)
737+
else
738+
call ESMF_LogWrite('MOM_cap:additional_restart_dir unset. Defaulting to '//trim(additional_restart_dir), &
739+
ESMF_LOGMSG_INFO)
740+
endif
741+
call NUOPC_CompAttributeSet(gcomp, name="additional_restart_dir", value=additional_restart_dir, rc=rc)
742+
if (chkerr(rc,__LINE__,u_FILE_u)) return
743+
709744
ocean_public%is_ocean_pe = .true.
745+
#ifdef _USE_GENERIC_TRACER
746+
! Initialise structures for extra tracer fluxes
747+
call gas_exchange_init(gas_fields_atm=gas_fields_atm, gas_fields_ocn=gas_fields_ocn, gas_fluxes=gas_fluxes)
748+
749+
if (cesm_coupled .and. len_trim(inst_suffix)>0) then
750+
call ocean_model_init(ocean_public, ocean_state, time0, time_start, gas_fields_ocn=gas_fields_ocn, &
751+
input_restart_file=trim(adjustl(restartfiles)), inst_index=inst_index)
752+
else
753+
call ocean_model_init(ocean_public, ocean_state, time0, time_start, gas_fields_ocn=gas_fields_ocn, &
754+
input_restart_file=trim(adjustl(restartfiles)))
755+
endif
756+
757+
! Enable data override via the data_table using the component name 'OCN'
758+
call get_ocean_grid(ocean_state, ocean_grid)
759+
call data_override_init(ocean_grid%Domain)
760+
#else
710761
if (cesm_coupled .and. len_trim(inst_suffix)>0) then
711762
call ocean_model_init(ocean_public, ocean_state, time0, time_start, &
712763
input_restart_file=trim(adjustl(restartfiles)), inst_index=inst_index)
713764
else
714765
call ocean_model_init(ocean_public, ocean_state, time0, time_start, input_restart_file=trim(adjustl(restartfiles)))
715766
endif
767+
#endif
716768

717769
! GMM, this call is not needed in CESM. Check with EMC if it can be deleted.
718770
call ocean_model_flux_init(ocean_state)
@@ -780,6 +832,31 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
780832
endif
781833
endif
782834

835+
#ifdef _USE_GENERIC_TRACER
836+
! Allocate fields for extra tracer fluxes in Ice_ocean_boundary
837+
! Annoyingly, spawning doesn't copy param array, so add manually
838+
call coupler_type_spawn(gas_fluxes, Ice_ocean_boundary%fluxes, (/isc,isc,iec,iec/), &
839+
(/jsc,jsc,jec,jec/), suffix='_ice_ocn')
840+
call add_gas_fluxes_param(Ice_ocean_boundary%fluxes)
841+
842+
! Initialise structure for atmos fields related to extra tracer fluxes
843+
! This is set in the ESMF Internal State to be accessed elsewhere
844+
! TODO: should we deallocate atm_fields in a finalise step? Ice_ocean_boundary is handled
845+
! in a similar way and does not appear to be deallocated.
846+
allocate(atm_fields)
847+
ocean_internalstate%ptr%coupler_2d_bc_type_ptr => atm_fields
848+
call coupler_type_spawn(gas_fields_atm, atm_fields, (/isc,isc,iec,iec/), &
849+
(/jsc,jsc,jec,jec/), suffix='_atm')
850+
851+
! Register diagnosics for extra tracer flux structures
852+
call coupler_type_set_diags(Ice_ocean_boundary%fluxes, "ocean_flux", ocean_public%axes(1:2), time_start)
853+
call coupler_type_set_diags(atm_fields, "atmos_sfc", ocean_public%axes(1:2), time_start)
854+
855+
! Restore ocean fields related to extra tracer fluxes from restart files
856+
call get_MOM_input(dirs=dirs)
857+
call gas_fields_restore(ocean_public%fields, ocean_public%domain, dirs%restart_input_dir)
858+
#endif
859+
783860
if (use_waves) then
784861
if (wave_method == "EFACTOR") then
785862
allocate( Ice_ocean_boundary%lamult(isc:iec,jsc:jec), source=0.0)
@@ -881,6 +958,15 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
881958
endif
882959
endif
883960

961+
#ifdef _USE_GENERIC_TRACER
962+
! Add import fields required for extra tracer fluxes
963+
do n = 1, gas_fluxes%num_bcs
964+
stdname = get_coupled_field_name(gas_fluxes%bc(n)%name)
965+
if (stdname /= UNKNOWN_CMEPS_FIELD) &
966+
call fld_list_add(fldsToOcn_num, fldsToOcn, stdname, "will provide")
967+
enddo
968+
#endif
969+
884970
!--------- export fields -------------
885971
call fld_list_add(fldsFrOcn_num, fldsFrOcn, "So_omask" , "will provide")
886972
call fld_list_add(fldsFrOcn_num, fldsFrOcn, "So_t" , "will provide")
@@ -895,6 +981,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc)
895981
call fld_list_add(fldsFrOcn_num, fldsFrOcn, "Faoo_fco2_ocn", "will provide")
896982
endif
897983

984+
! TODO: dts: How to handle export fields from generic tracers?
985+
898986
do n = 1,fldsToOcn_num
899987
call NUOPC_Advertise(importState, standardName=fldsToOcn(n)%stdname, name=fldsToOcn(n)%shortname, rc=rc)
900988
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -1706,11 +1794,14 @@ subroutine ModelAdvance(gcomp, rc)
17061794
type (ocean_public_type), pointer :: ocean_public => NULL()
17071795
type (ocean_state_type), pointer :: ocean_state => NULL()
17081796
type(ice_ocean_boundary_type), pointer :: Ice_ocean_boundary => NULL()
1797+
type(coupler_2d_bc_type), pointer :: atm_fields => NULL()
17091798
type(ocean_internalstate_wrapper) :: ocean_internalstate
17101799
type(ocean_grid_type) , pointer :: ocean_grid
17111800
type(time_type) :: Time
1801+
type(time_type) :: Time_import
17121802
type(time_type) :: Time_step_coupled
17131803
type(time_type) :: Time_restart_current
1804+
integer :: isc,iec,jsc,jec
17141805
integer :: dth, dtm, dts
17151806
integer :: nc
17161807
type(ESMF_Time) :: MyTime
@@ -1722,13 +1813,14 @@ subroutine ModelAdvance(gcomp, rc)
17221813
integer :: writeunit
17231814
integer :: localPet
17241815
type(ESMF_VM) :: vm
1725-
integer :: n, i
1816+
integer :: m, n, i
17261817
character(240) :: import_timestr, export_timestr
17271818
character(len=128) :: fldname
17281819
character(len=*),parameter :: subname='(MOM_cap:ModelAdvance)'
17291820
character(len=8) :: suffix
17301821
character(len=:), allocatable :: rpointer_filename
17311822
character(len=17) :: timestamp
1823+
character(240) :: additional_restart_dir
17321824
integer :: num_rest_files
17331825
real(8) :: MPI_Wtime, timers
17341826
logical :: write_restart, write_restartfh
@@ -1769,6 +1861,7 @@ subroutine ModelAdvance(gcomp, rc)
17691861

17701862
Time_step_coupled = esmf2fms_time(timeStep)
17711863
Time = esmf2fms_time(currTime)
1864+
Time_import = Time
17721865

17731866
!---------------
17741867
! Apply ocean lag for startup runs:
@@ -1844,8 +1937,39 @@ subroutine ModelAdvance(gcomp, rc)
18441937
! Import data
18451938
!---------------
18461939

1940+
#ifdef _USE_GENERIC_TRACER
1941+
atm_fields => ocean_internalstate%ptr%coupler_2d_bc_type_ptr
1942+
1943+
call mom_import(ocean_public, ocean_grid, importState, ice_ocean_boundary, atm_fields=atm_fields, rc=rc)
1944+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
1945+
1946+
! Potentially override atm_fields from data_table.
1947+
call coupler_type_data_override('OCN', atm_fields, Time_import)
1948+
1949+
! Potentially override ice_ocean_boundary%fluxes from data_table.
1950+
! Doing this before atmos_ocean_fluxes_calc call avoids unnecessary calculation of overridden fluxes.
1951+
! However, we cannot use coupler_type_data_override here since it does not set the override flag on
1952+
! overridden fields
1953+
do n = 1, ice_ocean_boundary%fluxes%num_bcs
1954+
do m = 1, ice_ocean_boundary%fluxes%bc(n)%num_fields
1955+
call data_override('OCN', ice_ocean_boundary%fluxes%bc(n)%field(m)%name, &
1956+
ice_ocean_boundary%fluxes%bc(n)%field(m)%values, Time_import, &
1957+
override=ice_ocean_boundary%fluxes%bc(n)%field(m)%override)
1958+
enddo
1959+
enddo
1960+
1961+
! Calculate the extra tracer fluxes
1962+
call get_domain_extent(ocean_public%domain, isc, iec, jsc, jec)
1963+
call atmos_ocean_fluxes_calc(atm_fields, ocean_public%fields, ice_ocean_boundary%fluxes, &
1964+
ice_ocean_boundary%ice_fraction, isc, iec, jsc, jec)
1965+
1966+
! Send diagnostics
1967+
call coupler_type_send_data(atm_fields, Time_import)
1968+
call coupler_type_send_data(ice_ocean_boundary%fluxes, Time_import)
1969+
#else
18471970
call mom_import(ocean_public, ocean_grid, importState, ice_ocean_boundary, rc=rc)
18481971
if (ChkErr(rc,__LINE__,u_FILE_u)) return
1972+
#endif
18491973

18501974
!---------------
18511975
! Update MOM6
@@ -1912,7 +2036,7 @@ subroutine ModelAdvance(gcomp, rc)
19122036
! determine restart filename
19132037
call ESMF_ClockGetNextTime(clock, MyTime, rc=rc)
19142038
if (ChkErr(rc,__LINE__,u_FILE_u)) return
1915-
call ESMF_TimeGet (MyTime, yy=year, mm=month, dd=day, h=hour, m=minute, s=seconds, rc=rc )
2039+
call ESMF_TimeGet (MyTime, yy=year, mm=month, dd=day, s=seconds, rc=rc )
19162040
if (ChkErr(rc,__LINE__,u_FILE_u)) return
19172041

19182042
if (cesm_coupled) then
@@ -1975,6 +2099,14 @@ subroutine ModelAdvance(gcomp, rc)
19752099

19762100
endif
19772101

2102+
#ifdef _USE_GENERIC_TRACER
2103+
! Write fields for extra tracer fluxes to their internally defined ocean restart file
2104+
call NUOPC_CompAttributeGet(gcomp, name="additional_restart_dir", value=additional_restart_dir, rc=rc)
2105+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
2106+
2107+
call gas_fields_restart(ocean_public%fields, ocean_public%domain, additional_restart_dir)
2108+
#endif
2109+
19782110
if (is_root_pe()) then
19792111
write(stdout,*) subname//' writing restart file ',trim(restartname)
19802112
endif
@@ -2213,6 +2345,7 @@ subroutine ocean_model_finalize(gcomp, rc)
22132345
type(ESMF_Alarm), allocatable :: alarmList(:)
22142346
integer :: alarmCount
22152347
logical :: write_restart
2348+
character(240) :: additional_restart_dir
22162349
character(len=*),parameter :: subname='(MOM_cap:ocean_model_finalize)'
22172350
real(8) :: MPI_Wtime, timefs
22182351

@@ -2246,6 +2379,18 @@ subroutine ocean_model_finalize(gcomp, rc)
22462379

22472380
call ocean_model_end(ocean_public, ocean_State, Time, write_restart=write_restart)
22482381

2382+
#ifdef _USE_GENERIC_TRACER
2383+
if (write_restart) then
2384+
! Write fields for extra tracer fluxes to their internally defined ocean restart file
2385+
call NUOPC_CompAttributeGet(gcomp, name="additional_restart_dir", value=additional_restart_dir, rc=rc)
2386+
if (ChkErr(rc,__LINE__,u_FILE_u)) return
2387+
2388+
call gas_fields_restart(ocean_public%fields, ocean_public%domain, additional_restart_dir)
2389+
endif
2390+
#endif
2391+
2392+
call field_manager_end()
2393+
22492394
call io_infra_end()
22502395
call MOM_infra_end()
22512396

0 commit comments

Comments
 (0)