47 real(kind=
rp),
intent(in) :: z, l_ob, z0
53 real(kind=
rp),
intent(in) :: z, l_ob, z0h
59 real(kind=
rp),
intent(in) :: z, l_ob
65 real(kind=
rp),
intent(in) :: z, l_ob
69 function f_interface(Ri_b, z, z0, z0h, Pr, L_ob, slaw_m, slaw_h)
result(f)
71 real(kind=
rp),
intent(in) :: ri_b, z, z0, z0h, l_ob, pr
78 slaw_m, slaw_h, fd_h)
result(dfdl)
80 real(kind=
rp),
intent(in) :: l_upper, l_lower, z, z0, z0h, l_ob, fd_h, pr
107 character(len=*),
intent(in) :: bc_type
108 real(kind=
rp),
intent(in) :: hi, ti, kappa, utau, z0h, bc_value, pr
109 real(kind=
rp),
intent(inout) :: q,ts
110 select case (bc_type)
118 q = (kappa/pr)*utau*(ts - ti)/log(hi/z0h)
122 call neko_error(
"Invalid specified temperature b.c. type " // &
123 "('neumann' or 'dirichlet'?)")
128 subroutine compute_ri_b(bc_type, g_dot_n, hi, ti, ts, magu, kappa, q, &
130 character(len=*),
intent(in) :: bc_type
131 real(kind=
rp),
intent(in) :: hi, ti, ts, pr
132 real(kind=
rp),
intent(in) :: magu, kappa, g_dot_n
133 real(kind=
rp),
intent(inout) :: q, ri_b
135 select case (bc_type)
137 ri_b = - g_dot_n*hi / ti*q*pr / (magu**3*kappa**2)
139 ri_b = g_dot_n*hi/ti*(ti - ts)/magu**2
141 call neko_error(
"Invalid specified temperature b.c. type " // &
142 "('neumann' or 'dirichlet'?)")
149 real(kind=
rp),
intent(in) :: ri_b, ri_threshold
151 if (ri_b > ri_threshold)
then
156 elseif (ri_b < -ri_threshold)
then
170 n_x, n_y, n_z, h, tau_x, tau_y, tau_z, n_nodes, &
171 kappa, mu_w, rho_w, g_vec, Pr, z0, z0h_in, bc_type, bc_value, tstep, &
172 Ri_b_diagn, L_ob_diagn, utau_diagn, magu_diagn, ti_diagn, ts_diagn,&
174 integer,
intent(in) :: n_nodes, tstep
175 real(kind=
rp),
dimension(n_nodes),
intent(in) :: u, v, w, temp, temp_w
176 real(kind=
rp),
dimension(n_nodes),
intent(in) :: n_x, n_y, n_z, h
177 real(kind=
rp),
intent(in) :: kappa, z0, z0h_in, bc_value, pr
178 real(kind=
rp),
dimension(3),
intent(in) :: g_vec
179 real(kind=
rp),
dimension(n_nodes),
intent(in) :: mu_w, rho_w
180 real(kind=
rp) :: g_dot_n
181 character(len=*),
intent(in) :: bc_type
182 real(kind=
rp),
dimension(n_nodes),
intent(inout) :: tau_x, tau_y, tau_z
183 real(kind=
rp) :: ui, vi, wi, hi, rho, mu
184 real(kind=
rp) :: normu, z0h
185 real(kind=
rp) :: l_upper, l_lower, l_old
186 real(kind=
rp) :: f, dfdl, fd_h, l_new, l_sign
188 integer,
parameter :: max_count = 50
189 real(kind=
rp),
parameter :: tol = 0.001_rp
190 real(kind=
rp),
parameter :: nr_step = 0.001_rp
191 real(kind=
rp),
parameter :: ri_threshold = 0.0001_rp
192 character(len=LOG_SIZE) :: log_buf
193 real(kind=
rp) :: utau, ri_b, l_ob, magu, q, ti, ts
194 real(kind=
rp),
dimension(n_nodes),
intent(inout) :: ri_b_diagn, l_ob_diagn
195 real(kind=
rp),
dimension(n_nodes),
intent(inout) :: utau_diagn, magu_diagn
196 real(kind=
rp),
dimension(n_nodes),
intent(inout) :: ti_diagn, ts_diagn
197 real(kind=
rp),
dimension(n_nodes),
intent(inout) :: q_diagn
213 normu = ui * n_x(i) + vi * n_y(i) + wi * n_z(i)
214 ui = ui - normu * n_x(i)
215 vi = vi - normu * n_y(i)
216 wi = wi - normu * n_z(i)
219 magu = sqrt(ui**2 + vi**2 + wi**2)
220 magu =
max(magu, 1.0e-6_rp)
221 utau = magu*kappa / log(hi/z0)
226 z0h = z0 * exp(z0h_in*sqrt((utau*z0)/(mu/rho)))
237 g_dot_n = abs(g_vec(1)*n_x(i) + g_vec(2)*n_y(i) + g_vec(3)*n_z(i))
240 call compute_ri_b(bc_type, g_dot_n, hi, ti, ts, magu, kappa, q, pr, ri_b)
243 if (abs((ri_b)) <= ri_threshold)
then
248 if ((ri_b) > 0.0_rp)
then
249 l_ob = hi /
max(ri_b, ri_threshold)
252 l_ob = hi / min(ri_b, -ri_threshold)
260 do while ((abs(l_old - l_ob) / abs(l_ob) > tol) .and. &
267 l_upper = l_ob + fd_h
268 l_lower = l_ob - fd_h
272 dfdl =
dfdl_ptr(l_upper, l_lower, hi, z0, z0h, pr, l_ob, &
274 if (abs(dfdl) < 1.0e-12_rp)
then
277 l_new = l_ob - f/dfdl
279 if (l_new*l_sign <= 0.0_rp)
then
281 l_new = 0.5_rp * l_ob
284 l_ob = sign(
max(abs(l_new), 1.0e-8_rp), l_sign)
285 l_ob = sign(min(abs(l_ob), 1.0e8_rp), l_sign)
288 if (abs(l_ob) > 5e5_rp .or. abs(l_ob) < 1e-6_rp)
then
291 call neko_warning(
"Obukhov length did not converge " // &
296 if (.not.
associated(
f_ptr) .or. .not.
associated(
dfdl_ptr))
then
297 call neko_error(
"Unassociated pointer for f or dfdl")
302 select case (bc_type)
310 q = kappa/pr*utau*(ts - ti)/
slaw_h_ptr(hi, l_ob, z0h)
312 call neko_error(
"Invalid specified temperature b.c. type " // &
313 "('neumann' or 'dirichlet'?)")
318 magu =
max(magu, 1.0e-6_rp)
319 tau_x(i) = -rho * utau**2 * ui / magu
320 tau_y(i) = -rho * utau**2 * vi / magu
321 tau_z(i) = -rho * utau**2 * wi / magu
328 ts_diagn(i) = temp_w(i)
342 real(kind=
rp),
intent(in) :: z, l_ob, z0
343 real(kind=
rp) :: slaw
349 real(kind=
rp),
intent(in) :: z,l_ob,z0h
350 real(kind=
rp) :: slaw
356 real(kind=
rp),
intent(in) :: z, l_ob
357 real(kind=
rp) :: corr
358 real(kind=
rp) :: a, b, c, d
359 real(kind=
rp) :: zeta
366 corr = - a*zeta - b*(zeta-c/d)*exp(-d*zeta) - b*c/d
370 real(kind=
rp),
intent(in) :: z, l_ob
371 real(kind=
rp) :: corr
372 real(kind=
rp) :: a, b, c, d
373 real(kind=
rp) :: zeta
381 corr = -b * (zeta - c / d) * exp(-d * zeta) - &
382 (1.0_rp + 2.0_rp / 3.0_rp * a * zeta)**1.5_rp - b * c / d + &
394 real(kind=
rp),
intent(in) :: z, l_ob, z0
395 real(kind=
rp) :: slaw
401 real(kind=
rp),
intent(in) :: z, l_ob, z0h
402 real(kind=
rp) :: slaw
409 real(kind=
rp),
intent(in) :: z, l_ob
410 real(kind=
rp) :: xi,
pi, zeta
411 real(kind=
rp) :: corr
416 xi = (1.0_rp - 16.0_rp*zeta)**0.25_rp
417 corr = 2*log(0.5_rp*(1 + xi)) + log(0.5_rp*(1 + xi**2)) - 2*atan(xi) +
pi/2
421 real(kind=
rp),
intent(in) :: z, l_ob
422 real(kind=
rp) :: zeta,
pi, xi
423 real(kind=
rp) :: corr
428 xi = (1.0_rp - 16.0_rp*zeta)**0.25_rp
429 corr = 2*log(0.5_rp*(1 + xi**2))
434 real(kind=
rp),
intent(in) :: z, l_ob, z0
435 real(kind=
rp) :: slaw
441 real(kind=
rp),
intent(in) :: z, l_ob, z0h
442 real(kind=
rp) :: slaw
448 function f_neumann(Ri_b, z, z0, z0h, Pr, L_ob, slaw_m, slaw_h)
result(f)
449 real(kind=
rp),
intent(in) :: ri_b, z, z0, z0h, l_ob, pr
454 f = (ri_b - pr*z/l_ob/slaw_m(z, l_ob, z0)**3)
458 slaw_m, slaw_h, fd_h)
result(dfdl)
459 real(kind=
rp),
intent(in) :: l_upper, l_lower, z, z0, z0h, l_ob, fd_h, pr
462 real(kind=
rp) :: dfdl
464 dfdl = (-z/l_upper/slaw_m(z, l_upper, z0)**3)
465 dfdl = dfdl + (z/l_lower/slaw_m(z, l_lower, z0)**3)
466 dfdl = pr*dfdl/(2*fd_h)
469 function f_dirichlet(Ri_b, z, z0, z0h, Pr, L_ob, slaw_m, slaw_h)
result(f)
470 real(kind=
rp),
intent(in) :: ri_b, z, z0, z0h, l_ob, pr
475 f = (ri_b - pr*z/l_ob*slaw_h(z, l_ob, z0h)/slaw_m(z, l_ob, z0)**2)
479 slaw_m, slaw_h, fd_h)
result(dfdl)
480 real(kind=
rp),
intent(in) :: l_upper, l_lower, z, z0, z0h, l_ob, fd_h, pr
483 real(kind=
rp) :: dfdl
485 dfdl = (-z / l_upper * slaw_h(z, l_upper, z0h) / &
486 slaw_m(z, l_upper, z0)**2)
487 dfdl = dfdl + (z / l_lower * slaw_h(z, l_lower, z0h) / &
488 slaw_m(z, l_lower, z0)**2)
489 dfdl = pr*dfdl/(2*fd_h)
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
real(kind=rp), parameter, public pi
real(kind=rp) function, public glsum(a, n)
Sum a vector of length n.
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
Implements the CPU kernel for the most_t type.
real(kind=rp) function slaw_m_stable(z, l_ob, z0)
Similarity laws and corrections for the STABLE regime: REFERENCE: Holtslag, A. A. M....
real(kind=rp) function corr_m_convective(z, l_ob)
real(kind=rp) function corr_h_convective(z, l_ob)
real(kind=rp) function f_neumann(ri_b, z, z0, z0h, pr, l_ob, slaw_m, slaw_h)
Simialrity laws (different for neumann and dirichlet bc's)
real(kind=rp) function slaw_m_neutral(z, l_ob, z0)
Similarity laws and corrections for the NEUTRAL regime:
procedure(slaw_m_interface), pointer slaw_m_ptr
subroutine compute_ri_b(bc_type, g_dot_n, hi, ti, ts, magu, kappa, q, pr, ri_b)
Computes the Richardson number.
real(kind=rp) function corr_m_stable(z, l_ob)
subroutine set_stability_regime(ri_b, ri_threshold)
Sets the stability regime based on the Richardson number value (quite arbitrary).
procedure(corr_h_interface), pointer corr_h_ptr
procedure(dfdl_interface), pointer dfdl_ptr
real(kind=rp) function slaw_h_neutral(z, l_ob, z0h)
subroutine, public most_compute_cpu(u, v, w, temp, temp_w, n_x, n_y, n_z, h, tau_x, tau_y, tau_z, n_nodes, kappa, mu_w, rho_w, g_vec, pr, z0, z0h_in, bc_type, bc_value, tstep, ri_b_diagn, l_ob_diagn, utau_diagn, magu_diagn, ti_diagn, ts_diagn, q_diagn)
Main routine to compute the surface stresses based on MOST.
procedure(slaw_h_interface), pointer slaw_h_ptr
real(kind=rp) function dfdl_dirichlet(l_upper, l_lower, z, z0, z0h, pr, l_ob, slaw_m, slaw_h, fd_h)
real(kind=rp) function slaw_h_stable(z, l_ob, z0h)
procedure(corr_m_interface), pointer corr_m_ptr
real(kind=rp) function slaw_h_convective(z, l_ob, z0h)
real(kind=rp) function corr_h_stable(z, l_ob)
real(kind=rp) function f_dirichlet(ri_b, z, z0, z0h, pr, l_ob, slaw_m, slaw_h)
procedure(f_interface), pointer f_ptr
real(kind=rp) function slaw_m_convective(z, l_ob, z0)
Similarity laws and corrections for the UNSTABLE (convective) regime: REFERENCE: Dyer,...
subroutine select_bc_operators(bc_type, bc_value, q, ts, ti, kappa, utau, z0h, hi, pr)
Selects different expressions for the similarity functions in MOST based on the type of bottom bounda...
real(kind=rp) function dfdl_neumann(l_upper, l_lower, z, z0, z0h, pr, l_ob, slaw_m, slaw_h, fd_h)
integer, parameter, public rp
Global precision used in computations.
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.