6 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, &
13 use mom_time_manager,
only : set_date, time_type, time_type_to_real,
operator(-)
15 implicit none ;
private
17 public calc_tidal_forcing, tidal_forcing_init, tidal_forcing_end
18 public tidal_forcing_sensitivity
20 public astro_longitudes_init, eq_phase, nodal_fu, tidal_frequency
22 #include <MOM_memory.h>
24 integer,
parameter :: max_constituents = 10
29 s, & !< Mean longitude of moon [rad]
30 h, & !< Mean longitude of sun [rad]
31 p, & !< Mean longitude of lunar perigee [rad]
37 logical :: use_sal_scalar
39 logical :: tidal_sal_from_file
42 logical :: use_prev_tides
44 logical :: use_eq_phase
52 real,
dimension(MAX_CONSTITUENTS) :: &
53 freq, & !< The frequency of a tidal constituent [s-1].
54 phase0, & !< The phase of a tidal constituent at time 0, in radians.
55 amp, & !< The amplitude of a tidal constituent at time 0 [m].
57 integer :: struct(max_constituents)
58 character (len=16) :: const_name(max_constituents)
60 type(time_type) :: time_ref
63 real,
pointer,
dimension(:,:,:) :: &
64 sin_struct => null(), &
65 cos_struct => null(), &
66 cosphasesal => null(), &
67 sinphasesal => null(), &
69 cosphase_prev => null(), &
70 sinphase_prev => null(), &
74 integer :: id_clock_tides
87 subroutine astro_longitudes_init(time_ref, longitudes)
88 type(time_type),
intent(in) :: time_ref
91 real,
parameter :: pi = 4.0 * atan(1.0)
93 d = time_type_to_real(time_ref - set_date(1900, 1, 1)) / (24.0 * 3600.0)
99 longitudes%s = mod((277.0248 + 481267.8906 * t) + 0.0011 * (t**2), 360.0) * pi / 180.0
101 longitudes%h = mod((280.1895 + 36000.7689 * t) + 3.0310e-4 * (t**2), 360.0) * pi / 180.0
103 longitudes%p = mod((334.3853 + 4069.0340 * t) - 0.0103 * (t**2), 360.0) * pi / 180.0
105 longitudes%N = mod((259.1568 - 1934.142 * t) + 0.0021 * (t**2), 360.0) * pi / 180.0
106 end subroutine astro_longitudes_init
112 function eq_phase(constit, longitudes)
113 character (len=2),
intent(in) :: constit
115 real,
parameter :: pi = 4.0 * atan(1.0)
118 select case (constit)
120 eq_phase = 2 * (longitudes%h - longitudes%s)
124 eq_phase = (- 3 * longitudes%s + 2 * longitudes%h) + longitudes%p
126 eq_phase = 2 * longitudes%h
128 eq_phase = longitudes%h + pi / 2.0
130 eq_phase = (- 2 * longitudes%s + longitudes%h) - pi / 2.0
132 eq_phase = - longitudes%h - pi / 2.0
134 eq_phase = ((- 3 * longitudes%s + longitudes%h) + longitudes%p) - pi / 2.0
136 eq_phase = 2 * longitudes%s
138 eq_phase = longitudes%s - longitudes%p
140 call mom_error(fatal,
"eq_phase: unrecognized constituent")
142 end function eq_phase
146 function tidal_frequency(constit)
147 character (len=2),
intent(in) :: constit
148 real :: tidal_frequency
150 select case (constit)
152 tidal_frequency = 1.4051890e-4
154 tidal_frequency = 1.4544410e-4
156 tidal_frequency = 1.3787970e-4
158 tidal_frequency = 1.4584234e-4
160 tidal_frequency = 0.7292117e-4
162 tidal_frequency = 0.6759774e-4
164 tidal_frequency = 0.7252295e-4
166 tidal_frequency = 0.6495854e-4
168 tidal_frequency = 0.053234e-4
170 tidal_frequency = 0.026392e-4
172 call mom_error(fatal,
"tidal_frequency: unrecognized constituent")
174 end function tidal_frequency
179 subroutine nodal_fu(constit, N, fn, un)
180 character (len=2),
intent(in) :: constit
181 real,
intent(in) :: n
183 real,
parameter :: radians = 4.0 * atan(1.0) / 180.0
184 real,
intent(out) :: &
185 fn, & !> Amplitude modulation [nondim]
187 select case (constit)
189 fn = 1.0 - 0.037 * cos(n)
190 un = -2.1 * radians * sin(n)
195 fn = 1.0 - 0.037 * cos(n)
196 un = -2.1 * radians * sin(n)
198 fn = 1.024 + 0.286 * cos(n)
199 un = -17.7 * radians * sin(n)
201 fn = 1.006 + 0.115 * cos(n)
202 un = -8.9 * radians * sin(n)
204 fn = 1.009 + 0.187 * cos(n)
205 un = 10.8 * radians * sin(n)
210 fn = 1.009 + 0.187 * cos(n)
211 un = 10.8 * radians * sin(n)
213 fn = 1.043 + 0.414 * cos(n)
214 un = -23.7 * radians * sin(n)
216 fn = 1.0 - 0.130 * cos(n)
219 call mom_error(fatal,
"nodal_fu: unrecognized constituent")
222 end subroutine nodal_fu
229 subroutine tidal_forcing_init(Time, G, param_file, CS)
230 type(time_type),
intent(in) :: time
236 real,
dimension(SZI_(G), SZJ_(G)) :: &
240 real,
dimension(MAX_CONSTITUENTS) :: freq_def, phase0_def, amp_def, love_def
241 integer,
dimension(3) :: tide_ref_date
243 logical :: use_m2, use_s2, use_n2, use_k2, use_k1, use_o1, use_p1, use_q1
244 logical :: use_mf, use_mm
246 logical :: fail_if_missing = .true.
248 #include "version_variable.h"
249 character(len=40) :: mdl =
"MOM_tidal_forcing"
250 character(len=128) :: mesg
251 character(len=200) :: tidal_input_files(4*max_constituents)
252 integer :: i, j, c, is, ie, js, je, isd, ied, jsd, jed, nc
253 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
254 isd = g%isd ; ied = g%ied ; jsd = g%jsd; jed = g%jed
256 if (
associated(cs))
then
257 call mom_error(warning,
"tidal_forcing_init called with an associated "// &
258 "control structure.")
264 call get_param(param_file, mdl,
"TIDES", tides, &
265 "If true, apply tidal momentum forcing.", default=.false.)
267 if (.not.tides)
return
273 allocate(cs%sin_struct(isd:ied,jsd:jed,3)) ; cs%sin_struct(:,:,:) = 0.0
274 allocate(cs%cos_struct(isd:ied,jsd:jed,3)) ; cs%cos_struct(:,:,:) = 0.0
275 deg_to_rad = 4.0*atan(1.0)/180.0
276 do j=js-1,je+1 ;
do i=is-1,ie+1
277 lat_rad(i,j) = g%geoLatT(i,j)*deg_to_rad
278 lon_rad(i,j) = g%geoLonT(i,j)*deg_to_rad
280 do j=js-1,je+1 ;
do i=is-1,ie+1
281 cs%sin_struct(i,j,1) = -sin(2.0*lat_rad(i,j)) * sin(lon_rad(i,j))
282 cs%cos_struct(i,j,1) = sin(2.0*lat_rad(i,j)) * cos(lon_rad(i,j))
283 cs%sin_struct(i,j,2) = -cos(lat_rad(i,j))**2 * sin(2.0*lon_rad(i,j))
284 cs%cos_struct(i,j,2) = cos(lat_rad(i,j))**2 * cos(2.0*lon_rad(i,j))
285 cs%sin_struct(i,j,3) = 0.0
286 cs%cos_struct(i,j,3) = (0.5-1.5*sin(lat_rad(i,j))**2)
289 call get_param(param_file, mdl,
"TIDE_M2", use_m2, &
290 "If true, apply tidal momentum forcing at the M2 "//&
291 "frequency. This is only used if TIDES is true.", &
293 call get_param(param_file, mdl,
"TIDE_S2", use_s2, &
294 "If true, apply tidal momentum forcing at the S2 "//&
295 "frequency. This is only used if TIDES is true.", &
297 call get_param(param_file, mdl,
"TIDE_N2", use_n2, &
298 "If true, apply tidal momentum forcing at the N2 "//&
299 "frequency. This is only used if TIDES is true.", &
301 call get_param(param_file, mdl,
"TIDE_K2", use_k2, &
302 "If true, apply tidal momentum forcing at the K2 "//&
303 "frequency. This is only used if TIDES is true.", &
305 call get_param(param_file, mdl,
"TIDE_K1", use_k1, &
306 "If true, apply tidal momentum forcing at the K1 "//&
307 "frequency. This is only used if TIDES is true.", &
309 call get_param(param_file, mdl,
"TIDE_O1", use_o1, &
310 "If true, apply tidal momentum forcing at the O1 "//&
311 "frequency. This is only used if TIDES is true.", &
313 call get_param(param_file, mdl,
"TIDE_P1", use_p1, &
314 "If true, apply tidal momentum forcing at the P1 "//&
315 "frequency. This is only used if TIDES is true.", &
317 call get_param(param_file, mdl,
"TIDE_Q1", use_q1, &
318 "If true, apply tidal momentum forcing at the Q1 "//&
319 "frequency. This is only used if TIDES is true.", &
321 call get_param(param_file, mdl,
"TIDE_MF", use_mf, &
322 "If true, apply tidal momentum forcing at the MF "//&
323 "frequency. This is only used if TIDES is true.", &
325 call get_param(param_file, mdl,
"TIDE_MM", use_mm, &
326 "If true, apply tidal momentum forcing at the MM "//&
327 "frequency. This is only used if TIDES is true.", &
332 if (use_m2) nc=nc+1 ;
if (use_s2) nc=nc+1
333 if (use_n2) nc=nc+1 ;
if (use_k2) nc=nc+1
334 if (use_k1) nc=nc+1 ;
if (use_o1) nc=nc+1
335 if (use_p1) nc=nc+1 ;
if (use_q1) nc=nc+1
336 if (use_mf) nc=nc+1 ;
if (use_mm) nc=nc+1
340 call mom_error(fatal,
"tidal_forcing_init: "// &
341 "TIDES are defined, but no tidal constituents are used.")
345 call get_param(param_file, mdl,
"TIDAL_SAL_FROM_FILE", cs%tidal_sal_from_file, &
346 "If true, read the tidal self-attraction and loading "//&
347 "from input files, specified by TIDAL_INPUT_FILE. "//&
348 "This is only used if TIDES is true.", default=.false.)
349 call get_param(param_file, mdl,
"USE_PREVIOUS_TIDES", cs%use_prev_tides, &
350 "If true, use the SAL from the previous iteration of the "//&
351 "tides to facilitate convergent iteration. "//&
352 "This is only used if TIDES is true.", default=.false.)
353 call get_param(param_file, mdl,
"TIDE_USE_SAL_SCALAR", cs%use_sal_scalar, &
354 "If true and TIDES is true, use the scalar approximation "//&
355 "when calculating self-attraction and loading.", &
356 default=.not.cs%tidal_sal_from_file)
358 if (cs%use_sal_scalar .or. cs%use_prev_tides) &
359 call get_param(param_file, mdl,
"TIDE_SAL_SCALAR_VALUE", cs%sal_scalar, &
360 "The constant of proportionality between sea surface "//&
361 "height (really it should be bottom pressure) anomalies "//&
362 "and bottom geopotential anomalies. This is only used if "//&
363 "TIDES and TIDE_USE_SAL_SCALAR are true.", units=
"m m-1", &
364 fail_if_missing=.true.)
366 if (nc > max_constituents)
then
367 write(mesg,
'("Increase MAX_CONSTITUENTS in MOM_tidal_forcing.F90 to at least",I3, &
368 &"to accommodate all the registered tidal constituents.")') nc
369 call mom_error(fatal,
"MOM_tidal_forcing"//mesg)
372 do c=1,4*max_constituents ; tidal_input_files(c) =
"" ;
enddo
374 if (cs%tidal_sal_from_file .or. cs%use_prev_tides)
then
375 call get_param(param_file, mdl,
"TIDAL_INPUT_FILE", tidal_input_files, &
376 "A list of input files for tidal information.", &
377 default =
"", fail_if_missing=.true.)
380 call get_param(param_file, mdl,
"TIDE_REF_DATE", tide_ref_date, &
381 "Year,month,day to use as reference date for tidal forcing. "//&
382 "If not specified, defaults to 0.", &
385 call get_param(param_file, mdl,
"TIDE_USE_EQ_PHASE", cs%use_eq_phase, &
386 "Correct phases by calculating equilibrium phase arguments for TIDE_REF_DATE. ", &
387 default=.false., fail_if_missing=.false.)
389 if (sum(tide_ref_date) == 0)
then
390 cs%time_ref = set_date(1, 1, 1)
392 if(.not. cs%use_eq_phase)
then
396 call mom_mesg(
'Tidal phases will *not* be corrected with equilibrium arguments.')
398 cs%time_ref = set_date(tide_ref_date(1), tide_ref_date(2), tide_ref_date(3))
403 if (cs%use_eq_phase)
call astro_longitudes_init(cs%time_ref, cs%tidal_longitudes)
406 c=c+1 ; cs%const_name(c) =
"M2" ; cs%struct(c) = 2
407 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.242334
411 c=c+1 ; cs%const_name(c) =
"S2" ; cs%struct(c) = 2
412 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.112743
416 c=c+1 ; cs%const_name(c) =
"N2" ; cs%struct(c) = 2
417 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.046397
421 c=c+1 ; cs%const_name(c) =
"K2" ; cs%struct(c) = 2
422 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.030684
426 c=c+1 ; cs%const_name(c) =
"K1" ; cs%struct(c) = 1
427 cs%love_no(c) = 0.736 ; cs%amp(c) = 0.141565
431 c=c+1 ; cs%const_name(c) =
"O1" ; cs%struct(c) = 1
432 cs%love_no(c) = 0.695 ; cs%amp(c) = 0.100661
436 c=c+1 ; cs%const_name(c) =
"P1" ; cs%struct(c) = 1
437 cs%love_no(c) = 0.706 ; cs%amp(c) = 0.046848
441 c=c+1 ; cs%const_name(c) =
"Q1" ; cs%struct(c) = 1
442 cs%love_no(c) = 0.695 ; cs%amp(c) = 0.019273
446 c=c+1 ; cs%const_name(c) =
"MF" ; cs%struct(c) = 3
447 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.042041
451 c=c+1 ; cs%const_name(c) =
"MM" ; cs%struct(c) = 3
452 cs%love_no(c) = 0.693 ; cs%amp(c) = 0.022191
458 cs%freq(c) = tidal_frequency(cs%const_name(c))
459 freq_def(c) = cs%freq(c)
460 love_def(c) = cs%love_no(c)
461 amp_def(c) = cs%amp(c)
463 if (cs%use_eq_phase)
then
464 phase0_def(c) = eq_phase(cs%const_name(c), cs%tidal_longitudes)
474 call get_param(param_file, mdl,
"TIDE_"//trim(cs%const_name(c))//
"_FREQ", cs%freq(c), &
475 "Frequency of the "//trim(cs%const_name(c))//
" tidal constituent. "//&
476 "This is only used if TIDES and TIDE_"//trim(cs%const_name(c))// &
477 " are true, or if OBC_TIDE_N_CONSTITUENTS > 0 and "//trim(cs%const_name(c))// &
478 " is in OBC_TIDE_CONSTITUENTS.", units=
"s-1", default=freq_def(c))
479 call get_param(param_file, mdl,
"TIDE_"//trim(cs%const_name(c))//
"_AMP", cs%amp(c), &
480 "Amplitude of the "//trim(cs%const_name(c))//
" tidal constituent. "//&
481 "This is only used if TIDES and TIDE_"//trim(cs%const_name(c))// &
482 " are true.", units=
"m", default=amp_def(c))
483 call get_param(param_file, mdl,
"TIDE_"//trim(cs%const_name(c))//
"_PHASE_T0", cs%phase0(c), &
484 "Phase of the "//trim(cs%const_name(c))//
" tidal constituent at time 0. "//&
485 "This is only used if TIDES and TIDE_"//trim(cs%const_name(c))// &
486 " are true.", units=
"radians", default=phase0_def(c))
489 if (cs%tidal_sal_from_file)
then
490 allocate(cs%cosphasesal(isd:ied,jsd:jed,nc))
491 allocate(cs%sinphasesal(isd:ied,jsd:jed,nc))
492 allocate(cs%ampsal(isd:ied,jsd:jed,nc))
495 call find_in_files(tidal_input_files,
"PHASE_SAL_"//trim(cs%const_name(c)),phase,g)
496 call find_in_files(tidal_input_files,
"AMP_SAL_"//trim(cs%const_name(c)),cs%ampsal(:,:,c),g)
497 call pass_var(phase, g%domain,complete=.false.)
498 call pass_var(cs%ampsal(:,:,c),g%domain,complete=.true.)
499 do j=js-1,je+1 ;
do i=is-1,ie+1
500 cs%cosphasesal(i,j,c) = cos(phase(i,j)*deg_to_rad)
501 cs%sinphasesal(i,j,c) = sin(phase(i,j)*deg_to_rad)
506 if (cs%USE_PREV_TIDES)
then
507 allocate(cs%cosphase_prev(isd:ied,jsd:jed,nc))
508 allocate(cs%sinphase_prev(isd:ied,jsd:jed,nc))
509 allocate(cs%amp_prev(isd:ied,jsd:jed,nc))
512 call find_in_files(tidal_input_files,
"PHASE_PREV_"//trim(cs%const_name(c)),phase,g)
513 call find_in_files(tidal_input_files,
"AMP_PREV_"//trim(cs%const_name(c)),cs%amp_prev(:,:,c),g)
514 call pass_var(phase, g%domain,complete=.false.)
515 call pass_var(cs%amp_prev(:,:,c),g%domain,complete=.true.)
516 do j=js-1,je+1 ;
do i=is-1,ie+1
517 cs%cosphase_prev(i,j,c) = cos(phase(i,j)*deg_to_rad)
518 cs%sinphase_prev(i,j,c) = sin(phase(i,j)*deg_to_rad)
523 id_clock_tides = cpu_clock_id(
'(Ocean tides)', grain=clock_module)
525 end subroutine tidal_forcing_init
529 subroutine find_in_files(filenames, varname, array, G)
530 character(len=*),
dimension(:),
intent(in) :: filenames
531 character(len=*),
intent(in) :: varname
533 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: array
537 do nf=1,
size(filenames)
538 if (len_trim(filenames(nf)) == 0) cycle
539 if (field_exists(filenames(nf), varname, g%Domain%mpp_domain))
then
545 do nf=
size(filenames),1,-1
547 call mom_error(fatal,
"MOM_tidal_forcing.F90: Unable to find "// &
548 trim(varname)//
" in any of the tidal input files, last tried "// &
553 call mom_error(fatal,
"MOM_tidal_forcing.F90: Unable to find any of the "// &
554 "tidal input files, including "//trim(filenames(1)))
556 end subroutine find_in_files
561 subroutine tidal_forcing_sensitivity(G, CS, deta_tidal_deta)
564 real,
intent(out) :: deta_tidal_deta
567 if (cs%USE_SAL_SCALAR .and. cs%USE_PREV_TIDES)
then
568 deta_tidal_deta = 2.0*cs%SAL_SCALAR
569 elseif (cs%USE_SAL_SCALAR .or. cs%USE_PREV_TIDES)
then
570 deta_tidal_deta = cs%SAL_SCALAR
572 deta_tidal_deta = 0.0
574 end subroutine tidal_forcing_sensitivity
582 subroutine calc_tidal_forcing(Time, eta, eta_tidal, G, CS, deta_tidal_deta, m_to_Z)
584 type(time_type),
intent(in) :: time
585 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: eta
587 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: eta_tidal
591 real,
optional,
intent(out) :: deta_tidal_deta
594 real,
optional,
intent(in) :: m_to_z
598 real :: amp_cosomegat, amp_sinomegat
599 real :: cosomegat, sinomegat
602 integer :: i, j, c, m, is, ie, js, je, isq, ieq, jsq, jeq
603 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
604 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
606 if (.not.
associated(cs))
return
608 call cpu_clock_begin(id_clock_tides)
611 do j=jsq,jeq+1 ;
do i=isq,ieq+1 ; eta_tidal(i,j) = 0.0 ;
enddo ;
enddo
615 now = time_type_to_real(time - cs%time_ref)
617 if (cs%USE_SAL_SCALAR .and. cs%USE_PREV_TIDES)
then
618 eta_prop = 2.0*cs%SAL_SCALAR
619 elseif (cs%USE_SAL_SCALAR .or. cs%USE_PREV_TIDES)
then
620 eta_prop = cs%SAL_SCALAR
625 if (
present(deta_tidal_deta))
then
626 deta_tidal_deta = eta_prop
627 do j=jsq,jeq+1 ;
do i=isq,ieq+1 ; eta_tidal(i,j) = 0.0 ;
enddo ;
enddo
629 do j=jsq,jeq+1 ;
do i=isq,ieq+1
630 eta_tidal(i,j) = eta_prop*eta(i,j)
634 m_z = 1.0 ;
if (
present(m_to_z)) m_z = m_to_z
638 amp_cosomegat = m_z*cs%amp(c)*cs%love_no(c) * cos(cs%freq(c)*now + cs%phase0(c))
639 amp_sinomegat = m_z*cs%amp(c)*cs%love_no(c) * sin(cs%freq(c)*now + cs%phase0(c))
640 do j=jsq,jeq+1 ;
do i=isq,ieq+1
641 eta_tidal(i,j) = eta_tidal(i,j) + (amp_cosomegat*cs%cos_struct(i,j,m) + &
642 amp_sinomegat*cs%sin_struct(i,j,m))
646 if (cs%tidal_sal_from_file)
then ;
do c=1,cs%nc
647 cosomegat = cos(cs%freq(c)*now)
648 sinomegat = sin(cs%freq(c)*now)
649 do j=jsq,jeq+1 ;
do i=isq,ieq+1
650 eta_tidal(i,j) = eta_tidal(i,j) + m_z*cs%ampsal(i,j,c) * &
651 (cosomegat*cs%cosphasesal(i,j,c) + sinomegat*cs%sinphasesal(i,j,c))
655 if (cs%USE_PREV_TIDES)
then ;
do c=1,cs%nc
656 cosomegat = cos(cs%freq(c)*now)
657 sinomegat = sin(cs%freq(c)*now)
658 do j=jsq,jeq+1 ;
do i=isq,ieq+1
659 eta_tidal(i,j) = eta_tidal(i,j) - m_z*cs%SAL_SCALAR*cs%amp_prev(i,j,c) * &
660 (cosomegat*cs%cosphase_prev(i,j,c) + sinomegat*cs%sinphase_prev(i,j,c))
664 call cpu_clock_end(id_clock_tides)
666 end subroutine calc_tidal_forcing
669 subroutine tidal_forcing_end(CS)
673 if (
associated(cs%sin_struct))
deallocate(cs%sin_struct)
674 if (
associated(cs%cos_struct))
deallocate(cs%cos_struct)
676 if (
associated(cs%cosphasesal))
deallocate(cs%cosphasesal)
677 if (
associated(cs%sinphasesal))
deallocate(cs%sinphasesal)
678 if (
associated(cs%ampsal))
deallocate(cs%ampsal)
680 if (
associated(cs%cosphase_prev))
deallocate(cs%cosphase_prev)
681 if (
associated(cs%sinphase_prev))
deallocate(cs%sinphase_prev)
682 if (
associated(cs%amp_prev))
deallocate(cs%amp_prev)
684 if (
associated(cs))
deallocate(cs)
686 end subroutine tidal_forcing_end