24 implicit none ;
private 26 #include <MOM_memory.h> 28 public wave_structure, wave_structure_init
39 real,
allocatable,
dimension(:,:,:) :: w_strct
41 real,
allocatable,
dimension(:,:,:) :: u_strct
43 real,
allocatable,
dimension(:,:,:) :: w_profile
47 real,
allocatable,
dimension(:,:,:) :: uavg_profile
50 real,
allocatable,
dimension(:,:,:) :: z_depths
52 real,
allocatable,
dimension(:,:,:) :: n2
54 integer,
allocatable,
dimension(:,:):: num_intfaces
56 real :: int_tide_source_x
58 real :: int_tide_source_y
91 subroutine wave_structure(h, tv, G, GV, US, cn, ModeNum, freq, CS, En, full_halos)
95 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
98 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: cn
100 integer,
intent(in) :: modenum
101 real,
intent(in) :: freq
104 real,
dimension(SZI_(G),SZJ_(G)), &
105 optional,
intent(in) :: en
106 logical,
optional,
intent(in) :: full_halos
109 real,
dimension(SZK_(G)+1) :: &
116 real,
dimension(SZK_(G)) :: &
119 real,
dimension(SZK_(G),SZI_(G)) :: &
124 real,
dimension(SZK_(G)) :: &
130 real,
dimension(SZI_(G),SZJ_(G)) :: &
135 real,
dimension(SZI_(G)) :: &
144 real,
parameter :: tol1 = 0.0001, tol2 = 0.001
145 real,
pointer,
dimension(:,:,:) :: t => null(), s => null()
148 integer :: kf(szi_(g))
149 integer,
parameter :: max_itt = 1
151 real,
parameter :: a_int = 0.5
157 real,
dimension(SZK_(G)+1) :: w_strct, u_strct, w_profile, uavg_profile, z_int, n2
160 real,
dimension(SZK_(G)+1) :: w_strct2, u_strct2
162 real,
dimension(SZK_(G)) :: dz
172 real,
dimension(SZK_(G)-1) :: lam_z
174 real,
dimension(SZK_(G)-1) :: a_diag, b_diag, c_diag
177 real,
dimension(SZK_(G)-1) :: e_guess
178 real,
dimension(SZK_(G)-1) :: e_itt
181 integer :: i, j, k, k2, itt, is, ie, js, je, nz, nzm, row, ig, jg, ig_stop, jg_stop
183 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
187 if (.not.
associated(cs))
call mom_error(fatal,
"MOM_wave_structure: "// &
188 "Module must be initialized before it is used.")
191 if (
present(full_halos))
then ;
if (full_halos)
then 192 is = g%isd ; ie = g%ied ; js = g%jsd ; je = g%jed
197 s => tv%S ; t => tv%T
198 g_rho0 = us%L_T_to_m_s**2 * gv%g_Earth / gv%Rho0
199 cg_subro = 1e-100*us%m_s_to_L_T
200 use_eos =
associated(tv%eqn_of_state)
203 z_to_pres = gv%Z_to_H * (gv%H_to_RZ * gv%g_Earth)
206 min_h_frac = tol1 / real(nz)
212 do i=is,ie ; htot(i,j) = 0.0 ;
enddo 213 do k=1,nz ;
do i=is,ie ; htot(i,j) = htot(i,j) + h(i,j,k)*gv%H_to_Z ;
enddo ;
enddo 216 hmin(i) = htot(i,j)*min_h_frac ; kf(i) = 1 ; h_here(i) = 0.0
217 hxt_here(i) = 0.0 ; hxs_here(i) = 0.0 ; hxr_here(i) = 0.0
220 do k=1,nz ;
do i=is,ie
221 if ((h_here(i) > hmin(i)) .and. (h(i,j,k)*gv%H_to_Z > hmin(i)))
then 222 hf(kf(i),i) = h_here(i)
223 tf(kf(i),i) = hxt_here(i) / h_here(i)
224 sf(kf(i),i) = hxs_here(i) / h_here(i)
228 h_here(i) = h(i,j,k)*gv%H_to_Z
229 hxt_here(i) = (h(i,j,k)*gv%H_to_Z)*t(i,j,k)
230 hxs_here(i) = (h(i,j,k)*gv%H_to_Z)*s(i,j,k)
232 h_here(i) = h_here(i) + h(i,j,k)*gv%H_to_Z
233 hxt_here(i) = hxt_here(i) + (h(i,j,k)*gv%H_to_Z)*t(i,j,k)
234 hxs_here(i) = hxs_here(i) + (h(i,j,k)*gv%H_to_Z)*s(i,j,k)
237 do i=is,ie ;
if (h_here(i) > 0.0)
then 238 hf(kf(i),i) = h_here(i)
239 tf(kf(i),i) = hxt_here(i) / h_here(i)
240 sf(kf(i),i) = hxs_here(i) / h_here(i)
243 do k=1,nz ;
do i=is,ie
244 if ((h_here(i) > hmin(i)) .and. (h(i,j,k)*gv%H_to_Z > hmin(i)))
then 245 hf(kf(i),i) = h_here(i) ; rf(kf(i),i) = hxr_here(i) / h_here(i)
249 h_here(i) = h(i,j,k)*gv%H_to_Z
250 hxr_here(i) = (h(i,j,k)*gv%H_to_Z)*gv%Rlay(k)
252 h_here(i) = h_here(i) + h(i,j,k)*gv%H_to_Z
253 hxr_here(i) = hxr_here(i) + (h(i,j,k)*gv%H_to_Z)*gv%Rlay(k)
256 do i=is,ie ;
if (h_here(i) > 0.0)
then 257 hf(kf(i),i) = h_here(i) ; rf(kf(i),i) = hxr_here(i) / h_here(i)
263 do i=is,ie ;
if (cn(i,j)>0.0)
then 265 ig = i + g%idg_offset ; jg = j + g%jdg_offset
268 if (g%mask2dT(i,j) > 0.5)
then 270 lam = 1/(us%L_T_to_m_s**2 * cn(i,j)**2)
276 pres(k) = pres(k-1) + z_to_pres*hf(k-1,i)
277 t_int(k) = 0.5*(tf(k,i)+tf(k-1,i))
278 s_int(k) = 0.5*(sf(k,i)+sf(k-1,i))
281 tv%eqn_of_state, (/2,kf(i)/) )
287 drxh_sum = drxh_sum + 0.5*(hf(k-1,i)+hf(k,i)) * &
288 max(0.0,drho_dt(k)*(tf(k,i)-tf(k-1,i)) + &
289 drho_ds(k)*(sf(k,i)-sf(k-1,i)))
294 drxh_sum = drxh_sum + 0.5*(hf(k-1,i)+hf(k,i)) * &
295 max(0.0,rf(k,i)-rf(k-1,i))
301 if (drxh_sum >= 0.0)
then 306 hc(1) = hf(1,i) ; tc(1) = tf(1,i) ; sc(1) = sf(1,i)
308 if ((drho_dt(k)*(tf(k,i)-tc(kc)) + drho_ds(k)*(sf(k,i)-sc(kc))) * &
309 (hc(kc) + hf(k,i)) < 2.0 * tol2*drxh_sum)
then 311 i_hnew = 1.0 / (hc(kc) + hf(k,i))
312 tc(kc) = (hc(kc)*tc(kc) + hf(k,i)*tf(k,i)) * i_hnew
313 sc(kc) = (hc(kc)*sc(kc) + hf(k,i)*sf(k,i)) * i_hnew
314 hc(kc) = (hc(kc) + hf(k,i))
319 if ((drho_dt(k2)*(tc(k2)-tc(k2-1)) + drho_ds(k2)*(sc(k2)-sc(k2-1))) * &
320 (hc(k2) + hc(k2-1)) < tol2*drxh_sum)
then 322 i_hnew = 1.0 / (hc(kc) + hc(kc-1))
323 tc(kc-1) = (hc(kc)*tc(kc) + hc(kc-1)*tc(kc-1)) * i_hnew
324 sc(kc-1) = (hc(kc)*sc(kc) + hc(kc-1)*sc(kc-1)) * i_hnew
325 hc(kc-1) = (hc(kc) + hc(kc-1))
332 drho_ds(kc) = drho_ds(k) ; drho_dt(kc) = drho_dt(k)
333 tc(kc) = tf(k,i) ; sc(kc) = sf(k,i) ; hc(kc) = hf(k,i)
338 gprime(k) = g_rho0 * (drho_dt(k)*(tc(k)-tc(k-1)) + &
339 drho_ds(k)*(sc(k)-sc(k-1)))
344 hc(1) = hf(1,i) ; rc(1) = rf(1,i)
346 if ((rf(k,i) - rc(kc)) * (hc(kc) + hf(k,i)) < 2.0*tol2*drxh_sum)
then 348 rc(kc) = (hc(kc)*rc(kc) + hf(k,i)*rf(k,i)) / (hc(kc) + hf(k,i))
349 hc(kc) = (hc(kc) + hf(k,i))
354 if ((rc(k2)-rc(k2-1)) * (hc(k2)+hc(k2-1)) < tol2*drxh_sum)
then 356 rc(kc-1) = (hc(kc)*rc(kc) + hc(kc-1)*rc(kc-1)) / (hc(kc) + hc(kc-1))
357 hc(kc-1) = (hc(kc) + hc(kc-1))
364 rc(kc) = rf(k,i) ; hc(kc) = hf(k,i)
369 gprime(k) = g_rho0 * (rc(k)-rc(k-1))
381 if (kc >= max(3, modenum + 1))
then 387 igl(k) = 1.0/(gprime(k)*hc(k)) ; igu(k) = 1.0/(gprime(k)*hc(k-1))
388 z_int(k) = z_int(k-1) + hc(k-1)
389 n2(k) = us%m_to_Z**2*gprime(k)/(0.5*(hc(k)+hc(k-1)))
392 n2(1) = n2(2) ; n2(kc+1) = n2(kc)
394 z_int(kc+1) = z_int(kc)+hc(kc)
396 if (abs(z_int(kc+1)-htot(i,j)) > 1.e-14*htot(i,j))
then 397 call mom_error(fatal,
"wave_structure: mismatch in total depths")
410 gp_unscaled = us%m_to_Z*gprime(k)
411 lam_z(row) = lam*gp_unscaled
412 a_diag(row) = gp_unscaled*(-igu(k))
413 b_diag(row) = gp_unscaled*(igu(k)+igl(k)) - lam_z(row)
414 c_diag(row) = gp_unscaled*(-igl(k))
415 if (isnan(lam_z(row)))
then ; print *,
"Wave_structure: lam_z(row) is NAN" ;
endif 416 if (isnan(a_diag(row)))
then ; print *,
"Wave_structure: a(k) is NAN" ;
endif 417 if (isnan(b_diag(row)))
then ; print *,
"Wave_structure: b(k) is NAN" ;
endif 418 if (isnan(c_diag(row)))
then ; print *,
"Wave_structure: c(k) is NAN" ;
endif 422 gp_unscaled = us%m_to_Z*gprime(k)
423 lam_z(row) = lam*gp_unscaled
425 b_diag(row) = gp_unscaled*(igu(k)+igl(k)) - lam_z(row)
426 c_diag(row) = gp_unscaled*(-igl(k))
429 gp_unscaled = us%m_to_Z*gprime(k)
430 lam_z(row) = lam*gp_unscaled
431 a_diag(row) = gp_unscaled*(-igu(k))
432 b_diag(row) = gp_unscaled*(igu(k)+igl(k)) - lam_z(row)
436 e_guess(1:kc-1) = sin((z_int(2:kc)/htot(i,j)) *pi)
437 e_guess(1:kc-1) = e_guess(1:kc-1)/sqrt(sum(e_guess(1:kc-1)**2))
441 call tridiag_solver(a_diag(1:kc-1),b_diag(1:kc-1),c_diag(1:kc-1), &
442 -lam_z(1:kc-1),e_guess(1:kc-1),
"TDMA_H",e_itt)
443 e_guess(1:kc-1) = e_itt(1:kc-1) / sqrt(sum(e_itt(1:kc-1)**2))
445 w_strct(2:kc) = e_guess(1:kc-1)
450 ig_stop = 0 ; jg_stop = 0
451 if (isnan(sum(w_strct(1:kc+1))))
then 452 print *,
"Wave_structure: w_strct has a NAN at ig=", ig,
", jg=", jg
453 if (i<g%isc .or. i>g%iec .or. j<g%jsc .or. j>g%jec)
then 454 print *,
"This is occuring at a halo point." 456 ig_stop = ig ; jg_stop = jg
465 dz(k) = us%Z_to_m*hc(k)
466 w2avg = w2avg + 0.5*(w_strct(k)**2+w_strct(k+1)**2)*dz(k)
469 w2avg = w2avg / htot(i,j)
470 w_strct(:) = w_strct(:) / sqrt(htot(i,j)*w2avg*i_a_int)
474 u_strct(k) = 0.5*((w_strct(k-1) - w_strct(k) )/dz(k-1) + &
475 (w_strct(k) - w_strct(k+1))/dz(k))
477 u_strct(1) = (w_strct(1) - w_strct(2) )/dz(1)
478 u_strct(nzm) = (w_strct(nzm-1)- w_strct(nzm))/dz(nzm-1)
481 f2 = g%CoriolisBu(i,j)**2
484 kmag2 = us%m_to_L**2 * (freq**2 - f2) / (cn(i,j)**2 + cg_subro**2)
487 int_dwdz2 = 0.0 ; int_w2 = 0.0 ; int_n2w2 = 0.0
488 u_strct2(1:nzm) = u_strct(1:nzm)**2
489 w_strct2(1:nzm) = w_strct(1:nzm)**2
492 int_dwdz2 = int_dwdz2 + 0.5*(u_strct2(k)+u_strct2(k+1)) * us%m_to_Z*dz(k)
493 int_w2 = int_w2 + 0.5*(w_strct2(k)+w_strct2(k+1)) * us%m_to_Z*dz(k)
494 int_n2w2 = int_n2w2 + 0.5*(w_strct2(k)*n2(k)+w_strct2(k+1)*n2(k+1)) * us%m_to_Z*dz(k)
498 if (
present(en) .and. (freq**2*kmag2 > 0.0))
then 500 ke_term = 0.25*gv%Rho0*( ((freq**2 + f2) / (freq**2*kmag2))*int_dwdz2 + int_w2 )
501 pe_term = 0.25*gv%Rho0*( int_n2w2 / (us%s_to_T*freq)**2 )
502 if (en(i,j) >= 0.0)
then 503 w0 = sqrt( en(i,j) / (ke_term + pe_term) )
505 call mom_error(warning,
"wave_structure: En < 0.0; setting to W0 to 0.0")
506 print *,
"En(i,j)=", en(i,j),
" at ig=", ig,
", jg=", jg
510 w_profile(:) = w0*w_strct(:)
513 uavg_profile(:) = us%Z_to_L*abs(w0*u_strct(:)) * sqrt((freq**2 + f2) / (2.0*freq**2*kmag2))
517 uavg_profile(:) = 0.0
521 cs%w_strct(i,j,1:nzm) = w_strct(1:nzm)
522 cs%u_strct(i,j,1:nzm) = u_strct(1:nzm)
523 cs%W_profile(i,j,1:nzm) = w_profile(1:nzm)
524 cs%Uavg_profile(i,j,1:nzm)= uavg_profile(1:nzm)
525 cs%z_depths(i,j,1:nzm) = us%Z_to_m*z_int(1:nzm)
526 cs%N2(i,j,1:nzm) = n2(1:nzm)
527 cs%num_intfaces(i,j) = nzm
531 cs%w_strct(i,j,1:nzm) = 0.0
532 cs%u_strct(i,j,1:nzm) = 0.0
533 cs%W_profile(i,j,1:nzm) = 0.0
534 cs%Uavg_profile(i,j,1:nzm)= 0.0
535 cs%z_depths(i,j,1:nzm) = 0.0
536 cs%N2(i,j,1:nzm) = 0.0
537 cs%num_intfaces(i,j) = nzm
547 cs%w_strct(i,j,1:nzm) = 0.0
548 cs%u_strct(i,j,1:nzm) = 0.0
549 cs%W_profile(i,j,1:nzm) = 0.0
550 cs%Uavg_profile(i,j,1:nzm)= 0.0
551 cs%z_depths(i,j,1:nzm) = 0.0
552 cs%N2(i,j,1:nzm) = 0.0
553 cs%num_intfaces(i,j) = nzm
557 end subroutine wave_structure
562 subroutine tridiag_solver(a, b, c, h, y, method, x)
563 real,
dimension(:),
intent(in) :: a
564 real,
dimension(:),
intent(in) :: b
565 real,
dimension(:),
intent(in) :: c
566 real,
dimension(:),
intent(in) :: h
573 real,
dimension(:),
intent(in) :: y
574 character(len=*),
intent(in) :: method
575 real,
dimension(:),
intent(out) :: x
580 real,
allocatable,
dimension(:) :: c_prime, y_prime, q, alpha
582 real :: Q_prime, beta
587 allocate(c_prime(nrow))
588 allocate(y_prime(nrow))
590 allocate(alpha(nrow))
594 if (method ==
'TDMA_T')
then 597 c_prime(:) = 0.0 ; y_prime(:) = 0.0
598 c_prime(1) = c(1)/b(1) ; y_prime(1) = y(1)/b(1)
602 c_prime(k) = c(k)/(b(k)-a(k)*c_prime(k-1))
606 y_prime(k) = (y(k)-a(k)*y_prime(k-1))/(b(k)-a(k)*c_prime(k-1))
609 x(nrow) = y_prime(nrow)
613 x(k) = y_prime(k)-c_prime(k)*x(k+1)
632 elseif (method ==
'TDMA_H')
then 642 if (abs(a(k+1)-c(k)) > 1.e-10*(abs(a(k+1))+abs(c(k))))
then 643 call mom_error(warning,
"tridiag_solver: matrix not symmetric; need symmetry when invoking TDMA_H")
649 alpha(nrow) = b(nrow)-h(nrow)-alpha(nrow-1)
652 y_prime(:) = 0.0 ; q(:) = 0.0
653 y_prime(1) = beta*y(1) ; q(1) = beta*alpha(1)
658 beta = 1/(h(k)+alpha(k-1)*q_prime+alpha(k))
659 if (isnan(beta))
then ; print *,
"Tridiag_solver: beta is NAN" ;
endif 661 y_prime(k) = beta*(y(k)+alpha(k-1)*y_prime(k-1))
662 q_prime = beta*(h(k)+alpha(k-1)*q_prime)
664 if ((h(nrow)+alpha(nrow-1)*q_prime+alpha(nrow)) == 0.0)
then 665 call mom_error(fatal,
"Tridiag_solver: this system is not stable.")
668 beta = 1/(h(nrow)+alpha(nrow-1)*q_prime+alpha(nrow))
670 y_prime(nrow) = beta*(y(nrow)+alpha(nrow-1)*y_prime(nrow-1))
671 x(nrow) = y_prime(nrow)
674 x(k) = y_prime(k)+q(k)*x(k+1)
680 deallocate(c_prime,y_prime,q,alpha)
683 end subroutine tridiag_solver
686 subroutine wave_structure_init(Time, G, param_file, diag, CS)
687 type(time_type),
intent(in) :: time
691 type(
diag_ctrl),
target,
intent(in) :: diag
696 #include "version_variable.h" 697 character(len=40) :: mdl =
"MOM_wave_structure" 698 integer :: isd, ied, jsd, jed, nz
700 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
702 if (
associated(cs))
then 703 call mom_error(warning,
"wave_structure_init called with an "// &
704 "associated control structure.")
706 else ;
allocate(cs) ;
endif 708 call get_param(param_file, mdl,
"INTERNAL_TIDE_SOURCE_X", cs%int_tide_source_x, &
709 "X Location of generation site for internal tide", default=1.)
710 call get_param(param_file, mdl,
"INTERNAL_TIDE_SOURCE_Y", cs%int_tide_source_y, &
711 "Y Location of generation site for internal tide", default=1.)
717 allocate(cs%w_strct(isd:ied,jsd:jed,nz+1))
718 allocate(cs%u_strct(isd:ied,jsd:jed,nz+1))
719 allocate(cs%W_profile(isd:ied,jsd:jed,nz+1))
720 allocate(cs%Uavg_profile(isd:ied,jsd:jed,nz+1))
721 allocate(cs%z_depths(isd:ied,jsd:jed,nz+1))
722 allocate(cs%N2(isd:ied,jsd:jed,nz+1))
723 allocate(cs%num_intfaces(isd:ied,jsd:jed))
728 end subroutine wave_structure_init
Ocean grid type. See mom_grid for details.
The control structure for the MOM_wave_structure module.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
The MOM6 facility to parse input files for runtime parameters.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Routines for error handling and I/O management.
Calculate the derivatives of density with temperature and salinity from T, S, and P.
Provides subroutines for quantities specific to the equation of state.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Provides a transparent vertical ocean grid type and supporting routines.
Vertical structure functions for first baroclinic mode wave speed.
Provides transparent structures with groups of MOM6 variables and supporting routines.
An overloaded interface to read and log the values of various types of parameters.
Provides checksumming functions for debugging.