← back to index

src/ALE/MOM_regridding.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Generates vertical grids as part of the ALE algorithm
6module MOM_regridding
7
8use MOM_error_handler, only : MOM_error, FATAL, WARNING, NOTE, assert
9use MOM_file_parser, only : param_file_type, get_param, log_param
10use MOM_io, only : file_exists, field_exists, field_size, MOM_read_data
11use MOM_io, only : read_variable
12use MOM_io, only : vardesc, var_desc, SINGLE_FILE
13use MOM_io, only : MOM_netCDF_file, MOM_field
14use MOM_io, only : create_MOM_file, MOM_write_field
15use MOM_io, only : verify_variable_units, slasher
16use MOM_unit_scaling, only : unit_scale_type
17use MOM_variables, only : ocean_grid_type, thermo_var_ptrs
18use MOM_verticalGrid, only : verticalGrid_type
19use MOM_EOS, only : EOS_type, calculate_density
20use MOM_domains, only : max_across_PEs, pass_var
21use MOM_string_functions, only : uppercase, extractWord, extract_integer, extract_real
22
23use MOM_remapping, only : remapping_CS
24use regrid_consts, only : state_dependent, coordinateUnits
25use regrid_consts, only : coordinateMode, DEFAULT_COORDINATE_MODE
26use regrid_consts, only : REGRIDDING_LAYER, REGRIDDING_ZSTAR
27use regrid_consts, only : REGRIDDING_RHO, REGRIDDING_SIGMA
28use regrid_consts, only : REGRIDDING_ARBITRARY, REGRIDDING_SIGMA_SHELF_ZSTAR
29use regrid_consts, only : REGRIDDING_HYCOM1, REGRIDDING_HYBGEN, REGRIDDING_ADAPTIVE
30use regrid_interp, only : interp_CS_type
31use regrid_interp, only : set_interp_scheme, set_interp_extrap, set_interp_answer_date
32
33use coord_zlike, only : zlike_CS
34use coord_zlike, only : init_coord_zlike, set_zlike_params, build_zstar_column, end_coord_zlike
35use coord_sigma, only : sigma_CS
36use coord_sigma, only : init_coord_sigma, set_sigma_params, build_sigma_column, end_coord_sigma
37use coord_rho, only : init_coord_rho, rho_CS, set_rho_params, build_rho_column, end_coord_rho
38use coord_rho, only : old_inflate_layers_1d
39use coord_hycom, only : hycom_CS
40use coord_hycom, only : init_coord_hycom, set_hycom_params, build_hycom1_column, end_coord_hycom
41use coord_hycom, only : init_3d_coord_hycom
42use coord_adapt, only : adapt_CS
43use coord_adapt, only : init_coord_adapt, set_adapt_params, build_adapt_column, end_coord_adapt
44use MOM_hybgen_regrid, only : hybgen_regrid, hybgen_regrid_CS, init_hybgen_regrid, end_hybgen_regrid
45use MOM_hybgen_regrid, only : write_Hybgen_coord_file
46
47implicit none ; private
48
49#include <MOM_memory.h>
50
51! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
52! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
53! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
54! vary with the Boussinesq approximation, the Boussinesq variant is given first.
55
56!> Regridding control structure
57type, public :: regridding_CS ; private
58
59 !> This array is set by function setCoordinateResolution()
60 !! It contains the "resolution" or delta coordinate of the target
61 !! coordinate. It has the units of the target coordinate, e.g.
62 !! [Z ~> m] for z*, [nondim] for sigma, etc.
63 real, dimension(:), allocatable :: coordinateResolution
64
65 !> This is a scaling factor that restores coordinateResolution to values in
66 !! the natural units for output, perhaps [nondim]
67 real :: coord_scale = 1.0
68
69 !> This array is set by function set_target_densities()
70 !! This array is the nominal coordinate of interfaces and is the
71 !! running sum of coordinateResolution, in [R ~> kg m-3]. i.e.
72 !! target_density(k+1) = coordinateResolution(k) + coordinateResolution(k)
73 !! It is only used in "rho" or "Hycom" mode.
74 real, dimension(:), allocatable :: target_density
75
76 !> A flag to indicate that the target_density arrays has been filled with data.
77 logical :: target_density_set = .false.
78
79 !> Nominal HYCOM1 3D near-surface resolution [Z ~> m]
80 real, allocatable, dimension(:,:,:) :: coordinateResolution_3d
81
82 !> Nominal HYCOM1 3D density of interfaces [R ~> kg m-3]
83 real, allocatable, dimension(:,:,:) :: target_density_3d
84
85 !> This array is set by function set_regrid_max_depths()
86 !! It specifies the maximum depth that every interface is allowed to take [H ~> m or kg m-2].
87 real, dimension(:), allocatable :: max_interface_depths
88
89 !> This array is set by function set_regrid_max_thickness()
90 !! It specifies the maximum depth that every interface is allowed to take [H ~> m or kg m-2].
91 real, dimension(:), allocatable :: max_layer_thickness
92
93 integer :: nk !< Number of layers/levels in generated grid
94
95 !> Indicates which grid to use in the vertical (z*, sigma, target interface
96 !! densities)
97 integer :: regridding_scheme
98
99 !> Interpolation control structure
100 type(interp_CS_type) :: interp_CS
101
102 !> Minimum thickness allowed when building the new grid through regridding [H ~> m or kg m-2].
103 real :: min_thickness
104
105 !> If true, call adjust_interface_motion() after initial grid generation
106 logical :: use_adjust_interface_motion
107
108 !> Reference pressure for potential density calculations [R L2 T-2 ~> Pa]
109 real :: ref_pressure = 2.e7
110
111 !> If true, always pass through the depth-based time filtering that uses CS%old_grid_weight
112 !! If false, allows bypassing of the call if CS%old_grid_weight==0
113 logical :: use_depth_based_time_filter
114
115 !> Weight given to old coordinate when blending between new and old grids [nondim]
116 !! Used only below depth_of_time_filter_shallow, with a cubic variation
117 !! from zero to full effect between depth_of_time_filter_shallow and
118 !! depth_of_time_filter_deep.
119 real :: old_grid_weight = 0.
120
121 !> Depth above which no time-filtering of grid is applied [H ~> m or kg m-2]
122 real :: depth_of_time_filter_shallow = 0.
123
124 !> Depth below which time-filtering of grid is applied at full effect [H ~> m or kg m-2]
125 real :: depth_of_time_filter_deep = 0.
126
127 !> Fraction (between 0 and 1) of compressibility to add to potential density
128 !! profiles when interpolating for target grid positions [nondim]
129 real :: compressibility_fraction = 0.
130
131 !> If true, each interface is given a maximum depth based on a rescaling of
132 !! the indexing of coordinateResolution.
133 logical :: set_maximum_depths = .false.
134
135 !> If true, integrate for interface positions from the top downward.
136 !! If false, integrate from the bottom upward, as does the rest of the model.
137 logical :: integrate_downward_for_e = .true.
138
139 !> The vintage of the order of arithmetic and expressions to use for remapping.
140 !! Values below 20190101 recover the remapping answers from 2018.
141 !! Higher values use more robust forms of the same remapping expressions.
142 integer :: remap_answer_date = 99991231
143
144 logical :: use_hybgen_unmix = .false. !< If true, use the hybgen unmixing code before remapping
145
146 type(zlike_CS), pointer :: zlike_CS => null() !< Control structure for z-like coordinate generator
147 type(sigma_CS), pointer :: sigma_CS => null() !< Control structure for sigma coordinate generator
148 type(rho_CS), pointer :: rho_CS => null() !< Control structure for rho coordinate generator
149 type(hycom_CS), pointer :: hycom_CS => null() !< Control structure for hybrid coordinate generator
150 type(adapt_CS), pointer :: adapt_CS => null() !< Control structure for adaptive coordinate generator
151 type(hybgen_regrid_CS), pointer :: hybgen_CS => NULL() !< Control structure for hybgen regridding
152
153end type
154
155! The following routines are visible to the outside world
156public initialize_regridding, end_regridding, regridding_main
157public regridding_preadjust_reqs, convective_adjustment
158public inflate_vanished_layers_old, check_grid_column
159public set_regrid_params, get_regrid_size, write_regrid_file
160public uniformResolution, setCoordinateResolution
161public set_target_densities_from_GV, set_target_densities
162public set_regrid_max_depths, set_regrid_max_thickness
163public getCoordinateResolution, getCoordinateInterfaces
164public getCoordinateUnits, getCoordinateShortName, getStaticThickness
165public DEFAULT_COORDINATE_MODE
166public set_h_neglect, set_dz_neglect
167public get_zlike_CS, get_sigma_CS, get_rho_CS
168
169!> Documentation for coordinate options
170character(len=*), parameter, public :: regriddingCoordinateModeDoc = &
171 " LAYER - Isopycnal or stacked shallow water layers\n"//&
172 " ZSTAR, Z* - stretched geopotential z*\n"//&
173 " SIGMA_SHELF_ZSTAR - stretched geopotential z* ignoring shelf\n"//&
174 " SIGMA - terrain following coordinates\n"//&
175 " RHO - continuous isopycnal\n"//&
176 " HYCOM1 - HyCOM-like hybrid coordinate\n"//&
177 " HYBGEN - Hybrid coordinate from the Hycom hybgen code\n"//&
178 " ADAPTIVE - optimize for smooth neutral density surfaces"
179
180!> Documentation for regridding interpolation schemes
181character(len=*), parameter, public :: regriddingInterpSchemeDoc = &
182 " P1M_H2 (2nd-order accurate)\n"//&
183 " P1M_H4 (2nd-order accurate)\n"//&
184 " P1M_IH4 (2nd-order accurate)\n"//&
185 " PLM (2nd-order accurate)\n"//&
186 " PPM_CW (3rd-order accurate)\n"//&
187 " PPM_H4 (3rd-order accurate)\n"//&
188 " PPM_IH4 (3rd-order accurate)\n"//&
189 " P3M_IH4IH3 (4th-order accurate)\n"//&
190 " P3M_IH6IH5 (4th-order accurate)\n"//&
191 " PQM_IH4IH3 (4th-order accurate)\n"//&
192 " PQM_IH6IH5 (5th-order accurate)"
193
194!> Default interpolation scheme
195character(len=*), parameter, public :: regriddingDefaultInterpScheme = "P1M_H2"
196!> Default mode for boundary extrapolation
197logical, parameter, public :: regriddingDefaultBoundaryExtrapolation = .false.
198!> Default minimum thickness for some coordinate generation modes [m]
199real, parameter, public :: regriddingDefaultMinThickness = 1.e-3
200
201!> Maximum length of parameters
202integer, parameter :: MAX_PARAM_LENGTH = 120
203
204#undef __DO_SAFETY_CHECKS__
205
206contains
207
208!> Initialization and configures a regridding control structure based on customizable run-time parameters
2092subroutine initialize_regridding(CS, G, GV, US, max_depth, param_file, mdl, &
210 coord_mode, param_prefix, param_suffix)
211 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
212 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
213 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
214 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
215 real, intent(in) :: max_depth !< The maximum depth of the ocean [Z ~> m].
216 type(param_file_type), intent(in) :: param_file !< Parameter file
217 character(len=*), intent(in) :: mdl !< Name of calling module.
218 character(len=*), intent(in) :: coord_mode !< Coordinate mode
219 character(len=*), intent(in) :: param_prefix !< String to prefix to parameter names.
220 !! If empty, causes main model parameters to be used.
221 character(len=*), intent(in) :: param_suffix !< String to append to parameter names.
222
223 ! Local variables
224 integer :: ke ! Number of levels
225 integer :: n_sigma ! Number of shallow dz's, for HYBRID_MAP or HYBRID_3D
226 integer :: np ! Number of profiles, for HYBRID_MAP
227 integer :: nceiling ! ceiling of map index, for HYBRID_MAP
228 integer :: nfloor ! floor of map index, for HYBRID_MAP
229 real :: nfrac ! fraction of map index, for HYBRID_MAP [nondim]
230 character(len=80) :: string, string2, varName ! Temporary strings
231 character(len=40) :: coord_units, coord_res_param ! Temporary strings
232 character(len=MAX_PARAM_LENGTH) :: param_name
233 character(len=200) :: inputdir, fileName, longString
234 character(len=320) :: message ! Temporary strings
235 character(len=12) :: expected_units, alt_units ! Temporary strings
236 logical :: tmpLogical, do_sum, main_parameters
237 logical :: coord_is_state_dependent, ierr
238 integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags.
239 integer :: remap_answer_date ! The vintage of the remapping expressions to use.
240 integer :: regrid_answer_date ! The vintage of the regridding expressions to use.
241 real :: tmpReal ! A temporary variable used in setting other variables [various]
242 real :: P_Ref ! The coordinate variable reference pression [R L2 T-2 ~> Pa]
243 real :: maximum_depth ! The maximum depth of the ocean [m] (not in Z).
244 real :: dz_extra ! The thickness of an added layer to append to the woa09_dz profile when
245 ! maximum_depth is large [m] (not in Z).
246 real :: nominalDepth ! Depth of ocean bottom in thickness units (positive downward) [H ~> m or kg m-2]
247 real :: depth_q ! A depth scale factor [nondim]
248 real :: depth_s ! The end of the shallow Z regime [m]
249 real :: depth_d ! The start of the deep Z regime [m]
250 real :: adaptTimeRatio, adaptZoomCoeff ! Temporary variables for input parameters [nondim]
251 real :: adaptBuoyCoeff, adaptAlpha ! Temporary variables for input parameters [nondim]
252 real :: adaptZoom ! The thickness of the near-surface zooming region with the adaptive coordinate [H ~> m or kg m-2]
253 real :: adaptDrho0 ! Reference density difference for stratification-dependent diffusion. [R ~> kg m-3]
254 integer :: i, j, k, nzf(4)
2552 real, dimension(:), allocatable :: dz ! Resolution (thickness) in units of coordinate, which may be [m]
256 ! or [Z ~> m] or [H ~> m or kg m-2] or [R ~> kg m-3] or other units.
2572 real, dimension(:,:), allocatable :: dz_2d ! 2D resolution (thickness) in units of coordinate, which may be [m]
258 ! or [Z ~> m] or [H ~> m or kg m-2] or [R ~> kg m-3] or other units.
2592 real, dimension(:,:,:), allocatable :: dz_3d ! 3D resolution (thickness) in units of coordinate, which may be [m]
260 ! or [Z ~> m] or [H ~> m or kg m-2] or [R ~> kg m-3] or other units.
2612 real, dimension(:), allocatable :: dz_shallow ! Shallow resolution (thickness), for HYBRID_MAP or HYBRID_3D [m]
2622 real, dimension(:,:), allocatable :: rho_target_2d ! 2D target density used in HYBRID mode [kg m-3]
2632 real, dimension(:,:,:), allocatable :: rho_target_3d ! 3D target density used in HYBRID mode [kg m-3]
2642 real, dimension(:,:), allocatable :: index_map ! Region array of indexes for HYBRID_MAP [nondim]
2652 real, dimension(:), allocatable :: h_max ! Maximum layer thicknesses [H ~> m or kg m-2]
2662 real, dimension(:), allocatable :: z_max ! Maximum interface depths [H ~> m or kg m-2] or other
267 ! units depending on the coordinate
2682 real, dimension(:), allocatable :: dz_max ! Thicknesses used to find maximum interface depths
269 ! [H ~> m or kg m-2] or other units
2702 real, dimension(:), allocatable :: rho_target ! Target density used in HYBRID mode [kg m-3]
271 ! Thicknesses [m] that give level centers approximately corresponding to table 2 of WOA09
272 ! These are approximate because the WOA09 depths are not smoothly spaced. Levels
273 ! 1, 4, 5, 9, 12, 24, and 36 are 2.5, 2.5, 1.25 12.5, 37.5 and 62.5 m deeper than WOA09
274 ! but all others are identical.
275 real, dimension(40) :: woa09_dz_approx = (/ 5., 10., 10., 15., 22.5, 25., 25., 25., &
276 37.5, 50., 50., 75., 100., 100., 100., 100., &
277 100., 100., 100., 100., 100., 100., 100., 175., &
278 250., 375., 500., 500., 500., 500., 500., 500., &
279 500., 500., 500., 500., 500., 500., 500., 500. /)
280 ! These are the actual spacings [m] between WOA09 depths which, if used for layer thickness, places
281 ! the interfaces at the WOA09 depths.
282 real, dimension(39) :: woa09_dzi = (/ 10., 10., 10., 20., 25., 25., 25., 25., &
283 50., 50., 50., 100., 100., 100., 100., 100., &
284 100., 100., 100., 100., 100., 100., 100., 250., &
285 250., 500., 500., 500., 500., 500., 500., 500., &
286 500., 500., 500., 500., 500., 500., 500. /)
287 ! These are the spacings [m] between WOA23 depths from table 3 of
288 ! https://www.ncei.noaa.gov/data/oceans/woa/WOA13/DOC/woa13documentation.pdf
289 real, dimension(136) :: woa23_dzi = (/ 5., 5., 5., 5., 5., 5., 5., 5., 5., 5., &
290 5., 5., 5., 5., 5., 5., 5., 5., 5., 5., &
291 25., 25., 25., 25., 25., 25., 25., 25., 25., 25., &
292 25., 25., 25., 25., 25., 25., 50., 50., 50., 50., &
293 50., 50., 50., 50., 50., 50., 50., 50., 50., 50., &
294 50., 50., 50., 50., 50., 50., 50., 50., 50., 50., &
295 50., 50., 50., 50., 50., 50., 100., 100., 100., 100., &
296 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
297 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
298 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
299 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
300 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
301 100., 100., 100., 100., 100., 100., 100., 100., 100., 100., &
302 100., 100., 100., 100., 100., 100. /)
303
3042 call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
3052 inputdir = slasher(inputdir)
306
3072 main_parameters=.false.
3082 if (len_trim(param_prefix)==0) main_parameters=.true.
3092 if (main_parameters .and. len_trim(param_suffix)>0) call MOM_error(FATAL,trim(mdl)//&
3100 ' initialize_regridding: Suffix provided without prefix for parameter names!')
311
3122 CS%nk = 0
3132 CS%regridding_scheme = coordinateMode(coord_mode)
3142 coord_is_state_dependent = state_dependent(coord_mode)
3152 maximum_depth = US%Z_to_m*max_depth
316
3172 if (main_parameters) then
318 ! Read coordinate units parameter (main model = REGRIDDING_COORDINATE_UNITS)
319 call get_param(param_file, mdl, "REGRIDDING_COORDINATE_UNITS", coord_units, &
3201 "Units of the regridding coordinate.", default=coordinateUnits(coord_mode))
321 else
3221 coord_units=coordinateUnits(coord_mode)
323 endif
324
3252 if (coord_is_state_dependent) then
3260 if (main_parameters) then
3270 param_name = "INTERPOLATION_SCHEME"
3280 string2 = regriddingDefaultInterpScheme
329 else
3300 param_name = create_coord_param(param_prefix, "INTERP_SCHEME", param_suffix)
3310 string2 = 'PPM_H4' ! Default for diagnostics
332 endif
333 call get_param(param_file, mdl, param_name, string, &
334 "This sets the interpolation scheme to use to "//&
335 "determine the new grid. These parameters are "//&
336 "only relevant when REGRIDDING_COORDINATE_MODE is "//&
337 "set to a function of state. Otherwise, it is not "//&
338 "used. It can be one of the following schemes: \n"//&
3390 trim(regriddingInterpSchemeDoc), default=trim(string2))
3400 call set_regrid_params(CS, interp_scheme=string)
341
342 call get_param(param_file, mdl, "DEFAULT_ANSWER_DATE", default_answer_date, &
343 "This sets the default value for the various _ANSWER_DATE parameters.", &
3440 default=99991231)
345 call get_param(param_file, mdl, "REMAPPING_ANSWER_DATE", remap_answer_date, &
346 "The vintage of the expressions and order of arithmetic to use for remapping. "//&
347 "Values below 20190101 result in the use of older, less accurate expressions "//&
348 "that were in use at the end of 2018. Higher values result in the use of more "//&
349 "robust and accurate forms of mathematically equivalent expressions.", &
3500 default=default_answer_date, do_not_log=.not.GV%Boussinesq)
3510 if (.not.GV%Boussinesq) remap_answer_date = max(remap_answer_date, 20230701)
3520 call set_regrid_params(CS, remap_answer_date=remap_answer_date)
353 call get_param(param_file, mdl, "REGRIDDING_ANSWER_DATE", regrid_answer_date, &
354 "The vintage of the expressions and order of arithmetic to use for regridding. "//&
355 "Values below 20190101 result in the use of older, less accurate expressions "//&
356 "that were in use at the end of 2018. Higher values result in the use of more "//&
357 "robust and accurate forms of mathematically equivalent expressions.", &
3580 default=default_answer_date, do_not_log=.not.GV%Boussinesq)
3590 if (.not.GV%Boussinesq) regrid_answer_date = max(regrid_answer_date, 20230701)
3600 call set_regrid_params(CS, regrid_answer_date=regrid_answer_date)
361 endif
362
3632 if (main_parameters .and. coord_is_state_dependent) then
364 call get_param(param_file, mdl, "BOUNDARY_EXTRAPOLATION", tmpLogical, &
365 "When defined, a proper high-order reconstruction "//&
366 "scheme is used within boundary cells rather "//&
367 "than PCM. E.g., if PPM is used for remapping, a "//&
368 "PPM reconstruction will also be used within "//&
3690 "boundary cells.", default=regriddingDefaultBoundaryExtrapolation)
3700 call set_regrid_params(CS, boundary_extrapolation=tmpLogical)
371 else
3722 call set_regrid_params(CS, boundary_extrapolation=.false.)
373 endif
374
375 ! Read coordinate configuration parameter (main model = ALE_COORDINATE_CONFIG)
3762 if (main_parameters) then
3771 param_name = "ALE_COORDINATE_CONFIG"
3781 coord_res_param = "ALE_RESOLUTION"
3791 string2 = 'UNIFORM'
380 else
3811 param_name = create_coord_param(param_prefix, "DEF", param_suffix)
3821 coord_res_param = create_coord_param(param_prefix, "RES", param_suffix)
3831 string2 = 'UNIFORM'
3841 if ((maximum_depth>3000.) .and. (maximum_depth<9250.)) string2='WOA09' ! For convenience
385 endif
386 call get_param(param_file, mdl, param_name, string, &
387 "Determines how to specify the coordinate "//&
388 "resolution. Valid options are:\n"//&
389 " PARAM - use the vector-parameter "//trim(coord_res_param)//"\n"//&
390 " UNIFORM[:N] - uniformly distributed\n"//&
391 " FILE:string - read from a file. The string specifies\n"//&
392 " the filename and variable name, separated\n"//&
393 " by a comma or space, e.g. FILE:lev.nc,dz\n"//&
394 " or FILE:lev.nc,interfaces=zw\n"//&
395 " WOA09[:N] - the WOA09 vertical grid (approximately)\n"//&
396 " WOA09INT[:N] - layers spanned by the WOA09 depths\n"//&
397 " WOA23INT[:N] - layers spanned by the WOA23 depths\n"//&
398 " FNC1:string - FNC1:dz_min,H_total,power,precision\n"//&
399 " HYBRID:string - read from a file. The string specifies\n"//&
400 " the filename and two variable names, separated\n"//&
401 " by a comma or space, for sigma-2 and dz.\n"//&
402 " e.g. HYBRID:vgrid.nc,sigma2,dz\n"//&
403 " HYBRID_3D:string - read from a file. The string specifies\n"//&
404 " the filename and two 3D variable names, separated\n"//&
405 " by a comma or space, for sigma-2 and dz. The\n"//&
406 " latter can be FNC1:string which is used everywhere.\n"//&
407 " e.g. HYBRID_3D:vgrid.nc,sigma2,dz\n"//&
408 " HYBRID_MAP:string - read from a file. The string specifies\n"//&
409 " the filename and three variable names, separated\n"//&
410 " by a comma or space, for map, sigma-2 and dz.\n"//&
411 " Map is a spatial index array with, maxval(map)=N,\n"//&
412 " and the others are 2D arrays containing N profiles.\n"//&
413 " Map typically contains integer values, but it can\n"//&
414 " contain real values, I+w, which imply using\n"//&
415 " the weighted sum of profiles I and I+1.\n"//&
416 " Dz can be FNC1:string which is used everywhere.\n"//&
417 " e.g. HYBRID_MAP:vgrid.nc,map,sigma2,dz",&
4182 default=trim(string2))
419 message = "The distribution of vertical resolution for the target\n"//&
420 "grid used for Eulerian-like coordinates. For example,\n"//&
421 "in z-coordinate mode, the parameter is a list of level\n"//&
422 "thicknesses (in m). In sigma-coordinate mode, the list\n"//&
4232 "is of non-dimensional fractions of the water column."
4242 if (index(trim(string),'UNIFORM')==1) then
4250 if (len_trim(string)==7) then
4260 ke = GV%ke ! Use model nk by default
4270 tmpReal = maximum_depth
4280 elseif (index(trim(string),'UNIFORM:')==1 .and. len_trim(string)>8) then
429 ! Format is "UNIFORM:N" or "UNIFORM:N,dz"
4300 ke = extract_integer(string(9:len_trim(string)),'',1)
4310 tmpReal = extract_real(string(9:len_trim(string)),',',2,missing_value=maximum_depth)
432 else
433 call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
4340 'Unable to interpret "'//trim(string)//'".')
435 endif
4360 allocate(dz(ke))
437 dz(:) = uniformResolution(ke, coord_mode, tmpReal, &
438 US%R_to_kg_m3*(GV%Rlay(1) + 0.5*(GV%Rlay(1)-GV%Rlay(min(2,ke)))), &
4390 US%R_to_kg_m3*(GV%Rlay(ke) + 0.5*(GV%Rlay(ke)-GV%Rlay(max(ke-1,1)))) )
4400 if (main_parameters) call log_param(param_file, mdl, "!"//coord_res_param, dz, &
4410 trim(message), units=trim(coord_units))
4422 elseif (trim(string)=='PARAM') then
443 ! Read coordinate resolution (main model = ALE_RESOLUTION)
4440 allocate(dz(1001))
4450 dz(:) = -1. ! Setting to <0 allows detection of unset elements
4460 call get_param(param_file, mdl, coord_res_param, dz, "Scan", units="", do_not_log=.true.)
4470 if (dz(1001)>=0.) call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
4480 "PARAM specification is limited to 1000 values. Hack the code to use more!")
4490 do ke=1,1000 ! Find number of defined levels
4500 if (dz(ke+1)<0.) exit
451 enddo
4520 deallocate(dz)
4530 allocate(dz(ke)) ! Allocate with the correct number of levels, and re-read thicknesses
454 call get_param(param_file, mdl, coord_res_param, dz, &
4550 trim(message), units=trim(coord_units), fail_if_missing=.true.)
4562 elseif (index(trim(string),'FILE:')==1) then
457 ! FILE:filename,var_name is assumed to be reading level thickness variables
458 ! FILE:filename,interfaces=var_name reads positions
4590 if (string(6:6)=='.' .or. string(6:6)=='/') then
460 ! If we specified "FILE:./xyz" or "FILE:/xyz" then we have a relative or absolute path
4610 fileName = trim( extractWord(trim(string(6:80)), 1) )
462 else
463 ! Otherwise assume we should look for the file in INPUTDIR
4640 fileName = trim(inputdir) // trim( extractWord(trim(string(6:80)), 1) )
465 endif
4660 if (.not. file_exists(fileName)) call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
4670 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(string)//")")
468
4690 varName = trim( extractWord(trim(string(6:)), 2) )
4700 if (len_trim(varName)==0) then
4710 if (field_exists(fileName,'dz')) then ; varName = 'dz'
4720 elseif (field_exists(fileName,'dsigma')) then ; varName = 'dsigma'
4730 elseif (field_exists(fileName,'ztest')) then ; varName = 'ztest'
474 else ; call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
4750 "Coordinate variable not specified and none could be guessed.")
476 endif
477 endif
478 ! This check fails when the variable is a dimension variable! -AJA
479 !if (.not. field_exists(fileName,trim(varName))) call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
480 ! "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
4810 if (CS%regridding_scheme == REGRIDDING_SIGMA) then
4820 expected_units = 'nondim' ; alt_units = expected_units
4830 elseif (CS%regridding_scheme == REGRIDDING_RHO) then
4840 expected_units = 'kg m-3' ; alt_units = expected_units
485 else
4860 expected_units = 'meters' ; alt_units = 'm'
487 endif
4880 if (index(trim(varName),'interfaces=')==1) then
4890 varName=trim(varName(12:))
4900 call verify_variable_units(filename, varName, expected_units, message, ierr, alt_units)
4910 if (ierr) call MOM_error(FATAL, trim(mdl)//", initialize_regridding: "//&
492 "Unsupported format in grid definition '"//trim(filename)//&
4930 "'. Error message "//trim(message))
4940 call field_size(trim(fileName), trim(varName), nzf)
4950 ke = nzf(1)-1
4960 if (ke < 1) call MOM_error(FATAL, trim(mdl)//" initialize_regridding via Var "//&
497 trim(varName)//"in FILE "//trim(filename)//&
4980 " requires at least 2 target interface values.")
4990 if (CS%regridding_scheme == REGRIDDING_RHO) then
5000 allocate(rho_target(ke+1))
5010 call MOM_read_data(trim(fileName), trim(varName), rho_target)
502 else
5030 allocate(dz(ke))
5040 allocate(z_max(ke+1))
5050 call MOM_read_data(trim(fileName), trim(varName), z_max)
5060 dz(:) = abs(z_max(1:ke) - z_max(2:ke+1))
5070 deallocate(z_max)
508 endif
509 else
510 ! Assume reading resolution
5110 call field_size(trim(fileName), trim(varName), nzf)
5120 ke = nzf(1)
5130 allocate(dz(ke))
5140 call MOM_read_data(trim(fileName), trim(varName), dz)
515 endif
5160 if (main_parameters .and. (ke/=GV%ke)) then
517 call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
5180 'Mismatch in number of model levels and "'//trim(string)//'".')
519 endif
5200 if (main_parameters) call log_param(param_file, mdl, "!"//coord_res_param, dz, &
5210 trim(message), units=coordinateUnits(coord_mode))
5222 elseif (index(trim(string),'FNC1:')==1) then
5231 ke = GV%ke ; allocate(dz(ke))
5241 call dz_function1( trim(string(6:)), dz )
5251 if (main_parameters) call log_param(param_file, mdl, "!"//coord_res_param, dz, &
5261 trim(message), units=coordinateUnits(coord_mode))
5271 elseif (index(trim(string),'RFNC1:')==1) then
528 ! Function used for set target interface densities
5290 ke = rho_function1( trim(string(7:)), rho_target )
5301 elseif (index(trim(string),'HYBRID:')==1) then
5310 ke = GV%ke
5320 allocate(dz(ke))
5330 allocate(rho_target(ke+1))
534 ! The following assumes the FILE: syntax of above but without "FILE:" in the string
5350 varName = trim( extractWord(trim(string(8:)), 3) )
5360 if (varname == " ") call MOM_error(FATAL, &
537 trim(mdl)//", initialize_regridding: HYBRID "// &
5380 "Too few arguments in ("//trim(string)//")")
5390 fileName = trim( extractWord(trim(string(8:)), 1) )
5400 if (fileName(1:1)/='.' .and. filename(1:1)/='/') fileName = trim(inputdir) // trim( fileName )
5410 if (.not. file_exists(fileName)) call MOM_error(FATAL, &
542 trim(mdl)//", initialize_regridding: HYBRID "// &
5430 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(string)//")")
5440 varName = trim( extractWord(trim(string(8:)), 2) )
5450 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
546 trim(mdl)//", initialize_regridding: HYBRID "// &
5470 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
5480 call MOM_read_data(trim(fileName), trim(varName), rho_target)
5490 varName = trim( extractWord(trim(string(8:)), 3) )
5500 if (varName(1:5) == 'FNC1:') then ! Use FNC1 to calculate dz
5510 call dz_function1( trim(string((index(trim(string),'FNC1:')+5):)), dz )
552 else ! Read dz from file
5530 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
554 trim(mdl)//", initialize_regridding: HYBRID "// &
5550 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
5560 call MOM_read_data(trim(fileName), trim(varName), dz)
557 endif
5580 if (main_parameters) then
559 call log_param(param_file, mdl, "!"//coord_res_param, dz, &
5600 trim(message), units=coordinateUnits(coord_mode))
561 call log_param(param_file, mdl, "!TARGET_DENSITIES", rho_target, &
5620 'HYBRID target densities for interfaces', units="kg m-3")
563 endif
5641 elseif (index(trim(string),'HYBRID_3D:')==1) then
5650 ke = GV%ke
5660 allocate(dz_3d(SZI_(G),SZJ_(G),ke), source=0.0)
5670 allocate(rho_target_3d(SZI_(G),SZJ_(G),ke+1), source=0.0)
568 ! The following assumes the FILE: syntax of above but without "FILE:" in the string
5690 varName = trim( extractWord(trim(string(11:)), 3) )
5700 if (varname == " ") call MOM_error(FATAL, &
571 trim(mdl)//", initialize_regridding: HYBRID_3D "// &
5720 "Too few arguments in ("//trim(string)//")")
5730 fileName = trim( extractWord(trim(string(11:)), 1) )
5740 if (fileName(1:1)/='.' .and. filename(1:1)/='/') fileName = trim(inputdir) // trim( fileName )
5750 if (.not. file_exists(fileName)) call MOM_error(FATAL, &
576 trim(mdl)//", initialize_regridding: HYBRID_3D "// &
5770 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(string)//")")
5780 varName = trim( extractWord(trim(string(11:)), 2) )
5790 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
580 trim(mdl)//", initialize_regridding: HYBRID_3D "// &
5810 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
5820 call MOM_read_data(trim(fileName), trim(varName), rho_target_3d, G%Domain)
5830 call pass_var(rho_target_3d, G%Domain, halo=1)
5840 varName = trim( extractWord(trim(string(11:)), 3) )
5850 if (varName(1:5) == 'FNC1:') then ! Use FNC1 to calculate dz_3d
5860 allocate(dz(ke))
5870 call dz_function1( trim(string((index(trim(string),'FNC1:')+5):)), dz )
588 ! Adjust target grid to be consistent with maximum_depth
5890 tmpReal = sum( dz(:) )
5900 if (tmpReal < maximum_depth) then
5910 dz(ke) = dz(ke) + ( maximum_depth - tmpReal )
592 endif
5930 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
5940 if (G%mask2dT(i,j)>0.) then
5950 do k=1,ke
5960 dz_3d(i,j,k) = dz(k)
597 enddo
598 endif !mask2dT
599 enddo ; enddo
6000 if (main_parameters) then
601 call log_param(param_file, mdl, "!"//coord_res_param, dz, &
6020 trim(message), units=coordinateUnits(coord_mode))
603 endif
604 else ! Read dz from file
6050 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
606 trim(mdl)//", initialize_regridding: HYBRID_3D "// &
6070 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
6080 call MOM_read_data(trim(fileName), trim(varName), dz_3d, G%Domain)
6090 call pass_var(dz_3d, G%Domain, halo=1)
610 ! set nominal 1-d dz to UNIFORM
6110 allocate(dz(ke))
612 dz(:) = uniformResolution(ke, coord_mode, maximum_depth, &
613 US%R_to_kg_m3*(GV%Rlay(1) + 0.5*(GV%Rlay(1)-GV%Rlay(min(2,ke)))), &
6140 US%R_to_kg_m3*(GV%Rlay(ke) + 0.5*(GV%Rlay(ke)-GV%Rlay(max(ke-1,1)))) )
615 endif !dz
6161 elseif (index(trim(string),'HYBRID_MAP:')==1) then
6170 ke = GV%ke
6180 allocate(dz_3d(SZI_(G),SZJ_(G),ke), source=0.0)
6190 allocate(rho_target_3d(SZI_(G),SZJ_(G),ke+1), source=0.0)
6200 allocate(index_map(SZI_(G),SZJ_(G)), source=1.0)
621 ! The following assumes the FILE: syntax of above but without "FILE:" in the string
6220 varName = trim( extractWord(trim(string(12:)), 4) )
6230 if (varname == " ") call MOM_error(FATAL, &
624 trim(mdl)//", initialize_regridding: HYBRID_3D "// &
6250 "Too few arguments in ("//trim(string)//")")
6260 fileName = trim( extractWord(trim(string(12:)), 1) )
6270 if (fileName(1:1)/='.' .and. filename(1:1)/='/') fileName = trim(inputdir) // trim( fileName )
6280 if (.not. file_exists(fileName)) call MOM_error(FATAL, &
629 trim(mdl)//", initialize_regridding: HYBRID_MAP "// &
6300 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(string)//")")
6310 varName = trim( extractWord(trim(string(12:)), 2) )
6320 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
633 trim(mdl)//", initialize_regridding: HYBRID_MAP "// &
6340 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
6350 call MOM_read_data(trim(fileName), trim(varName), index_map, G%Domain)
6360 call pass_var(index_map, G%Domain, halo=1)
637 !find maximum index
6380 np = 1
6390 do j=G%jsc, G%jec ; do i=G%isc, G%iec
6400 np = max(np,ceiling(index_map(i,j)))
641 enddo ; enddo
6420 call max_across_PEs(np)
6430 write(string2,"(i3)") np
644 call MOM_error(NOTE, &
6450 trim(mdl)//", initialize_regridding: HYBRID_MAP NP="//trim(string2))
6460 if (np<1) call MOM_error(FATAL, &
6470 trim(mdl)//", initialize_regridding: HYBRID_MAP to small NP from "//trim(varName))
6480 allocate(dz_2d(ke,np))
6490 allocate(rho_target_2d(ke+1,np))
6500 varName = trim( extractWord(trim(string(12:)), 3) )
6510 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
652 trim(mdl)//", initialize_regridding: HYBRID_MAP "// &
6530 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
654 ! MOM_read_data can't handle this array
6550 call read_variable(trim(fileName), trim(varName), rho_target_2d)
6560 if (main_parameters) then
657 call log_param(param_file, mdl, "!TARGET_DENSITIES", rho_target_2d(:,1), &
6580 'HYBRID target densities for interfaces', units="kg m-3")
659 endif
6600 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
6610 if (G%mask2dT(i,j)>0.) then
6620 nfloor = floor(index_map(i,j))
6630 nceiling = ceiling(index_map(i,j))
6640 if (nfloor<1 .or. nceiling>np) then
6650 write(0,'(a,2i5,a,g20.6)') 'HYBRID_MAP: i,j=',i,j,'index_map(i,j)=', index_map(i,j)
666 call MOM_error(FATAL, trim(mdl)//", initialize_regridding: HYBRID_MAP "// &
6670 "index_map out of range")
668 endif
6690 if (nfloor == nceiling) then
6700 do k=1,ke+1
6710 rho_target_3d(i,j,k) = rho_target_2d(k,nfloor)
672 enddo
673 else
6740 nfrac = index_map(i,j) - nfloor !between 0.0 and 1.0
6750 do k=1,ke+1
676 rho_target_3d(i,j,k) = (1.0-nfrac)*rho_target_2d(k,nfloor) + &
6770 nfrac *rho_target_2d(k,nceiling)
678 enddo
679 endif !integer:else
680 endif !mask2dT
681 enddo ; enddo
6820 varName = trim( extractWord(trim(string(12:)), 4) )
6830 if (varName(1:5) == 'FNC1:') then ! Use FNC1 to calculate dz_3d
6840 allocate(dz(ke))
6850 call dz_function1( trim(string((index(trim(string),'FNC1:')+5):)), dz )
686 ! Adjust target grid to be consistent with maximum_depth
6870 tmpReal = sum( dz(:) )
6880 if (tmpReal < maximum_depth) then
6890 dz(ke) = dz(ke) + ( maximum_depth - tmpReal )
690 endif
6910 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
6920 if (G%mask2dT(i,j)>0.) then
6930 do k=1,ke
6940 dz_3d(i,j,k) = dz(k)
695 enddo
696 endif !mask2dT
697 enddo ; enddo
6980 if (main_parameters) then
699 call log_param(param_file, mdl, "!"//coord_res_param, dz, &
7000 trim(message), units=coordinateUnits(coord_mode))
701 endif
702 else ! Read dz from file
7030 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL, &
704 trim(mdl)//", initialize_regridding: HYBRID_MAP "// &
7050 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
706 ! MOM_read_data can't handle this array
7070 call read_variable(trim(fileName), trim(varName), dz_2d)
7080 if (main_parameters) then
709 call log_param(param_file, mdl, "!"//coord_res_param, dz_2d(:,1), &
7100 trim(message), units=coordinateUnits(coord_mode))
711 endif
7120 do i=1,np
7130 tmpReal = sum( dz_2d(:,i) )
7140 if (tmpReal < maximum_depth) then
7150 dz_2d(ke,i) = dz_2d(ke,i) + ( maximum_depth - tmpReal )
716 endif
717 enddo
7180 allocate(dz(ke))
7190 dz(:) = dz_2d(:,1)
7200 if (main_parameters) then
721 call log_param(param_file, mdl, "!"//coord_res_param, dz, &
7220 trim(message), units=coordinateUnits(coord_mode))
723 endif
7240 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
7250 if (G%mask2dT(i,j)>0.) then
7260 nfloor = floor(index_map(i,j))
7270 nceiling = ceiling(index_map(i,j))
7280 if (nfloor == nceiling) then
7290 do k=1,ke
7300 dz_3d(i,j,k) = dz_2d(k,nfloor)
731 enddo
732 else
7330 nfrac = index_map(i,j) - nfloor !between 0.0 and 1.0
7340 do k=1,ke
735 dz_3d(i,j,k) = (1.0-nfrac)*dz_2d(k,nfloor) + &
7360 nfrac *dz_2d(k,nceiling)
737 enddo
738 endif !integer:else
739 endif !mask2dT
740 enddo ; enddo
741 endif !dz
7420 deallocate(index_map)
7430 deallocate(rho_target_2d)
7440 deallocate(dz_2d)
7451 elseif (index(trim(string),'WOA09INT')==1) then
7460 if (len_trim(string)==8) then ! string=='WOA09INT'
7470 tmpReal = 0. ; ke = 0 ; dz_extra = 0.
7480 do while (tmpReal<maximum_depth)
7490 ke = ke + 1
7500 if (ke > size(woa09_dzi)) then
7510 dz_extra = maximum_depth - tmpReal
7520 exit
753 endif
7540 tmpReal = tmpReal + woa09_dzi(ke)
755 enddo
7560 elseif (index(trim(string),'WOA09INT:')==1) then ! string starts with 'WOA09INT:'
7570 if (len_trim(string)==9) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
7580 'Expected string of form "WOA09INT:N" but got "'//trim(string)//'".')
7590 ke = extract_integer(string(10:len_trim(string)),'',1)
7600 if (ke>39 .or. ke<1) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
7610 'For "WOA05INT:N" N must 0<N<40 but got "'//trim(string)//'".')
762 endif
7630 allocate(dz(ke))
7640 do k=1,min(ke, size(woa09_dzi))
7650 dz(k) = woa09_dzi(k)
766 enddo
7670 if (ke > size(woa09_dzi)) dz(ke) = dz_extra
7681 elseif (index(trim(string),'WOA23INT')==1) then
7690 if (len_trim(string)==8) then ! string=='WOA23INT'
7700 tmpReal = 0. ; ke = 0 ; dz_extra = 0.
7710 do while (tmpReal<maximum_depth)
7720 ke = ke + 1
7730 if (ke > size(woa23_dzi)) then
7740 dz_extra = maximum_depth - tmpReal
7750 exit
776 endif
7770 tmpReal = tmpReal + woa23_dzi(ke)
778 enddo
7790 elseif (index(trim(string),'WOA23INT:')==1) then ! string starts with 'WOA23INT:'
7800 if (len_trim(string)==9) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
7810 'Expected string of form "WOA23INT:N" but got "'//trim(string)//'".')
7820 ke = extract_integer(string(10:len_trim(string)),'',1)
7830 if (ke>39 .or. ke<1) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
7840 'For "WOA05INT:N" N must 0<N<40 but got "'//trim(string)//'".')
785 endif
7860 allocate(dz(ke))
7870 do k=1,min(ke, size(woa23_dzi))
7880 dz(k) = woa23_dzi(k)
789 enddo
7900 if (ke > size(woa23_dzi)) dz(ke) = dz_extra
7911 elseif (index(trim(string),'WOA09')==1) then
7921 if (len_trim(string)==5) then ! string=='WOA09'
7931 tmpReal = 0. ; ke = 0 ; dz_extra = 0.
79434 do while (tmpReal<maximum_depth)
79533 ke = ke + 1
79633 if (ke > size(woa09_dz_approx)) then
7970 dz_extra = maximum_depth - tmpReal
7980 exit
799 endif
80033 tmpReal = tmpReal + woa09_dz_approx(ke)
801 enddo
8020 elseif (index(trim(string),'WOA09:')==1) then ! string starts with 'WOA09:'
8030 if (len_trim(string)==6) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
8040 'Expected string of form "WOA09:N" but got "'//trim(string)//'".')
8050 ke = extract_integer(string(7:len_trim(string)),'',1)
8060 if (ke>40 .or. ke<1) call MOM_error(FATAL,trim(mdl)//', initialize_regridding: '// &
8070 'For "WOA05:N" N must 0<N<41 but got "'//trim(string)//'".')
808 endif
8091 allocate(dz(ke))
81034 do k=1,min(ke, size(woa09_dz_approx))
81134 dz(k) = woa09_dz_approx(k)
812 enddo
8131 if (ke > size(woa09_dz_approx)) dz(ke) = dz_extra
814 else
815 call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
8160 "Unrecognized coordinate configuration"//trim(string))
817 endif
818
8192 if (main_parameters) then
820 ! This is a work around to apparently needed to work with the from_Z initialization... ???
821 if (coordinateMode(coord_mode) == REGRIDDING_ZSTAR .or. &
822 coordinateMode(coord_mode) == REGRIDDING_HYCOM1 .or. &
8231 coordinateMode(coord_mode) == REGRIDDING_HYBGEN .or. &
824 coordinateMode(coord_mode) == REGRIDDING_ADAPTIVE) then
8251 if (allocated(dz)) then
826 ! Adjust target grid to be consistent with maximum_depth
82776 tmpReal = sum( dz(:) )
8281 if (tmpReal < maximum_depth) then
8290 dz(ke) = dz(ke) + ( maximum_depth - tmpReal )
8301 elseif (tmpReal > maximum_depth) then
8310 if ( dz(ke) + ( maximum_depth - tmpReal ) > 0. ) then
8320 dz(ke) = dz(ke) + ( maximum_depth - tmpReal )
833 else
834 call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
8350 "MAXIMUM_DEPTH was too shallow to adjust bottom layer of DZ!"//trim(string))
836 endif
837 endif
838 endif !allocated(dz)
839 endif
840 endif
841
8422 if (coordinateMode(coord_mode) == REGRIDDING_HYCOM1) then
8430 allocate(dz_shallow(ke))
844 call get_param(param_file, mdl, "SHALLOW_"//trim(coord_res_param), dz_shallow, &
845 "HYBGEN-style Z-sigma-Z near surface fixed coordinate. "//&
846 "The default of all zeros turns this option off. "//&
847 "Let N_SIGMA be the number of consecutive non-zero entries, typically < NK. "//&
848 "Use SHALLOW_"//trim(coord_res_param)//" when rest depth is shallower than "//&
849 "SUM(SHALLOW_"//trim(coord_res_param)//"(1:N_SIGMA)). "//&
850 "Use "//trim(coord_res_param)//" when rest depth is deeper than "//&
851 "SUM("//trim(coord_res_param)//"(1:N_SIGMA)). "//&
852 "Otherwise use a linear sum of the two weighted by rest depth.",&
8530 units="m", default=0.0)
8540 n_sigma = ke
8550 depth_s = 0.0
8560 do k= 1,ke
8570 depth_s = depth_s + dz_shallow(k)
8580 if (dz_shallow(k) == 0.0) then
8590 n_sigma = k-1
8600 exit
861 endif
862 enddo
8630 if (n_sigma > 0) then
8640 if (main_parameters) call log_param(param_file, mdl, "!N_SIGMA", n_sigma, &
865 "Number of consecutive non-zero entries in SHALLOW_"//&
8660 trim(coord_res_param)//".")
8670 if (.not.allocated(dz_3d)) then
8680 allocate(dz_3d(SZI_(G),SZJ_(G),ke), source=0.0)
8690 allocate(rho_target_3d(SZI_(G),SZJ_(G),ke+1), source=0.0)
8700 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
8710 if (G%mask2dT(i,j)>0.) then
8720 do k=1,ke
8730 dz_3d(i,j,k) = dz(k)
874 enddo
8750 do k=1,ke+1
8760 rho_target_3d(i,j,k) = rho_target(k)
877 enddo
878 endif !mask2dT
879 enddo ; enddo
880 endif
8810 do i=G%isc-1,G%iec+1 ; do j=G%jsc-1,G%jec+1
8820 if (G%mask2dT(i,j)>0.) then
8830 nominalDepth = max(G%meanSL(i,j) + G%bathyT(i,j), 0.0) * US%Z_to_m
8840 if (nominalDepth <= depth_s) then
8850 do k= 1,n_sigma
8860 dz_3d(i,j,k) = dz_shallow(k)
887 enddo
8880 do k= n_sigma+1,ke
8890 dz_3d(i,j,k) = dz_shallow(n_sigma)
890 enddo
891 else ! >depth_s
8920 depth_d = 0.0
8930 do k= 1,n_sigma
8940 depth_d = depth_d + dz_3d(i,j,k)
895 enddo
896 ! do nothing if nominalDepth >= depth_d
8970 if (nominalDepth < depth_d) then
8980 depth_q = (nominalDepth - depth_s) / (depth_d - depth_s)
8990 do k= 1,n_sigma
9000 dz_3d(i,j,k) = (1.0-depth_q)*dz_shallow(k) + depth_q*dz_3d(i,j,k)
901 enddo
9020 do k= n_sigma+1,ke
9030 dz_3d(i,j,k) = (1.0-depth_q)*dz_shallow(n_sigma) + depth_q*dz_3d(i,j,k)
904 enddo
905 endif !<depth_d and >depth_s
906 endif !nominalDepth
907 endif !mask2dT
908 enddo ; enddo
909 endif !n_sigma
9100 deallocate(dz_shallow)
911 endif !REGRIDDING_HYCOM1
912
9132 CS%nk=ke
914
915 ! Target resolution (for fixed coordinates)
9162 if (allocated(dz_3d)) then
9170 allocate( CS%coordinateResolution(CS%nk), source=-1.E30 )
9180 allocate( CS%coordinateResolution_3d(SZI_(G),SZJ_(G),CS%nk), source=-1.E30 )
9190 allocate( CS%target_density_3d(SZI_(G),SZJ_(G),CS%nk+1), source=-1.E30*US%kg_m3_to_R )
920 else
921110 allocate( CS%coordinateResolution(CS%nk), source=-1.E30 )
9222 if (state_dependent(CS%regridding_scheme)) then
923 ! Target values
9240 allocate( CS%target_density(CS%nk+1), source=-1.E30*US%kg_m3_to_R )
925 endif
926 endif
927
9282 if (allocated(dz_3d)) then
929 ! set both 1d and 3d fields
9300 call setCoordinateResolution(dz, CS, scale=US%m_to_Z)
9310 call setCoordinateResolution_3d(dz_3d, CS, scale=US%m_to_Z)
9320 CS%coord_scale = US%Z_to_m
9330 deallocate(dz_3d)
9342 elseif (allocated(dz)) then
9352 if (coordinateMode(coord_mode) == REGRIDDING_SIGMA) then
9360 call setCoordinateResolution(dz, CS, scale=1.0)
9372 elseif (coordinateMode(coord_mode) == REGRIDDING_RHO) then
9380 call setCoordinateResolution(dz, CS, scale=US%kg_m3_to_R)
9392 elseif (coordinateMode(coord_mode) == REGRIDDING_ADAPTIVE) then
9400 call setCoordinateResolution(dz, CS, scale=GV%m_to_H)
9410 CS%coord_scale = GV%H_to_m
942 else
9432 call setCoordinateResolution(dz, CS, scale=US%m_to_Z)
9442 CS%coord_scale = US%Z_to_m
945 endif
946 endif
947
948 ! set coord_scale for RHO regridding independent of allocation status of dz
9492 if (coordinateMode(coord_mode) == REGRIDDING_RHO) then
9500 CS%coord_scale = US%R_to_kg_m3
951 endif
952
953 ! ensure CS%ref_pressure is rescaled properly
9542 CS%ref_pressure = US%Pa_to_RL2_T2 * CS%ref_pressure
955
9562 if (allocated(rho_target_3d)) then
9570 call set_target_densities_3d(CS, G, US%kg_m3_to_R, rho_target_3d)
9580 deallocate(rho_target_3d)
9592 elseif (allocated(rho_target)) then
9600 call set_target_densities(CS, US%kg_m3_to_R*rho_target)
9610 deallocate(rho_target)
9622 elseif (coordinateMode(coord_mode) == REGRIDDING_RHO) then
9630 call set_target_densities_from_GV(GV, US, CS)
964 call log_param(param_file, mdl, "!TARGET_DENSITIES", US%R_to_kg_m3*CS%target_density(:), &
9650 'RHO target densities for interfaces', "kg m-3")
966 endif
967
968 ! initialise coordinate-specific control structure
9692 call initCoord(CS, G, GV, US, coord_mode, param_file)
970
9712 if (coord_is_state_dependent) then
9720 if (main_parameters) then
973 call get_param(param_file, mdl, create_coord_param(param_prefix, "P_REF", param_suffix), &
974 P_Ref, &
975 "The pressure that is used for calculating the coordinate "//&
976 "density. (1 Pa = 1e4 dbar, so 2e7 is commonly used.) "//&
977 "This is only used if USE_EOS and ENABLE_THERMODYNAMICS are true.", &
9780 units="Pa", default=2.0e7, scale=US%Pa_to_RL2_T2)
979 else
980 call get_param(param_file, mdl, create_coord_param(param_prefix, "P_REF", param_suffix), &
981 P_Ref, &
982 "The pressure that is used for calculating the diagnostic coordinate "//&
983 "density. (1 Pa = 1e4 dbar, so 2e7 is commonly used.) "//&
984 "This is only used for the RHO coordinate.", &
9850 units="Pa", default=2.0e7, scale=US%Pa_to_RL2_T2)
986 endif
987 call get_param(param_file, mdl, create_coord_param(param_prefix, &
988 "REGRID_COMPRESSIBILITY_FRACTION", param_suffix), tmpReal, &
989 "When interpolating potential density profiles we can add "//&
990 "some artificial compressibility solely to make homogeneous "//&
9910 "regions appear stratified.", units="nondim", default=0.)
9920 call set_regrid_params(CS, compress_fraction=tmpReal, ref_pressure=P_Ref)
993 endif
994
9952 if (main_parameters) then
996 call get_param(param_file, mdl, "MIN_THICKNESS", tmpReal, &
997 "When regridding, this is the minimum layer "//&
998 "thickness allowed.", units="m", scale=GV%m_to_H, &
9991 default=regriddingDefaultMinThickness )
10001 call set_regrid_params(CS, min_thickness=tmpReal)
1001 call get_param(param_file, mdl, "USE_ADJUST_INTERFACE_MOTION", tmpLogical, &
1002 "When regridding, after the primary grid generation, call a function that ensures "//&
10031 "positive layer thicknesses. Historically, this was required.", default=.true.)
10041 call set_regrid_params(CS, use_adjust_interface_motion=tmpLogical)
1005 else
10061 call set_regrid_params(CS, min_thickness=0.)
10071 call set_regrid_params(CS, use_adjust_interface_motion=.true.)
10081 call set_regrid_params(CS, use_depth_based_time_filter=.true.)
1009 endif
1010
10112 if (main_parameters .and. coordinateMode(coord_mode) == REGRIDDING_HYCOM1) then
1012 call get_param(param_file, mdl, "HYCOM1_ONLY_IMPROVES", tmpLogical, &
1013 "When regridding, an interface is only moved if this improves "//&
10140 "the fit to the target density.", default=.false.)
10150 call set_hycom_params(CS%hycom_CS, only_improves=tmpLogical)
1016 endif
1017
10182 CS%use_hybgen_unmix = .false.
10192 if (coordinateMode(coord_mode) == REGRIDDING_HYBGEN) then
1020 call get_param(param_file, mdl, "USE_HYBGEN_UNMIX", CS%use_hybgen_unmix, &
1021 "If true, use hybgen unmixing code before regridding.", &
10220 default=.false.)
1023 endif
1024
10252 if (coordinateMode(coord_mode) == REGRIDDING_ADAPTIVE) then
1026 call get_param(param_file, mdl, "ADAPT_TIME_RATIO", adaptTimeRatio, &
10270 "Ratio of ALE timestep to grid timescale.", units="nondim", default=1.0e-1)
1028 call get_param(param_file, mdl, "ADAPT_ZOOM_DEPTH", adaptZoom, &
10290 "Depth of near-surface zooming region.", units="m", default=200.0, scale=GV%m_to_H)
1030 call get_param(param_file, mdl, "ADAPT_ZOOM_COEFF", adaptZoomCoeff, &
10310 "Coefficient of near-surface zooming diffusivity.", units="nondim", default=0.2)
1032 call get_param(param_file, mdl, "ADAPT_BUOY_COEFF", adaptBuoyCoeff, &
10330 "Coefficient of buoyancy diffusivity.", units="nondim", default=0.8)
1034 call get_param(param_file, mdl, "ADAPT_ALPHA", adaptAlpha, &
10350 "Scaling on optimization tendency.", units="nondim", default=1.0)
1036 call get_param(param_file, mdl, "ADAPT_DO_MIN_DEPTH", tmpLogical, &
1037 "If true, make a HyCOM-like mixed layer by preventing interfaces "//&
1038 "from being shallower than the depths specified by the regridding coordinate.", &
10390 default=.false.)
1040 call get_param(param_file, mdl, "ADAPT_DRHO0", adaptDrho0, &
1041 "Reference density difference for stratification-dependent diffusion.", &
10420 units="kg m-3", default=0.5, scale=US%kg_m3_to_R)
1043
1044 call set_regrid_params(CS, adaptTimeRatio=adaptTimeRatio, adaptZoom=adaptZoom, &
1045 adaptZoomCoeff=adaptZoomCoeff, adaptBuoyCoeff=adaptBuoyCoeff, adaptAlpha=adaptAlpha, &
10460 adaptDoMin=tmpLogical, adaptDrho0=adaptDrho0)
1047 endif
1048
10492 if (main_parameters .and. coord_is_state_dependent) then
1050 call get_param(param_file, mdl, "MAXIMUM_INT_DEPTH_CONFIG", string, &
1051 "Determines how to specify the maximum interface depths.\n"//&
1052 "Valid options are:\n"//&
1053 " NONE - there are no maximum interface depths\n"//&
1054 " PARAM - use the vector-parameter MAXIMUM_INTERFACE_DEPTHS\n"//&
1055 " FILE:string - read from a file. The string specifies\n"//&
1056 " the filename and variable name, separated\n"//&
1057 " by a comma or space, e.g. FILE:lev.nc,Z\n"//&
1058 " FNC1:string - FNC1:dz_min,H_total,power,precision",&
10590 default='NONE')
10600 message = "The list of maximum depths for each interface."
10610 allocate(z_max(ke+1))
10620 allocate(dz_max(ke))
10630 if ( trim(string) == "NONE") then
1064 ! Do nothing.
10650 elseif ( trim(string) == "PARAM") then
1066 call get_param(param_file, mdl, "MAXIMUM_INTERFACE_DEPTHS", z_max, &
10670 trim(message), units="m", scale=GV%m_to_H, fail_if_missing=.true.)
10680 call set_regrid_max_depths(CS, z_max)
10690 elseif (index(trim(string),'FILE:')==1) then
10700 if (string(6:6)=='.' .or. string(6:6)=='/') then
1071 ! If we specified "FILE:./xyz" or "FILE:/xyz" then we have a relative or absolute path
10720 fileName = trim( extractWord(trim(string(6:80)), 1) )
1073 else
1074 ! Otherwise assume we should look for the file in INPUTDIR
10750 fileName = trim(inputdir) // trim( extractWord(trim(string(6:80)), 1) )
1076 endif
10770 if (.not. file_exists(fileName)) call MOM_error(FATAL,trim(mdl)// &
1078 ", initialize_regridding: "// &
10790 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(string)//")")
1080
10810 do_sum = .false.
10820 varName = trim( extractWord(trim(string(6:)), 2) )
10830 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL,trim(mdl)// &
1084 ", initialize_regridding: "// &
10850 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(string)//")")
10860 if (len_trim(varName)==0) then
10870 if (field_exists(fileName,'z_max')) then ; varName = 'z_max'
10880 elseif (field_exists(fileName,'dz')) then ; varName = 'dz' ; do_sum = .true.
10890 elseif (field_exists(fileName,'dz_max')) then ; varName = 'dz_max' ; do_sum = .true.
1090 else ; call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
10910 "MAXIMUM_INT_DEPTHS variable not specified and none could be guessed.")
1092 endif
1093 endif
10940 if (do_sum) then
10950 call MOM_read_data(trim(fileName), trim(varName), dz_max)
10960 z_max(1) = 0.0 ; do K=1,ke ; z_max(K+1) = z_max(K) + dz_max(k) ; enddo
1097 else
10980 call MOM_read_data(trim(fileName), trim(varName), z_max)
1099 endif
1100 call log_param(param_file, mdl, "!MAXIMUM_INT_DEPTHS", z_max, &
11010 trim(message), units=coordinateUnits(coord_mode))
11020 call set_regrid_max_depths(CS, z_max, GV%m_to_H)
11030 elseif (index(trim(string),'FNC1:')==1) then
11040 call dz_function1( trim(string(6:)), dz_max )
11050 z_max(1) = 0.0 ; do K=1,ke ; z_max(K+1) = z_max(K) + dz_max(K) ; enddo
1106 call log_param(param_file, mdl, "!MAXIMUM_INT_DEPTHS", z_max, &
11070 trim(message), units=coordinateUnits(coord_mode))
11080 call set_regrid_max_depths(CS, z_max, GV%m_to_H)
1109 else
1110 call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
11110 "Unrecognized MAXIMUM_INT_DEPTH_CONFIG "//trim(string))
1112 endif
11130 deallocate(z_max)
11140 deallocate(dz_max)
1115
1116 ! Optionally specify maximum thicknesses for each layer, enforced by moving
1117 ! the interface below a layer downward.
1118 call get_param(param_file, mdl, "MAX_LAYER_THICKNESS_CONFIG", longString, &
1119 "Determines how to specify the maximum layer thicknesses.\n"//&
1120 "Valid options are:\n"//&
1121 " NONE - there are no maximum layer thicknesses\n"//&
1122 " PARAM - use the vector-parameter MAX_LAYER_THICKNESS\n"//&
1123 " FILE:string - read from a file. The string specifies\n"//&
1124 " the filename and variable name, separated\n"//&
1125 " by a comma or space, e.g. FILE:lev.nc,Z\n"//&
1126 " FNC1:string - FNC1:dz_min,H_total,power,precision",&
11270 default='NONE')
11280 message = "The list of maximum thickness for each layer."
11290 allocate(h_max(ke))
11300 if ( trim(longString) == "NONE") then
1131 ! Do nothing.
11320 elseif ( trim(longString) == "PARAM") then
1133 call get_param(param_file, mdl, "MAX_LAYER_THICKNESS", h_max, &
11340 trim(message), units="m", fail_if_missing=.true., scale=GV%m_to_H)
11350 call set_regrid_max_thickness(CS, h_max)
11360 elseif (index(trim(longString),'FILE:')==1) then
11370 if (longString(6:6)=='.' .or. longString(6:6)=='/') then
1138 ! If we specified "FILE:./xyz" or "FILE:/xyz" then we have a relative or absolute path
11390 fileName = trim( extractWord(trim(longString(6:200)), 1) )
1140 else
1141 ! Otherwise assume we should look for the file in INPUTDIR
11420 fileName = trim(inputdir) // trim( extractWord(trim(longString(6:200)), 1) )
1143 endif
11440 if (.not. file_exists(fileName)) call MOM_error(FATAL,trim(mdl)// &
1145 ", initialize_regridding: "// &
11460 "Specified file not found: Looking for '"//trim(fileName)//"' ("//trim(longString)//")")
1147
11480 varName = trim( extractWord(trim(longString(6:)), 2) )
11490 if (.not. field_exists(fileName,varName)) call MOM_error(FATAL,trim(mdl)// &
1150 ", initialize_regridding: "// &
11510 "Specified field not found: Looking for '"//trim(varName)//"' ("//trim(longString)//")")
11520 if (len_trim(varName)==0) then
11530 if (field_exists(fileName,'h_max')) then ; varName = 'h_max'
11540 elseif (field_exists(fileName,'dz_max')) then ; varName = 'dz_max'
1155 else ; call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
11560 "MAXIMUM_INT_DEPTHS variable not specified and none could be guessed.")
1157 endif
1158 endif
11590 call MOM_read_data(trim(fileName), trim(varName), h_max)
1160 call log_param(param_file, mdl, "!MAX_LAYER_THICKNESS", h_max, &
11610 trim(message), units=coordinateUnits(coord_mode))
11620 call set_regrid_max_thickness(CS, h_max, GV%m_to_H)
11630 elseif (index(trim(longString),'FNC1:')==1) then
11640 call dz_function1( trim(longString(6:)), h_max )
1165 call log_param(param_file, mdl, "!MAX_LAYER_THICKNESS", h_max, &
11660 trim(message), units=coordinateUnits(coord_mode))
11670 call set_regrid_max_thickness(CS, h_max, GV%m_to_H)
1168 else
1169 call MOM_error(FATAL,trim(mdl)//", initialize_regridding: "// &
11700 "Unrecognized MAX_LAYER_THICKNESS_CONFIG "//trim(longString))
1171 endif
11720 deallocate(h_max)
1173 endif
1174
11752 if (allocated(dz)) deallocate(dz)
11764end subroutine initialize_regridding
1177
1178
1179
1180!> Deallocation of regridding memory
11811subroutine end_regridding(CS)
1182 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
1183
11841 if (associated(CS%zlike_CS)) call end_coord_zlike(CS%zlike_CS)
11851 if (associated(CS%sigma_CS)) call end_coord_sigma(CS%sigma_CS)
11861 if (associated(CS%rho_CS)) call end_coord_rho(CS%rho_CS)
11871 if (associated(CS%hycom_CS)) call end_coord_hycom(CS%hycom_CS)
11881 if (associated(CS%adapt_CS)) call end_coord_adapt(CS%adapt_CS)
11891 if (associated(CS%hybgen_CS)) call end_hybgen_regrid(CS%hybgen_CS)
1190
11911 deallocate( CS%coordinateResolution )
11921 if (allocated(CS%coordinateResolution_3d)) deallocate( CS%coordinateResolution_3d )
11931 if (allocated(CS%target_density_3d)) deallocate( CS%target_density_3d )
11941 if (allocated(CS%target_density)) deallocate( CS%target_density )
11951 if (allocated(CS%max_interface_depths) ) deallocate( CS%max_interface_depths )
11961 if (allocated(CS%max_layer_thickness) ) deallocate( CS%max_layer_thickness )
1197
11981end subroutine end_regridding
1199
1200!------------------------------------------------------------------------------
1201!> Dispatching regridding routine for orchestrating regridding & remapping
120239subroutine regridding_main( remapCS, CS, G, GV, US, h, tv, h_new, dzInterface, &
120313 frac_shelf_h, PCM_cell)
1204!------------------------------------------------------------------------------
1205! This routine takes care of (1) building a new grid and (2) remapping between
1206! the old grid and the new grid. The creation of the new grid can be based
1207! on z coordinates, target interface densities, sigma coordinates or any
1208! arbitrary coordinate system.
1209! The MOM6 interface positions are always calculated from the bottom up by
1210! accumulating the layer thicknesses starting at z=-G%bathyT. z increases
1211! upwards (decreasing k-index).
1212! The new grid is defined by the change in position of those interfaces in z
1213! dzInterface = zNew - zOld.
1214! Thus, if the regridding inflates the top layer, hNew(1) > hOld(1), then the
1215! second interface moves downward, zNew(2) < zOld(2), and dzInterface(2) < 0.
1216! hNew(k) = hOld(k) - dzInterface(k+1) + dzInterface(k)
1217! IMPORTANT NOTE:
1218! This is the converse of the sign convention used in the remapping code!
1219!------------------------------------------------------------------------------
1220
1221 ! Arguments
1222 type(remapping_CS), intent(in) :: remapCS !< Remapping parameters and options
1223 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1224 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
1225 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
1226 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1227 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Current 3D grid obtained after
1228 !! the last time step [H ~> m or kg m-2]
1229 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamical variables (T, S, ...)
1230 real, dimension(SZI_(G),SZJ_(G),CS%nk), intent(inout) :: h_new !< New 3D grid consistent with target
1231 !! coordinate [H ~> m or kg m-2]
1232 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< The change in position of each
1233 !! interface [H ~> m or kg m-2]
1234 real, dimension(SZI_(G),SZJ_(G)), optional, intent(in ) :: frac_shelf_h !< Fractional ice shelf coverage [nondim]
1235 logical, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1236 optional, intent(out ) :: PCM_cell !< Use PCM remapping in cells where true
1237
1238 ! Local variables
123926 real :: nom_depth_H(SZI_(G),SZJ_(G)) !< The nominal ocean depth at each point in thickness units [H ~> m or kg m-2]
124026 real :: tot_h(SZI_(G),SZJ_(G)) !< The total thickness of the water column [H ~> m or kg m-2]
124126 real :: tot_dz(SZI_(G),SZJ_(G)) !< The total distance between the top and bottom of the water column [Z ~> m]
1242 real :: Z_to_H ! A conversion factor used by some routines to convert coordinate
1243 ! parameters to depth units [H Z-1 ~> nondim or kg m-3]
1244 character(len=128) :: mesg ! A string for error messages
1245 integer :: i, j, k
1246
12478553688 if (present(PCM_cell)) PCM_cell(:,:,:) = .false.
1248
124913 Z_to_H = US%Z_to_m * GV%m_to_H ! Often this is equivalent to GV%Z_to_H.
1250
125113 if ((allocated(tv%SpV_avg)) .and. (tv%valid_SpV_halo < 1)) then
12520 if (tv%valid_SpV_halo < 0) then
12530 mesg = "invalid values of SpV_avg."
1254 else
12550 mesg = "insufficiently large SpV_avg halos of width 0 but 1 is needed."
1256 endif
12570 call MOM_error(FATAL, "Regridding_main called in fully non-Boussinesq mode with "//trim(mesg))
1258 endif
1259
126013 if (allocated(tv%SpV_avg)) then ! This is the fully non-Boussinesq case
12610 do j=G%jsc-1,G%jec+1 ; do i=G%isc-1,G%iec+1
12620 tot_h(i,j) = 0.0 ; tot_dz(i,j) = 0.0
1263 enddo ; enddo
12640 do k=1,GV%ke ; do j=G%jsc-1,G%jec+1 ; do i=G%isc-1,G%iec+1
12650 tot_h(i,j) = tot_h(i,j) + h(i,j,k)
12660 tot_dz(i,j) = tot_dz(i,j) + GV%H_to_RZ * tv%SpV_avg(i,j,k) * h(i,j,k)
1267 enddo ; enddo ; enddo
12680 do j=G%jsc-1,G%jec+1 ; do i=G%isc-1,G%iec+1
12690 if (tot_dz(i,j) > 0.0) then
12700 nom_depth_H(i,j) = max(G%meanSL(i,j) + G%bathyT(i,j), 0.0) * (tot_h(i,j) / tot_dz(i,j))
1271 else
12720 nom_depth_H(i,j) = 0.0
1273 endif
1274 enddo ; enddo
1275 else
127699151 do j=G%jsc-1,G%jec+1 ; do i=G%isc-1,G%iec+1
127799138 nom_depth_H(i,j) = max(G%meanSL(i,j) + G%bathyT(i,j), 0.0) * Z_to_H
1278 enddo ; enddo
1279 endif
1280
128126 select case ( CS%regridding_scheme )
1282
1283 case ( REGRIDDING_ZSTAR )
128413 call build_zstar_grid( CS, G, GV, h, nom_depth_H, dzInterface, frac_shelf_h, zScale=Z_to_H )
128513 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1286 case ( REGRIDDING_SIGMA_SHELF_ZSTAR)
12870 call build_zstar_grid( CS, G, GV, h, nom_depth_H, dzInterface, zScale=Z_to_H )
12880 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1289 case ( REGRIDDING_SIGMA )
12900 call build_sigma_grid( CS, G, GV, h, nom_depth_H, dzInterface )
12910 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1292 case ( REGRIDDING_RHO )
12930 call build_rho_grid( G, GV, G%US, h, nom_depth_H, tv, dzInterface, remapCS, CS, frac_shelf_h )
12940 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1295 case ( REGRIDDING_HYCOM1 )
1296 call build_grid_HyCOM1( G, GV, G%US, h, nom_depth_H, tv, h_new, dzInterface, remapCS, CS, &
12970 frac_shelf_h, zScale=Z_to_H )
1298 case ( REGRIDDING_HYBGEN )
12990 call hybgen_regrid(G, GV, G%US, h, nom_depth_H, tv, CS%hybgen_CS, dzInterface, PCM_cell)
13000 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1301 case ( REGRIDDING_ADAPTIVE )
13020 call build_grid_adaptive(G, GV, G%US, h, nom_depth_H, tv, dzInterface, remapCS, CS)
13030 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1304
1305 case ( REGRIDDING_ARBITRARY )
1306 call MOM_error(FATAL,'MOM_regridding, regridding_main: '//&
13070 'Regridding mode "ARB" is not implemented.')
1308 case default
1309 call MOM_error(FATAL,'MOM_regridding, regridding_main: '//&
131013 'Unknown regridding scheme selected!')
1311
1312 end select ! type of grid
1313
1314#ifdef __DO_SAFETY_CHECKS__
1315 if (CS%nk == GV%ke) then
1316 do j = G%jsc-1,G%jec+1 ; do i = G%isc-1,G%iec+1 ; if (G%mask2dT(i,j)>0.) then
1317 call check_grid_column( GV%ke, h(i,j,:), dzInterface(i,j,:), 'in regridding_main')
1318 endif ; enddo ; enddo
1319 endif
1320#endif
132194393 do j=G%jsc,G%jec ; do i=G%isc,G%iec ; if (G%mask2dT(i,j) > 0.) then
13224953832 if (minval(h(i,j,:)) < 0.0) then
13230 write(0,*) 'regridding_main check_grid: i,j=', i, j, 'h_new(i,j,:)=', h_new(i,j,:)
13240 call MOM_error(FATAL, "regridding_main: negative thickness encountered.")
1325 endif
1326 endif ; enddo ; enddo
1327
132826end subroutine regridding_main
1329
1330!------------------------------------------------------------------------------
1331!> This routine returns flags indicating which pre-remapping state adjustments
1332!! are needed depending on the coordinate mode in use.
13331subroutine regridding_preadjust_reqs(CS, do_conv_adj, do_hybgen_unmix, hybgen_CS)
1334
1335 ! Arguments
1336 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1337 logical, intent(out) :: do_conv_adj !< Convective adjustment should be done
1338 logical, intent(out) :: do_hybgen_unmix !< Hybgen unmixing should be done
1339 type(hybgen_regrid_CS), pointer, &
1340 optional, intent(out) :: hybgen_CS !< Control structure for hybgen regridding for sharing parameters.
1341
1342
13431 do_conv_adj = .false. ; do_hybgen_unmix = .false.
13442 select case ( CS%regridding_scheme )
1345
1346 case ( REGRIDDING_ZSTAR, REGRIDDING_SIGMA_SHELF_ZSTAR, REGRIDDING_SIGMA, REGRIDDING_ARBITRARY, &
1347 REGRIDDING_HYCOM1, REGRIDDING_ADAPTIVE )
13481 do_conv_adj = .false. ; do_hybgen_unmix = .false.
1349 case ( REGRIDDING_RHO )
13500 do_conv_adj = .true. ; do_hybgen_unmix = .false.
1351 case ( REGRIDDING_HYBGEN )
13520 do_conv_adj = .false. ; do_hybgen_unmix = CS%use_hybgen_unmix
1353 case default
1354 call MOM_error(FATAL,'MOM_regridding, regridding_preadjust_reqs: '//&
13551 'Unknown regridding scheme selected!')
1356 end select ! type of grid
1357
13581 if (present(hybgen_CS) .and. do_hybgen_unmix) hybgen_CS => CS%hybgen_CS
1359
13601end subroutine regridding_preadjust_reqs
1361
1362
1363!> Calculates h_new from h + delta_k dzInterface
136413subroutine calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
1365 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1366 type(ocean_grid_type), intent(in) :: G !< Grid structure
1367 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
1368 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Old layer thicknesses [H ~> m or kg m-2]
1369 !! or other units
1370 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(in) :: dzInterface !< Change in interface positions
1371 !! in the same units as h [H ~> m or kg m-2]
1372 real, dimension(SZI_(G),SZJ_(G),CS%nk), intent(inout) :: h_new !< New layer thicknesses in the same
1373 !! units as h [H ~> m or kg m-2]
1374 ! Local variables
1375 integer :: i, j, k, nki
1376
137713 nki = min(CS%nk, GV%ke)
1378
1379 !$OMP parallel do default(shared)
1380819 do j = G%jsc-1,G%jec+1
138199151 do i = G%isc-1,G%iec+1
138299138 if (G%mask2dT(i,j)>0.) then
13834989400 do k=1,nki
13844989400 h_new(i,j,k) = max( 0., h(i,j,k) + ( dzInterface(i,j,k) - dzInterface(i,j,k+1) ) )
1385 enddo
138665650 if (CS%nk > GV%ke) then
13870 do k=nki+1, CS%nk
13880 h_new(i,j,k) = max( 0., dzInterface(i,j,k) - dzInterface(i,j,k+1) )
1389 enddo
1390 endif
1391 else
13922483832 h_new(i,j,1:nki) = h(i,j,1:nki)
139332682 if (CS%nk > GV%ke) h_new(i,j,nki+1:CS%nk) = 0.
1394 ! On land points, why are we keeping the original h rather than setting to zero? -AJA
1395 endif
1396 enddo
1397 enddo
1398
139913end subroutine calc_h_new_by_dz
1400
1401
1402!> Check that the total thickness of new and old grids are consistent
14030subroutine check_grid_column( nk, h, dzInterface, msg )
1404 integer, intent(in) :: nk !< Number of cells
1405 real, dimension(nk), intent(in) :: h !< Cell thicknesses [Z ~> m] or arbitrary units
1406 real, dimension(nk+1), intent(in) :: dzInterface !< Change in interface positions (same units as h), often [Z ~> m]
1407 character(len=*), intent(in) :: msg !< Message to append to errors
1408 ! Local variables
1409 integer :: k
1410 real :: eps ! A tiny relative thickness [nondim]
1411 real :: total_h_old ! The total thickness in the old column, in [Z ~> m] or arbitrary units
1412 real :: total_h_new ! The total thickness in the updated column, in [Z ~> m] or arbitrary units
1413 real :: h_new ! A thickness in the updated column, in [Z ~> m] or arbitrary units
1414
14150 eps =1. ; eps = epsilon(eps)
1416
1417 ! Total thickness of grid h
14180 total_h_old = 0.
14190 do k = 1,nk
14200 total_h_old = total_h_old + h(k)
1421 enddo
1422
14230 total_h_new = 0.
14240 do k = nk,1,-1
14250 h_new = h(k) + ( dzInterface(k) - dzInterface(k+1) ) ! New thickness
14260 if (h_new<0.) then
14270 write(0,*) 'k,h,hnew=',k,h(k),h_new
14280 write(0,*) 'dzI(k+1),dzI(k)=',dzInterface(k+1),dzInterface(k)
1429 call MOM_error( FATAL, 'MOM_regridding, check_grid_column: '//&
14300 'Negative layer thickness implied by re-gridding, '//trim(msg))
1431 endif
14320 total_h_new = total_h_new + h_new
1433
1434 enddo
1435
1436 ! Conservation by implied h_new
14370 if (abs(total_h_new-total_h_old)>real(nk-1)*0.5*(total_h_old+total_h_new)*eps) then
14380 write(0,*) 'nk=',nk
14390 do k = 1,nk
14400 write(0,*) 'k,h,hnew=',k,h(k),h(k)+(dzInterface(k)-dzInterface(k+1))
1441 enddo
14420 write(0,*) 'Hold,Hnew,Hnew-Hold=',total_h_old,total_h_new,total_h_new-total_h_old
14430 write(0,*) 'eps,(n)/2*eps*H=',eps,real(nk-1)*0.5*(total_h_old+total_h_new)*eps
1444 call MOM_error( FATAL, 'MOM_regridding, check_grid_column: '//&
14450 'Re-gridding did NOT conserve total thickness to within roundoff '//trim(msg))
1446 endif
1447
1448 ! Check that the top and bottom are intentionally moving
14490 if (dzInterface(1) /= 0.) call MOM_error( FATAL, &
14500 'MOM_regridding, check_grid_column: Non-zero dzInterface at surface! '//trim(msg))
14510 if (dzInterface(nk+1) /= 0.) call MOM_error( FATAL, &
14520 'MOM_regridding, check_grid_column: Non-zero dzInterface at bottom! '//trim(msg))
1453
14540end subroutine check_grid_column
1455
1456!> Returns the change in interface position motion after filtering and
1457!! assuming the top and bottom interfaces do not move. The filtering is
1458!! a function of depth, and is applied as the integrated average filtering
1459!! over the trajectory of the interface. By design, this code can not give
1460!! tangled interfaces provided that z_old and z_new are not already tangled.
146165650subroutine filtered_grid_motion( CS, nk, z_old, z_new, dz_g )
1462 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1463 integer, intent(in) :: nk !< Number of cells in source grid
1464 real, dimension(nk+1), intent(in) :: z_old !< Old grid position [H ~> m or kg m-2]
1465 real, dimension(CS%nk+1), intent(in) :: z_new !< New grid position before filtering [H ~> m or kg m-2]
1466 real, dimension(CS%nk+1), intent(inout) :: dz_g !< Change in interface positions including
1467 !! the effects of filtering [H ~> m or kg m-2]
1468 ! Local variables
1469 real :: sgn ! The sign convention for downward [nondim].
1470 real :: dz_tgt ! The target grid movement of the unfiltered grid [H ~> m or kg m-2]
1471 real :: zr1 ! The old grid position of an interface relative to the surface [H ~> m or kg m-2]
1472 real :: z_old_k ! The corrected position of the old grid [H ~> m or kg m-2]
1473 real :: Aq ! A temporary variable related to the grid weights [nondim]
1474 real :: Bq ! A temporary variable used in the linear term in the quadratic expression for the
1475 ! filtered grid movement [H ~> m or kg m-2]
1476 real :: z0, dz0 ! Together these give the position of an interface relative to a reference hieght
1477 ! that may be adjusted for numerical accuracy in a solver [H ~> m or kg m-2]
1478 real :: F0 ! An estimated grid movement [H ~> m or kg m-2]
1479 real :: zs ! The depth at which the shallow filtering timescale applies [H ~> m or kg m-2]
1480 real :: zd ! The depth at which the deep filtering timescale applies [H ~> m or kg m-2]
1481 real :: dzwt ! The depth range over which the transition in the filtering timescale occurs [H ~> m or kg m-2]
1482 real :: Idzwt ! The Adcroft reciprocal of dzwt [H-1 ~> m-1 or m2 kg-1]
1483 real :: wtd ! The weight given to the new grid when time filtering [nondim]
1484 real :: Iwtd ! The inverse of wtd [nondim]
1485 real :: Int_zs ! A depth integral of the weights in [H ~> m or kg m-2]
1486 real :: Int_zd ! A depth integral of the weights in [H ~> m or kg m-2]
1487 real :: dInt_zs_zd ! The depth integral of the weights between the deep and shallow depths in [H ~> m or kg m-2]
1488! For debugging:
148965650 real, dimension(nk+1) :: z_act ! The final grid positions after the filtered movement [H ~> m or kg m-2]
1490! real, dimension(nk+1) :: ddz_g_s, ddz_g_d
1491 logical :: debug = .false.
1492 integer :: k
1493
149465650 if ((z_old(nk+1) - z_old(1)) * (z_new(CS%nk+1) - z_new(1)) < 0.0) then
14950 call MOM_error(FATAL, "filtered_grid_motion: z_old and z_new use different sign conventions.")
149665650 elseif ((z_old(nk+1) - z_old(1)) * (z_new(CS%nk+1) - z_new(1)) == 0.0) then
1497 ! This is a massless column, so do nothing and return.
14980 do k=1,CS%nk+1 ; dz_g(k) = 0.0 ; enddo ; return
149965650 elseif ((z_old(nk+1) - z_old(1)) + (z_new(CS%nk+1) - z_new(1)) > 0.0) then
15000 sgn = 1.0
1501 else
150265650 sgn = -1.0
1503 endif
1504
150565650 if (debug) then
15060 do k=2,CS%nk+1
15070 if (sgn*(z_new(k)-z_new(k-1)) < -5e-16*(abs(z_new(k))+abs(z_new(k-1))) ) &
15080 call MOM_error(FATAL, "filtered_grid_motion: z_new is tangled.")
1509 enddo
15100 do k=2,nk+1
15110 if (sgn*(z_old(k)-z_old(k-1)) < -5e-16*(abs(z_old(k))+abs(z_old(k-1))) ) &
15120 call MOM_error(FATAL, "filtered_grid_motion: z_old is tangled.")
1513 enddo
1514 ! ddz_g_s(:) = 0.0 ; ddz_g_d(:) = 0.0
1515 endif
1516
151765650 zs = CS%depth_of_time_filter_shallow
151865650 zd = CS%depth_of_time_filter_deep
151965650 wtd = 1.0 - CS%old_grid_weight
152065650 Iwtd = 1.0 / wtd
1521
152265650 dzwt = (zd - zs)
152365650 Idzwt = 0.0 ; if (abs(zd - zs) > 0.0) Idzwt = 1.0 / (zd - zs)
152465650 dInt_zs_zd = 0.5*(1.0 + Iwtd) * (zd - zs)
152565650 Aq = 0.5*(Iwtd - 1.0)
1526
152765650 dz_g(1) = 0.0
152865650 z_old_k = z_old(1)
15294989400 do k = 2,CS%nk+1
15304923750 if (k<=nk+1) z_old_k = z_old(k) ! This allows for virtual z_old interface at bottom of the model
1531 ! zr1 is positive and increases with depth, and dz_tgt is positive downward.
15324923750 dz_tgt = sgn*(z_new(k) - z_old_k)
15334923750 zr1 = sgn*(z_old_k - z_old(1))
1534
1535 ! First, handle the two simple and common cases that do not pass through
1536 ! the adjustment rate transition zone.
15374989400 if ((zr1 > zd) .and. (zr1 + wtd * dz_tgt > zd)) then
15384923750 dz_g(k) = sgn * wtd * dz_tgt
15390 elseif ((zr1 < zs) .and. (zr1 + dz_tgt < zs)) then
15400 dz_g(k) = sgn * dz_tgt
1541 else
1542 ! Find the new value by inverting the equation
1543 ! integral(0 to dz_new) Iwt(z) dz = dz_tgt
1544 ! This is trivial where Iwt is a constant, and agrees with the two limits above.
1545
1546 ! Take test values at the transition points to figure out which segment
1547 ! the new value will be found in.
15480 if (zr1 >= zd) then
15490 Int_zd = Iwtd*(zd - zr1)
15500 Int_zs = Int_zd - dInt_zs_zd
15510 elseif (zr1 <= zs) then
15520 Int_zs = (zs - zr1)
15530 Int_zd = dInt_zs_zd + (zs - zr1)
1554 else
1555! Int_zd = (zd - zr1) * (Iwtd + 0.5*(1.0 - Iwtd) * (zd - zr1) / (zd - zs))
15560 Int_zd = (zd - zr1) * (Iwtd*(0.5*(zd+zr1) - zs) + 0.5*(zd - zr1)) * Idzwt
15570 Int_zs = (zs - zr1) * (0.5*Iwtd * ((zr1 - zs)) + (zd - 0.5*(zr1+zs))) * Idzwt
1558 ! It has been verified that Int_zs = Int_zd - dInt_zs_zd to within roundoff.
1559 endif
1560
15610 if (dz_tgt >= Int_zd) then ! The new location is in the deep, slow region.
15620 dz_g(k) = sgn * ((zd-zr1) + wtd*(dz_tgt - Int_zd))
15630 elseif (dz_tgt <= Int_zs) then ! The new location is in the shallow region.
15640 dz_g(k) = sgn * ((zs-zr1) + (dz_tgt - Int_zs))
1565 else ! We need to solve a quadratic equation for z_new.
1566 ! For accuracy, do the integral from the starting depth or the nearest
1567 ! edge of the transition region. The results with each choice are
1568 ! mathematically equivalent, but differ in roundoff, and this choice
1569 ! should minimize the likelihood of inadvertently overlapping interfaces.
15700 if (zr1 <= zs) then ; dz0 = zs-zr1 ; z0 = zs ; F0 = dz_tgt - Int_zs
15710 elseif (zr1 >= zd) then ; dz0 = zd-zr1 ; z0 = zd ; F0 = dz_tgt - Int_zd
15720 else ; dz0 = 0.0 ; z0 = zr1 ; F0 = dz_tgt ; endif
1573
15740 Bq = (dzwt + 2.0*Aq*(z0-zs))
1575 ! Solve the quadratic: Aq*(zn-z0)**2 + Bq*(zn-z0) - F0*dzwt = 0
1576 ! Note that b>=0, and the two terms in the standard form cancel for the right root.
15770 dz_g(k) = sgn * (dz0 + 2.0*F0*dzwt / (Bq + sqrt(Bq**2 + 4.0*Aq*F0*dzwt) ))
1578
1579! if (debug) then
1580! dz0 = zs-zr1 ; z0 = zs ; F0 = dz_tgt - Int_zs ; Bq = (dzwt + 2.0*Aq*(z0-zs))
1581! ddz_g_s(k) = sgn * (dz0 + 2.0*F0*dzwt / (Bq + sqrt(Bq**2 + 4.0*Aq*F0*dzwt) )) - dz_g(k)
1582! dz0 = zd-zr1 ; z0 = zd ; F0 = dz_tgt - Int_zd ; Bq = (dzwt + 2.0*Aq*(z0-zs))
1583! ddz_g_d(k) = sgn * (dz0 + 2.0*F0*dzwt / (Bq + sqrt(Bq**2 + 4.0*Aq*F0*dzwt) )) - dz_g(k)
1584!
1585! if (abs(ddz_g_s(k)) > 1e-12*(abs(dz_g(k)) + abs(dz_g(k)+ddz_g_s(k)))) &
1586! call MOM_error(WARNING, "filtered_grid_motion: Expect z_output to be tangled (sc).")
1587! if (abs(ddz_g_d(k) - ddz_g_s(k)) > 1e-12*(abs(dz_g(k)+ddz_g_d(k)) + abs(dz_g(k)+ddz_g_s(k)))) &
1588! call MOM_error(WARNING, "filtered_grid_motion: Expect z_output to be tangled.")
1589! endif
1590 endif
1591
1592 endif
1593 enddo
1594 !dz_g(CS%nk+1) = 0.0
1595
159665650 if (debug) then
15970 z_old_k = z_old(1)
15980 do k=1,CS%nk+1
15990 if (k<=nk+1) z_old_k = z_old(k) ! This allows for virtual z_old interface at bottom of the model
16000 z_act(k) = z_old_k + dz_g(k)
1601 enddo
16020 do k=2,CS%nk+1
16030 if (sgn*((z_act(k))-z_act(k-1)) < -1e-15*(abs(z_act(k))+abs(z_act(k-1))) ) &
16040 call MOM_error(FATAL, "filtered_grid_motion: z_output is tangled.")
1605 enddo
1606 endif
1607
1608end subroutine filtered_grid_motion
1609
1610!> Builds a z*-coordinate grid with partial steps (Adcroft and Campin, 2004).
1611!! z* is defined as
1612!! z* = (z-eta)/(H+eta)*H s.t. z*=0 when z=eta and z*=-H when z=-H .
16130subroutine build_zstar_grid( CS, G, GV, h, nom_depth_H, dzInterface, frac_shelf_h, zScale)
1614
1615 ! Arguments
1616 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1617 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
1618 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
1619 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
1620 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: nom_depth_H !< The bathymetric depth of this column
1621 !! relative to mean sea level or another locally
1622 !! valid reference height, converted to thickness
1623 !! units [H ~> m or kg m-2]
1624 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< The change in interface depth
1625 !! [H ~> m or kg m-2].
1626 real, dimension(SZI_(G),SZJ_(G)), optional,intent(in) :: frac_shelf_h !< Fractional
1627 !! ice shelf coverage [nondim].
1628 real, optional, intent(in) :: zScale !< Scaling factor from the target coordinate
1629 !! resolution in Z to desired units for zInterface,
1630 !! usually Z_to_H in which case it is in
1631 !! units of [H Z-1 ~> nondim or kg m-3]
1632 ! Local variables
1633 real :: nominalDepth, minThickness, totalThickness ! Depths and thicknesses [H ~> m or kg m-2]
1634#ifdef __DO_SAFETY_CHECKS__
1635 real :: dh ! The larger of the total column thickness or bathymetric depth [H ~> m or kg m-2]
1636#endif
163726 real, dimension(SZK_(GV)+1) :: zOld ! Previous coordinate interface heights [H ~> m or kg m-2]
163826 real, dimension(CS%nk+1) :: zNew ! New coordinate interface heights [H ~> m or kg m-2]
1639 integer :: i, j, k, nz
1640 logical :: ice_shelf
1641
164213 nz = GV%ke
164313 minThickness = CS%min_thickness
164413 ice_shelf = present(frac_shelf_h)
1645
1646 !$OMP parallel do default(none) shared(G,GV,dzInterface,CS,nz,h,frac_shelf_h, &
1647 !$OMP ice_shelf,minThickness,zScale,nom_depth_H) &
1648 !$OMP private(nominalDepth,totalThickness, &
1649#ifdef __DO_SAFETY_CHECKS__
1650 !$OMP dh, &
1651#endif
1652 !$OMP zNew,zOld)
1653819 do j = G%jsc-1,G%jec+1
165499151 do i = G%isc-1,G%iec+1
1655
165698332 if (G%mask2dT(i,j)==0.) then
16572516514 dzInterface(i,j,:) = 0.
165832682 cycle
1659 endif
1660
1661 ! Local depth (positive downward)
166265650 nominalDepth = nom_depth_H(i,j)
1663
1664 ! Determine water column thickness
166565650 totalThickness = 0.0
16664989400 do k = 1,nz
16674989400 totalThickness = totalThickness + h(i,j,k)
1668 enddo
1669
1670 ! if (GV%Boussinesq) then
167165650 zOld(nz+1) = - nominalDepth
16724989400 do k = nz,1,-1
16734989400 zOld(k) = zOld(k+1) + h(i,j,k)
1674 enddo
1675 ! else ! Work downward?
1676 ! endif
1677
167865650 if (ice_shelf) then
16790 if (frac_shelf_h(i,j) > 0.) then ! under ice shelf
1680 call build_zstar_column(CS%zlike_CS, nominalDepth, totalThickness, zNew, &
1681 z_rigid_top=totalThickness-nominalDepth, &
16820 eta_orig=zOld(1), zScale=zScale)
1683 else
1684 call build_zstar_column(CS%zlike_CS, nominalDepth, totalThickness, &
16850 zNew, zScale=zScale)
1686 endif
1687 else
1688 call build_zstar_column(CS%zlike_CS, nominalDepth, totalThickness, &
168965650 zNew, zScale=zScale)
1690 endif
1691
1692 ! Calculate the final change in grid position after blending new and old grids
169365650 if (CS%use_depth_based_time_filter .or. CS%old_grid_weight>0.) &
169465650 call filtered_grid_motion(CS, nz, zOld, zNew, dzInterface(i,j,:))
1695
1696#ifdef __DO_SAFETY_CHECKS__
1697 dh = max(nominalDepth,totalThickness)
1698 if (abs(zNew(1)-zOld(1)) > (nz-1)*0.5*epsilon(dh)*dh) then
1699 write(0,*) 'min_thickness=',CS%min_thickness
1700 write(0,*) 'nominalDepth=',nominalDepth,'totalThickness=',totalThickness
1701 write(0,*) 'dzInterface(1) = ', dzInterface(i,j,1), epsilon(dh), nz, CS%nk
1702 do k=1,min(nz,CS%nk)+1
1703 write(0,*) k,zOld(k),zNew(k)
1704 enddo
1705 do k=min(nz,CS%nk)+2,CS%nk+1
1706 write(0,*) k,zOld(nz+1),zNew(k)
1707 enddo
1708 do k=1,min(nz,CS%nk)
1709 write(0,*) k,h(i,j,k),zNew(k)-zNew(k+1),CS%coordinateResolution(k)
1710 enddo
1711 do k=min(nz,CS%nk)+1,CS%nk
1712 write(0,*) k, 0.0, zNew(k)-zNew(k+1), CS%coordinateResolution(k)
1713 enddo
1714 call MOM_error( FATAL, &
1715 'MOM_regridding, build_zstar_grid(): top surface has moved!!!' )
1716 endif
1717#endif
1718
171966456 if (CS%use_adjust_interface_motion) call adjust_interface_motion( CS, nz, h(i,j,:), dzInterface(i,j,:) )
1720
1721 enddo
1722 enddo
1723
172413end subroutine build_zstar_grid
1725
1726!------------------------------------------------------------------------------
1727! Build sigma grid
1728!> This routine builds a grid based on terrain-following coordinates.
17290subroutine build_sigma_grid( CS, G, GV, h, nom_depth_H, dzInterface )
1730!------------------------------------------------------------------------------
1731! This routine builds a grid based on terrain-following coordinates.
1732! The module parameter coordinateResolution(:) determines the resolution in
1733! sigma coordinate, dSigma(:). sigma-coordinates are defined by
1734! sigma = (eta-z)/(H+eta) s.t. sigma=0 at z=eta and sigma=1 at z=-H .
1735!------------------------------------------------------------------------------
1736
1737 ! Arguments
1738 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1739 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
1740 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
1741 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
1742 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: nom_depth_H !< The bathymetric depth of this column
1743 !! relative to mean sea level or another locally
1744 !! valid reference height, converted to thickness
1745 !! units [H ~> m or kg m-2]
1746 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< The change in interface depth
1747 !! [H ~> m or kg m-2]
1748
1749 ! Local variables
1750 real :: nominalDepth ! The nominal depth of the sea-floor in thickness units [H ~> m or kg m-2]
1751 real :: totalThickness ! The total thickness of the water column [H ~> m or kg m-2]
1752#ifdef __DO_SAFETY_CHECKS__
1753 real :: dh ! The larger of the total column thickness or bathymetric depth [H ~> m or kg m-2]
1754#endif
17550 real, dimension(SZK_(GV)+1) :: zOld ! Previous coordinate interface heights [H ~> m or kg m-2]
17560 real, dimension(CS%nk+1) :: zNew ! New coordinate interface heights [H ~> m or kg m-2]
1757 integer :: i, j, k, nz
1758
17590 nz = GV%ke
1760
17610 do i = G%isc-1,G%iec+1
17620 do j = G%jsc-1,G%jec+1
1763
17640 if (G%mask2dT(i,j)==0.) then
17650 dzInterface(i,j,:) = 0.
17660 cycle
1767 endif
1768
1769 ! Determine water column height
17700 totalThickness = 0.0
17710 do k = 1,nz
17720 totalThickness = totalThickness + h(i,j,k)
1773 enddo
1774
1775 ! In sigma coordinates, the bathymetric depth is only used as an arbitrary offset that
1776 ! cancels out when determining coordinate motion, so referencing the column postions to
1777 ! the surface is perfectly acceptable, but for preservation of previous answers the
1778 ! referencing is done relative to the bottom when in Boussinesq or semi-Boussinesq mode.
17790 if (GV%Boussinesq .or. GV%semi_Boussinesq) then
17800 nominalDepth = nom_depth_H(i,j)
1781 else
17820 nominalDepth = totalThickness
1783 endif
1784
17850 call build_sigma_column(CS%sigma_CS, nominalDepth, totalThickness, zNew)
1786
1787 ! Calculate the final change in grid position after blending new and old grids
17880 zOld(nz+1) = -nominalDepth
17890 do k = nz,1,-1
17900 zOld(k) = zOld(k+1) + h(i,j,k)
1791 enddo
1792
17930 if (CS%use_depth_based_time_filter .or. CS%old_grid_weight>0.) &
17940 call filtered_grid_motion(CS, nz, zOld, zNew, dzInterface(i,j,:))
1795
1796#ifdef __DO_SAFETY_CHECKS__
1797 dh = max(nominalDepth,totalThickness)
1798 if (abs(zNew(1)-zOld(1)) > (CS%nk-1)*0.5*epsilon(dh)*dh) then
1799 write(0,*) 'min_thickness=',CS%min_thickness
1800 write(0,*) 'nominalDepth=',nominalDepth,'totalThickness=',totalThickness
1801 write(0,*) 'dzInterface(1) = ',dzInterface(i,j,1),epsilon(dh),nz,CS%nk
1802 do k=1,min(nz,CS%nk)+1
1803 write(0,*) k,zOld(k),zNew(k)
1804 enddo
1805 do k=min(nz,CS%nk)+2,CS%nk+1
1806 write(0,*) k,zOld(nz+1),zNew(k)
1807 enddo
1808 do k=1,min(nz,CS%nk)
1809 write(0,*) k,h(i,j,k),zNew(k)-zNew(k+1),totalThickness*CS%coordinateResolution(k), &
1810 CS%coordinateResolution(k)
1811 enddo
1812 do k=min(nz,CS%nk)+1,CS%nk
1813 write(0,*) k,0.0,zNew(k)-zNew(k+1),totalThickness*CS%coordinateResolution(k), &
1814 CS%coordinateResolution(k)
1815 enddo
1816 call MOM_error( FATAL, &
1817 'MOM_regridding, build_sigma_grid: top surface has moved!!!' )
1818 endif
1819 dzInterface(i,j,1) = 0.
1820 dzInterface(i,j,CS%nk+1) = 0.
1821#endif
1822
1823 enddo
1824 enddo
1825
18260end subroutine build_sigma_grid
1827
1828!------------------------------------------------------------------------------
1829! Build grid based on target interface densities
1830!------------------------------------------------------------------------------
1831!> This routine builds a new grid based on a given set of target interface densities.
18320subroutine build_rho_grid( G, GV, US, h, nom_depth_H, tv, dzInterface, remapCS, CS, frac_shelf_h )
1833!------------------------------------------------------------------------------
1834! This routine builds a new grid based on a given set of target interface
1835! densities (these target densities are computed by taking the mean value
1836! of given layer densities). The algorithm operates as follows within each
1837! column:
1838! 1. Given T & S within each layer, the layer densities are computed.
1839! 2. Based on these layer densities, a global density profile is reconstructed
1840! (this profile is monotonically increasing and may be discontinuous)
1841! 3. The new grid interfaces are determined based on the target interface
1842! densities.
1843! 4. T & S are remapped onto the new grid.
1844! 5. Return to step 1 until convergence or until the maximum number of
1845! iterations is reached, whichever comes first.
1846!------------------------------------------------------------------------------
1847
1848 ! Arguments
1849 type(regridding_CS), intent(in) :: CS !< Regridding control structure
1850 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
1851 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
1852 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1853 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
1854 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: nom_depth_H !< The bathymetric depth of this column
1855 !! relative to mean sea level or another locally
1856 !! valid reference height, converted to thickness
1857 !! units [H ~> m or kg m-2]
1858 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamics structure
1859 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< The change in interface depth
1860 !! [H ~> m or kg m-2]
1861 type(remapping_CS), intent(in) :: remapCS !< The remapping control structure
1862 real, dimension(SZI_(G),SZJ_(G)), optional, intent(in) :: frac_shelf_h !< Fractional ice
1863 !! shelf coverage [nondim]
1864 ! Local variables
1865 integer :: nz ! The number of layers in the input grid
1866 integer :: i, j, k
1867 real :: nominalDepth ! Depth of the bottom of the ocean, positive downward [H ~> m or kg m-2]
18680 real, dimension(SZK_(GV)+1) :: zOld ! Previous coordinate interface heights [H ~> m or kg m-2]
18690 real, dimension(CS%nk+1) :: zNew ! New coordinate interface heights [H ~> m or kg m-2]
1870 real :: h_neglect, h_neglect_edge ! Negligible thicknesses [H ~> m or kg m-2]
1871 real :: totalThickness ! Total thicknesses [H ~> m or kg m-2]
1872#ifdef __DO_SAFETY_CHECKS__
1873 real :: dh ! The larger of the total column thickness or bathymetric depth [H ~> m or kg m-2]
1874#endif
1875 logical :: ice_shelf
1876
18770 h_neglect = set_h_neglect(GV, CS%remap_answer_date, h_neglect_edge)
1878
18790 nz = GV%ke
18800 ice_shelf = present(frac_shelf_h)
1881
18820 if (.not.CS%target_density_set) call MOM_error(FATAL, "build_rho_grid: "//&
18830 "Target densities must be set before build_rho_grid is called.")
1884
1885 ! Build grid based on target interface densities
18860 do j = G%jsc-1,G%jec+1
18870 do i = G%isc-1,G%iec+1
1888
18890 if (G%mask2dT(i,j)==0.) then
18900 dzInterface(i,j,:) = 0.
18910 cycle
1892 endif
1893
1894 ! Determine total water column thickness
18950 totalThickness = 0.0
18960 do k=1,nz
18970 totalThickness = totalThickness + h(i,j,k)
1898 enddo
1899
1900 ! In rho coordinates, the bathymetric depth is only used as an arbitrary offset that
1901 ! cancels out when determining coordinate motion, so referencing the column postions to
1902 ! the surface is perfectly acceptable, but for preservation of previous answers the
1903 ! referencing is done relative to the bottom when in Boussinesq or semi-Boussinesq mode.
19040 if (GV%Boussinesq .or. GV%semi_Boussinesq) then
19050 nominalDepth = nom_depth_H(i,j)
1906 else
19070 nominalDepth = totalThickness
1908 endif
1909
1910 ! Determine absolute interface positions
19110 zOld(nz+1) = - nominalDepth
19120 do k = nz,1,-1
19130 zOld(k) = zOld(k+1) + h(i,j,k)
1914 enddo
1915
19160 if (ice_shelf) then
1917 call build_rho_column(CS%rho_CS, nz, nominalDepth, h(i,j,:), &
1918 tv%T(i,j,:), tv%S(i,j,:), tv%eqn_of_state, zNew, &
1919 z_rigid_top=totalThickness - nominalDepth, eta_orig = zOld(1), &
19200 h_neglect=h_neglect, h_neglect_edge=h_neglect_edge)
1921 else
1922 call build_rho_column(CS%rho_CS, nz, nominalDepth, h(i,j,:), &
1923 tv%T(i,j,:), tv%S(i,j,:), tv%eqn_of_state, zNew, &
19240 h_neglect=h_neglect, h_neglect_edge=h_neglect_edge)
1925 endif
1926
19270 if (CS%integrate_downward_for_e) then
19280 zOld(1) = 0.
19290 do k = 1,nz
19300 zOld(k+1) = zOld(k) - h(i,j,k)
1931 enddo
1932 else
1933 ! The rest of the model defines grids integrating up from the bottom
19340 zOld(nz+1) = - nominalDepth
19350 do k = nz,1,-1
19360 zOld(k) = zOld(k+1) + h(i,j,k)
1937 enddo
1938 endif
1939
1940 ! Calculate the final change in grid position after blending new and old grids
19410 if (CS%use_depth_based_time_filter .or. CS%old_grid_weight>0.) &
19420 call filtered_grid_motion(CS, nz, zOld, zNew, dzInterface(i,j,:))
1943
1944#ifdef __DO_SAFETY_CHECKS__
1945 do k=2,CS%nk
1946 if (zNew(k) > zOld(1)) then
1947 write(0,*) 'zOld=',zOld
1948 write(0,*) 'zNew=',zNew
1949 call MOM_error( FATAL, 'MOM_regridding, build_rho_grid: '//&
1950 'interior interface above surface!' )
1951 endif
1952 if (zNew(k) > zNew(k-1)) then
1953 write(0,*) 'zOld=',zOld
1954 write(0,*) 'zNew=',zNew
1955 call MOM_error( FATAL, 'MOM_regridding, build_rho_grid: '//&
1956 'interior interfaces cross!' )
1957 endif
1958 enddo
1959
1960 totalThickness = 0.0
1961 do k = 1,nz
1962 totalThickness = totalThickness + h(i,j,k)
1963 enddo
1964
1965 dh = max(nominalDepth, totalThickness)
1966 if (abs(zNew(1)-zOld(1)) > (nz-1)*0.5*epsilon(dh)*dh) then
1967 write(0,*) 'min_thickness=',CS%min_thickness
1968 write(0,*) 'nominalDepth=',nominalDepth,'totalThickness=',totalThickness
1969 write(0,*) 'zNew(1)-zOld(1) = ',zNew(1)-zOld(1),epsilon(dh),nz
1970 do k=1,min(nz,CS%nk)+1
1971 write(0,*) k,zOld(k),zNew(k)
1972 enddo
1973 do k=min(nz,CS%nk)+2,CS%nk+1
1974 write(0,*) k,zOld(nz+1),zNew(k)
1975 enddo
1976 do k=1,nz
1977 write(0,*) k,h(i,j,k),zNew(k)-zNew(k+1)
1978 enddo
1979 do k=min(nz,CS%nk)+1,CS%nk
1980 write(0,*) k, 0.0, zNew(k)-zNew(k+1), CS%coordinateResolution(k)
1981 enddo
1982 call MOM_error( FATAL, &
1983 'MOM_regridding, build_rho_grid: top surface has moved!!!' )
1984 endif
1985#endif
1986
1987 enddo ! end loop on i
1988 enddo ! end loop on j
1989
19900end subroutine build_rho_grid
1991
1992!> Builds a simple HyCOM-like grid with the deepest location of potential
1993!! density interpolated from the column profile and a clipping of depth for
1994!! each interface to a fixed z* or p* grid. This should probably be (optionally?)
1995!! changed to find the nearest location of the target density.
1996!! \remark { Based on Bleck, 2002: An ocean-ice general circulation model framed in
1997!! hybrid isopycnic-Cartesian coordinates, Ocean Modelling 37, 55-88.
1998!! http://dx.doi.org/10.1016/S1463-5003(01)00012-9 }
19990subroutine build_grid_HyCOM1( G, GV, US, h, nom_depth_H, tv, h_new, dzInterface, remapCS, CS, &
20000 frac_shelf_h, zScale )
2001 type(ocean_grid_type), intent(in) :: G !< Grid structure
2002 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
2003 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2004 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Existing model thickness [H ~> m or kg m-2]
2005 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: nom_depth_H !< The bathymetric depth of this column
2006 !! relative to mean sea level or another locally
2007 !! valid reference height, converted to thickness
2008 !! units [H ~> m or kg m-2]
2009 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamics structure
2010 type(remapping_CS), intent(in) :: remapCS !< The remapping control structure
2011 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2012 real, dimension(SZI_(G),SZJ_(G),CS%nk), intent(inout) :: h_new !< New layer thicknesses [H ~> m or kg m-2]
2013 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< Changes in interface position
2014 !! in thickness units [H ~> m or kg m-2]
2015 real, dimension(SZI_(G),SZJ_(G)), optional, intent(in) :: frac_shelf_h !< Fractional ice shelf
2016 !! coverage [nondim]
2017 real, optional, intent(in) :: zScale !< Scaling factor from the target coordinate
2018 !! resolution in Z to desired units for zInterface,
2019 !! usually Z_to_H in which case it is in
2020 !! units of [H Z-1 ~> nondim or kg m-3]
2021
2022 ! Local variables
20230 real, dimension(SZK_(GV)+1) :: z_col ! Source interface positions relative to the surface [H ~> m or kg m-2]
20240 real, dimension(SZK_(GV)) :: p_col ! Layer center pressure in the input column [R L2 T-2 ~> Pa]
20250 real, dimension(CS%nk+1) :: z_col_new ! New interface positions relative to the surface [H ~> m or kg m-2]
20260 real, dimension(CS%nk+1) :: dz_col ! The realized change in z_col [H ~> m or kg m-2]
2027 real :: nominalDepth ! The nominal depth of the seafloor in thickness units [H ~> m or kg m-2]
2028 real :: h_neglect, h_neglect_edge ! Negligible thicknesses used for remapping [H ~> m or kg m-2]
2029 real :: z_top_col ! The nominal height of the sea surface or ice-ocean interface
2030 ! in thickness units [H ~> m or kg m-2]
2031 real :: totalThickness ! The total thickness of the water column [H ~> m or kg m-2]
2032 logical :: ice_shelf
2033 integer :: i, j, k, nki
2034
20350 h_neglect = set_h_neglect(GV, CS%remap_answer_date, h_neglect_edge)
2036
20370 if (.not.CS%target_density_set) call MOM_error(FATAL, "build_grid_HyCOM1 : "//&
20380 "Target densities must be set before build_grid_HyCOM1 is called.")
2039
20400 nki = min(GV%ke, CS%nk)
20410 ice_shelf = present(frac_shelf_h)
2042
2043 ! Build grid based on target interface densities
20440 do j = G%jsc-1,G%jec+1 ; do i = G%isc-1,G%iec+1
20450 if (G%mask2dT(i,j)>0.) then
2046
20470 nominalDepth = nom_depth_H(i,j)
2048
20490 if (ice_shelf) then
20500 totalThickness = 0.0
20510 do k=1,GV%ke
20520 totalThickness = totalThickness + h(i,j,k)
2053 enddo
20540 z_top_col = max(nominalDepth-totalThickness,0.0)
2055 else
20560 z_top_col = 0.0
2057 endif
2058
20590 z_col(1) = z_top_col ! Work downward rather than bottom up
20600 do K = 1, GV%ke
20610 z_col(K+1) = z_col(K) + h(i,j,k)
2062 p_col(k) = tv%P_Ref + CS%compressibility_fraction * &
20630 ( 0.5 * ( z_col(K) + z_col(K+1) ) * (GV%H_to_RZ*GV%g_Earth) - tv%P_Ref )
2064 enddo
2065
2066 call build_hycom1_column(CS%hycom_CS, remapCS, tv%eqn_of_state, GV%ke, i, j, nominalDepth, &
2067 h(i,j,:), tv%T(i,j,:), tv%S(i,j,:), p_col, &
2068 z_col, z_col_new, zScale=zScale, &
20690 h_neglect=h_neglect, h_neglect_edge=h_neglect_edge)
2070
2071 ! Calculate the final change in grid position after blending new and old grids
20720 if (CS%use_depth_based_time_filter .or. CS%old_grid_weight>0.) &
20730 call filtered_grid_motion( CS, GV%ke, z_col, z_col_new, dz_col )
2074
2075 ! This adjusts things robust to round-off errors
20760 dz_col(:) = -dz_col(:)
20770 if (CS%use_adjust_interface_motion) call adjust_interface_motion( CS, GV%ke, h(i,j,:), dz_col(:) )
2078
20790 dzInterface(i,j,1:nki+1) = dz_col(1:nki+1)
20800 if (nki<CS%nk) dzInterface(i,j,nki+2:CS%nk+1) = 0.
2081
2082 else ! on land
20830 dzInterface(i,j,:) = 0.
2084 endif ! mask2dT
2085 enddo ; enddo ! i,j
2086
20870 call calc_h_new_by_dz(CS, G, GV, h, dzInterface, h_new)
2088
20890end subroutine build_grid_HyCOM1
2090
2091!> This subroutine builds an adaptive grid that follows density surfaces where
2092!! possible, subject to constraints on the smoothness of interface heights.
20930subroutine build_grid_adaptive(G, GV, US, h, nom_depth_H, tv, dzInterface, remapCS, CS)
2094 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
2095 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
2096 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2097 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
2098 real, dimension(SZI_(G),SZJ_(G)), intent(in) :: nom_depth_H !< The bathymetric depth of this column
2099 !! relative to mean sea level or another locally
2100 !! valid reference height, converted to thickness
2101 !! units [H ~> m or kg m-2]
2102 type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
2103 !! thermodynamic variables
2104 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2105 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(inout) :: dzInterface !< The change in interface depth
2106 !! [H ~> m or kg m-2]
2107 type(remapping_CS), intent(in) :: remapCS !< The remapping control structure
2108
2109 ! local variables
2110 integer :: i, j, k, nz ! indices and dimension lengths
21110 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: tInt ! Temperature on interfaces [C ~> degC]
21120 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: sInt ! Salinity on interfaces [S ~> ppt]
2113 ! current interface positions and after tendency term is applied
2114 ! positive downward
21150 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: zInt ! Interface depths [H ~> m or kg m-2]
21160 real, dimension(SZK_(GV)+1) :: zNext ! New interface depths [H ~> m or kg m-2]
2117
21180 nz = GV%ke
2119
2120 call assert((GV%ke == CS%nk), "build_grid_adaptive is only written to work "//&
21210 "with the same number of input and target layers.")
2122
2123 ! position surface at z = 0.
21240 zInt(:,:,1) = 0.
2125
2126 ! work on interior interfaces
21270 do K = 2, nz ; do j = G%jsc-2,G%jec+2 ; do i = G%isc-2,G%iec+2
21280 tInt(i,j,K) = 0.5 * (tv%T(i,j,k-1) + tv%T(i,j,k))
21290 sInt(i,j,K) = 0.5 * (tv%S(i,j,k-1) + tv%S(i,j,k))
21300 zInt(i,j,K) = zInt(i,j,K-1) + h(i,j,k-1) ! zInt in [H]
2131 enddo ; enddo ; enddo
2132
2133 ! top and bottom temp/salt interfaces are just the layer
2134 ! average values
21350 tInt(:,:,1) = tv%T(:,:,1) ; tInt(:,:,nz+1) = tv%T(:,:,nz)
21360 sInt(:,:,1) = tv%S(:,:,1) ; sInt(:,:,nz+1) = tv%S(:,:,nz)
2137
2138 ! set the bottom interface depth
21390 zInt(:,:,nz+1) = zInt(:,:,nz) + h(:,:,nz)
2140
2141 ! calculate horizontal density derivatives (alpha/beta)
2142 ! between cells in a 5-point stencil, columnwise
21430 do j = G%jsc-1,G%jec+1 ; do i = G%isc-1,G%iec+1
21440 if (G%mask2dT(i,j) < 0.5) then
21450 dzInterface(i,j,:) = 0. ! land point, don't move interfaces, and skip
21460 cycle
2147 endif
2148
2149 call build_adapt_column(CS%adapt_CS, G, GV, US, tv, i, j, zInt, tInt, sInt, h, &
21500 nom_depth_H, zNext)
2151
21520 if (CS%use_depth_based_time_filter .or. CS%old_grid_weight>0.) &
21530 call filtered_grid_motion(CS, nz, zInt(i,j,:), zNext, dzInterface(i,j,:))
2154 ! convert from depth to z
21550 do K = 1, nz+1 ; dzInterface(i,j,K) = -dzInterface(i,j,K) ; enddo
21560 if (CS%use_adjust_interface_motion) call adjust_interface_motion(CS, nz, h(i,j,:), dzInterface(i,j,:))
2157 enddo ; enddo
21580end subroutine build_grid_adaptive
2159
2160!> Adjust dz_Interface to ensure non-negative future thicknesses
216165650subroutine adjust_interface_motion( CS, nk, h_old, dz_int )
2162 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2163 integer, intent(in) :: nk !< Number of layers in h_old
2164 real, dimension(nk), intent(in) :: h_old !< Layer thicknesses on the old grid [H ~> m or kg m-2]
2165 real, dimension(CS%nk+1), intent(inout) :: dz_int !< Interface movements, adjusted to keep the thicknesses
2166 !! thicker than their minimum value [H ~> m or kg m-2]
2167 ! Local variables
2168 real :: h_new ! A layer thickness on the new grid [H ~> m or kg m-2]
2169 real :: eps ! A tiny relative thickness [nondim]
2170 real :: h_total ! The total thickness of the old grid [H ~> m or kg m-2]
2171 real :: h_err ! An error tolerance that use used to flag unacceptably large negative layer thicknesses
2172 ! that can not be explained by roundoff errors [H ~> m or kg m-2]
2173 integer :: k
2174
217565650 eps = 1. ; eps = epsilon(eps)
2176
217765650 h_total = 0. ; h_err = 0.
21784989400 do k = 1, min(CS%nk,nk)
21794923750 h_total = h_total + h_old(k)
21804923750 h_err = h_err + max( h_old(k), abs(dz_int(k)), abs(dz_int(k+1)) )*eps
21814923750 h_new = h_old(k) + ( dz_int(k) - dz_int(k+1) )
21824989400 if (h_new < -3.0*h_err) then
21830 write(0,*) 'h<0 at k=',k,'h_old=',h_old(k), &
21840 'wup=',dz_int(k),'wdn=',dz_int(k+1),'dw_dz=',dz_int(k) - dz_int(k+1), &
21850 'h_new=',h_new,'h_err=',h_err
2186 call MOM_error( FATAL, 'MOM_regridding: adjust_interface_motion() - '//&
21870 'implied h<0 is larger than roundoff!')
2188 endif
2189 enddo
219065650 if (CS%nk>nk) then
21910 do k = nk+1, CS%nk
21920 h_err = h_err + max( abs(dz_int(k)), abs(dz_int(k+1)) )*eps
21930 h_new = ( dz_int(k) - dz_int(k+1) )
21940 if (h_new < -3.0*h_err) then
21950 write(0,*) 'h<0 at k=',k,'h_old was empty',&
21960 'wup=',dz_int(k),'wdn=',dz_int(k+1),'dw_dz=',dz_int(k) - dz_int(k+1), &
21970 'h_new=',h_new,'h_err=',h_err
2198 call MOM_error( FATAL, 'MOM_regridding: adjust_interface_motion() - '//&
21990 'implied h<0 is larger than roundoff!')
2200 endif
2201 enddo
2202 endif
22034923750 do k = min(CS%nk,nk),2,-1
22044858100 h_new = h_old(k) + ( dz_int(k) - dz_int(k+1) )
22054858100 if (h_new<CS%min_thickness) &
2206886070 dz_int(k) = ( dz_int(k+1) - h_old(k) ) + CS%min_thickness ! Implies next h_new = min_thickness
22074858100 h_new = h_old(k) + ( dz_int(k) - dz_int(k+1) )
22084858100 if (h_new<0.) &
22090 dz_int(k) = ( 1. - eps ) * ( dz_int(k+1) - h_old(k) ) ! Backup in case min_thickness==0
22104858100 h_new = h_old(k) + ( dz_int(k) - dz_int(k+1) )
22114923750 if (h_new<0.) then
22120 write(0,*) 'h<0 at k=',k,'h_old=',h_old(k), &
22130 'wup=',dz_int(k),'wdn=',dz_int(k+1),'dw_dz=',dz_int(k) - dz_int(k+1), &
22140 'h_new=',h_new
22150 stop 'Still did not work!'
2216 call MOM_error( FATAL, 'MOM_regridding: adjust_interface_motion() - '//&
2217 'Repeated adjustment for roundoff h<0 failed!')
2218 endif
2219 enddo
2220 !if (dz_int(1)/=0.) stop 'MOM_regridding: adjust_interface_motion() surface moved'
2221
222265650end subroutine adjust_interface_motion
2223
2224
2225!------------------------------------------------------------------------------
2226!> make sure all layers are at least as thick as the minimum thickness allowed
2227!! for regridding purposes by inflating thin layers. This breaks mass conservation
2228!! and adds mass to the model when there are excessively thin layers.
22291subroutine inflate_vanished_layers_old( CS, G, GV, h )
2230!------------------------------------------------------------------------------
2231! This routine is called when initializing the regridding options. The
2232! objective is to make sure all layers are at least as thick as the minimum
2233! thickness allowed for regridding purposes (this parameter is set in the
2234! MOM_input file or defaulted to 1.0e-3). When layers are too thin, they
2235! are inflated up to the minimum thickness.
2236!------------------------------------------------------------------------------
2237
2238 ! Arguments
2239 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2240 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
2241 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
2242 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2]
2243
2244 ! Local variables
2245 integer :: i, j, k
22462 real :: hTmp(GV%ke) ! A copy of a 1-d column of h [H ~> m or kg m-2]
2247
2248123 do i = G%isc-1,G%iec+1
22497687 do j = G%jsc-1,G%jec+1
2250
2251 ! Build grid for current column
2252574864 do k = 1,GV%ke
2253574864 hTmp(k) = h(i,j,k)
2254 enddo
2255
22567564 call old_inflate_layers_1d( CS%min_thickness, GV%ke, hTmp )
2257
2258 ! Save modified grid
2259574986 do k = 1,GV%ke
2260574864 h(i,j,k) = hTmp(k)
2261 enddo
2262
2263 enddo
2264 enddo
2265
22661end subroutine inflate_vanished_layers_old
2267
2268!------------------------------------------------------------------------------
2269!> Achieve convective adjustment by swapping layers
22700subroutine convective_adjustment(G, GV, h, tv)
2271 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
2272 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
2273 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2274 intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2]
2275 type(thermo_var_ptrs), intent(inout) :: tv !< A structure pointing to various thermodynamic variables
2276!------------------------------------------------------------------------------
2277! Check each water column to see whether it is stratified. If not, sort the
2278! layers by successive swappings of water masses (bubble sort algorithm)
2279!------------------------------------------------------------------------------
2280
2281 ! Local variables
2282 real :: T0, T1 ! temperatures of two layers [C ~> degC]
2283 real :: S0, S1 ! salinities of two layers [S ~> ppt]
2284 real :: r0, r1 ! densities of two layers [R ~> kg m-3]
2285 real :: h0, h1 ! Layer thicknesses [H ~> m or kg m-2]
22860 real, dimension(GV%ke) :: p_col ! A column of zero pressures [R L2 T-2 ~> Pa]
22870 real, dimension(GV%ke) :: densities ! Densities in the column [R ~> kg m-3]
2288 logical :: stratified
2289 integer :: i, j, k
2290
2291 !### Doing convective adjustment based on potential densities with zero pressure seems
2292 ! questionable, although it does avoid ambiguous sorting. -RWH
22930 p_col(:) = 0.
2294
2295 ! Loop on columns
22960 do j = G%jsc-1,G%jec+1 ; do i = G%isc-1,G%iec+1
2297
2298 ! Compute densities within current water column
22990 call calculate_density(tv%T(i,j,:), tv%S(i,j,:), p_col, densities, tv%eqn_of_state)
2300
2301 ! Repeat restratification until complete
23020 do
23030 stratified = .true.
23040 do k = 1,GV%ke-1
2305 ! Gather information of current and next cells
23060 T0 = tv%T(i,j,k) ; T1 = tv%T(i,j,k+1)
23070 S0 = tv%S(i,j,k) ; S1 = tv%S(i,j,k+1)
23080 r0 = densities(k) ; r1 = densities(k+1)
23090 h0 = h(i,j,k) ; h1 = h(i,j,k+1)
2310 ! If the density of the current cell is larger than the density
2311 ! below it, we swap the cells and recalculate the densitiies
2312 ! within the swapped cells
23130 if ( r0 > r1 ) then
23140 tv%T(i,j,k) = T1 ; tv%T(i,j,k+1) = T0
23150 tv%S(i,j,k) = S1 ; tv%S(i,j,k+1) = S0
23160 h(i,j,k) = h1 ; h(i,j,k+1) = h0
2317 ! Recompute densities at levels k and k+1
2318 call calculate_density(tv%T(i,j,k), tv%S(i,j,k), p_col(k), &
23190 densities(k), tv%eqn_of_state)
2320 call calculate_density(tv%T(i,j,k+1), tv%S(i,j,k+1), p_col(k+1), &
23210 densities(k+1), tv%eqn_of_state )
2322 ! Because p_col is has uniform values, these calculate_density calls are equivalent to
2323 ! densities(k) = r1 ; densities(k+1) = r0
23240 stratified = .false.
2325 endif
2326 enddo ! k
2327
23280 if ( stratified ) exit
2329 enddo
2330
2331 enddo ; enddo ! i & j
2332
23330end subroutine convective_adjustment
2334
2335
2336!------------------------------------------------------------------------------
2337!> Return a uniform resolution vector in the units of the coordinate
23380function uniformResolution(nk,coordMode,maxDepth,rhoLight,rhoHeavy)
2339!------------------------------------------------------------------------------
2340! Calculate a vector of uniform resolution in the units of the coordinate
2341!------------------------------------------------------------------------------
2342 ! Arguments
2343 integer, intent(in) :: nk !< Number of cells in source grid
2344 character(len=*), intent(in) :: coordMode !< A string indicating the coordinate mode.
2345 !! See the documentation for regrid_consts
2346 !! for the recognized values.
2347 real, intent(in) :: maxDepth !< The range of the grid values in some modes, in coordinate
2348 !! dependent units that might be [m] or [kg m-3] or [nondim]
2349 !! or something else.
2350 real, intent(in) :: rhoLight !< The minimum value of the grid in RHO mode [kg m-3]
2351 real, intent(in) :: rhoHeavy !< The maximum value of the grid in RHO mode [kg m-3]
2352
2353 real :: uniformResolution(nk) !< The returned uniform resolution grid, in
2354 !! coordinate dependent units that might be [m] or
2355 !! [kg m-3] or [nondim] or something else.
2356
2357 ! Local variables
2358 integer :: scheme
2359
23600 scheme = coordinateMode(coordMode)
23610 select case ( scheme )
2362
2363 case ( REGRIDDING_ZSTAR, REGRIDDING_HYCOM1, REGRIDDING_HYBGEN, &
2364 REGRIDDING_SIGMA_SHELF_ZSTAR, REGRIDDING_ADAPTIVE )
23650 uniformResolution(:) = maxDepth / real(nk)
2366
2367 case ( REGRIDDING_RHO )
23680 uniformResolution(:) = (rhoHeavy - rhoLight) / real(nk)
2369
2370 case ( REGRIDDING_SIGMA )
23710 uniformResolution(:) = 1. / real(nk)
2372
2373 case default
2374 call MOM_error(FATAL, "MOM_regridding, uniformResolution: "//&
23750 "Unrecognized choice for coordinate mode ("//trim(coordMode)//").")
2376
2377 end select ! type of grid
2378
2379end function uniformResolution
2380
2381!> Initialize the coordinate resolutions by calling the appropriate initialization
2382!! routine for the specified coordinate mode.
23832subroutine initCoord(CS, G, GV, US, coord_mode, param_file)
2384 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2385 type(ocean_grid_type), intent(in) :: G !< Ocean grid structure
2386 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
2387 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2388 character(len=*), intent(in) :: coord_mode !< A string indicating the coordinate mode.
2389 !! See the documentation for regrid_consts
2390 !! for the recognized values.
2391 type(param_file_type), intent(in) :: param_file !< Parameter file
2392
23932 select case (coordinateMode(coord_mode))
2394 case (REGRIDDING_ZSTAR)
23952 call init_coord_zlike(CS%zlike_CS, CS%nk, CS%coordinateResolution)
2396 case (REGRIDDING_SIGMA_SHELF_ZSTAR)
23970 call init_coord_zlike(CS%zlike_CS, CS%nk, CS%coordinateResolution)
2398 case (REGRIDDING_SIGMA)
23990 call init_coord_sigma(CS%sigma_CS, CS%nk, CS%coordinateResolution)
2400 case (REGRIDDING_RHO)
24010 call init_coord_rho(CS%rho_CS, CS%nk, CS%ref_pressure, CS%target_density, CS%interp_CS)
2402 case (REGRIDDING_HYCOM1)
24030 if (allocated(CS%coordinateResolution_3d)) then
2404 call init_3d_coord_hycom(CS%hycom_CS, G, CS%nk, &
2405 CS%coordinateResolution_3d, CS%target_density_3d, &
24060 CS%interp_CS)
2407 else
2408 call init_coord_hycom(CS%hycom_CS, CS%nk, CS%coordinateResolution, CS%target_density, &
24090 CS%interp_CS)
2410 endif
2411 case (REGRIDDING_HYBGEN)
24120 call init_hybgen_regrid(CS%hybgen_CS, GV, US, param_file)
2413 case (REGRIDDING_ADAPTIVE)
24142 call init_coord_adapt(CS%adapt_CS, CS%nk, CS%coordinateResolution, GV%m_to_H, US%kg_m3_to_R)
2415 end select
24162end subroutine initCoord
2417
2418!------------------------------------------------------------------------------
2419!> Set the fixed resolution data
24202subroutine setCoordinateResolution( dz, CS, scale )
2421 real, dimension(:), intent(in) :: dz !< A vector of vertical grid spacings, in arbitrary coordinate
2422 !! dependent units, such as [m] for a z-coordinate or [kg m-3]
2423 !! for a density coordinate.
2424 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2425 real, optional, intent(in) :: scale !< A scaling factor converting dz to the internal represetation
2426 !! of coordRes, in various units that depend on the coordinate,
2427 !! such as [Z m-1 ~> 1] for a z-coordinate or [R m3 kg-1 ~> 1] for
2428 !! a density coordinate.
2429
24302 if (size(dz)/=CS%nk) call MOM_error( FATAL, &
24310 'setCoordinateResolution: inconsistent number of levels' )
2432
24332 if (present(scale)) then
2434110 CS%coordinateResolution(:) = scale*dz(:)
2435 else
24360 CS%coordinateResolution(:) = dz(:)
2437 endif
2438
24392end subroutine setCoordinateResolution
2440
2441!> Set the 3d fixed resolution data
24420subroutine setCoordinateResolution_3d( dz_3d, CS, scale )
2443 real, dimension(:,:,:), intent(in) :: dz_3d !< A vector of vertical grid spacings, in arbitrary coordinate
2444 !! dependent units, such as [m] for a z-coordinate or [kg m-3]
2445 !! for a density coordinate.
2446 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2447 real, optional, intent(in) :: scale !< A scaling factor converting dz to coordRes [Z m-1 ~> 1]
2448
24490 if (.not.allocated(CS%coordinateResolution_3d)) &
2450 call MOM_error(FATAL,'setCoordinateResolution_3d: '//&
24510 'CS%coordinateResolution_3d not allocated.')
2452
24530 if (present(scale)) then
24540 CS%coordinateResolution_3d(:,:,:) = scale*dz_3d(:,:,:)
2455 else
24560 CS%coordinateResolution_3d(:,:,:) = dz_3d(:,:,:)
2457 endif
2458
24590end subroutine setCoordinateResolution_3d
2460
2461!> Set target densities based on the old Rlay variable
24620subroutine set_target_densities_from_GV( GV, US, CS )
2463 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
2464 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2465 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2466 ! Local variables
2467 integer :: k, nz
2468
24690 nz = CS%nk
24700 if (nz == 1) then ! Set a broad range of bounds. Regridding may not be meaningful in this case.
24710 CS%target_density(1) = 0.0
24720 CS%target_density(2) = 2.0*GV%Rlay(1)
2473 else
24740 CS%target_density(1) = (GV%Rlay(1) + 0.5*(GV%Rlay(1)-GV%Rlay(2)))
24750 CS%target_density(nz+1) = (GV%Rlay(nz) + 0.5*(GV%Rlay(nz)-GV%Rlay(nz-1)))
24760 do k=2,nz
24770 CS%target_density(k) = CS%target_density(k-1) + CS%coordinateResolution(k)
2478 enddo
2479 endif
24800 CS%target_density_set = .true.
2481
24820end subroutine set_target_densities_from_GV
2483
2484!> Set target densities based on vector of interface values
24850subroutine set_target_densities_3d( CS, G, scale, rho_int_3d )
2486 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2487 type(ocean_grid_type),intent(in) :: G !< Ocean grid structure
2488 real, intent(in) :: scale !< A scaling factor converting densities [R m3 kg-1 ~> 1]
2489 real, dimension(SZI_(G),SZJ_(G),CS%nk+1), intent(in) :: rho_int_3d !< Interface densities [kg m-3]
2490
24910 if (.not.allocated(CS%target_density_3d)) &
2492 call MOM_error(FATAL,'set_target_densities_3d: '//&
24930 'CS%target_density_3d not allocated.')
2494
24950 CS%target_density_3d(:,:,:) = scale * rho_int_3d(:,:,:)
24960 CS%target_density_set = .true.
2497
24980end subroutine set_target_densities_3d
2499
2500!> Set target densities based on vector of interface values
25010subroutine set_target_densities( CS, rho_int )
2502 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2503 real, dimension(CS%nk+1), intent(in) :: rho_int !< Interface densities [R ~> kg m-3]
2504
25050 if (size(CS%target_density)/=size(rho_int)) then
25060 call MOM_error(FATAL, "set_target_densities inconsistent args!")
2507 endif
2508
25090 CS%target_density(:) = rho_int(:)
25100 CS%target_density_set = .true.
2511
25120end subroutine set_target_densities
2513
2514!> Set maximum interface depths based on a vector of input values.
25150subroutine set_regrid_max_depths( CS, max_depths, units_to_H )
2516 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2517 real, dimension(CS%nk+1), intent(in) :: max_depths !< Maximum interface depths, in arbitrary units, often [m]
2518 real, optional, intent(in) :: units_to_H !< A conversion factor for max_depths into H units,
2519 !! often in [H m-1 ~> 1 or kg m-3]
2520 ! Local variables
2521 real :: val_to_H ! A conversion factor from the units for max_depths into H units, often [H m-1 ~> 1 or kg m-3]
2522 ! if units_to_H is present, or [nondim] if it is absent.
2523 integer :: K
2524
25250 if (.not.allocated(CS%max_interface_depths)) allocate(CS%max_interface_depths(1:CS%nk+1))
2526
25270 val_to_H = 1.0 ; if (present(units_to_H)) val_to_H = units_to_H
25280 if (max_depths(CS%nk+1) < max_depths(1)) val_to_H = -1.0*val_to_H
2529
2530 ! Check for sign reversals in the depths.
25310 if (max_depths(CS%nk+1) < max_depths(1)) then
25320 do K=1,CS%nk
25330 if (max_depths(K+1) > max_depths(K)) &
25340 call MOM_error(FATAL, "Unordered list of maximum depths sent to set_regrid_max_depths!")
2535 enddo
2536 else
25370 do K=1,CS%nk
25380 if (max_depths(K+1) < max_depths(K)) &
25390 call MOM_error(FATAL, "Unordered list of maximum depths sent to set_regrid_max_depths.")
2540 enddo
2541 endif
2542
25430 do K=1,CS%nk+1
25440 CS%max_interface_depths(K) = val_to_H * max_depths(K)
2545 enddo
2546
2547 ! set max depths for coordinate
25480 select case (CS%regridding_scheme)
2549 case (REGRIDDING_HYCOM1)
25500 call set_hycom_params(CS%hycom_CS, max_interface_depths=CS%max_interface_depths)
2551 end select
25520end subroutine set_regrid_max_depths
2553
2554!> Set maximum layer thicknesses based on a vector of input values.
25550subroutine set_regrid_max_thickness( CS, max_h, units_to_H )
2556 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2557 real, dimension(CS%nk+1), intent(in) :: max_h !< Maximum layer thicknesses, in arbitrary units, often [m]
2558 real, optional, intent(in) :: units_to_H !< A conversion factor for max_h into H units,
2559 !! often [H m-1 ~> 1 or kg m-3]
2560 ! Local variables
2561 real :: val_to_H ! A conversion factor from the units for max_h into H units, often [H m-1 ~> 1 or kg m-3]
2562 ! if units_to_H is present, or [nondim] if it is absent.
2563 integer :: k
2564
25650 if (.not.allocated(CS%max_layer_thickness)) allocate(CS%max_layer_thickness(1:CS%nk))
2566
25670 val_to_H = 1.0 ; if (present( units_to_H)) val_to_H = units_to_H
2568
25690 do k=1,CS%nk
25700 CS%max_layer_thickness(k) = val_to_H * max_h(k)
2571 enddo
2572
2573 ! set max thickness for coordinate
25740 select case (CS%regridding_scheme)
2575 case (REGRIDDING_HYCOM1)
25760 call set_hycom_params(CS%hycom_CS, max_layer_thickness=CS%max_layer_thickness)
2577 end select
25780end subroutine set_regrid_max_thickness
2579
2580
2581!> Write the vertical coordinate information into a file.
2582!! This subroutine writes out a file containing any available data related
2583!! to the vertical grid used by the MOM ocean model when in ALE mode.
25841subroutine write_regrid_file( CS, GV, filepath )
2585 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2586 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
2587 character(len=*), intent(in) :: filepath !< The full path to the file to write
2588
258931 type(vardesc) :: vars(2)
25906 type(MOM_field) :: fields(2)
25911 type(MOM_netCDF_file) :: IO_handle ! The I/O handle of the fileset
25922 real :: ds(GV%ke), dsi(GV%ke+1) ! The labeling layer and interface coordinates for output
2593 ! in axes in files, in coordinate-dependent units that can
2594 ! be obtained from getCoordinateUnits [various]
2595
25961 if (CS%regridding_scheme == REGRIDDING_HYBGEN) then
25970 call write_Hybgen_coord_file(GV, CS%hybgen_CS, filepath)
25980 return
2599 endif
2600
260176 ds(:) = CS%coord_scale * CS%coordinateResolution(:)
26021 dsi(1) = 0.5*ds(1)
260375 dsi(2:GV%ke) = 0.5*( ds(1:GV%ke-1) + ds(2:GV%ke) )
26041 dsi(GV%ke+1) = 0.5*ds(GV%ke)
2605
2606 vars(1) = var_desc('ds', getCoordinateUnits( CS ), &
26076 'Layer Coordinate Thickness', '1', 'L', '1')
2608 vars(2) = var_desc('ds_interface', getCoordinateUnits( CS ), &
26096 'Layer Center Coordinate Separation', '1', 'i', '1')
2610
2611 call create_MOM_file(IO_handle, trim(filepath), vars, 2, fields, &
26121 SINGLE_FILE, GV=GV)
26131 call MOM_write_field(IO_handle, fields(1), ds)
26141 call MOM_write_field(IO_handle, fields(2), dsi)
26151 call IO_handle%close()
2616
26172end subroutine write_regrid_file
2618
2619!> Set appropriate values for the negligible thicknesses used for remapping based on an answer date.
2620193function set_h_neglect(GV, remap_answer_date, h_neglect_edge) result(h_neglect)
2621 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
2622 integer, intent(in) :: remap_answer_date !< The vintage of the expressions to use
2623 !! for remapping. Values below 20190101 recover the
2624 !! remapping answers from 2018. Higher values use more
2625 !! robust forms of the same remapping algorithms.
2626 real, intent(out) :: h_neglect_edge !< A negligibly small thickness used in
2627 !! remapping edge value calculations [H ~> m or kg m-2]
2628 real :: h_neglect !< A negligibly small thickness used in
2629 !! remapping cell reconstructions [H ~> m or kg m-2]
2630
2631193 if (remap_answer_date >= 20190101) then
2632193 h_neglect = GV%H_subroundoff ; h_neglect_edge = GV%H_subroundoff
26330 elseif (GV%Boussinesq) then
26340 h_neglect = GV%m_to_H*1.0e-30 ; h_neglect_edge = GV%m_to_H*1.0e-10
2635 else
26360 h_neglect = GV%kg_m2_to_H*1.0e-30 ; h_neglect_edge = GV%kg_m2_to_H*1.0e-10
2637 endif
2638193end function set_h_neglect
2639
2640!> Set appropriate values for the negligible vertical layer extents used for remapping based on an answer date.
26410function set_dz_neglect(GV, US, remap_answer_date, dz_neglect_edge) result(dz_neglect)
2642 type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
2643 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2644 integer, intent(in) :: remap_answer_date !< The vintage of the expressions to use
2645 !! for remapping. Values below 20190101 recover the
2646 !! remapping answers from 2018. Higher values use more
2647 !! robust forms of the same remapping algorithms.
2648 real, intent(out) :: dz_neglect_edge !< A negligibly small vertical layer extent
2649 !! used in remapping edge value calculations [Z ~> m]
2650 real :: dz_neglect !< A negligibly small vertical layer extent
2651 !! used in remapping cell reconstructions [Z ~> m]
2652
26530 if (remap_answer_date >= 20190101) then
26540 dz_neglect = GV%dZ_subroundoff ; dz_neglect_edge = GV%dZ_subroundoff
26550 elseif (GV%Boussinesq) then
26560 dz_neglect = US%m_to_Z*1.0e-30 ; dz_neglect_edge = US%m_to_Z*1.0e-10
2657 else
26580 dz_neglect = GV%kg_m2_to_H * (GV%H_to_m*US%m_to_Z) * 1.0e-30
26590 dz_neglect_edge = GV%kg_m2_to_H * (GV%H_to_m*US%m_to_Z) * 1.0e-10
2660 endif
26610end function set_dz_neglect
2662
2663!------------------------------------------------------------------------------
2664!> Query the fixed resolution data
26650function getCoordinateResolution( CS, undo_scaling )
2666 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2667 logical, optional, intent(in) :: undo_scaling !< If present and true, undo any internal
2668 !! rescaling of the resolution data.
2669 real, dimension(CS%nk) :: getCoordinateResolution !< The resolution or delta of the target coordinate,
2670 !! in units that depend on the coordinate [various]
2671
2672 logical :: unscale
26730 unscale = .false. ; if (present(undo_scaling)) unscale = undo_scaling
2674
26750 if (unscale) then
26760 getCoordinateResolution(:) = CS%coord_scale * CS%coordinateResolution(:)
2677 else
26780 getCoordinateResolution(:) = CS%coordinateResolution(:)
2679 endif
2680
2681end function getCoordinateResolution
2682
2683!> Query the target coordinate interface positions
26842function getCoordinateInterfaces( CS, undo_scaling )
2685 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2686 logical, optional, intent(in) :: undo_scaling !< If present and true, undo any internal
2687 !! rescaling of the resolution data.
2688 real, dimension(CS%nk+1) :: getCoordinateInterfaces !< Interface positions in target coordinate,
2689 !! in units that depend on the coordinate [various]
2690
2691 integer :: k
2692 logical :: unscale
26932 unscale = .false. ; if (present(undo_scaling)) unscale = undo_scaling
2694
2695 ! When using a coordinate with target densities, we need to get the actual
2696 ! densities, rather than computing the interfaces based on resolution
26972 if (CS%regridding_scheme == REGRIDDING_RHO) then
26980 if (.not. CS%target_density_set) &
2699 call MOM_error(FATAL, 'MOM_regridding, getCoordinateInterfaces: '//&
27000 'target densities not set!')
2701
27020 if (unscale) then
27030 getCoordinateInterfaces(:) = CS%coord_scale * CS%target_density(:)
2704 else
27050 getCoordinateInterfaces(:) = CS%target_density(:)
2706 endif
2707 else
27082 if (unscale) then
27092 getCoordinateInterfaces(1) = 0.
2710110 do k = 1, CS%nk
2711 getCoordinateInterfaces(K+1) = getCoordinateInterfaces(K) - &
2712110 CS%coord_scale * CS%coordinateResolution(k)
2713 enddo
2714 else
27150 getCoordinateInterfaces(1) = 0.
27160 do k = 1, CS%nk
2717 getCoordinateInterfaces(K+1) = getCoordinateInterfaces(K) - &
27180 CS%coordinateResolution(k)
2719 enddo
2720 endif
2721 ! The following line has an "abs()" to allow ferret users to reference
2722 ! data by index. It is a temporary work around... :( -AJA
2723112 getCoordinateInterfaces(:) = abs( getCoordinateInterfaces(:) )
2724 endif
2725
2726end function getCoordinateInterfaces
2727
2728!------------------------------------------------------------------------------
2729!> Query the target coordinate units
27303function getCoordinateUnits( CS )
2731 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2732 character(len=20) :: getCoordinateUnits
2733
27346 select case ( CS%regridding_scheme )
2735 case ( REGRIDDING_ZSTAR, REGRIDDING_HYCOM1, REGRIDDING_HYBGEN, &
2736 REGRIDDING_ADAPTIVE )
27373 getCoordinateUnits = 'meter'
2738 case ( REGRIDDING_SIGMA_SHELF_ZSTAR )
27390 getCoordinateUnits = 'meter/fraction'
2740 case ( REGRIDDING_SIGMA )
27410 getCoordinateUnits = 'fraction'
2742 case ( REGRIDDING_RHO )
27430 getCoordinateUnits = 'kg/m3'
2744 case ( REGRIDDING_ARBITRARY )
27450 getCoordinateUnits = 'unknown'
2746 case default
2747 call MOM_error(FATAL,'MOM_regridding, getCoordinateUnits: '//&
27483 'Unknown regridding scheme selected!')
2749 end select ! type of grid
2750
27513end function getCoordinateUnits
2752
2753!------------------------------------------------------------------------------
2754!> Query the short name of the coordinate
27551function getCoordinateShortName( CS )
2756 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2757 character(len=20) :: getCoordinateShortName
2758
27592 select case ( CS%regridding_scheme )
2760 case ( REGRIDDING_ZSTAR )
2761 !getCoordinateShortName = 'z*'
2762 ! The following line is a temporary work around... :( -AJA
27631 getCoordinateShortName = 'pseudo-depth, -z*'
2764 case ( REGRIDDING_SIGMA_SHELF_ZSTAR )
27650 getCoordinateShortName = 'pseudo-depth, -z*/sigma'
2766 case ( REGRIDDING_SIGMA )
27670 getCoordinateShortName = 'sigma'
2768 case ( REGRIDDING_RHO )
27690 getCoordinateShortName = 'rho'
2770 case ( REGRIDDING_ARBITRARY )
27710 getCoordinateShortName = 'coordinate'
2772 case ( REGRIDDING_HYCOM1 )
27730 getCoordinateShortName = 'z-rho'
2774 case ( REGRIDDING_HYBGEN )
27750 getCoordinateShortName = 'hybrid'
2776 case ( REGRIDDING_ADAPTIVE )
27770 getCoordinateShortName = 'adaptive'
2778 case default
2779 call MOM_error(FATAL,'MOM_regridding, getCoordinateShortName: '//&
27801 'Unknown regridding scheme selected!')
2781 end select ! type of grid
2782
27831end function getCoordinateShortName
2784
2785!> Can be used to set any of the parameters for MOM_regridding.
278623subroutine set_regrid_params( CS, boundary_extrapolation, min_thickness, old_grid_weight, &
2787 use_depth_based_time_filter, depth_of_time_filter_shallow, depth_of_time_filter_deep, &
2788 interp_scheme, use_adjust_interface_motion, compress_fraction, ref_pressure, &
2789 integrate_downward_for_e, remap_answers_2018, remap_answer_date, regrid_answer_date, &
2790 adaptTimeRatio, adaptZoom, adaptZoomCoeff, adaptBuoyCoeff, &
2791 adaptAlpha, adaptDoMin, adaptDrho0)
2792 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2793 logical, optional, intent(in) :: boundary_extrapolation !< Extrapolate in boundary cells
2794 real, optional, intent(in) :: min_thickness !< Minimum thickness allowed when building the
2795 !! new grid [H ~> m or kg m-2]
2796 real, optional, intent(in) :: old_grid_weight !< Weight given to old coordinate when time-filtering grid [nondim]
2797 logical, optional, intent(in) :: use_depth_based_time_filter !< Allow depth-based time filtering
2798 real, optional, intent(in) :: depth_of_time_filter_shallow !< Depth to start cubic [H ~> m or kg m-2]
2799 real, optional, intent(in) :: depth_of_time_filter_deep !< Depth to end cubic [H ~> m or kg m-2]
2800 character(len=*), optional, intent(in) :: interp_scheme !< Interpolation method for state-dependent coordinates
2801 logical, optional, intent(in) :: use_adjust_interface_motion !< Call adjust_interface_motion()
2802 real, optional, intent(in) :: compress_fraction !< Fraction of compressibility to add to potential density [nondim]
2803 real, optional, intent(in) :: ref_pressure !< The reference pressure for density-dependent
2804 !! coordinates [R L2 T-2 ~> Pa]
2805 logical, optional, intent(in) :: integrate_downward_for_e !< If true, integrate for interface positions downward
2806 !! from the top.
2807 logical, optional, intent(in) :: remap_answers_2018 !< If true, use the order of arithmetic and expressions
2808 !! that recover the remapping answers from 2018. Otherwise
2809 !! use more robust but mathematically equivalent expressions.
2810 integer, optional, intent(in) :: remap_answer_date !< The vintage of the expressions to use for remapping
2811 integer, optional, intent(in) :: regrid_answer_date !< The vintage of the expressions to use for regridding
2812 real, optional, intent(in) :: adaptTimeRatio !< Ratio of the ALE timestep to the grid timescale [nondim].
2813 real, optional, intent(in) :: adaptZoom !< Depth of near-surface zooming region [H ~> m or kg m-2].
2814 real, optional, intent(in) :: adaptZoomCoeff !< Coefficient of near-surface zooming diffusivity [nondim].
2815 real, optional, intent(in) :: adaptBuoyCoeff !< Coefficient of buoyancy diffusivity [nondim].
2816 real, optional, intent(in) :: adaptAlpha !< Scaling factor on optimization tendency [nondim].
2817 logical, optional, intent(in) :: adaptDoMin !< If true, make a HyCOM-like mixed layer by
2818 !! preventing interfaces from being shallower than
2819 !! the depths specified by the regridding coordinate.
2820 real, optional, intent(in) :: adaptDrho0 !< Reference density difference for stratification-dependent
2821 !! diffusion. [R ~> kg m-3]
2822
28230 if (present(interp_scheme)) call set_interp_scheme(CS%interp_CS, interp_scheme)
282423 if (present(boundary_extrapolation)) call set_interp_extrap(CS%interp_CS, boundary_extrapolation)
282523 if (present(regrid_answer_date)) call set_interp_answer_date(CS%interp_CS, regrid_answer_date)
2826
282723 if (present(old_grid_weight)) then
282812 if (old_grid_weight<0. .or. old_grid_weight>1.) &
28290 call MOM_error(FATAL,'MOM_regridding, set_regrid_params: Weight is out side the range 0..1!')
283012 CS%old_grid_weight = old_grid_weight
2831 endif
283223 if (present(use_depth_based_time_filter)) CS%use_depth_based_time_filter = &
28332 use_depth_based_time_filter
283423 if (present(depth_of_time_filter_shallow)) CS%depth_of_time_filter_shallow = &
28351 depth_of_time_filter_shallow
283623 if (present(depth_of_time_filter_deep)) CS%depth_of_time_filter_deep = &
28371 depth_of_time_filter_deep
283823 if (present(depth_of_time_filter_shallow) .or. present(depth_of_time_filter_deep)) then
28391 if (CS%depth_of_time_filter_deep<CS%depth_of_time_filter_shallow) call MOM_error(FATAL, &
2840 'MOM_regridding, '//&
28410 'set_regrid_params: depth_of_time_filter_deep<depth_of_time_filter_shallow!')
2842 endif
2843
284423 if (present(min_thickness)) CS%min_thickness = min_thickness
284523 if (present(use_adjust_interface_motion)) CS%use_adjust_interface_motion = use_adjust_interface_motion
284623 if (present(compress_fraction)) CS%compressibility_fraction = compress_fraction
284723 if (present(ref_pressure)) CS%ref_pressure = ref_pressure
284823 if (present(integrate_downward_for_e)) CS%integrate_downward_for_e = integrate_downward_for_e
284923 if (present(remap_answers_2018)) then
28500 if (remap_answers_2018) then
28510 CS%remap_answer_date = 20181231
2852 else
28530 CS%remap_answer_date = 20190101
2854 endif
2855 endif
285623 if (present(remap_answer_date)) CS%remap_answer_date = remap_answer_date
2857
285846 select case (CS%regridding_scheme)
2859 case (REGRIDDING_ZSTAR)
286023 if (present(min_thickness)) call set_zlike_params(CS%zlike_CS, min_thickness=min_thickness)
2861 case (REGRIDDING_SIGMA_SHELF_ZSTAR)
28620 if (present(min_thickness)) call set_zlike_params(CS%zlike_CS, min_thickness=min_thickness)
2863 case (REGRIDDING_SIGMA)
28640 if (present(min_thickness)) call set_sigma_params(CS%sigma_CS, min_thickness=min_thickness)
2865 case (REGRIDDING_RHO)
28660 if (present(min_thickness)) call set_rho_params(CS%rho_CS, min_thickness=min_thickness)
28670 if (present(ref_pressure)) call set_rho_params(CS%rho_CS, ref_pressure=ref_pressure)
28680 if (present(integrate_downward_for_e)) &
28690 call set_rho_params(CS%rho_CS, integrate_downward_for_e=integrate_downward_for_e)
28700 if (associated(CS%rho_CS) .and. (present(interp_scheme) .or. &
2871 present(boundary_extrapolation))) &
28720 call set_rho_params(CS%rho_CS, interp_CS=CS%interp_CS)
2873 case (REGRIDDING_HYCOM1)
28740 if (associated(CS%hycom_CS) .and. (present(interp_scheme) .or. &
2875 present(boundary_extrapolation))) &
28760 call set_hycom_params(CS%hycom_CS, interp_CS=CS%interp_CS)
2877 case (REGRIDDING_HYBGEN)
2878 ! Do nothing for now.
2879 case (REGRIDDING_ADAPTIVE)
28800 if (present(adaptTimeRatio)) call set_adapt_params(CS%adapt_CS, adaptTimeRatio=adaptTimeRatio)
28810 if (present(adaptZoom)) call set_adapt_params(CS%adapt_CS, adaptZoom=adaptZoom)
28820 if (present(adaptZoomCoeff)) call set_adapt_params(CS%adapt_CS, adaptZoomCoeff=adaptZoomCoeff)
28830 if (present(adaptBuoyCoeff)) call set_adapt_params(CS%adapt_CS, adaptBuoyCoeff=adaptBuoyCoeff)
28840 if (present(adaptAlpha)) call set_adapt_params(CS%adapt_CS, adaptAlpha=adaptAlpha)
28850 if (present(adaptDoMin)) call set_adapt_params(CS%adapt_CS, adaptDoMin=adaptDoMin)
288623 if (present(adaptDrho0)) call set_adapt_params(CS%adapt_CS, adaptDrho0=adaptDrho0)
2887 end select
2888
288923end subroutine set_regrid_params
2890
2891!> Returns the number of levels/layers in the regridding control structure
28921integer function get_regrid_size(CS)
2893 type(regridding_CS), intent(inout) :: CS !< Regridding control structure
2894
28951 get_regrid_size = CS%nk
2896
28971end function get_regrid_size
2898
2899!> This returns a copy of the zlike_CS stored in the regridding control structure.
2900974650function get_zlike_CS(CS)
2901 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2902 type(zlike_CS) :: get_zlike_CS
2903
2904974650 get_zlike_CS = CS%zlike_CS
29051949300end function get_zlike_CS
2906
2907!> This returns a copy of the sigma_CS stored in the regridding control structure.
29080function get_sigma_CS(CS)
2909 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2910 type(sigma_CS) :: get_sigma_CS
2911
29120 get_sigma_CS = CS%sigma_CS
29130end function get_sigma_CS
2914
2915!> This returns a copy of the rho_CS stored in the regridding control structure.
29160function get_rho_CS(CS)
2917 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2918 type(rho_CS) :: get_rho_CS
2919
29200 get_rho_CS = CS%rho_CS
29210end function get_rho_CS
2922
2923!------------------------------------------------------------------------------
2924!> Return coordinate-derived thicknesses for fixed coordinate systems
29250function getStaticThickness( CS, SSH, depth )
2926 type(regridding_CS), intent(in) :: CS !< Regridding control structure
2927 real, intent(in) :: SSH !< The sea surface height, in the same units as depth, often [Z ~> m]
2928 real, intent(in) :: depth !< The maximum depth of the grid, often [Z ~> m]
2929 real, dimension(CS%nk) :: getStaticThickness !< The returned thicknesses in the units of
2930 !! depth, often [Z ~> m]
2931 ! Local
2932 integer :: k
2933 real :: z, dz ! Vertical positions and grid spacing [Z ~> m]
2934
29350 select case ( CS%regridding_scheme )
2936 case ( REGRIDDING_ZSTAR, REGRIDDING_SIGMA_SHELF_ZSTAR, REGRIDDING_HYCOM1, &
2937 REGRIDDING_HYBGEN, REGRIDDING_ADAPTIVE )
29380 if (depth>0.) then
29390 z = ssh
29400 do k = 1, CS%nk
29410 dz = CS%coordinateResolution(k) * ( 1. + ssh/depth ) ! Nominal dz*
29420 dz = max(dz, 0.) ! Avoid negative incase ssh=-depth
29430 dz = min(dz, depth - z) ! Clip if below topography
29440 z = z + dz ! Bottom of layer
29450 getStaticThickness(k) = dz
2946 enddo
2947 else
29480 getStaticThickness(:) = 0. ! On land ...
2949 endif
2950 case ( REGRIDDING_SIGMA )
29510 getStaticThickness(:) = CS%coordinateResolution(:) * ( depth + ssh )
2952 case ( REGRIDDING_RHO )
29530 getStaticThickness(:) = 0. ! Not applicable
2954 case ( REGRIDDING_ARBITRARY )
29550 getStaticThickness(:) = 0. ! Not applicable
2956 case default
2957 call MOM_error(FATAL,'MOM_regridding, getStaticThickness: '//&
29580 'Unknown regridding scheme selected!')
2959 end select ! type of grid
2960
2961end function getStaticThickness
2962
2963!> Parses a string and generates a dz(:) profile that goes like k**power.
29641subroutine dz_function1( string, dz )
2965 character(len=*), intent(in) :: string !< String with list of parameters in form
2966 !! dz_min, H_total, power, precision
2967 real, dimension(:), intent(inout) :: dz !< Profile of nominal thicknesses [m] or other units
2968 ! Local variables
2969 integer :: nk, k
2970 real :: dz_min ! minimum grid spacing [m] or other units
2971 real :: power ! A power to raise the relative position in index space [nondim]
2972 real :: prec ! The precision with which positions are returned [m] or other units
2973 real :: H_total ! The sum of the nominal thicknesses [m] or other units
2974
29751 nk = size(dz) ! Number of cells
29761 prec = -1024.
29771 read( string, *) dz_min, H_total, power, prec
29781 if (prec == -1024.) call MOM_error(FATAL,"dz_function1: "// &
29790 "Problem reading FNC1: string ="//trim(string))
2980 ! Create profile of ( dz - dz_min )
298176 do k = 1, nk
298276 dz(k) = (real(k-1)/real(nk-1))**power
2983 enddo
2984151 dz(:) = ( H_total - real(nk) * dz_min ) * ( dz(:) / sum(dz) ) ! Rescale to so total is H_total
298576 dz(:) = anint( dz(:) / prec ) * prec ! Rounds to precision prec
2986151 dz(:) = ( H_total - real(nk) * dz_min ) * ( dz(:) / sum(dz) ) ! Rescale to so total is H_total
298776 dz(:) = anint( dz(:) / prec ) * prec ! Rounds to precision prec
298876 dz(nk) = dz(nk) + ( H_total - sum( dz(:) + dz_min ) ) ! Adjust bottommost layer
298976 dz(:) = anint( dz(:) / prec ) * prec ! Rounds to precision prec
299076 dz(:) = dz(:) + dz_min ! Finally add in the constant dz_min
2991
29921end subroutine dz_function1
2993
2994!> Construct the name of a parameter for a specific coordinate based on param_prefix and param_suffix. For the main,
2995!! prognostic coordinate this will simply return the parameter name (e.g. P_REF)
29962function create_coord_param(param_prefix, param_name, param_suffix) result(coord_param)
2997 character(len=*) :: param_name !< The base name of the parameter (e.g. the one used for the main coordinate)
2998 character(len=*) :: param_prefix !< String to prefix to parameter names.
2999 character(len=*) :: param_suffix !< String to append to parameter names.
3000 character(len=MAX_PARAM_LENGTH) :: coord_param !< Parameter name prepended by param_prefix
3001 !! and appended with param_suffix
3002 integer :: out_length
3003
30042 if (len_trim(param_prefix) + len_trim(param_suffix) == 0) then
30050 coord_param = param_name
3006 else
3007 ! Note the +2 is because of two underscores
30082 out_length = len_trim(param_name)+len_trim(param_prefix)+len_trim(param_suffix)+2
30092 if (out_length > MAX_PARAM_LENGTH) then
30100 call MOM_error(FATAL,"Coordinate parameter is too long; increase MAX_PARAM_LENGTH")
3011 endif
30122 coord_param = TRIM(param_prefix)//"_"//TRIM(param_name)//"_"//TRIM(param_suffix)
3013 endif
3014
30152end function create_coord_param
3016
3017!> Parses a string and generates a rho_target(:) profile with refined resolution downward
3018!! and returns the number of levels
30190integer function rho_function1( string, rho_target )
3020 character(len=*), intent(in) :: string !< String with list of parameters in form
3021 !! dz_min, H_total, power, precision
3022 real, dimension(:), allocatable, intent(inout) :: rho_target !< Profile of interface densities [kg m-3]
3023 ! Local variables
3024 integer :: nki, k, nk
3025 real :: dx ! Fractional distance from interface nki [nondim]
3026 real :: ddx ! Change in dx between interfaces [nondim]
3027 real :: rho_1, rho_2 ! Density of the top two layers in a profile [kg m-3]
3028 real :: rho_3 ! Density in the third layer, below which the density increase linearly
3029 ! in subsequent layers [kg m-3]
3030 real :: drho ! Change in density over the linear region [kg m-3]
3031 real :: rho_4 ! The densest density in this profile [kg m-3], which might be very large.
3032 real :: drho_min ! A minimal fractional density difference [nondim]?
3033
30340 read( string, *) nk, rho_1, rho_2, rho_3, drho, rho_4, drho_min
30350 allocate(rho_target(nk+1))
30360 nki = nk + 1 - 4 ! Number of interfaces minus 4 specified values
30370 rho_target(1) = rho_1
30380 rho_target(2) = rho_2
30390 dx = 0.
30400 do k = 0, nki
30410 ddx = max( drho_min, real(nki-k)/real(nki*nki) )
30420 dx = dx + ddx
30430 rho_target(3+k) = rho_3 + (2. * drho) * dx
3044 enddo
30450 rho_target(nki+4) = rho_4
3046
30470 rho_function1 = nk
3048
30490end function rho_function1
3050
3051!> \namespace mom_regridding
3052!!
3053!! A vertical grid is defined solely by the cell thicknesses, \f$h\f$.
3054!! Most calculations in this module start with the coordinate at the bottom
3055!! of the column set to -depth, and use a increasing value of coordinate with
3056!! decreasing k. This is consistent with the rest of MOM6 that uses position,
3057!! \f$z\f$ which is a negative quantity for most of the ocean.
3058!!
3059!! A change in grid is define through a change in position of the interfaces:
3060!! \f[
3061!! z^n_{k+1/2} = z^{n-1}_{k+1/2} + \Delta z_{k+1/2}
3062!! \f]
3063!! with the positive upward coordinate convention
3064!! \f[
3065!! z_{k-1/2} = z_{k+1/2} + h_k
3066!! \f]
3067!! so that
3068!! \f[
3069!! h^n_k = h^{n-1}_k + ( \Delta z_{k-1/2} - \Delta z_{k+1/2} )
3070!! \f]
3071!!
3072!! Original date of creation: 2008.06.09 by L. White
3073
30740end module MOM_regridding