1 module mom_tracer_initialization_from_z
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
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
40 implicit none ;
private 42 #include <MOM_memory.h> 44 public :: mom_initialize_tracer_from_z, horiz_interp_and_extrap_tracer
46 character(len=40) :: mdl =
"MOM_tracer_initialization_from_Z" 48 interface fill_boundaries
49 module procedure fill_boundaries_real
50 module procedure fill_boundaries_int
53 real,
parameter :: epsln=1.e-10
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 )
71 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)), &
73 real,
dimension(:,:,:),
pointer :: tr
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
82 real :: land_fill = 0.0
83 character(len=200) :: inputdir
84 character(len=200) :: mesg
87 character(len=10) :: remapscheme
88 logical :: homog,useale
91 #include "version_variable.h" 93 character(len=40) :: mdl =
"MOM_initialize_tracers_from_Z" 95 integer :: is, ie, js, je, nz
96 integer :: isc,iec,jsc,jec
97 integer :: isg, ieg, jsg, jeg
98 integer :: isd, ied, jsd, jed
100 integer :: i, j, k, kd
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
107 real,
dimension(:),
allocatable :: h1, h2, htarget, deltae, tmpt1d
108 real,
dimension(:),
allocatable :: tmpt1din
109 real :: ztopofcell, zbottomofcell
112 real,
dimension(:,:,:),
allocatable :: hsrc
114 real :: tempavg, missing_value
115 integer :: npoints, ans
116 integer :: id_clock_routine, id_clock_ale
117 logical :: reentrant_x, tripolar_n
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)
122 call cpu_clock_begin(id_clock_routine)
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
128 call calltree_enter(trim(mdl)//
"(), MOM_state_initialization.F90")
130 call mpp_get_compute_domain(g%domain%mpp_domain,isc,iec,jsc,jec)
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.",&
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")
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.)
148 if (
PRESENT(homogenize)) homog=homogenize
149 if (
PRESENT(usealeremapping)) useale=usealeremapping
150 if (
PRESENT(remappingscheme)) remapscheme=remappingscheme
152 if (
PRESENT(src_var_record)) recnum = src_var_record
154 if (
PRESENT(src_var_unit_conversion)) convert = src_var_unit_conversion
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)
160 kd =
size(z_edges_in,1)-1
167 call cpu_clock_begin(id_clock_ale)
170 allocate( hsrc(isd:ied,jsd:jed,kd) )
171 allocate( tmpt1din(kd) )
172 call initialize_remapping( remapcs, remapscheme, boundary_extrapolation=.false. )
174 allocate( htarget(nz) )
176 allocate( tmpt1d(nz) )
177 allocate( deltae(nz+1) )
179 do j = js, je ;
do i = is, ie
180 if (g%mask2dT(i,j)>0.)
then 182 ztopofcell = 0. ; zbottomofcell = 0. ; npoints = 0
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)
188 zbottomofcell = -g%bathyT(i,j)
189 tmpt1din(k) = tmpt1din(k-1)
193 h1(k) = ztopofcell - zbottomofcell
194 if (h1(k)>0.) npoints = npoints + 1
195 ztopofcell = zbottomofcell
197 h1(kd) = h1(kd) + ( ztopofcell + g%bathyT(i,j) )
204 call ale_remap_scalar(remapcs, g, gv, kd, hsrc, tr_z, h, tr, all_cells=.false. )
209 deallocate( htarget )
211 deallocate( tmpt1din )
215 call mystats(tr(:,:,k),missing_value,is,ie,js,je,k,
'Tracer from ALE()')
217 call cpu_clock_end(id_clock_ale)
221 do k=1,nz ;
do j=js,je ;
do i=is,ie
222 if (tr(i,j,k) == missing_value)
then 225 enddo ;
enddo ;
enddo 229 call cpu_clock_end(id_clock_routine)
232 end subroutine mom_initialize_tracer_from_z
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
243 character(len=120) :: lmesg
244 mina = 9.e24 ; maxa = -9.e24 ; found = .false.
248 if (array(i,j) /= array(i,j)) stop
'Nan!' 249 if (abs(array(i,j)-missing)>1.e-6*abs(missing))
then 251 mina = min(mina, array(i,j))
252 maxa = max(maxa, array(i,j))
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)
268 end subroutine mystats
270 subroutine fill_miss_2d(aout,good,fill,prev,G,smooth,num_pass,relc,crit,keep_bug,debug)
285 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: aout
286 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: good
288 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: fill
291 real,
dimension(SZI_(G),SZJ_(G)),
optional, &
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
299 real,
dimension(SZI_(G),SZJ_(G)) :: b,r
300 real,
dimension(SZI_(G),SZJ_(G)) :: fill_pts,good_,good_new
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
311 integer :: is, ie, js, je, nz
312 real :: relax_coeff, acrit, ares
316 if (
PRESENT(debug)) debug_it=debug
318 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
320 npass = num_pass_default
321 if (
PRESENT(num_pass)) npass = num_pass
323 relax_coeff = relc_default
324 if (
PRESENT(relc)) relax_coeff = relc
327 if (
PRESENT(crit)) acrit = crit
330 if (
PRESENT(keep_bug)) siena_bug = keep_bug
333 if (
PRESENT(smooth)) do_smooth=smooth
335 fill_pts(:,:)=fill(:,:)
337 nfill = sum(fill(is:ie,js:je))
338 call sum_across_pes(nfill)
344 do while (nfill > 0.0)
350 good_new(:,:)=good_(:,:)
355 if (good_(i,j) .eq. 1.0 .or. fill(i,j) .eq. 0.) cycle i_loop
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
367 b(i,j)=(east+west+north+south)/ngood
374 aout(is:ie,js:je)=b(is:ie,js:je)
375 good_(is:ie,js:je)=good_new(is:ie,js:je)
377 nfill = sum(fill_pts(is:ie,js:je))
378 call sum_across_pes(nfill)
380 if (nfill == nfill_prev .and.
PRESENT(prev))
then 383 if (fill_pts(i,j).eq.1.0)
then 389 else if (nfill .eq. nfill_prev)
then 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
397 nfill = sum(fill_pts(is:ie,js:je))
398 call sum_across_pes(nfill)
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))
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 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? ")
435 end subroutine fill_miss_2d
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 )
439 character(len=*),
intent(in) :: filename
441 character(len=*),
intent(in) :: varnam
442 real,
intent(in) :: conversion
443 integer,
intent(in) :: recnum
445 real,
allocatable,
dimension(:,:,:) :: tr_z
447 real,
allocatable,
dimension(:,:,:) :: mask_z
449 real,
allocatable,
dimension(:) :: z_in
450 real,
allocatable,
dimension(:) :: z_edges_in
451 real,
intent(out) :: missing_value
452 logical,
intent(in) :: reentrant_x, tripolar_n
453 logical,
intent(in),
optional :: homogenize
455 real,
dimension(:,:),
allocatable :: tr_in,tr_inp
458 real,
dimension(:,:),
allocatable :: mask_in
461 integer :: rcode, ncid, varid, ndims, id, jd, kd, jdp
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
470 character(len=8) :: laynum
471 type(horiz_interp_type) :: interp
472 integer :: is, ie, js, je
473 integer :: isc,iec,jsc,jec
474 integer :: isg, ieg, jsg, jeg
475 integer :: isd, ied, jsd, jed
476 integer :: ni, nj, nz
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
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
491 id_clock_read = cpu_clock_id(
'(Initialize tracer from Z) read', grain=clock_loop)
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)
503 call cpu_clock_begin(id_clock_read)
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")
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.")
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")
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")
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)
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))
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")
566 call cpu_clock_end(id_clock_read)
570 max_lat = maxval(lat_in)
572 if (max_lat < 90.0)
then 575 allocate(lat_inp(jdp))
576 lat_inp(1:jd)=lat_in(:)
579 allocate(lat_in(1:jdp))
589 z_edges_in(k)=0.5*(z_in(k-1)+z_in(k))
591 z_edges_in(kd+1)=2.0*z_in(kd) - z_in(kd-1)
593 call horiz_interp_init()
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)
600 lon_out(:,:) = g%geoLonT(:,:)*pi_180
601 lat_out(:,:) = g%geoLatT(:,:)*pi_180
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
609 max_depth = maxval(g%bathyT)
610 call mpp_max(max_depth)
612 if (z_edges_in(kd+1)<max_depth) z_edges_in(kd+1)=max_depth
619 roundoff = 3.0*epsilon(missing_value)
622 write(laynum,
'(I8)') k ; laynum = adjustl(laynum)
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))
632 last_row(:)=tr_in(:,jd); pole=0.0;npole=0.0
634 if (abs(tr_in(i,jd)-missing_value) .gt. abs(roundoff*missing_value))
then 635 pole = pole+last_row(i)
644 tr_inp(:,1:jd) = tr_in(:,:)
647 tr_inp(:,:) = tr_in(:,:)
653 call mpp_broadcast(tr_inp,id*jdp,root_pe())
654 call mpp_sync_self ()
660 if (abs(tr_inp(i,j)-missing_value) .gt. abs(roundoff*missing_value))
then 662 tr_inp(i,j) = tr_inp(i,j) * conversion
664 tr_inp(i,j)=missing_value
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)
679 call mystats(tr_inp,missing_value, is,ie,js,je,k,
'Tracer from file')
684 call horiz_interp(interp,tr_inp,tr_out(is:ie,js:je), missing_value=missing_value, new_missing_handle=.true.)
689 if (abs(tr_out(i,j)-missing_value) .lt. abs(roundoff*missing_value)) mask_out(i,j)=0.
693 fill = 0.0; good = 0.0
695 npoints = 0 ; varavg = 0.
698 if (mask_out(i,j) .lt. 1.0)
then 699 tr_out(i,j)=missing_value
702 npoints = npoints + 1
703 varavg = varavg + tr_out(i,j)
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
712 call mystats(tr_out,missing_value, is,ie,js,je,k,
'variable from horiz_interp()')
716 if (
PRESENT(homogenize))
then 718 call sum_across_pes(npoints)
719 call sum_across_pes(varavg)
721 varavg = varavg/
real(npoints)
730 tr_outf(:,:)=tr_out(:,:)
731 if (k==1) tr_prev(:,:)=tr_outf(:,:)
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()')
738 tr_z(:,:,k) = tr_outf(:,:)*g%mask2dT(:,:)
739 mask_z(:,:,k) = good2(:,:)+fill2(:,:)
741 tr_prev(:,:)=tr_z(:,:,k)
744 call hchksum(tr_prev,
'field after fill ',g%HI)
749 end subroutine horiz_interp_and_extrap_tracer
751 function tracer_z_init(tr_in,z_edges,e,nkml,nkbl,land_fill,wet,nlay,nlevs,debug,i_debug,j_debug)
result(tr)
775 real,
dimension(:,:,:),
intent(in) :: tr_in
777 real,
dimension(size(tr_in,3)+1),
intent(in) :: z_edges
779 integer,
intent(in) :: nlay
780 real,
dimension(size(tr_in,1),size(tr_in,2),nlay+1), &
782 integer,
intent(in) :: nkml
783 integer,
intent(in) :: nkbl
784 real,
intent(in) :: land_fill
785 real,
dimension(size(tr_in,1),size(tr_in,2)), &
787 real,
dimension(size(tr_in,1),size(tr_in,2)), &
788 optional,
intent(in) :: nlevs
789 logical,
intent(in),
optional :: debug
790 integer,
intent(in),
optional :: i_debug
791 integer,
intent(in),
optional :: j_debug
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
799 integer :: n,i,j,k,l,nx,ny,nz,nt,kz
800 integer :: k_top,k_bot,k_bot_prev,kk,kstart
802 real,
dimension(size(tr_in,3)) :: wt,z1,z2
803 logical :: debug_msg, debug_
805 nx =
size(tr_in,1); ny=
size(tr_in,2); nz =
size(tr_in,3)
807 nlevs_data =
size(tr_in,3)
808 if (
PRESENT(nlevs))
then 809 nlevs_data = anint(nlevs)
813 if (
PRESENT(debug))
then 825 if (nlevs_data(i,j) .eq. 0 .or. wet(i,j) .eq. 0.)
then 826 tr(i,j,:) = land_fill
831 tr_1d(k) = tr_in(i,j,k)
837 k_bot = 1 ; k_bot_prev = -1
839 if (e_1d(k+1) > z_edges(1))
then 841 elseif (e_1d(k) < z_edges(nlevs_data(i,j)+1))
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
848 print *,
'*** I will extrapolate below using the bottom-most valid values' 851 tr(i,j,k) = tr_1d(nlevs_data(i,j))
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)
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)
867 if (kz /= k_bot_prev)
then 869 if ((kz < nlevs_data(i,j)) .and. (kz > 1))
then 870 sl_tr = find_limited_slope(tr_1d, z_edges, kz)
873 if (kz > nlevs_data(i,j)) kz = nlevs_data(i,j)
875 tr(i,j,k) = wt(kz) * &
876 (tr_1d(kz) + 0.5*sl_tr*(z2(kz) + z1(kz)))
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
890 do kz=k_top+1,k_bot-1
891 tr(i,j,k) = tr(i,j,k) + wt(kz)*tr_1d(kz)
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)
902 if (k_bot > k_top)
then 906 if ((kz < nlevs_data(i,j)) .and. (kz > 1))
then 907 sl_tr = find_limited_slope(tr_1d, z_edges, kz)
913 tr(i,j,k) = tr(i,j,k) + wt(kz) * &
914 (tr_1d(kz) + 0.5*sl_tr*(z2(kz) + z1(kz)))
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)
934 if (e_1d(k)-e_1d(k+1) .le. epsln) tr(i,j,k)=tr(i,j,k-1)
942 end function tracer_z_init
945 function bisect_fast(a, x, lo, hi)
result(bi_r)
958 real,
dimension(:,:),
intent(in) :: a
959 real,
dimension(:),
intent(in) :: x
960 integer,
dimension(size(a,1)), &
961 intent(in),
optional :: lo,hi
962 integer,
dimension(size(a,1),size(x,1)) :: bi_r
964 integer :: mid,num_x,num_a,i
965 integer,
dimension(size(a,1)) :: lo_,hi_,lo0,hi0
968 lo_=1;hi_=
size(a,2);num_x=
size(x,1);bi_r=-1;nprofs=
size(a,1)
970 if (
PRESENT(lo))
then 973 if (
PRESENT(hi))
then 982 do while (lo_(j) < hi_(j))
983 mid = (lo_(j)+hi_(j))/2
984 if (x(i) < a(j,mid))
then 997 end function bisect_fast
1001 subroutine determine_temperature(temp,salt,R,p_ref,niter,land_fill,h,k_start)
1014 real(kind=8),
dimension(:,:,:),
intent(inout) :: temp
1015 real(kind=8),
dimension(:,:,:),
intent(inout) :: salt
1016 real(kind=8),
dimension(size(temp,3)),
intent(in) :: r
1018 real,
intent(in) :: p_ref
1019 integer,
intent(in) :: niter
1020 integer,
intent(in) :: k_start
1022 real,
intent(in) :: land_fill
1023 real(kind=8),
dimension(:,:,:),
intent(in) :: h
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
1030 integer :: nx,ny,nz,nt,i,j,k,n,itt
1031 logical :: adjust_salt , old_fit
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
1039 subroutine determine_temperature(temp,salt,R,p_ref,niter,land_fill,h,k_start,eos)
1054 real,
dimension(:,:,:),
intent(inout) :: temp
1055 real,
dimension(:,:,:),
intent(inout) :: salt
1056 real,
dimension(size(temp,3)),
intent(in) :: r
1057 real,
intent(in) :: p_ref
1058 integer,
intent(in) :: niter
1059 integer,
intent(in) :: k_start
1061 real,
intent(in) :: land_fill
1062 real,
dimension(:,:,:),
intent(in) :: h
1064 type(
eos_type),
pointer,
intent(in) :: eos
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
1070 integer :: nx,ny,nz,nt,i,j,k,n,itt
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
1087 nx=
size(temp,1);ny=
size(temp,2); nz=
size(temp,3)
1097 adjust_salt = .true.
1098 iter_loop:
do itt = 1,niter
1100 rho=wright_eos_2d(t,s,p_ref)
1101 drho_dt=alpha_wright_eos_2d(t,s,p_ref)
1105 call calculate_density_derivs(t(:,k),s(:,k),press,drho_dt(:,k),drho_ds(:,k),1,nx,eos)
1112 if (abs(rho(i,k)-r(k))>tol)
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)
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)
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)
1130 if (maxval(abs(dt)) < tol)
then 1131 adjust_salt = .false.
1136 if (adjust_salt .and. old_fit)
then 1137 iter_loop2:
do itt = 1,niter
1139 rho=wright_eos_2d(t,s,p_ref)
1140 drho_ds=beta_wright_eos_2d(t,s,p_ref)
1144 call calculate_density_derivs(t(:,k),s(:,k),press,drho_dt(:,k),drho_ds(:,k),1,nx,eos)
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)
1158 if (maxval(abs(ds)) < tol)
then 1171 end subroutine determine_temperature
1174 subroutine find_overlap(e, Z_top, Z_bot, k_max, k_start, k_top, k_bot, wt, z1, z2)
1195 real,
dimension(:),
intent(in) :: e
1196 real,
intent(in) :: z_top
1197 real,
intent(in) :: z_bot
1198 integer,
intent(in) :: k_max
1199 integer,
intent(in) :: k_start
1200 integer,
intent(out) :: k_top, k_bot
1202 real,
dimension(:),
intent(out) :: wt
1203 real,
dimension(:),
intent(out) :: z1, z2
1209 real :: ih, e_c, tot_wt, i_totwt
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
1215 do k=k_start,k_max ;
if (e(k+1)<z_top)
exit ;
enddo 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
1228 wt(k) = min(e(k),z_top) - e(k+1) ; tot_wt = wt(k)
1229 z1(k) = (0.5*(e(k)+e(k+1)) - min(e(k),z_top)) / (e(k)-e(k+1))
1233 if (e(k+1)<=z_bot)
then 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))
1238 wt(k) = e(k) - e(k+1) ; z1(k) = -0.5 ; z2(k) = 0.5
1240 tot_wt = tot_wt + wt(k)
1244 i_totwt = 1.0 / tot_wt
1245 do k=k_top,k_bot ; wt(k) = i_totwt*wt(k) ;
enddo 1250 end subroutine find_overlap
1253 function find_limited_slope(val, e, k)
result(slope)
1264 real,
dimension(:),
intent(in) :: val
1265 real,
dimension(:),
intent(in) :: e
1266 integer,
intent(in) :: k
1267 real :: slope,amx,bmx,amn,bmn,cmn,dmn
1271 if ((val(k)-val(k-1)) * (val(k)-val(k+1)) >= 0.0)
then 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))
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)))
1285 slope = sign(1.0,slope) * dmn
1295 end function find_limited_slope
1299 function find_interfaces(rho,zin,Rb,depth,nlevs,nkml,nkbl,hml,debug)
result(zi)
1309 real,
dimension(:,:,:),
intent(in) :: rho
1310 real,
dimension(size(rho,3)),
intent(in) :: zin
1311 real,
dimension(:),
intent(in) :: rb
1312 real,
dimension(size(rho,1),size(rho,2)), &
1314 real,
dimension(size(rho,1),size(rho,2)), &
1315 optional,
intent(in) :: nlevs
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
1319 integer,
intent(in),
optional :: nkbl
1320 real,
intent(in),
optional :: hml
1322 real,
dimension(size(rho,1),size(rho,3)) :: rho_
1323 real,
dimension(size(rho,1)) :: depth_
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.
1335 real,
parameter :: zoff=0.999
1342 if (
PRESENT(debug)) debug_=debug
1344 nx =
size(rho,1); ny=
size(rho,2); nz =
size(rho,3)
1345 nlevs_data(:,:) =
size(rho,3)
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
1352 if (
PRESENT(nlevs))
then 1353 nlevs_data(:,:) = nlevs(:,:)
1357 rho_(:,:) = rho(:,j,:)
1360 print *,
'looking for interfaces, i,j,nlevs= ',i,j,nlevs_data(i,j)
1361 print *,
'initial density profile= ', rho_(i,:)
1368 do k=2,nlevs_data(i,j)-1
1369 if (rho_(i,k) - rho_(i,k-1) < 0.0 )
then 1371 rho_(i,k-1)=rho_(i,k)-epsln
1373 drhodz = (rho_(i,k+1)-rho_(i,k-1))/(zin(k+1)-zin(k-1))
1374 if (drhodz < 0.0)
then 1377 rho_(i,k) = rho_(i,k-1)+drhodz*zoff*(zin(k)-zin(k-1))
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
1388 drhodz = (rho_(i,k+1)-rho_(i,k-1))/(zin(k+1)-zin(k-1))
1389 if (drhodz < 0.0)
then 1392 rho_(i,k) = rho_(i,k+1)-drhodz*(zin(k+1)-zin(k))
1400 print *,
'final density profile= ', rho_(i,:)
1406 depth_(:)=-1.0*depth(:,j)
1408 hi(:)=nlevs_data(:,j)
1409 ki_ = bisect_fast(rho_,rb,lo,hi)
1410 ki_(:,:) = max(1,ki_(:,:)-1)
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_)
1418 zi_(i,nlay+1)=depth_(i)
1420 zi_(i,l)=max(((1.0-
real(l))/
real(nkml_))*hml_,depth_(i))
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
1426 if (zi_(i,l)>-1.0*hml_)
then 1427 zi_(i,l)=max(-1.0*hml_,depth_(i))
1437 end function find_interfaces
1439 subroutine meshgrid(x,y,x_T,y_T)
1444 real,
dimension(:),
intent(in) :: x,y
1445 real,
dimension(size(x,1),size(y,1)),
intent(inout) :: x_t,y_t
1447 integer :: ni,nj,i,j
1449 ni=
size(x,1);nj=
size(y,1)
1461 end subroutine meshgrid
1463 subroutine smooth_heights(zi,fill,bad,sor,niter,cyclic_x, tripolar_n)
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
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
1488 ni=
size(zi,1); nj=
size(zi,2)
1491 mp=fill_boundaries(zi,cyclic_x,tripolar_n)
1494 nm=fill_boundaries(bad,cyclic_x,tripolar_n)
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)
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))
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)
1516 res(:,:)=res(:,:)*sor
1520 mp(i,j)=mp(i,j)+res(i,j)
1524 zi(:,:)=mp(1:ni,1:nj)
1525 mp = fill_boundaries(zi,cyclic_x,tripolar_n)
1532 end subroutine smooth_heights
1534 function fill_boundaries_int(m,cyclic_x,tripolar_n)
result(mp)
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
1546 mp_real = fill_boundaries_real(m_real,cyclic_x,tripolar_n)
1552 end function fill_boundaries_int
1554 function fill_boundaries_real(m,cyclic_x,tripolar_n)
result(mp)
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
1561 integer :: ni,nj,i,j
1563 ni=
size(m,1); nj=
size(m,2)
1565 mp(1:ni,1:nj)=m(:,:)
1568 mp(0,1:nj)=m(ni,1:nj)
1569 mp(ni+1,1:nj)=m(1,1:nj)
1571 mp(0,1:nj)=m(1,1:nj)
1572 mp(ni+1,1:nj)=m(ni,1:nj)
1575 mp(1:ni,0)=m(1:ni,1)
1576 if (tripolar_n)
then 1578 mp(i,nj+1)=m(ni-i+1,nj)
1581 mp(1:ni,nj+1)=m(1:ni,nj)
1586 end function fill_boundaries_real
1590 end module mom_tracer_initialization_from_z
subroutine, public read_axis_data(filename, axis_name, var)
This module contains the main regridding routines. Regridding comprises two steps: (1) Interpolation ...
logical function, public ispointincell(G, i, j, x, y)
Returns true if the coordinates (x,y) are within the h-cell (i,j)
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...
integer, parameter, public to_all
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Provides the ocean grid type.
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.
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.
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.
Type for describing a variable, typically a tracer.
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...
subroutine, public mom_error(level, message, all_print)
A control structure for the equation of state.
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.