MOM6
Kelvin_initialization.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
23 use mom_error_handler, only : mom_mesg, mom_error, fatal, warning, is_root_pe
25 use mom_grid, only : ocean_grid_type
32 use mom_time_manager, only : time_type, set_time, time_type_to_real
33 
34 implicit none ; private
35 
36 #include <MOM_memory.h>
37 
40 
41 !> Control structure for Kelvin wave open boundaries.
42 type, public :: kelvin_obc_cs ; private
43  integer :: mode = 0 !< Vertical mode
44  real :: coast_angle = 0 !< Angle of coastline
45  real :: coast_offset = 0 !< Longshore distance to coastal angle
46  real :: n0 = 0 !< Brunt-Vaisala frequency
47  real :: h0 = 0 !< Bottom depth
48  real :: f_0 !< Coriolis parameter
49  real :: plx = 0 !< Longshore wave parameter
50  real :: pmz = 0 !< Vertical wave parameter
51  real :: lambda = 0 !< Vertical wave parameter
52  real :: omega !< Frequency
53  real :: rho_range !< Density range
54  real :: rho_0 !< Mean density
55 end type kelvin_obc_cs
56 
57 ! This include declares and sets the variable "version".
58 #include "version_variable.h"
59 
60 contains
61 
62 !> Add Kelvin wave to OBC registry.
63 function register_kelvin_obc(param_file, CS, OBC_Reg)
64  type(param_file_type), intent(in) :: param_file !< parameter file.
65  type(kelvin_obc_cs), pointer :: CS !< Kelvin wave control structure.
66  type(obc_registry_type), pointer :: OBC_Reg !< OBC registry.
67  logical :: register_Kelvin_OBC
68  character(len=40) :: mdl = "register_Kelvin_OBC" !< This subroutine's name.
69  character(len=32) :: casename = "Kelvin wave" !< This case's name.
70  character(len=200) :: config
71 
72  if (associated(cs)) then
73  call mom_error(warning, "register_Kelvin_OBC called with an "// &
74  "associated control structure.")
75  return
76  endif
77  allocate(cs)
78 
79  call log_version(param_file, mdl, version, "")
80  call get_param(param_file, mdl, "KELVIN_WAVE_MODE", cs%mode, &
81  "Vertical Kelvin wave mode imposed at upstream open boundary.", &
82  default=0)
83  call get_param(param_file, mdl, "F_0", cs%F_0, &
84  default=0.0, do_not_log=.true.)
85  call get_param(param_file, mdl, "TOPO_CONFIG", config, do_not_log=.true.)
86  if (trim(config) == "Kelvin") then
87  call get_param(param_file, mdl, "KELVIN_COAST_OFFSET", cs%coast_offset, &
88  "The distance along the southern and northern boundaries \n"//&
89  "at which the coasts angle in.", &
90  units="km", default=100.0)
91  call get_param(param_file, mdl, "KELVIN_COAST_ANGLE", cs%coast_angle, &
92  "The angle of the southern bondary beyond X=KELVIN_COAST_OFFSET.", &
93  units="degrees", default=11.3)
94  cs%coast_angle = cs%coast_angle * (atan(1.0)/45.) ! Convert to radians
95  cs%coast_offset = cs%coast_offset * 1.e3 ! Convert to m
96  endif
97  if (cs%mode /= 0) then
98  call get_param(param_file, mdl, "DENSITY_RANGE", cs%rho_range, &
99  default=2.0, do_not_log=.true.)
100  call get_param(param_file, mdl, "RHO_0", cs%rho_0, &
101  default=1035.0, do_not_log=.true.)
102  call get_param(param_file, mdl, "MAXIMUM_DEPTH", cs%H0, &
103  default=1000.0, do_not_log=.true.)
104  endif
105 
106  ! Register the Kelvin open boundary.
107  call register_obc(casename, param_file, obc_reg)
108  register_kelvin_obc = .true.
109 
110 end function register_kelvin_obc
111 
112 !> Clean up the Kelvin wave OBC from registry.
113 subroutine kelvin_obc_end(CS)
114  type(kelvin_obc_cs), pointer :: CS !< Kelvin wave control structure.
115 
116  if (associated(cs)) then
117  deallocate(cs)
118  endif
119 end subroutine kelvin_obc_end
120 
121 ! -----------------------------------------------------------------------------
122 !> This subroutine sets up the Kelvin topography and land mask
123 subroutine kelvin_initialize_topography(D, G, param_file, max_depth)
124  type(dyn_horgrid_type), intent(in) :: G !< The dynamic horizontal grid type
125  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: D !< Ocean bottom depth in m
126  type(param_file_type), intent(in) :: param_file !< Parameter file structure
127  real, intent(in) :: max_depth !< Maximum depth of model in m
128  ! Local variables
129  character(len=40) :: mdl = "Kelvin_initialize_topography" ! This subroutine's name.
130  real :: min_depth ! The minimum and maximum depths in m.
131  real :: PI ! 3.1415...
132  real :: coast_offset, coast_angle, right_angle
133  integer :: i, j
134 
135  call mom_mesg(" Kelvin_initialization.F90, Kelvin_initialize_topography: setting topography", 5)
136 
137  call get_param(param_file, mdl, "MINIMUM_DEPTH", min_depth, &
138  "The minimum depth of the ocean.", units="m", default=0.0)
139  call get_param(param_file, mdl, "KELVIN_COAST_OFFSET", coast_offset, &
140  default=100.0, do_not_log=.true.)
141  call get_param(param_file, mdl, "KELVIN_COAST_ANGLE", coast_angle, &
142  default=11.3, do_not_log=.true.)
143 
144  coast_angle = coast_angle * (atan(1.0)/45.) ! Convert to radians
145  right_angle = 2 * atan(1.0)
146 
147  do j=g%jsc,g%jec ; do i=g%isc,g%iec
148  d(i,j)=max_depth
149  ! Southern side
150  if ((g%geoLonT(i,j) > coast_offset) .AND. &
151  (atan2(g%geoLatT(i,j),g%geoLonT(i,j) - coast_offset) < &
152  coast_angle)) d(i,j)=0.5*min_depth
153  ! Northern side
154  if ((g%geoLonT(i,j) < g%len_lon - coast_offset) .AND. &
155  (atan2(g%len_lat - g%geoLatT(i,j),g%len_lon - coast_offset - g%geoLonT(i,j)) < &
156  coast_angle)) d(i,j)=0.5*min_depth
157  ! Western side
158  if ((g%geoLonT(i,j) < coast_offset) .AND. &
159  (atan2(g%geoLatT(i,j),g%geoLonT(i,j) - coast_offset) > &
160  right_angle + coast_angle)) d(i,j)=0.5*min_depth
161  ! Eastern side
162  if ((g%geoLonT(i,j) > g%len_lon - coast_offset) .AND. &
163  (atan2(g%len_lat - g%geoLatT(i,j),g%len_lon - coast_offset - g%geoLonT(i,j)) > &
164  right_angle + coast_angle)) d(i,j)=0.5*min_depth
165 
166  if (d(i,j) > max_depth) d(i,j) = max_depth
167  if (d(i,j) < min_depth) d(i,j) = 0.5*min_depth
168  enddo ; enddo
169 
170 end subroutine kelvin_initialize_topography
171 
172 !> This subroutine sets the properties of flow at open boundary conditions.
173 subroutine kelvin_set_obc_data(OBC, CS, G, h, Time)
174  type(ocean_obc_type), pointer :: OBC !< This open boundary condition type specifies
175  !! whether, where, and what open boundary
176  !! conditions are used.
177  type(kelvin_obc_cs), pointer :: CS !< Kelvin wave control structure.
178  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
179  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< layer thickness.
180  type(time_type), intent(in) :: Time !< model time.
181 
182  ! The following variables are used to set up the transport in the Kelvin example.
183  real :: time_sec, cff
184  real :: PI
185  integer :: i, j, k, n, is, ie, js, je, isd, ied, jsd, jed, nz
186  integer :: IsdB, IedB, JsdB, JedB
187  real :: fac, x, y, x1, y1
188  real :: val1, val2, sina, cosa
189  type(obc_segment_type), pointer :: segment
191  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
192  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
193  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
194 
195  if (.not.associated(obc)) call mom_error(fatal, 'Kelvin_initialization.F90: '// &
196  'Kelvin_set_OBC_data() was called but OBC type was not initialized!')
197 
198  time_sec = time_type_to_real(time)
199  pi = 4.0*atan(1.0)
200  fac = 1.0
201 
202  if (cs%mode == 0) then
203  cs%omega = 2.0 * pi / (12.42 * 3600.0) ! M2 Tide period
204  val1 = sin(cs%omega * time_sec)
205  else
206  cs%N0 = sqrt(cs%rho_range / cs%rho_0 * g%g_Earth * cs%H0)
207  ! Two wavelengths in domain
208  cs%plx = 4.0 * pi / g%len_lon
209  cs%pmz = pi * cs%mode / cs%H0
210  cs%lambda = cs%pmz * cs%F_0 / cs%N0
211  cs%omega = cs%F_0 * cs%plx / cs%lambda
212  endif
213 
214  sina = sin(cs%coast_angle)
215  cosa = cos(cs%coast_angle)
216  do n=1,obc%number_of_segments
217  segment => obc%segment(n)
218  if (.not. segment%on_pe) cycle
219  ! Apply values to the inflow end only.
220  if (segment%direction == obc_direction_e) cycle
221  if (segment%direction == obc_direction_n) cycle
222 
223  ! This should be somewhere else...
224  segment%Tnudge_in = 1.0/(0.3*86400)
225 
226  if (segment%direction == obc_direction_w) then
227  isdb = segment%HI%IsdB ; iedb = segment%HI%IedB
228  jsd = segment%HI%jsd ; jed = segment%HI%jed
229  do j=jsd,jed ; do i=isdb,iedb
230  x1 = 1000. * g%geoLonCu(i,j)
231  y1 = 1000. * g%geoLatCu(i,j)
232  x = (x1 - cs%coast_offset) * cosa + y1 * sina
233  y = - (x1 - cs%coast_offset) * sina + y1 * cosa
234  if (cs%mode == 0) then
235  cff = sqrt(g%g_Earth * 0.5 * (g%bathyT(i+1,j) + g%bathyT(i,j)))
236  val2 = fac * exp(- cs%F_0 * y / cff)
237  segment%eta(i,j) = val2 * cos(cs%omega * time_sec)
238  segment%normal_vel_bt(i,j) = val1 * cff * cosa / &
239  (0.5 * (g%bathyT(i+1,j) + g%bathyT(i,j))) * val2
240  else
241  segment%eta(i,j) = 0.0
242  segment%normal_vel_bt(i,j) = 0.0
243  do k=1,nz
244  segment%nudged_normal_vel(i,j,k) = fac * cs%lambda / cs%F_0 * &
245  exp(- cs%lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * &
246  cos(cs%omega * time_sec)
247  enddo
248  endif
249  enddo ; enddo
250  else
251  isd = segment%HI%isd ; ied = segment%HI%ied
252  jsdb = segment%HI%JsdB ; jedb = segment%HI%JedB
253  do j=jsdb,jedb ; do i=isd,ied
254  x1 = 1000. * g%geoLonCv(i,j)
255  y1 = 1000. * g%geoLatCv(i,j)
256  x = (x1 - cs%coast_offset) * cosa + y1 * sina
257  y = - (x1 - cs%coast_offset) * sina + y1 * cosa
258  if (cs%mode == 0) then
259  cff = sqrt(g%g_Earth * 0.5 * (g%bathyT(i,j+1) + g%bathyT(i,j)))
260  val2 = fac * exp(- 0.5 * (g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j)) * y / cff)
261  segment%eta(i,j) = val2 * cos(cs%omega * time_sec)
262  segment%normal_vel_bt(i,j) = val1 * cff * sina / &
263  (0.5 * (g%bathyT(i+1,j) + g%bathyT(i,j))) * val2
264  else
265  segment%eta(i,j) = 0.0
266  segment%normal_vel_bt(i,j) = 0.0
267  do k=1,nz
268  segment%nudged_normal_vel(i,j,k) = fac * cs%lambda / cs%F_0 * &
269  exp(- cs%lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * cosa
270  enddo
271  endif
272  enddo ; enddo
273  endif
274  enddo
275 
276 end subroutine kelvin_set_obc_data
277 
278 !> \class Kelvin_Initialization
279 !!
280 !! The module configures the model for the Kelvin wave experiment.
281 !! Kelvin = coastally-trapped Kelvin waves from the ROMS examples.
282 !! Initialize with level surfaces and drive the wave in at the west,
283 !! radiate out at the east.
284 end module kelvin_initialization
integer, parameter, public obc_direction_s
Indicates the boundary is an effective southern boundary.
subroutine, public kelvin_set_obc_data(OBC, CS, G, h, Time)
This subroutine sets the properties of flow at open boundary conditions.
integer, parameter, public obc_direction_w
Indicates the boundary is an effective western boundary.
integer, parameter, public obc_direction_n
Indicates the boundary is an effective northern boundary.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Open boundary segment data structure.
subroutine, public register_obc(name, param_file, Reg)
register open boundary objects for boundary updates.
subroutine, public kelvin_obc_end(CS)
Clean up the Kelvin wave OBC from registry.
subroutine, public kelvin_initialize_topography(D, G, param_file, max_depth)
This subroutine sets up the Kelvin topography and land mask.
Type to carry basic OBC information needed for updating values.
logical function, public is_root_pe()
subroutine, public mom_mesg(message, verb, all_print)
integer, parameter, public obc_direction_e
Indicates the boundary is an effective eastern boundary.
logical function, public register_kelvin_obc(param_file, CS, OBC_Reg)
Add Kelvin wave to OBC registry.
Control structure for Kelvin wave open boundaries.
integer, parameter, public obc_none
Controls where open boundary conditions are applied.
subroutine, public mom_error(level, message, all_print)