MOM6
MOM_horizontal_regridding.F90
1 !> Horizontal interpolation
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_debugging, only : hchksum
7 use mom_coms, only : max_across_pes, min_across_pes
8 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
9 use mom_cpu_clock, only : clock_routine, clock_loop
10 use mom_domains, only : pass_var, pass_vector, sum_across_pes, broadcast
11 use mom_domains, only : root_pe, to_all, scalar_pair, cgrid_ne, agrid
12 use mom_error_handler, only : mom_mesg, mom_error, fatal, warning, is_root_pe
13 use mom_error_handler, only : calltree_enter, calltree_leave, calltree_waypoint
15 use mom_file_parser, only : log_version
16 use mom_get_input, only : directories
17 use mom_grid, only : ocean_grid_type, ispointincell
18 use mom_io, only : close_file, fieldtype, file_exists
19 use mom_io, only : open_file, read_data, read_axis_data, single_file, multiple
20 use mom_io, only : slasher, vardesc, write_field
21 use mom_string_functions, only : uppercase
22 use mom_time_manager, only : time_type, get_external_field_size
23 use mom_time_manager, only : init_external_field
24 use mom_time_manager, only : get_external_field_axes, get_external_field_missing
25 use mom_transform_fms, only : time_interp_external => rotated_time_interp_external
27 use mpp_io_mod, only : axistype
28 use mpp_domains_mod, only : mpp_global_field, mpp_get_compute_domain
29 use mpp_mod, only : mpp_broadcast,mpp_root_pe,mpp_sync,mpp_sync_self
30 use mpp_mod, only : mpp_max
31 use horiz_interp_mod, only : horiz_interp_new, horiz_interp,horiz_interp_type
32 use horiz_interp_mod, only : horiz_interp_init, horiz_interp_del
33 
34 use mpp_io_mod, only : mpp_get_axis_data
35 use mpp_io_mod, only : mpp_single
36 use netcdf
37 
38 implicit none ; private
39 
40 #include <MOM_memory.h>
41 
42 public :: horiz_interp_and_extrap_tracer, mystats
43 
44 ! character(len=40) :: mdl = "MOM_horizontal_regridding" ! This module's name.
45 
46 !> Fill grid edges
47 interface fill_boundaries
48  module procedure fill_boundaries_real
49  module procedure fill_boundaries_int
50 end interface
51 
52 !> Extrapolate and interpolate data
54  module procedure horiz_interp_and_extrap_tracer_record
55  module procedure horiz_interp_and_extrap_tracer_fms_id
56 end interface
57 
58 contains
59 
60 !> Write to the terminal some basic statistics about the k-th level of an array
61 subroutine mystats(array, missing, is, ie, js, je, k, mesg)
62  real, dimension(:,:), intent(in) :: array !< input array (ND)
63  real, intent(in) :: missing !< missing value (ND)
64  integer :: is !< Start index in i
65  integer :: ie !< End index in i
66  integer :: js !< Start index in j
67  integer :: je !< End index in j
68  integer :: k !< Level to calculate statistics for
69  character(len=*) :: mesg !< Label to use in message
70  ! Local variables
71  real :: mina, maxa
72  integer :: i,j
73  logical :: found
74  character(len=120) :: lmesg
75  mina = 9.e24 ; maxa = -9.e24 ; found = .false.
76 
77  do j=js,je ; do i=is,ie
78  if (array(i,j) /= array(i,j)) stop 'Nan!'
79  if (abs(array(i,j)-missing) > 1.e-6*abs(missing)) then
80  if (found) then
81  mina = min(mina, array(i,j))
82  maxa = max(maxa, array(i,j))
83  else
84  found = .true.
85  mina = array(i,j)
86  maxa = array(i,j)
87  endif
88  endif
89  enddo ; enddo
90  call min_across_pes(mina)
91  call max_across_pes(maxa)
92  if (is_root_pe()) then
93  write(lmesg(1:120),'(2(a,es12.4),a,i3,x,a)') &
94  'init_from_Z: min=',mina,' max=',maxa,' Level=',k,trim(mesg)
95  call mom_mesg(lmesg,2)
96  endif
97 
98 end subroutine mystats
99 
100 !> Use ICE-9 algorithm to populate points (fill=1) with
101 !! valid data (good=1). If no information is available,
102 !! Then use a previous guess (prev). Optionally (smooth)
103 !! blend the filled points to achieve a more desirable result.
104 subroutine fill_miss_2d(aout, good, fill, prev, G, smooth, num_pass, relc, crit, debug, answers_2018)
105  use mom_coms, only : sum_across_pes
106 
107  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
108  real, dimension(SZI_(G),SZJ_(G)), &
109  intent(inout) :: aout !< The array with missing values to fill
110  real, dimension(SZI_(G),SZJ_(G)), &
111  intent(in) :: good !< Valid data mask for incoming array
112  !! (1==good data; 0==missing data).
113  real, dimension(SZI_(G),SZJ_(G)), &
114  intent(in) :: fill !< Same shape array of points which need
115  !! filling (1==fill;0==dont fill)
116  real, dimension(SZI_(G),SZJ_(G)), &
117  optional, intent(in) :: prev !< First guess where isolated holes exist.
118  logical, optional, intent(in) :: smooth !< If present and true, apply a number of
119  !! Laplacian iterations to the interpolated data
120  integer, optional, intent(in) :: num_pass !< The maximum number of iterations
121  real, optional, intent(in) :: relc !< A relaxation coefficient for Laplacian (ND)
122  real, optional, intent(in) :: crit !< A minimal value for deltas between iterations.
123  logical, optional, intent(in) :: debug !< If true, write verbose debugging messages.
124  logical, optional, intent(in) :: answers_2018 !< If true, use expressions that give the same
125  !! answers as the code did in late 2018. Otherwise
126  !! add parentheses for rotational symmetry.
127 
128  real, dimension(SZI_(G),SZJ_(G)) :: b,r
129  real, dimension(SZI_(G),SZJ_(G)) :: fill_pts, good_, good_new
130 
131  character(len=256) :: mesg ! The text of an error message
132  integer :: i,j,k
133  real :: east,west,north,south,sor
134  real :: ge,gw,gn,gs,ngood
135  logical :: do_smooth,siena_bug
136  real :: nfill, nfill_prev
137  integer, parameter :: num_pass_default = 10000
138  real, parameter :: relc_default = 0.25, crit_default = 1.e-3
139 
140  integer :: npass
141  integer :: is, ie, js, je
142  real :: relax_coeff, acrit, ares
143  logical :: debug_it, ans_2018
144 
145  debug_it=.false.
146  if (PRESENT(debug)) debug_it=debug
147 
148  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
149 
150  npass = num_pass_default
151  if (PRESENT(num_pass)) npass = num_pass
152 
153  relax_coeff = relc_default
154  if (PRESENT(relc)) relax_coeff = relc
155 
156  acrit = crit_default
157  if (PRESENT(crit)) acrit = crit
158 
159  do_smooth=.false.
160  if (PRESENT(smooth)) do_smooth=smooth
161 
162  ans_2018 = .true. ; if (PRESENT(answers_2018)) ans_2018 = answers_2018
163 
164  fill_pts(:,:) = fill(:,:)
165 
166  nfill = sum(fill(is:ie,js:je))
167  call sum_across_pes(nfill)
168 
169  nfill_prev = nfill
170  good_(:,:) = good(:,:)
171  r(:,:) = 0.0
172 
173  do while (nfill > 0.0)
174 
175  call pass_var(good_,g%Domain)
176  call pass_var(aout,g%Domain)
177 
178  b(:,:)=aout(:,:)
179  good_new(:,:)=good_(:,:)
180 
181  do j=js,je ; do i=is,ie
182 
183  if (good_(i,j) == 1.0 .or. fill(i,j) == 0.) cycle
184 
185  ge=good_(i+1,j) ; gw=good_(i-1,j)
186  gn=good_(i,j+1) ; gs=good_(i,j-1)
187  east=0.0 ; west=0.0 ; north=0.0 ; south=0.0
188  if (ge == 1.0) east = aout(i+1,j)*ge
189  if (gw == 1.0) west = aout(i-1,j)*gw
190  if (gn == 1.0) north = aout(i,j+1)*gn
191  if (gs == 1.0) south = aout(i,j-1)*gs
192 
193  if (ans_2018) then
194  ngood = ge+gw+gn+gs
195  else
196  ngood = (ge+gw) + (gn+gs)
197  endif
198  if (ngood > 0.) then
199  if (ans_2018) then
200  b(i,j)=(east+west+north+south)/ngood
201  else
202  b(i,j) = ((east+west) + (north+south))/ngood
203  endif
204  fill_pts(i,j) = 0.0
205  good_new(i,j) = 1.0
206  endif
207  enddo ; enddo
208 
209  aout(is:ie,js:je) = b(is:ie,js:je)
210  good_(is:ie,js:je) = good_new(is:ie,js:je)
211  nfill_prev = nfill
212  nfill = sum(fill_pts(is:ie,js:je))
213  call sum_across_pes(nfill)
214 
215  if (nfill == nfill_prev .and. PRESENT(prev)) then
216  do j=js,je ; do i=is,ie ; if (fill_pts(i,j) == 1.0) then
217  aout(i,j) = prev(i,j)
218  fill_pts(i,j) = 0.0
219  endif ; enddo ; enddo
220  elseif (nfill == nfill_prev) then
221  call mom_error(warning, &
222  'Unable to fill missing points using either data at the same vertical level from a connected basin'//&
223  'or using a point from a previous vertical level. Make sure that the original data has some valid'//&
224  'data in all basins.', .true.)
225  write(mesg,*) 'nfill=',nfill
226  call mom_error(warning, mesg, .true.)
227  endif
228 
229  nfill = sum(fill_pts(is:ie,js:je))
230  call sum_across_pes(nfill)
231 
232  enddo
233 
234  if (do_smooth) then ; do k=1,npass
235  call pass_var(aout,g%Domain)
236  do j=js,je ; do i=is,ie
237  if (fill(i,j) == 1) then
238  east = max(good(i+1,j),fill(i+1,j)) ; west = max(good(i-1,j),fill(i-1,j))
239  north = max(good(i,j+1),fill(i,j+1)) ; south = max(good(i,j-1),fill(i,j-1))
240  if (ans_2018) then
241  r(i,j) = relax_coeff*(south*aout(i,j-1)+north*aout(i,j+1) + &
242  west*aout(i-1,j)+east*aout(i+1,j) - &
243  (south+north+west+east)*aout(i,j))
244  else
245  r(i,j) = relax_coeff*( ((south*aout(i,j-1) + north*aout(i,j+1)) + &
246  (west*aout(i-1,j)+east*aout(i+1,j))) - &
247  ((south+north)+(west+east))*aout(i,j) )
248  endif
249  else
250  r(i,j) = 0.
251  endif
252  enddo ; enddo
253  ares = 0.0
254  do j=js,je ; do i=is,ie
255  aout(i,j) = r(i,j) + aout(i,j)
256  ares = max(ares, abs(r(i,j)))
257  enddo ; enddo
258  call max_across_pes(ares)
259  if (ares <= acrit) exit
260  enddo ; endif
261 
262  do j=js,je ; do i=is,ie
263  if (good_(i,j) == 0.0 .and. fill_pts(i,j) == 1.0) then
264  write(mesg,*) 'In fill_miss, fill, good,i,j= ',fill_pts(i,j),good_(i,j),i,j
265  call mom_error(warning, mesg, .true.)
266  call mom_error(fatal,"MOM_initialize: "// &
267  "fill is true and good is false after fill_miss, how did this happen? ")
268  endif
269  enddo ; enddo
270 
271 end subroutine fill_miss_2d
272 
273 !> Extrapolate and interpolate from a file record
274 subroutine horiz_interp_and_extrap_tracer_record(filename, varnam, conversion, recnum, G, tr_z, &
275  mask_z, z_in, z_edges_in, missing_value, reentrant_x, &
276  tripolar_n, homogenize, m_to_Z, answers_2018, ongrid)
277 
278  character(len=*), intent(in) :: filename !< Path to file containing tracer to be
279  !! interpolated.
280  character(len=*), intent(in) :: varnam !< Name of tracer in filee.
281  real, intent(in) :: conversion !< Conversion factor for tracer.
282  integer, intent(in) :: recnum !< Record number of tracer to be read.
283  type(ocean_grid_type), intent(inout) :: G !< Grid object
284  real, allocatable, dimension(:,:,:) :: tr_z !< pointer to allocatable tracer array on local
285  !! model grid and input-file vertical levels.
286  real, allocatable, dimension(:,:,:) :: mask_z !< pointer to allocatable tracer mask array on
287  !! local model grid and input-file vertical levels.
288  real, allocatable, dimension(:) :: z_in !< Cell grid values for input data.
289  real, allocatable, dimension(:) :: z_edges_in !< Cell grid edge values for input data.
290  real, intent(out) :: missing_value !< The missing value in the returned array.
291  logical, intent(in) :: reentrant_x !< If true, this grid is reentrant in the x-direction
292  logical, intent(in) :: tripolar_n !< If true, this is a northern tripolar grid
293  logical, optional, intent(in) :: homogenize !< If present and true, horizontally homogenize data
294  !! to produce perfectly "flat" initial conditions
295  real, optional, intent(in) :: m_to_Z !< A conversion factor from meters to the units
296  !! of depth. If missing, G%bathyT must be in m.
297  logical, optional, intent(in) :: answers_2018 !< If true, use expressions that give the same
298  !! answers as the code did in late 2018. Otherwise
299  !! add parentheses for rotational symmetry.
300  logical, optional, intent(in) :: ongrid !< If true, then data are assumed to have been interpolated
301  !! to the model horizontal grid. In this case, only
302  !! extrapolation is performed by this routine
303 
304  ! Local variables
305  real, dimension(:,:), allocatable :: tr_in, tr_inp ! A 2-d array for holding input data on
306  ! native horizontal grid and extended grid
307  ! with poles.
308  real, dimension(:,:), allocatable :: mask_in ! A 2-d mask for extended input grid.
309 
310  real :: PI_180
311  integer :: rcode, ncid, varid, ndims, id, jd, kd, jdp
312  integer :: i,j,k
313  integer, dimension(4) :: start, count, dims, dim_id
314  real, dimension(:,:), allocatable :: x_in, y_in
315  real, dimension(:), allocatable :: lon_in, lat_in
316  real, dimension(:), allocatable :: lat_inp, last_row
317  real :: max_lat, min_lat, pole, max_depth, npole
318  real :: roundoff ! The magnitude of roundoff, usually ~2e-16.
319  real :: add_offset, scale_factor
320  logical :: add_np
321  logical :: is_ongrid
322  character(len=8) :: laynum
323  type(horiz_interp_type) :: Interp
324  integer :: is, ie, js, je ! compute domain indices
325  integer :: isc,iec,jsc,jec ! global compute domain indices
326  integer :: isg, ieg, jsg, jeg ! global extent
327  integer :: isd, ied, jsd, jed ! data domain indices
328  integer :: id_clock_read
329  character(len=12) :: dim_name(4)
330  logical :: debug=.false.
331  real :: npoints,varAvg
332  real, dimension(SZI_(G),SZJ_(G)) :: lon_out, lat_out, tr_out, mask_out
333  real, dimension(SZI_(G),SZJ_(G)) :: good, fill
334  real, dimension(SZI_(G),SZJ_(G)) :: tr_outf,tr_prev
335  real, dimension(SZI_(G),SZJ_(G)) :: good2,fill2
336  real, dimension(SZI_(G),SZJ_(G)) :: nlevs
337 
338  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
339  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
340  isg = g%isg ; ieg = g%ieg ; jsg = g%jsg ; jeg = g%jeg
341 
342  id_clock_read = cpu_clock_id('(Initialize tracer from Z) read', grain=clock_loop)
343 
344  is_ongrid=.false.
345  if (present(ongrid)) is_ongrid=ongrid
346 
347  if (allocated(tr_z)) deallocate(tr_z)
348  if (allocated(mask_z)) deallocate(mask_z)
349  if (allocated(z_edges_in)) deallocate(z_edges_in)
350 
351  pi_180=atan(1.0)/45.
352 
353  ! Open NetCDF file and if present, extract data and spatial coordinate information
354  ! The convention adopted here requires that the data be written in (i,j,k) ordering.
355 
356  call cpu_clock_begin(id_clock_read)
357 
358  rcode = nf90_open(filename, nf90_nowrite, ncid)
359  if (rcode /= 0) call mom_error(fatal,"error opening file "//trim(filename)//&
360  " in hinterp_extrap")
361  rcode = nf90_inq_varid(ncid, varnam, varid)
362  if (rcode /= 0) call mom_error(fatal,"error finding variable "//trim(varnam)//&
363  " in file "//trim(filename)//" in hinterp_extrap")
364 
365  rcode = nf90_inquire_variable(ncid, varid, ndims=ndims, dimids=dims)
366  if (rcode /= 0) call mom_error(fatal,'error inquiring dimensions hinterp_extrap')
367  if (ndims < 3) call mom_error(fatal,"Variable "//trim(varnam)//" in file "// &
368  trim(filename)//" has too few dimensions.")
369 
370  rcode = nf90_inquire_dimension(ncid, dims(1), dim_name(1), len=id)
371  if (rcode /= 0) call mom_error(fatal,"error reading dimension 1 data for "// &
372  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
373  rcode = nf90_inq_varid(ncid, dim_name(1), dim_id(1))
374  if (rcode /= 0) call mom_error(fatal,"error finding variable "//trim(dim_name(1))//&
375  " in file "//trim(filename)//" in hinterp_extrap")
376  rcode = nf90_inquire_dimension(ncid, dims(2), dim_name(2), len=jd)
377  if (rcode /= 0) call mom_error(fatal,"error reading dimension 2 data for "// &
378  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
379  rcode = nf90_inq_varid(ncid, dim_name(2), dim_id(2))
380  if (rcode /= 0) call mom_error(fatal,"error finding variable "//trim(dim_name(2))//&
381  " in file "//trim(filename)//" in hinterp_extrap")
382  rcode = nf90_inquire_dimension(ncid, dims(3), dim_name(3), len=kd)
383  if (rcode /= 0) call mom_error(fatal,"error reading dimension 3 data for "// &
384  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
385  rcode = nf90_inq_varid(ncid, dim_name(3), dim_id(3))
386  if (rcode /= 0) call mom_error(fatal,"error finding variable "//trim(dim_name(3))//&
387  " in file "//trim(filename)//" in hinterp_extrap")
388 
389  missing_value=0.0
390  rcode = nf90_get_att(ncid, varid, "_FillValue", missing_value)
391  if (rcode /= 0) call mom_error(fatal,"error finding missing value for "//&
392  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
393 
394  rcode = nf90_get_att(ncid, varid, "add_offset", add_offset)
395  if (rcode /= 0) add_offset = 0.0
396 
397  rcode = nf90_get_att(ncid, varid, "scale_factor", scale_factor)
398  if (rcode /= 0) scale_factor = 1.0
399 
400  if (allocated(lon_in)) deallocate(lon_in)
401  if (allocated(lat_in)) deallocate(lat_in)
402  if (allocated(z_in)) deallocate(z_in)
403  if (allocated(z_edges_in)) deallocate(z_edges_in)
404  if (allocated(tr_z)) deallocate(tr_z)
405  if (allocated(mask_z)) deallocate(mask_z)
406 
407  allocate(lon_in(id),lat_in(jd),z_in(kd),z_edges_in(kd+1))
408  allocate(tr_z(isd:ied,jsd:jed,kd), mask_z(isd:ied,jsd:jed,kd))
409 
410  start = 1; count = 1; count(1) = id
411  rcode = nf90_get_var(ncid, dim_id(1), lon_in, start, count)
412  if (rcode /= 0) call mom_error(fatal,"error reading dimension 1 values for var_name "// &
413  trim(varnam)//",dim_name "//trim(dim_name(1))//" in file "// trim(filename)//" in hinterp_extrap")
414  start = 1; count = 1; count(1) = jd
415  rcode = nf90_get_var(ncid, dim_id(2), lat_in, start, count)
416  if (rcode /= 0) call mom_error(fatal,"error reading dimension 2 values for var_name "// &
417  trim(varnam)//",dim_name "//trim(dim_name(2))//" in file "// trim(filename)//" in hinterp_extrap")
418  start = 1; count = 1; count(1) = kd
419  rcode = nf90_get_var(ncid, dim_id(3), z_in, start, count)
420  if (rcode /= 0) call mom_error(fatal,"error reading dimension 3 values for var_name "// &
421  trim(varnam//",dim_name "//trim(dim_name(3)))//" in file "// trim(filename)//" in hinterp_extrap")
422 
423  call cpu_clock_end(id_clock_read)
424 
425  if (present(m_to_z)) then ; do k=1,kd ; z_in(k) = m_to_z * z_in(k) ; enddo ; endif
426 
427  ! extrapolate the input data to the north pole using the northerm-most latitude
428  add_np=.false.
429  jdp=jd
430  if (.not. is_ongrid) then
431  max_lat = maxval(lat_in)
432  if (max_lat < 90.0) then
433  add_np=.true.
434  jdp=jd+1
435  allocate(lat_inp(jdp))
436  lat_inp(1:jd)=lat_in(:)
437  lat_inp(jd+1)=90.0
438  deallocate(lat_in)
439  allocate(lat_in(1:jdp))
440  lat_in(:)=lat_inp(:)
441  endif
442  endif
443  ! construct level cell boundaries as the mid-point between adjacent centers
444 
445  z_edges_in(1) = 0.0
446  do k=2,kd
447  z_edges_in(k)=0.5*(z_in(k-1)+z_in(k))
448  enddo
449  z_edges_in(kd+1)=2.0*z_in(kd) - z_in(kd-1)
450 
451  if (is_ongrid) then
452  allocate(tr_in(is:ie,js:je)) ; tr_in(:,:)=0.0
453  allocate(mask_in(is:ie,js:je)) ; mask_in(:,:)=0.0
454  else
455  call horiz_interp_init()
456  lon_in = lon_in*pi_180
457  lat_in = lat_in*pi_180
458  allocate(x_in(id,jdp),y_in(id,jdp))
459  call meshgrid(lon_in,lat_in, x_in, y_in)
460  lon_out(:,:) = g%geoLonT(:,:)*pi_180
461  lat_out(:,:) = g%geoLatT(:,:)*pi_180
462  allocate(tr_in(id,jd)) ; tr_in(:,:)=0.0
463  allocate(tr_inp(id,jdp)) ; tr_inp(:,:)=0.0
464  allocate(mask_in(id,jdp)) ; mask_in(:,:)=0.0
465  allocate(last_row(id)) ; last_row(:)=0.0
466  endif
467 
468 
469 
470  max_depth = maxval(g%bathyT)
471  call mpp_max(max_depth)
472 
473  if (z_edges_in(kd+1)<max_depth) z_edges_in(kd+1)=max_depth
474  roundoff = 3.0*epsilon(missing_value)
475 
476  ! loop through each data level and interpolate to model grid.
477  ! after interpolating, fill in points which will be needed
478  ! to define the layers
479  do k=1,kd
480  write(laynum,'(I8)') k ; laynum = adjustl(laynum)
481  mask_in=0.0
482  if (is_ongrid) then
483  start(1) = is+g%HI%idg_offset ; start(2) = js+g%HI%jdg_offset ; start(3) = k
484  count(1) = ie-is+1 ; count(2) = je-js+1; count(3) = 1
485  rcode = nf90_get_var(ncid,varid, tr_in, start, count)
486  if (rcode /= 0) call mom_error(fatal,"hinterp_and_extract_from_Fie: "//&
487  "error reading level "//trim(laynum)//" of variable "//&
488  trim(varnam)//" in file "// trim(filename))
489 
490  do j=js,je
491  do i=is,ie
492  if (abs(tr_in(i,j)-missing_value) > abs(roundoff*missing_value)) then
493  mask_in(i,j) = 1.0
494  tr_in(i,j) = (tr_in(i,j)*scale_factor+add_offset) * conversion
495  else
496  tr_in(i,j) = missing_value
497  endif
498  enddo
499  enddo
500 
501  else
502  if (is_root_pe()) then
503  start = 1 ; start(3) = k ; count(:) = 1 ; count(1) = id ; count(2) = jd
504  rcode = nf90_get_var(ncid,varid, tr_in, start, count)
505  if (rcode /= 0) call mom_error(fatal,"hinterp_and_extract_from_Fie: "//&
506  "error reading level "//trim(laynum)//" of variable "//&
507  trim(varnam)//" in file "// trim(filename))
508 
509  if (add_np) then
510  last_row(:)=tr_in(:,jd); pole=0.0;npole=0.0
511  do i=1,id
512  if (abs(tr_in(i,jd)-missing_value) > abs(roundoff*missing_value)) then
513  pole = pole+last_row(i)
514  npole = npole+1.0
515  endif
516  enddo
517  if (npole > 0) then
518  pole=pole/npole
519  else
520  pole=missing_value
521  endif
522  tr_inp(:,1:jd) = tr_in(:,:)
523  tr_inp(:,jdp) = pole
524  else
525  tr_inp(:,:) = tr_in(:,:)
526  endif
527  endif
528 
529  call mpp_sync()
530  call mpp_broadcast(tr_inp, id*jdp, root_pe())
531  call mpp_sync_self()
532 
533  do j=1,jdp
534  do i=1,id
535  if (abs(tr_inp(i,j)-missing_value) > abs(roundoff*missing_value)) then
536  mask_in(i,j) = 1.0
537  tr_inp(i,j) = (tr_inp(i,j)*scale_factor+add_offset) * conversion
538  else
539  tr_inp(i,j) = missing_value
540  endif
541  enddo
542  enddo
543 
544  endif
545 
546 
547 
548 ! call fms routine horiz_interp to interpolate input level data to model horizontal grid
549  if (.not. is_ongrid) then
550  if (k == 1) then
551  call horiz_interp_new(interp,x_in,y_in,lon_out(is:ie,js:je),lat_out(is:ie,js:je), &
552  interp_method='bilinear',src_modulo=.true.)
553  endif
554 
555  if (debug) then
556  call mystats(tr_inp,missing_value, is,ie,js,je,k,'Tracer from file')
557  endif
558  endif
559 
560  tr_out(:,:) = 0.0
561  if (is_ongrid) then
562  tr_out(is:ie,js:je)=tr_in(is:ie,js:je)
563  else
564  call horiz_interp(interp,tr_inp,tr_out(is:ie,js:je), missing_value=missing_value, new_missing_handle=.true.)
565  endif
566 
567  mask_out=1.0
568  do j=js,je
569  do i=is,ie
570  if (abs(tr_out(i,j)-missing_value) < abs(roundoff*missing_value)) mask_out(i,j)=0.
571  enddo
572  enddo
573 
574  fill = 0.0; good = 0.0
575 
576  npoints = 0 ; varavg = 0.
577  do j=js,je
578  do i=is,ie
579  if (mask_out(i,j) < 1.0) then
580  tr_out(i,j)=missing_value
581  else
582  good(i,j)=1.0
583  npoints = npoints + 1
584  varavg = varavg + tr_out(i,j)
585  endif
586  if (g%mask2dT(i,j) == 1.0 .and. z_edges_in(k) <= g%bathyT(i,j) .and. mask_out(i,j) < 1.0) &
587  fill(i,j)=1.0
588  enddo
589  enddo
590  call pass_var(fill,g%Domain)
591  call pass_var(good,g%Domain)
592 
593  if (debug) then
594  call mystats(tr_out,missing_value, is,ie,js,je,k,'variable from horiz_interp()')
595  endif
596 
597  ! Horizontally homogenize data to produce perfectly "flat" initial conditions
598  if (PRESENT(homogenize)) then
599  if (homogenize) then
600  call sum_across_pes(npoints)
601  call sum_across_pes(varavg)
602  if (npoints>0) then
603  varavg = varavg/real(npoints)
604  endif
605  tr_out(:,:) = varavg
606  endif
607  endif
608 
609  ! tr_out contains input z-space data on the model grid with missing values
610  ! now fill in missing values using "ICE-nine" algorithm.
611  tr_outf(:,:) = tr_out(:,:)
612  if (k==1) tr_prev(:,:) = tr_outf(:,:)
613  good2(:,:) = good(:,:)
614  fill2(:,:) = fill(:,:)
615 
616  call fill_miss_2d(tr_outf, good2, fill2, tr_prev, g, smooth=.true., answers_2018=answers_2018)
617  call mystats(tr_outf, missing_value, is, ie, js, je, k, 'field from fill_miss_2d()')
618 
619  tr_z(:,:,k) = tr_outf(:,:) * g%mask2dT(:,:)
620  mask_z(:,:,k) = good2(:,:) + fill2(:,:)
621 
622  tr_prev(:,:) = tr_z(:,:,k)
623 
624  if (debug) then
625  call hchksum(tr_prev,'field after fill ',g%HI)
626  endif
627 
628  enddo ! kd
629 
630 end subroutine horiz_interp_and_extrap_tracer_record
631 
632 !> Extrapolate and interpolate using a FMS time interpolation handle
633 subroutine horiz_interp_and_extrap_tracer_fms_id(fms_id, Time, conversion, G, tr_z, mask_z, &
634  z_in, z_edges_in, missing_value, reentrant_x, &
635  tripolar_n, homogenize, spongeOngrid, m_to_Z, answers_2018)
636 
637  integer, intent(in) :: fms_id !< A unique id used by the FMS time interpolator
638  type(time_type), intent(in) :: Time !< A FMS time type
639  real, intent(in) :: conversion !< Conversion factor for tracer.
640  type(ocean_grid_type), intent(inout) :: G !< Grid object
641  real, allocatable, dimension(:,:,:) :: tr_z !< pointer to allocatable tracer array on local
642  !! model grid and native vertical levels.
643  real, allocatable, dimension(:,:,:) :: mask_z !< pointer to allocatable tracer mask array on
644  !! local model grid and native vertical levels.
645  real, allocatable, dimension(:) :: z_in !< Cell grid values for input data.
646  real, allocatable, dimension(:) :: z_edges_in !< Cell grid edge values for input data. (Intent out)
647  real, intent(out) :: missing_value !< The missing value in the returned array.
648  logical, intent(in) :: reentrant_x !< If true, this grid is reentrant in the x-direction
649  logical, intent(in) :: tripolar_n !< If true, this is a northern tripolar grid
650  logical, optional, intent(in) :: homogenize !< If present and true, horizontally homogenize data
651  !! to produce perfectly "flat" initial conditions
652  logical, optional, intent(in) :: spongeOngrid !< If present and true, the sponge data are on the model grid
653  real, optional, intent(in) :: m_to_Z !< A conversion factor from meters to the units
654  !! of depth. If missing, G%bathyT must be in m.
655  logical, optional, intent(in) :: answers_2018 !< If true, use expressions that give the same
656  !! answers as the code did in late 2018. Otherwise
657  !! add parentheses for rotational symmetry.
658 
659  ! Local variables
660  real, dimension(:,:), allocatable :: tr_in,tr_inp !< A 2-d array for holding input data on
661  !! native horizontal grid and extended grid
662  !! with poles.
663  real, dimension(:,:,:), allocatable :: data_in !< A buffer for storing the full 3-d time-interpolated array
664  !! on the original grid
665  real, dimension(:,:), allocatable :: mask_in !< A 2-d mask for extended input grid.
666 
667  real :: PI_180
668  integer :: rcode, ncid, varid, ndims, id, jd, kd, jdp
669  integer :: i,j,k
670  integer, dimension(4) :: start, count, dims, dim_id
671  real, dimension(:,:), allocatable :: x_in, y_in
672  real, dimension(:), allocatable :: lon_in, lat_in
673  real, dimension(:), allocatable :: lat_inp, last_row
674  real :: max_lat, min_lat, pole, max_depth, npole
675  real :: roundoff ! The magnitude of roundoff, usually ~2e-16.
676  logical :: add_np
677  character(len=8) :: laynum
678  type(horiz_interp_type) :: Interp
679  type(axistype), dimension(4) :: axes_data
680  integer :: is, ie, js, je ! compute domain indices
681  integer :: isc,iec,jsc,jec ! global compute domain indices
682  integer :: isg, ieg, jsg, jeg ! global extent
683  integer :: isd, ied, jsd, jed ! data domain indices
684  integer :: id_clock_read
685  integer, dimension(4) :: fld_sz
686  character(len=12) :: dim_name(4)
687  logical :: debug=.false.
688  logical :: spongeDataOngrid
689  real :: npoints,varAvg
690  real, dimension(SZI_(G),SZJ_(G)) :: lon_out, lat_out, tr_out, mask_out
691  real, dimension(SZI_(G),SZJ_(G)) :: good, fill
692  real, dimension(SZI_(G),SZJ_(G)) :: tr_outf,tr_prev
693  real, dimension(SZI_(G),SZJ_(G)) :: good2,fill2
694  real, dimension(SZI_(G),SZJ_(G)) :: nlevs
695  integer :: turns
696 
697  turns = g%HI%turns
698 
699  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
700  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
701  isg = g%isg ; ieg = g%ieg ; jsg = g%jsg ; jeg = g%jeg
702 
703  id_clock_read = cpu_clock_id('(Initialize tracer from Z) read', grain=clock_loop)
704 
705  pi_180=atan(1.0)/45.
706 
707  ! Open NetCDF file and if present, extract data and spatial coordinate information
708  ! The convention adopted here requires that the data be written in (i,j,k) ordering.
709 
710  call cpu_clock_begin(id_clock_read)
711 
712  fld_sz = get_external_field_size(fms_id)
713  if (allocated(lon_in)) deallocate(lon_in)
714  if (allocated(lat_in)) deallocate(lat_in)
715  if (allocated(z_in)) deallocate(z_in)
716  if (allocated(z_edges_in)) deallocate(z_edges_in)
717  if (allocated(tr_z)) deallocate(tr_z)
718  if (allocated(mask_z)) deallocate(mask_z)
719 
720  axes_data = get_external_field_axes(fms_id)
721 
722  id = fld_sz(1) ; jd = fld_sz(2) ; kd = fld_sz(3)
723 
724  spongedataongrid=.false.
725  if (PRESENT(spongeongrid)) spongedataongrid=spongeongrid
726  if (.not. spongedataongrid) then
727  allocate(lon_in(id),lat_in(jd))
728  call mpp_get_axis_data(axes_data(1), lon_in)
729  call mpp_get_axis_data(axes_data(2), lat_in)
730  endif
731 
732  allocate(z_in(kd),z_edges_in(kd+1))
733 
734  allocate(tr_z(isd:ied,jsd:jed,kd), mask_z(isd:ied,jsd:jed,kd))
735 
736  call mpp_get_axis_data(axes_data(3), z_in)
737 
738  if (present(m_to_z)) then ; do k=1,kd ; z_in(k) = m_to_z * z_in(k) ; enddo ; endif
739 
740  call cpu_clock_end(id_clock_read)
741 
742  missing_value = get_external_field_missing(fms_id)
743 
744  if (.not. spongedataongrid) then
745  ! extrapolate the input data to the north pole using the northerm-most latitude
746  max_lat = maxval(lat_in)
747  add_np=.false.
748  if (max_lat < 90.0) then
749  add_np = .true.
750  jdp = jd+1
751  allocate(lat_inp(jdp))
752  lat_inp(1:jd) = lat_in(:)
753  lat_inp(jd+1) = 90.0
754  deallocate(lat_in)
755  allocate(lat_in(1:jdp))
756  lat_in(:) = lat_inp(:)
757  else
758  jdp=jd
759  endif
760  call horiz_interp_init()
761  lon_in = lon_in*pi_180
762  lat_in = lat_in*pi_180
763  allocate(x_in(id,jdp), y_in(id,jdp))
764  call meshgrid(lon_in, lat_in, x_in, y_in)
765  lon_out(:,:) = g%geoLonT(:,:)*pi_180
766  lat_out(:,:) = g%geoLatT(:,:)*pi_180
767  allocate(data_in(id,jd,kd)) ; data_in(:,:,:)=0.0
768  allocate(tr_in(id,jd)) ; tr_in(:,:)=0.0
769  allocate(tr_inp(id,jdp)) ; tr_inp(:,:)=0.0
770  allocate(mask_in(id,jdp)) ; mask_in(:,:)=0.0
771  allocate(last_row(id)) ; last_row(:)=0.0
772  else
773  allocate(data_in(isd:ied,jsd:jed,kd))
774  endif
775  ! construct level cell boundaries as the mid-point between adjacent centers
776  z_edges_in(1) = 0.0
777  do k=2,kd
778  z_edges_in(k) = 0.5*(z_in(k-1)+z_in(k))
779  enddo
780  z_edges_in(kd+1) = 2.0*z_in(kd) - z_in(kd-1)
781 
782 
783  max_depth = maxval(g%bathyT)
784  call mpp_max(max_depth)
785 
786  if (z_edges_in(kd+1)<max_depth) z_edges_in(kd+1)=max_depth
787 
788  ! roundoff = 3.0*EPSILON(missing_value)
789  roundoff = 1.e-4
790 
791  if (.not.spongedataongrid) then
792  if (is_root_pe()) &
793  call time_interp_external(fms_id, time, data_in, verbose=.true., turns=turns)
794  ! loop through each data level and interpolate to model grid.
795  ! after interpolating, fill in points which will be needed
796  ! to define the layers
797  do k=1,kd
798  write(laynum,'(I8)') k ; laynum = adjustl(laynum)
799  if (is_root_pe()) then
800  tr_in(1:id,1:jd) = data_in(1:id,1:jd,k)
801  if (add_np) then
802  last_row(:)=tr_in(:,jd); pole=0.0;npole=0.0
803  do i=1,id
804  if (abs(tr_in(i,jd)-missing_value) > abs(roundoff*missing_value)) then
805  pole = pole+last_row(i)
806  npole = npole+1.0
807  endif
808  enddo
809  if (npole > 0) then
810  pole=pole/npole
811  else
812  pole=missing_value
813  endif
814  tr_inp(:,1:jd) = tr_in(:,:)
815  tr_inp(:,jdp) = pole
816  else
817  tr_inp(:,:) = tr_in(:,:)
818  endif
819  endif
820 
821  call mpp_sync()
822  call mpp_broadcast(tr_inp, id*jdp, root_pe())
823  call mpp_sync_self()
824 
825  mask_in=0.0
826 
827  do j=1,jdp ; do i=1,id
828  if (abs(tr_inp(i,j)-missing_value) > abs(roundoff*missing_value)) then
829  mask_in(i,j)=1.0
830  tr_inp(i,j) = tr_inp(i,j) * conversion
831  else
832  tr_inp(i,j) = missing_value
833  endif
834  enddo ; enddo
835 
836  ! call fms routine horiz_interp to interpolate input level data to model horizontal grid
837  if (k == 1) then
838  call horiz_interp_new(interp, x_in, y_in, lon_out(is:ie,js:je), lat_out(is:ie,js:je), &
839  interp_method='bilinear', src_modulo=.true.)
840  endif
841 
842  if (debug) then
843  call mystats(tr_in, missing_value, 1, id, 1, jd, k, 'Tracer from file')
844  endif
845 
846  tr_out(:,:) = 0.0
847 
848  call horiz_interp(interp, tr_inp, tr_out(is:ie,js:je), missing_value=missing_value, &
849  new_missing_handle=.true.)
850 
851  mask_out(:,:) = 1.0
852  do j=js,je ; do i=is,ie
853  if (abs(tr_out(i,j)-missing_value) < abs(roundoff*missing_value)) mask_out(i,j) = 0.
854  enddo ; enddo
855 
856  fill(:,:) = 0.0 ; good(:,:) = 0.0
857 
858  npoints = 0 ; varavg = 0.
859  do j=js,je ; do i=is,ie
860  if (mask_out(i,j) < 1.0) then
861  tr_out(i,j) = missing_value
862  else
863  good(i,j) = 1.0
864  npoints = npoints + 1
865  varavg = varavg + tr_out(i,j)
866  endif
867  if ((g%mask2dT(i,j) == 1.0) .and. (z_edges_in(k) <= g%bathyT(i,j)) .and. &
868  (mask_out(i,j) < 1.0)) &
869  fill(i,j)=1.0
870  enddo ; enddo
871  call pass_var(fill, g%Domain)
872  call pass_var(good, g%Domain)
873 
874  if (debug) then
875  call mystats(tr_out, missing_value, is, ie, js, je, k, 'variable from horiz_interp()')
876  endif
877 
878  ! Horizontally homogenize data to produce perfectly "flat" initial conditions
879  if (PRESENT(homogenize)) then ; if (homogenize) then
880  call sum_across_pes(npoints)
881  call sum_across_pes(varavg)
882  if (npoints>0) then
883  varavg = varavg/real(npoints)
884  endif
885  tr_out(:,:) = varavg
886  endif ; endif
887 
888  ! tr_out contains input z-space data on the model grid with missing values
889  ! now fill in missing values using "ICE-nine" algorithm.
890  tr_outf(:,:) = tr_out(:,:)
891  if (k==1) tr_prev(:,:) = tr_outf(:,:)
892  good2(:,:) = good(:,:)
893  fill2(:,:) = fill(:,:)
894 
895  call fill_miss_2d(tr_outf, good2, fill2, tr_prev, g, smooth=.true., answers_2018=answers_2018)
896 
897 ! if (debug) then
898 ! call hchksum(tr_outf, 'field from fill_miss_2d ', G%HI)
899 ! endif
900 
901 ! call myStats(tr_outf, missing_value, is, ie, js, je, k, 'field from fill_miss_2d()')
902 
903  tr_z(:,:,k) = tr_outf(:,:)*g%mask2dT(:,:)
904  mask_z(:,:,k) = good2(:,:) + fill2(:,:)
905  tr_prev(:,:) = tr_z(:,:,k)
906 
907  if (debug) then
908  call hchksum(tr_prev,'field after fill ',g%HI)
909  endif
910 
911  enddo ! kd
912  else
913  call time_interp_external(fms_id, time, data_in, verbose=.true., turns=turns)
914  do k=1,kd
915  do j=js,je
916  do i=is,ie
917  tr_z(i,j,k)=data_in(i,j,k)
918  if (abs(tr_z(i,j,k)-missing_value) < abs(roundoff*missing_value)) mask_z(i,j,k) = 0.
919  enddo
920  enddo
921  enddo
922  endif
923 
924 end subroutine horiz_interp_and_extrap_tracer_fms_id
925 
926 !> Create a 2d-mesh of grid coordinates from 1-d arrays.
927 subroutine meshgrid(x, y, x_T, y_T)
928  real, dimension(:), intent(in) :: x !< input 1-dimensional vector
929  real, dimension(:), intent(in) :: y !< input 1-dimensional vector
930  real, dimension(size(x,1),size(y,1)), intent(inout) :: x_T !< output 2-dimensional array
931  real, dimension(size(x,1),size(y,1)), intent(inout) :: y_T !< output 2-dimensional array
932 
933  integer :: ni,nj,i,j
934 
935  ni=size(x,1) ; nj=size(y,1)
936 
937  do j=1,nj ; do i=1,ni
938  x_t(i,j) = x(i)
939  enddo ; enddo
940 
941  do j=1,nj ; do i=1,ni
942  y_t(i,j) = y(j)
943  enddo ; enddo
944 
945 end subroutine meshgrid
946 
947 ! None of the subsequent code appears to be used at all.
948 
949 !> Fill grid edges for integer data
950 function fill_boundaries_int(m,cyclic_x,tripolar_n) result(mp)
951  integer, dimension(:,:), intent(in) :: m !< input array (ND)
952  logical, intent(in) :: cyclic_x !< True if domain is zonally re-entrant
953  logical, intent(in) :: tripolar_n !< True if domain has an Arctic fold
954  integer, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp
955 
956  real, dimension(size(m,1),size(m,2)) :: m_real
957  real, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp_real
958 
959  m_real = real(m)
960 
961  mp_real = fill_boundaries_real(m_real,cyclic_x,tripolar_n)
962 
963  mp = int(mp_real)
964 
965 end function fill_boundaries_int
966 
967 !> Fill grid edges for real data
968 function fill_boundaries_real(m,cyclic_x,tripolar_n) result(mp)
969  real, dimension(:,:), intent(in) :: m !< input array (ND)
970  logical, intent(in) :: cyclic_x !< True if domain is zonally re-entrant
971  logical, intent(in) :: tripolar_n !< True if domain has an Arctic fold
972  real, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp
973 
974  integer :: ni,nj,i,j
975 
976  ni=size(m,1); nj=size(m,2)
977 
978  mp(1:ni,1:nj)=m(:,:)
979 
980  if (cyclic_x) then
981  mp(0,1:nj)=m(ni,1:nj)
982  mp(ni+1,1:nj)=m(1,1:nj)
983  else
984  mp(0,1:nj)=m(1,1:nj)
985  mp(ni+1,1:nj)=m(ni,1:nj)
986  endif
987 
988  mp(1:ni,0)=m(1:ni,1)
989  if (tripolar_n) then
990  do i=1,ni
991  mp(i,nj+1)=m(ni-i+1,nj)
992  enddo
993  else
994  mp(1:ni,nj+1)=m(1:ni,nj)
995  endif
996 
997 end function fill_boundaries_real
998 
999 !> Solve del2 (zi) = 0 using successive iterations
1000 !! with a 5 point stencil. Only points fill==1 are
1001 !! modified. Except where bad==1, information propagates
1002 !! isotropically in index space. The resulting solution
1003 !! in each region is an approximation to del2(zi)=0 subject to
1004 !! boundary conditions along the valid points curve bounding this region.
1005 subroutine smooth_heights(zi,fill,bad,sor,niter,cyclic_x, tripolar_n)
1006  real, dimension(:,:), intent(inout) :: zi !< input and output array (ND)
1007  integer, dimension(size(zi,1),size(zi,2)), intent(in) :: fill !< same shape as zi, 1=fill
1008  integer, dimension(size(zi,1),size(zi,2)), intent(in) :: bad !< same shape as zi, 1=bad data
1009  real, intent(in) :: sor !< relaxation coefficient (ND)
1010  integer, intent(in) :: niter !< maximum number of iterations
1011  logical, intent(in) :: cyclic_x !< true if domain is zonally reentrant
1012  logical, intent(in) :: tripolar_n !< true if domain has an Arctic fold
1013 
1014  ! Local variables
1015  real, dimension(size(zi,1),size(zi,2)) :: res, m
1016  integer, dimension(size(zi,1),size(zi,2),4) :: B
1017  real, dimension(0:size(zi,1)+1,0:size(zi,2)+1) :: mp
1018  integer, dimension(0:size(zi,1)+1,0:size(zi,2)+1) :: nm
1019  integer :: i,j,k,n
1020  integer :: ni,nj
1021  real :: Isum, bsum
1022 
1023  ni=size(zi,1) ; nj=size(zi,2)
1024 
1025 
1026  mp(:,:) = fill_boundaries(zi,cyclic_x,tripolar_n)
1027 
1028  b(:,:,:) = 0.0
1029  nm(:,:) = fill_boundaries(bad,cyclic_x,tripolar_n)
1030 
1031  do j=1,nj
1032  do i=1,ni
1033  if (fill(i,j) == 1) then
1034  b(i,j,1)=1-nm(i+1,j);b(i,j,2)=1-nm(i-1,j)
1035  b(i,j,3)=1-nm(i,j+1);b(i,j,4)=1-nm(i,j-1)
1036  endif
1037  enddo
1038  enddo
1039 
1040  do n=1,niter
1041  do j=1,nj
1042  do i=1,ni
1043  if (fill(i,j) == 1) then
1044  bsum = real(b(i,j,1)+b(i,j,2)+b(i,j,3)+b(i,j,4))
1045  isum = 1.0/bsum
1046  res(i,j)=isum*(b(i,j,1)*mp(i+1,j)+b(i,j,2)*mp(i-1,j)+&
1047  b(i,j,3)*mp(i,j+1)+b(i,j,4)*mp(i,j-1)) - mp(i,j)
1048  endif
1049  enddo
1050  enddo
1051  res(:,:)=res(:,:)*sor
1052 
1053  do j=1,nj
1054  do i=1,ni
1055  mp(i,j)=mp(i,j)+res(i,j)
1056  enddo
1057  enddo
1058 
1059  zi(:,:)=mp(1:ni,1:nj)
1060  mp = fill_boundaries(zi,cyclic_x,tripolar_n)
1061  enddo
1062 
1063 end subroutine smooth_heights
1064 
1065 end module mom_horizontal_regridding
mom_time_manager
Wraps the FMS time manager functions.
Definition: MOM_time_manager.F90:2
mom_transform_fms
Support functions and interfaces to permit transformed model domains to interact with FMS operations ...
Definition: MOM_transform_FMS.F90:4
mom_horizontal_regridding::horiz_interp_and_extrap_tracer
Extrapolate and interpolate data.
Definition: MOM_horizontal_regridding.F90:53
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_variables::thermo_var_ptrs
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Definition: MOM_variables.F90:80
mom_get_input::directories
Container for paths and parameter file names.
Definition: MOM_get_input.F90:20
mom_string_functions
Handy functions for manipulating strings.
Definition: MOM_string_functions.F90:2
mom_horizontal_regridding::fill_boundaries
Fill grid edges.
Definition: MOM_horizontal_regridding.F90:47
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:54
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_horizontal_regridding
Horizontal interpolation.
Definition: MOM_horizontal_regridding.F90:2
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_get_input
Reads the only Fortran name list needed to boot-strap the model.
Definition: MOM_get_input.F90:6
mom_coms
Interfaces to non-domain-oriented communication subroutines, including the MOM6 reproducing sums faci...
Definition: MOM_coms.F90:3
mom_domains::pass_vector
Do a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:59
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_variables
Provides transparent structures with groups of MOM6 variables and supporting routines.
Definition: MOM_variables.F90:2
mom_cpu_clock
Wraps the MPP cpu clock functions.
Definition: MOM_cpu_clock.F90:2
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_transform_fms::rotated_time_interp_external
Read a field based on model time, and rotate to the model domain.
Definition: MOM_transform_FMS.F90:42
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_debugging
Provides checksumming functions for debugging.
Definition: MOM_debugging.F90:7
mom_io::vardesc
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:53
mom_io::file_exists
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
mom_file_parser::read_param
An overloaded interface to read various types of parameters.
Definition: MOM_file_parser.F90:90