diff --git a/config_src/nuopc_driver/mom_cap.F90 b/config_src/nuopc_driver/mom_cap.F90
index 3f6dd1348b..e99a1a0a22 100644
--- a/config_src/nuopc_driver/mom_cap.F90
+++ b/config_src/nuopc_driver/mom_cap.F90
@@ -1,903 +1,411 @@
-!>
-!! @subpage MOM NUOPC Cap
-!! @author Fei Liu (fei.liu@gmail.com)
-!! @date 5/10/13 Original documentation
-!! @author Rocky Dunlap (rocky.dunlap@noaa.gov)
-!! @date 1/12/17 Moved to doxygen
-!! @date 2/28/19 Rewrote for unified cap
-!!
-!! @tableofcontents
-!!
-!! @section Overview Overview
+!> This module contains a set of subroutines that are required by NUOPC.
+
+module MOM_cap_mod
+
+use constants_mod, only: constants_init
+use diag_manager_mod, only: diag_manager_init, diag_manager_end
+use field_manager_mod, only: field_manager_init, field_manager_end
+use fms_mod, only: fms_init, fms_end, open_namelist_file, check_nml_error
+use fms_mod, only: close_file, file_exist, uppercase
+use fms_io_mod, only: fms_io_exit
+use mpp_domains_mod, only: domain2d, mpp_get_compute_domain, mpp_get_compute_domains
+use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_pelist, mpp_get_global_domain
+use mpp_domains_mod, only: mpp_get_domain_npes
+use mpp_io_mod, only: mpp_open, MPP_RDONLY, MPP_ASCII, MPP_OVERWR, MPP_APPEND, mpp_close, MPP_SINGLE
+use mpp_mod, only: stdlog, stdout, mpp_root_pe, mpp_clock_id
+use mpp_mod, only: mpp_clock_begin, mpp_clock_end, MPP_CLOCK_SYNC
+use mpp_mod, only: MPP_CLOCK_DETAILED, CLOCK_COMPONENT, MAXPES
+use time_interp_external_mod, only: time_interp_external_init
+use time_manager_mod, only: set_calendar_type, time_type, increment_date
+use time_manager_mod, only: set_time, set_date, get_time, get_date, month_name
+use time_manager_mod, only: GREGORIAN, JULIAN, NOLEAP, THIRTY_DAY_MONTHS, NO_CALENDAR
+use time_manager_mod, only: operator( <= ), operator( < ), operator( >= )
+use time_manager_mod, only: operator( + ), operator( - ), operator( / )
+use time_manager_mod, only: operator( * ), operator( /= ), operator( > )
+use time_manager_mod, only: date_to_string
+use time_manager_mod, only: fms_get_calendar_type => get_calendar_type
+use MOM_domains, only: MOM_infra_init, num_pes, root_pe, pe_here
+use MOM_file_parser, only: get_param, log_version, param_file_type, close_param_file
+use MOM_get_input, only: Get_MOM_Input, directories
+use MOM_domains, only: pass_var
+use MOM_error_handler, only: MOM_error, FATAL, is_root_pe
+use MOM_ocean_model_nuopc, only: ice_ocean_boundary_type
+use MOM_grid, only: ocean_grid_type, get_global_grid_size
+use MOM_ocean_model_nuopc, only: ocean_model_restart, ocean_public_type, ocean_state_type
+use MOM_ocean_model_nuopc, only: ocean_model_init_sfc
+use MOM_ocean_model_nuopc, only: ocean_model_init, update_ocean_model, ocean_model_end
+use MOM_ocean_model_nuopc, only: get_ocean_grid, get_eps_omesh
+use MOM_cap_time, only: AlarmInit
+use MOM_cap_methods, only: mom_import, mom_export, mom_set_geomtype
+#ifdef CESMCOUPLED
+use shr_file_mod, only: shr_file_setLogUnit, shr_file_getLogUnit
+#endif
+use time_utils_mod, only: esmf2fms_time
+
+use, intrinsic :: iso_fortran_env, only: output_unit
+
+use ESMF, only: ESMF_ClockAdvance, ESMF_ClockGet, ESMF_ClockPrint
+use ESMF, only: ESMF_ClockGetAlarm, ESMF_ClockGetNextTime, ESMF_ClockAdvance
+use ESMF, only: ESMF_ClockSet, ESMF_Clock, ESMF_GeomType_Flag, ESMF_LOGMSG_INFO
+use ESMF, only: ESMF_Grid, ESMF_GridCreate, ESMF_GridAddCoord
+use ESMF, only: ESMF_GridGetCoord, ESMF_GridAddItem, ESMF_GridGetItem
+use ESMF, only: ESMF_GridComp, ESMF_GridCompSetEntryPoint, ESMF_GridCompGet
+use ESMF, only: ESMF_LogFoundError, ESMF_LogWrite, ESMF_LogSetError
+use ESMF, only: ESMF_LOGERR_PASSTHRU, ESMF_KIND_R8, ESMF_RC_VAL_WRONG
+use ESMF, only: ESMF_GEOMTYPE_MESH, ESMF_GEOMTYPE_GRID, ESMF_SUCCESS
+use ESMF, only: ESMF_METHOD_INITIALIZE, ESMF_MethodRemove, ESMF_State
+use ESMF, only: ESMF_LOGMSG_INFO, ESMF_RC_ARG_BAD, ESMF_VM, ESMF_Time
+use ESMF, only: ESMF_TimeInterval, ESMF_MAXSTR, ESMF_VMGetCurrent
+use ESMF, only: ESMF_VMGet, ESMF_TimeGet, ESMF_TimeIntervalGet, ESMF_MeshGet
+use ESMF, only: ESMF_MethodExecute, ESMF_Mesh, ESMF_DeLayout, ESMF_Distgrid
+use ESMF, only: ESMF_DistGridConnection, ESMF_StateItem_Flag, ESMF_KIND_I4
+use ESMF, only: ESMF_KIND_I8, ESMF_FAILURE, ESMF_DistGridCreate, ESMF_MeshCreate
+use ESMF, only: ESMF_FILEFORMAT_ESMFMESH, ESMF_DELayoutCreate, ESMF_DistGridConnectionSet
+use ESMF, only: ESMF_DistGridGet, ESMF_STAGGERLOC_CORNER, ESMF_GRIDITEM_MASK
+use ESMF, only: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_R8, ESMF_STAGGERLOC_CENTER
+use ESMF, only: ESMF_GRIDITEM_AREA, ESMF_Field, ESMF_ALARM, ESMF_VMLogMemInfo
+use ESMF, only: ESMF_AlarmIsRinging, ESMF_AlarmRingerOff, ESMF_StateRemove
+use ESMF, only: ESMF_FieldCreate, ESMF_LOGMSG_ERROR, ESMF_LOGMSG_WARNING
+use ESMF, only: ESMF_COORDSYS_SPH_DEG, ESMF_GridCreate, ESMF_INDEX_DELOCAL
+use ESMF, only: ESMF_MESHLOC_ELEMENT, ESMF_RC_VAL_OUTOFRANGE, ESMF_StateGet
+use ESMF, only: ESMF_TimePrint, ESMF_AlarmSet, ESMF_FieldGet, ESMF_Array
+use ESMF, only: ESMF_ArrayCreate
+use ESMF, only: operator(==), operator(/=), operator(+), operator(-)
+
+! TODO ESMF_GridCompGetInternalState does not have an explicit Fortran interface.
+!! Model does not compile with "use ESMF, only: ESMF_GridCompGetInternalState"
+!! Is this okay?
+
+use NUOPC, only: NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize
+use NUOPC, only: NUOPC_CompFilterPhaseMap, NUOPC_CompAttributeGet, NUOPC_CompAttributeAdd
+use NUOPC, only: NUOPC_Advertise, NUOPC_SetAttribute, NUOPC_IsUpdated, NUOPC_Write
+use NUOPC, only: NUOPC_IsConnected, NUOPC_Realize, NUOPC_CompAttributeSet
+use NUOPC_Model, only: NUOPC_ModelGet
+use NUOPC_Model, &
+ model_routine_SS => SetServices, &
+ model_label_Advance => label_Advance, &
+ model_label_DataInitialize => label_DataInitialize, &
+ model_label_SetRunClock => label_SetRunClock, &
+ model_label_Finalize => label_Finalize
+
+implicit none; private
+
+public SetServices
+
+!> Internal state type with pointers to three types defined by MOM.
+type ocean_internalstate_type
+ type(ocean_public_type), pointer :: ocean_public_type_ptr
+ type(ocean_state_type), pointer :: ocean_state_type_ptr
+ type(ice_ocean_boundary_type), pointer :: ice_ocean_boundary_type_ptr
+end type
+
+!> Wrapper-derived type required to associate an internal state instance
+!! with the ESMF/NUOPC component
+type ocean_internalstate_wrapper
+ type(ocean_internalstate_type), pointer :: ptr
+end type
+
+!> Contains field information
+type fld_list_type
+ character(len=64) :: stdname
+ character(len=64) :: shortname
+ character(len=64) :: transferOffer
+end type fld_list_type
+
+integer,parameter :: fldsMax = 100
+integer :: fldsToOcn_num = 0
+type (fld_list_type) :: fldsToOcn(fldsMax)
+integer :: fldsFrOcn_num = 0
+type (fld_list_type) :: fldsFrOcn(fldsMax)
+
+integer :: debug = 0
+integer :: import_slice = 1
+integer :: export_slice = 1
+character(len=256) :: tmpstr
+logical :: write_diagnostics = .false.
+character(len=32) :: runtype !< run type
+integer :: logunit !< stdout logging unit number
+logical :: profile_memory = .true.
+logical :: grid_attach_area = .false.
+character(len=128) :: scalar_field_name = ''
+integer :: scalar_field_count = 0
+integer :: scalar_field_idx_grid_nx = 0
+integer :: scalar_field_idx_grid_ny = 0
+character(len=*),parameter :: u_file_u = &
+ __FILE__
+
+#ifdef CESMCOUPLED
+logical :: cesm_coupled = .true.
+type(ESMF_GeomType_Flag) :: geomtype = ESMF_GEOMTYPE_MESH
+#else
+logical :: cesm_coupled = .false.
+type(ESMF_GeomType_Flag) :: geomtype = ESMF_GEOMTYPE_GRID
+#endif
+
+contains
+
+!> NUOPC SetService method is the only public entry point.
+!! SetServices registers all of the user-provided subroutines
+!! in the module with the NUOPC layer.
!!
-!! **This MOM cap has been tested with MOM6.**
+!! @param gcomp an ESMF_GridComp object
+!! @param rc return code
+subroutine SetServices(gcomp, rc)
+
+ type(ESMF_GridComp) :: gcomp !< an ESMF_GridComp object
+ integer, intent(out) :: rc !< return code
+
+ ! local variables
+ character(len=*),parameter :: subname='(MOM_cap:SetServices)'
+
+ rc = ESMF_SUCCESS
+
+ ! the NUOPC model component will register the generic methods
+ call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ ! switching to IPD versions
+ call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
+ userRoutine=InitializeP0, phase=0, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ ! set entry point for methods that require specific implementation
+ call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
+ phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeAdvertise, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+ call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
+ phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeRealize, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ !------------------
+ ! attach specializing method(s)
+ !------------------
+
+ call NUOPC_CompSpecialize(gcomp, specLabel=model_label_DataInitialize, &
+ specRoutine=DataInitialize, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, &
+ specRoutine=ModelAdvance, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+ call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, &
+ specRoutine=ModelSetRunClock, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+ call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, &
+ specRoutine=ocean_model_finalize, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return ! bail out
+
+end subroutine SetServices
+
+!> First initialize subroutine called by NUOPC. The purpose
+!! is to set which version of the Initialize Phase Definition (IPD)
+!! to use.
!!
-!! This document describes the MOM NUOPC "cap", which is a light weight software layer that is
-!! required when the [MOM ocean model](https://github.com/NOAA-GFDL/MOM6/tree/dev/master)
-!! is used in [National Unified Operation Prediction Capability]
-!! (http://www.earthsystemcog.org/projects/nuopc) (NUOPC) coupled systems. Also see the
-!! [MOM wiki](https://github.com/NOAA-GFDL/MOM6-Examples/wiki) for more documentation.
+!! For this MOM cap, we are using IPDv01.
!!
-!! NUOPC is a software layer built on top of the [Earth System Modeling
-!! Framework] (https://www.earthsystemcog.org/projects/esmf) (ESMF).
-!! ESMF is a high-performance modeling framework that provides
-!! data structures, interfaces, and operations suited for building coupled models
-!! from a set of components. NUOPC refines the capabilities of ESMF by providing
-!! a more precise definition of what it means for a model to be a component and
-!! how components should interact and share data in a coupled system. The NUOPC
-!! Layer software is designed to work with typical high-performance models in the
-!! Earth sciences domain, most of which are written in Fortran and are based on a
-!! distributed memory model of parallelism (MPI).
-!!
-!! A NUOPC "cap" is a Fortran module that serves as the interface to a model
-!! when it's used in a NUOPC-based coupled system.
-!! The term "cap" is used because it is a light weight software layer that sits on top
-!! of model code, making calls into it and exposing model data structures in a
-!! standard way.
-!!
-!! The MOM cap package includes the cap code itself (MOM_cap.F90, MOM_cap_methods.F90
-!! and MOM_cap_time.F90), a set of time utilities (time_utils.F90) for converting between ESMF and FMS
-!! time type and two modules MOM_ocean_model_nuopc.F90 and MOM_surface_forcing_nuopc.F90. MOM_surface_forcing_nuopc.F90
-!! converts the input ESMF data (import data) to a MOM-specific data type (surface_forcing_CS).
-!! MOM_ocean_model_nuopc.F90 contains routines for initialization, update and finalization of the ocean model state.
-!!
-!! @subsection CapSubroutines Cap Subroutines
-!!
-!! The MOM cap modules contains a set of subroutines that are required
-!! by NUOPC. These subroutines are called by the NUOPC infrastructure according
-!! to a predefined calling sequence. Some subroutines are called during
-!! initialization of the coupled system, some during the run of the coupled
-!! system, and some during finalization of the coupled system.
-!!
-!! The initialization sequence is the most complex and is governed by the NUOPC technical rules.
-!! Details about the initialization sequence can be found in the [NUOPC Reference Manual]
-!! (http://www.earthsystemmodeling.org/esmf_releases/last_built/NUOPC_refdoc/).
-!! The cap requires beta snapshot ESMF v8.0.0bs16 or later.
-!!
-!! The following table summarizes the NUOPC-required subroutines that appear in the
-!! MOM cap. The "Phase" column says whether the subroutine is called during the
-!! initialization, run, or finalize part of the coupled system run.
-!!
-!! Phase | MOM Cap Subroutine | Description
-!! ---------|--------------------------------------------------------------------|--------------------------------------
-!! Init | [InitializeP0] (@ref MOM_cap_mod::initializep0) | Sets the Initialize Phase Definition
-!! | (IPD) version to use
-!! Init | [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) | Advertises standard names of import
-!! | and export fields
-!! Init | [InitializeRealize] (@ref MOM_cap_mod::initializerealize) | Creates an ESMF_Grid or ESMF_Mesh
-!! | as well as ESMF_Fields for import
-!! | and export fields
-!! Run | [ModelAdvance] (@ref MOM_cap_mod::modeladvance) | Advances the model by a timestep
-!! Final | [Finalize] (@ref MOM_cap_mod::ocean_model_finalize) | Cleans up
-!!
-!! @section UnderlyingModelInterfaces Underlying Model Interfaces
-!!
-!!
-!! @subsection DomainCreation Domain Creation
-!!
-!! The cap can accomodate a MOM tripolar grid which is represented either as a 2D `ESMF_Grid` or
-!! as a 1D `ESMF_Mesh`. Other MOM grids (e.g. a bipolar grid) can be represented as a 1d `ESMF_Mesh` only.
-!! Coupling fields are placed on either the `ESMF_Grid` or `ESMF_Mesh`.
-!! Note that for either the `ESMF_Grid` or `ESMF_Mesh` representation, the fields are translated into
-!! a 2D MOM specific surface boundary type and the distinction between the two is no longer there.
-!! Calls related to creating the grid are located in the [InitializeRealize]
-!! (@ref MOM_cap_mod::initializerealize) subroutine, which is called by the NUOPC infrastructure
-!! during the intialization sequence.
-!!
-!! The cap determines parameters for setting up the grid by calling subroutines in the
-!! `mpp_domains_mod` module. The global domain size is determined by calling `mpp_get_global_domain()`.
-!! A check is in place to ensure that there is only a single tile in the domain (the
-!! cap is currently limited to one tile; multi-tile mosaics are not supported). The
-!! decomposition across processors is determined via calls to `mpp_get_compute_domains()`
-!! (to retrieve decomposition block indices) and `mpp_get_pelist()` (to determine how
-!! blocks are assigned to processors).
-!!
-!! The `ESMF_Grid` is created in several steps:
-!! - an `ESMF_DELayout` is created based on the pelist from MOM
-!! - an `ESMF_DistGrid` is created over the global index space. Connections are set
-!! up so that the index space is periodic in the first dimension and has a
-!! fold at the top for the bipole. The decompostion blocks are also passed in
-!! along with the `ESMF_DELayout` mentioned above.
-!! - an `ESMF_Grid` is then created by passing in the above `ESMF_DistGrid`.
-!! - masks, areas, center (tlat, tlon), and corner (ulat, ulon) coordinates are then added to the `ESMF_Grid`
-!! by retrieving those fields from the MOM datatype `ocean_grid` elements.
-!!
-!! The `ESMF_Mesh` is also created in several steps:
-!! - the target mesh is generated offline.
-!! - a temporary mesh is created from an input file specified by the config variable `mesh_ocn`.
-!! the mesh has a distribution that is automatically generated by ESMF when reading in the mesh
-!! - an `ESMF_DistGrid` is created from the global index space for the computational domain.
-!! - the final `ESMF_Mesh` is then created by distributing the temporary mesh using the created `ESMF_DistGrid`.
-!!
-!!
-!! @subsection Initialization Initialization
-!!
-!! During the [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) phase, calls are
-!! made to MOM's native initialization subroutines, including `fms_init()`, `constants_init()`,
-!! `field_manager_init()`, `diag_manager_init()`, and `set_calendar_type()`. The MPI communicator
-!! is pulled in through the ESMF VM object for the MOM component. The dt and start time are set
-!! from parameters from the incoming ESMF clock with calls to `set_time()` and `set_date().`
-!!
-!!
-!! @subsection Run Run
-!!
-!! The [ModelAdvance] (@ref MOM_cap_mod::modeladvance) subroutine is called by the NUOPC
-!! infrastructure when it's time for MOM to advance in time. During this subroutine, there is a
-!! call into the MOM update routine:
-!!
-!! call update_ocean_model(Ice_ocean_boundary, Ocean_state, Ocean_public, Time, Time_step_coupled)
-!!
-!! Priori to the call to `update_ocean_model()`, the cap performs these steps
-!! - the `Time` and `Time_step_coupled` parameters, based on FMS types, are derived from the incoming ESMF clock
-!! - diagnostics are optionally written to files `field_ocn_import_*`, one for each import field
-!! - mom_import is called and translates to the ESMF input data to a MOM specific data type
-!! - momentum flux vectors are rotated to internal grid
-!!
-!! After the call to `update_ocean_model()`, the cap performs these steps:
-!! - mom_export is called
-!! - the `ocean_mask` export is set to match that of the internal MOM mask
-!! - the `freezing_melting_potential` export is converted from J m-2 to W m-2 by dividing by the coupling interval
-!! - vector rotations are applied to the `ocean_current_zonal` and `ocean_current_merid` exports, back to lat-lon grid
-!! - diagnostics are optionally written to files `field_ocn_export_*`, one for each export field
-!! - optionally, a call is made to `ocean_model_restart()` at the interval `restart_interval`
-!!
-!! @subsubsection VectorRotations Vector Rotations
-!!
-!! Vector rotations are applied to incoming momentum fluxes (from regular lat-lon to tripolar grid) and
-!! outgoing ocean currents (from tripolar to regular lat-lon). The rotation angles are provided
-!! from the native MOM grid by a call to `get_ocean_grid(Ocean_grid)`.
-!! The cosine and sine of the rotation angle are:
-!!
-!! ocean_grid%cos_rot(i,j)
-!! ocean_grid%sin_rot(i,j)
-!!
-!! The rotation of momentum flux from regular lat-lon to tripolar is:
-!! \f[
-!! \begin{bmatrix}
-!! \tau_x' \\
-!! \tau_y'
-!! \end{bmatrix} =
-!! \begin{bmatrix}
-!! cos \theta & sin \theta \\
-!! -sin \theta & cos \theta
-!! \end{bmatrix} *
-!! \begin{bmatrix}
-!! \tau_x \\
-!! \tau_y
-!! \end{bmatrix}
-!! \f]
-!!
-!! The rotation of ocean current from tripolar to regular lat-lon is:
-!! \f[
-!! \begin{bmatrix}
-!! u' \\
-!! v'
-!! \end{bmatrix} =
-!! \begin{bmatrix}
-!! cos \theta & -sin \theta \\
-!! sin \theta & cos \theta
-!! \end{bmatrix} *
-!! \begin{bmatrix}
-!! u \\
-!! v
-!! \end{bmatrix}
-!! \f]
-!! @subsection Finalization Finalization
-!!
-!! NUOPC infrastructure calls [ocean_model_finalize] (@ref MOM_cap_mod::ocean_model_finalize)
-!! at the end of the run. This subroutine is a hook to call into MOM's native shutdown
-!! procedures:
-!!
-!! call ocean_model_end (ocean_public, ocean_State, Time)
-!! call diag_manager_end(Time )
-!! call field_manager_end
-!! call fms_io_exit
-!! call fms_end
-!!
-!! @section ModelFields Model Fields
-!!
-!! The following tables list the import and export fields currently set up in the MOM cap.
-!!
-!! @subsection ImportFields Import Fields
-!!
-!!
-!!
-!!
-!! Standard Name |
-!! Units |
-!! Model Variable |
-!! Description |
-!! Notes |
-!!
-!!
-!!
-!!
-!! inst_pres_height_surface |
-!! Pa |
-!! p |
-!! pressure of overlying sea ice and atmosphere |
-!!
-!!
-!! mass_of_overlying_sea_ice |
-!! kg |
-!! mi |
-!! mass of overlying sea ice |
-!! |
-!!
-!!
-!! seaice_melt_heat |
-!! W m-2 |
-!! seaice_melt_heat |
-!! sea ice and snow melt heat flux |
-!! |
-!!
-!!
-!! seaice_melt |
-!! kg m-2 s-1 |
-!! seaice_melt |
-!! water flux due to sea ice and snow melting |
-!! |
-!!
-!!
-!! mean_calving_heat_flx |
-!! W m-2 |
-!! calving_hflx |
-!! heat flux, relative to 0C, of frozen land water into ocean |
-!!
-!!
-!! mean_calving_rate |
-!! kg m-2 s-1 |
-!! calving |
-!! mass flux of frozen runoff |
-!! |
-!!
-!!
-!! mean_evap_rate |
-!! kg m-2 s-1 |
-!! q_flux |
-!! specific humidity flux |
-!!
-!!
-!! mean_fprec_rate |
-!! kg m-2 s-1 |
-!! fprec |
-!! mass flux of frozen precip |
-!! |
-!!
-!!
-!! mean_merid_moment_flx |
-!! Pa |
-!! v_flux |
-!! j-directed wind stress into ocean |
-!! [vector rotation] (@ref VectorRotations) applied - lat-lon to tripolar |
-!!
-!!
-!! mean_net_lw_flx |
-!! W m-2 |
-!! lw_flux |
-!! long wave radiation |
-!! |
-!!
-!!
-!! mean_net_sw_ir_dif_flx |
-!! W m-2 |
-!! sw_flux_nir_dif |
-!! diffuse near IR shortwave radiation |
-!! |
-!!
-!!
-!! mean_net_sw_ir_dir_flx |
-!! W m-2 |
-!! sw_flux_nir_dir |
-!! direct near IR shortwave radiation |
-!! |
-!!
-!!
-!! mean_net_sw_vis_dif_flx |
-!! W m-2 |
-!! sw_flux_vis_dif |
-!! diffuse visible shortware radiation |
-!! |
-!!
-!!
-!! mean_net_sw_vis_dir_flx |
-!! W m-2 |
-!! sw_flux_vis_dir |
-!! direct visible shortware radiation |
-!! |
-!!
-!!
-!! mean_prec_rate |
-!! kg m-2 s-1 |
-!! lprec |
-!! mass flux of liquid precip |
-!! |
-!!
-!!
-!! mean_runoff_heat_flx |
-!! W m-2 |
-!! runoff_hflx |
-!! heat flux, relative to 0C, of liquid land water into ocean |
-!!
-!!
-!! mean_runoff_rate |
-!! kg m-2 s-1 |
-!! runoff |
-!! mass flux of liquid runoff |
-!! |
-!!
-!!
-!! mean_salt_rate |
-!! kg m-2 s-1 |
-!! salt_flux |
-!! salt flux |
-!! |
-!!
-!!
-!! mean_sensi_heat_flx |
-!! W m-2 |
-!! t_flux |
-!! sensible heat flux into ocean |
-!!
-!!
-!! mean_zonal_moment_flx |
-!! Pa |
-!! u_flux |
-!! i-directed wind stress into ocean |
-!! [vector rotation] (@ref VectorRotations) applied - lat-lon to tripolar |
-!!
-!!
-!!
-!!
-!! @subsection ExportField Export Fields
-!!
-!! Export fields are populated from the `ocean_public` parameter (type `ocean_public_type`)
-!! after the call to `update_ocean_model()`.
-!!
-!!
-!!
-!!
-!! Standard Name |
-!! Units |
-!! Model Variable |
-!! Description |
-!! Notes |
-!!
-!!
-!!
-!!
-!! freezing_melting_potential |
-!! W m-2 |
-!! combination of frazil and melt_potential |
-!! cap converts model units (J m-2) to (W m-2) for export |
-!!
-!!
-!! ocean_mask |
-!! |
-!! |
-!! ocean mask |
-!! |
-!!
-!!
-!! ocn_current_merid |
-!! m s-1 |
-!! v_surf |
-!! j-directed surface velocity on u-cell |
-!! [vector rotation] (@ref VectorRotations) applied - tripolar to lat-lon |
-!!
-!!
-!! ocn_current_zonal |
-!! m s-1 |
-!! u_surf |
-!! i-directed surface velocity on u-cell |
-!! [vector rotation] (@ref VectorRotations) applied - tripolar to lat-lon |
-!!
-!!
-!! s_surf |
-!! psu |
-!! s_surf |
-!! sea surface salinity on t-cell |
-!! |
-!!
-!!
-!! sea_surface_temperature |
-!! K |
-!! t_surf |
-!! sea surface temperature on t-cell |
-!! |
-!!
-!!
-!! sea_surface_slope_zonal |
-!! unitless |
-!! created from ssh |
-!! sea surface zonal slope |
-!! |
-!!
-!!
-!! sea_surface_slope_merid |
-!! unitless |
-!! created from ssh |
-!! sea surface meridional slope |
-!! |
-!!
-!!
-!! so_bldepth |
-!! m |
-!! obld |
-!! ocean surface boundary layer depth |
-!! |
-!!
-!!
-!!
-!!
-!! @subsection MemoryManagement Memory Management
-!!
-!! The MOM cap has an internal state type with pointers to three
-!! types defined by MOM. There is also a small wrapper derived type
-!! required to associate an internal state instance
-!! with the ESMF/NUOPC component:
-!!
-!! type ocean_internalstate_type
-!! type(ocean_public_type), pointer :: ocean_public_type_ptr
-!! type(ocean_state_type), pointer :: ocean_state_type_ptr
-!! type(ice_ocean_boundary_type), pointer :: ice_ocean_boundary_type_ptr
-!! end type
-!!
-!! type ocean_internalstate_wrapper
-!! type(ocean_internalstate_type), pointer :: ptr
-!! end type
-!!
-!! The member of type `ocean_public_type` stores ocean surface fields used during the coupling.
-!! The member of type `ocean_state_type` is required by the ocean driver,
-!! although its internals are private (not to be used by the coupling directly).
-!! This type is passed to the ocean init and update routines
-!! so that it can maintain state there if desired.
-!! The member of type `ice_ocean_boundary_type` is populated by this cap
-!! with incoming coupling fields from other components. These three derived types are allocated during the
-!! [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) phase. Also during that
-!! phase, the `ice_ocean_boundary` type members are all allocated using bounds retrieved
-!! from `mpp_get_compute_domain()`.
-!!
-!! During the [InitializeRealize] (@ref MOM_cap_mod::initializerealize) phase,
-!! `ESMF_Field`s are created for each of the coupling fields in the `ice_ocean_boundary`
-!! and `ocean_public_type` members of the internal state. These fields directly reference into the members of
-!! the `ice_ocean_boundary` and `ocean_public_type` so that memory-to-memory copies are not required to move
-!! data from the cap's import and export states to the memory areas used internally
-!! by MOM.
-!!
-!! @subsection IO I/O
-!!
-!! The cap can optionally output coupling fields for diagnostic purposes if the ESMF attribute
-!! "DumpFields" has been set to "true". In this case the cap will write out NetCDF files
-!! with names "field_ocn_import_.nc" and "field_ocn_export_.nc".
-!! Additionally, calls will be made to the cap subroutine [dumpMomInternal]
-!! (@ref MOM_cap_mod::dumpmominternal) to write out model internal fields to files
-!! named "field_ocn_internal_.nc". In all cases these NetCDF files will
-!! contain a time series of field data.
-!!
-!! @section RuntimeConfiguration Runtime Configuration
-!!
-!! At runtime, the MOM cap can be configured with several options provided
-!! as ESMF attributes. Attributes can be set in the cap by the NUOPC Driver
-!! above this cap, or in some systems ESMF attributes are set by
-!! reading in from a configuration file. The available attributes are:
-!!
-!! * `DumpFields` - when set to "true", write out diagnostic NetCDF files for import/export/internal fields
-!! * `ProfileMemory` - when set to "true", write out memory usage information to the ESMF log files; this
-!! information is written when entering and leaving the [ModelAdvance]
-!! (@ref MOM_cap_mod::modeladvance) subroutine and before and after the call to
-!! `update_ocean_model()`.
-!! * `restart_interval` - integer number of seconds indicating the interval at
-!! which to call `ocean_model_restart()`; no restarts written if set to 0
-!!
-!!
-
-!> This module contains a set of subroutines that are required by NUOPC.
-module MOM_cap_mod
-use constants_mod, only: constants_init
-use diag_manager_mod, only: diag_manager_init, diag_manager_end
-use field_manager_mod, only: field_manager_init, field_manager_end
-use fms_mod, only: fms_init, fms_end, open_namelist_file, check_nml_error
-use fms_mod, only: close_file, file_exist, uppercase
-use fms_io_mod, only: fms_io_exit
-use mpp_domains_mod, only: domain2d, mpp_get_compute_domain, mpp_get_compute_domains
-use mpp_domains_mod, only: mpp_get_ntile_count, mpp_get_pelist, mpp_get_global_domain
-use mpp_domains_mod, only: mpp_get_domain_npes
-use mpp_io_mod, only: mpp_open, MPP_RDONLY, MPP_ASCII, MPP_OVERWR, MPP_APPEND, mpp_close, MPP_SINGLE
-use mpp_mod, only: stdlog, stdout, mpp_root_pe, mpp_clock_id
-use mpp_mod, only: mpp_clock_begin, mpp_clock_end, MPP_CLOCK_SYNC
-use mpp_mod, only: MPP_CLOCK_DETAILED, CLOCK_COMPONENT, MAXPES
-use time_interp_external_mod, only: time_interp_external_init
-use time_manager_mod, only: set_calendar_type, time_type, increment_date
-use time_manager_mod, only: set_time, set_date, get_time, get_date, month_name
-use time_manager_mod, only: GREGORIAN, JULIAN, NOLEAP, THIRTY_DAY_MONTHS, NO_CALENDAR
-use time_manager_mod, only: operator( <= ), operator( < ), operator( >= )
-use time_manager_mod, only: operator( + ), operator( - ), operator( / )
-use time_manager_mod, only: operator( * ), operator( /= ), operator( > )
-use time_manager_mod, only: date_to_string
-use time_manager_mod, only: fms_get_calendar_type => get_calendar_type
-use MOM_domains, only: MOM_infra_init, num_pes, root_pe, pe_here
-use MOM_file_parser, only: get_param, log_version, param_file_type, close_param_file
-use MOM_get_input, only: Get_MOM_Input, directories
-use MOM_domains, only: pass_var
-use MOM_error_handler, only: MOM_error, FATAL, is_root_pe
-use MOM_ocean_model_nuopc, only: ice_ocean_boundary_type
-use MOM_grid, only: ocean_grid_type, get_global_grid_size
-use MOM_ocean_model_nuopc, only: ocean_model_restart, ocean_public_type, ocean_state_type
-use MOM_ocean_model_nuopc, only: ocean_model_init_sfc
-use MOM_ocean_model_nuopc, only: ocean_model_init, update_ocean_model, ocean_model_end
-use MOM_ocean_model_nuopc, only: get_ocean_grid, get_eps_omesh
-use MOM_cap_time, only: AlarmInit
-use MOM_cap_methods, only: mom_import, mom_export, mom_set_geomtype
-#ifdef CESMCOUPLED
-use shr_file_mod, only: shr_file_setLogUnit, shr_file_getLogUnit
-#endif
-use time_utils_mod, only: esmf2fms_time
-
-use, intrinsic :: iso_fortran_env, only: output_unit
-
-use ESMF, only: ESMF_ClockAdvance, ESMF_ClockGet, ESMF_ClockPrint
-use ESMF, only: ESMF_ClockGetAlarm, ESMF_ClockGetNextTime, ESMF_ClockAdvance
-use ESMF, only: ESMF_ClockSet, ESMF_Clock, ESMF_GeomType_Flag, ESMF_LOGMSG_INFO
-use ESMF, only: ESMF_Grid, ESMF_GridCreate, ESMF_GridAddCoord
-use ESMF, only: ESMF_GridGetCoord, ESMF_GridAddItem, ESMF_GridGetItem
-use ESMF, only: ESMF_GridComp, ESMF_GridCompSetEntryPoint, ESMF_GridCompGet
-use ESMF, only: ESMF_LogFoundError, ESMF_LogWrite, ESMF_LogSetError
-use ESMF, only: ESMF_LOGERR_PASSTHRU, ESMF_KIND_R8, ESMF_RC_VAL_WRONG
-use ESMF, only: ESMF_GEOMTYPE_MESH, ESMF_GEOMTYPE_GRID, ESMF_SUCCESS
-use ESMF, only: ESMF_METHOD_INITIALIZE, ESMF_MethodRemove, ESMF_State
-use ESMF, only: ESMF_LOGMSG_INFO, ESMF_RC_ARG_BAD, ESMF_VM, ESMF_Time
-use ESMF, only: ESMF_TimeInterval, ESMF_MAXSTR, ESMF_VMGetCurrent
-use ESMF, only: ESMF_VMGet, ESMF_TimeGet, ESMF_TimeIntervalGet, ESMF_MeshGet
-use ESMF, only: ESMF_MethodExecute, ESMF_Mesh, ESMF_DeLayout, ESMF_Distgrid
-use ESMF, only: ESMF_DistGridConnection, ESMF_StateItem_Flag, ESMF_KIND_I4
-use ESMF, only: ESMF_KIND_I8, ESMF_FAILURE, ESMF_DistGridCreate, ESMF_MeshCreate
-use ESMF, only: ESMF_FILEFORMAT_ESMFMESH, ESMF_DELayoutCreate, ESMF_DistGridConnectionSet
-use ESMF, only: ESMF_DistGridGet, ESMF_STAGGERLOC_CORNER, ESMF_GRIDITEM_MASK
-use ESMF, only: ESMF_TYPEKIND_I4, ESMF_TYPEKIND_R8, ESMF_STAGGERLOC_CENTER
-use ESMF, only: ESMF_GRIDITEM_AREA, ESMF_Field, ESMF_ALARM, ESMF_VMLogMemInfo
-use ESMF, only: ESMF_AlarmIsRinging, ESMF_AlarmRingerOff, ESMF_StateRemove
-use ESMF, only: ESMF_FieldCreate, ESMF_LOGMSG_ERROR, ESMF_LOGMSG_WARNING
-use ESMF, only: ESMF_COORDSYS_SPH_DEG, ESMF_GridCreate, ESMF_INDEX_DELOCAL
-use ESMF, only: ESMF_MESHLOC_ELEMENT, ESMF_RC_VAL_OUTOFRANGE, ESMF_StateGet
-use ESMF, only: ESMF_TimePrint, ESMF_AlarmSet, ESMF_FieldGet, ESMF_Array
-use ESMF, only: ESMF_ArrayCreate
-use ESMF, only: operator(==), operator(/=), operator(+), operator(-)
-
-! TODO ESMF_GridCompGetInternalState does not have an explicit Fortran interface.
-!! Model does not compile with "use ESMF, only: ESMF_GridCompGetInternalState"
-!! Is this okay?
-
-use NUOPC, only: NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize
-use NUOPC, only: NUOPC_CompFilterPhaseMap, NUOPC_CompAttributeGet, NUOPC_CompAttributeAdd
-use NUOPC, only: NUOPC_Advertise, NUOPC_SetAttribute, NUOPC_IsUpdated, NUOPC_Write
-use NUOPC, only: NUOPC_IsConnected, NUOPC_Realize, NUOPC_CompAttributeSet
-use NUOPC_Model, only: NUOPC_ModelGet
-use NUOPC_Model, &
- model_routine_SS => SetServices, &
- model_label_Advance => label_Advance, &
- model_label_DataInitialize => label_DataInitialize, &
- model_label_SetRunClock => label_SetRunClock, &
- model_label_Finalize => label_Finalize
-
-implicit none; private
-
-public SetServices
-
-!> Internal state type with pointers to three types defined by MOM.
-type ocean_internalstate_type
- type(ocean_public_type), pointer :: ocean_public_type_ptr
- type(ocean_state_type), pointer :: ocean_state_type_ptr
- type(ice_ocean_boundary_type), pointer :: ice_ocean_boundary_type_ptr
-end type
-
-!> Wrapper-derived type required to associate an internal state instance
-!! with the ESMF/NUOPC component
-type ocean_internalstate_wrapper
- type(ocean_internalstate_type), pointer :: ptr
-end type
-
-!> Contains field information
-type fld_list_type
- character(len=64) :: stdname
- character(len=64) :: shortname
- character(len=64) :: transferOffer
-end type fld_list_type
-
-integer,parameter :: fldsMax = 100
-integer :: fldsToOcn_num = 0
-type (fld_list_type) :: fldsToOcn(fldsMax)
-integer :: fldsFrOcn_num = 0
-type (fld_list_type) :: fldsFrOcn(fldsMax)
-
-integer :: debug = 0
-integer :: import_slice = 1
-integer :: export_slice = 1
-character(len=256) :: tmpstr
-logical :: write_diagnostics = .false.
-character(len=32) :: runtype !< run type
-integer :: logunit !< stdout logging unit number
-logical :: profile_memory = .true.
-logical :: grid_attach_area = .false.
-character(len=128) :: scalar_field_name = ''
-integer :: scalar_field_count = 0
-integer :: scalar_field_idx_grid_nx = 0
-integer :: scalar_field_idx_grid_ny = 0
-character(len=*),parameter :: u_file_u = &
- __FILE__
-
-#ifdef CESMCOUPLED
-logical :: cesm_coupled = .true.
-type(ESMF_GeomType_Flag) :: geomtype = ESMF_GEOMTYPE_MESH
-#else
-logical :: cesm_coupled = .false.
-type(ESMF_GeomType_Flag) :: geomtype = ESMF_GEOMTYPE_GRID
-#endif
-
-contains
-
-!> NUOPC SetService method is the only public entry point.
-!! SetServices registers all of the user-provided subroutines
-!! in the module with the NUOPC layer.
-!!
-!! @param gcomp an ESMF_GridComp object
-!! @param rc return code
-subroutine SetServices(gcomp, rc)
-
- type(ESMF_GridComp) :: gcomp !< an ESMF_GridComp object
- integer, intent(out) :: rc !< return code
-
- ! local variables
- character(len=*),parameter :: subname='(MOM_cap:SetServices)'
-
- rc = ESMF_SUCCESS
-
- ! the NUOPC model component will register the generic methods
- call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- ! switching to IPD versions
- call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- userRoutine=InitializeP0, phase=0, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- ! set entry point for methods that require specific implementation
- call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeAdvertise, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
- call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeRealize, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- !------------------
- ! attach specializing method(s)
- !------------------
-
- call NUOPC_CompSpecialize(gcomp, specLabel=model_label_DataInitialize, &
- specRoutine=DataInitialize, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, &
- specRoutine=ModelAdvance, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
- call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, &
- specRoutine=ModelSetRunClock, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
- call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, &
- specRoutine=ocean_model_finalize, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return ! bail out
-
-end subroutine SetServices
-
-!> First initialize subroutine called by NUOPC. The purpose
-!! is to set which version of the Initialize Phase Definition (IPD)
-!! to use.
-!!
-!! For this MOM cap, we are using IPDv01.
-!!
-!! @param gcomp an ESMF_GridComp object
-!! @param importState an ESMF_State object for import fields
-!! @param exportState an ESMF_State object for export fields
-!! @param clock an ESMF_Clock object
-!! @param rc return code
-subroutine InitializeP0(gcomp, importState, exportState, clock, rc)
- type(ESMF_GridComp) :: gcomp !< ESMF_GridComp object
- type(ESMF_State) :: importState, exportState !< ESMF_State object for
- !! import/export fields
- type(ESMF_Clock) :: clock !< ESMF_Clock object
- integer, intent(out) :: rc !< return code
-
- ! local variables
- logical :: isPresent, isSet
- integer :: iostat
- character(len=64) :: value, logmsg
- character(len=*),parameter :: subname='(MOM_cap:InitializeP0)'
-
- rc = ESMF_SUCCESS
-
- ! Switch to IPDv03 by filtering all other phaseMap entries
- call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, &
- acceptStringList=(/"IPDv03p"/), rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
-
- write_diagnostics = .false.
- call NUOPC_CompAttributeGet(gcomp, name="DumpFields", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) write_diagnostics=(trim(value)=="true")
-
- write(logmsg,*) write_diagnostics
- call ESMF_LogWrite('MOM_cap:DumpFields = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
-
- profile_memory = .false.
- call NUOPC_CompAttributeGet(gcomp, name="ProfileMemory", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) profile_memory=(trim(value)=="true")
- write(logmsg,*) profile_memory
- call ESMF_LogWrite('MOM_cap:ProfileMemory = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
-
- grid_attach_area = .false.
- call NUOPC_CompAttributeGet(gcomp, name="GridAttachArea", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) grid_attach_area=(trim(value)=="true")
- write(logmsg,*) grid_attach_area
- call ESMF_LogWrite('MOM_cap:GridAttachArea = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
-
- scalar_field_name = ""
- call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldName", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) then
- scalar_field_name = trim(value)
- call ESMF_LogWrite('MOM_cap:ScalarFieldName = '//trim(scalar_field_name), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- endif
-
- scalar_field_count = 0
- call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldCount", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) then
- read(value, '(i)', iostat=iostat) scalar_field_count
- if (iostat /= 0) then
- call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
- msg=subname//": ScalarFieldCount not an integer: "//trim(value), &
- line=__LINE__, file=__FILE__, rcToReturn=rc)
- return
- endif
- write(logmsg,*) scalar_field_count
- call ESMF_LogWrite('MOM_cap:ScalarFieldCount = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- endif
-
- scalar_field_idx_grid_nx = 0
- call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNX", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) then
- read(value, '(i)', iostat=iostat) scalar_field_idx_grid_nx
- if (iostat /= 0) then
- call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
- msg=subname//": ScalarFieldIdxGridNX not an integer: "//trim(value), &
- line=__LINE__, file=__FILE__, rcToReturn=rc)
- return
- endif
- write(logmsg,*) scalar_field_idx_grid_nx
- call ESMF_LogWrite('MOM_cap:ScalarFieldIdxGridNX = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- endif
-
- scalar_field_idx_grid_ny = 0
- call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNY", value=value, &
- isPresent=isPresent, isSet=isSet, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- if (isPresent .and. isSet) then
- read(value, '(i)', iostat=iostat) scalar_field_idx_grid_ny
- if (iostat /= 0) then
- call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
- msg=subname//": ScalarFieldIdxGridNY not an integer: "//trim(value), &
- line=__LINE__, file=__FILE__, rcToReturn=rc)
- return
- endif
- write(logmsg,*) scalar_field_idx_grid_ny
- call ESMF_LogWrite('MOM_cap:ScalarFieldIdxGridNY = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
- endif
-
- call NUOPC_CompAttributeAdd(gcomp, &
- attrList=(/'RestartFileToRead', 'RestartFileToWrite'/), rc=rc)
- if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
- line=__LINE__, &
- file=__FILE__)) &
- return
-
-end subroutine
-
-!> Called by NUOPC to advertise import and export fields. "Advertise"
-!! simply means that the standard names of all import and export
-!! fields are supplied. The NUOPC layer uses these to match fields
-!! between components in the coupled system.
+!! @param gcomp an ESMF_GridComp object
+!! @param importState an ESMF_State object for import fields
+!! @param exportState an ESMF_State object for export fields
+!! @param clock an ESMF_Clock object
+!! @param rc return code
+subroutine InitializeP0(gcomp, importState, exportState, clock, rc)
+ type(ESMF_GridComp) :: gcomp !< ESMF_GridComp object
+ type(ESMF_State) :: importState, exportState !< ESMF_State object for
+ !! import/export fields
+ type(ESMF_Clock) :: clock !< ESMF_Clock object
+ integer, intent(out) :: rc !< return code
+
+ ! local variables
+ logical :: isPresent, isSet
+ integer :: iostat
+ character(len=64) :: value, logmsg
+ character(len=*),parameter :: subname='(MOM_cap:InitializeP0)'
+
+ rc = ESMF_SUCCESS
+
+ ! Switch to IPDv03 by filtering all other phaseMap entries
+ call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, &
+ acceptStringList=(/"IPDv03p"/), rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+
+ write_diagnostics = .false.
+ call NUOPC_CompAttributeGet(gcomp, name="DumpFields", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) write_diagnostics=(trim(value)=="true")
+
+ write(logmsg,*) write_diagnostics
+ call ESMF_LogWrite('MOM_cap:DumpFields = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+
+ profile_memory = .false.
+ call NUOPC_CompAttributeGet(gcomp, name="ProfileMemory", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) profile_memory=(trim(value)=="true")
+ write(logmsg,*) profile_memory
+ call ESMF_LogWrite('MOM_cap:ProfileMemory = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+
+ grid_attach_area = .false.
+ call NUOPC_CompAttributeGet(gcomp, name="GridAttachArea", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) grid_attach_area=(trim(value)=="true")
+ write(logmsg,*) grid_attach_area
+ call ESMF_LogWrite('MOM_cap:GridAttachArea = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+
+ scalar_field_name = ""
+ call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldName", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) then
+ scalar_field_name = trim(value)
+ call ESMF_LogWrite('MOM_cap:ScalarFieldName = '//trim(scalar_field_name), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ endif
+
+ scalar_field_count = 0
+ call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldCount", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) then
+ read(value, '(i)', iostat=iostat) scalar_field_count
+ if (iostat /= 0) then
+ call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
+ msg=subname//": ScalarFieldCount not an integer: "//trim(value), &
+ line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return
+ endif
+ write(logmsg,*) scalar_field_count
+ call ESMF_LogWrite('MOM_cap:ScalarFieldCount = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ endif
+
+ scalar_field_idx_grid_nx = 0
+ call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNX", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) then
+ read(value, '(i)', iostat=iostat) scalar_field_idx_grid_nx
+ if (iostat /= 0) then
+ call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
+ msg=subname//": ScalarFieldIdxGridNX not an integer: "//trim(value), &
+ line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return
+ endif
+ write(logmsg,*) scalar_field_idx_grid_nx
+ call ESMF_LogWrite('MOM_cap:ScalarFieldIdxGridNX = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ endif
+
+ scalar_field_idx_grid_ny = 0
+ call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNY", value=value, &
+ isPresent=isPresent, isSet=isSet, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ if (isPresent .and. isSet) then
+ read(value, '(i)', iostat=iostat) scalar_field_idx_grid_ny
+ if (iostat /= 0) then
+ call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
+ msg=subname//": ScalarFieldIdxGridNY not an integer: "//trim(value), &
+ line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return
+ endif
+ write(logmsg,*) scalar_field_idx_grid_ny
+ call ESMF_LogWrite('MOM_cap:ScalarFieldIdxGridNY = '//trim(logmsg), ESMF_LOGMSG_INFO, rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+ endif
+
+ call NUOPC_CompAttributeAdd(gcomp, &
+ attrList=(/'RestartFileToRead', 'RestartFileToWrite'/), rc=rc)
+ if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+ line=__LINE__, &
+ file=__FILE__)) &
+ return
+
+end subroutine
+
+!> Called by NUOPC to advertise import and export fields. "Advertise"
+!! simply means that the standard names of all import and export
+!! fields are supplied. The NUOPC layer uses these to match fields
+!! between components in the coupled system.
!!
!! @param gcomp an ESMF_GridComp object
!! @param importState an ESMF_State object for import fields
@@ -2816,4 +2324,496 @@ subroutine shr_file_getLogUnit(nunit)
end subroutine shr_file_getLogUnit
#endif
+!>
+!! @subpage MOM NUOPC Cap
+!! @author Fei Liu (fei.liu@gmail.com)
+!! @date 5/10/13 Original documentation
+!! @author Rocky Dunlap (rocky.dunlap@noaa.gov)
+!! @date 1/12/17 Moved to doxygen
+!! @date 2/28/19 Rewrote for unified cap
+!!
+!! @tableofcontents
+!!
+!! @section Overview Overview
+!!
+!! **This MOM cap has been tested with MOM6.**
+!!
+!! This document describes the MOM NUOPC "cap", which is a light weight software layer that is
+!! required when the [MOM ocean model](https://github.com/NOAA-GFDL/MOM6/tree/dev/master)
+!! is used in [National Unified Operation Prediction Capability]
+!! (http://www.earthsystemcog.org/projects/nuopc) (NUOPC) coupled systems. Also see the
+!! [MOM wiki](https://github.com/NOAA-GFDL/MOM6-Examples/wiki) for more documentation.
+!!
+!! NUOPC is a software layer built on top of the [Earth System Modeling
+!! Framework] (https://www.earthsystemcog.org/projects/esmf) (ESMF).
+!! ESMF is a high-performance modeling framework that provides
+!! data structures, interfaces, and operations suited for building coupled models
+!! from a set of components. NUOPC refines the capabilities of ESMF by providing
+!! a more precise definition of what it means for a model to be a component and
+!! how components should interact and share data in a coupled system. The NUOPC
+!! Layer software is designed to work with typical high-performance models in the
+!! Earth sciences domain, most of which are written in Fortran and are based on a
+!! distributed memory model of parallelism (MPI).
+!!
+!! A NUOPC "cap" is a Fortran module that serves as the interface to a model
+!! when it's used in a NUOPC-based coupled system.
+!! The term "cap" is used because it is a light weight software layer that sits on top
+!! of model code, making calls into it and exposing model data structures in a
+!! standard way.
+!!
+!! The MOM cap package includes the cap code itself (MOM_cap.F90, MOM_cap_methods.F90
+!! and MOM_cap_time.F90), a set of time utilities (time_utils.F90) for converting between ESMF and FMS
+!! time type and two modules MOM_ocean_model_nuopc.F90 and MOM_surface_forcing_nuopc.F90. MOM_surface_forcing_nuopc.F90
+!! converts the input ESMF data (import data) to a MOM-specific data type (surface_forcing_CS).
+!! MOM_ocean_model_nuopc.F90 contains routines for initialization, update and finalization of the ocean model state.
+!!
+!! @subsection CapSubroutines Cap Subroutines
+!!
+!! The MOM cap modules contains a set of subroutines that are required
+!! by NUOPC. These subroutines are called by the NUOPC infrastructure according
+!! to a predefined calling sequence. Some subroutines are called during
+!! initialization of the coupled system, some during the run of the coupled
+!! system, and some during finalization of the coupled system.
+!!
+!! The initialization sequence is the most complex and is governed by the NUOPC technical rules.
+!! Details about the initialization sequence can be found in the [NUOPC Reference Manual]
+!! (http://www.earthsystemmodeling.org/esmf_releases/last_built/NUOPC_refdoc/).
+!! The cap requires beta snapshot ESMF v8.0.0bs16 or later.
+!!
+!! The following table summarizes the NUOPC-required subroutines that appear in the
+!! MOM cap. The "Phase" column says whether the subroutine is called during the
+!! initialization, run, or finalize part of the coupled system run.
+!!
+!! Phase | MOM Cap Subroutine | Description
+!! ---------|--------------------------------------------------------------------|--------------------------------------
+!! Init | [InitializeP0] (@ref MOM_cap_mod::initializep0) | Sets the Initialize Phase Definition
+!! | (IPD) version to use
+!! Init | [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) | Advertises standard names of import
+!! | and export fields
+!! Init | [InitializeRealize] (@ref MOM_cap_mod::initializerealize) | Creates an ESMF_Grid or ESMF_Mesh
+!! | as well as ESMF_Fields for import
+!! | and export fields
+!! Run | [ModelAdvance] (@ref MOM_cap_mod::modeladvance) | Advances the model by a timestep
+!! Final | [Finalize] (@ref MOM_cap_mod::ocean_model_finalize) | Cleans up
+!!
+!! @section UnderlyingModelInterfaces Underlying Model Interfaces
+!!
+!!
+!! @subsection DomainCreation Domain Creation
+!!
+!! The cap can accomodate a MOM tripolar grid which is represented either as a 2D `ESMF_Grid` or
+!! as a 1D `ESMF_Mesh`. Other MOM grids (e.g. a bipolar grid) can be represented as a 1d `ESMF_Mesh` only.
+!! Coupling fields are placed on either the `ESMF_Grid` or `ESMF_Mesh`.
+!! Note that for either the `ESMF_Grid` or `ESMF_Mesh` representation, the fields are translated into
+!! a 2D MOM specific surface boundary type and the distinction between the two is no longer there.
+!! Calls related to creating the grid are located in the [InitializeRealize]
+!! (@ref MOM_cap_mod::initializerealize) subroutine, which is called by the NUOPC infrastructure
+!! during the intialization sequence.
+!!
+!! The cap determines parameters for setting up the grid by calling subroutines in the
+!! `mpp_domains_mod` module. The global domain size is determined by calling `mpp_get_global_domain()`.
+!! A check is in place to ensure that there is only a single tile in the domain (the
+!! cap is currently limited to one tile; multi-tile mosaics are not supported). The
+!! decomposition across processors is determined via calls to `mpp_get_compute_domains()`
+!! (to retrieve decomposition block indices) and `mpp_get_pelist()` (to determine how
+!! blocks are assigned to processors).
+!!
+!! The `ESMF_Grid` is created in several steps:
+!! - an `ESMF_DELayout` is created based on the pelist from MOM
+!! - an `ESMF_DistGrid` is created over the global index space. Connections are set
+!! up so that the index space is periodic in the first dimension and has a
+!! fold at the top for the bipole. The decompostion blocks are also passed in
+!! along with the `ESMF_DELayout` mentioned above.
+!! - an `ESMF_Grid` is then created by passing in the above `ESMF_DistGrid`.
+!! - masks, areas, center (tlat, tlon), and corner (ulat, ulon) coordinates are then added to the `ESMF_Grid`
+!! by retrieving those fields from the MOM datatype `ocean_grid` elements.
+!!
+!! The `ESMF_Mesh` is also created in several steps:
+!! - the target mesh is generated offline.
+!! - a temporary mesh is created from an input file specified by the config variable `mesh_ocn`.
+!! the mesh has a distribution that is automatically generated by ESMF when reading in the mesh
+!! - an `ESMF_DistGrid` is created from the global index space for the computational domain.
+!! - the final `ESMF_Mesh` is then created by distributing the temporary mesh using the created `ESMF_DistGrid`.
+!!
+!!
+!! @subsection Initialization Initialization
+!!
+!! During the [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) phase, calls are
+!! made to MOM's native initialization subroutines, including `fms_init()`, `constants_init()`,
+!! `field_manager_init()`, `diag_manager_init()`, and `set_calendar_type()`. The MPI communicator
+!! is pulled in through the ESMF VM object for the MOM component. The dt and start time are set
+!! from parameters from the incoming ESMF clock with calls to `set_time()` and `set_date().`
+!!
+!!
+!! @subsection Run Run
+!!
+!! The [ModelAdvance] (@ref MOM_cap_mod::modeladvance) subroutine is called by the NUOPC
+!! infrastructure when it's time for MOM to advance in time. During this subroutine, there is a
+!! call into the MOM update routine:
+!!
+!! call update_ocean_model(Ice_ocean_boundary, Ocean_state, Ocean_public, Time, Time_step_coupled)
+!!
+!! Priori to the call to `update_ocean_model()`, the cap performs these steps
+!! - the `Time` and `Time_step_coupled` parameters, based on FMS types, are derived from the incoming ESMF clock
+!! - diagnostics are optionally written to files `field_ocn_import_*`, one for each import field
+!! - mom_import is called and translates to the ESMF input data to a MOM specific data type
+!! - momentum flux vectors are rotated to internal grid
+!!
+!! After the call to `update_ocean_model()`, the cap performs these steps:
+!! - mom_export is called
+!! - the `ocean_mask` export is set to match that of the internal MOM mask
+!! - the `freezing_melting_potential` export is converted from J m-2 to W m-2 by dividing by the coupling interval
+!! - vector rotations are applied to the `ocean_current_zonal` and `ocean_current_merid` exports, back to lat-lon grid
+!! - diagnostics are optionally written to files `field_ocn_export_*`, one for each export field
+!! - optionally, a call is made to `ocean_model_restart()` at the interval `restart_interval`
+!!
+!! @subsubsection VectorRotations Vector Rotations
+!!
+!! Vector rotations are applied to incoming momentum fluxes (from regular lat-lon to tripolar grid) and
+!! outgoing ocean currents (from tripolar to regular lat-lon). The rotation angles are provided
+!! from the native MOM grid by a call to `get_ocean_grid(Ocean_grid)`.
+!! The cosine and sine of the rotation angle are:
+!!
+!! ocean_grid%cos_rot(i,j)
+!! ocean_grid%sin_rot(i,j)
+!!
+!! The rotation of momentum flux from regular lat-lon to tripolar is:
+!! \f[
+!! \begin{bmatrix}
+!! \tau_x' \\
+!! \tau_y'
+!! \end{bmatrix} =
+!! \begin{bmatrix}
+!! cos \theta & sin \theta \\
+!! -sin \theta & cos \theta
+!! \end{bmatrix} *
+!! \begin{bmatrix}
+!! \tau_x \\
+!! \tau_y
+!! \end{bmatrix}
+!! \f]
+!!
+!! The rotation of ocean current from tripolar to regular lat-lon is:
+!! \f[
+!! \begin{bmatrix}
+!! u' \\
+!! v'
+!! \end{bmatrix} =
+!! \begin{bmatrix}
+!! cos \theta & -sin \theta \\
+!! sin \theta & cos \theta
+!! \end{bmatrix} *
+!! \begin{bmatrix}
+!! u \\
+!! v
+!! \end{bmatrix}
+!! \f]
+!! @subsection Finalization Finalization
+!!
+!! NUOPC infrastructure calls [ocean_model_finalize] (@ref MOM_cap_mod::ocean_model_finalize)
+!! at the end of the run. This subroutine is a hook to call into MOM's native shutdown
+!! procedures:
+!!
+!! call ocean_model_end (ocean_public, ocean_State, Time)
+!! call diag_manager_end(Time )
+!! call field_manager_end
+!! call fms_io_exit
+!! call fms_end
+!!
+!! @section ModelFields Model Fields
+!!
+!! The following tables list the import and export fields currently set up in the MOM cap.
+!!
+!! @subsection ImportFields Import Fields
+!!
+!!
+!!
+!!
+!! Standard Name |
+!! Units |
+!! Model Variable |
+!! Description |
+!! Notes |
+!!
+!!
+!!
+!!
+!! inst_pres_height_surface |
+!! Pa |
+!! p |
+!! pressure of overlying sea ice and atmosphere |
+!!
+!!
+!! mass_of_overlying_sea_ice |
+!! kg |
+!! mi |
+!! mass of overlying sea ice |
+!! |
+!!
+!!
+!! seaice_melt_heat |
+!! W m-2 |
+!! seaice_melt_heat |
+!! sea ice and snow melt heat flux |
+!! |
+!!
+!!
+!! seaice_melt |
+!! kg m-2 s-1 |
+!! seaice_melt |
+!! water flux due to sea ice and snow melting |
+!! |
+!!
+!!
+!! mean_calving_heat_flx |
+!! W m-2 |
+!! calving_hflx |
+!! heat flux, relative to 0C, of frozen land water into ocean |
+!!
+!!
+!! mean_calving_rate |
+!! kg m-2 s-1 |
+!! calving |
+!! mass flux of frozen runoff |
+!! |
+!!
+!!
+!! mean_evap_rate |
+!! kg m-2 s-1 |
+!! q_flux |
+!! specific humidity flux |
+!!
+!!
+!! mean_fprec_rate |
+!! kg m-2 s-1 |
+!! fprec |
+!! mass flux of frozen precip |
+!! |
+!!
+!!
+!! mean_merid_moment_flx |
+!! Pa |
+!! v_flux |
+!! j-directed wind stress into ocean |
+!! [vector rotation] (@ref VectorRotations) applied - lat-lon to tripolar |
+!!
+!!
+!! mean_net_lw_flx |
+!! W m-2 |
+!! lw_flux |
+!! long wave radiation |
+!! |
+!!
+!!
+!! mean_net_sw_ir_dif_flx |
+!! W m-2 |
+!! sw_flux_nir_dif |
+!! diffuse near IR shortwave radiation |
+!! |
+!!
+!!
+!! mean_net_sw_ir_dir_flx |
+!! W m-2 |
+!! sw_flux_nir_dir |
+!! direct near IR shortwave radiation |
+!! |
+!!
+!!
+!! mean_net_sw_vis_dif_flx |
+!! W m-2 |
+!! sw_flux_vis_dif |
+!! diffuse visible shortware radiation |
+!! |
+!!
+!!
+!! mean_net_sw_vis_dir_flx |
+!! W m-2 |
+!! sw_flux_vis_dir |
+!! direct visible shortware radiation |
+!! |
+!!
+!!
+!! mean_prec_rate |
+!! kg m-2 s-1 |
+!! lprec |
+!! mass flux of liquid precip |
+!! |
+!!
+!!
+!! mean_runoff_heat_flx |
+!! W m-2 |
+!! runoff_hflx |
+!! heat flux, relative to 0C, of liquid land water into ocean |
+!!
+!!
+!! mean_runoff_rate |
+!! kg m-2 s-1 |
+!! runoff |
+!! mass flux of liquid runoff |
+!! |
+!!
+!!
+!! mean_salt_rate |
+!! kg m-2 s-1 |
+!! salt_flux |
+!! salt flux |
+!! |
+!!
+!!
+!! mean_sensi_heat_flx |
+!! W m-2 |
+!! t_flux |
+!! sensible heat flux into ocean |
+!!
+!!
+!! mean_zonal_moment_flx |
+!! Pa |
+!! u_flux |
+!! i-directed wind stress into ocean |
+!! [vector rotation] (@ref VectorRotations) applied - lat-lon to tripolar |
+!!
+!!
+!!
+!!
+!! @subsection ExportField Export Fields
+!!
+!! Export fields are populated from the `ocean_public` parameter (type `ocean_public_type`)
+!! after the call to `update_ocean_model()`.
+!!
+!!
+!!
+!!
+!! Standard Name |
+!! Units |
+!! Model Variable |
+!! Description |
+!! Notes |
+!!
+!!
+!!
+!!
+!! freezing_melting_potential |
+!! W m-2 |
+!! combination of frazil and melt_potential |
+!! cap converts model units (J m-2) to (W m-2) for export |
+!!
+!!
+!! ocean_mask |
+!! |
+!! |
+!! ocean mask |
+!! |
+!!
+!!
+!! ocn_current_merid |
+!! m s-1 |
+!! v_surf |
+!! j-directed surface velocity on u-cell |
+!! [vector rotation] (@ref VectorRotations) applied - tripolar to lat-lon |
+!!
+!!
+!! ocn_current_zonal |
+!! m s-1 |
+!! u_surf |
+!! i-directed surface velocity on u-cell |
+!! [vector rotation] (@ref VectorRotations) applied - tripolar to lat-lon |
+!!
+!!
+!! s_surf |
+!! psu |
+!! s_surf |
+!! sea surface salinity on t-cell |
+!! |
+!!
+!!
+!! sea_surface_temperature |
+!! K |
+!! t_surf |
+!! sea surface temperature on t-cell |
+!! |
+!!
+!!
+!! sea_surface_slope_zonal |
+!! unitless |
+!! created from ssh |
+!! sea surface zonal slope |
+!! |
+!!
+!!
+!! sea_surface_slope_merid |
+!! unitless |
+!! created from ssh |
+!! sea surface meridional slope |
+!! |
+!!
+!!
+!! so_bldepth |
+!! m |
+!! obld |
+!! ocean surface boundary layer depth |
+!! |
+!!
+!!
+!!
+!!
+!! @subsection MemoryManagement Memory Management
+!!
+!! The MOM cap has an internal state type with pointers to three
+!! types defined by MOM. There is also a small wrapper derived type
+!! required to associate an internal state instance
+!! with the ESMF/NUOPC component:
+!!
+!! type ocean_internalstate_type
+!! type(ocean_public_type), pointer :: ocean_public_type_ptr
+!! type(ocean_state_type), pointer :: ocean_state_type_ptr
+!! type(ice_ocean_boundary_type), pointer :: ice_ocean_boundary_type_ptr
+!! end type
+!!
+!! type ocean_internalstate_wrapper
+!! type(ocean_internalstate_type), pointer :: ptr
+!! end type
+!!
+!! The member of type `ocean_public_type` stores ocean surface fields used during the coupling.
+!! The member of type `ocean_state_type` is required by the ocean driver,
+!! although its internals are private (not to be used by the coupling directly).
+!! This type is passed to the ocean init and update routines
+!! so that it can maintain state there if desired.
+!! The member of type `ice_ocean_boundary_type` is populated by this cap
+!! with incoming coupling fields from other components. These three derived types are allocated during the
+!! [InitializeAdvertise] (@ref MOM_cap_mod::initializeadvertise) phase. Also during that
+!! phase, the `ice_ocean_boundary` type members are all allocated using bounds retrieved
+!! from `mpp_get_compute_domain()`.
+!!
+!! During the [InitializeRealize] (@ref MOM_cap_mod::initializerealize) phase,
+!! `ESMF_Field`s are created for each of the coupling fields in the `ice_ocean_boundary`
+!! and `ocean_public_type` members of the internal state. These fields directly reference into the members of
+!! the `ice_ocean_boundary` and `ocean_public_type` so that memory-to-memory copies are not required to move
+!! data from the cap's import and export states to the memory areas used internally
+!! by MOM.
+!!
+!! @subsection IO I/O
+!!
+!! The cap can optionally output coupling fields for diagnostic purposes if the ESMF attribute
+!! "DumpFields" has been set to "true". In this case the cap will write out NetCDF files
+!! with names "field_ocn_import_.nc" and "field_ocn_export_.nc".
+!! Additionally, calls will be made to the cap subroutine [dumpMomInternal]
+!! (@ref MOM_cap_mod::dumpmominternal) to write out model internal fields to files
+!! named "field_ocn_internal_.nc". In all cases these NetCDF files will
+!! contain a time series of field data.
+!!
+!! @section RuntimeConfiguration Runtime Configuration
+!!
+!! At runtime, the MOM cap can be configured with several options provided
+!! as ESMF attributes. Attributes can be set in the cap by the NUOPC Driver
+!! above this cap, or in some systems ESMF attributes are set by
+!! reading in from a configuration file. The available attributes are:
+!!
+!! * `DumpFields` - when set to "true", write out diagnostic NetCDF files for import/export/internal fields
+!! * `ProfileMemory` - when set to "true", write out memory usage information to the ESMF log files; this
+!! information is written when entering and leaving the [ModelAdvance]
+!! (@ref MOM_cap_mod::modeladvance) subroutine and before and after the call to
+!! `update_ocean_model()`.
+!! * `restart_interval` - integer number of seconds indicating the interval at
+!! which to call `ocean_model_restart()`; no restarts written if set to 0
+
end module MOM_cap_mod