34 implicit none ;
private 36 #include <MOM_memory.h> 44 real :: coast_angle = 0
45 real :: coast_offset = 0
58 #include "version_variable.h" 67 logical :: register_Kelvin_OBC
68 character(len=40) :: mdl =
"register_Kelvin_OBC" 69 character(len=32) :: casename =
"Kelvin wave" 70 character(len=200) :: config
72 if (
associated(cs))
then 73 call mom_error(warning,
"register_Kelvin_OBC called with an "// &
74 "associated control structure.")
80 call get_param(param_file, mdl,
"KELVIN_WAVE_MODE", cs%mode, &
81 "Vertical Kelvin wave mode imposed at upstream open boundary.", &
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.)
95 cs%coast_offset = cs%coast_offset * 1.e3
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.)
107 call register_obc(casename, param_file, obc_reg)
108 register_kelvin_obc = .true.
116 if (
associated(cs))
then 125 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: D
127 real,
intent(in) :: max_depth
129 character(len=40) :: mdl =
"Kelvin_initialize_topography" 132 real :: coast_offset, coast_angle, right_angle
135 call mom_mesg(
" Kelvin_initialization.F90, Kelvin_initialize_topography: setting topography", 5)
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.)
144 coast_angle = coast_angle * (atan(1.0)/45.)
145 right_angle = 2 * atan(1.0)
147 do j=g%jsc,g%jec ;
do i=g%isc,g%iec
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
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
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
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
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
179 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
180 type(time_type),
intent(in) :: Time
183 real :: time_sec, cff
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
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
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!')
198 time_sec = time_type_to_real(time)
202 if (cs%mode == 0)
then 203 cs%omega = 2.0 * pi / (12.42 * 3600.0)
204 val1 = sin(cs%omega * time_sec)
206 cs%N0 = sqrt(cs%rho_range / cs%rho_0 * g%g_Earth * cs%H0)
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
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
220 if (segment%direction == obc_direction_e) cycle
221 if (segment%direction == obc_direction_n) cycle
224 segment%Tnudge_in = 1.0/(0.3*86400)
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
241 segment%eta(i,j) = 0.0
242 segment%normal_vel_bt(i,j) = 0.0
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)
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
265 segment%eta(i,j) = 0.0
266 segment%normal_vel_bt(i,j) = 0.0
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
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.
Provides the ocean grid type.
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)