-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a dynamic stress (wave model) to wall_models #1233
base: main
Are you sure you want to change the base?
Changes from all commits
0b38a3e
af9dca8
d544679
413ff04
a81f466
a02e4de
bccef92
019111f
cd538ba
38bdbe7
0dbbeed
8961796
f338263
2ff2142
8c5eff6
6f186b3
e9f91a4
f686cba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#ifndef MOSD_H | ||
#define MOSD_H | ||
|
||
#include "AMReX_AmrCore.H" | ||
#include <AMReX.H> | ||
namespace amr_wind { | ||
struct MOSD | ||
{ | ||
/* | ||
* A dynamic wall model that calculates the stress from wave to wind | ||
* based on geometric information of the wave. | ||
*/ | ||
|
||
amrex::Real amplitude{0.05}; | ||
amrex::Real wavenumber{4}; | ||
amrex::Real omega{0.8}; | ||
amrex::Real time; | ||
|
||
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real get_dyn_tau( | ||
const amrex::Real u_dx, | ||
const amrex::Real v_dx, | ||
const amrex::Real xc, | ||
const amrex::Real unit_nor) const | ||
{ | ||
|
||
// Building the wave surface, gradients, wave velocities and unit normal | ||
const amrex::Real dx_eta_wave = | ||
-amplitude * wavenumber * std::sin(wavenumber * xc - omega * time); | ||
const amrex::Real dy_eta_wave = 0; | ||
const amrex::Real dt_eta_wave = | ||
amplitude * omega * std::sin(wavenumber * xc - omega * time); | ||
const amrex::Real grad_eta_wave = | ||
std::sqrt(dx_eta_wave * dx_eta_wave + dy_eta_wave * dy_eta_wave); | ||
const amrex::Real Cx_wave = | ||
-dt_eta_wave * dx_eta_wave * (1 / (grad_eta_wave * grad_eta_wave)); | ||
const amrex::Real Cy_wave = | ||
-dt_eta_wave * dy_eta_wave * (1 / (grad_eta_wave * grad_eta_wave)); | ||
const amrex::Real n_x = dx_eta_wave / grad_eta_wave; | ||
const amrex::Real n_y = dy_eta_wave / grad_eta_wave; | ||
|
||
// Calculating the relative velocity, heaviside function | ||
const amrex::Real u_r = u_dx - Cx_wave; | ||
const amrex::Real v_r = v_dx - Cy_wave; | ||
const amrex::Real ur_mag = | ||
std::sqrt(u_r * u_r * n_x * n_x + v_r * v_r * n_y * n_y); | ||
const amrex::Real Heavi_arg = (u_r * dx_eta_wave + v_r * dy_eta_wave); | ||
const amrex::Real Heavi = | ||
(Heavi_arg + std::abs(Heavi_arg)) / (2 * Heavi_arg); | ||
|
||
// Calculating the magnitude of the stress | ||
return (1 / M_PI) * ur_mag * ur_mag * grad_eta_wave * grad_eta_wave * | ||
Heavi * (unit_nor == 0 ? n_x : n_y); | ||
} | ||
}; | ||
|
||
} // namespace amr_wind | ||
#endif /* MOSD_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ WallFunction::WallFunction(CFDSim& sim) | |
{ | ||
amrex::Real mu; | ||
amrex::Real rho{1.0}; | ||
|
||
{ | ||
amrex::ParmParse pp("BodyForce"); | ||
amrex::Vector<amrex::Real> body_force{0.0, 0.0, 0.0}; | ||
|
@@ -44,6 +45,13 @@ WallFunction::WallFunction(CFDSim& sim) | |
(geom.ProbLo(m_direction) + | ||
(m_log_law.ref_index + 0.5) * geom.CellSize(m_direction)); | ||
} | ||
{ | ||
amrex::ParmParse pp( | ||
"wave_mosd"); // "wave_mosd" is the prefix used in the input file | ||
pp.query("amplitude", m_mosd.amplitude); | ||
pp.query("wavenumber", m_mosd.wavenumber); | ||
pp.query("frequency", m_mosd.omega); | ||
} | ||
} | ||
|
||
VelWallFunc::VelWallFunc(Field& /*unused*/, WallFunction& wall_func) | ||
|
@@ -55,7 +63,8 @@ VelWallFunc::VelWallFunc(Field& /*unused*/, WallFunction& wall_func) | |
|
||
if (m_wall_shear_stress_type == "constant" || | ||
m_wall_shear_stress_type == "log_law" || | ||
m_wall_shear_stress_type == "schumann") { | ||
m_wall_shear_stress_type == "schumann" || | ||
m_wall_shear_stress_type == "mosd") { | ||
amrex::Print() << "Shear Stress model: " << m_wall_shear_stress_type | ||
<< std::endl; | ||
} else { | ||
|
@@ -92,6 +101,9 @@ void VelWallFunc::wall_model( | |
const auto& vold_lev = velocity.state(FieldState::Old)(lev); | ||
const auto& eta_lev = viscosity(lev); | ||
|
||
const auto& problo = geom.ProbLoArray(); | ||
const auto& dx = geom.CellSizeArray(); | ||
|
||
if (amrex::Gpu::notInLaunchRegion()) { | ||
mfi_info.SetDynamic(true); | ||
} | ||
|
@@ -116,14 +128,103 @@ void VelWallFunc::wall_model( | |
const amrex::Real vv = | ||
vold_arr(i, j, k + idx_offset, 1); | ||
const amrex::Real wspd = std::sqrt(uu * uu + vv * vv); | ||
// Dirichlet BC | ||
varr(i, j, k - 1, 2) = 0.0; | ||
const amrex::Real xc = problo[0] + (i + 0.5) * dx[0]; | ||
|
||
// Shear stress BC | ||
varr(i, j, k - 1, 0) = | ||
tau.get_shear(uu, wspd) / mu * den(i, j, k); | ||
varr(i, j, k - 1, 1) = | ||
tau.get_shear(vv, wspd) / mu * den(i, j, k); | ||
// Check if dx[0] > dx[2] | ||
if (dx[0] <= dx[2]) { | ||
// Handle the case where dx[0] <= dx[2] | ||
// Use the nearest cell value without interpolation | ||
const int k_nearest = | ||
static_cast<int>(std::round(dx[0] / dx[2])); | ||
const amrex::Real u_dx = | ||
vold_arr(i, j, k_nearest, 0); | ||
const amrex::Real v_dx = | ||
vold_arr(i, j, k_nearest, 1); | ||
|
||
varr(i, j, k - 1, 0) = | ||
tau.get_shear(uu, wspd, u_dx, v_dx, xc, 0) / | ||
mu * den(i, j, k); | ||
varr(i, j, k - 1, 1) = | ||
tau.get_shear(vv, wspd, u_dx, v_dx, xc, 1) / | ||
mu * den(i, j, k); | ||
} else { | ||
// Case where dx[0] > dx[2] | ||
const int k_lo = static_cast<int>( | ||
std::floor(dx[0] / dx[2] - 0.5)); | ||
const int k_hi = k_lo + 1; | ||
|
||
// Ensure the interpolation points are within the | ||
// valid box | ||
if (bx.contains(amrex::IntVect(i, j, k_lo)) && | ||
bx.contains(amrex::IntVect(i, j, k_hi))) { | ||
const amrex::Real z_lo = (k_lo + 0.5) * dx[2]; | ||
const amrex::Real z_hi = (k_hi + 0.5) * dx[2]; | ||
const amrex::Real z_interp = dx[0]; | ||
|
||
// Check if the interpolation condition is | ||
// satisfied | ||
if (z_lo < z_interp && z_interp < z_hi) { | ||
const amrex::Real weight = | ||
(z_interp - z_lo) / (z_hi - z_lo); | ||
const amrex::Real u_low = | ||
vold_arr(i, j, k_lo, 0); | ||
const amrex::Real u_up = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor comment, can we change these to |
||
vold_arr(i, j, k_hi, 0); | ||
const amrex::Real v_low = | ||
vold_arr(i, j, k_lo, 1); | ||
const amrex::Real v_up = | ||
vold_arr(i, j, k_hi, 1); | ||
|
||
const amrex::Real u_dx = | ||
u_low + (u_up - u_low) * weight; | ||
const amrex::Real v_dx = | ||
v_low + (v_up - v_low) * weight; | ||
|
||
varr(i, j, k - 1, 0) = | ||
tau.get_shear( | ||
uu, wspd, u_dx, v_dx, xc, 0) / | ||
mu * den(i, j, k); | ||
varr(i, j, k - 1, 1) = | ||
tau.get_shear( | ||
vv, wspd, u_dx, v_dx, xc, 1) / | ||
mu * den(i, j, k); | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious, when do we expect this branch to occur? |
||
// Fallback: use nearest point if | ||
// interpolation condition is not met | ||
const int k_nearest = | ||
(z_interp - z_lo < z_hi - z_interp) | ||
? k_lo | ||
: k_hi; | ||
const amrex::Real u_dx = | ||
vold_arr(i, j, k_nearest, 0); | ||
const amrex::Real v_dx = | ||
vold_arr(i, j, k_nearest, 1); | ||
|
||
varr(i, j, k - 1, 0) = | ||
tau.get_shear( | ||
uu, wspd, u_dx, v_dx, xc, 0) / | ||
mu * den(i, j, k); | ||
varr(i, j, k - 1, 1) = | ||
tau.get_shear( | ||
vv, wspd, u_dx, v_dx, xc, 1) / | ||
mu * den(i, j, k); | ||
} | ||
} else { | ||
// Fallback: use the original cell value if | ||
// interpolation points are out of bounds | ||
const amrex::Real u_dx = vold_arr(i, j, k, 0); | ||
const amrex::Real v_dx = vold_arr(i, j, k, 1); | ||
|
||
varr(i, j, k - 1, 0) = | ||
tau.get_shear(uu, wspd, u_dx, v_dx, xc, 0) / | ||
mu * den(i, j, k); | ||
varr(i, j, k - 1, 1) = | ||
tau.get_shear(vv, wspd, u_dx, v_dx, xc, 1) / | ||
mu * den(i, j, k); | ||
} | ||
} | ||
|
||
varr(i, j, k - 1, 2) = 0.0; | ||
}); | ||
} | ||
|
||
|
@@ -143,9 +244,11 @@ void VelWallFunc::wall_model( | |
|
||
// Shear stress BC | ||
varr(i, j, k, 0) = | ||
-tau.get_shear(uu, wspd) / mu * den(i, j, k); | ||
-tau.get_shear(uu, wspd, 0, 0, 0, 0) / mu * | ||
den(i, j, k); | ||
varr(i, j, k, 1) = | ||
-tau.get_shear(vv, wspd) / mu * den(i, j, k); | ||
-tau.get_shear(vv, wspd, 0, 0, 0, 1) / mu * | ||
den(i, j, k); | ||
}); | ||
} | ||
} | ||
|
@@ -238,6 +341,12 @@ void VelWallFunc::operator()(Field& velocity, const FieldState rho_state) | |
m_wall_func.update_umean(); | ||
auto tau = SimpleShearSchumann(m_wall_func.log_law()); | ||
wall_model(velocity, rho_state, tau); | ||
} else if (m_wall_shear_stress_type == "mosd") { | ||
m_wall_func.update_umean(); | ||
m_wall_func.update_utau_mean(); | ||
m_wall_func.update_time(); | ||
auto tau = SimpleShearMOSD(m_wall_func.log_law(), m_wall_func.mosd()); | ||
wall_model(velocity, rho_state, tau); | ||
} | ||
} | ||
|
||
|
@@ -249,4 +358,6 @@ void WallFunction::update_umean() | |
} | ||
|
||
void WallFunction::update_utau_mean() { m_log_law.update_utau_mean(); } | ||
|
||
void WallFunction::update_time() { m_mosd.time = m_sim.time().current_time(); } | ||
} // namespace amr_wind |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be
z_lo <= z_interp
? Exampledx[0] = 1.5 * dx[2]