MOM6
MOM_shared_initialization.F90
Go to the documentation of this file.
1 !> Code that initializes fixed aspects of the model grid, such as horizontal
2 !! grid metrics, topography and Coriolis, and can be shared between components.
4 
5 ! This file is part of MOM6. See LICENSE.md for the license.
6 
7 use mom_coms, only : max_across_pes, reproducing_sum
8 use mom_domains, only : pass_var, pass_vector, sum_across_pes, broadcast
9 use mom_domains, only : root_pe, to_all, scalar_pair, cgrid_ne, agrid
11 use mom_error_handler, only : mom_mesg, mom_error, fatal, warning, is_root_pe
14 use mom_io, only : close_file, create_file, fieldtype, file_exists
15 use mom_io, only : mom_read_data, mom_read_vector, single_file, multiple
16 use mom_io, only : slasher, vardesc, write_field, var_desc
19 
20 use netcdf
21 
22 implicit none ; private
23 
32 
33 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
34 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
35 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
36 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
37 
38 contains
39 
40 ! -----------------------------------------------------------------------------
41 !> MOM_shared_init_init just writes the code version.
42 subroutine mom_shared_init_init(PF)
43  type(param_file_type), intent(in) :: pf !< A structure indicating the open file
44  !! to parse for model parameter values.
45 
46  character(len=40) :: mdl = "MOM_shared_initialization" ! This module's name.
47 
48 ! This include declares and sets the variable "version".
49 #include "version_variable.h"
50  call log_version(pf, mdl, version, &
51  "Sharable code to initialize time-invariant fields, like bathymetry and Coriolis parameters.")
52 
53 end subroutine mom_shared_init_init
54 ! -----------------------------------------------------------------------------
55 
56 !> MOM_initialize_rotation makes the appropriate call to set up the Coriolis parameter.
57 subroutine mom_initialize_rotation(f, G, PF, US)
58  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
59  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), intent(out) :: f !< The Coriolis parameter [T-1 ~> s-1]
60  type(param_file_type), intent(in) :: pf !< Parameter file structure
61  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
62 
63 ! This subroutine makes the appropriate call to set up the Coriolis parameter.
64 ! This is a separate subroutine so that it can be made public and shared with
65 ! the ice-sheet code or other components.
66 ! Set up the Coriolis parameter, f, either analytically or from file.
67  character(len=40) :: mdl = "MOM_initialize_rotation" ! This subroutine's name.
68  character(len=200) :: config
69 
70  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
71  call get_param(pf, mdl, "ROTATION", config, &
72  "This specifies how the Coriolis parameter is specified: \n"//&
73  " \t 2omegasinlat - Use twice the planetary rotation rate \n"//&
74  " \t\t times the sine of latitude.\n"//&
75  " \t betaplane - Use a beta-plane or f-plane.\n"//&
76  " \t USER - call a user modified routine.", &
77  default="2omegasinlat")
78  select case (trim(config))
79  case ("2omegasinlat"); call set_rotation_planetary(f, g, pf, us)
80  case ("beta"); call set_rotation_beta_plane(f, g, pf, us)
81  case ("betaplane"); call set_rotation_beta_plane(f, g, pf, us)
82  !case ("nonrotating") ! Note from AJA: Missing case?
83  case default ; call mom_error(fatal,"MOM_initialize: "// &
84  "Unrecognized rotation setup "//trim(config))
85  end select
86  call calltree_leave(trim(mdl)//'()')
87 end subroutine mom_initialize_rotation
88 
89 !> Calculates the components of grad f (Coriolis parameter)
90 subroutine mom_calculate_grad_coriolis(dF_dx, dF_dy, G, US)
91  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid type
92  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
93  intent(out) :: df_dx !< x-component of grad f [T-1 L-1 ~> s-1 m-1]
94  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
95  intent(out) :: df_dy !< y-component of grad f [T-1 L-1 ~> s-1 m-1]
96  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
97  ! Local variables
98  integer :: i,j
99  real :: m_to_l ! A unit conversion factor [L m-1 ~> nondim]
100  real :: f1, f2
101 
102  m_to_l = 1.0 ; if (present(us)) m_to_l = us%m_to_L
103 
104  if ((lbound(g%CoriolisBu,1) > g%isc-1) .or. &
105  (lbound(g%CoriolisBu,2) > g%isc-1)) then
106  ! The gradient of the Coriolis parameter can not be calculated with this grid.
107  df_dx(:,:) = 0.0 ; df_dy(:,:) = 0.0
108  return
109  endif
110 
111  do j=g%jsc, g%jec ; do i=g%isc, g%iec
112  f1 = 0.5*( g%CoriolisBu(i,j) + g%CoriolisBu(i,j-1) )
113  f2 = 0.5*( g%CoriolisBu(i-1,j) + g%CoriolisBu(i-1,j-1) )
114  df_dx(i,j) = g%IdxT(i,j) * ( f1 - f2 )
115  f1 = 0.5*( g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j) )
116  f2 = 0.5*( g%CoriolisBu(i,j-1) + g%CoriolisBu(i-1,j-1) )
117  df_dy(i,j) = g%IdyT(i,j) * ( f1 - f2 )
118  enddo ; enddo
119  call pass_vector(df_dx, df_dy, g%Domain, stagger=agrid)
120 
121 end subroutine mom_calculate_grad_coriolis
122 
123 !> Return the global maximum ocean bottom depth in the same units as the input depth.
124 function diagnosemaximumdepth(D, G)
125  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
126  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
127  intent(in) :: d !< Ocean bottom depth in m or Z
128  real :: diagnosemaximumdepth !< The global maximum ocean bottom depth in m or Z
129  ! Local variables
130  integer :: i,j
131  diagnosemaximumdepth = d(g%isc,g%jsc)
132  do j=g%jsc, g%jec ; do i=g%isc, g%iec
134  enddo ; enddo
135  call max_across_pes(diagnosemaximumdepth)
136 end function diagnosemaximumdepth
137 
138 
139 !> Read gridded depths from file
140 subroutine initialize_topography_from_file(D, G, param_file, US)
141  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
142  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
143  intent(out) :: d !< Ocean bottom depth in m or Z if US is present
144  type(param_file_type), intent(in) :: param_file !< Parameter file structure
145  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
146  ! Local variables
147  real :: m_to_z ! A dimensional rescaling factor.
148  character(len=200) :: filename, topo_file, inputdir ! Strings for file/path
149  character(len=200) :: topo_varname ! Variable name in file
150  character(len=40) :: mdl = "initialize_topography_from_file" ! This subroutine's name.
151 
152  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
153 
154  m_to_z = 1.0 ; if (present(us)) m_to_z = us%m_to_Z
155 
156  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
157  inputdir = slasher(inputdir)
158  call get_param(param_file, mdl, "TOPO_FILE", topo_file, &
159  "The file from which the bathymetry is read.", &
160  default="topog.nc")
161  call get_param(param_file, mdl, "TOPO_VARNAME", topo_varname, &
162  "The name of the bathymetry variable in TOPO_FILE.", &
163  default="depth")
164 
165  filename = trim(inputdir)//trim(topo_file)
166  call log_param(param_file, mdl, "INPUTDIR/TOPO_FILE", filename)
167 
168  if (.not.file_exists(filename, g%Domain)) call mom_error(fatal, &
169  " initialize_topography_from_file: Unable to open "//trim(filename))
170 
171  d(:,:) = -9.e30*m_to_z ! Initializing to a very large negative depth (tall mountains) everywhere
172  ! before reading from a file should do nothing. However, in the instance of
173  ! masked-out PEs, halo regions are not updated when a processor does not
174  ! exist. We need to ensure the depth in masked-out PEs appears to be that
175  ! of land so this line does that in the halo regions. For non-masked PEs
176  ! the halo region is filled properly with a later pass_var().
177  call mom_read_data(filename, trim(topo_varname), d, g%Domain, scale=m_to_z)
178 
179  call apply_topography_edits_from_file(d, g, param_file, us)
180 
181  call calltree_leave(trim(mdl)//'()')
182 end subroutine initialize_topography_from_file
183 
184 !> Applies a list of topography overrides read from a netcdf file
185 subroutine apply_topography_edits_from_file(D, G, param_file, US)
186  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
187  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
188  intent(inout) :: d !< Ocean bottom depth in m or Z if US is present
189  type(param_file_type), intent(in) :: param_file !< Parameter file structure
190  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
191 
192  ! Local variables
193  real :: m_to_z ! A dimensional rescaling factor.
194  character(len=200) :: topo_edits_file, inputdir ! Strings for file/path
195  character(len=40) :: mdl = "apply_topography_edits_from_file" ! This subroutine's name.
196  integer :: n_edits, n, ashape(5), i, j, ncid, id, ncstatus, iid, jid, zid
197  integer, dimension(:), allocatable :: ig, jg
198  real, dimension(:), allocatable :: new_depth
199 
200  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
201 
202  m_to_z = 1.0 ; if (present(us)) m_to_z = us%m_to_Z
203 
204  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
205  inputdir = slasher(inputdir)
206  call get_param(param_file, mdl, "TOPO_EDITS_FILE", topo_edits_file, &
207  "The file from which to read a list of i,j,z topography overrides.", &
208  default="")
209 
210  if (len_trim(topo_edits_file)==0) return
211 
212  topo_edits_file = trim(inputdir)//trim(topo_edits_file)
213  if (.not.file_exists(topo_edits_file, g%Domain)) call mom_error(fatal, &
214  'initialize_topography_from_file: Unable to open '//trim(topo_edits_file))
215 
216  ncstatus = nf90_open(trim(topo_edits_file), nf90_nowrite, ncid)
217  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
218  'Failed to open '//trim(topo_edits_file))
219 
220  ! Get nEdits
221  ncstatus = nf90_inq_dimid(ncid, 'nEdits', id)
222  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
223  'Failed to inq_dimid nEdits for '//trim(topo_edits_file))
224  ncstatus = nf90_inquire_dimension(ncid, id, len=n_edits)
225  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
226  'Failed to inquire_dimension nEdits for '//trim(topo_edits_file))
227 
228  ! Read ni
229  ncstatus = nf90_inq_varid(ncid, 'ni', id)
230  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
231  'Failed to inq_varid ni for '//trim(topo_edits_file))
232  ncstatus = nf90_get_var(ncid, id, i)
233  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
234  'Failed to get_var ni for '//trim(topo_edits_file))
235  if (i /= g%ieg) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
236  'Incompatible i-dimension of grid in '//trim(topo_edits_file))
237 
238  ! Read nj
239  ncstatus = nf90_inq_varid(ncid, 'nj', id)
240  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
241  'Failed to inq_varid nj for '//trim(topo_edits_file))
242  ncstatus = nf90_get_var(ncid, id, j)
243  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
244  'Failed to get_var nj for '//trim(topo_edits_file))
245  if (j /= g%jeg) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
246  'Incompatible j-dimension of grid in '//trim(topo_edits_file))
247 
248  ! Read iEdit
249  ncstatus = nf90_inq_varid(ncid, 'iEdit', id)
250  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
251  'Failed to inq_varid iEdit for '//trim(topo_edits_file))
252  allocate(ig(n_edits))
253  ncstatus = nf90_get_var(ncid, id, ig)
254  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
255  'Failed to get_var iEdit for '//trim(topo_edits_file))
256 
257  ! Read jEdit
258  ncstatus = nf90_inq_varid(ncid, 'jEdit', id)
259  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
260  'Failed to inq_varid jEdit for '//trim(topo_edits_file))
261  allocate(jg(n_edits))
262  ncstatus = nf90_get_var(ncid, id, jg)
263  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
264  'Failed to get_var jEdit for '//trim(topo_edits_file))
265 
266  ! Read zEdit
267  ncstatus = nf90_inq_varid(ncid, 'zEdit', id)
268  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
269  'Failed to inq_varid zEdit for '//trim(topo_edits_file))
270  allocate(new_depth(n_edits))
271  ncstatus = nf90_get_var(ncid, id, new_depth)
272  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
273  'Failed to get_var zEdit for '//trim(topo_edits_file))
274 
275  ! Close file
276  ncstatus = nf90_close(ncid)
277  if (ncstatus /= nf90_noerr) call mom_error(fatal, 'apply_topography_edits_from_file: '//&
278  'Failed to close '//trim(topo_edits_file))
279 
280  do n = 1, n_edits
281  i = ig(n) - g%isd_global + 2 ! +1 for python indexing and +1 for ig-isd_global+1
282  j = jg(n) - g%jsd_global + 2
283  if (i>=g%isc .and. i<=g%iec .and. j>=g%jsc .and. j<=g%jec) then
284  if (new_depth(n)/=0.) then
285  write(*,'(a,3i5,f8.2,a,f8.2,2i4)') &
286  'Ocean topography edit: ',n,ig(n),jg(n),d(i,j)/m_to_z,'->',abs(new_depth(n)),i,j
287  d(i,j) = abs(m_to_z*new_depth(n)) ! Allows for height-file edits (i.e. converts negatives)
288  else
289  call mom_error(fatal, ' apply_topography_edits_from_file: '//&
290  "A zero depth edit would change the land mask and is not allowed in"//trim(topo_edits_file))
291  endif
292  endif
293  enddo
294 
295  deallocate( ig, jg, new_depth )
296 
297  call calltree_leave(trim(mdl)//'()')
299 
300 !> initialize the bathymetry based on one of several named idealized configurations
301 subroutine initialize_topography_named(D, G, param_file, topog_config, max_depth, US)
302  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
303  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
304  intent(out) :: d !< Ocean bottom depth in m or Z if US is present
305  type(param_file_type), intent(in) :: param_file !< Parameter file structure
306  character(len=*), intent(in) :: topog_config !< The name of an idealized
307  !! topographic configuration
308  real, intent(in) :: max_depth !< Maximum depth of model in the units of D
309  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
310 
311  ! This subroutine places the bottom depth in m into D(:,:), shaped according to the named config.
312 
313  ! Local variables
314  real :: m_to_z ! A dimensional rescaling factor.
315  real :: min_depth ! The minimum depth [Z ~> m].
316  real :: pi ! 3.1415926... calculated as 4*atan(1)
317  real :: d0 ! A constant to make the maximum basin depth MAXIMUM_DEPTH.
318  real :: expdecay ! A decay scale of associated with the sloping boundaries [m].
319  real :: dedge ! The depth [Z ~> m], at the basin edge
320 ! real :: south_lat, west_lon, len_lon, len_lat, Rad_earth
321  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
322  character(len=40) :: mdl = "initialize_topography_named" ! This subroutine's name.
323  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
324  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
325 
326  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
327  call mom_mesg(" MOM_shared_initialization.F90, initialize_topography_named: "//&
328  "TOPO_CONFIG = "//trim(topog_config), 5)
329 
330  m_to_z = 1.0 ; if (present(us)) m_to_z = us%m_to_Z
331 
332  call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, &
333  "The minimum depth of the ocean.", units="m", default=0.0, scale=m_to_z)
334  if (max_depth<=0.) call mom_error(fatal,"initialize_topography_named: "// &
335  "MAXIMUM_DEPTH has a non-sensical value! Was it set?")
336 
337  if (trim(topog_config) /= "flat") then
338  call get_param(param_file, mdl, "EDGE_DEPTH", dedge, &
339  "The depth at the edge of one of the named topographies.", &
340  units="m", default=100.0, scale=m_to_z)
341 ! call get_param(param_file, mdl, "SOUTHLAT", south_lat, &
342 ! "The southern latitude of the domain.", units="degrees", &
343 ! fail_if_missing=.true.)
344 ! call get_param(param_file, mdl, "LENLAT", len_lat, &
345 ! "The latitudinal length of the domain.", units="degrees", &
346 ! fail_if_missing=.true.)
347 ! call get_param(param_file, mdl, "WESTLON", west_lon, &
348 ! "The western longitude of the domain.", units="degrees", &
349 ! default=0.0)
350 ! call get_param(param_file, mdl, "LENLON", len_lon, &
351 ! "The longitudinal length of the domain.", units="degrees", &
352 ! fail_if_missing=.true.)
353 ! call get_param(param_file, mdl, "RAD_EARTH", Rad_Earth, &
354 ! "The radius of the Earth.", units="m", default=6.378e6)
355  call get_param(param_file, mdl, "TOPOG_SLOPE_SCALE", expdecay, &
356  "The exponential decay scale used in defining some of "//&
357  "the named topographies.", units="m", default=400000.0)
358  endif
359 
360 
361  pi = 4.0*atan(1.0)
362 
363  if (trim(topog_config) == "flat") then
364  do i=is,ie ; do j=js,je ; d(i,j) = max_depth ; enddo ; enddo
365  elseif (trim(topog_config) == "spoon") then
366  d0 = (max_depth - dedge) / &
367  ((1.0 - exp(-0.5*g%len_lat*g%Rad_earth*pi/(180.0 *expdecay))) * &
368  (1.0 - exp(-0.5*g%len_lat*g%Rad_earth*pi/(180.0 *expdecay))))
369  do i=is,ie ; do j=js,je
370  ! This sets a bowl shaped (sort of) bottom topography, with a !
371  ! maximum depth of max_depth. !
372  d(i,j) = dedge + d0 * &
373  (sin(pi * (g%geoLonT(i,j) - (g%west_lon)) / g%len_lon) * &
374  (1.0 - exp((g%geoLatT(i,j) - (g%south_lat+g%len_lat))*g%Rad_earth*pi / &
375  (180.0*expdecay)) ))
376  enddo ; enddo
377  elseif (trim(topog_config) == "bowl") then
378  d0 = (max_depth - dedge) / &
379  ((1.0 - exp(-0.5*g%len_lat*g%Rad_earth*pi/(180.0 *expdecay))) * &
380  (1.0 - exp(-0.5*g%len_lat*g%Rad_earth*pi/(180.0 *expdecay))))
381 
382  ! This sets a bowl shaped (sort of) bottom topography, with a
383  ! maximum depth of max_depth.
384  do i=is,ie ; do j=js,je
385  d(i,j) = dedge + d0 * &
386  (sin(pi * (g%geoLonT(i,j) - g%west_lon) / g%len_lon) * &
387  ((1.0 - exp(-(g%geoLatT(i,j) - g%south_lat)*g%Rad_Earth*pi/ &
388  (180.0*expdecay))) * &
389  (1.0 - exp((g%geoLatT(i,j) - (g%south_lat+g%len_lat))* &
390  g%Rad_Earth*pi/(180.0*expdecay)))))
391  enddo ; enddo
392  elseif (trim(topog_config) == "halfpipe") then
393  d0 = max_depth - dedge
394  do i=is,ie ; do j=js,je
395  d(i,j) = dedge + d0 * abs(sin(pi*(g%geoLatT(i,j) - g%south_lat)/g%len_lat))
396  enddo ; enddo
397  else
398  call mom_error(fatal,"initialize_topography_named: "// &
399  "Unrecognized topography name "//trim(topog_config))
400  endif
401 
402  ! This is here just for safety. Hopefully it doesn't do anything.
403  do i=is,ie ; do j=js,je
404  if (d(i,j) > max_depth) d(i,j) = max_depth
405  if (d(i,j) < min_depth) d(i,j) = 0.5*min_depth
406  enddo ; enddo
407 
408  call calltree_leave(trim(mdl)//'()')
409 end subroutine initialize_topography_named
410 ! -----------------------------------------------------------------------------
411 
412 ! -----------------------------------------------------------------------------
413 !> limit_topography ensures that min_depth < D(x,y) < max_depth
414 subroutine limit_topography(D, G, param_file, max_depth, US)
415  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
416  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
417  intent(inout) :: d !< Ocean bottom depth in m or Z if US is present
418  type(param_file_type), intent(in) :: param_file !< Parameter file structure
419  real, intent(in) :: max_depth !< Maximum depth of model in the units of D
420  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
421 
422  ! Local variables
423  real :: m_to_z ! A dimensional rescaling factor.
424  integer :: i, j
425  character(len=40) :: mdl = "limit_topography" ! This subroutine's name.
426  real :: min_depth, mask_depth
427 
428  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
429 
430  m_to_z = 1.0 ; if (present(us)) m_to_z = us%m_to_Z
431 
432  call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, &
433  "If MASKING_DEPTH is unspecified, then anything shallower than "//&
434  "MINIMUM_DEPTH is assumed to be land and all fluxes are masked out. "//&
435  "If MASKING_DEPTH is specified, then all depths shallower than "//&
436  "MINIMUM_DEPTH but deeper than MASKING_DEPTH are rounded to MINIMUM_DEPTH.", &
437  units="m", default=0.0, scale=m_to_z)
438  call get_param(param_file, mdl, "MASKING_DEPTH", mask_depth, &
439  "The depth below which to mask the ocean as land.", &
440  units="m", default=-9999.0, scale=m_to_z, do_not_log=.true.)
441 
442 ! Make sure that min_depth < D(x,y) < max_depth
443  if (mask_depth < -9990.*m_to_z) then
444  do j=g%jsd,g%jed ; do i=g%isd,g%ied
445  d(i,j) = min( max( d(i,j), 0.5*min_depth ), max_depth )
446  enddo ; enddo
447  else
448  do j=g%jsd,g%jed ; do i=g%isd,g%ied
449  if (d(i,j)>0.) then
450  d(i,j) = min( max( d(i,j), min_depth ), max_depth )
451  else
452  d(i,j) = 0.
453  endif
454  enddo ; enddo
455  endif
456 
457  call calltree_leave(trim(mdl)//'()')
458 end subroutine limit_topography
459 ! -----------------------------------------------------------------------------
460 
461 ! -----------------------------------------------------------------------------
462 !> This subroutine sets up the Coriolis parameter for a sphere
463 subroutine set_rotation_planetary(f, G, param_file, US)
464  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid
465  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
466  intent(out) :: f !< Coriolis parameter (vertical component) [T-1 ~> s-1]
467  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
468  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
469 
470 ! This subroutine sets up the Coriolis parameter for a sphere
471  character(len=30) :: mdl = "set_rotation_planetary" ! This subroutine's name.
472  integer :: i, j
473  real :: pi
474  real :: omega ! The planetary rotation rate [T-1 ~> s-1]
475  real :: t_to_s ! A time unit conversion factor
476 
477  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
478 
479  t_to_s = 1.0 ; if (present(us)) t_to_s = us%T_to_s
480 
481  call get_param(param_file, "set_rotation_planetary", "OMEGA", omega, &
482  "The rotation rate of the earth.", units="s-1", &
483  default=7.2921e-5, scale=t_to_s)
484  pi = 4.0*atan(1.0)
485 
486  do i=g%IsdB,g%IedB ; do j=g%JsdB,g%JedB
487  f(i,j) = ( 2.0 * omega ) * sin( ( pi * g%geoLatBu(i,j) ) / 180.)
488  enddo ; enddo
489 
490  call calltree_leave(trim(mdl)//'()')
491 end subroutine set_rotation_planetary
492 ! -----------------------------------------------------------------------------
493 
494 ! -----------------------------------------------------------------------------
495 !> This subroutine sets up the Coriolis parameter for a beta-plane or f-plane
496 subroutine set_rotation_beta_plane(f, G, param_file, US)
497  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid
498  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB), &
499  intent(out) :: f !< Coriolis parameter (vertical component) [T-1 ~> s-1]
500  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
501  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
502 
503 ! This subroutine sets up the Coriolis parameter for a beta-plane
504  integer :: i, j
505  real :: f_0 ! The reference value of the Coriolis parameter [T-1 ~> s-1]
506  real :: beta ! The meridional gradient of the Coriolis parameter [T-1 m-1 ~> s-1 m-1]
507  real :: y_scl, rad_earth
508  real :: t_to_s ! A time unit conversion factor
509  real :: pi
510  character(len=40) :: mdl = "set_rotation_beta_plane" ! This subroutine's name.
511  character(len=200) :: axis_units
512 
513  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
514 
515  t_to_s = 1.0 ; if (present(us)) t_to_s = us%T_to_s
516 
517  call get_param(param_file, mdl, "F_0", f_0, &
518  "The reference value of the Coriolis parameter with the "//&
519  "betaplane option.", units="s-1", default=0.0, scale=t_to_s)
520  call get_param(param_file, mdl, "BETA", beta, &
521  "The northward gradient of the Coriolis parameter with "//&
522  "the betaplane option.", units="m-1 s-1", default=0.0, scale=t_to_s)
523  call get_param(param_file, mdl, "AXIS_UNITS", axis_units, default="degrees")
524 
525  pi = 4.0*atan(1.0)
526  select case (axis_units(1:1))
527  case ("d")
528  call get_param(param_file, mdl, "RAD_EARTH", rad_earth, &
529  "The radius of the Earth.", units="m", default=6.378e6)
530  y_scl = rad_earth/pi
531  case ("k"); y_scl = 1.e3
532  case ("m"); y_scl = 1.
533  case ("c"); y_scl = 1.e-2
534  case default ; call mom_error(fatal, &
535  " set_rotation_beta_plane: unknown AXIS_UNITS = "//trim(axis_units))
536  end select
537 
538  do i=g%IsdB,g%IedB ; do j=g%JsdB,g%JedB
539  f(i,j) = f_0 + beta * ( g%geoLatBu(i,j) * y_scl )
540  enddo ; enddo
541 
542  call calltree_leave(trim(mdl)//'()')
543 end subroutine set_rotation_beta_plane
544 
545 !> initialize_grid_rotation_angle initializes the arrays with the sine and
546 !! cosine of the angle between logical north on the grid and true north.
547 subroutine initialize_grid_rotation_angle(G, PF)
548  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
549  type(param_file_type), intent(in) :: pf !< A structure indicating the open file
550  !! to parse for model parameter values.
551 
552  real :: angle, lon_scale
553  real :: len_lon ! The periodic range of longitudes, usually 360 degrees.
554  real :: pi_720deg ! One quarter the conversion factor from degrees to radians.
555  real :: lonb(2,2) ! The longitude of a point, shifted to have about the same value.
556  character(len=40) :: mdl = "initialize_grid_rotation_angle" ! This subroutine's name.
557  logical :: use_bugs
558  integer :: i, j, m, n
559 
560  call get_param(pf, mdl, "GRID_ROTATION_ANGLE_BUGS", use_bugs, &
561  "If true, use an older algorithm to calculate the sine and "//&
562  "cosines needed rotate between grid-oriented directions and "//&
563  "true north and east. Differences arise at the tripolar fold.", &
564  default=.true.)
565 
566  if (use_bugs) then
567  do j=g%jsc,g%jec ; do i=g%isc,g%iec
568  lon_scale = cos((g%geoLatBu(i-1,j-1) + g%geoLatBu(i,j-1 ) + &
569  g%geoLatBu(i-1,j) + g%geoLatBu(i,j)) * atan(1.0)/180)
570  angle = atan2((g%geoLonBu(i-1,j) + g%geoLonBu(i,j) - &
571  g%geoLonBu(i-1,j-1) - g%geoLonBu(i,j-1))*lon_scale, &
572  g%geoLatBu(i-1,j) + g%geoLatBu(i,j) - &
573  g%geoLatBu(i-1,j-1) - g%geoLatBu(i,j-1) )
574  g%sin_rot(i,j) = sin(angle) ! angle is the clockwise angle from lat/lon to ocean
575  g%cos_rot(i,j) = cos(angle) ! grid (e.g. angle of ocean "north" from true north)
576  enddo ; enddo
577 
578  ! This is not right at a tripolar or cubed-sphere fold.
579  call pass_var(g%cos_rot, g%Domain)
580  call pass_var(g%sin_rot, g%Domain)
581  else
582  pi_720deg = atan(1.0) / 180.0
583  len_lon = 360.0 ; if (g%len_lon > 0.0) len_lon = g%len_lon
584  do j=g%jsc,g%jec ; do i=g%isc,g%iec
585  do n=1,2 ; do m=1,2
586  lonb(m,n) = modulo_around_point(g%geoLonBu(i+m-2,j+n-2), g%geoLonT(i,j), len_lon)
587  enddo ; enddo
588  lon_scale = cos(pi_720deg*((g%geoLatBu(i-1,j-1) + g%geoLatBu(i,j)) + &
589  (g%geoLatBu(i,j-1) + g%geoLatBu(i-1,j)) ) )
590  angle = atan2(lon_scale*((lonb(1,2) - lonb(2,1)) + (lonb(2,2) - lonb(1,1))), &
591  (g%geoLatBu(i-1,j) - g%geoLatBu(i,j-1)) + &
592  (g%geoLatBu(i,j) - g%geoLatBu(i-1,j-1)) )
593  g%sin_rot(i,j) = sin(angle) ! angle is the clockwise angle from lat/lon to ocean
594  g%cos_rot(i,j) = cos(angle) ! grid (e.g. angle of ocean "north" from true north)
595  enddo ; enddo
596 
597  call pass_vector(g%cos_rot, g%sin_rot, g%Domain, stagger=agrid)
598  endif
599 
600 end subroutine initialize_grid_rotation_angle
601 
602 ! -----------------------------------------------------------------------------
603 !> Return the modulo value of x in an interval [xc-(Lx/2) xc+(Lx/2)]
604 !! If Lx<=0, then it returns x without applying modulo arithmetic.
605 function modulo_around_point(x, xc, Lx) result(x_mod)
606  real, intent(in) :: x !< Value to which to apply modulo arithmetic
607  real, intent(in) :: xc !< Center of modulo range
608  real, intent(in) :: lx !< Modulo range width
609  real :: x_mod !< x shifted by an integer multiple of Lx to be close to xc.
610 
611  if (lx > 0.0) then
612  x_mod = modulo(x - (xc - 0.5*lx), lx) + (xc - 0.5*lx)
613  else
614  x_mod = x
615  endif
616 end function modulo_around_point
617 
618 ! -----------------------------------------------------------------------------
619 !> This subroutine sets the open face lengths at selected points to restrict
620 !! passages to their observed widths based on a named set of sizes.
621 subroutine reset_face_lengths_named(G, param_file, name, US)
622  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
623  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
624  character(len=*), intent(in) :: name !< The name for the set of face lengths. Only "global_1deg"
625  !! is currently implemented.
626  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
627 
628  ! Local variables
629  character(len=256) :: mesg ! Message for error messages.
630  real :: m_to_l ! A unit conversion factor [L m-1 ~> nondim]
631  real :: l_to_m ! A unit conversion factor [m L-1 ~> nondim]
632  real :: dx_2 = -1.0, dy_2 = -1.0
633  real :: pi_180
634  integer :: option = -1
635  integer :: i, j, isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
636  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
637  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
638  pi_180 = (4.0*atan(1.0))/180.0
639 
640  select case ( trim(name) )
641  case ("global_1deg") ; option = 1 ; dx_2 = 0.5*1.0
642  case default ; call mom_error(fatal, "reset_face_lengths_named: "//&
643  "Unrecognized channel configuration name "//trim(name))
644  end select
645 
646  m_to_l = 1.0 ; if (present(us)) m_to_l = us%m_to_L
647  l_to_m = 1.0 ; if (present(us)) l_to_m = us%L_to_m
648 
649  if (option==1) then ! 1-degree settings.
650  do j=jsd,jed ; do i=isdb,iedb ! Change any u-face lengths within this loop.
651  dy_2 = dx_2 * g%dyCu(i,j)*g%IdxCu(i,j) * cos(pi_180 * g%geoLatCu(i,j))
652 
653  if ((abs(g%geoLatCu(i,j)-35.5) < dy_2) .and. (g%geoLonCu(i,j) < -4.5) .and. &
654  (g%geoLonCu(i,j) > -6.5)) &
655  g%dy_Cu(i,j) = g%mask2dCu(i,j)*12000.0*m_to_l ! Gibraltar
656 
657  if ((abs(g%geoLatCu(i,j)-12.5) < dy_2) .and. (abs(g%geoLonCu(i,j)-43.0) < dx_2)) &
658  g%dy_Cu(i,j) = g%mask2dCu(i,j)*10000.0*m_to_l ! Red Sea
659 
660  if ((abs(g%geoLatCu(i,j)-40.5) < dy_2) .and. (abs(g%geoLonCu(i,j)-26.0) < dx_2)) &
661  g%dy_Cu(i,j) = g%mask2dCu(i,j)*5000.0*m_to_l ! Dardanelles
662 
663  if ((abs(g%geoLatCu(i,j)-41.5) < dy_2) .and. (abs(g%geoLonCu(i,j)+220.0) < dx_2)) &
664  g%dy_Cu(i,j) = g%mask2dCu(i,j)*35000.0*m_to_l ! Tsugaru strait at 140.0e
665 
666  if ((abs(g%geoLatCu(i,j)-45.5) < dy_2) .and. (abs(g%geoLonCu(i,j)+217.5) < 0.9)) &
667  g%dy_Cu(i,j) = g%mask2dCu(i,j)*15000.0*m_to_l ! Betw Hokkaido and Sakhalin at 217&218 = 142e
668 
669  ! Greater care needs to be taken in the tripolar region.
670  if ((abs(g%geoLatCu(i,j)-80.84) < 0.2) .and. (abs(g%geoLonCu(i,j)+64.9) < 0.8)) &
671  g%dy_Cu(i,j) = g%mask2dCu(i,j)*38000.0*m_to_l ! Smith Sound in Canadian Arch - tripolar region
672 
673  enddo ; enddo
674 
675  do j=jsdb,jedb ; do i=isd,ied ! Change any v-face lengths within this loop.
676  dy_2 = dx_2 * g%dyCv(i,j)*g%IdxCv(i,j) * cos(pi_180 * g%geoLatCv(i,j))
677  if ((abs(g%geoLatCv(i,j)-41.0) < dy_2) .and. (abs(g%geoLonCv(i,j)-28.5) < dx_2)) &
678  g%dx_Cv(i,j) = g%mask2dCv(i,j)*2500.0*m_to_l ! Bosporus - should be 1000.0 m wide.
679 
680  if ((abs(g%geoLatCv(i,j)-13.0) < dy_2) .and. (abs(g%geoLonCv(i,j)-42.5) < dx_2)) &
681  g%dx_Cv(i,j) = g%mask2dCv(i,j)*10000.0*m_to_l ! Red Sea
682 
683  if ((abs(g%geoLatCv(i,j)+2.8) < 0.8) .and. (abs(g%geoLonCv(i,j)+241.5) < dx_2)) &
684  g%dx_Cv(i,j) = g%mask2dCv(i,j)*40000.0*m_to_l ! Makassar Straits at 241.5 W = 118.5 E
685 
686  if ((abs(g%geoLatCv(i,j)-0.56) < 0.5) .and. (abs(g%geoLonCv(i,j)+240.5) < dx_2)) &
687  g%dx_Cv(i,j) = g%mask2dCv(i,j)*80000.0*m_to_l ! entry to Makassar Straits at 240.5 W = 119.5 E
688 
689  if ((abs(g%geoLatCv(i,j)-0.19) < 0.5) .and. (abs(g%geoLonCv(i,j)+230.5) < dx_2)) &
690  g%dx_Cv(i,j) = g%mask2dCv(i,j)*25000.0*m_to_l ! Channel betw N Guinea and Halmahara 230.5 W = 129.5 E
691 
692  if ((abs(g%geoLatCv(i,j)-0.19) < 0.5) .and. (abs(g%geoLonCv(i,j)+229.5) < dx_2)) &
693  g%dx_Cv(i,j) = g%mask2dCv(i,j)*25000.0*m_to_l ! Channel betw N Guinea and Halmahara 229.5 W = 130.5 E
694 
695  if ((abs(g%geoLatCv(i,j)-0.0) < 0.25) .and. (abs(g%geoLonCv(i,j)+228.5) < dx_2)) &
696  g%dx_Cv(i,j) = g%mask2dCv(i,j)*25000.0*m_to_l ! Channel betw N Guinea and Halmahara 228.5 W = 131.5 E
697 
698  if ((abs(g%geoLatCv(i,j)+8.5) < 0.5) .and. (abs(g%geoLonCv(i,j)+244.5) < dx_2)) &
699  g%dx_Cv(i,j) = g%mask2dCv(i,j)*20000.0*m_to_l ! Lombok Straits at 244.5 W = 115.5 E
700 
701  if ((abs(g%geoLatCv(i,j)+8.5) < 0.5) .and. (abs(g%geoLonCv(i,j)+235.5) < dx_2)) &
702  g%dx_Cv(i,j) = g%mask2dCv(i,j)*20000.0*m_to_l ! Timor Straits at 235.5 W = 124.5 E
703 
704  if ((abs(g%geoLatCv(i,j)-52.5) < dy_2) .and. (abs(g%geoLonCv(i,j)+218.5) < dx_2)) &
705  g%dx_Cv(i,j) = g%mask2dCv(i,j)*2500.0*m_to_l ! Russia and Sakhalin Straits at 218.5 W = 141.5 E
706 
707  ! Greater care needs to be taken in the tripolar region.
708  if ((abs(g%geoLatCv(i,j)-76.8) < 0.06) .and. (abs(g%geoLonCv(i,j)+88.7) < dx_2)) &
709  g%dx_Cv(i,j) = g%mask2dCv(i,j)*8400.0*m_to_l ! Jones Sound in Canadian Arch - tripolar region
710 
711  enddo ; enddo
712  endif
713 
714  ! These checks apply regardless of the chosen option.
715 
716  do j=jsd,jed ; do i=isdb,iedb
717  if (l_to_m*g%dy_Cu(i,j) > l_to_m*g%dyCu(i,j)) then
718  write(mesg,'("dy_Cu of ",ES11.4," exceeds unrestricted width of ",ES11.4,&
719  &" by ",ES11.4," at lon/lat of ", ES11.4, ES11.4)') &
720  l_to_m*g%dy_Cu(i,j), l_to_m*g%dyCu(i,j), l_to_m*g%dy_Cu(i,j)-l_to_m*g%dyCu(i,j), &
721  g%geoLonCu(i,j), g%geoLatCu(i,j)
722  call mom_error(fatal,"reset_face_lengths_named "//mesg)
723  endif
724  g%areaCu(i,j) = g%dxCu(i,j) * g%dy_Cu(i,j)
725  g%IareaCu(i,j) = 0.0
726  if (g%areaCu(i,j) > 0.0) g%IareaCu(i,j) = g%mask2dCu(i,j) / (g%areaCu(i,j))
727  enddo ; enddo
728 
729  do j=jsdb,jedb ; do i=isd,ied
730  if (l_to_m*g%dx_Cv(i,j) > l_to_m*g%dxCv(i,j)) then
731  write(mesg,'("dx_Cv of ",ES11.4," exceeds unrestricted width of ",ES11.4,&
732  &" by ",ES11.4, " at lon/lat of ", ES11.4, ES11.4)') &
733  l_to_m*g%dx_Cv(i,j), l_to_m*g%dxCv(i,j), l_to_m*g%dx_Cv(i,j)-l_to_m*g%dxCv(i,j), &
734  g%geoLonCv(i,j), g%geoLatCv(i,j)
735 
736  call mom_error(fatal,"reset_face_lengths_named "//mesg)
737  endif
738  g%areaCv(i,j) = g%dyCv(i,j) * g%dx_Cv(i,j)
739  g%IareaCv(i,j) = 0.0
740  if (g%areaCv(i,j) > 0.0) g%IareaCv(i,j) = g%mask2dCv(i,j) / (g%areaCv(i,j))
741  enddo ; enddo
742 
743 end subroutine reset_face_lengths_named
744 ! -----------------------------------------------------------------------------
745 
746 ! -----------------------------------------------------------------------------
747 !> This subroutine sets the open face lengths at selected points to restrict
748 !! passages to their observed widths from a arrays read from a file.
749 subroutine reset_face_lengths_file(G, param_file, US)
750  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
751  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
752  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
753 
754  ! Local variables
755  character(len=40) :: mdl = "reset_face_lengths_file" ! This subroutine's name.
756  character(len=256) :: mesg ! Message for error messages.
757  character(len=200) :: filename, chan_file, inputdir ! Strings for file/path
758  real :: m_to_l ! A unit conversion factor [L m-1 ~> nondim]
759  real :: l_to_m ! A unit conversion factor [m L-1 ~> nondim]
760  integer :: i, j, isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
761  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
762  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
763  ! These checks apply regardless of the chosen option.
764 
765  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
766  m_to_l = 1.0 ; if (present(us)) m_to_l = us%m_to_L
767  l_to_m = 1.0 ; if (present(us)) l_to_m = us%L_to_m
768 
769  call get_param(param_file, mdl, "CHANNEL_WIDTH_FILE", chan_file, &
770  "The file from which the list of narrowed channels is read.", &
771  default="ocean_geometry.nc")
772  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
773  inputdir = slasher(inputdir)
774  filename = trim(inputdir)//trim(chan_file)
775  call log_param(param_file, mdl, "INPUTDIR/CHANNEL_WIDTH_FILE", filename)
776 
777  if (is_root_pe()) then ; if (.not.file_exists(filename)) &
778  call mom_error(fatal," reset_face_lengths_file: Unable to open "//&
779  trim(filename))
780  endif
781 
782  call mom_read_vector(filename, "dyCuo", "dxCvo", g%dy_Cu, g%dx_Cv, g%Domain, scale=m_to_l)
783  call pass_vector(g%dy_Cu, g%dx_Cv, g%Domain, to_all+scalar_pair, cgrid_ne)
784 
785  do j=jsd,jed ; do i=isdb,iedb
786  if (l_to_m*g%dy_Cu(i,j) > l_to_m*g%dyCu(i,j)) then
787  write(mesg,'("dy_Cu of ",ES11.4," exceeds unrestricted width of ",ES11.4,&
788  &" by ",ES11.4," at lon/lat of ", ES11.4, ES11.4)') &
789  l_to_m*g%dy_Cu(i,j), l_to_m*g%dyCu(i,j), l_to_m*g%dy_Cu(i,j)-l_to_m*g%dyCu(i,j), &
790  g%geoLonCu(i,j), g%geoLatCu(i,j)
791  call mom_error(fatal,"reset_face_lengths_file "//mesg)
792  endif
793  g%areaCu(i,j) = g%dxCu(i,j) * g%dy_Cu(i,j)
794  g%IareaCu(i,j) = 0.0
795  if (g%areaCu(i,j) > 0.0) g%IareaCu(i,j) = g%mask2dCu(i,j) / (g%areaCu(i,j))
796  enddo ; enddo
797 
798  do j=jsdb,jedb ; do i=isd,ied
799  if (l_to_m*g%dx_Cv(i,j) > l_to_m*g%dxCv(i,j)) then
800  write(mesg,'("dx_Cv of ",ES11.4," exceeds unrestricted width of ",ES11.4,&
801  &" by ",ES11.4, " at lon/lat of ", ES11.4, ES11.4)') &
802  l_to_m*g%dx_Cv(i,j), l_to_m*g%dxCv(i,j), l_to_m*g%dx_Cv(i,j)-l_to_m*g%dxCv(i,j), &
803  g%geoLonCv(i,j), g%geoLatCv(i,j)
804 
805  call mom_error(fatal,"reset_face_lengths_file "//mesg)
806  endif
807  g%areaCv(i,j) = g%dyCv(i,j) * g%dx_Cv(i,j)
808  g%IareaCv(i,j) = 0.0
809  if (g%areaCv(i,j) > 0.0) g%IareaCv(i,j) = g%mask2dCv(i,j) / (g%areaCv(i,j))
810  enddo ; enddo
811 
812  call calltree_leave(trim(mdl)//'()')
813 end subroutine reset_face_lengths_file
814 ! -----------------------------------------------------------------------------
815 
816 ! -----------------------------------------------------------------------------
817 !> This subroutine sets the open face lengths at selected points to restrict
818 !! passages to their observed widths from a list read from a file.
819 subroutine reset_face_lengths_list(G, param_file, US)
820  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
821  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
822  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
823 
824  ! Local variables
825  character(len=120), pointer, dimension(:) :: lines => null()
826  character(len=120) :: line
827  character(len=200) :: filename, chan_file, inputdir, mesg ! Strings for file/path
828  character(len=40) :: mdl = "reset_face_lengths_list" ! This subroutine's name.
829  real, pointer, dimension(:,:) :: &
830  u_lat => null(), u_lon => null(), v_lat => null(), v_lon => null()
831  real, pointer, dimension(:) :: &
832  u_width => null(), v_width => null()
833  real :: m_to_l ! A unit conversion factor [L m-1 ~> nondim]
834  real :: l_to_m ! A unit conversion factor [m L-1 ~> nondim]
835  real :: lat, lon ! The latitude and longitude of a point.
836  real :: len_lon ! The periodic range of longitudes, usually 360 degrees.
837  real :: len_lat ! The range of latitudes, usually 180 degrees.
838  real :: lon_p, lon_m ! The longitude of a point shifted by 360 degrees.
839  logical :: check_360 ! If true, check for longitudes that are shifted by
840  ! +/- 360 degrees from the specified range of values.
841  logical :: found_u, found_v
842  logical :: unit_in_use
843  integer :: ios, iounit, isu, isv
844  integer :: last, num_lines, nl_read, ln, npt, u_pt, v_pt
845  integer :: i, j, isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
846  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
847  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
848 
849  call calltree_enter(trim(mdl)//"(), MOM_shared_initialization.F90")
850  m_to_l = 1.0 ; if (present(us)) m_to_l = us%m_to_L
851  l_to_m = 1.0 ; if (present(us)) l_to_m = us%L_to_m
852 
853  call get_param(param_file, mdl, "CHANNEL_LIST_FILE", chan_file, &
854  "The file from which the list of narrowed channels is read.", &
855  default="MOM_channel_list")
856  call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
857  inputdir = slasher(inputdir)
858  filename = trim(inputdir)//trim(chan_file)
859  call log_param(param_file, mdl, "INPUTDIR/CHANNEL_LIST_FILE", filename)
860  call get_param(param_file, mdl, "CHANNEL_LIST_360_LON_CHECK", check_360, &
861  "If true, the channel configuration list works for any "//&
862  "longitudes in the range of -360 to 360.", default=.true.)
863 
864  if (is_root_pe()) then
865  ! Open the input file.
866  if (.not.file_exists(filename)) call mom_error(fatal, &
867  " reset_face_lengths_list: Unable to open "//trim(filename))
868 
869  ! Find an unused unit number.
870  do iounit=10,512
871  INQUIRE(iounit,opened=unit_in_use) ; if (.not.unit_in_use) exit
872  enddo
873  if (iounit >= 512) call mom_error(fatal, &
874  "reset_face_lengths_list: No unused file unit could be found.")
875 
876  ! Open the parameter file.
877  open(iounit, file=trim(filename), access='SEQUENTIAL', &
878  form='FORMATTED', action='READ', position='REWIND', iostat=ios)
879  if (ios /= 0) call mom_error(fatal, &
880  "reset_face_lengths_list: Error opening "//trim(filename))
881 
882  ! Count the number of u_width and v_width entries.
883  call read_face_length_list(iounit, filename, num_lines, lines)
884  endif
885 
886  len_lon = 360.0 ; if (g%len_lon > 0.0) len_lon = g%len_lon
887  len_lat = 180.0 ; if (g%len_lat > 0.0) len_lat = g%len_lat
888  ! Broadcast the number of lines and allocate the required space.
889  call broadcast(num_lines, root_pe())
890  u_pt = 0 ; v_pt = 0
891  if (num_lines > 0) then
892  allocate (lines(num_lines))
893  if (num_lines > 0) then
894  allocate(u_lat(2,num_lines)) ; u_lat(:,:) = -1e34
895  allocate(u_lon(2,num_lines)) ; u_lon(:,:) = -1e34
896  allocate(u_width(num_lines)) ; u_width(:) = -1e34
897 
898  allocate(v_lat(2,num_lines)) ; v_lat(:,:) = -1e34
899  allocate(v_lon(2,num_lines)) ; v_lon(:,:) = -1e34
900  allocate(v_width(num_lines)) ; v_width(:) = -1e34
901  endif
902 
903  ! Actually read the lines.
904  if (is_root_pe()) then
905  call read_face_length_list(iounit, filename, nl_read, lines)
906  if (nl_read /= num_lines) &
907  call mom_error(fatal, 'reset_face_lengths_list : Found different '// &
908  'number of valid lines on second reading of '//trim(filename))
909  close(iounit) ; iounit = -1
910  endif
911 
912  ! Broadcast the lines.
913  call broadcast(lines, 120, root_pe())
914 
915  ! Populate the u_width, etc., data.
916  do ln=1,num_lines
917  line = lines(ln)
918  ! Detect keywords
919  found_u = .false.; found_v = .false.
920  isu = index(uppercase(line), "U_WIDTH" ); if (isu > 0) found_u = .true.
921  isv = index(uppercase(line), "V_WIDTH" ); if (isv > 0) found_v = .true.
922 
923  ! Store and check the relevant values.
924  if (found_u) then
925  u_pt = u_pt + 1
926  read(line(isu+8:),*) u_lon(1:2,u_pt), u_lat(1:2,u_pt), u_width(u_pt)
927  if (is_root_pe()) then
928  if (check_360) then
929  if ((abs(u_lon(1,u_pt)) > len_lon) .or. (abs(u_lon(2,u_pt)) > len_lon)) &
930  call mom_error(warning, "reset_face_lengths_list : Out-of-bounds "//&
931  "u-longitude found when reading line "//trim(line)//" from file "//&
932  trim(filename))
933  if ((abs(u_lat(1,u_pt)) > len_lat) .or. (abs(u_lat(2,u_pt)) > len_lat)) &
934  call mom_error(warning, "reset_face_lengths_list : Out-of-bounds "//&
935  "u-latitude found when reading line "//trim(line)//" from file "//&
936  trim(filename))
937  endif
938  if (u_lat(1,u_pt) > u_lat(2,u_pt)) &
939  call mom_error(warning, "reset_face_lengths_list : Out-of-order "//&
940  "u-face latitudes found when reading line "//trim(line)//" from file "//&
941  trim(filename))
942  if (u_lon(1,u_pt) > u_lon(2,u_pt)) &
943  call mom_error(warning, "reset_face_lengths_list : Out-of-order "//&
944  "u-face longitudes found when reading line "//trim(line)//" from file "//&
945  trim(filename))
946  if (u_width(u_pt) < 0.0) &
947  call mom_error(warning, "reset_face_lengths_list : Negative "//&
948  "u-width found when reading line "//trim(line)//" from file "//&
949  trim(filename))
950  endif
951  elseif (found_v) then
952  v_pt = v_pt + 1
953  read(line(isv+8:),*) v_lon(1:2,v_pt), v_lat(1:2,v_pt), v_width(v_pt)
954  if (is_root_pe()) then
955  if (check_360) then
956  if ((abs(v_lon(1,v_pt)) > len_lon) .or. (abs(v_lon(2,v_pt)) > len_lon)) &
957  call mom_error(warning, "reset_face_lengths_list : Out-of-bounds "//&
958  "v-longitude found when reading line "//trim(line)//" from file "//&
959  trim(filename))
960  if ((abs(v_lat(1,v_pt)) > len_lat) .or. (abs(v_lat(2,v_pt)) > len_lat)) &
961  call mom_error(warning, "reset_face_lengths_list : Out-of-bounds "//&
962  "v-latitude found when reading line "//trim(line)//" from file "//&
963  trim(filename))
964  endif
965  if (v_lat(1,v_pt) > v_lat(2,v_pt)) &
966  call mom_error(warning, "reset_face_lengths_list : Out-of-order "//&
967  "v-face latitudes found when reading line "//trim(line)//" from file "//&
968  trim(filename))
969  if (v_lon(1,v_pt) > v_lon(2,v_pt)) &
970  call mom_error(warning, "reset_face_lengths_list : Out-of-order "//&
971  "v-face longitudes found when reading line "//trim(line)//" from file "//&
972  trim(filename))
973  if (v_width(v_pt) < 0.0) &
974  call mom_error(warning, "reset_face_lengths_list : Negative "//&
975  "v-width found when reading line "//trim(line)//" from file "//&
976  trim(filename))
977  endif
978  endif
979  enddo
980 
981  deallocate(lines)
982  endif
983 
984  do j=jsd,jed ; do i=isdb,iedb
985  lat = g%geoLatCu(i,j) ; lon = g%geoLonCu(i,j)
986  if (check_360) then ; lon_p = lon+len_lon ; lon_m = lon-len_lon
987  else ; lon_p = lon ; lon_m = lon ; endif
988 
989  do npt=1,u_pt
990  if (((lat >= u_lat(1,npt)) .and. (lat <= u_lat(2,npt))) .and. &
991  (((lon >= u_lon(1,npt)) .and. (lon <= u_lon(2,npt))) .or. &
992  ((lon_p >= u_lon(1,npt)) .and. (lon_p <= u_lon(2,npt))) .or. &
993  ((lon_m >= u_lon(1,npt)) .and. (lon_m <= u_lon(2,npt)))) ) then
994 
995  g%dy_Cu(i,j) = g%mask2dCu(i,j) * m_to_l*min(l_to_m*g%dyCu(i,j), max(u_width(npt), 0.0))
996  if (j>=g%jsc .and. j<=g%jec .and. i>=g%isc .and. i<=g%iec) then ! Limit messages/checking to compute domain
997  if ( g%mask2dCu(i,j) == 0.0 ) then
998  write(*,'(A,2F8.2,A,4F8.2,A)') "read_face_lengths_list : G%mask2dCu=0 at ",lat,lon," (",&
999  u_lat(1,npt), u_lat(2,npt), u_lon(1,npt), u_lon(2,npt),") so grid metric is unmodified."
1000  else
1001  write(*,'(A,2F8.2,A,4F8.2,A5,F9.2,A1)') &
1002  "read_face_lengths_list : Modifying dy_Cu gridpoint at ",lat,lon," (",&
1003  u_lat(1,npt), u_lat(2,npt), u_lon(1,npt), u_lon(2,npt),") to ",l_to_m*g%dy_Cu(i,j),"m"
1004  endif
1005  endif
1006  endif
1007  enddo
1008 
1009  g%areaCu(i,j) = g%dxCu(i,j) * g%dy_Cu(i,j)
1010  g%IareaCu(i,j) = 0.0
1011  if (g%areaCu(i,j) > 0.0) g%IareaCu(i,j) = g%mask2dCu(i,j) / (g%areaCu(i,j))
1012  enddo ; enddo
1013 
1014  do j=jsdb,jedb ; do i=isd,ied
1015  lat = g%geoLatCv(i,j) ; lon = g%geoLonCv(i,j)
1016  if (check_360) then ; lon_p = lon+len_lon ; lon_m = lon-len_lon
1017  else ; lon_p = lon ; lon_m = lon ; endif
1018 
1019  do npt=1,v_pt
1020  if (((lat >= v_lat(1,npt)) .and. (lat <= v_lat(2,npt))) .and. &
1021  (((lon >= v_lon(1,npt)) .and. (lon <= v_lon(2,npt))) .or. &
1022  ((lon_p >= v_lon(1,npt)) .and. (lon_p <= v_lon(2,npt))) .or. &
1023  ((lon_m >= v_lon(1,npt)) .and. (lon_m <= v_lon(2,npt)))) ) then
1024  g%dx_Cv(i,j) = g%mask2dCv(i,j) * m_to_l*min(l_to_m*g%dxCv(i,j), max(v_width(npt), 0.0))
1025  if (i>=g%isc .and. i<=g%iec .and. j>=g%jsc .and. j<=g%jec) then ! Limit messages/checking to compute domain
1026  if ( g%mask2dCv(i,j) == 0.0 ) then
1027  write(*,'(A,2F8.2,A,4F8.2,A)') "read_face_lengths_list : G%mask2dCv=0 at ",lat,lon," (",&
1028  v_lat(1,npt), v_lat(2,npt), v_lon(1,npt), v_lon(2,npt),") so grid metric is unmodified."
1029  else
1030  write(*,'(A,2F8.2,A,4F8.2,A5,F9.2,A1)') &
1031  "read_face_lengths_list : Modifying dx_Cv gridpoint at ",lat,lon," (",&
1032  v_lat(1,npt), v_lat(2,npt), v_lon(1,npt), v_lon(2,npt),") to ",l_to_m*g%dx_Cv(i,j),"m"
1033  endif
1034  endif
1035  endif
1036  enddo
1037 
1038  g%areaCv(i,j) = g%dyCv(i,j) * g%dx_Cv(i,j)
1039  g%IareaCv(i,j) = 0.0
1040  if (g%areaCv(i,j) > 0.0) g%IareaCv(i,j) = g%mask2dCv(i,j) / (g%areaCv(i,j))
1041  enddo ; enddo
1042 
1043  if (num_lines > 0) then
1044  deallocate(u_lat) ; deallocate(u_lon) ; deallocate(u_width)
1045  deallocate(v_lat) ; deallocate(v_lon) ; deallocate(v_width)
1046  endif
1047 
1048  call calltree_leave(trim(mdl)//'()')
1049 end subroutine reset_face_lengths_list
1050 ! -----------------------------------------------------------------------------
1051 
1052 ! -----------------------------------------------------------------------------
1053 !> This subroutine reads and counts the non-blank lines in the face length list file, after removing comments.
1054 subroutine read_face_length_list(iounit, filename, num_lines, lines)
1055  integer, intent(in) :: iounit !< An open I/O unit number for the file
1056  character(len=*), intent(in) :: filename !< The name of the face-length file to read
1057  integer, intent(out) :: num_lines !< The number of non-blank lines in the file
1058  character(len=120), dimension(:), pointer :: lines !< The non-blank lines, after removing comments
1059 
1060  ! This subroutine reads and counts the non-blank lines in the face length
1061  ! list file, after removing comments.
1062  character(len=120) :: line, line_up
1063  logical :: found_u, found_v
1064  integer :: isu, isv, icom, verbose
1065  integer :: last
1066 
1067  num_lines = 0
1068 
1069  if (iounit <= 0) return
1070  rewind(iounit)
1071  do while(.true.)
1072  read(iounit, '(a)', end=8, err=9) line
1073  last = len_trim(line)
1074  ! Eliminate either F90 or C comments from the line.
1075  icom = index(line(:last), "!") ; if (icom > 0) last = icom-1
1076  icom = index(line(:last), "/*") ; if (icom > 0) last = icom-1
1077  if (last < 1) cycle
1078 
1079  ! Detect keywords
1080  line_up = uppercase(line)
1081  found_u = .false.; found_v = .false.
1082  isu = index(line_up(:last), "U_WIDTH" ); if (isu > 0) found_u = .true.
1083  isv = index(line_up(:last), "V_WIDTH" ); if (isv > 0) found_v = .true.
1084 
1085  if (found_u .and. found_v) call mom_error(fatal, &
1086  "read_face_length_list : both U_WIDTH and V_WIDTH found when "//&
1087  "reading the line "//trim(line(:last))//" in file "//trim(filename))
1088  if (found_u .or. found_v) then
1089  num_lines = num_lines + 1
1090  if (associated(lines)) then
1091  lines(num_lines) = line(1:last)
1092  endif
1093  endif
1094  enddo ! while (.true.)
1095 
1096 8 continue
1097  return
1098 
1099 9 call mom_error(fatal, "read_face_length_list : "//&
1100  "Error while reading file "//trim(filename))
1101 
1102 end subroutine read_face_length_list
1103 ! -----------------------------------------------------------------------------
1104 
1105 ! -----------------------------------------------------------------------------
1106 !> Set the bathymetry at velocity points to be the maximum of the depths at the
1107 !! neighoring tracer points.
1108 subroutine set_velocity_depth_max(G)
1109  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
1110  ! This subroutine sets the 4 bottom depths at velocity points to be the
1111  ! maximum of the adjacent depths.
1112  integer :: i, j
1113 
1114  do i=g%isd,g%ied-1 ; do j=g%jsd,g%jed
1115  g%Dblock_u(i,j) = g%mask2dCu(i,j) * max(g%bathyT(i,j), g%bathyT(i+1,j))
1116  g%Dopen_u(i,j) = g%Dblock_u(i,j)
1117  enddo ; enddo
1118  do i=g%isd,g%ied ; do j=g%jsd,g%jed-1
1119  g%Dblock_v(i,j) = g%mask2dCv(i,j) * max(g%bathyT(i,j), g%bathyT(i,j+1))
1120  g%Dopen_v(i,j) = g%Dblock_v(i,j)
1121  enddo ; enddo
1122 end subroutine set_velocity_depth_max
1123 ! -----------------------------------------------------------------------------
1124 
1125 ! -----------------------------------------------------------------------------
1126 !> Set the bathymetry at velocity points to be the minimum of the depths at the
1127 !! neighoring tracer points.
1128 subroutine set_velocity_depth_min(G)
1129  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
1130  ! This subroutine sets the 4 bottom depths at velocity points to be the
1131  ! minimum of the adjacent depths.
1132  integer :: i, j
1133 
1134  do i=g%isd,g%ied-1 ; do j=g%jsd,g%jed
1135  g%Dblock_u(i,j) = g%mask2dCu(i,j) * min(g%bathyT(i,j), g%bathyT(i+1,j))
1136  g%Dopen_u(i,j) = g%Dblock_u(i,j)
1137  enddo ; enddo
1138  do i=g%isd,g%ied ; do j=g%jsd,g%jed-1
1139  g%Dblock_v(i,j) = g%mask2dCv(i,j) * min(g%bathyT(i,j), g%bathyT(i,j+1))
1140  g%Dopen_v(i,j) = g%Dblock_v(i,j)
1141  enddo ; enddo
1142 end subroutine set_velocity_depth_min
1143 ! -----------------------------------------------------------------------------
1144 
1145 ! -----------------------------------------------------------------------------
1146 !> Pre-compute global integrals of grid quantities (like masked ocean area) for
1147 !! later use in reporting diagnostics
1148 subroutine compute_global_grid_integrals(G, US)
1149  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
1150  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
1151 
1152  ! Local variables
1153  real, dimension(G%isc:G%iec, G%jsc:G%jec) :: tmpforsumming
1154  real :: area_scale ! A scaling factor for area into MKS units
1155  integer :: i,j
1156 
1157  area_scale = 1.0 ; if (present(us)) area_scale = us%L_to_m**2
1158 
1159  tmpforsumming(:,:) = 0.
1160  g%areaT_global = 0.0 ; g%IareaT_global = 0.0
1161  do j=g%jsc,g%jec ; do i=g%isc,g%iec
1162  tmpforsumming(i,j) = area_scale*g%areaT(i,j) * g%mask2dT(i,j)
1163  enddo ; enddo
1164  g%areaT_global = reproducing_sum(tmpforsumming)
1165 
1166  if (g%areaT_global == 0.0) &
1167  call mom_error(fatal, "compute_global_grid_integrals: "//&
1168  "zero ocean area (check topography?)")
1169 
1170  g%IareaT_global = 1.0 / (g%areaT_global)
1171 end subroutine compute_global_grid_integrals
1172 ! -----------------------------------------------------------------------------
1173 
1174 ! -----------------------------------------------------------------------------
1175 !> Write out a file describing the topography, Coriolis parameter, grid locations
1176 !! and various other fixed fields from the grid.
1177 subroutine write_ocean_geometry_file(G, param_file, directory, geom_file, US)
1178  type(dyn_horgrid_type), intent(inout) :: g !< The dynamic horizontal grid
1179  type(param_file_type), intent(in) :: param_file !< Parameter file structure
1180  character(len=*), intent(in) :: directory !< The directory into which to place the geometry file.
1181  character(len=*), optional, intent(in) :: geom_file !< If present, the name of the geometry file
1182  !! (otherwise the file is "ocean_geometry")
1183  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
1184 
1185  ! Local variables.
1186  character(len=240) :: filepath
1187  character(len=40) :: mdl = "write_ocean_geometry_file"
1188  integer, parameter :: nflds=23
1189  type(vardesc) :: vars(nflds)
1190  type(fieldtype) :: fields(nflds)
1191  real :: z_to_m_scale ! A unit conversion factor from Z to m.
1192  real :: s_to_t_scale ! A unit conversion factor from T-1 to s-1.
1193  real :: l_to_m_scale ! A unit conversion factor from L to m.
1194  integer :: unit
1195  integer :: file_threading
1196  integer :: nflds_used
1197  integer :: i, j, is, ie, js, je, isq, ieq, jsq, jeq
1198  integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
1199  logical :: multiple_files
1200  real, dimension(G%isd :G%ied ,G%jsd :G%jed ) :: out_h
1201  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB) :: out_q
1202  real, dimension(G%IsdB:G%IedB,G%jsd :G%jed ) :: out_u
1203  real, dimension(G%isd :G%ied ,G%JsdB:G%JedB) :: out_v
1204 
1205  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1206  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
1207  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1208  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1209 
1210  z_to_m_scale = 1.0 ; if (present(us)) z_to_m_scale = us%Z_to_m
1211  s_to_t_scale = 1.0 ; if (present(us)) s_to_t_scale = us%s_to_T
1212  l_to_m_scale = 1.0 ; if (present(us)) l_to_m_scale = us%L_to_m
1213 
1214 ! vardesc is a structure defined in MOM_io.F90. The elements of
1215 ! this structure, in order, are:
1216 ! (1) the variable name for the NetCDF file
1217 ! (2) the variable's long name
1218 ! (3) a character indicating the horizontal grid, which may be '1' (column),
1219 ! 'h', 'q', 'u', or 'v', for the corresponding C-grid variable
1220 ! (4) a character indicating the vertical grid, which may be 'L' (layer),
1221 ! 'i' (interface), or '1' (no vertical location)
1222 ! (5) a character indicating the time levels of the field, which may be
1223 ! 's' (snap-shot), 'p' (periodic), or '1' (no time variation)
1224 ! (6) the variable's units
1225  vars(1) = var_desc("geolatb","degree","latitude at corner (Bu) points",'q','1','1')
1226  vars(2) = var_desc("geolonb","degree","longitude at corner (Bu) points",'q','1','1')
1227  vars(3) = var_desc("geolat","degree", "latitude at tracer (T) points", 'h','1','1')
1228  vars(4) = var_desc("geolon","degree","longitude at tracer (T) points",'h','1','1')
1229  vars(5) = var_desc("D","meter","Basin Depth",'h','1','1')
1230  vars(6) = var_desc("f","s-1","Coriolis Parameter",'q','1','1')
1231  vars(7) = var_desc("dxCv","m","Zonal grid spacing at v points",'v','1','1')
1232  vars(8) = var_desc("dyCu","m","Meridional grid spacing at u points",'u','1','1')
1233  vars(9) = var_desc("dxCu","m","Zonal grid spacing at u points",'u','1','1')
1234  vars(10)= var_desc("dyCv","m","Meridional grid spacing at v points",'v','1','1')
1235  vars(11)= var_desc("dxT","m","Zonal grid spacing at h points",'h','1','1')
1236  vars(12)= var_desc("dyT","m","Meridional grid spacing at h points",'h','1','1')
1237  vars(13)= var_desc("dxBu","m","Zonal grid spacing at q points",'q','1','1')
1238  vars(14)= var_desc("dyBu","m","Meridional grid spacing at q points",'q','1','1')
1239  vars(15)= var_desc("Ah","m2","Area of h cells",'h','1','1')
1240  vars(16)= var_desc("Aq","m2","Area of q cells",'q','1','1')
1241 
1242  vars(17)= var_desc("dxCvo","m","Open zonal grid spacing at v points",'v','1','1')
1243  vars(18)= var_desc("dyCuo","m","Open meridional grid spacing at u points",'u','1','1')
1244  vars(19)= var_desc("wet", "nondim", "land or ocean?", 'h','1','1')
1245 
1246  vars(20) = var_desc("Dblock_u","m","Blocked depth at u points",'u','1','1')
1247  vars(21) = var_desc("Dopen_u","m","Open depth at u points",'u','1','1')
1248  vars(22) = var_desc("Dblock_v","m","Blocked depth at v points",'v','1','1')
1249  vars(23) = var_desc("Dopen_v","m","Open depth at v points",'v','1','1')
1250 
1251 
1252  nflds_used = 19 ; if (g%bathymetry_at_vel) nflds_used = 23
1253 
1254  if (present(geom_file)) then
1255  filepath = trim(directory) // trim(geom_file)
1256  else
1257  filepath = trim(directory) // "ocean_geometry"
1258  endif
1259 
1260  out_h(:,:) = 0.0
1261  out_u(:,:) = 0.0
1262  out_v(:,:) = 0.0
1263  out_q(:,:) = 0.0
1264 
1265  call get_param(param_file, mdl, "PARALLEL_RESTARTFILES", multiple_files, &
1266  "If true, each processor writes its own restart file, "//&
1267  "otherwise a single restart file is generated", &
1268  default=.false.)
1269  file_threading = single_file
1270  if (multiple_files) file_threading = multiple
1271 
1272  call create_file(unit, trim(filepath), vars, nflds_used, fields, &
1273  file_threading, dg=g)
1274 
1275  do j=jsq,jeq; do i=isq,ieq; out_q(i,j) = g%geoLatBu(i,j); enddo ; enddo
1276  call write_field(unit, fields(1), g%Domain%mpp_domain, out_q)
1277  do j=jsq,jeq; do i=isq,ieq; out_q(i,j) = g%geoLonBu(i,j); enddo ; enddo
1278  call write_field(unit, fields(2), g%Domain%mpp_domain, out_q)
1279  call write_field(unit, fields(3), g%Domain%mpp_domain, g%geoLatT)
1280  call write_field(unit, fields(4), g%Domain%mpp_domain, g%geoLonT)
1281 
1282  do j=js,je ; do i=is,ie ; out_h(i,j) = z_to_m_scale*g%bathyT(i,j) ; enddo ; enddo
1283  call write_field(unit, fields(5), g%Domain%mpp_domain, out_h)
1284  do j=jsq,jeq ; do i=isq,ieq ; out_q(i,j) = s_to_t_scale*g%CoriolisBu(i,j) ; enddo ; enddo
1285  call write_field(unit, fields(6), g%Domain%mpp_domain, out_q)
1286 
1287  ! I think that all of these copies are holdovers from a much earlier
1288  ! ancestor code in which many of the metrics were macros that could have
1289  ! had reduced dimensions, and that they are no longer needed in MOM6. -RWH
1290  do j=jsq,jeq ; do i=is,ie ; out_v(i,j) = l_to_m_scale*g%dxCv(i,j) ; enddo ; enddo
1291  call write_field(unit, fields(7), g%Domain%mpp_domain, out_v)
1292  do j=js,je ; do i=isq,ieq ; out_u(i,j) = l_to_m_scale*g%dyCu(i,j) ; enddo ; enddo
1293  call write_field(unit, fields(8), g%Domain%mpp_domain, out_u)
1294 
1295  do j=js,je ; do i=isq,ieq ; out_u(i,j) = l_to_m_scale*g%dxCu(i,j) ; enddo ; enddo
1296  call write_field(unit, fields(9), g%Domain%mpp_domain, out_u)
1297  do j=jsq,jeq ; do i=is,ie ; out_v(i,j) = l_to_m_scale*g%dyCv(i,j) ; enddo ; enddo
1298  call write_field(unit, fields(10), g%Domain%mpp_domain, out_v)
1299 
1300  do j=js,je ; do i=is,ie ; out_h(i,j) = l_to_m_scale*g%dxT(i,j); enddo ; enddo
1301  call write_field(unit, fields(11), g%Domain%mpp_domain, out_h)
1302  do j=js,je ; do i=is,ie ; out_h(i,j) = l_to_m_scale*g%dyT(i,j) ; enddo ; enddo
1303  call write_field(unit, fields(12), g%Domain%mpp_domain, out_h)
1304 
1305  do j=jsq,jeq ; do i=isq,ieq ; out_q(i,j) = l_to_m_scale*g%dxBu(i,j) ; enddo ; enddo
1306  call write_field(unit, fields(13), g%Domain%mpp_domain, out_q)
1307  do j=jsq,jeq ; do i=isq,ieq ; out_q(i,j) = l_to_m_scale*g%dyBu(i,j) ; enddo ; enddo
1308  call write_field(unit, fields(14), g%Domain%mpp_domain, out_q)
1309 
1310  do j=js,je ; do i=is,ie ; out_h(i,j) = g%areaT(i,j) ; enddo ; enddo
1311  call write_field(unit, fields(15), g%Domain%mpp_domain, out_h)
1312  do j=jsq,jeq ; do i=isq,ieq ; out_q(i,j) = g%areaBu(i,j) ; enddo ; enddo
1313  call write_field(unit, fields(16), g%Domain%mpp_domain, out_q)
1314 
1315  do j=jsq,jeq ; do i=is,ie ; out_v(i,j) = l_to_m_scale*g%dx_Cv(i,j) ; enddo ; enddo
1316  call write_field(unit, fields(17), g%Domain%mpp_domain, out_v)
1317  do j=js,je ; do i=isq,ieq ; out_u(i,j) = l_to_m_scale*g%dy_Cu(i,j) ; enddo ; enddo
1318  call write_field(unit, fields(18), g%Domain%mpp_domain, out_u)
1319  call write_field(unit, fields(19), g%Domain%mpp_domain, g%mask2dT)
1320 
1321  if (g%bathymetry_at_vel) then
1322  do j=js,je ; do i=isq,ieq ; out_u(i,j) = z_to_m_scale*g%Dblock_u(i,j) ; enddo ; enddo
1323  call write_field(unit, fields(20), g%Domain%mpp_domain, out_u)
1324  do j=js,je ; do i=isq,ieq ; out_u(i,j) = z_to_m_scale*g%Dopen_u(i,j) ; enddo ; enddo
1325  call write_field(unit, fields(21), g%Domain%mpp_domain, out_u)
1326  do j=jsq,jeq ; do i=is,ie ; out_v(i,j) = z_to_m_scale*g%Dblock_v(i,j) ; enddo ; enddo
1327  call write_field(unit, fields(22), g%Domain%mpp_domain, out_v)
1328  do j=jsq,jeq ; do i=is,ie ; out_v(i,j) = z_to_m_scale*g%Dopen_v(i,j) ; enddo ; enddo
1329  call write_field(unit, fields(23), g%Domain%mpp_domain, out_v)
1330  endif
1331 
1332  call close_file(unit)
1333 
1334 end subroutine write_ocean_geometry_file
1335 
1336 end module mom_shared_initialization
mom_shared_initialization
Code that initializes fixed aspects of the model grid, such as horizontal grid metrics,...
Definition: MOM_shared_initialization.F90:3
mom_io::var_desc
type(vardesc) function, public var_desc(name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, cmor_longname, conversion, caller)
Returns a vardesc type whose elements have been filled with the provided fields. The argument name is...
Definition: MOM_io.F90:600
mom_shared_initialization::reset_face_lengths_file
subroutine, public reset_face_lengths_file(G, param_file, US)
This subroutine sets the open face lengths at selected points to restrict passages to their observed ...
Definition: MOM_shared_initialization.F90:750
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_shared_initialization::mom_shared_init_init
subroutine, public mom_shared_init_init(PF)
MOM_shared_init_init just writes the code version.
Definition: MOM_shared_initialization.F90:43
mom_dyn_horgrid
Contains a shareable dynamic type for describing horizontal grids and metric data and utilty routines...
Definition: MOM_dyn_horgrid.F90:3
mom_string_functions
Handy functions for manipulating strings.
Definition: MOM_string_functions.F90:2
mom_error_handler::mom_mesg
subroutine, public mom_mesg(message, verb, all_print)
This provides a convenient interface for writing an informative comment.
Definition: MOM_error_handler.F90:53
mom_shared_initialization::read_face_length_list
subroutine, public read_face_length_list(iounit, filename, num_lines, lines)
This subroutine reads and counts the non-blank lines in the face length list file,...
Definition: MOM_shared_initialization.F90:1055
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:49
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_shared_initialization::set_rotation_beta_plane
subroutine, public set_rotation_beta_plane(f, G, param_file, US)
This subroutine sets up the Coriolis parameter for a beta-plane or f-plane.
Definition: MOM_shared_initialization.F90:497
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_string_functions::uppercase
character(len=len(input_string)) function, public uppercase(input_string)
Return a string in which all uppercase letters have been replaced by their lowercase counterparts.
Definition: MOM_string_functions.F90:42
mom_shared_initialization::reset_face_lengths_named
subroutine, public reset_face_lengths_named(G, param_file, name, US)
This subroutine sets the open face lengths at selected points to restrict passages to their observed ...
Definition: MOM_shared_initialization.F90:622
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_coms
Interfaces to non-domain-oriented communication subroutines, including the MOM6 reproducing sums faci...
Definition: MOM_coms.F90:3
mom_shared_initialization::set_velocity_depth_min
subroutine, public set_velocity_depth_min(G)
Set the bathymetry at velocity points to be the minimum of the depths at the neighoring tracer points...
Definition: MOM_shared_initialization.F90:1129
mom_shared_initialization::limit_topography
subroutine, public limit_topography(D, G, param_file, max_depth, US)
limit_topography ensures that min_depth < D(x,y) < max_depth
Definition: MOM_shared_initialization.F90:415
mom_domains::pass_vector
Do a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:54
mom_domains::to_all
integer, parameter, public to_all
A flag for passing in all directions.
Definition: MOM_domains.F90:132
mom_shared_initialization::initialize_topography_from_file
subroutine, public initialize_topography_from_file(D, G, param_file, US)
Read gridded depths from file.
Definition: MOM_shared_initialization.F90:141
mom_shared_initialization::set_velocity_depth_max
subroutine, public set_velocity_depth_max(G)
Set the bathymetry at velocity points to be the maximum of the depths at the neighoring tracer points...
Definition: MOM_shared_initialization.F90:1109
mom_shared_initialization::set_rotation_planetary
subroutine, public set_rotation_planetary(f, G, param_file, US)
This subroutine sets up the Coriolis parameter for a sphere.
Definition: MOM_shared_initialization.F90:464
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_io::mom_read_vector
Read a pair of data fields representing the two components of a vector from a file.
Definition: MOM_io.F90:82
mom_shared_initialization::apply_topography_edits_from_file
subroutine, public apply_topography_edits_from_file(D, G, param_file, US)
Applies a list of topography overrides read from a netcdf file.
Definition: MOM_shared_initialization.F90:186
mom_shared_initialization::initialize_topography_named
subroutine, public initialize_topography_named(D, G, param_file, topog_config, max_depth, US)
initialize the bathymetry based on one of several named idealized configurations
Definition: MOM_shared_initialization.F90:302
mom_io::mom_read_data
Read a data field from a file.
Definition: MOM_io.F90:74
mom_shared_initialization::mom_initialize_rotation
subroutine, public mom_initialize_rotation(f, G, PF, US)
MOM_initialize_rotation makes the appropriate call to set up the Coriolis parameter.
Definition: MOM_shared_initialization.F90:58
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_shared_initialization::mom_calculate_grad_coriolis
subroutine, public mom_calculate_grad_coriolis(dF_dx, dF_dy, G, US)
Calculates the components of grad f (Coriolis parameter)
Definition: MOM_shared_initialization.F90:91
mom_error_handler::calltree_leave
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
Definition: MOM_error_handler.F90:151
mom_io::create_file
subroutine, public create_file(unit, filename, vars, novars, fields, threading, timeunit, G, dG, GV, checksums)
Routine creates a new NetCDF file. It also sets up structures that describe this file and variables t...
Definition: MOM_io.F90:93
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
mom_error_handler::is_root_pe
logical function, public is_root_pe()
This returns .true. if the current PE is the root PE.
Definition: MOM_error_handler.F90:44
mom_io::vardesc
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:53
mom_shared_initialization::modulo_around_point
real function modulo_around_point(x, xc, Lx)
Return the modulo value of x in an interval [xc-(Lx/2) xc+(Lx/2)] If Lx<=0, then it returns x without...
Definition: MOM_shared_initialization.F90:606
mom_shared_initialization::initialize_grid_rotation_angle
subroutine, public initialize_grid_rotation_angle(G, PF)
initialize_grid_rotation_angle initializes the arrays with the sine and cosine of the angle between l...
Definition: MOM_shared_initialization.F90:548
mom_io::file_exists
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
mom_error_handler::mom_error
subroutine, public mom_error(level, message, all_print)
This provides a convenient interface for writing an mpp_error message with run-time filter based on a...
Definition: MOM_error_handler.F90:72
mom_error_handler::calltree_waypoint
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
Definition: MOM_error_handler.F90:161
mom_coms::reproducing_sum
Find an accurate and order-invariant sum of distributed 2d or 3d fields.
Definition: MOM_coms.F90:54
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_shared_initialization::reset_face_lengths_list
subroutine, public reset_face_lengths_list(G, param_file, US)
This subroutine sets the open face lengths at selected points to restrict passages to their observed ...
Definition: MOM_shared_initialization.F90:820
mom_shared_initialization::write_ocean_geometry_file
subroutine, public write_ocean_geometry_file(G, param_file, directory, geom_file, US)
Write out a file describing the topography, Coriolis parameter, grid locations and various other fixe...
Definition: MOM_shared_initialization.F90:1178
mom_shared_initialization::compute_global_grid_integrals
subroutine, public compute_global_grid_integrals(G, US)
Pre-compute global integrals of grid quantities (like masked ocean area) for later use in reporting d...
Definition: MOM_shared_initialization.F90:1149
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_error_handler::calltree_enter
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.
Definition: MOM_error_handler.F90:130
mom_dyn_horgrid::dyn_horgrid_type
Describes the horizontal ocean grid with only dynamic memory arrays.
Definition: MOM_dyn_horgrid.F90:23
mom_shared_initialization::diagnosemaximumdepth
real function, public diagnosemaximumdepth(D, G)
Return the global maximum ocean bottom depth in the same units as the input depth.
Definition: MOM_shared_initialization.F90:125