MOM6
MOM_tracer_initialization_from_Z.F90
Go to the documentation of this file.
1 module mom_tracer_initialization_from_z
2 
3 ! This file is part of MOM6. See LICENSE.md for the license.
4 
5 use mom_debugging, only : hchksum
6 use mom_coms, only : max_across_pes, min_across_pes
7 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
8 use mom_cpu_clock, only : clock_routine, clock_loop
9 use mom_domains, only : pass_var, pass_vector, sum_across_pes, broadcast
10 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_file_parser, only : log_version
15 use mom_get_input, only : directories
17 use mom_io, only : close_file, fieldtype, file_exists
18 use mom_io, only : open_file, read_data, read_axis_data, single_file, multiple
19 use mom_io, only : slasher, vardesc, write_field
21 use mom_time_manager, only : time_type, set_time
25 use mom_eos, only : int_specific_vol_dp
26 use mom_ale, only : ale_remap_scalar
27 use mom_regridding, only : regridding_cs
31 
32 use mpp_domains_mod, only : mpp_global_field, mpp_get_compute_domain
33 use mpp_mod, only : mpp_broadcast,mpp_root_pe,mpp_sync,mpp_sync_self
34 use mpp_mod, only : mpp_max
35 use horiz_interp_mod, only : horiz_interp_new, horiz_interp,horiz_interp_type
36 use horiz_interp_mod, only : horiz_interp_init, horiz_interp_del
37 
38 use netcdf
39 
40 implicit none ; private
41 
42 #include <MOM_memory.h>
43 
44 public :: mom_initialize_tracer_from_z, horiz_interp_and_extrap_tracer
45 
46 character(len=40) :: mdl = "MOM_tracer_initialization_from_Z" ! This module's name.
47 
48 interface fill_boundaries
49  module procedure fill_boundaries_real
50  module procedure fill_boundaries_int
51 end interface
52 
53 real, parameter :: epsln=1.e-10
54 
55 contains
56 
57 subroutine mom_initialize_tracer_from_z(h, tr, G, GV, PF, src_file, src_var_nam, &
58  src_var_unit_conversion, src_var_record, &
59  homogenize, useALEremapping, remappingScheme, src_var_gridspec )
60 
61 ! Arguments:
62 ! (in) h - Layer thickness, in m.
63 ! (inout) tv - A structure containing pointers to any available
64 ! thermodynamic fields, including potential temperature and
65 ! salinity or mixed layer density. Absent fields have NULL ptrs.
66 ! (in) G - The ocean's grid structure.
67 ! (in) GV - The ocean's vertical grid structure.
68 
69  type(ocean_grid_type), intent(inout) :: g !< Ocean grid structure.
70  type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure.
71  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
72  intent(in) :: h !< Layer thickness, in m.
73  real, dimension(:,:,:), pointer :: tr
74  type(param_file_type), intent(in) :: pf
75  character(len=*), intent(in) :: src_file, src_var_nam
76  real, optional, intent(in) :: src_var_unit_conversion
77  integer, optional, intent(in) :: src_var_record
78  logical, optional, intent(in) :: homogenize, usealeremapping
79  character(len=*), optional, intent(in) :: remappingscheme
80  character(len=*), optional, intent(in) :: src_var_gridspec ! Not implemented yet.
81 
82  real :: land_fill = 0.0
83  character(len=200) :: inputdir ! The directory where NetCDF input files are.
84  character(len=200) :: mesg
85  real :: convert
86  integer :: recnum
87  character(len=10) :: remapscheme
88  logical :: homog,useale
89 
90 ! This include declares and sets the variable "version".
91 #include "version_variable.h"
92 
93  character(len=40) :: mdl = "MOM_initialize_tracers_from_Z" ! This module's name.
94 
95  integer :: is, ie, js, je, nz ! compute domain indices
96  integer :: isc,iec,jsc,jec ! global compute domain indices
97  integer :: isg, ieg, jsg, jeg ! global extent
98  integer :: isd, ied, jsd, jed ! data domain indices
99 
100  integer :: i, j, k, kd
101 
102  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: zi
103  real, allocatable, dimension(:,:,:), target :: tr_z, mask_z
104  real, allocatable, dimension(:), target :: z_edges_in, z_in
105 
106  ! Local variables for ALE remapping
107  real, dimension(:), allocatable :: h1, h2, htarget, deltae, tmpt1d
108  real, dimension(:), allocatable :: tmpt1din
109  real :: ztopofcell, zbottomofcell
110  type(remapping_cs) :: remapcs ! Remapping parameters and work arrays
111 
112  real, dimension(:,:,:), allocatable :: hsrc
113 
114  real :: tempavg, missing_value
115  integer :: npoints, ans
116  integer :: id_clock_routine, id_clock_ale
117  logical :: reentrant_x, tripolar_n
118 
119  id_clock_routine = cpu_clock_id('(Initialize tracer from Z)', grain=clock_routine)
120  id_clock_ale = cpu_clock_id('(Initialize tracer from Z) ALE', grain=clock_loop)
121 
122  call cpu_clock_begin(id_clock_routine)
123 
124  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
125  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
126  isg = g%isg ; ieg = g%ieg ; jsg = g%jsg ; jeg = g%jeg
127 
128  call calltree_enter(trim(mdl)//"(), MOM_state_initialization.F90")
129 
130  call mpp_get_compute_domain(g%domain%mpp_domain,isc,iec,jsc,jec)
131 
132  call get_param(pf, mdl, "Z_INIT_HOMOGENIZE", homog, &
133  "If True, then horizontally homogenize the interpolated \n"//&
134  "initial conditions.", default=.false.)
135  call get_param(pf, mdl, "Z_INIT_ALE_REMAPPING", useale, &
136  "If True, then remap straight to model coordinate from file.",&
137  default=.true.)
138  call get_param(pf, mdl, "Z_INIT_REMAPPING_SCHEME", remapscheme, &
139  "The remapping scheme to use if using Z_INIT_ALE_REMAPPING\n"//&
140  "is True.", default="PLM")
141 
142  ! These are model grid properties, but being applied to the data grid for now.
143  ! need to revisit this (mjh)
144  reentrant_x = .false. ; call get_param(pf, mdl, "REENTRANT_X", reentrant_x,default=.true.)
145  tripolar_n = .false. ; call get_param(pf, mdl, "TRIPOLAR_N", tripolar_n, default=.false.)
146 
147 
148  if (PRESENT(homogenize)) homog=homogenize
149  if (PRESENT(usealeremapping)) useale=usealeremapping
150  if (PRESENT(remappingscheme)) remapscheme=remappingscheme
151  recnum=1
152  if (PRESENT(src_var_record)) recnum = src_var_record
153  convert=1.0
154  if (PRESENT(src_var_unit_conversion)) convert = src_var_unit_conversion
155 
156 
157  call horiz_interp_and_extrap_tracer(src_file, src_var_nam, convert, recnum, &
158  g, tr_z, mask_z, z_in, z_edges_in, missing_value, reentrant_x, tripolar_n, homog)
159 
160  kd = size(z_edges_in,1)-1
161  call pass_var(tr_z,g%Domain)
162  call pass_var(mask_z,g%Domain)
163 
164 ! Done with horizontal interpolation.
165 ! Now remap to model coordinates
166  if (useale) then
167  call cpu_clock_begin(id_clock_ale)
168  ! First we reserve a work space for reconstructions of the source data
169  allocate( h1(kd) )
170  allocate( hsrc(isd:ied,jsd:jed,kd) )
171  allocate( tmpt1din(kd) )
172  call initialize_remapping( remapcs, remapscheme, boundary_extrapolation=.false. ) ! Data for reconstructions
173  ! Next we initialize the regridding package so that it knows about the target grid
174  allocate( htarget(nz) )
175  allocate( h2(nz) )
176  allocate( tmpt1d(nz) )
177  allocate( deltae(nz+1) )
178 
179  do j = js, je ; do i = is, ie
180  if (g%mask2dT(i,j)>0.) then
181  ! Build the source grid
182  ztopofcell = 0. ; zbottomofcell = 0. ; npoints = 0
183  do k = 1, kd
184  if (mask_z(i,j,k) > 0.) then
185  zbottomofcell = -min( z_edges_in(k+1), g%bathyT(i,j) )
186  tmpt1din(k) = tr_z(i,j,k)
187  elseif (k>1) then
188  zbottomofcell = -g%bathyT(i,j)
189  tmpt1din(k) = tmpt1din(k-1)
190  else ! This next block should only ever be reached over land
191  tmpt1din(k) = -99.9
192  endif
193  h1(k) = ztopofcell - zbottomofcell
194  if (h1(k)>0.) npoints = npoints + 1
195  ztopofcell = zbottomofcell ! Bottom becomes top for next value of k
196  enddo
197  h1(kd) = h1(kd) + ( ztopofcell + g%bathyT(i,j) ) ! In case data is deeper than model
198  else
199  tr(i,j,:) = 0.
200  endif ! mask2dT
201  hsrc(i,j,:) = h1(:)
202  enddo ; enddo
203 
204  call ale_remap_scalar(remapcs, g, gv, kd, hsrc, tr_z, h, tr, all_cells=.false. )
205 
206  deallocate( hsrc )
207  deallocate( h1 )
208  deallocate( h2 )
209  deallocate( htarget )
210  deallocate( tmpt1d )
211  deallocate( tmpt1din )
212  deallocate( deltae )
213 
214  do k=1,nz
215  call mystats(tr(:,:,k),missing_value,is,ie,js,je,k,'Tracer from ALE()')
216  enddo
217  call cpu_clock_end(id_clock_ale)
218  endif ! useALEremapping
219 
220 ! Fill land values
221  do k=1,nz ; do j=js,je ; do i=is,ie
222  if (tr(i,j,k) == missing_value) then
223  tr(i,j,k)=land_fill
224  endif
225  enddo ; enddo ; enddo
226 
227 
228  call calltree_leave(trim(mdl)//'()')
229  call cpu_clock_end(id_clock_routine)
230 
231 
232 end subroutine mom_initialize_tracer_from_z
233 
234 subroutine mystats(array, missing, is, ie, js, je, k, mesg)
235  real, dimension(:,:), intent(in) :: array
236  real, intent(in) :: missing
237  integer :: is,ie,js,je,k
238  character(len=*) :: mesg
239  ! Local variables
240  real :: mina, maxa
241  integer :: i,j
242  logical :: found
243  character(len=120) :: lmesg
244  mina = 9.e24 ; maxa = -9.e24 ; found = .false.
245 
246  do j = js, je
247  do i = is, ie
248  if (array(i,j) /= array(i,j)) stop 'Nan!'
249  if (abs(array(i,j)-missing)>1.e-6*abs(missing)) then
250  if (found) then
251  mina = min(mina, array(i,j))
252  maxa = max(maxa, array(i,j))
253  else
254  found = .true.
255  mina = array(i,j)
256  maxa = array(i,j)
257  endif
258  endif
259  enddo
260  enddo
261  call min_across_pes(mina)
262  call max_across_pes(maxa)
263  if (is_root_pe()) then
264  write(lmesg(1:120),'(2(a,es12.4),a,i3,x,a)') &
265  'init_from_Z: min=',mina,' max=',maxa,' Level=',k,trim(mesg)
266  call mom_mesg(lmesg,8)
267  endif
268 end subroutine mystats
269 
270 subroutine fill_miss_2d(aout,good,fill,prev,G,smooth,num_pass,relc,crit,keep_bug,debug)
271  !
272  !# Use ICE-9 algorithm to populate points (fill=1) with
273  !# valid data (good=1). If no information is available,
274  !# Then use a previous guess (prev). Optionally (smooth)
275  !# blend the filled points to achieve a more desirable result.
276  !
277  ! (in) a : input 2-d array with missing values
278  ! (in) good : valid data mask for incoming array (1==good data; 0==missing data)
279  ! (in) fill : same shape array of points which need filling (1==please fill;0==leave it alone)
280  ! (in) prev : first guess where isolated holes exist,
281  !
282  use mom_coms, only : sum_across_pes
283 
284  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
285  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: aout
286  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: good !< Valid data mask for incoming array
287  !! (1==good data; 0==missing data).
288  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: fill !< Same shape array of points which need
289  !! filling (1==please fill;0==leave
290  !! it alone).
291  real, dimension(SZI_(G),SZJ_(G)), optional, &
292  intent(in) :: prev !< First guess where isolated holes exist.
293  logical, intent(in), optional :: smooth
294  integer, intent(in), optional :: num_pass
295  real, intent(in), optional :: relc,crit
296  logical, intent(in), optional :: keep_bug, debug
297 
298 
299  real, dimension(SZI_(G),SZJ_(G)) :: b,r
300  real, dimension(SZI_(G),SZJ_(G)) :: fill_pts,good_,good_new
301 
302  integer :: i,j,k
303  real :: east,west,north,south,sor
304  real :: ge,gw,gn,gs,ngood
305  logical :: do_smooth,siena_bug
306  real :: nfill, nfill_prev
307  integer, parameter :: num_pass_default = 10000
308  real, parameter :: relc_default = 0.25, crit_default = 1.e-3
309 
310  integer :: npass
311  integer :: is, ie, js, je, nz
312  real :: relax_coeff, acrit, ares
313  logical :: debug_it
314 
315  debug_it=.false.
316  if (PRESENT(debug)) debug_it=debug
317 
318  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
319 
320  npass = num_pass_default
321  if (PRESENT(num_pass)) npass = num_pass
322 
323  relax_coeff = relc_default
324  if (PRESENT(relc)) relax_coeff = relc
325 
326  acrit = crit_default
327  if (PRESENT(crit)) acrit = crit
328 
329  siena_bug=.false.
330  if (PRESENT(keep_bug)) siena_bug = keep_bug
331 
332  do_smooth=.false.
333  if (PRESENT(smooth)) do_smooth=smooth
334 
335  fill_pts(:,:)=fill(:,:)
336 
337  nfill = sum(fill(is:ie,js:je))
338  call sum_across_pes(nfill)
339 
340  nfill_prev = nfill
341  good_(:,:)=good(:,:)
342  r(:,:)=0.0
343 
344  do while (nfill > 0.0)
345 
346  call pass_var(good_,g%Domain)
347  call pass_var(aout,g%Domain)
348 
349  b(:,:)=aout(:,:)
350  good_new(:,:)=good_(:,:)
351 
352  do j=js,je
353  i_loop: do i=is,ie
354 
355  if (good_(i,j) .eq. 1.0 .or. fill(i,j) .eq. 0.) cycle i_loop
356 
357  ge=good_(i+1,j);gw=good_(i-1,j)
358  gn=good_(i,j+1);gs=good_(i,j-1)
359  east=0.0;west=0.0;north=0.0;south=0.0
360  if (ge.eq.1.0) east=aout(i+1,j)*ge
361  if (gw.eq.1.0) west=aout(i-1,j)*gw
362  if (gn.eq.1.0) north=aout(i,j+1)*gn
363  if (gs.eq.1.0) south=aout(i,j-1)*gs
364 
365  ngood = ge+gw+gn+gs
366  if (ngood > 0.) then
367  b(i,j)=(east+west+north+south)/ngood
368  fill_pts(i,j)=0.0
369  good_new(i,j)=1.0
370  endif
371  enddo i_loop
372  enddo
373 
374  aout(is:ie,js:je)=b(is:ie,js:je)
375  good_(is:ie,js:je)=good_new(is:ie,js:je)
376  nfill_prev = nfill
377  nfill = sum(fill_pts(is:ie,js:je))
378  call sum_across_pes(nfill)
379 
380  if (nfill == nfill_prev .and. PRESENT(prev)) then
381  do j=js,je
382  do i=is,ie
383  if (fill_pts(i,j).eq.1.0) then
384  aout(i,j)=prev(i,j)
385  fill_pts(i,j)=0.0
386  endif
387  enddo
388  enddo
389  else if (nfill .eq. nfill_prev) then
390  print *,&
391  'Unable to fill missing points using either data at the same vertical level from a connected basin'//&
392  'or using a point from a previous vertical level. Make sure that the original data has some valid'//&
393  'data in all basins.'
394  print *,'nfill=',nfill
395  endif
396 
397  nfill = sum(fill_pts(is:ie,js:je))
398  call sum_across_pes(nfill)
399 
400  end do
401 
402  if (do_smooth) then
403  do k=1,npass
404  call pass_var(aout,g%Domain)
405  do j=js,je
406  do i=is,ie
407  if (fill(i,j) .eq. 1) then
408  east=max(good(i+1,j),fill(i+1,j));west=max(good(i-1,j),fill(i-1,j))
409  north=max(good(i,j+1),fill(i,j+1));south=max(good(i,j-1),fill(i,j-1))
410  r(i,j) = relax_coeff*(south*aout(i,j-1)+north*aout(i,j+1)+west*aout(i-1,j)+east*aout(i+1,j) - (south+north+west+east)*aout(i,j))
411  else
412  r(i,j) = 0.
413  endif
414  enddo
415  enddo
416  aout(is:ie,js:je)=r(is:ie,js:je)+aout(is:ie,js:je)
417  ares = maxval(abs(r))
418  call max_across_pes(ares)
419  if (ares <= acrit) exit
420  enddo
421  endif
422 
423  do j=js,je
424  do i=is,ie
425  if (good_(i,j).eq.0.0 .and. fill_pts(i,j) .eq. 1.0) then
426  print *,'in fill_miss, fill, good,i,j= ',fill_pts(i,j),good_(i,j),i,j
427  call mom_error(fatal,"MOM_initialize: "// &
428  "fill is true and good is false after fill_miss, how did this happen? ")
429  endif
430  enddo
431  enddo
432 
433  return
434 
435 end subroutine fill_miss_2d
436 
437 subroutine horiz_interp_and_extrap_tracer(filename, varnam, conversion, recnum, G, tr_z, mask_z, z_in, z_edges_in, missing_value, reentrant_x, tripolar_n, homogenize )
438 
439  character(len=*), intent(in) :: filename !< Path to file containing tracer to be
440  !! interpolated.
441  character(len=*), intent(in) :: varnam !< Name of tracer in filee.
442  real, intent(in) :: conversion !< Conversion factor for tracer.
443  integer, intent(in) :: recnum !< Record number of tracer to be read.
444  type(ocean_grid_type), intent(inout) :: g !< Grid object
445  real, allocatable, dimension(:,:,:) :: tr_z !< pointer to allocatable tracer array on local
446  !! model grid and native vertical levels.
447  real, allocatable, dimension(:,:,:) :: mask_z !< pointer to allocatable tracer mask array on
448  !! local model grid and native vertical levels.
449  real, allocatable, dimension(:) :: z_in !< Cell grid values for input data.
450  real, allocatable, dimension(:) :: z_edges_in !< Cell grid edge values for input data.
451  real, intent(out) :: missing_value
452  logical, intent(in) :: reentrant_x, tripolar_n
453  logical, intent(in), optional :: homogenize
454 
455  real, dimension(:,:), allocatable :: tr_in,tr_inp !< A 2-d array for holding input data on
456  !! native horizontal grid and extended grid
457  !! with poles.
458  real, dimension(:,:), allocatable :: mask_in !< A 2-d mask for extended input grid.
459 
460  real :: pi_180
461  integer :: rcode, ncid, varid, ndims, id, jd, kd, jdp
462  integer :: i,j,k
463  integer, dimension(4) :: start, count, dims, dim_id
464  real, dimension(:,:), allocatable :: x_in, y_in
465  real, dimension(:), allocatable :: lon_in, lat_in
466  real, dimension(:), allocatable :: lat_inp, last_row
467  real :: max_lat, min_lat, pole, max_depth, npole
468  real :: roundoff ! The magnitude of roundoff, usually ~2e-16.
469  logical :: add_np
470  character(len=8) :: laynum
471  type(horiz_interp_type) :: interp
472  integer :: is, ie, js, je ! compute domain indices
473  integer :: isc,iec,jsc,jec ! global compute domain indices
474  integer :: isg, ieg, jsg, jeg ! global extent
475  integer :: isd, ied, jsd, jed ! data domain indices
476  integer :: ni, nj, nz ! global grid size
477  integer :: id_clock_read
478  character(len=12) :: dim_name(4)
479  logical :: debug=.false.
480  real :: npoints,varavg
481  real, dimension(SZI_(G),SZJ_(G)) :: lon_out, lat_out, tr_out, mask_out
482  real, dimension(SZI_(G),SZJ_(G)) :: good, fill
483  real, dimension(SZI_(G),SZJ_(G)) :: tr_outf,tr_prev
484  real, dimension(SZI_(G),SZJ_(G)) :: good2,fill2
485  real, dimension(SZI_(G),SZJ_(G)) :: nlevs
486 
487  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
488  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
489  isg = g%isg ; ieg = g%ieg ; jsg = g%jsg ; jeg = g%jeg
490 
491  id_clock_read = cpu_clock_id('(Initialize tracer from Z) read', grain=clock_loop)
492 
493 
494  if (ALLOCATED(tr_z)) deallocate(tr_z)
495  if (ALLOCATED(mask_z)) deallocate(mask_z)
496  if (ALLOCATED(z_edges_in)) deallocate(z_edges_in)
497 
498  pi_180=atan(1.0)/45.
499 
500  ! Open NetCDF file and if present, extract data and spatial coordinate information
501  ! The convention adopted here requires that the data be written in (i,j,k) ordering.
502 
503  call cpu_clock_begin(id_clock_read)
504 
505 
506  rcode = nf90_open(filename, nf90_nowrite, ncid)
507  if (rcode .ne. 0) call mom_error(fatal,"error opening file "//trim(filename)//&
508  " in hinterp_extrap")
509  rcode = nf90_inq_varid(ncid, varnam, varid)
510  if (rcode .ne. 0) call mom_error(fatal,"error finding variable "//trim(varnam)//&
511  " in file "//trim(filename)//" in hinterp_extrap")
512 
513  rcode = nf90_inquire_variable(ncid, varid, ndims=ndims, dimids=dims)
514  if (rcode .ne. 0) call mom_error(fatal,'error inquiring dimensions hinterp_extrap')
515  if (ndims < 3) call mom_error(fatal,"Variable "//trim(varnam)//" in file "// &
516  trim(filename)//" has too few dimensions.")
517 
518  rcode = nf90_inquire_dimension(ncid, dims(1), dim_name(1), len=id)
519  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 1 data for "// &
520  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
521  rcode = nf90_inq_varid(ncid, dim_name(1), dim_id(1))
522  if (rcode .ne. 0) call mom_error(fatal,"error finding variable "//trim(dim_name(1))//&
523  " in file "//trim(filename)//" in hinterp_extrap")
524  rcode = nf90_inquire_dimension(ncid, dims(2), dim_name(2), len=jd)
525  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 2 data for "// &
526  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
527  rcode = nf90_inq_varid(ncid, dim_name(2), dim_id(2))
528  if (rcode .ne. 0) call mom_error(fatal,"error finding variable "//trim(dim_name(2))//&
529  " in file "//trim(filename)//" in hinterp_extrap")
530  rcode = nf90_inquire_dimension(ncid, dims(3), dim_name(3), len=kd)
531  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 3 data for "// &
532  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
533  rcode = nf90_inq_varid(ncid, dim_name(3), dim_id(3))
534  if (rcode .ne. 0) call mom_error(fatal,"error finding variable "//trim(dim_name(3))//&
535  " in file "//trim(filename)//" in hinterp_extrap")
536 
537 
538  missing_value=0.0
539  rcode = nf90_get_att(ncid, varid, "_FillValue", missing_value)
540  if (rcode .ne. 0) call mom_error(fatal,"error finding missing value for "//&
541  trim(varnam)//" in file "// trim(filename)//" in hinterp_extrap")
542 
543  if (allocated(lon_in)) deallocate(lon_in)
544  if (allocated(lat_in)) deallocate(lat_in)
545  if (allocated(z_in)) deallocate(z_in)
546  if (allocated(z_edges_in)) deallocate(z_edges_in)
547  if (allocated(tr_z)) deallocate(tr_z)
548  if (allocated(mask_z)) deallocate(mask_z)
549 
550  allocate(lon_in(id),lat_in(jd),z_in(kd),z_edges_in(kd+1))
551  allocate(tr_z(isd:ied,jsd:jed,kd), mask_z(isd:ied,jsd:jed,kd))
552 
553  start = 1; count = 1; count(1) = id
554  rcode = nf90_get_var(ncid, dim_id(1), lon_in, start, count)
555  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 1 values for var_name "// &
556  trim(varnam)//",dim_name "//trim(dim_name(1))//" in file "// trim(filename)//" in hinterp_extrap")
557  start = 1; count = 1; count(1) = jd
558  rcode = nf90_get_var(ncid, dim_id(2), lat_in, start, count)
559  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 2 values for var_name "// &
560  trim(varnam)//",dim_name "//trim(dim_name(2))//" in file "// trim(filename)//" in hinterp_extrap")
561  start = 1; count = 1; count(1) = kd
562  rcode = nf90_get_var(ncid, dim_id(3), z_in, start, count)
563  if (rcode .ne. 0) call mom_error(fatal,"error reading dimension 3 values for var_name "// &
564  trim(varnam//",dim_name "//trim(dim_name(3)))//" in file "// trim(filename)//" in hinterp_extrap")
565 
566  call cpu_clock_end(id_clock_read)
567 
568 ! extrapolate the input data to the north pole using the northerm-most latitude
569 
570  max_lat = maxval(lat_in)
571  add_np=.false.
572  if (max_lat < 90.0) then
573  add_np=.true.
574  jdp=jd+1
575  allocate(lat_inp(jdp))
576  lat_inp(1:jd)=lat_in(:)
577  lat_inp(jd+1)=90.0
578  deallocate(lat_in)
579  allocate(lat_in(1:jdp))
580  lat_in(:)=lat_inp(:)
581  else
582  jdp=jd
583  endif
584 
585 ! construct level cell boundaries as the mid-point between adjacent centers
586 
587  z_edges_in(1) = 0.0
588  do k=2,kd
589  z_edges_in(k)=0.5*(z_in(k-1)+z_in(k))
590  enddo
591  z_edges_in(kd+1)=2.0*z_in(kd) - z_in(kd-1)
592 
593  call horiz_interp_init()
594 
595  lon_in = lon_in*pi_180
596  lat_in = lat_in*pi_180
597  allocate(x_in(id,jdp),y_in(id,jdp))
598  call meshgrid(lon_in,lat_in, x_in, y_in)
599 
600  lon_out(:,:) = g%geoLonT(:,:)*pi_180
601  lat_out(:,:) = g%geoLatT(:,:)*pi_180
602 
603 
604  allocate(tr_in(id,jd)) ; tr_in(:,:)=0.0
605  allocate(tr_inp(id,jdp)) ; tr_inp(:,:)=0.0
606  allocate(mask_in(id,jdp)) ; mask_in(:,:)=0.0
607  allocate(last_row(id)) ; last_row(:)=0.0
608 
609  max_depth = maxval(g%bathyT)
610  call mpp_max(max_depth)
611 
612  if (z_edges_in(kd+1)<max_depth) z_edges_in(kd+1)=max_depth
613 
614 
615 ! loop through each data level and interpolate to model grid.
616 ! after interpolating, fill in points which will be needed
617 ! to define the layers
618 
619  roundoff = 3.0*epsilon(missing_value)
620 
621  do k=1,kd
622  write(laynum,'(I8)') k ; laynum = adjustl(laynum)
623 
624  if (is_root_pe()) then
625  start = 1; start(3) = k; count = 1; count(1) = id; count(2) = jd
626  rcode = nf90_get_var(ncid,varid, tr_in, start, count)
627  if (rcode .ne. 0) call mom_error(fatal,"hinterp_and_extract_from_Fie: "//&
628  "error reading level "//trim(laynum)//" of variable "//&
629  trim(varnam)//" in file "// trim(filename))
630 
631  if (add_np) then
632  last_row(:)=tr_in(:,jd); pole=0.0;npole=0.0
633  do i=1,id
634  if (abs(tr_in(i,jd)-missing_value) .gt. abs(roundoff*missing_value)) then
635  pole = pole+last_row(i)
636  npole = npole+1.0
637  endif
638  enddo
639  if (npole > 0) then
640  pole=pole/npole
641  else
642  pole=missing_value
643  endif
644  tr_inp(:,1:jd) = tr_in(:,:)
645  tr_inp(:,jdp) = pole
646  else
647  tr_inp(:,:) = tr_in(:,:)
648  endif
649 
650  endif
651 
652  call mpp_sync()
653  call mpp_broadcast(tr_inp,id*jdp,root_pe())
654  call mpp_sync_self ()
655 
656  mask_in=0.0
657 
658  do j=1,jdp
659  do i=1,id
660  if (abs(tr_inp(i,j)-missing_value) .gt. abs(roundoff*missing_value)) then
661  mask_in(i,j)=1.0
662  tr_inp(i,j) = tr_inp(i,j) * conversion
663  else
664  tr_inp(i,j)=missing_value
665  endif
666  enddo
667  enddo
668 
669 
670 ! call fms routine horiz_interp to interpolate input level data to model horizontal grid
671 
672 
673  if (k == 1) then
674  call horiz_interp_new(interp,x_in,y_in,lon_out(is:ie,js:je),lat_out(is:ie,js:je), &
675  interp_method='bilinear',src_modulo=reentrant_x)
676  endif
677 
678  if (debug) then
679  call mystats(tr_inp,missing_value, is,ie,js,je,k,'Tracer from file')
680  endif
681 
682  tr_out(:,:) = 0.0
683 
684  call horiz_interp(interp,tr_inp,tr_out(is:ie,js:je), missing_value=missing_value, new_missing_handle=.true.)
685 
686  mask_out=1.0
687  do j=js,je
688  do i=is,ie
689  if (abs(tr_out(i,j)-missing_value) .lt. abs(roundoff*missing_value)) mask_out(i,j)=0.
690  enddo
691  enddo
692 
693  fill = 0.0; good = 0.0
694 
695  npoints = 0 ; varavg = 0.
696  do j=js,je
697  do i=is,ie
698  if (mask_out(i,j) .lt. 1.0) then
699  tr_out(i,j)=missing_value
700  else
701  good(i,j)=1.0
702  npoints = npoints + 1
703  varavg = varavg + tr_out(i,j)
704  endif
705  if (g%mask2dT(i,j) == 1.0 .and. z_edges_in(k) <= g%bathyT(i,j) .and. mask_out(i,j) .lt. 1.0) fill(i,j)=1.0
706  enddo
707  enddo
708  call pass_var(fill,g%Domain)
709  call pass_var(good,g%Domain)
710 
711  if (debug) then
712  call mystats(tr_out,missing_value, is,ie,js,je,k,'variable from horiz_interp()')
713  endif
714 
715  ! Horizontally homogenize data to produce perfectly "flat" initial conditions
716  if (PRESENT(homogenize)) then
717  if (homogenize) then
718  call sum_across_pes(npoints)
719  call sum_across_pes(varavg)
720  if (npoints>0) then
721  varavg = varavg/real(npoints)
722  endif
723  tr_out(:,:) = varavg
724  endif
725  endif
726 
727 ! tr_out contains input z-space data on the model grid with missing values
728 ! now fill in missing values using "ICE-nine" algorithm.
729 
730  tr_outf(:,:)=tr_out(:,:)
731  if (k==1) tr_prev(:,:)=tr_outf(:,:)
732  good2(:,:)=good(:,:)
733  fill2(:,:)=fill(:,:)
734 
735  call fill_miss_2d(tr_outf,good2,fill2,tr_prev,g,smooth=.true.)
736  call mystats(tr_outf,missing_value,is,ie,js,je,k,'field from fill_miss_2d()')
737 
738  tr_z(:,:,k) = tr_outf(:,:)*g%mask2dT(:,:)
739  mask_z(:,:,k) = good2(:,:)+fill2(:,:)
740 
741  tr_prev(:,:)=tr_z(:,:,k)
742 
743  if (debug) then
744  call hchksum(tr_prev,'field after fill ',g%HI)
745  endif
746 
747  enddo ! kd
748 
749 end subroutine horiz_interp_and_extrap_tracer
750 
751 function tracer_z_init(tr_in,z_edges,e,nkml,nkbl,land_fill,wet,nlay,nlevs,debug,i_debug,j_debug) result(tr)
752 !
753 ! Adopted from R. Hallberg
754 ! Arguments:
755 ! (in) tr_in - The z-space array of tracer concentrations that is read in.
756 ! (in) z_edges - The depths of the cell edges in the input z* data (m)
757 ! (in) e - The depths of the layer interfaces (m)
758 ! (in) nkml - number of mixed layer pieces
759 ! (in) nkbl - number of buffer layer pieces
760 ! (in) land_fill - fill in data over land
761 ! (in) wet - wet mask (1=ocean)
762 ! (in) nlay - number of layers
763 ! (in) nlevs - number of levels
764 
765 ! (out) tr - tracers on layers
766 
767 ! tr_1d ! A copy of the input tracer concentrations in a column.
768 ! wt ! The fractional weight for each layer in the range between
769  ! k_top and k_bot, nondim.
770 ! z1 ! z1 and z2 are the depths of the top and bottom limits of the part
771 ! z2 ! of a z-cell that contributes to a layer, relative to the cell
772 ! center and normalized by the cell thickness, nondim.
773 ! Note that -1/2 <= z1 <= z2 <= 1/2.
774 !
775 real, dimension(:,:,:), intent(in) :: tr_in !< The z-space array of tracer
776  !! concentrations that is read in.
777 real, dimension(size(tr_in,3)+1), intent(in) :: z_edges !< The depths of the cell edges in the input
778  !! z* data (m).
779 integer, intent(in) :: nlay !< Number of layers.
780 real, dimension(size(tr_in,1),size(tr_in,2),nlay+1), &
781  intent(in) :: e !< The depths of the layer interfaces (m).
782 integer, intent(in) :: nkml !< Number of mixed layer pieces.
783 integer, intent(in) :: nkbl !< Number of buffer layer pieces.
784 real, intent(in) :: land_fill !< Fill in data over land.
785 real, dimension(size(tr_in,1),size(tr_in,2)), &
786  intent(in) :: wet !< Wet mask (1=ocean)
787 real, dimension(size(tr_in,1),size(tr_in,2)), &
788  optional, intent(in) :: nlevs !< Number of levels
789 logical, intent(in), optional :: debug
790 integer, intent(in), optional :: i_debug
791 integer, intent(in), optional :: j_debug
792 
793 real, dimension(size(tr_in,1),size(tr_in,2),nlay) :: tr
794 real, dimension(size(tr_in,3)) :: tr_1d
795 real, dimension(nlay+1) :: e_1d
796 real, dimension(nlay) :: tr_
797 integer, dimension(size(tr_in,1),size(tr_in,2)) :: nlevs_data
798 
799 integer :: n,i,j,k,l,nx,ny,nz,nt,kz
800 integer :: k_top,k_bot,k_bot_prev,kk,kstart
801 real :: sl_tr
802 real, dimension(size(tr_in,3)) :: wt,z1,z2
803 logical :: debug_msg, debug_
804 
805 nx = size(tr_in,1); ny=size(tr_in,2); nz = size(tr_in,3)
806 
807 nlevs_data = size(tr_in,3)
808 if (PRESENT(nlevs)) then
809  nlevs_data = anint(nlevs)
810 endif
811 
812 debug_=.false.
813 if (PRESENT(debug)) then
814  debug_=debug
815 endif
816 
817 debug_msg = .false.
818 if (debug_) then
819  debug_msg=.true.
820 endif
821 
822 
823 do j=1,ny
824  i_loop: do i=1,nx
825  if (nlevs_data(i,j) .eq. 0 .or. wet(i,j) .eq. 0.) then
826  tr(i,j,:) = land_fill
827  cycle i_loop
828  endif
829 
830  do k=1,nz
831  tr_1d(k) = tr_in(i,j,k)
832  enddo
833 
834  do k=1,nlay+1
835  e_1d(k) = e(i,j,k)
836  enddo
837  k_bot = 1 ; k_bot_prev = -1
838  do k=1,nlay
839  if (e_1d(k+1) > z_edges(1)) then
840  tr(i,j,k) = tr_1d(1)
841  elseif (e_1d(k) < z_edges(nlevs_data(i,j)+1)) then
842  if (debug_msg) then
843  print *,'*** WARNING : Found interface below valid range of z data '
844  print *,'(i,j,z_bottom,interface)= ',&
845  i,j,z_edges(nlevs_data(i,j)+1),e_1d(k)
846  print *,'z_edges= ',z_edges
847  print *,'e=',e_1d
848  print *,'*** I will extrapolate below using the bottom-most valid values'
849  debug_msg = .false.
850  endif
851  tr(i,j,k) = tr_1d(nlevs_data(i,j))
852 
853  else
854  kstart=k_bot
855  call find_overlap(z_edges, e_1d(k), e_1d(k+1), nlevs_data(i,j), &
856  kstart, k_top, k_bot, wt, z1, z2)
857 
858  if (debug_) then
859  if (PRESENT(i_debug)) then
860  if (i.eq.i_debug.and.j.eq.j_debug) then
861  print *,'0001 k,k_top,k_bot,sum(wt),sum(z2-z1) = ',k,k_top,k_bot,sum(wt),sum(z2-z1)
862  endif
863  endif
864  endif
865  kz = k_top
866  sl_tr=0.0; ! cur_tr=0.0
867  if (kz /= k_bot_prev) then
868 ! Calculate the intra-cell profile.
869  if ((kz < nlevs_data(i,j)) .and. (kz > 1)) then
870  sl_tr = find_limited_slope(tr_1d, z_edges, kz)
871  endif
872  endif
873  if (kz > nlevs_data(i,j)) kz = nlevs_data(i,j)
874 ! This is the piecewise linear form.
875  tr(i,j,k) = wt(kz) * &
876  (tr_1d(kz) + 0.5*sl_tr*(z2(kz) + z1(kz)))
877 ! For the piecewise parabolic form add the following...
878 ! + C1_3*cur_tr*(z2(kz)**2 + z2(kz)*z1(kz) + z1(kz)**2))
879 ! if (debug_) then
880 ! print *,'k,k_top,k_bot= ',k,k_top,k_bot
881 ! endif
882  if (debug_) then
883  if (PRESENT(i_debug)) then
884  if (i.eq.i_debug.and.j.eq.j_debug) then
885  print *,'0002 k,k_top,k_bot,k_bot_prev,sl_tr = ',k,k_top,k_bot,k_bot_prev,sl_tr
886  endif
887  endif
888  endif
889 
890  do kz=k_top+1,k_bot-1
891  tr(i,j,k) = tr(i,j,k) + wt(kz)*tr_1d(kz)
892  enddo
893 
894  if (debug_) then
895  if (PRESENT(i_debug)) then
896  if (i.eq.i_debug.and.j.eq.j_debug) then
897  print *,'0003 k,tr = ',k,tr(i,j,k)
898  endif
899  endif
900  endif
901 
902  if (k_bot > k_top) then
903  kz = k_bot
904 ! Calculate the intra-cell profile.
905  sl_tr = 0.0 ! ; cur_tr = 0.0
906  if ((kz < nlevs_data(i,j)) .and. (kz > 1)) then
907  sl_tr = find_limited_slope(tr_1d, z_edges, kz)
908 ! if (debug_) then
909 ! print *,'002 sl_tr,k,kz,nlevs= ',sl_tr,k,kz,nlevs_data(i,j),nlevs(i,j)
910 ! endif
911  endif
912 ! This is the piecewise linear form.
913  tr(i,j,k) = tr(i,j,k) + wt(kz) * &
914  (tr_1d(kz) + 0.5*sl_tr*(z2(kz) + z1(kz)))
915 ! For the piecewise parabolic form add the following...
916 ! + C1_3*cur_tr*(z2(kz)**2 + z2(kz)*z1(kz) + z1(kz)**2))
917 
918  if (debug_) then
919  if (PRESENT(i_debug)) then
920  if (i.eq.i_debug.and.j.eq.j_debug) then
921  print *,'0004 k,kz,nlevs,sl_tr,tr = ',k,kz,nlevs_data(i,j),sl_tr,tr(i,j,k)
922  print *,'0005 k,kz,tr(kz),tr(kz-1),tr(kz+1) = ',k,kz,tr_1d(kz),tr_1d(kz-1),tr_1d(kz+1),z_edges(kz+2)
923  endif
924  endif
925  endif
926 
927  endif
928  k_bot_prev = k_bot
929 
930  endif
931  enddo ! k-loop
932 
933  do k=2,nlay ! simply fill vanished layers with adjacent value
934  if (e_1d(k)-e_1d(k+1) .le. epsln) tr(i,j,k)=tr(i,j,k-1)
935  enddo
936 
937  enddo i_loop
938 enddo
939 
940 return
941 
942 end function tracer_z_init
943 
944 
945 function bisect_fast(a, x, lo, hi) result(bi_r)
946 !
947 ! Return the index where to insert item x in list a, assuming a is sorted.
948 ! The return values [i] is such that all e in a[:i-1] have e <= x, and all e in
949 ! a[i:] have e > x. So if x already appears in the list, will
950 ! insert just after the rightmost x already there.
951 ! Optional args lo (default 1) and hi (default len(a)) bound the
952 ! slice of a to be searched.
953 !
954 ! (in) a - sorted list
955 ! (in) x - item to be inserted
956 ! (in) lo, hi - optional range to search
957 
958 real, dimension(:,:), intent(in) :: a !< Sorted list.
959 real, dimension(:), intent(in) :: x !< Item to be inserted.
960 integer, dimension(size(a,1)), &
961  intent(in), optional :: lo,hi !< Optional range to search.
962 integer, dimension(size(a,1),size(x,1)) :: bi_r
963 
964 integer :: mid,num_x,num_a,i
965 integer, dimension(size(a,1)) :: lo_,hi_,lo0,hi0
966 integer :: nprofs,j
967 
968 lo_=1;hi_=size(a,2);num_x=size(x,1);bi_r=-1;nprofs=size(a,1)
969 
970 if (PRESENT(lo)) then
971  where (lo>0) lo_=lo
972 end if
973 if (PRESENT(hi)) then
974  where (hi>0) hi_=hi
975 endif
976 
977 lo0=lo_;hi0=hi_
978 
979 do j=1,nprofs
980  do i=1,num_x
981  lo_=lo0;hi_=hi0
982  do while (lo_(j) < hi_(j))
983  mid = (lo_(j)+hi_(j))/2
984  if (x(i) < a(j,mid)) then
985  hi_(j) = mid
986  else
987  lo_(j) = mid+1
988  endif
989  enddo
990  bi_r(j,i)=lo_(j)
991  enddo
992 enddo
993 
994 
995 return
996 
997 end function bisect_fast
998 
999 
1000 #ifdef PY_SOLO
1001 subroutine determine_temperature(temp,salt,R,p_ref,niter,land_fill,h,k_start)
1002 !< This subroutine determines the potential temperature and
1003 !! salinity that is consistent with the target density
1004 !! using provided initial guess
1005 ! # (inout) temp - potential temperature (degC)
1006 ! # (inout) salt - salinity (PSU)
1007 ! # (in) R - Desired potential density, in kg m-3.
1008 ! # (in) p_ref - Reference pressure, in Pa.
1009 ! # (in) niter - maximum number of iterations
1010 ! # (in) h - layer thickness . Do not iterate for massless layers
1011 ! # (in) k_start - starting index (i.e. below the buffer layer)
1012 ! # (in) land_fill - land fill value
1013 
1014 real(kind=8), dimension(:,:,:), intent(inout) :: temp !< Potential temperature (degC).
1015 real(kind=8), dimension(:,:,:), intent(inout) :: salt !< Salinity (PSU).
1016 real(kind=8), dimension(size(temp,3)), intent(in) :: r !< Desired potential density,
1017  !! in kg m-3.
1018 real, intent(in) :: p_ref !< Reference pressure, in Pa.
1019 integer, intent(in) :: niter !< Maximum number of iterations.
1020 integer, intent(in) :: k_start !< Starting index (i.e. below the
1021  !! buffer layer).
1022 real, intent(in) :: land_fill !< Land fill value.
1023 real(kind=8), dimension(:,:,:), intent(in) :: h !< Layer thickness. Do not iterate
1024  !! for massless layers.
1025 
1026 real(kind=8), dimension(size(temp,1),size(temp,3)) :: t,s,dt,ds,rho,hin
1027 real(kind=8), dimension(size(temp,1),size(temp,3)) :: drho_dt,drho_ds
1028 real(kind=8), dimension(size(temp,1)) :: press
1029 
1030 integer :: nx,ny,nz,nt,i,j,k,n,itt
1031 logical :: adjust_salt , old_fit
1032 real :: dt_ds
1033 real, parameter :: t_max = 35.0, t_min = -2.0
1034 real, parameter :: s_min = 0.5, s_max=65.0
1035 real, parameter :: tol=1.e-4, max_t_adj=1.0, max_s_adj = 0.5
1036 
1037 #else
1038 
1039 subroutine determine_temperature(temp,salt,R,p_ref,niter,land_fill,h,k_start,eos)
1040 
1041 !< This subroutine determines the potential temperature and
1042 !! salinity that is consistent with the target density
1043 !! using provided initial guess
1044 ! # (inout) temp - potential temperature (degC)
1045 ! # (inout) salt - salinity (PSU)
1046 ! # (in) R - Desired potential density, in kg m-3.
1047 ! # (in) p_ref - Reference pressure, in Pa.
1048 ! # (in) niter - maximum number of iterations
1049 ! # (in) h - layer thickness . Do not iterate for massless layers
1050 ! # (in) k_start - starting index (i.e. below the buffer layer)
1051 ! # (in) land_fill - land fill value
1052 ! # (in) eos - seawater equation of state
1053 
1054 real, dimension(:,:,:), intent(inout) :: temp !< Potential temperature (degC).
1055 real, dimension(:,:,:), intent(inout) :: salt !< Salinity (PSU).
1056 real, dimension(size(temp,3)), intent(in) :: r !< Desired potential density, in kg m-3.
1057 real, intent(in) :: p_ref !< Reference pressure, in Pa.
1058 integer, intent(in) :: niter !< Maximum number of iterations.
1059 integer, intent(in) :: k_start !< Starting index (i.e. below the buffer
1060  !! layer).
1061 real, intent(in) :: land_fill !< Land fill value.
1062 real, dimension(:,:,:), intent(in) :: h !< Layer thickness . Do not iterate for
1063  !! massless layers.
1064 type(eos_type), pointer, intent(in) :: eos !< Seawater equation of state
1065 
1066 real(kind=8), dimension(size(temp,1),size(temp,3)) :: t,s,dt,ds,rho,hin
1067 real(kind=8), dimension(size(temp,1),size(temp,3)) :: drho_dt,drho_ds
1068 real(kind=8), dimension(size(temp,1)) :: press
1069 
1070 integer :: nx,ny,nz,nt,i,j,k,n,itt
1071 real :: dt_ds
1072 logical :: adjust_salt , old_fit
1073 real, parameter :: t_max = 31.0, t_min = -2.0
1074 real, parameter :: s_min = 0.5, s_max=65.0
1075 real, parameter :: tol=1.e-4, max_t_adj=1.0, max_s_adj = 0.5
1076 
1077 
1078 #endif
1079 
1080 
1081 old_fit = .true. ! reproduces siena behavior
1082  ! will switch to the newer
1083  ! method which simultaneously adjusts
1084  ! temp and salt based on the ratio
1085  ! of the thermal and haline coefficients.
1086 
1087 nx=size(temp,1);ny=size(temp,2); nz=size(temp,3)
1088 
1089 press(:) = p_ref
1090 
1091 do j=1,ny
1092  ds(:,:) = 0. ! Needs to be zero everywhere since there is a maxval(abs(dS)) later...
1093  t=temp(:,j,:)
1094  s=salt(:,j,:)
1095  hin=h(:,j,:)
1096  dt=0.0
1097  adjust_salt = .true.
1098  iter_loop: do itt = 1,niter
1099 #ifdef PY_SOLO
1100  rho=wright_eos_2d(t,s,p_ref)
1101  drho_dt=alpha_wright_eos_2d(t,s,p_ref)
1102 #else
1103  do k=1, nz
1104  call calculate_density(t(:,k),s(:,k),press,rho(:,k),1,nx,eos)
1105  call calculate_density_derivs(t(:,k),s(:,k),press,drho_dt(:,k),drho_ds(:,k),1,nx,eos)
1106  enddo
1107 #endif
1108  do k=k_start,nz
1109  do i=1,nx
1110 
1111 ! if (abs(rho(i,k)-R(k))>tol .and. hin(i,k)>epsln .and. abs(T(i,k)-land_fill) < epsln) then
1112  if (abs(rho(i,k)-r(k))>tol) then
1113  if (old_fit) then
1114  dt(i,k)=(r(k)-rho(i,k))/drho_dt(i,k)
1115  if (dt(i,k)>max_t_adj) dt(i,k)=max_t_adj
1116  if (dt(i,k)<-1.0*max_t_adj) dt(i,k)=-1.0*max_t_adj
1117  t(i,k)=max(min(t(i,k)+dt(i,k),t_max),t_min)
1118  else
1119  dt_ds = 10.0 - min(-drho_dt(i,k)/drho_ds(i,k),10.)
1120  ds(i,k) = (r(k)-rho(i,k))/(drho_ds(i,k) - drho_dt(i,k)*dt_ds )
1121  dt(i,k)= -dt_ds*ds(i,k)
1122  ! if (dT(i,k)>max_t_adj) dT(i,k)=max_t_adj
1123  ! if (dT(i,k)<-1.0*max_t_adj) dT(i,k)=-1.0*max_t_adj
1124  t(i,k)=max(min(t(i,k)+dt(i,k),t_max),t_min)
1125  s(i,k)=max(min(s(i,k)+ds(i,k),s_max),s_min)
1126  endif
1127  endif
1128  enddo
1129  enddo
1130  if (maxval(abs(dt)) < tol) then
1131  adjust_salt = .false.
1132  exit iter_loop
1133  endif
1134  enddo iter_loop
1135 
1136  if (adjust_salt .and. old_fit) then
1137  iter_loop2: do itt = 1,niter
1138 #ifdef PY_SOLO
1139  rho=wright_eos_2d(t,s,p_ref)
1140  drho_ds=beta_wright_eos_2d(t,s,p_ref)
1141 #else
1142  do k=1, nz
1143  call calculate_density(t(:,k),s(:,k),press,rho(:,k),1,nx,eos)
1144  call calculate_density_derivs(t(:,k),s(:,k),press,drho_dt(:,k),drho_ds(:,k),1,nx,eos)
1145  enddo
1146 #endif
1147  do k=k_start,nz
1148  do i=1,nx
1149 ! if (abs(rho(i,k)-R(k))>tol .and. hin(i,k)>epsln .and. abs(T(i,k)-land_fill) < epsln ) then
1150  if (abs(rho(i,k)-r(k))>tol ) then
1151  ds(i,k)=(r(k)-rho(i,k))/drho_ds(i,k)
1152  if (ds(i,k)>max_s_adj) ds(i,k)=max_s_adj
1153  if (ds(i,k)<-1.0*max_s_adj) ds(i,k)=-1.0*max_s_adj
1154  s(i,k)=max(min(s(i,k)+ds(i,k),s_max),s_min)
1155  endif
1156  enddo
1157  enddo
1158  if (maxval(abs(ds)) < tol) then
1159  exit iter_loop2
1160  endif
1161  enddo iter_loop2
1162  endif
1163 
1164  temp(:,j,:)=t(:,:)
1165  salt(:,j,:)=s(:,:)
1166 enddo
1167 
1168 
1169 return
1170 
1171 end subroutine determine_temperature
1172 
1173 
1174 subroutine find_overlap(e, Z_top, Z_bot, k_max, k_start, k_top, k_bot, wt, z1, z2)
1175 
1176 !< This subroutine determines the layers bounded by interfaces e that overlap
1177 !! with the depth range between Z_top and Z_bot, and also the fractional weights
1178 !! of each layer. It also calculates the normalized relative depths of the range
1179 !! of each layer that overlaps that depth range.
1180 !! Note that by convention, e decreases with increasing k and Z_top > Z_bot.
1181 !
1182 ! Arguments: e - A column's interface heights, in m.
1183 ! (in) Z_top - The top of the range being mapped to, in m.
1184 ! (in) Z_bot - The bottom of the range being mapped to, in m.
1185 ! (in) k_max - The number of valid layers.
1186 ! (in) k_start - The layer at which to start searching.
1187 ! (out) k_top, k_bot - The indices of the top and bottom layers that
1188 ! overlap with the depth range.
1189 ! (out) wt - The relative weights of each layer from k_top to k_bot.
1190 ! (out) z1, z2 - z1 and z2 are the depths of the top and bottom limits of
1191 ! the part of a layer that contributes to a depth level,
1192 ! relative to the cell center and normalized by the cell
1193 ! thickness, nondim. Note that -1/2 <= z1 < z2 <= 1/2.
1194 
1195 real, dimension(:), intent(in) :: e !< A column's interface heights, in m.
1196 real, intent(in) :: z_top !< The top of the range being mapped to, in m.
1197 real, intent(in) :: z_bot !< The bottom of the range being mapped to, in m.
1198 integer, intent(in) :: k_max !< The number of valid layers.
1199 integer, intent(in) :: k_start !< The layer at which to start searching.
1200 integer, intent(out) :: k_top, k_bot !< The indices of the top and bottom layers that
1201  !! overlap with the depth range.
1202 real, dimension(:), intent(out) :: wt !< The relative weights of each layer from k_top to k_bot.
1203 real, dimension(:), intent(out) :: z1, z2 !< z1 and z2 are the depths of the top and bottom limits
1204  !! of the part of a layer that contributes to a depth
1205  !! level, relative to the cell center and normalized by
1206  !! the cell thickness, nondim. Note that -1/2 <= z1
1207  !! < z2 <= 1/2.
1208 
1209 real :: ih, e_c, tot_wt, i_totwt
1210 integer :: k
1211 
1212 wt(:)=0.0; z1(:)=0.0; z2(:)=0.0
1213 k_top = k_start; k_bot= k_start; wt(1) = 1.0; z1(1)=-0.5; z2(1) = 0.5
1214 
1215 do k=k_start,k_max ;if (e(k+1)<z_top) exit ; enddo
1216 k_top = k
1217 if (k>k_max) return
1218 
1219 ! Determine the fractional weights of each layer.
1220 ! Note that by convention, e and Z_int decrease with increasing k.
1221 if (e(k+1)<=z_bot) then
1222  wt(k) = 1.0 ; k_bot = k
1223  ih = 1.0 / (e(k)-e(k+1))
1224  e_c = 0.5*(e(k)+e(k+1))
1225  z1(k) = (e_c - min(e(k),z_top)) * ih
1226  z2(k) = (e_c - z_bot) * ih
1227 else
1228  wt(k) = min(e(k),z_top) - e(k+1) ; tot_wt = wt(k) ! These are always > 0.
1229  z1(k) = (0.5*(e(k)+e(k+1)) - min(e(k),z_top)) / (e(k)-e(k+1))
1230  z2(k) = 0.5
1231  k_bot = k_max
1232  do k=k_top+1,k_max
1233  if (e(k+1)<=z_bot) then
1234  k_bot = k
1235  wt(k) = e(k) - z_bot ; z1(k) = -0.5
1236  z2(k) = (0.5*(e(k)+e(k+1)) - z_bot) / (e(k)-e(k+1))
1237  else
1238  wt(k) = e(k) - e(k+1) ; z1(k) = -0.5 ; z2(k) = 0.5
1239  endif
1240  tot_wt = tot_wt + wt(k) ! wt(k) is always > 0.
1241  if (k>=k_bot) exit
1242  enddo
1243 
1244  i_totwt = 1.0 / tot_wt
1245  do k=k_top,k_bot ; wt(k) = i_totwt*wt(k) ; enddo
1246 endif
1247 
1248 return
1249 
1250 end subroutine find_overlap
1251 
1252 
1253 function find_limited_slope(val, e, k) result(slope)
1254 
1255 !< This subroutine determines a limited slope for val to be advected with
1256 !! a piecewise limited scheme.
1257 
1258 ! Arguments: val - An column the values that are being interpolated.
1259 ! (in) e - A column's interface heights, in m.
1260 ! (in) slope - The normalized slope in the intracell distribution of val.
1261 ! (in) k - The layer whose slope is being determined.
1262 
1263 
1264 real, dimension(:), intent(in) :: val !< An column the values that are being interpolated.
1265 real, dimension(:), intent(in) :: e !< A column's interface heights, in m.
1266 integer, intent(in) :: k !< The layer whose slope is being determined.
1267 real :: slope,amx,bmx,amn,bmn,cmn,dmn
1268 
1269 real :: d1, d2
1270 
1271 if ((val(k)-val(k-1)) * (val(k)-val(k+1)) >= 0.0) then
1272  slope = 0.0 ! ; curvature = 0.0
1273 else
1274  d1 = 0.5*(e(k-1)-e(k+1)) ; d2 = 0.5*(e(k)-e(k+2))
1275  slope = ((d1**2)*(val(k+1) - val(k)) + (d2**2)*(val(k) - val(k-1))) * &
1276  (e(k) - e(k+1)) / (d1*d2*(d1+d2))
1277 ! slope = 0.5*(val(k+1) - val(k-1))
1278 ! This is S.J. Lin's form of the PLM limiter.
1279  amx=max(val(k-1),val(k))
1280  bmx = max(amx,val(k+1))
1281  amn = min(abs(slope),2.0*(bmx-val(k)))
1282  bmn = min(val(k-1),val(k))
1283  cmn = 2.0*(val(k)-min(bmn,val(k+1)))
1284  dmn = min(amn,cmn)
1285  slope = sign(1.0,slope) * dmn
1286 
1287 ! min(abs(slope), &
1288 ! 2.0*(max(val(k-1),val(k),val(k+1)) - val(k)), &
1289 ! 2.0*(val(k) - min(val(k-1),val(k),val(k+1))))
1290 ! curvature = 0.0
1291 endif
1292 
1293 return
1294 
1295 end function find_limited_slope
1296 
1297 
1298 
1299 function find_interfaces(rho,zin,Rb,depth,nlevs,nkml,nkbl,hml,debug) result(zi)
1300 ! (in) rho : potential density in z-space (kg m-3)
1301 ! (in) zin : levels (m)
1302 ! (in) Rb : target interface densities (kg m-3)
1303 ! (in) depth: ocean depth (m)
1304 ! (in) nlevs: number of valid points in each column
1305 ! (in) nkml : number of mixed layer pieces
1306 ! (in) nkbl : number of buffer layer pieces
1307 ! (in) hml : mixed layer depth
1308 
1309 real, dimension(:,:,:), intent(in) :: rho !< Potential density in z-space (kg m-3)
1310 real, dimension(size(rho,3)), intent(in) :: zin !< LKevels (m)
1311 real, dimension(:), intent(in) :: rb !< Target interface densities (kg m-3)
1312 real, dimension(size(rho,1),size(rho,2)), &
1313  intent(in) :: depth !< Ocean depth (m)
1314 real, dimension(size(rho,1),size(rho,2)), &
1315  optional, intent(in) :: nlevs !< Number of valid points in each column
1316 logical, optional, intent(in) :: debug
1317 real, dimension(size(rho,1),size(rho,2),size(Rb,1)) :: zi
1318 integer, intent(in), optional :: nkml !< Number of mixed layer pieces
1319 integer, intent(in), optional :: nkbl !< Number of buffer layer pieces
1320 real, intent(in), optional :: hml !< Mixed layer depth
1321 
1322 real, dimension(size(rho,1),size(rho,3)) :: rho_
1323 real, dimension(size(rho,1)) :: depth_
1324 logical :: unstable
1325 integer :: dir
1326 integer, dimension(size(rho,1),size(Rb,1)) :: ki_
1327 real, dimension(size(rho,1),size(Rb,1)) :: zi_
1328 integer, dimension(size(rho,1),size(rho,2)) :: nlevs_data
1329 integer, dimension(size(rho,1)) :: lo,hi
1330 real :: slope,rsm,drhodz,hml_
1331 integer :: n,i,j,k,l,nx,ny,nz,nt
1332 integer :: nlay,kk,nkml_,nkbl_
1333 logical :: debug_ = .false.
1334 
1335 real, parameter :: zoff=0.999
1336 
1337 nlay=size(rb)-1
1338 
1339 zi=0.0
1340 
1341 
1342 if (PRESENT(debug)) debug_=debug
1343 
1344 nx = size(rho,1); ny=size(rho,2); nz = size(rho,3)
1345 nlevs_data(:,:) = size(rho,3)
1346 
1347 nkml_=0;nkbl_=0;hml_=0.0
1348 if (PRESENT(nkml)) nkml_=max(0,nkml)
1349 if (PRESENT(nkbl)) nkbl_=max(0,nkbl)
1350 if (PRESENT(hml)) hml_=hml
1351 
1352 if (PRESENT(nlevs)) then
1353  nlevs_data(:,:) = nlevs(:,:)
1354 endif
1355 
1356 do j=1,ny
1357  rho_(:,:) = rho(:,j,:)
1358  i_loop: do i=1,nx
1359  if (debug_) then
1360  print *,'looking for interfaces, i,j,nlevs= ',i,j,nlevs_data(i,j)
1361  print *,'initial density profile= ', rho_(i,:)
1362  endif
1363  unstable=.true.
1364  dir=1
1365  do while (unstable)
1366  unstable=.false.
1367  if (dir == 1) then
1368  do k=2,nlevs_data(i,j)-1
1369  if (rho_(i,k) - rho_(i,k-1) < 0.0 ) then
1370  if (k.eq.2) then
1371  rho_(i,k-1)=rho_(i,k)-epsln
1372  else
1373  drhodz = (rho_(i,k+1)-rho_(i,k-1))/(zin(k+1)-zin(k-1))
1374  if (drhodz < 0.0) then
1375  unstable=.true.
1376  endif
1377  rho_(i,k) = rho_(i,k-1)+drhodz*zoff*(zin(k)-zin(k-1))
1378  endif
1379  endif
1380  enddo
1381  dir=-1*dir
1382  else
1383  do k=nlevs_data(i,j)-1,2,-1
1384  if (rho_(i,k+1) - rho_(i,k) < 0.0) then
1385  if (k .eq. nlevs_data(i,j)-1) then
1386  rho_(i,k+1)=rho_(i,k-1)+epsln
1387  else
1388  drhodz = (rho_(i,k+1)-rho_(i,k-1))/(zin(k+1)-zin(k-1))
1389  if (drhodz < 0.0) then
1390  unstable=.true.
1391  endif
1392  rho_(i,k) = rho_(i,k+1)-drhodz*(zin(k+1)-zin(k))
1393  endif
1394  endif
1395  enddo
1396  dir=-1*dir
1397  endif
1398  enddo
1399  if (debug_) then
1400  print *,'final density profile= ', rho_(i,:)
1401  endif
1402  enddo i_loop
1403 
1404  ki_(:,:) = 0
1405  zi_(:,:) = 0.0
1406  depth_(:)=-1.0*depth(:,j)
1407  lo(:)=1
1408  hi(:)=nlevs_data(:,j)
1409  ki_ = bisect_fast(rho_,rb,lo,hi)
1410  ki_(:,:) = max(1,ki_(:,:)-1)
1411  do i=1,nx
1412  do l=2,nlay
1413  slope = (zin(ki_(i,l)+1) - zin(ki_(i,l)))/max(rho_(i,ki_(i,l)+1) - rho_(i,ki_(i,l)),epsln)
1414  zi_(i,l) = -1.0*(zin(ki_(i,l)) + slope*(rb(l)-rho_(i,ki_(i,l))))
1415  zi_(i,l) = max(zi_(i,l),depth_(i))
1416  zi_(i,l) = min(zi_(i,l),-1.0*hml_)
1417  enddo
1418  zi_(i,nlay+1)=depth_(i)
1419  do l=2,nkml_+1
1420  zi_(i,l)=max(((1.0-real(l))/real(nkml_))*hml_,depth_(i))
1421  enddo
1422  do l=nlay,nkml_+2,-1
1423  if (zi_(i,l) < zi_(i,l+1)+epsln) then
1424  zi_(i,l)=zi_(i,l+1)+epsln
1425  endif
1426  if (zi_(i,l)>-1.0*hml_) then
1427  zi_(i,l)=max(-1.0*hml_,depth_(i))
1428  endif
1429  enddo
1430  enddo
1431  zi(:,j,:)=zi_(:,:)
1432 enddo
1433 
1434 return
1435 
1436 
1437 end function find_interfaces
1438 
1439 subroutine meshgrid(x,y,x_T,y_T)
1440 
1441 !< create a 2d-mesh of grid coordinates
1442 !! from 1-d arrays.
1443 
1444 real, dimension(:), intent(in) :: x,y
1445 real, dimension(size(x,1),size(y,1)), intent(inout) :: x_t,y_t
1446 
1447 integer :: ni,nj,i,j
1448 
1449 ni=size(x,1);nj=size(y,1)
1450 
1451 do j=1,nj
1452  x_t(:,j)=x(:)
1453 enddo
1454 
1455 do i=1,ni
1456  y_t(i,:)=y(:)
1457 enddo
1458 
1459 return
1460 
1461 end subroutine meshgrid
1462 
1463 subroutine smooth_heights(zi,fill,bad,sor,niter,cyclic_x, tripolar_n)
1464 !< Solve del2 (zi) = 0 using successive iterations
1465 !! with a 5 point stencil. Only points fill==1 are
1466 !! modified. Except where bad==1, information propagates
1467 !! isotropically in index space. The resulting solution
1468 !! in each region is an approximation to del2(zi)=0 subject to
1469 !! boundary conditions along the valid points curve bounding this region.
1470 
1471 real, dimension(:,:), intent(inout) :: zi
1472 integer, dimension(size(zi,1),size(zi,2)), intent(in) :: fill
1473 integer, dimension(size(zi,1),size(zi,2)), intent(in) :: bad
1474 real, intent(in) :: sor
1475 integer, intent(in) :: niter
1476 logical, intent(in) :: cyclic_x, tripolar_n
1477 
1478 integer :: i,j,k,n
1479 integer :: ni,nj
1480 
1481 real, dimension(size(zi,1),size(zi,2)) :: res, m
1482 integer, dimension(size(zi,1),size(zi,2),4) :: b
1483 real, dimension(0:size(zi,1)+1,0:size(zi,2)+1) :: mp
1484 integer, dimension(0:size(zi,1)+1,0:size(zi,2)+1) :: nm
1485 
1486 real :: isum, bsum
1487 
1488 ni=size(zi,1); nj=size(zi,2)
1489 
1490 
1491 mp=fill_boundaries(zi,cyclic_x,tripolar_n)
1492 
1493 b(:,:,:)=0.0
1494 nm=fill_boundaries(bad,cyclic_x,tripolar_n)
1495 
1496 do j=1,nj
1497  do i=1,ni
1498  if (fill(i,j) .eq. 1) then
1499  b(i,j,1)=1-nm(i+1,j);b(i,j,2)=1-nm(i-1,j)
1500  b(i,j,3)=1-nm(i,j+1);b(i,j,4)=1-nm(i,j-1)
1501  endif
1502  enddo
1503 enddo
1504 
1505 do n=1,niter
1506  do j=1,nj
1507  do i=1,ni
1508  if (fill(i,j) .eq. 1) then
1509  bsum = real(b(i,j,1)+b(i,j,2)+b(i,j,3)+b(i,j,4))
1510  isum = 1.0/bsum
1511  res(i,j)=isum*(b(i,j,1)*mp(i+1,j)+b(i,j,2)*mp(i-1,j)+&
1512  b(i,j,3)*mp(i,j+1)+b(i,j,4)*mp(i,j-1)) - mp(i,j)
1513  endif
1514  enddo
1515  enddo
1516  res(:,:)=res(:,:)*sor
1517 
1518  do j=1,nj
1519  do i=1,ni
1520  mp(i,j)=mp(i,j)+res(i,j)
1521  enddo
1522  enddo
1523 
1524  zi(:,:)=mp(1:ni,1:nj)
1525  mp = fill_boundaries(zi,cyclic_x,tripolar_n)
1526 end do
1527 
1528 
1529 
1530 return
1531 
1532 end subroutine smooth_heights
1533 
1534 function fill_boundaries_int(m,cyclic_x,tripolar_n) result(mp)
1535 !
1536 ! fill grid edges
1537 !
1538 integer, dimension(:,:), intent(in) :: m
1539 logical, intent(in) :: cyclic_x, tripolar_n
1540 real, dimension(size(m,1),size(m,2)) :: m_real
1541 real, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp_real
1542 integer, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp
1543 
1544 m_real = real(m)
1545 
1546 mp_real = fill_boundaries_real(m_real,cyclic_x,tripolar_n)
1547 
1548 mp = int(mp_real)
1549 
1550 return
1551 
1552 end function fill_boundaries_int
1553 
1554 function fill_boundaries_real(m,cyclic_x,tripolar_n) result(mp)
1555 !< fill grid edges
1556 
1557 real, dimension(:,:), intent(in) :: m
1558 logical, intent(in) :: cyclic_x, tripolar_n
1559 real, dimension(0:size(m,1)+1,0:size(m,2)+1) :: mp
1560 
1561 integer :: ni,nj,i,j
1562 
1563 ni=size(m,1); nj=size(m,2)
1564 
1565 mp(1:ni,1:nj)=m(:,:)
1566 
1567 if (cyclic_x) then
1568  mp(0,1:nj)=m(ni,1:nj)
1569  mp(ni+1,1:nj)=m(1,1:nj)
1570 else
1571  mp(0,1:nj)=m(1,1:nj)
1572  mp(ni+1,1:nj)=m(ni,1:nj)
1573 endif
1574 
1575 mp(1:ni,0)=m(1:ni,1)
1576 if (tripolar_n) then
1577  do i=1,ni
1578  mp(i,nj+1)=m(ni-i+1,nj)
1579  enddo
1580 else
1581  mp(1:ni,nj+1)=m(1:ni,nj)
1582 endif
1583 
1584 return
1585 
1586 end function fill_boundaries_real
1587 
1588 
1589 
1590 end module mom_tracer_initialization_from_z
subroutine, public read_axis_data(filename, axis_name, var)
Definition: MOM_io.F90:424
This module contains the main regridding routines. Regridding comprises two steps: (1) Interpolation ...
Definition: MOM_ALE.F90:7
logical function, public ispointincell(G, i, j, x, y)
Returns true if the coordinates (x,y) are within the h-cell (i,j)
Definition: MOM_grid.F90:406
subroutine, public int_specific_vol_dp(T, S, p_t, p_b, alpha_ref, HI, EOS, dza, intp_dza, intx_dza, inty_dza, halo_size)
Calls the appropriate subroutine to alculate analytical and nearly-analytical integrals in pressure a...
Definition: MOM_EOS.F90:333
integer, parameter, public to_all
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Generates vertical grids as part of the ALE algorithm.
Provides column-wise vertical remapping functions.
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
This module contains I/O framework code.
Definition: MOM_io.F90:2
subroutine, public setverticalgridaxes(Rlay, GV)
This sets the coordinate data for the "layer mode" of the isopycnal model.
Container for remapping parameters.
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Definition: MOM_EOS.F90:214
character(len=len(input_string)) function, public uppercase(input_string)
Regridding control structure.
logical function, public is_root_pe()
subroutine, public mom_mesg(message, verb, all_print)
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
subroutine, public remapping_core_h(CS, n0, h0, u0, n1, h1, u1)
Remaps column of values u0 on grid h0 to grid h1 assuming the top edge is aligned.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public initialize_remapping(CS, remapping_scheme, boundary_extrapolation, check_reconstruction, check_remapping, force_bounds_in_subcell)
Constructor for remapping control structure.
subroutine, public ale_remap_scalar(CS, G, GV, nk_src, h_src, s_src, h_dst, s_dst, all_cells, old_remap)
Remaps a single scalar between grids described by thicknesses h_src and h_dst. h_dst must be dimensio...
Definition: MOM_ALE.F90:970
subroutine, public mom_error(level, message, all_print)
A control structure for the equation of state.
Definition: MOM_EOS.F90:55
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.