MOM6
MOM_ALE.F90
1 !> This module contains the main regridding routines.
2 !!
3 !! Regridding comprises two steps:
4 !! 1. Interpolation and creation of a new grid based on target interface
5 !! densities (or any other criterion).
6 !! 2. Remapping of quantities between old grid and new grid.
7 !!
8 !! Original module written by Laurent White, 2008.06.09
9 module mom_ale
10 
11 ! This file is part of MOM6. See LICENSE.md for the license.
12 
13 use mom_debugging, only : check_column_integrals
14 use mom_diag_mediator, only : register_diag_field, post_data, diag_ctrl
15 use mom_diag_mediator, only : time_type, diag_update_remap_grids
16 use mom_diag_vkernels, only : interpolate_column, reintegrate_column
17 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
18 use mom_eos, only : calculate_density
19 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
20 use mom_error_handler, only : mom_error, fatal, warning
21 use mom_error_handler, only : calltree_showquery
22 use mom_error_handler, only : calltree_enter, calltree_leave, calltree_waypoint
24 use mom_io, only : vardesc, var_desc, fieldtype, single_file
25 use mom_io, only : create_file, write_field, close_file
27 use mom_regridding, only : initialize_regridding, regridding_main, end_regridding
28 use mom_regridding, only : uniformresolution
29 use mom_regridding, only : inflate_vanished_layers_old
30 use mom_regridding, only : set_target_densities_from_gv, set_target_densities
31 use mom_regridding, only : regriddingcoordinatemodedoc, default_coordinate_mode
32 use mom_regridding, only : regriddinginterpschemedoc, regriddingdefaultinterpscheme
33 use mom_regridding, only : regriddingdefaultboundaryextrapolation
34 use mom_regridding, only : regriddingdefaultminthickness
35 use mom_regridding, only : regridding_cs, set_regrid_params
36 use mom_regridding, only : getcoordinateinterfaces, getcoordinateresolution
37 use mom_regridding, only : getcoordinateunits, getcoordinateshortname
38 use mom_regridding, only : getstaticthickness
39 use mom_remapping, only : initialize_remapping, end_remapping
40 use mom_remapping, only : remapping_core_h, remapping_core_w
41 use mom_remapping, only : remappingschemesdoc, remappingdefaultscheme
42 use mom_remapping, only : remapping_cs, dzfromh1h2
43 use mom_string_functions, only : uppercase, extractword, extract_integer
44 use mom_tracer_registry, only : tracer_registry_type, tracer_type, mom_tracer_chkinv
46 use mom_variables, only : ocean_grid_type, thermo_var_ptrs
47 use mom_verticalgrid, only : get_thickness_units, verticalgrid_type
48 
49 !use regrid_consts, only : coordinateMode, DEFAULT_COORDINATE_MODE
50 use regrid_consts, only : coordinateunits, coordinatemode, state_dependent
51 use regrid_edge_values, only : edge_values_implicit_h4
52 use plm_functions, only : plm_reconstruction, plm_boundary_extrapolation
53 use ppm_functions, only : ppm_reconstruction, ppm_boundary_extrapolation
54 use p1m_functions, only : p1m_interpolation, p1m_boundary_extrapolation
55 use p3m_functions, only : p3m_interpolation, p3m_boundary_extrapolation
56 
57 
58 implicit none ; private
59 #include <MOM_memory.h>
60 
61 
62 !> ALE control structure
63 type, public :: ale_cs ; private
64  logical :: remap_uv_using_old_alg !< If true, uses the old "remapping via a delta z"
65  !! method. If False, uses the new method that
66  !! remaps between grids described by h.
67 
68  real :: regrid_time_scale !< The time-scale used in blending between the current (old) grid
69  !! and the target (new) grid. (s)
70 
71  type(regridding_cs) :: regridcs !< Regridding parameters and work arrays
72  type(remapping_cs) :: remapcs !< Remapping parameters and work arrays
73 
74  integer :: nk !< Used only for queries, not directly by this module
75 
76  logical :: remap_after_initialization !< Indicates whether to regrid/remap after initializing the state.
77 
78  logical :: show_call_tree !< For debugging
79 
80  ! for diagnostics
81  type(diag_ctrl), pointer :: diag !< structure to regulate output
82  integer, dimension(:), allocatable :: id_tracer_remap_tendency !< diagnostic id
83  integer, dimension(:), allocatable :: id_htracer_remap_tendency !< diagnostic id
84  integer, dimension(:), allocatable :: id_htracer_remap_tendency_2d !< diagnostic id
85  logical, dimension(:), allocatable :: do_tendency_diag !< flag for doing diagnostics
86  integer :: id_dzregrid = -1 !< diagnostic id
87 
88  ! diagnostic for fields prior to applying ALE remapping
89  integer :: id_u_preale = -1 !< diagnostic id for zonal velocity before ALE.
90  integer :: id_v_preale = -1 !< diagnostic id for meridional velocity before ALE.
91  integer :: id_h_preale = -1 !< diagnostic id for layer thicknesses before ALE.
92  integer :: id_t_preale = -1 !< diagnostic id for temperatures before ALE.
93  integer :: id_s_preale = -1 !< diagnostic id for salinities before ALE.
94  integer :: id_e_preale = -1 !< diagnostic id for interface heights before ALE.
95  integer :: id_vert_remap_h = -1 !< diagnostic id for layer thicknesses used for remapping
96  integer :: id_vert_remap_h_tendency = -1 !< diagnostic id for layer thickness tendency due to ALE
97 
98 end type
99 
100 ! Publicly available functions
101 public ale_init
102 public ale_end
103 public ale_main
104 public ale_main_offline
105 public ale_offline_inputs
106 public ale_offline_tracer_final
107 public ale_build_grid
108 public ale_regrid_accelerated
109 public ale_remap_scalar
110 public pressure_gradient_plm
111 public pressure_gradient_ppm
112 public adjustgridforintegrity
113 public ale_initregridding
114 public ale_getcoordinate
115 public ale_getcoordinateunits
116 public ale_writecoordinatefile
117 public ale_updateverticalgridtype
118 public ale_initthicknesstocoord
119 public ale_update_regrid_weights
120 public ale_remap_init_conds
121 public ale_register_diags
122 
123 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
124 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
125 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
126 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
127 
128 contains
129 
130 !> This routine is typically called (from initialize_MOM in file MOM.F90)
131 !! before the main time integration loop to initialize the regridding stuff.
132 !! We read the MOM_input file to register the values of different
133 !! regridding/remapping parameters.
134 subroutine ale_init( param_file, GV, US, max_depth, CS)
135  type(param_file_type), intent(in) :: param_file !< Parameter file
136  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
137  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
138  real, intent(in) :: max_depth !< The maximum depth of the ocean [Z ~> m].
139  type(ale_cs), pointer :: cs !< Module control structure
140 
141  ! Local variables
142  real, dimension(:), allocatable :: dz
143  character(len=40) :: mdl = "MOM_ALE" ! This module's name.
144  character(len=80) :: string ! Temporary strings
145  real :: filter_shallow_depth, filter_deep_depth
146  logical :: check_reconstruction
147  logical :: check_remapping
148  logical :: force_bounds_in_subcell
149  logical :: local_logical
150  logical :: remap_boundary_extrap
151 
152  if (associated(cs)) then
153  call mom_error(warning, "ALE_init called with an associated "// &
154  "control structure.")
155  return
156  endif
157  allocate(cs)
158 
159  cs%show_call_tree = calltree_showquery()
160  if (cs%show_call_tree) call calltree_enter("ALE_init(), MOM_ALE.F90")
161 
162  call get_param(param_file, mdl, "REMAP_UV_USING_OLD_ALG", &
163  cs%remap_uv_using_old_alg, &
164  "If true, uses the old remapping-via-a-delta-z method for "//&
165  "remapping u and v. If false, uses the new method that remaps "//&
166  "between grids described by an old and new thickness.", &
167  default=.true.)
168 
169  ! Initialize and configure regridding
170  call ale_initregridding(gv, us, max_depth, param_file, mdl, cs%regridCS)
171 
172  ! Initialize and configure remapping
173  call get_param(param_file, mdl, "REMAPPING_SCHEME", string, &
174  "This sets the reconstruction scheme used "//&
175  "for vertical remapping for all variables. "//&
176  "It can be one of the following schemes: "//&
177  trim(remappingschemesdoc), default=remappingdefaultscheme)
178  call get_param(param_file, mdl, "FATAL_CHECK_RECONSTRUCTIONS", check_reconstruction, &
179  "If true, cell-by-cell reconstructions are checked for "//&
180  "consistency and if non-monotonicity or an inconsistency is "//&
181  "detected then a FATAL error is issued.", default=.false.)
182  call get_param(param_file, mdl, "FATAL_CHECK_REMAPPING", check_remapping, &
183  "If true, the results of remapping are checked for "//&
184  "conservation and new extrema and if an inconsistency is "//&
185  "detected then a FATAL error is issued.", default=.false.)
186  call get_param(param_file, mdl, "REMAP_BOUND_INTERMEDIATE_VALUES", force_bounds_in_subcell, &
187  "If true, the values on the intermediate grid used for remapping "//&
188  "are forced to be bounded, which might not be the case due to "//&
189  "round off.", default=.false.)
190  call get_param(param_file, mdl, "REMAP_BOUNDARY_EXTRAP", remap_boundary_extrap, &
191  "If true, values at the interfaces of boundary cells are "//&
192  "extrapolated instead of piecewise constant", default=.false.)
193  call initialize_remapping( cs%remapCS, string, &
194  boundary_extrapolation=remap_boundary_extrap, &
195  check_reconstruction=check_reconstruction, &
196  check_remapping=check_remapping, &
197  force_bounds_in_subcell=force_bounds_in_subcell)
198 
199  call get_param(param_file, mdl, "REMAP_AFTER_INITIALIZATION", cs%remap_after_initialization, &
200  "If true, applies regridding and remapping immediately after "//&
201  "initialization so that the state is ALE consistent. This is a "//&
202  "legacy step and should not be needed if the initialization is "//&
203  "consistent with the coordinate mode.", default=.true.)
204 
205  call get_param(param_file, mdl, "REGRID_TIME_SCALE", cs%regrid_time_scale, &
206  "The time-scale used in blending between the current (old) grid "//&
207  "and the target (new) grid. A short time-scale favors the target "//&
208  "grid (0. or anything less than DT_THERM) has no memory of the old "//&
209  "grid. A very long time-scale makes the model more Lagrangian.", &
210  units="s", default=0.)
211  call get_param(param_file, mdl, "REGRID_FILTER_SHALLOW_DEPTH", filter_shallow_depth, &
212  "The depth above which no time-filtering is applied. Above this depth "//&
213  "final grid exactly matches the target (new) grid.", &
214  units="m", default=0., scale=gv%m_to_H)
215  call get_param(param_file, mdl, "REGRID_FILTER_DEEP_DEPTH", filter_deep_depth, &
216  "The depth below which full time-filtering is applied with time-scale "//&
217  "REGRID_TIME_SCALE. Between depths REGRID_FILTER_SHALLOW_DEPTH and "//&
218  "REGRID_FILTER_SHALLOW_DEPTH the filter weights adopt a cubic profile.", &
219  units="m", default=0., scale=gv%m_to_H)
220  call set_regrid_params(cs%regridCS, depth_of_time_filter_shallow=filter_shallow_depth, &
221  depth_of_time_filter_deep=filter_deep_depth)
222  call get_param(param_file, mdl, "REGRID_USE_OLD_DIRECTION", local_logical, &
223  "If true, the regridding ntegrates upwards from the bottom for "//&
224  "interface positions, much as the main model does. If false "//&
225  "regridding integrates downward, consistant with the remapping "//&
226  "code.", default=.true., do_not_log=.true.)
227  call set_regrid_params(cs%regridCS, integrate_downward_for_e=.not.local_logical)
228 
229  ! Keep a record of values for subsequent queries
230  cs%nk = gv%ke
231 
232  if (cs%show_call_tree) call calltree_leave("ALE_init()")
233 end subroutine ale_init
234 
235 !> Initialize diagnostics for the ALE module.
236 subroutine ale_register_diags(Time, G, GV, US, diag, CS)
237  type(time_type),target, intent(in) :: time !< Time structure
238  type(ocean_grid_type), intent(in) :: g !< Grid structure
239  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
240  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
241  type(diag_ctrl), target, intent(in) :: diag !< Diagnostics control structure
242  type(ale_cs), pointer :: cs !< Module control structure
243 
244  cs%diag => diag
245 
246  ! These diagnostics of the state variables before ALE are useful for
247  ! debugging the ALE code.
248  cs%id_u_preale = register_diag_field('ocean_model', 'u_preale', diag%axesCuL, time, &
249  'Zonal velocity before remapping', 'm s-1')
250  cs%id_v_preale = register_diag_field('ocean_model', 'v_preale', diag%axesCvL, time, &
251  'Meridional velocity before remapping', 'm s-1')
252  cs%id_h_preale = register_diag_field('ocean_model', 'h_preale', diag%axesTL, time, &
253  'Layer Thickness before remapping', get_thickness_units(gv), v_extensive=.true.)
254  cs%id_T_preale = register_diag_field('ocean_model', 'T_preale', diag%axesTL, time, &
255  'Temperature before remapping', 'degC')
256  cs%id_S_preale = register_diag_field('ocean_model', 'S_preale', diag%axesTL, time, &
257  'Salinity before remapping', 'PSU')
258  cs%id_e_preale = register_diag_field('ocean_model', 'e_preale', diag%axesTi, time, &
259  'Interface Heights before remapping', 'm', conversion=us%Z_to_m)
260 
261  cs%id_dzRegrid = register_diag_field('ocean_model','dzRegrid',diag%axesTi,time, &
262  'Change in interface height due to ALE regridding', 'm')
263  cs%id_vert_remap_h = register_diag_field('ocean_model','vert_remap_h',diag%axestl,time, &
264  'layer thicknesses after ALE regridding and remapping', 'm', v_extensive = .true.)
265  cs%id_vert_remap_h_tendency = register_diag_field('ocean_model','vert_remap_h_tendency',diag%axestl,time, &
266  'Layer thicknesses tendency due to ALE regridding and remapping', 'm', v_extensive = .true.)
267 
268 end subroutine ale_register_diags
269 
270 !> Crudely adjust (initial) grid for integrity.
271 !! This routine is typically called (from initialize_MOM in file MOM.F90)
272 !! before the main time integration loop to initialize the regridding stuff.
273 !! We read the MOM_input file to register the values of different
274 !! regridding/remapping parameters.
275 subroutine adjustgridforintegrity( CS, G, GV, h )
276  type(ale_cs), pointer :: cs !< Regridding parameters and options
277  type(ocean_grid_type), intent(in) :: g !< Ocean grid informations
278  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
279  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Current 3D grid thickness that
280  !! are to be adjusted [H ~> m or kg-2]
281  call inflate_vanished_layers_old( cs%regridCS, g, gv, h(:,:,:) )
282 
283 end subroutine adjustgridforintegrity
284 
285 
286 !> End of regridding (memory deallocation).
287 !! This routine is typically called (from MOM_end in file MOM.F90)
288 !! after the main time integration loop to deallocate the regridding stuff.
289 subroutine ale_end(CS)
290  type(ale_cs), pointer :: cs !< module control structure
291 
292  ! Deallocate memory used for the regridding
293  call end_remapping( cs%remapCS )
294  call end_regridding( cs%regridCS )
295 
296  deallocate(cs)
297 
298 end subroutine ale_end
299 
300 !> Takes care of (1) building a new grid and (2) remapping all variables between
301 !! the old grid and the new grid. The creation of the new grid can be based
302 !! on z coordinates, target interface densities, sigma coordinates or any
303 !! arbitrary coordinate system.
304 subroutine ale_main( G, GV, US, h, u, v, tv, Reg, CS, dt, frac_shelf_h)
305  type(ocean_grid_type), intent(in) :: g !< Ocean grid informations
306  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
307  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
308  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Current 3D grid obtained after the
309  !! last time step [H ~> m or kg m-2]
310  real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: u !< Zonal velocity field [m s-1]
311  real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: v !< Meridional velocity field [m s-1]
312  type(thermo_var_ptrs), intent(inout) :: tv !< Thermodynamic variable structure
313  type(tracer_registry_type), pointer :: reg !< Tracer registry structure
314  type(ale_cs), pointer :: cs !< Regridding parameters and options
315  real, optional, intent(in) :: dt !< Time step between calls to ALE_main()
316  real, dimension(:,:), optional, pointer :: frac_shelf_h !< Fractional ice shelf coverage
317  ! Local variables
318  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: dzregrid ! The change in grid interface positions
319  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: eta_preale
320  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_new ! New 3D grid obtained after last time step [H ~> m or kg-2]
321  integer :: nk, i, j, k, isc, iec, jsc, jec
322  logical :: ice_shelf
323 
324  nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
325 
326  ice_shelf = .false.
327  if (present(frac_shelf_h)) then
328  if (associated(frac_shelf_h)) ice_shelf = .true.
329  endif
330 
331  if (cs%show_call_tree) call calltree_enter("ALE_main(), MOM_ALE.F90")
332 
333  ! These diagnostics of the state before ALE is applied are mostly used for debugging.
334  if (cs%id_u_preale > 0) call post_data(cs%id_u_preale, u, cs%diag)
335  if (cs%id_v_preale > 0) call post_data(cs%id_v_preale, v, cs%diag)
336  if (cs%id_h_preale > 0) call post_data(cs%id_h_preale, h, cs%diag)
337  if (cs%id_T_preale > 0) call post_data(cs%id_T_preale, tv%T, cs%diag)
338  if (cs%id_S_preale > 0) call post_data(cs%id_S_preale, tv%S, cs%diag)
339  if (cs%id_e_preale > 0) then
340  call find_eta(h, tv, g, gv, us, eta_preale)
341  call post_data(cs%id_e_preale, eta_preale, cs%diag)
342  endif
343 
344  if (present(dt)) then
345  call ale_update_regrid_weights( dt, cs )
346  endif
347  dzregrid(:,:,:) = 0.0
348 
349  ! Build new grid. The new grid is stored in h_new. The old grid is h.
350  ! Both are needed for the subsequent remapping of variables.
351  if (ice_shelf) then
352  call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid, frac_shelf_h)
353  else
354  call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid)
355  endif
356 
357  call check_grid( g, gv, h, 0. )
358 
359  if (cs%show_call_tree) call calltree_waypoint("new grid generated (ALE_main)")
360 
361  ! The presence of dt is used for expediency to distinguish whether ALE_main is being called during init
362  ! or in the main loop. Tendency diagnostics in remap_all_state_vars also rely on this logic.
363  if (present(dt)) then
364  call diag_update_remap_grids(cs%diag)
365  endif
366  ! Remap all variables from old grid h onto new grid h_new
367  call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, -dzregrid, &
368  u, v, cs%show_call_tree, dt )
369 
370  if (cs%show_call_tree) call calltree_waypoint("state remapped (ALE_main)")
371 
372  ! Override old grid with new one. The new grid 'h_new' is built in
373  ! one of the 'build_...' routines above.
374  !$OMP parallel do default(shared)
375  do k = 1,nk ; do j = jsc-1,jec+1 ; do i = isc-1,iec+1
376  h(i,j,k) = h_new(i,j,k)
377  enddo ; enddo ; enddo
378 
379  if (cs%show_call_tree) call calltree_leave("ALE_main()")
380 
381  if (cs%id_dzRegrid>0 .and. present(dt)) call post_data(cs%id_dzRegrid, dzregrid, cs%diag)
382 
383 
384 end subroutine ale_main
385 
386 !> Takes care of (1) building a new grid and (2) remapping all variables between
387 !! the old grid and the new grid. The creation of the new grid can be based
388 !! on z coordinates, target interface densities, sigma coordinates or any
389 !! arbitrary coordinate system.
390 subroutine ale_main_offline( G, GV, h, tv, Reg, CS, dt)
391  type(ocean_grid_type), intent(in) :: g !< Ocean grid informations
392  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
393  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Current 3D grid obtained after the
394  !! last time step [H ~> m or kg-2]
395  type(thermo_var_ptrs), intent(inout) :: tv !< Thermodynamic variable structure
396  type(tracer_registry_type), pointer :: reg !< Tracer registry structure
397  type(ale_cs), pointer :: cs !< Regridding parameters and options
398  real, optional, intent(in) :: dt !< Time step between calls to ALE_main()
399  ! Local variables
400  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid ! The change in grid interface positions
401  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_new ! New 3D grid obtained after last time step [H ~> m or kg-2]
402  integer :: nk, i, j, k, isc, iec, jsc, jec
403 
404  nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
405 
406  if (cs%show_call_tree) call calltree_enter("ALE_main_offline(), MOM_ALE.F90")
407 
408  if (present(dt)) then
409  call ale_update_regrid_weights( dt, cs )
410  endif
411  dzregrid(:,:,:) = 0.0
412 
413  ! Build new grid. The new grid is stored in h_new. The old grid is h.
414  ! Both are needed for the subsequent remapping of variables.
415  call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid )
416 
417  call check_grid( g, gv, h, 0. )
418 
419  if (cs%show_call_tree) call calltree_waypoint("new grid generated (ALE_main)")
420 
421  ! Remap all variables from old grid h onto new grid h_new
422 
423  call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, debug=cs%show_call_tree, dt=dt )
424 
425  if (cs%show_call_tree) call calltree_waypoint("state remapped (ALE_main)")
426 
427  ! Override old grid with new one. The new grid 'h_new' is built in
428  ! one of the 'build_...' routines above.
429  !$OMP parallel do default(shared)
430  do k = 1,nk ; do j = jsc-1,jec+1 ; do i = isc-1,iec+1
431  h(i,j,k) = h_new(i,j,k)
432  enddo ; enddo ; enddo
433 
434  if (cs%show_call_tree) call calltree_leave("ALE_main()")
435  if (cs%id_dzRegrid>0 .and. present(dt)) call post_data(cs%id_dzRegrid, dzregrid, cs%diag)
436 
437 end subroutine ale_main_offline
438 
439 !> Regrid/remap stored fields used for offline tracer integrations. These input fields are assumed to have
440 !! the same layer thicknesses at the end of the last offline interval (which should be a Zstar grid). This
441 !! routine builds a grid on the runtime specified vertical coordinate
442 subroutine ale_offline_inputs(CS, G, GV, h, tv, Reg, uhtr, vhtr, Kd, debug)
443  type(ale_cs), pointer :: cs !< Regridding parameters and options
444  type(ocean_grid_type), intent(in ) :: g !< Ocean grid informations
445  type(verticalgrid_type), intent(in ) :: gv !< Ocean vertical grid structure
446  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Layer thicknesses
447  type(thermo_var_ptrs), intent(inout) :: tv !< Thermodynamic variable structure
448  type(tracer_registry_type), pointer :: reg !< Tracer registry structure
449  real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: uhtr !< Zonal mass fluxes
450  real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: vhtr !< Meridional mass fluxes
451  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(inout) :: kd !< Input diffusivites
452  logical, intent(in ) :: debug !< If true, then turn checksums
453  ! Local variables
454  integer :: nk, i, j, k, isc, iec, jsc, jec
455  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new ! Layer thicknesses after regridding
456  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid ! The change in grid interface positions
457  real, dimension(SZK_(GV)) :: h_src
458  real, dimension(SZK_(GV)) :: h_dest, uh_dest
459  real, dimension(SZK_(GV)) :: temp_vec
460 
461  nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
462  dzregrid(:,:,:) = 0.0
463  h_new(:,:,:) = 0.0
464 
465  if (debug) call mom_tracer_chkinv("Before ALE_offline_inputs", g, h, reg%Tr, reg%ntr)
466 
467  ! Build new grid from the Zstar state onto the requested vertical coordinate. The new grid is stored
468  ! in h_new. The old grid is h. Both are needed for the subsequent remapping of variables. Convective
469  ! adjustment right now is not used because it is unclear what to do with vanished layers
470  call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid, conv_adjust = .false. )
471  call check_grid( g, gv, h_new, 0. )
472  if (cs%show_call_tree) call calltree_waypoint("new grid generated (ALE_offline_inputs)")
473 
474  ! Remap all variables from old grid h onto new grid h_new
475  call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, debug=cs%show_call_tree )
476  if (cs%show_call_tree) call calltree_waypoint("state remapped (ALE_inputs)")
477 
478  ! Reintegrate mass transports from Zstar to the offline vertical coordinate
479  do j=jsc,jec ; do i=g%iscB,g%iecB
480  if (g%mask2dCu(i,j)>0.) then
481  h_src(:) = 0.5 * (h(i,j,:) + h(i+1,j,:))
482  h_dest(:) = 0.5 * (h_new(i,j,:) + h_new(i+1,j,:))
483  call reintegrate_column(nk, h_src, uhtr(i,j,:), nk, h_dest, 0., temp_vec)
484  uhtr(i,j,:) = temp_vec
485  endif
486  enddo ; enddo
487  do j=g%jscB,g%jecB ; do i=isc,iec
488  if (g%mask2dCv(i,j)>0.) then
489  h_src(:) = 0.5 * (h(i,j,:) + h(i,j+1,:))
490  h_dest(:) = 0.5 * (h_new(i,j,:) + h_new(i,j+1,:))
491  call reintegrate_column(nk, h_src, vhtr(i,j,:), nk, h_dest, 0., temp_vec)
492  vhtr(i,j,:) = temp_vec
493  endif
494  enddo ; enddo
495 
496  do j = jsc,jec ; do i=isc,iec
497  if (g%mask2dT(i,j)>0.) then
498  if (check_column_integrals(nk, h_src, nk, h_dest)) then
499  call mom_error(fatal, "ALE_offline_inputs: Kd interpolation columns do not match")
500  endif
501  call interpolate_column(nk, h(i,j,:), kd(i,j,:), nk, h_new(i,j,:), 0., kd(i,j,:))
502  endif
503  enddo ; enddo
504 
505  call ale_remap_scalar(cs%remapCS, g, gv, nk, h, tv%T, h_new, tv%T)
506  call ale_remap_scalar(cs%remapCS, g, gv, nk, h, tv%S, h_new, tv%S)
507 
508  if (debug) call mom_tracer_chkinv("After ALE_offline_inputs", g, h_new, reg%Tr, reg%ntr)
509 
510  ! Copy over the new layer thicknesses
511  do k = 1,nk ; do j = jsc-1,jec+1 ; do i = isc-1,iec+1
512  h(i,j,k) = h_new(i,j,k)
513  enddo ; enddo ; enddo
514 
515  if (cs%show_call_tree) call calltree_leave("ALE_offline_inputs()")
516 end subroutine ale_offline_inputs
517 
518 
519 !> Remaps all tracers from h onto h_target. This is intended to be called when tracers
520 !! are done offline. In the case where transports don't quite conserve, we still want to
521 !! make sure that layer thicknesses offline do not drift too far away from the online model
522 subroutine ale_offline_tracer_final( G, GV, h, tv, h_target, Reg, CS)
523  type(ocean_grid_type), intent(in) :: g !< Ocean grid informations
524  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
525  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Current 3D grid obtained after the
526  !! last time step [H ~> m or kg-2]
527  type(thermo_var_ptrs), intent(inout) :: tv !< Thermodynamic variable structure
528  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h_target !< Current 3D grid obtained after
529  !! last time step [H ~> m or kg-2]
530  type(tracer_registry_type), pointer :: reg !< Tracer registry structure
531  type(ale_cs), pointer :: cs !< Regridding parameters and options
532  ! Local variables
533 
534  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid !< The change in grid interface positions
535  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new !< Regridded target thicknesses
536  integer :: nk, i, j, k, isc, iec, jsc, jec
537 
538  nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
539 
540  if (cs%show_call_tree) call calltree_enter("ALE_offline_tracer_final(), MOM_ALE.F90")
541  ! Need to make sure that h_target is consistent with the current offline ALE confiuration
542  call regridding_main( cs%remapCS, cs%regridCS, g, gv, h_target, tv, h_new, dzregrid )
543  call check_grid( g, gv, h_target, 0. )
544 
545 
546  if (cs%show_call_tree) call calltree_waypoint("Source and target grids checked (ALE_offline_tracer_final)")
547 
548  ! Remap all variables from old grid h onto new grid h_new
549 
550  call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, debug=cs%show_call_tree )
551 
552  if (cs%show_call_tree) call calltree_waypoint("state remapped (ALE_offline_tracer_final)")
553 
554  ! Override old grid with new one. The new grid 'h_new' is built in
555  ! one of the 'build_...' routines above.
556  !$OMP parallel do default(shared)
557  do k = 1,nk
558  do j = jsc-1,jec+1 ; do i = isc-1,iec+1
559  h(i,j,k) = h_new(i,j,k)
560  enddo ; enddo
561  enddo
562  if (cs%show_call_tree) call calltree_leave("ALE_offline_tracer_final()")
563 end subroutine ale_offline_tracer_final
564 
565 !> Check grid for negative thicknesses
566 subroutine check_grid( G, GV, h, threshold )
567  type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
568  type(verticalgrid_type), intent(in) :: GV !< Ocean vertical grid structure
569  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Current 3D grid obtained after the
570  !! last time step [H ~> m or kg m-2]
571  real, intent(in) :: threshold !< Value below which to flag issues,
572  !! [H ~> m or kg m-2]
573  ! Local variables
574  integer :: i, j
575 
576  do j = g%jsc,g%jec ; do i = g%isc,g%iec
577  if (g%mask2dT(i,j)>0.) then
578  if (minval(h(i,j,:)) < threshold) then
579  write(0,*) 'check_grid: i,j=',i,j,'h(i,j,:)=',h(i,j,:)
580  if (threshold <= 0.) then
581  call mom_error(fatal,"MOM_ALE, check_grid: negative thickness encountered.")
582  else
583  call mom_error(fatal,"MOM_ALE, check_grid: too tiny thickness encountered.")
584  endif
585  endif
586  endif
587  enddo ; enddo
588 
589 
590 end subroutine check_grid
591 
592 !> Generates new grid
593 subroutine ale_build_grid( G, GV, regridCS, remapCS, h, tv, debug, frac_shelf_h )
594  type(ocean_grid_type), intent(in) :: g !< Ocean grid structure
595  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
596  type(regridding_cs), intent(in) :: regridcs !< Regridding parameters and options
597  type(remapping_cs), intent(in) :: remapcs !< Remapping parameters and options
598  type(thermo_var_ptrs), intent(inout) :: tv !< Thermodynamical variable structure
599  real, dimension(SZI_(G),SZJ_(G), SZK_(GV)), intent(inout) :: h !< Current 3D grid obtained after the
600  !! last time step [H ~> m or kg-2]
601  logical, optional, intent(in) :: debug !< If true, show the call tree
602  real, dimension(:,:), optional, pointer :: frac_shelf_h !< Fractional ice shelf coverage
603  ! Local variables
604  integer :: nk, i, j, k
605  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid ! The change in grid interface positions
606  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new ! The new grid thicknesses
607  logical :: show_call_tree, use_ice_shelf
608 
609  show_call_tree = .false.
610  if (present(debug)) show_call_tree = debug
611  if (show_call_tree) call calltree_enter("ALE_build_grid(), MOM_ALE.F90")
612  use_ice_shelf = .false.
613  if (present(frac_shelf_h)) then
614  if (associated(frac_shelf_h)) use_ice_shelf = .true.
615  endif
616 
617  ! Build new grid. The new grid is stored in h_new. The old grid is h.
618  ! Both are needed for the subsequent remapping of variables.
619  if (use_ice_shelf) then
620  call regridding_main( remapcs, regridcs, g, gv, h, tv, h_new, dzregrid, frac_shelf_h )
621  else
622  call regridding_main( remapcs, regridcs, g, gv, h, tv, h_new, dzregrid )
623  endif
624 
625  ! Override old grid with new one. The new grid 'h_new' is built in
626  ! one of the 'build_...' routines above.
627 !$OMP parallel do default(none) shared(G,h,h_new)
628  do j = g%jsc,g%jec ; do i = g%isc,g%iec
629  if (g%mask2dT(i,j)>0.) h(i,j,:) = h_new(i,j,:)
630  enddo ; enddo
631 
632  if (show_call_tree) call calltree_leave("ALE_build_grid()")
633 end subroutine ale_build_grid
634 
635 !> For a state-based coordinate, accelerate the process of regridding by
636 !! repeatedly applying the grid calculation algorithm
637 subroutine ale_regrid_accelerated(CS, G, GV, h, tv, n, u, v, Reg, dt, dzRegrid, initial)
638  type(ale_cs), pointer :: cs !< ALE control structure
639  type(ocean_grid_type), intent(inout) :: g !< Ocean grid
640  type(verticalgrid_type), intent(in) :: gv !< Vertical grid
641  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
642  intent(inout) :: h !< Original thicknesses
643  type(thermo_var_ptrs), intent(inout) :: tv !< Thermo vars (T/S/EOS)
644  integer, intent(in) :: n !< Number of times to regrid
645  real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
646  intent(inout) :: u !< Zonal velocity
647  real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
648  intent(inout) :: v !< Meridional velocity
649  type(tracer_registry_type), &
650  optional, pointer :: reg !< Tracer registry to remap onto new grid
651  real, optional, intent(in) :: dt !< Model timestep to provide a timescale for regridding
652  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
653  optional, intent(inout) :: dzregrid !< Final change in interface positions
654  logical, optional, intent(in) :: initial !< Whether we're being called from an initialization
655  !! routine (and expect diagnostics to work)
656 
657  ! Local variables
658  integer :: i, j, k, nz
659  type(thermo_var_ptrs) :: tv_local ! local/intermediate temp/salt
660  type(group_pass_type) :: pass_t_s_h ! group pass if the coordinate has a stencil
661  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_loc, h_orig ! A working copy of layer thicknesses
662  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), target :: t, s ! local temporary state
663  ! we have to keep track of the total dzInterface if for some reason
664  ! we're using the old remapping algorithm for u/v
665  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: dzinterface, dzinttotal
666 
667  nz = gv%ke
668 
669  ! initial total interface displacement due to successive regridding
670  dzinttotal(:,:,:) = 0.
671 
672  call create_group_pass(pass_t_s_h, t, g%domain)
673  call create_group_pass(pass_t_s_h, s, g%domain)
674  call create_group_pass(pass_t_s_h, h_loc, g%domain)
675 
676  ! copy original temp/salt and set our local tv_pointers to them
677  tv_local = tv
678  t(:,:,:) = tv%T(:,:,:)
679  s(:,:,:) = tv%S(:,:,:)
680  tv_local%T => t
681  tv_local%S => s
682 
683  ! get local copy of thickness and save original state for remapping
684  h_loc(:,:,:) = h(:,:,:)
685  h_orig(:,:,:) = h(:,:,:)
686 
687  ! Apply timescale to regridding (for e.g. filtered_grid_motion)
688  if (present(dt)) &
689  call ale_update_regrid_weights(dt, cs)
690 
691  do k = 1, n
692  call do_group_pass(pass_t_s_h, g%domain)
693 
694  ! generate new grid
695  call regridding_main(cs%remapCS, cs%regridCS, g, gv, h_loc, tv_local, h, dzinterface)
696  dzinttotal(:,:,:) = dzinttotal(:,:,:) + dzinterface(:,:,:)
697 
698  ! remap from original grid onto new grid
699  do j = g%jsc-1,g%jec+1 ; do i = g%isc-1,g%iec+1
700  call remapping_core_h(cs%remapCS, nz, h_orig(i,j,:), tv%S(i,j,:), nz, h(i,j,:), tv_local%S(i,j,:))
701  call remapping_core_h(cs%remapCS, nz, h_orig(i,j,:), tv%T(i,j,:), nz, h(i,j,:), tv_local%T(i,j,:))
702  enddo ; enddo
703 
704  ! starting grid for next iteration
705  h_loc(:,:,:) = h(:,:,:)
706  enddo
707 
708  ! remap all state variables (including those that weren't needed for regridding)
709  call remap_all_state_vars(cs%remapCS, cs, g, gv, h_orig, h, reg, dzinttotal, u, v, dt=dt)
710 
711  ! save total dzregrid for diags if needed?
712  if (present(dzregrid)) dzregrid(:,:,:) = dzinttotal(:,:,:)
713 end subroutine ale_regrid_accelerated
714 
715 !> This routine takes care of remapping all variable between the old and the
716 !! new grids. When velocity components need to be remapped, thicknesses at
717 !! velocity points are taken to be arithmetic averages of tracer thicknesses.
718 !! This routine is called during initialization of the model at time=0, to
719 !! remap initiali conditions to the model grid. It is also called during a
720 !! time step to update the state.
721 subroutine remap_all_state_vars(CS_remapping, CS_ALE, G, GV, h_old, h_new, Reg, dxInterface, u, v, debug, dt)
722  type(remapping_cs), intent(in) :: CS_remapping !< Remapping control structure
723  type(ale_cs), intent(in) :: CS_ALE !< ALE control structure
724  type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
725  type(verticalgrid_type), intent(in) :: GV !< Ocean vertical grid structure
726  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h_old !< Thickness of source grid
727  !! [H ~> m or kg-2]
728  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h_new !< Thickness of destination grid
729  !! [H ~> m or kg-2]
730  type(tracer_registry_type), pointer :: Reg !< Tracer registry structure
731  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
732  optional, intent(in) :: dxInterface !< Change in interface position
733  !! [H ~> m or kg-2]
734  real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
735  optional, intent(inout) :: u !< Zonal velocity component [m s-1]
736  real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
737  optional, intent(inout) :: v !< Meridional velocity component [m s-1]
738  logical, optional, intent(in) :: debug !< If true, show the call tree
739  real, optional, intent(in) :: dt !< time step for diagnostics
740  ! Local variables
741  integer :: i, j, k, m
742  integer :: nz, ntr
743  real, dimension(GV%ke+1) :: dx
744  real, dimension(GV%ke) :: h1, u_column
745  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: work_conc
746  real, dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: work_cont
747  real, dimension(SZI_(G), SZJ_(G)) :: work_2d
748  real :: Idt, ppt2mks
749  real, dimension(GV%ke) :: h2
750  real :: h_neglect, h_neglect_edge
751  logical :: show_call_tree
752  type(tracer_type), pointer :: Tr => null()
753 
754  show_call_tree = .false.
755  if (present(debug)) show_call_tree = debug
756  if (show_call_tree) call calltree_enter("remap_all_state_vars(), MOM_ALE.F90")
757 
758  ! If remap_uv_using_old_alg is .true. and u or v is requested, then we must have dxInterface. Otherwise,
759  ! u and v can be remapped without dxInterface
760  if ( .not. present(dxinterface) .and. (cs_ale%remap_uv_using_old_alg .and. (present(u) .or. present(v))) ) then
761  call mom_error(fatal, "remap_all_state_vars: dxInterface must be present if using old algorithm "// &
762  "and u/v are to be remapped")
763  endif
764 
765  !### Try replacing both of these with GV%H_subroundoff
766  if (gv%Boussinesq) then
767  h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
768  else
769  h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
770  endif
771 
772  nz = gv%ke
773  ppt2mks = 0.001
774 
775  ntr = 0 ; if (associated(reg)) ntr = reg%ntr
776 
777  if (present(dt)) then
778  idt = 1.0/dt
779  work_conc(:,:,:) = 0.0
780  work_cont(:,:,:) = 0.0
781  endif
782 
783  ! Remap tracer
784  if (ntr>0) then
785  if (show_call_tree) call calltree_waypoint("remapping tracers (remap_all_state_vars)")
786  !$OMP parallel do default(shared) private(h1,h2,u_column,Tr)
787  do m=1,ntr ! For each tracer
788  tr => reg%Tr(m)
789  do j = g%jsc,g%jec ; do i = g%isc,g%iec ; if (g%mask2dT(i,j)>0.) then
790  ! Build the start and final grids
791  h1(:) = h_old(i,j,:)
792  h2(:) = h_new(i,j,:)
793  call remapping_core_h(cs_remapping, nz, h1, tr%t(i,j,:), nz, h2, &
794  u_column, h_neglect, h_neglect_edge)
795 
796  ! Intermediate steps for tendency of tracer concentration and tracer content.
797  if (present(dt)) then
798  if (tr%id_remap_conc>0) then
799  do k=1,gv%ke
800  work_conc(i,j,k) = (u_column(k) - tr%t(i,j,k) ) * idt
801  enddo
802  endif
803  if (tr%id_remap_cont>0. .or. tr%id_remap_cont_2d>0) then
804  do k=1,gv%ke
805  work_cont(i,j,k) = (u_column(k)*h2(k) - tr%t(i,j,k)*h1(k)) * idt
806  enddo
807  endif
808  endif
809  ! update tracer concentration
810  tr%t(i,j,:) = u_column(:)
811  endif ; enddo ; enddo
812 
813  ! tendency diagnostics.
814  if (present(dt)) then
815  if (tr%id_remap_conc > 0) then
816  call post_data(tr%id_remap_conc, work_conc, cs_ale%diag)
817  endif
818  if (tr%id_remap_cont > 0) then
819  call post_data(tr%id_remap_cont, work_cont, cs_ale%diag)
820  endif
821  if (tr%id_remap_cont_2d > 0) then
822  do j = g%jsc,g%jec ; do i = g%isc,g%iec
823  work_2d(i,j) = 0.0
824  do k = 1,gv%ke
825  work_2d(i,j) = work_2d(i,j) + work_cont(i,j,k)
826  enddo
827  enddo ; enddo
828  call post_data(tr%id_remap_cont_2d, work_2d, cs_ale%diag)
829  endif
830  endif
831  enddo ! m=1,ntr
832 
833  endif ! endif for ntr > 0
834 
835  if (show_call_tree) call calltree_waypoint("tracers remapped (remap_all_state_vars)")
836 
837  ! Remap u velocity component
838  if ( present(u) ) then
839  !$OMP parallel do default(shared) private(h1,h2,dx,u_column)
840  do j = g%jsc,g%jec ; do i = g%iscB,g%iecB ; if (g%mask2dCu(i,j)>0.) then
841  ! Build the start and final grids
842  h1(:) = 0.5 * ( h_old(i,j,:) + h_old(i+1,j,:) )
843  if (cs_ale%remap_uv_using_old_alg) then
844  dx(:) = 0.5 * ( dxinterface(i,j,:) + dxinterface(i+1,j,:) )
845  do k = 1, nz
846  h2(k) = max( 0., h1(k) + ( dx(k+1) - dx(k) ) )
847  enddo
848  else
849  h2(:) = 0.5 * ( h_new(i,j,:) + h_new(i+1,j,:) )
850  endif
851  call remapping_core_h(cs_remapping, nz, h1, u(i,j,:), nz, h2, &
852  u_column, h_neglect, h_neglect_edge)
853  u(i,j,:) = u_column(:)
854  endif ; enddo ; enddo
855  endif
856 
857  if (show_call_tree) call calltree_waypoint("u remapped (remap_all_state_vars)")
858 
859  ! Remap v velocity component
860  if ( present(v) ) then
861  !$OMP parallel do default(shared) private(h1,h2,dx,u_column)
862  do j = g%jscB,g%jecB ; do i = g%isc,g%iec ; if (g%mask2dCv(i,j)>0.) then
863  ! Build the start and final grids
864  h1(:) = 0.5 * ( h_old(i,j,:) + h_old(i,j+1,:) )
865  if (cs_ale%remap_uv_using_old_alg) then
866  dx(:) = 0.5 * ( dxinterface(i,j,:) + dxinterface(i,j+1,:) )
867  do k = 1, nz
868  h2(k) = max( 0., h1(k) + ( dx(k+1) - dx(k) ) )
869  enddo
870  else
871  h2(:) = 0.5 * ( h_new(i,j,:) + h_new(i,j+1,:) )
872  endif
873  call remapping_core_h(cs_remapping, nz, h1, v(i,j,:), nz, h2, &
874  u_column, h_neglect, h_neglect_edge)
875  v(i,j,:) = u_column(:)
876  endif ; enddo ; enddo
877  endif
878 
879  if (cs_ale%id_vert_remap_h > 0) call post_data(cs_ale%id_vert_remap_h, h_old, cs_ale%diag)
880  if ((cs_ale%id_vert_remap_h_tendency > 0) .and. present(dt)) then
881  do k = 1, nz ; do j = g%jsc,g%jec ; do i = g%isc,g%iec
882  work_cont(i,j,k) = (h_new(i,j,k) - h_old(i,j,k))*idt
883  enddo ; enddo ; enddo
884  call post_data(cs_ale%id_vert_remap_h_tendency, work_cont, cs_ale%diag)
885  endif
886  if (show_call_tree) call calltree_waypoint("v remapped (remap_all_state_vars)")
887  if (show_call_tree) call calltree_leave("remap_all_state_vars()")
888 
889 end subroutine remap_all_state_vars
890 
891 
892 !> Remaps a single scalar between grids described by thicknesses h_src and h_dst.
893 !! h_dst must be dimensioned as a model array with GV%ke layers while h_src can
894 !! have an arbitrary number of layers specified by nk_src.
895 subroutine ale_remap_scalar(CS, G, GV, nk_src, h_src, s_src, h_dst, s_dst, all_cells, old_remap )
896  type(remapping_cs), intent(in) :: cs !< Remapping control structure
897  type(ocean_grid_type), intent(in) :: g !< Ocean grid structure
898  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
899  integer, intent(in) :: nk_src !< Number of levels on source grid
900  real, dimension(SZI_(G),SZJ_(G),nk_src), intent(in) :: h_src !< Level thickness of source grid
901  !! [H ~> m or kg-2]
902  real, dimension(SZI_(G),SZJ_(G),nk_src), intent(in) :: s_src !< Scalar on source grid
903  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)),intent(in) :: h_dst !< Level thickness of destination grid
904  !! [H ~> m or kg-2]
905  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)),intent(inout) :: s_dst !< Scalar on destination grid
906  logical, optional, intent(in) :: all_cells !< If false, only reconstruct for
907  !! non-vanished cells. Use all vanished
908  !! layers otherwise (default).
909  logical, optional, intent(in) :: old_remap !< If true, use the old "remapping_core_w"
910  !! method, otherwise use "remapping_core_h".
911  ! Local variables
912  integer :: i, j, k, n_points
913  real :: dx(gv%ke+1)
914  real :: h_neglect, h_neglect_edge
915  logical :: ignore_vanished_layers, use_remapping_core_w
916 
917  ignore_vanished_layers = .false.
918  if (present(all_cells)) ignore_vanished_layers = .not. all_cells
919  use_remapping_core_w = .false.
920  if (present(old_remap)) use_remapping_core_w = old_remap
921  n_points = nk_src
922 
923  !### Try replacing both of these with GV%H_subroundoff
924  if (gv%Boussinesq) then
925  h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
926  else
927  h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
928  endif
929 
930  !$OMP parallel do default(shared) firstprivate(n_points,dx)
931  do j = g%jsc,g%jec ; do i = g%isc,g%iec
932  if (g%mask2dT(i,j) > 0.) then
933  if (ignore_vanished_layers) then
934  n_points = 0
935  do k = 1, nk_src
936  if (h_src(i,j,k)>0.) n_points = n_points + 1
937  enddo
938  s_dst(i,j,:) = 0.
939  endif
940  if (use_remapping_core_w) then
941  call dzfromh1h2( n_points, h_src(i,j,1:n_points), gv%ke, h_dst(i,j,:), dx )
942  call remapping_core_w(cs, n_points, h_src(i,j,1:n_points), s_src(i,j,1:n_points), &
943  gv%ke, dx, s_dst(i,j,:), h_neglect, h_neglect_edge)
944  else
945  call remapping_core_h(cs, n_points, h_src(i,j,1:n_points), s_src(i,j,1:n_points), &
946  gv%ke, h_dst(i,j,:), s_dst(i,j,:), h_neglect, h_neglect_edge)
947  endif
948  else
949  s_dst(i,j,:) = 0.
950  endif
951  enddo ; enddo
952 
953 end subroutine ale_remap_scalar
954 
955 
956 !> Use plm reconstruction for pressure gradient (determine edge values)
957 !! By using a PLM (limited piecewise linear method) reconstruction, this
958 !! routine determines the edge values for the salinity and temperature
959 !! within each layer. These edge values are returned and are used to compute
960 !! the pressure gradient (by computing the densities).
961 subroutine pressure_gradient_plm( CS, S_t, S_b, T_t, T_b, G, GV, tv, h, bdry_extrap )
962  type(ocean_grid_type), intent(in) :: g !< ocean grid structure
963  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
964  type(ale_cs), intent(inout) :: cs !< module control structure
965  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
966  intent(inout) :: s_t !< Salinity at the top edge of each layer
967  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
968  intent(inout) :: s_b !< Salinity at the bottom edge of each layer
969  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
970  intent(inout) :: t_t !< Temperature at the top edge of each layer
971  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
972  intent(inout) :: t_b !< Temperature at the bottom edge of each layer
973  type(thermo_var_ptrs), intent(in) :: tv !< thermodynamics structure
974  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
975  intent(in) :: h !< layer thickness [H ~> m or kg m-2]
976  logical, intent(in) :: bdry_extrap !< If true, use high-order boundary
977  !! extrapolation within boundary cells
978 
979  ! Local variables
980  integer :: i, j, k
981  real :: htmp(gv%ke)
982  real :: tmp(gv%ke)
983  real, dimension(CS%nk,2) :: ppol_e !Edge value of polynomial
984  real, dimension(CS%nk,2) :: ppol_coefs !Coefficients of polynomial
985  real :: h_neglect
986 
987  !### Replace this with GV%H_subroundoff
988  if (gv%Boussinesq) then
989  h_neglect = gv%m_to_H*1.0e-30
990  else
991  h_neglect = gv%kg_m2_to_H*1.0e-30
992  endif
993 
994  ! Determine reconstruction within each column
995  !$OMP parallel do default(shared) private(hTmp,ppol_E,ppol_coefs,tmp)
996  do j = g%jsc-1,g%jec+1 ; do i = g%isc-1,g%iec+1
997  ! Build current grid
998  htmp(:) = h(i,j,:)
999  tmp(:) = tv%S(i,j,:)
1000  ! Reconstruct salinity profile
1001  ppol_e(:,:) = 0.0
1002  ppol_coefs(:,:) = 0.0
1003  call plm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1004  if (bdry_extrap) &
1005  call plm_boundary_extrapolation( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1006 
1007  do k = 1,gv%ke
1008  s_t(i,j,k) = ppol_e(k,1)
1009  s_b(i,j,k) = ppol_e(k,2)
1010  enddo
1011 
1012  ! Reconstruct temperature profile
1013  ppol_e(:,:) = 0.0
1014  ppol_coefs(:,:) = 0.0
1015  tmp(:) = tv%T(i,j,:)
1016  call plm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1017  if (bdry_extrap) &
1018  call plm_boundary_extrapolation( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1019 
1020  do k = 1,gv%ke
1021  t_t(i,j,k) = ppol_e(k,1)
1022  t_b(i,j,k) = ppol_e(k,2)
1023  enddo
1024 
1025  enddo ; enddo
1026 
1027 end subroutine pressure_gradient_plm
1028 
1029 
1030 !> Use ppm reconstruction for pressure gradient (determine edge values)
1031 !> By using a PPM (limited piecewise linear method) reconstruction, this
1032 !> routine determines the edge values for the salinity and temperature
1033 !> within each layer. These edge values are returned and are used to compute
1034 !> the pressure gradient (by computing the densities).
1035 subroutine pressure_gradient_ppm( CS, S_t, S_b, T_t, T_b, G, GV, tv, h, bdry_extrap )
1036  type(ocean_grid_type), intent(in) :: g !< ocean grid structure
1037  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
1038  type(ale_cs), intent(inout) :: cs !< module control structure
1039  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1040  intent(inout) :: s_t !< Salinity at the top edge of each layer
1041  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1042  intent(inout) :: s_b !< Salinity at the bottom edge of each layer
1043  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1044  intent(inout) :: t_t !< Temperature at the top edge of each layer
1045  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1046  intent(inout) :: t_b !< Temperature at the bottom edge of each layer
1047  type(thermo_var_ptrs), intent(in) :: tv !< thermodynamics structure
1048  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1049  intent(in) :: h !< layer thicknesses [H ~> m or kg m-2]
1050  logical, intent(in) :: bdry_extrap !< If true, use high-order boundary
1051  !! extrapolation within boundary cells
1052 
1053  ! Local variables
1054  integer :: i, j, k
1055  real :: htmp(gv%ke)
1056  real :: tmp(gv%ke)
1057  real, dimension(CS%nk,2) :: &
1058  ppol_e !Edge value of polynomial
1059  real, dimension(CS%nk,3) :: &
1060  ppol_coefs !Coefficients of polynomial
1061  real :: h_neglect, h_neglect_edge
1062 
1063  !### Try replacing both of these with GV%H_subroundoff
1064  if (gv%Boussinesq) then
1065  h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
1066  else
1067  h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
1068  endif
1069 
1070  ! Determine reconstruction within each column
1071  !$OMP parallel do default(shared) private(hTmp,tmp,ppol_E,ppol_coefs)
1072  do j = g%jsc-1,g%jec+1 ; do i = g%isc-1,g%iec+1
1073 
1074  ! Build current grid
1075  htmp(:) = h(i,j,:)
1076  tmp(:) = tv%S(i,j,:)
1077 
1078  ! Reconstruct salinity profile
1079  ppol_e(:,:) = 0.0
1080  ppol_coefs(:,:) = 0.0
1081  !### Try to replace the following value of h_neglect with GV%H_subroundoff.
1082  call edge_values_implicit_h4( gv%ke, htmp, tmp, ppol_e, h_neglect=h_neglect_edge )
1083  call ppm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1084  if (bdry_extrap) &
1085  call ppm_boundary_extrapolation( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1086 
1087  do k = 1,gv%ke
1088  s_t(i,j,k) = ppol_e(k,1)
1089  s_b(i,j,k) = ppol_e(k,2)
1090  enddo
1091 
1092  ! Reconstruct temperature profile
1093  ppol_e(:,:) = 0.0
1094  ppol_coefs(:,:) = 0.0
1095  tmp(:) = tv%T(i,j,:)
1096  !### Try to replace the following value of h_neglect with GV%H_subroundoff.
1097  call edge_values_implicit_h4( gv%ke, htmp, tmp, ppol_e, h_neglect=1.0e-10*gv%m_to_H )
1098  call ppm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1099  if (bdry_extrap) &
1100  call ppm_boundary_extrapolation(gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1101 
1102  do k = 1,gv%ke
1103  t_t(i,j,k) = ppol_e(k,1)
1104  t_b(i,j,k) = ppol_e(k,2)
1105  enddo
1106 
1107  enddo ; enddo
1108 
1109 end subroutine pressure_gradient_ppm
1110 
1111 
1112 !> Initializes regridding for the main ALE algorithm
1113 subroutine ale_initregridding(GV, US, max_depth, param_file, mdl, regridCS)
1114  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
1115  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
1116  real, intent(in) :: max_depth !< The maximum depth of the ocean [Z ~> m].
1117  type(param_file_type), intent(in) :: param_file !< parameter file
1118  character(len=*), intent(in) :: mdl !< Name of calling module
1119  type(regridding_cs), intent(out) :: regridcs !< Regridding parameters and work arrays
1120  ! Local variables
1121  character(len=30) :: coord_mode
1122 
1123  call get_param(param_file, mdl, "REGRIDDING_COORDINATE_MODE", coord_mode, &
1124  "Coordinate mode for vertical regridding. "//&
1125  "Choose among the following possibilities: "//&
1126  trim(regriddingcoordinatemodedoc), &
1127  default=default_coordinate_mode, fail_if_missing=.true.)
1128 
1129  call initialize_regridding(regridcs, gv, us, max_depth, param_file, mdl, coord_mode, '', '')
1130 
1131 end subroutine ale_initregridding
1132 
1133 !> Query the target coordinate interfaces positions
1134 function ale_getcoordinate( CS )
1135  type(ale_cs), pointer :: cs !< module control structure
1136 
1137  real, dimension(CS%nk+1) :: ale_getcoordinate
1138  ale_getcoordinate(:) = getcoordinateinterfaces( cs%regridCS, undo_scaling=.true. )
1139 
1140 end function ale_getcoordinate
1141 
1142 
1143 !> Query the target coordinate units
1144 function ale_getcoordinateunits( CS )
1145  type(ale_cs), pointer :: cs !< module control structure
1146 
1147  character(len=20) :: ale_getcoordinateunits
1148 
1149  ale_getcoordinateunits = getcoordinateunits( cs%regridCS )
1150 
1151 end function ale_getcoordinateunits
1152 
1153 
1154 !> Returns true if initial conditions should be regridded and remapped
1155 logical function ale_remap_init_conds( CS )
1156  type(ale_cs), pointer :: cs !< module control structure
1157 
1158  ale_remap_init_conds = .false.
1159  if (associated(cs)) ale_remap_init_conds = cs%remap_after_initialization
1160 end function ale_remap_init_conds
1161 
1162 !> Updates the weights for time filtering the new grid generated in regridding
1163 subroutine ale_update_regrid_weights( dt, CS )
1164  real, intent(in) :: dt !< Time-step used between ALE calls
1165  type(ale_cs), pointer :: cs !< ALE control structure
1166  ! Local variables
1167  real :: w ! An implicit weighting estimate.
1168 
1169  if (associated(cs)) then
1170  w = 0.0
1171  if (cs%regrid_time_scale > 0.0) then
1172  w = cs%regrid_time_scale / (cs%regrid_time_scale + dt)
1173  endif
1174  call set_regrid_params(cs%regridCS, old_grid_weight=w)
1175  endif
1176 
1177 end subroutine ale_update_regrid_weights
1178 
1179 !> Update the vertical grid type with ALE information.
1180 !! This subroutine sets information in the verticalGrid_type to be
1181 !! consistent with the use of ALE mode.
1182 subroutine ale_updateverticalgridtype(CS, GV)
1183  type(ale_cs), pointer :: cs !< ALE control structure
1184  type(verticalgrid_type), pointer :: gv !< vertical grid information
1185 
1186  integer :: nk
1187 
1188  nk = gv%ke
1189  gv%sInterface(1:nk+1) = getcoordinateinterfaces( cs%regridCS, undo_scaling=.true. )
1190  gv%sLayer(1:nk) = 0.5*( gv%sInterface(1:nk) + gv%sInterface(2:nk+1) )
1191  gv%zAxisUnits = getcoordinateunits( cs%regridCS )
1192  gv%zAxisLongName = getcoordinateshortname( cs%regridCS )
1193  gv%direction = -1 ! Because of ferret in z* mode. Need method to set
1194  ! as function of coordinae mode.
1195 
1196 end subroutine ale_updateverticalgridtype
1197 
1198 
1199 !> Write the vertical coordinate information into a file.
1200 !! This subroutine writes out a file containing any available data related
1201 !! to the vertical grid used by the MOM ocean model when in ALE mode.
1202 subroutine ale_writecoordinatefile( CS, GV, directory )
1203  type(ale_cs), pointer :: cs !< module control structure
1204  type(verticalgrid_type), intent(in) :: gv !< ocean vertical grid structure
1205  character(len=*), intent(in) :: directory !< directory for writing grid info
1206 
1207  character(len=240) :: filepath
1208  type(vardesc) :: vars(2)
1209  type(fieldtype) :: fields(2)
1210  integer :: unit
1211  real :: ds(gv%ke), dsi(gv%ke+1)
1212 
1213  filepath = trim(directory) // trim("Vertical_coordinate")
1214  ds(:) = getcoordinateresolution( cs%regridCS, undo_scaling=.true. )
1215  dsi(1) = 0.5*ds(1)
1216  dsi(2:gv%ke) = 0.5*( ds(1:gv%ke-1) + ds(2:gv%ke) )
1217  dsi(gv%ke+1) = 0.5*ds(gv%ke)
1218 
1219  vars(1) = var_desc('ds', getcoordinateunits( cs%regridCS ), &
1220  'Layer Coordinate Thickness','1','L','1')
1221  vars(2) = var_desc('ds_interface', getcoordinateunits( cs%regridCS ), &
1222  'Layer Center Coordinate Separation','1','i','1')
1223 
1224  call create_file(unit, trim(filepath), vars, 2, fields, single_file, gv=gv)
1225  call write_field(unit, fields(1), ds)
1226  call write_field(unit, fields(2), dsi)
1227  call close_file(unit)
1228 
1229 end subroutine ale_writecoordinatefile
1230 
1231 
1232 !> Set h to coordinate values for fixed coordinate systems
1233 subroutine ale_initthicknesstocoord( CS, G, GV, h )
1234  type(ale_cs), intent(inout) :: cs !< module control structure
1235  type(ocean_grid_type), intent(in) :: g !< module grid structure
1236  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
1237  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(out) :: h !< layer thickness [H ~> m or kg m-2]
1238 
1239  ! Local variables
1240  integer :: i, j, k
1241 
1242  do j = g%jsd,g%jed ; do i = g%isd,g%ied
1243  h(i,j,:) = gv%Z_to_H * getstaticthickness( cs%regridCS, 0., g%bathyT(i,j) )
1244  enddo ; enddo
1245 
1246 end subroutine ale_initthicknesstocoord
1247 
1248 end module mom_ale
ppm_functions
Provides functions used with the Piecewise-Parabolic-Method in the vertical ALE algorithm.
Definition: PPM_functions.F90:2
mom_diag_vkernels
Provides kernels for single-column interpolation, re-integration (re-mapping of integrated quantities...
Definition: MOM_diag_vkernels.F90:3
mom_regridding::regridding_cs
Regridding control structure.
Definition: MOM_regridding.F90:45
mom_verticalgrid
Provides a transparent vertical ocean grid type and supporting routines.
Definition: MOM_verticalGrid.F90:2
regrid_consts::state_dependent
Returns true if the coordinate is dependent on the state density, returns false otherwise.
Definition: regrid_consts.F90:44
mom_tracer_registry::tracer_type
The tracer type.
Definition: MOM_tracer_registry.F90:37
mom_diag_mediator
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Definition: MOM_diag_mediator.F90:3
mom_variables::thermo_var_ptrs
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Definition: MOM_variables.F90:82
p3m_functions
Cubic interpolation functions.
Definition: P3M_functions.F90:2
mom_string_functions
Handy functions for manipulating strings.
Definition: MOM_string_functions.F90:2
regrid_consts::coordinateunits
Returns a string with the coordinate units associated with the coordinate mode.
Definition: regrid_consts.F90:38
mom_eos
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
mom_remapping::remapping_cs
Container for remapping parameters.
Definition: MOM_remapping.F90:22
mom_tracer_registry
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
Definition: MOM_tracer_registry.F90:5
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
regrid_edge_values
Edge value estimation for high-order resconstruction.
Definition: regrid_edge_values.F90:2
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
p1m_functions
Linear interpolation functions.
Definition: P1M_functions.F90:2
regrid_consts
Contains constants for interpreting input parameters that control regridding.
Definition: regrid_consts.F90:2
mom_remapping
Provides column-wise vertical remapping functions.
Definition: MOM_remapping.F90:2
mom_diag_mediator::post_data
Make a diagnostic available for averaging or output.
Definition: MOM_diag_mediator.F90:70
mom_verticalgrid::verticalgrid_type
Describes the vertical ocean grid, including unit conversion factors.
Definition: MOM_verticalGrid.F90:24
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_ale
This module contains the main regridding routines.
Definition: MOM_ALE.F90:9
mom_variables
Provides transparent structures with groups of MOM6 variables and supporting routines.
Definition: MOM_variables.F90:2
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_ale::ale_cs
ALE control structure.
Definition: MOM_ALE.F90:63
mom_tracer_registry::tracer_registry_type
Type to carry basic tracer information.
Definition: MOM_tracer_registry.F90:122
mom_interface_heights::find_eta
Calculates the heights of sruface or all interfaces from layer thicknesses.
Definition: MOM_interface_heights.F90:21
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
mom_debugging
Provides checksumming functions for debugging.
Definition: MOM_debugging.F90:7
mom_io::vardesc
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:53
mom_regridding
Generates vertical grids as part of the ALE algorithm.
Definition: MOM_regridding.F90:2
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_domains::create_group_pass
Set up a group of halo updates.
Definition: MOM_domains.F90:79
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_interface_heights
Functions for calculating interface heights, including free surface height.
Definition: MOM_interface_heights.F90:2
plm_functions
Piecewise linear reconstruction functions.
Definition: PLM_functions.F90:2
mom_diag_mediator::diag_ctrl
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Definition: MOM_diag_mediator.F90:239
mom_eos::calculate_density
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:60