86 implicit none ;
private 88 #include <MOM_memory.h> 94 real,
dimension(:,:,:),
pointer :: p => null()
97 real,
dimension(:,:),
pointer :: p => null()
101 logical :: bulkmixedlayer
104 integer :: isc, iec, jsc, jec
105 integer :: isd, ied, jsd, jed
110 integer,
pointer :: col_i(:) => null()
111 integer,
pointer :: col_j(:) => null()
112 real,
pointer :: iresttime_col(:) => null()
114 real,
pointer :: rcv_ml_ref(:) => null()
116 real,
pointer :: ref_eta(:,:) => null()
118 type(
p3d) :: var(max_fields_)
119 type(
p2d) :: ref_val(max_fields_)
121 logical :: do_i_mean_sponge
122 real,
pointer :: iresttime_im(:) => null()
124 real,
pointer :: rcv_ml_ref_im(:) => null()
127 real,
pointer :: ref_eta_im(:,:) => null()
129 type(
p2d) :: ref_val_im(max_fields_)
134 integer :: id_w_sponge = -1
141 Iresttime_i_mean, int_height_i_mean)
143 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: Iresttime
144 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: int_height
147 real,
dimension(SZJ_(G)),
optional,
intent(in) :: Iresttime_i_mean
148 real,
dimension(SZJ_(G),SZK_(G)+1),
optional,
intent(in) :: int_height_i_mean
164 #include "version_variable.h" 165 character(len=40) :: mdl =
"MOM_sponge" 166 logical :: use_sponge
167 integer :: i, j, k, col, total_sponge_cols
169 if (
associated(cs))
then 170 call mom_error(warning,
"initialize_sponge called with an associated "// &
171 "control structure.")
177 call get_param(param_file, mdl,
"SPONGE", use_sponge, &
178 "If true, sponges may be applied anywhere in the domain. \n"//&
179 "The exact location and properties of those sponges are \n"//&
180 "specified from MOM_initialization.F90.", default=.false.)
182 if (.not.use_sponge)
return 185 if (
present(iresttime_i_mean) .neqv.
present(int_height_i_mean)) &
186 call mom_error(fatal,
"initialize_sponge: The optional arguments \n"//&
187 "Iresttime_i_mean and int_height_i_mean must both be present \n"//&
190 cs%do_i_mean_sponge =
present(iresttime_i_mean)
193 cs%isc = g%isc ; cs%iec = g%iec ; cs%jsc = g%jsc ; cs%jec = g%jec
194 cs%isd = g%isd ; cs%ied = g%ied ; cs%jsd = g%jsd ; cs%jed = g%jed
196 cs%bulkmixedlayer = .false.
198 cs%num_col = 0 ; cs%fldno = 0
199 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
200 if ((iresttime(i,j)>0.0) .and. (g%mask2dT(i,j)>0)) &
201 cs%num_col = cs%num_col + 1
204 if (cs%num_col > 0)
then 206 allocate(cs%Iresttime_col(cs%num_col)) ; cs%Iresttime_col = 0.0
207 allocate(cs%col_i(cs%num_col)) ; cs%col_i = 0
208 allocate(cs%col_j(cs%num_col)) ; cs%col_j = 0
211 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
212 if ((iresttime(i,j)>0.0) .and. (g%mask2dT(i,j)>0))
then 213 cs%col_i(col) = i ; cs%col_j(col) = j
214 cs%Iresttime_col(col) = iresttime(i,j)
219 allocate(cs%Ref_eta(cs%nz+1,cs%num_col))
220 do col=1,cs%num_col ;
do k=1,cs%nz+1
221 cs%Ref_eta(k,col) = int_height(cs%col_i(col),cs%col_j(col),k)
226 if (cs%do_i_mean_sponge)
then 227 allocate(cs%Iresttime_im(g%jsd:g%jed)) ; cs%Iresttime_im(:) = 0.0
228 allocate(cs%Ref_eta_im(g%jsd:g%jed,g%ke+1)) ; cs%Ref_eta_im(:,:) = 0.0
231 cs%Iresttime_im(j) = iresttime_i_mean(j)
233 do k=1,cs%nz+1 ;
do j=g%jsc,g%jec
234 cs%Ref_eta_im(j,k) = int_height_i_mean(j,k)
238 total_sponge_cols = cs%num_col
239 call sum_across_pes(total_sponge_cols)
241 call log_param(param_file, mdl,
"!Total sponge columns", total_sponge_cols, &
242 "The total number of columns where sponges are applied.")
247 type(time_type),
target,
intent(in) :: Time
249 type(
diag_ctrl),
target,
intent(inout) :: diag
262 if (.not.
associated(cs))
return 265 cs%id_w_sponge = register_diag_field(
'ocean_model',
'w_sponge', diag%axesTi, &
266 time,
'The diapycnal motion due to the sponges',
'meter second-1')
272 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: sp_val
273 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
target,
intent(in) :: f_ptr
274 integer,
intent(in) :: nlay
276 real,
dimension(SZJ_(G),SZK_(G)),
optional,
intent(in) :: sp_val_i_mean
291 character(len=256) :: mesg
293 if (.not.
associated(cs))
return 295 cs%fldno = cs%fldno + 1
297 if (cs%fldno > max_fields_)
then 298 write(mesg,
'("Increase MAX_FIELDS_ to at least ",I3," in MOM_memory.h or decrease & 299 &the number of fields to be damped in the call to & 300 &initialize_sponge." )') cs%fldno
301 call mom_error(fatal,
"set_up_sponge_field: "//mesg)
304 allocate(cs%Ref_val(cs%fldno)%p(cs%nz,cs%num_col))
305 cs%Ref_val(cs%fldno)%p(:,:) = 0.0
308 cs%Ref_val(cs%fldno)%p(k,col) = sp_val(cs%col_i(col),cs%col_j(col),k)
311 cs%Ref_val(cs%fldno)%p(k,col) = 0.0
315 cs%var(cs%fldno)%p => f_ptr
317 if (nlay/=cs%nz)
then 318 write(mesg,
'("Danger: Sponge reference fields require nz (",I3,") layers.& 319 & A field with ",I3," layers was passed to set_up_sponge_field.")') &
324 if (cs%do_i_mean_sponge)
then 325 if (.not.
present(sp_val_i_mean))
call mom_error(fatal, &
326 "set_up_sponge_field: sp_val_i_mean must be present with i-mean sponges.")
328 allocate(cs%Ref_val_im(cs%fldno)%p(cs%jsd:cs%jed,cs%nz))
329 cs%Ref_val(cs%fldno)%p(:,:) = 0.0
330 do k=1,cs%nz ;
do j=cs%jsc,cs%jec
331 cs%Ref_val_im(cs%fldno)%p(j,k) = sp_val_i_mean(j,k)
340 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: sp_val
342 real,
dimension(SZJ_(G)),
optional,
intent(in) :: sp_val_i_mean
352 character(len=256) :: mesg
354 if (.not.
associated(cs))
return 356 if (
associated(cs%Rcv_ml_ref))
then 357 call mom_error(fatal,
"set_up_sponge_ML_density appears to have been "//&
361 cs%bulkmixedlayer = .true.
362 allocate(cs%Rcv_ml_ref(cs%num_col)) ; cs%Rcv_ml_ref(:) = 0.0
364 cs%Rcv_ml_ref(col) = sp_val(cs%col_i(col),cs%col_j(col))
367 if (cs%do_i_mean_sponge)
then 368 if (.not.
present(sp_val_i_mean))
call mom_error(fatal, &
369 "set_up_sponge_field: sp_val_i_mean must be present with i-mean sponges.")
371 allocate(cs%Rcv_ml_ref_im(cs%jsd:cs%jed)) ; cs%Rcv_ml_ref_im(:) = 0.0
373 cs%Rcv_ml_ref_im(j) = sp_val_i_mean(j)
379 subroutine apply_sponge(h, dt, G, GV, ea, eb, CS, Rcv_ml)
382 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h
383 real,
intent(in) :: dt
384 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(out) :: ea
385 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(out) :: eb
387 real,
dimension(SZI_(G),SZJ_(G)),
optional,
intent(inout) :: Rcv_ml
407 real,
dimension(SZI_(G), SZJ_(G), SZK_(G)+1) :: &
412 real,
dimension(SZI_(G), SZJ_(G)) :: &
417 real,
dimension(SZJ_(G), SZK_(G)+1) :: &
419 real,
allocatable,
dimension(:,:,:) :: &
421 real,
dimension(SZI_(G), SZK_(G)+1) :: &
424 real,
dimension(SZI_(G)) :: &
443 integer :: c, m, nkmb, i, j, k, is, ie, js, je, nz
444 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
446 if (.not.
associated(cs))
return 447 if (cs%bulkmixedlayer) nkmb = gv%nk_rho_varies
448 if (cs%bulkmixedlayer .and. (.not.
present(rcv_ml))) &
449 call mom_error(fatal,
"Rml must be provided to apply_sponge when using "//&
450 "a bulk mixed layer.")
452 if ((cs%id_w_sponge > 0) .or. cs%do_i_mean_sponge)
then 453 do k=1,nz+1 ;
do j=js,je ;
do i=is,ie
455 enddo ;
enddo ;
enddo 458 if (cs%do_i_mean_sponge)
then 461 if (cs%bulkmixedlayer)
call mom_error(fatal,
"apply_sponge is not yet set up to "//&
462 "work properly with i-mean sponges and a bulk mixed layer.")
464 do j=js,je ;
do i=is,ie ; e_d(i,j,nz+1) = -g%bathyT(i,j) ;
enddo ;
enddo 465 do k=nz,1,-1 ;
do j=js,je ;
do i=is,ie
466 e_d(i,j,k) = e_d(i,j,k+1) + h(i,j,k)
467 enddo ;
enddo ;
enddo 470 dilate(i) = g%bathyT(i,j) / (e_d(i,j,1) + g%bathyT(i,j))
472 do k=1,nz+1 ;
do i=is,ie
473 e_d(i,j,k) = dilate(i) * (e_d(i,j,k) + g%bathyT(i,j)) - g%bathyT(i,j)
478 do j=js,je ;
do i=is,ie
479 eta_anom(i,j) = e_d(i,j,k) - cs%Ref_eta_im(j,k)
480 if (cs%Ref_eta_im(j,k) < -g%bathyT(i,j)) eta_anom(i,j) = 0.0
485 if (cs%fldno > 0)
allocate(fld_mean_anom(g%isd:g%ied,nz,cs%fldno))
487 do j=js,je ;
do i=is,ie
488 fld_anom(i,j) = cs%var(m)%p(i,j,k) - cs%Ref_val_im(m)%p(j,k)
490 call global_i_mean(fld_anom(:,:), fld_mean_anom(:,k,m), g, h(:,:,k))
493 do j=js,je ;
if (cs%Iresttime_im(j) > 0.0)
then 494 damp = dt*cs%Iresttime_im(j) ; damp_1pdamp = damp / (1.0 + damp)
497 h_above(i,1) = 0.0 ; h_below(i,nz+1) = 0.0
499 do k=nz,1,-1 ;
do i=is,ie
500 h_below(i,k) = h_below(i,k+1) + max(h(i,j,k)-gv%Angstrom, 0.0)
502 do k=2,nz+1 ;
do i=is,ie
503 h_above(i,k) = h_above(i,k-1) + max(h(i,j,k-1)-gv%Angstrom, 0.0)
508 w = damp_1pdamp * eta_mean_anom(j,k)
511 w_int(i,j,k) = min(w, h_below(i,k))
512 eb(i,j,k-1) = eb(i,j,k-1) + w_int(i,j,k)
514 w_int(i,j,k) = max(w, -h_above(i,k))
515 ea(i,j,k) = ea(i,j,k) - w_int(i,j,k)
519 do k=1,nz ;
do i=is,ie
520 ea_k = max(0.0, -w_int(i,j,k))
521 eb_k = max(0.0, w_int(i,j,k+1))
523 cs%var(m)%p(i,j,k) = (h(i,j,k)*cs%var(m)%p(i,j,k) + &
524 cs%Ref_val_im(m)%p(j,k) * (ea_k + eb_k)) / &
525 (h(i,j,k) + (ea_k + eb_k)) - &
526 damp_1pdamp * fld_mean_anom(j,k,m)
529 h(i,j,k) = max(h(i,j,k) + (w_int(i,j,k+1) - w_int(i,j,k)), &
530 min(h(i,j,k), gv%Angstrom))
534 if (cs%fldno > 0)
deallocate(fld_mean_anom)
541 i = cs%col_i(c) ; j = cs%col_j(c)
542 damp = dt*cs%Iresttime_col(c)
544 e(1) = 0.0 ; e0 = 0.0
546 e(k+1) = e(k) - h(i,j,k)
548 e_str = e(nz+1) / cs%Ref_eta(nz+1,c)
550 if ( cs%bulkmixedlayer )
then 551 i1pdamp = 1.0 / (1.0 + damp)
552 if (
associated(cs%Rcv_ml_ref)) &
553 rcv_ml(i,j) = i1pdamp * (rcv_ml(i,j) + cs%Rcv_ml_ref(c)*damp)
556 cs%var(m)%p(i,j,k) = i1pdamp * &
557 (cs%var(m)%p(i,j,k) + cs%Ref_val(m)%p(k,c)*damp)
563 if (gv%Rlay(k) > rcv_ml(i,j))
then 564 w = min((((e(k)-e0) - e_str*cs%Ref_eta(k,c)) * damp), &
565 ((wb + h(i,j,k)) - gv%Angstrom))
568 cs%var(m)%p(i,j,k) = (h(i,j,k)*cs%var(m)%p(i,j,k) + &
569 cs%Ref_val(m)%p(k,c)*(damp*h(i,j,k) + (wpb - wm))) / &
570 (h(i,j,k)*(1.0 + damp) + (wpb - wm))
574 cs%var(m)%p(i,j,k) = i1pdamp * &
575 (cs%var(m)%p(i,j,k) + cs%Ref_val(m)%p(k,c)*damp)
577 w = wb + (h(i,j,k) - gv%Angstrom)
580 eb(i,j,k) = eb(i,j,k) + wpb
581 ea(i,j,k) = ea(i,j,k) - wm
582 h(i,j,k) = h(i,j,k) + (wb - w)
589 w = min((wb + (h(i,j,k) - gv%Angstrom)),0.0)
590 h(i,j,k) = h(i,j,k) + (wb - w)
591 ea(i,j,k) = ea(i,j,k) - w
597 eb(i,j,k) = eb(i,j,k) + w
601 h(i,j,k) = h(i,j,k) + w
603 cs%var(m)%p(i,j,k) = (cs%var(m)%p(i,j,k)*h(i,j,k) + &
604 cs%Ref_val(m)%p(k,c)*w) / (h(i,j,k) + w)
610 cs%var(m)%p(i,j,k) = i1pdamp * &
611 (cs%var(m)%p(i,j,k) + cs%Ref_val(m)%p(gv%nkml,c)*damp)
620 w = min((((e(k)-e0) - e_str*cs%Ref_eta(k,c)) * damp), &
621 ((wb + h(i,j,k)) - gv%Angstrom))
622 wm = 0.5*(w - abs(w))
624 cs%var(m)%p(i,j,k) = (h(i,j,k)*cs%var(m)%p(i,j,k) + &
625 cs%Ref_val(m)%p(k,c) * (damp*h(i,j,k) + (wpb - wm))) / &
626 (h(i,j,k)*(1.0 + damp) + (wpb - wm))
628 eb(i,j,k) = eb(i,j,k) + wpb
629 ea(i,j,k) = ea(i,j,k) - wm
630 h(i,j,k) = h(i,j,k) + (wb - w)
638 if (
associated(cs%diag))
then ;
if (query_averaging_enabled(cs%diag))
then 640 if (cs%id_w_sponge > 0)
call post_data(cs%id_w_sponge, idt*w_int, cs%diag)
651 if (.not.
associated(cs))
return 653 if (
associated(cs%col_i))
deallocate(cs%col_i)
654 if (
associated(cs%col_j))
deallocate(cs%col_j)
656 if (
associated(cs%Iresttime_col))
deallocate(cs%Iresttime_col)
657 if (
associated(cs%Rcv_ml_ref))
deallocate(cs%Rcv_ml_ref)
658 if (
associated(cs%Ref_eta))
deallocate(cs%Ref_eta)
660 if (
associated(cs%Iresttime_im))
deallocate(cs%Iresttime_im)
661 if (
associated(cs%Rcv_ml_ref_im))
deallocate(cs%Rcv_ml_ref_im)
662 if (
associated(cs%Ref_eta_im))
deallocate(cs%Ref_eta_im)
665 if (
associated(cs%Ref_val(cs%fldno)%p))
deallocate(cs%Ref_val(cs%fldno)%p)
666 if (
associated(cs%Ref_val_im(cs%fldno)%p)) &
667 deallocate(cs%Ref_val_im(cs%fldno)%p)
Ocean grid type. See mom_grid for details.
Provides the ocean grid type.
subroutine, public sponge_end(CS)
subroutine, public init_sponge_diags(Time, G, diag, CS)
subroutine, public initialize_sponge(Iresttime, int_height, G, param_file, CS, Iresttime_i_mean, int_height_i_mean)
subroutine, public set_up_sponge_field(sp_val, f_ptr, G, nlay, CS, sp_val_i_mean)
subroutine, public global_i_mean(array, i_mean, G, mask)
logical function, public is_root_pe()
subroutine, public apply_sponge(h, dt, G, GV, ea, eb, CS, Rcv_ml)
subroutine, public set_up_sponge_ml_density(sp_val, G, CS, sp_val_i_mean)
subroutine, public mom_error(level, message, all_print)