23 implicit none ;
private 25 #include <MOM_memory.h> 27 public kelvin_set_obc_data, kelvin_initialize_topography
28 public register_kelvin_obc, kelvin_obc_end
38 real :: coast_angle = 0
39 real :: coast_offset1 = 0
40 real :: coast_offset2 = 0
48 #include "version_variable.h" 53 function register_kelvin_obc(param_file, CS, OBC_Reg)
59 logical :: register_Kelvin_OBC
60 character(len=40) :: mdl =
"register_Kelvin_OBC" 61 character(len=32) :: casename =
"Kelvin wave" 62 character(len=200) :: config
64 if (
associated(cs))
then 65 call mom_error(warning,
"register_Kelvin_OBC called with an "// &
66 "associated control structure.")
72 call get_param(param_file, mdl,
"KELVIN_WAVE_MODE", cs%mode, &
73 "Vertical Kelvin wave mode imposed at upstream open boundary.", &
75 call get_param(param_file, mdl,
"F_0", cs%F_0, &
76 default=0.0, do_not_log=.true.)
77 call get_param(param_file, mdl,
"TOPO_CONFIG", config, do_not_log=.true.)
78 if (trim(config) ==
"Kelvin")
then 79 call get_param(param_file, mdl,
"ROTATED_COAST_OFFSET_1", cs%coast_offset1, &
80 "The distance along the southern and northern boundaries "//&
81 "at which the coasts angle in.", &
82 units=
"km", default=100.0)
83 call get_param(param_file, mdl,
"ROTATED_COAST_OFFSET_2", cs%coast_offset2, &
84 "The distance from the southern and northern boundaries "//&
85 "at which the coasts angle in.", &
86 units=
"km", default=10.0)
87 call get_param(param_file, mdl,
"ROTATED_COAST_ANGLE", cs%coast_angle, &
88 "The angle of the southern bondary beyond X=ROTATED_COAST_OFFSET.", &
89 units=
"degrees", default=11.3)
90 cs%coast_angle = cs%coast_angle * (atan(1.0)/45.)
91 cs%coast_offset1 = cs%coast_offset1 * 1.e3
92 cs%coast_offset2 = cs%coast_offset2 * 1.e3
94 if (cs%mode /= 0)
then 95 call get_param(param_file, mdl,
"DENSITY_RANGE", cs%rho_range, &
96 default=2.0, do_not_log=.true.)
97 call get_param(param_file, mdl,
"RHO_0", cs%rho_0, &
98 default=1035.0, do_not_log=.true.)
99 call get_param(param_file, mdl,
"MAXIMUM_DEPTH", cs%H0, &
100 default=1000.0, do_not_log=.true.)
104 call register_obc(casename, param_file, obc_reg)
105 register_kelvin_obc = .true.
107 end function register_kelvin_obc
110 subroutine kelvin_obc_end(CS)
113 if (
associated(cs))
then 116 end subroutine kelvin_obc_end
120 subroutine kelvin_initialize_topography(D, G, param_file, max_depth, US)
122 real,
dimension(G%isd:G%ied,G%jsd:G%jed), &
125 real,
intent(in) :: max_depth
129 character(len=40) :: mdl =
"Kelvin_initialize_topography" 133 real :: coast_offset1, coast_offset2, coast_angle, right_angle
136 call mom_mesg(
" Kelvin_initialization.F90, Kelvin_initialize_topography: setting topography", 5)
138 m_to_z = 1.0 ;
if (
present(us)) m_to_z = us%m_to_Z
140 call get_param(param_file, mdl,
"MINIMUM_DEPTH", min_depth, &
141 "The minimum depth of the ocean.", units=
"m", default=0.0, scale=m_to_z)
142 call get_param(param_file, mdl,
"ROTATED_COAST_OFFSET_1", coast_offset1, &
143 default=100.0, do_not_log=.true.)
144 call get_param(param_file, mdl,
"ROTATED_COAST_OFFSET_2", coast_offset2, &
145 default=10.0, do_not_log=.true.)
146 call get_param(param_file, mdl,
"ROTATED_COAST_ANGLE", coast_angle, &
147 default=11.3, do_not_log=.true.)
149 coast_angle = coast_angle * (atan(1.0)/45.)
150 right_angle = 2 * atan(1.0)
152 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
155 if ((g%geoLonT(i,j) - g%west_lon > coast_offset1) .AND. &
156 (atan2(g%geoLatT(i,j) - g%south_lat + coast_offset2, &
157 g%geoLonT(i,j) - g%west_lon - coast_offset1) < coast_angle)) &
158 d(i,j) = 0.5*min_depth
160 if ((g%geoLonT(i,j) - g%west_lon < g%len_lon - coast_offset1) .AND. &
161 (atan2(g%len_lat + g%south_lat + coast_offset2 - g%geoLatT(i,j), &
162 g%len_lon + g%west_lon - coast_offset1 - g%geoLonT(i,j)) < coast_angle)) &
163 d(i,j) = 0.5*min_depth
165 if (d(i,j) > max_depth) d(i,j) = max_depth
166 if (d(i,j) < min_depth) d(i,j) = 0.5*min_depth
169 end subroutine kelvin_initialize_topography
172 subroutine kelvin_set_obc_data(OBC, CS, G, GV, US, h, Time)
180 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
181 type(time_type),
intent(in) :: Time
184 real :: time_sec, cff
191 integer :: i, j, k, n, is, ie, js, je, isd, ied, jsd, jed, nz
192 integer :: IsdB, IedB, JsdB, JedB
193 real :: fac, x, y, x1, y1
194 real :: val1, val2, sina, cosa
197 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
198 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
199 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
201 if (.not.
associated(obc))
call mom_error(fatal,
'Kelvin_initialization.F90: '// &
202 'Kelvin_set_OBC_data() was called but OBC type was not initialized!')
204 time_sec = time_type_to_real(time)
208 if (cs%mode == 0)
then 209 omega = 2.0 * pi / (12.42 * 3600.0)
210 val1 = us%m_to_Z * sin(omega * time_sec)
212 n0 = us%L_to_m*us%s_to_T * sqrt((cs%rho_range / cs%rho_0) * gv%g_Earth * (us%m_to_Z * cs%H0))
214 plx = 4.0 * pi / g%len_lon
215 pmz = pi * cs%mode / cs%H0
216 lambda = pmz * cs%F_0 / n0
217 omega = cs%F_0 * plx / lambda
223 sina = sin(cs%coast_angle)
224 cosa = cos(cs%coast_angle)
225 do n=1,obc%number_of_segments
226 segment => obc%segment(n)
227 if (.not. segment%on_pe) cycle
229 if (segment%direction == obc_direction_e) cycle
230 if (segment%direction == obc_direction_n) cycle
233 segment%Velocity_nudging_timescale_in = 1.0/(0.3*86400)
235 if (segment%direction == obc_direction_w)
then 236 isdb = segment%HI%IsdB ; iedb = segment%HI%IedB
237 jsd = segment%HI%jsd ; jed = segment%HI%jed
238 jsdb = segment%HI%JsdB ; jedb = segment%HI%JedB
239 do j=jsd,jed ;
do i=isdb,iedb
240 x1 = 1000. * g%geoLonCu(i,j)
241 y1 = 1000. * g%geoLatCu(i,j)
242 x = (x1 - cs%coast_offset1) * cosa + y1 * sina
243 y = - (x1 - cs%coast_offset1) * sina + y1 * cosa
244 if (cs%mode == 0)
then 246 cff = sqrt(gv%g_Earth * g%bathyT(i+1,j) )
247 val2 = fac * exp(- us%T_to_s*cs%F_0 * us%m_to_L*y / cff)
248 segment%eta(i,j) = val2 * cos(omega * time_sec)
249 segment%normal_vel_bt(i,j) = (val2 * (val1 * cff * cosa / &
250 (g%bathyT(i+1,j) )) )
251 if (segment%nudged)
then 253 segment%nudged_normal_vel(i,j,k) = (val2 * (val1 * cff * cosa / &
256 elseif (segment%specified)
then 258 segment%normal_vel(i,j,k) = (val2 * (val1 * cff * cosa / &
259 (g%bathyT(i+1,j) )) )
260 segment%normal_trans(i,j,k) = segment%normal_vel(i,j,k) * h(i+1,j,k) * g%dyCu(i,j)
265 segment%eta(i,j) = 0.0
266 segment%normal_vel_bt(i,j) = 0.0
267 if (segment%nudged)
then 269 segment%nudged_normal_vel(i,j,k) = us%m_s_to_L_T * fac * lambda / cs%F_0 * &
270 exp(- lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * &
271 cos(omega * time_sec)
273 elseif (segment%specified)
then 275 segment%normal_vel(i,j,k) = us%m_s_to_L_T * fac * lambda / cs%F_0 * &
276 exp(- lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * &
277 cos(omega * time_sec)
278 segment%normal_trans(i,j,k) = segment%normal_vel(i,j,k) * h(i+1,j,k) * g%dyCu(i,j)
283 if (
associated(segment%tangential_vel))
then 284 do j=jsdb+1,jedb-1 ;
do i=isdb,iedb
285 x1 = 1000. * g%geoLonBu(i,j)
286 y1 = 1000. * g%geoLatBu(i,j)
287 x = (x1 - cs%coast_offset1) * cosa + y1 * sina
288 y = - (x1 - cs%coast_offset1) * sina + y1 * cosa
289 cff =sqrt(gv%g_Earth * g%bathyT(i+1,j) )
290 val2 = fac * exp(- us%T_to_s*cs%F_0 * us%m_to_L*y / cff)
291 if (cs%mode == 0)
then ;
do k=1,nz
292 segment%tangential_vel(i,j,k) = (val1 * val2 * cff * sina) / &
293 ( 0.5*(g%bathyT(i+1,j+1) + g%bathyT(i+1,j) ) )
299 isd = segment%HI%isd ; ied = segment%HI%ied
300 jsdb = segment%HI%JsdB ; jedb = segment%HI%JedB
301 do j=jsdb,jedb ;
do i=isd,ied
302 x1 = 1000. * g%geoLonCv(i,j)
303 y1 = 1000. * g%geoLatCv(i,j)
304 x = (x1 - cs%coast_offset1) * cosa + y1 * sina
305 y = - (x1 - cs%coast_offset1) * sina + y1 * cosa
306 if (cs%mode == 0)
then 307 cff = sqrt(gv%g_Earth * g%bathyT(i,j+1) )
308 val2 = fac * exp(- 0.5 * (g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j)) * us%m_to_L*y / cff)
309 segment%eta(i,j) = val2 * cos(omega * time_sec)
310 segment%normal_vel_bt(i,j) = us%L_T_to_m_s * (val1 * cff * sina / &
311 (g%bathyT(i,j+1) )) * val2
312 if (segment%nudged)
then 314 segment%nudged_normal_vel(i,j,k) = us%L_T_to_m_s * (val1 * cff * sina / &
315 (g%bathyT(i,j+1) )) * val2
317 elseif (segment%specified)
then 319 segment%normal_vel(i,j,k) = us%L_T_to_m_s * (val1 * cff * sina / &
320 (g%bathyT(i,j+1) )) * val2
321 segment%normal_trans(i,j,k) = segment%normal_vel(i,j,k) * h(i,j+1,k) * g%dxCv(i,j)
326 segment%eta(i,j) = 0.0
327 segment%normal_vel_bt(i,j) = 0.0
328 if (segment%nudged)
then 330 segment%nudged_normal_vel(i,j,k) = us%m_s_to_L_T*fac * lambda / cs%F_0 * &
331 exp(- lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * cosa
333 elseif (segment%specified)
then 335 segment%normal_vel(i,j,k) = us%m_s_to_L_T*fac * lambda / cs%F_0 * &
336 exp(- lambda * y) * cos(pi * cs%mode * (k - 0.5) / nz) * cosa
337 segment%normal_trans(i,j,k) = segment%normal_vel(i,j,k) * h(i,j+1,k) * g%dxCv(i,j)
342 if (
associated(segment%tangential_vel))
then 343 do j=jsdb,jedb ;
do i=isdb+1,iedb-1
344 x1 = 1000. * g%geoLonBu(i,j)
345 y1 = 1000. * g%geoLatBu(i,j)
346 x = (x1 - cs%coast_offset1) * cosa + y1 * sina
347 y = - (x1 - cs%coast_offset1) * sina + y1 * cosa
348 cff = sqrt(gv%g_Earth * g%bathyT(i,j+1) )
349 val2 = fac * exp(- 0.5 * (g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j)) * us%m_to_L*y / cff)
350 if (cs%mode == 0)
then ;
do k=1,nz
351 segment%tangential_vel(i,j,k) = ((val1 * val2 * cff * sina) / &
352 ( 0.5*((g%bathyT(i+1,j+1)) + g%bathyT(i,j+1))) )
359 end subroutine kelvin_set_obc_data
Wraps the FMS time manager functions.
Ocean grid type. See mom_grid for details.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Open boundary segment data structure.
Describes the horizontal ocean grid with only dynamic memory arrays.
The MOM6 facility to parse input files for runtime parameters.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Type to carry basic OBC information needed for updating values.
Routines for error handling and I/O management.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Control structure for Kelvin wave open boundaries.
Configures the model for the Kelvin wave experiment.
Contains a shareable dynamic type for describing horizontal grids and metric data and utilty routines...
Controls where open boundary conditions are applied.
Provides a transparent vertical ocean grid type and supporting routines.
An overloaded interface to read and log the values of various types of parameters.