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