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