MOM6
MOM_tidal_forcing.F90
1 !> Tidal contributions to geopotential
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, &
7  clock_module
8 use mom_domains, only : pass_var
9 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning
11 use mom_grid, only : ocean_grid_type
12 use mom_io, only : field_exists, file_exists, mom_read_data
13 use mom_time_manager, only : set_date, time_type, time_type_to_real, operator(-)
14 
15 implicit none ; private
16 
17 public calc_tidal_forcing, tidal_forcing_init, tidal_forcing_end
18 public tidal_forcing_sensitivity
19 ! MOM_open_boundary uses the following to set tides on the boundary.
20 public astro_longitudes_init, eq_phase, nodal_fu, tidal_frequency
21 
22 #include <MOM_memory.h>
23 
24 integer, parameter :: max_constituents = 10 !< The maximum number of tidal
25  !! constituents that could be used.
26 !> Simple type to store astronomical longitudes used to calculate tidal phases.
27 type, public :: astro_longitudes
28  real :: &
29  s, & !< Mean longitude of moon [rad]
30  h, & !< Mean longitude of sun [rad]
31  p, & !< Mean longitude of lunar perigee [rad]
32  n !< Longitude of ascending node [rad]
33 end type astro_longitudes
34 
35 !> The control structure for the MOM_tidal_forcing module
36 type, public :: tidal_forcing_cs ; private
37  logical :: use_sal_scalar !< If true, use the scalar approximation when
38  !! calculating self-attraction and loading.
39  logical :: tidal_sal_from_file !< If true, Read the tidal self-attraction
40  !! and loading from input files, specified
41  !! by TIDAL_INPUT_FILE.
42  logical :: use_prev_tides !< If true, use the SAL from the previous
43  !! iteration of the tides to facilitate convergence.
44  logical :: use_eq_phase !< If true, tidal forcing is phase-shifted to match
45  !! equilibrium tide. Set to false if providing tidal phases
46  !! that have already been shifted by the
47  !! astronomical/equilibrium argument.
48  real :: sal_scalar !< The constant of proportionality between sea surface
49  !! height (really it should be bottom pressure) anomalies
50  !! and bottom geopotential anomalies.
51  integer :: nc !< The number of tidal constituents in use.
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].
56  love_no !< The Love number of a tidal constituent at time 0 [nondim].
57  integer :: struct(max_constituents) !< An encoded spatial structure for each constituent
58  character (len=16) :: const_name(max_constituents) !< The name of each constituent
59 
60  type(time_type) :: time_ref !< Reference time (t = 0) used to calculate tidal forcing.
61  type(astro_longitudes) :: tidal_longitudes !< Astronomical longitudes used to calculate
62  !! tidal phases at t = 0.
63  real, pointer, dimension(:,:,:) :: &
64  sin_struct => null(), & !< The sine and cosine based structures that can
65  cos_struct => null(), & !< be associated with the astronomical forcing.
66  cosphasesal => null(), & !< The cosine and sine of the phase of the
67  sinphasesal => null(), & !< self-attraction and loading amphidromes.
68  ampsal => null(), & !< The amplitude of the SAL [m].
69  cosphase_prev => null(), & !< The cosine and sine of the phase of the
70  sinphase_prev => null(), & !< amphidromes in the previous tidal solutions.
71  amp_prev => null() !< The amplitude of the previous tidal solution [m].
72 end type tidal_forcing_cs
73 
74 integer :: id_clock_tides !< CPU clock for tides
75 
76 contains
77 
78 !> Finds astronomical longitudes s, h, p, and N,
79 !! the mean longitude of the moon, sun, lunar perigee, and ascending node, respectively,
80 !! at the specified reference time time_ref.
81 !! These formulas were obtained from
82 !! Kowalik and Luick, "Modern Theory and Practice of Tide Analysis and Tidal Power", 2019
83 !! (their Equation I.71), which are based on Schureman, 1958.
84 !! For simplicity, the time associated with time_ref should
85 !! be at midnight. These formulas also only make sense if
86 !! the calendar is gregorian.
87 subroutine astro_longitudes_init(time_ref, longitudes)
88  type(time_type), intent(in) :: time_ref !> Time to calculate longitudes for.
89  type(astro_longitudes), intent(out) :: longitudes !> Lunar and solar longitudes at time_ref.
90  real :: D, T !> Date offsets
91  real, parameter :: PI = 4.0 * atan(1.0) !> 3.14159...
92  ! Find date at time_ref in days since 1900-01-01
93  d = time_type_to_real(time_ref - set_date(1900, 1, 1)) / (24.0 * 3600.0)
94  ! Time since 1900-01-01 in Julian centuries
95  ! Kowalik and Luick use 36526, but Schureman uses 36525 which I think is correct.
96  t = d / 36525.0
97  ! Calculate longitudes, including converting to radians on [0, 2pi)
98  ! s: Mean longitude of moon
99  longitudes%s = mod((277.0248 + 481267.8906 * t) + 0.0011 * (t**2), 360.0) * pi / 180.0
100  ! h: Mean longitude of sun
101  longitudes%h = mod((280.1895 + 36000.7689 * t) + 3.0310e-4 * (t**2), 360.0) * pi / 180.0
102  ! p: Mean longitude of lunar perigee
103  longitudes%p = mod((334.3853 + 4069.0340 * t) - 0.0103 * (t**2), 360.0) * pi / 180.0
104  ! n: Longitude of ascending node
105  longitudes%N = mod((259.1568 - 1934.142 * t) + 0.0021 * (t**2), 360.0) * pi / 180.0
106 end subroutine astro_longitudes_init
107 
108 !> Calculates the equilibrium phase argument for the given tidal
109 !! constituent constit and the astronomical longitudes and the reference time.
110 !! These formulas follow Table I.4 of Kowalik and Luick,
111 !! "Modern Theory and Practice of Tide Analysis and Tidal Power", 2019.
112 function eq_phase(constit, longitudes)
113  character (len=2), intent(in) :: constit !> Name of constituent (e.g., M2).
114  type(astro_longitudes), intent(in) :: longitudes !> Mean longitudes calculated using astro_longitudes_init
115  real, parameter :: PI = 4.0 * atan(1.0) !> 3.14159...
116  real :: eq_phase !> The equilibrium phase argument for the constituent [rad].
117 
118  select case (constit)
119  case ("M2")
120  eq_phase = 2 * (longitudes%h - longitudes%s)
121  case ("S2")
122  eq_phase = 0.0
123  case ("N2")
124  eq_phase = (- 3 * longitudes%s + 2 * longitudes%h) + longitudes%p
125  case ("K2")
126  eq_phase = 2 * longitudes%h
127  case ("K1")
128  eq_phase = longitudes%h + pi / 2.0
129  case ("O1")
130  eq_phase = (- 2 * longitudes%s + longitudes%h) - pi / 2.0
131  case ("P1")
132  eq_phase = - longitudes%h - pi / 2.0
133  case ("Q1")
134  eq_phase = ((- 3 * longitudes%s + longitudes%h) + longitudes%p) - pi / 2.0
135  case ("MF")
136  eq_phase = 2 * longitudes%s
137  case ("MM")
138  eq_phase = longitudes%s - longitudes%p
139  case default
140  call mom_error(fatal, "eq_phase: unrecognized constituent")
141  end select
142 end function eq_phase
143 
144 !> Looks up angular frequencies for the main tidal constituents.
145 !! Values used here are from previous versions of MOM.
146 function tidal_frequency(constit)
147  character (len=2), intent(in) :: constit !> Constituent to look up
148  real :: tidal_frequency !> Angular frequency [s-1]
149 
150  select case (constit)
151  case ("M2")
152  tidal_frequency = 1.4051890e-4
153  case ("S2")
154  tidal_frequency = 1.4544410e-4
155  case ("N2")
156  tidal_frequency = 1.3787970e-4
157  case ("K2")
158  tidal_frequency = 1.4584234e-4
159  case ("K1")
160  tidal_frequency = 0.7292117e-4
161  case ("O1")
162  tidal_frequency = 0.6759774e-4
163  case ("P1")
164  tidal_frequency = 0.7252295e-4
165  case ("Q1")
166  tidal_frequency = 0.6495854e-4
167  case ("MF")
168  tidal_frequency = 0.053234e-4
169  case ("MM")
170  tidal_frequency = 0.026392e-4
171  case default
172  call mom_error(fatal, "tidal_frequency: unrecognized constituent")
173  end select
174 end function tidal_frequency
175 
176 !> Find amplitude (f) and phase (u) modulation of tidal constituents by the 18.6
177 !! year nodal cycle. Values here follow Table I.6 in Kowalik and Luick,
178 !! "Modern Theory and Practice of Tide Analysis and Tidal Power", 2019.
179 subroutine nodal_fu(constit, N, fn, un)
180  character (len=2), intent(in) :: constit !> Tidal constituent to find modulation for.
181  real, intent(in) :: N !> Longitude of ascending node [rad].
182  !! Calculate using astro_longitudes_init.
183  real, parameter :: RADIANS = 4.0 * atan(1.0) / 180.0 !> Converts degrees to radians.
184  real, intent(out) :: &
185  fn, & !> Amplitude modulation [nondim]
186  un !> Phase modulation [rad]
187  select case (constit)
188  case ("M2")
189  fn = 1.0 - 0.037 * cos(n)
190  un = -2.1 * radians * sin(n)
191  case ("S2")
192  fn = 1.0 ! Solar S2 has no amplitude modulation.
193  un = 0.0 ! S2 has no phase modulation.
194  case ("N2")
195  fn = 1.0 - 0.037 * cos(n)
196  un = -2.1 * radians * sin(n)
197  case ("K2")
198  fn = 1.024 + 0.286 * cos(n)
199  un = -17.7 * radians * sin(n)
200  case ("K1")
201  fn = 1.006 + 0.115 * cos(n)
202  un = -8.9 * radians * sin(n)
203  case ("O1")
204  fn = 1.009 + 0.187 * cos(n)
205  un = 10.8 * radians * sin(n)
206  case ("P1")
207  fn = 1.0 ! P1 has no amplitude modulation.
208  un = 0.0 ! P1 has no phase modulation.
209  case ("Q1")
210  fn = 1.009 + 0.187 * cos(n)
211  un = 10.8 * radians * sin(n)
212  case ("MF")
213  fn = 1.043 + 0.414 * cos(n)
214  un = -23.7 * radians * sin(n)
215  case ("MM")
216  fn = 1.0 - 0.130 * cos(n)
217  un = 0.0 ! MM has no phase modulation.
218  case default
219  call mom_error(fatal, "nodal_fu: unrecognized constituent")
220  end select
221 
222 end subroutine nodal_fu
223 
224 !> This subroutine allocates space for the static variables used
225 !! by this module. The metrics may be effectively 0, 1, or 2-D arrays,
226 !! while fields like the background viscosities are 2-D arrays.
227 !! ALLOC is a macro defined in MOM_memory.h for allocate or nothing with
228 !! static memory.
229 subroutine tidal_forcing_init(Time, G, param_file, CS)
230  type(time_type), intent(in) :: Time !< The current model time.
231  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
232  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters.
233  type(tidal_forcing_cs), pointer :: CS !< A pointer that is set to point to the control
234  !! structure for this module.
235  ! Local variables
236  real, dimension(SZI_(G), SZJ_(G)) :: &
237  phase, & ! The phase of some tidal constituent.
238  lat_rad, lon_rad ! Latitudes and longitudes of h-points in radians.
239  real :: deg_to_rad
240  real, dimension(MAX_CONSTITUENTS) :: freq_def, phase0_def, amp_def, love_def
241  integer, dimension(3) :: tide_ref_date !< Reference date (t = 0) for tidal forcing.
242  logical :: use_const ! True if a constituent is being used.
243  logical :: use_M2, use_S2, use_N2, use_K2, use_K1, use_O1, use_P1, use_Q1
244  logical :: use_MF, use_MM
245  logical :: tides ! True if a tidal forcing is to be used.
246  logical :: FAIL_IF_MISSING = .true.
247 ! This include declares and sets the variable "version".
248 #include "version_variable.h"
249  character(len=40) :: mdl = "MOM_tidal_forcing" ! This module's name.
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
255 
256  if (associated(cs)) then
257  call mom_error(warning, "tidal_forcing_init called with an associated "// &
258  "control structure.")
259  return
260  endif
261 
262  ! Read all relevant parameters and write them to the model log.
263  call log_version(param_file, mdl, version, "")
264  call get_param(param_file, mdl, "TIDES", tides, &
265  "If true, apply tidal momentum forcing.", default=.false.)
266 
267  if (.not.tides) return
268 
269  allocate(cs)
270 
271  ! Set up the spatial structure functions for the diurnal, semidiurnal, and
272  ! low-frequency tidal components.
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
279  enddo ; enddo
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)
287  enddo ; enddo
288 
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.", &
292  default=.false.)
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.", &
296  default=.false.)
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.", &
300  default=.false.)
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.", &
304  default=.false.)
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.", &
308  default=.false.)
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.", &
312  default=.false.)
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.", &
316  default=.false.)
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.", &
320  default=.false.)
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.", &
324  default=.false.)
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.", &
328  default=.false.)
329 
330  ! Determine how many tidal components are to be used.
331  nc = 0
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
337  cs%nc = nc
338 
339  if (nc == 0) then
340  call mom_error(fatal, "tidal_forcing_init: "// &
341  "TIDES are defined, but no tidal constituents are used.")
342  return
343  endif
344 
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)
357  ! If it is being used, sal_scalar MUST be specified in param_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.)
365 
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)
370  endif
371 
372  do c=1,4*max_constituents ; tidal_input_files(c) = "" ; enddo
373 
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.)
378  endif
379 
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.", &
383  default=0)
384 
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.)
388 
389  if (sum(tide_ref_date) == 0) then ! tide_ref_date defaults to 0.
390  cs%time_ref = set_date(1, 1, 1)
391  else
392  if(.not. cs%use_eq_phase) then
393  ! Using a reference date but not using phase relative to equilibrium.
394  ! This makes sense as long as either phases are overridden, or
395  ! correctly simulating tidal phases is not desired.
396  call mom_mesg('Tidal phases will *not* be corrected with equilibrium arguments.')
397  endif
398  cs%time_ref = set_date(tide_ref_date(1), tide_ref_date(2), tide_ref_date(3))
399  endif
400  ! Set the parameters for all components that are in use.
401  ! Initialize reference time for tides and
402  ! find relevant lunar and solar longitudes at the reference time.
403  if (cs%use_eq_phase) call astro_longitudes_init(cs%time_ref, cs%tidal_longitudes)
404  c=0
405  if (use_m2) then
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
408  endif
409 
410  if (use_s2) then
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
413  endif
414 
415  if (use_n2) then
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
418  endif
419 
420  if (use_k2) then
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
423  endif
424 
425  if (use_k1) then
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
428  endif
429 
430  if (use_o1) then
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
433  endif
434 
435  if (use_p1) then
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
438  endif
439 
440  if (use_q1) then
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
443  endif
444 
445  if (use_mf) then
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
448  endif
449 
450  if (use_mm) then
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
453  endif
454 
455  ! Set defaults for all included constituents
456  ! and things that can be set by functions
457  do c=1,nc
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)
462  cs%phase0(c) = 0.0
463  if (cs%use_eq_phase) then
464  phase0_def(c) = eq_phase(cs%const_name(c), cs%tidal_longitudes)
465  else
466  phase0_def(c) = 0.0
467  endif
468  enddo
469 
470  ! Parse the input file to potentially override the default values for the
471  ! frequency, amplitude and initial phase of each constituent, and log the
472  ! values that are actually used.
473  do c=1,nc
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))
487  enddo
488 
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))
493  do c=1,nc
494  ! Read variables with names like PHASE_SAL_M2 and AMP_SAL_M2.
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)
502  enddo ; enddo
503  enddo
504  endif
505 
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))
510  do c=1,nc
511  ! Read variables with names like PHASE_PREV_M2 and AMP_PREV_M2.
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)
519  enddo ; enddo
520  enddo
521  endif
522 
523  id_clock_tides = cpu_clock_id('(Ocean tides)', grain=clock_module)
524 
525 end subroutine tidal_forcing_init
526 
527 !> This subroutine finds a named variable in a list of files and reads its
528 !! values into a domain-decomposed 2-d array
529 subroutine find_in_files(filenames, varname, array, G)
530  character(len=*), dimension(:), intent(in) :: filenames !< The names of the files to search for the named variable
531  character(len=*), intent(in) :: varname !< The name of the variable to read
532  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
533  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: array !< The array to fill with the data
534  ! Local variables
535  integer :: nf
536 
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
540  call mom_read_data(filenames(nf), varname, array, g%Domain)
541  return
542  endif
543  enddo
544 
545  do nf=size(filenames),1,-1
546  if (file_exists(filenames(nf), g%Domain)) then
547  call mom_error(fatal, "MOM_tidal_forcing.F90: Unable to find "// &
548  trim(varname)//" in any of the tidal input files, last tried "// &
549  trim(filenames(nf)))
550  endif
551  enddo
552 
553  call mom_error(fatal, "MOM_tidal_forcing.F90: Unable to find any of the "// &
554  "tidal input files, including "//trim(filenames(1)))
555 
556 end subroutine find_in_files
557 
558 !> This subroutine calculates returns the partial derivative of the local
559 !! geopotential height with the input sea surface height due to self-attraction
560 !! and loading.
561 subroutine tidal_forcing_sensitivity(G, CS, deta_tidal_deta)
562  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
563  type(tidal_forcing_cs), pointer :: CS !< The control structure returned by a previous call to tidal_forcing_init.
564  real, intent(out) :: deta_tidal_deta !< The partial derivative of eta_tidal with
565  !! the local value of eta [nondim].
566 
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
571  else
572  deta_tidal_deta = 0.0
573  endif
574 end subroutine tidal_forcing_sensitivity
575 
576 !> This subroutine calculates the geopotential anomalies that drive the tides,
577 !! including self-attraction and loading. Optionally, it also returns the
578 !! partial derivative of the local geopotential height with the input sea surface
579 !! height. For now, eta and eta_tidal are both geopotential heights in depth
580 !! units, but probably the input for eta should really be replaced with the
581 !! column mass anomalies.
582 subroutine calc_tidal_forcing(Time, eta, eta_tidal, G, CS, deta_tidal_deta, m_to_Z)
583  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
584  type(time_type), intent(in) :: Time !< The time for the caluculation.
585  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: eta !< The sea surface height anomaly from
586  !! a time-mean geoid [Z ~> m].
587  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: eta_tidal !< The tidal forcing geopotential height
588  !! anomalies [Z ~> m].
589  type(tidal_forcing_cs), pointer :: CS !< The control structure returned by a
590  !! previous call to tidal_forcing_init.
591  real, optional, intent(out) :: deta_tidal_deta !< The partial derivative of
592  !! eta_tidal with the local value of
593  !! eta [nondim].
594  real, optional, intent(in) :: m_to_Z !< A scaling factor from m to the units of eta.
595 
596  ! Local variables
597  real :: now ! The relative time in seconds.
598  real :: amp_cosomegat, amp_sinomegat
599  real :: cosomegat, sinomegat
600  real :: m_Z ! A scaling factor from m to depth units.
601  real :: eta_prop ! The nondimenional constant of proportionality beteen eta and eta_tidal.
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
605 
606  if (.not.associated(cs)) return
607 
608  call cpu_clock_begin(id_clock_tides)
609 
610  if (cs%nc == 0) then
611  do j=jsq,jeq+1 ; do i=isq,ieq+1 ; eta_tidal(i,j) = 0.0 ; enddo ; enddo
612  return
613  endif
614 
615  now = time_type_to_real(time - cs%time_ref)
616 
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
621  else
622  eta_prop = 0.0
623  endif
624 
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
628  else
629  do j=jsq,jeq+1 ; do i=isq,ieq+1
630  eta_tidal(i,j) = eta_prop*eta(i,j)
631  enddo ; enddo
632  endif
633 
634  m_z = 1.0 ; if (present(m_to_z)) m_z = m_to_z
635 
636  do c=1,cs%nc
637  m = cs%struct(c)
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))
643  enddo ; enddo
644  enddo
645 
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))
652  enddo ; enddo
653  enddo ; endif
654 
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))
661  enddo ; enddo
662  enddo ; endif
663 
664  call cpu_clock_end(id_clock_tides)
665 
666 end subroutine calc_tidal_forcing
667 
668 !> This subroutine deallocates memory associated with the tidal forcing module.
669 subroutine tidal_forcing_end(CS)
670  type(tidal_forcing_cs), pointer :: CS !< The control structure returned by a previous call
671  !! to tidal_forcing_init; it is deallocated here.
672 
673  if (associated(cs%sin_struct)) deallocate(cs%sin_struct)
674  if (associated(cs%cos_struct)) deallocate(cs%cos_struct)
675 
676  if (associated(cs%cosphasesal)) deallocate(cs%cosphasesal)
677  if (associated(cs%sinphasesal)) deallocate(cs%sinphasesal)
678  if (associated(cs%ampsal)) deallocate(cs%ampsal)
679 
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)
683 
684  if (associated(cs)) deallocate(cs)
685 
686 end subroutine tidal_forcing_end
687 
688 !> \namespace tidal_forcing
689 !!
690 !! Code by Robert Hallberg, August 2005, based on C-code by Harper
691 !! Simmons, February, 2003, in turn based on code by Brian Arbic.
692 !!
693 !! The main subroutine in this file calculates the total tidal
694 !! contribution to the geopotential, including self-attraction and
695 !! loading terms and the astronomical contributions. All options
696 !! are selected with entries in a file that is parsed at run-time.
697 !! Overall tides are enabled with the run-time parameter 'TIDES=True'.
698 !! Tidal constituents must be individually enabled with lines like
699 !! 'TIDE_M2=True'. This file has default values of amplitude,
700 !! frequency, Love number, and phase at time 0 for the Earth's M2,
701 !! S2, N2, K2, K1, O1, P1, Q1, MF, and MM tidal constituents, but
702 !! the frequency, amplitude and phase ant time 0 for each constituent
703 !! can be changed at run time by setting variables like TIDE_M2_FREQ,
704 !! TIDE_M2_AMP and TIDE_M2_PHASE_T0 (for M2).
705 !!
706 !! In addition, the approach to calculating self-attraction and
707 !! loading is set at run time. The default is to use the scalar
708 !! approximation, with a coefficient TIDE_SAL_SCALAR_VALUE that must
709 !! be set in the run-time file (for global runs, 0.094 is typical).
710 !! Alternately, TIDAL_SAL_FROM_FILE can be set to read the SAL from
711 !! a file containing the results of a previous simulation. To iterate
712 !! the SAL to convergence, USE_PREVIOUS_TIDES may be useful (for
713 !! details, see Arbic et al., 2004, DSR II). With TIDAL_SAL_FROM_FILE
714 !! or USE_PREVIOUS_TIDES,a list of input files must be provided to
715 !! describe each constituent's properties from a previous solution.
716 
717 end module mom_tidal_forcing
Wraps the FMS time manager functions.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Wraps the MPP cpu clock functions.
This module contains I/O framework code.
Definition: MOM_io.F90:2
The MOM6 facility to parse input files for runtime parameters.
Tidal contributions to geopotential.
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
Routines for error handling and I/O management.
An overloaded interface to log version information about modules.
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
Simple type to store astronomical longitudes used to calculate tidal phases.
The control structure for the MOM_tidal_forcing module.
Do a halo update on an array.
Definition: MOM_domains.F90:54
Read a data field from a file.
Definition: MOM_io.F90:74
An overloaded interface to read and log the values of various types of parameters.