Skip to content
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

Time varying abl bodyforce #1025

Merged
merged 28 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b2c0607
changes to write abl forcing to text file, add to existing reg test
mbkuhn Apr 19, 2024
4d6097f
reading in body force from file
mbkuhn Apr 19, 2024
9095b85
setting up reg test
mbkuhn Apr 22, 2024
643a923
formatting
mbkuhn Apr 22, 2024
426f56a
using start time and frequency arguments
mbkuhn Apr 23, 2024
b4e3747
write to file with Geostrophic Forcing
mbkuhn Apr 23, 2024
d54adb3
formatting
mbkuhn Apr 23, 2024
56c658e
reverting last change, because Geostrophic Forcing is reversible
mbkuhn Apr 24, 2024
4fab87b
time-varying target velocity for geostrophic wind
mbkuhn Apr 24, 2024
48df5c3
reg test for time-varying geostrophic wind
mbkuhn Apr 24, 2024
04ed32b
updating to use underscores, but keeping backwards-compatible
mbkuhn Apr 24, 2024
4cc838f
removing unused variable
mbkuhn Apr 24, 2024
7026bb8
proliferate m_coriolis_factor (fix issue from last commit)
mbkuhn Apr 24, 2024
db1c52c
Merge branch 'main' into time_varying_abl_bodyforce
mbkuhn Apr 24, 2024
e8630e1
input file documentation
mbkuhn Apr 25, 2024
49a0075
Merge branch 'time_varying_abl_bodyforce' of https://github.com/mbkuh…
mbkuhn Apr 25, 2024
a8762ba
Merge branch 'main' into time_varying_abl_bodyforce
mbkuhn Apr 25, 2024
b10b435
unit test start, better error feedback
mbkuhn Apr 29, 2024
06e0ab4
test to write forces file
mbkuhn Apr 29, 2024
cc99d49
body forcing unit test + better precision
mbkuhn Apr 29, 2024
4a0ef7c
geostrophic forcing unit test
mbkuhn Apr 29, 2024
cd817ca
Correct source term implementations for temporal discretization
mbkuhn Apr 29, 2024
f3b1c28
make body force test self-contained
mbkuhn Apr 29, 2024
1986d85
add headers to time table files in reg tests, note in documentation
mbkuhn Apr 29, 2024
5f6dabf
unused variables
mbkuhn Apr 29, 2024
f173185
avoiding angle interpolation issues
mbkuhn Apr 29, 2024
fe66520
Unit tests for new angle interpolation feature
mbkuhn Apr 30, 2024
2d96db0
Merge branch 'main' into time_varying_abl_bodyforce
mbkuhn Apr 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions amr-wind/equation_systems/icns/source_terms/ABLForcing.H
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,38 @@ public:
m_mean_vel[1] = uy;

const auto& current_time = m_time.current_time();
const auto& new_time = m_time.new_time();
const auto& nph_time = 0.5 * (current_time + new_time);
const auto& dt = m_time.deltaT();
const auto& t_step = m_time.time_index();

if (!m_vel_timetable.empty()) {
const amrex::Real current_spd = ::amr_wind::interp::linear(
m_time_table, m_speed_table, current_time);
const amrex::Real current_dir = ::amr_wind::interp::linear(
m_time_table, m_direction_table, current_time);

m_target_vel[0] = current_spd * std::cos(current_dir);
m_target_vel[1] = current_spd * std::sin(current_dir);
// Forces should be applied at n+1/2. Because ABL forcing is a
// delta, the difference between the target velocity (at n+1) and
// the current velocity (at n) puts the force term at n+1/2
const amrex::Real new_spd = ::amr_wind::interp::linear(
m_time_table, m_speed_table, new_time);
const amrex::Real new_dir = ::amr_wind::interp::linear_angle(
m_time_table, m_direction_table, new_time, 2.0 * M_PI);

m_target_vel[0] = new_spd * std::cos(new_dir);
m_target_vel[1] = new_spd * std::sin(new_dir);
}

m_abl_forcing[0] = (m_target_vel[0] - m_mean_vel[0]) / dt;
m_abl_forcing[1] = (m_target_vel[1] - m_mean_vel[1]) / dt;

if (m_write_force_timetable &&
amrex::ParallelDescriptor::IOProcessor() &&
(t_step % m_force_outfreq == 0) &&
(current_time >= m_force_outstart)) {
std::ofstream outfile;
// Forces are recorded at n+1/2
outfile.open(m_force_timetable, std::ios::out | std::ios::app);
outfile << std::fixed << std::setprecision(15) << nph_time << "\t"
<< m_abl_forcing[0] << "\t" << m_abl_forcing[1] << "\t"
<< 0.0 << std::endl;
}
}

amrex::RealArray abl_forcing() const { return m_abl_forcing; }
Expand All @@ -77,6 +95,15 @@ private:
//! File name for velocity forcing time table
std::string m_vel_timetable;

//! Bool for writing forcing time table
bool m_write_force_timetable{false};
//! File name for forcing time table output
std::string m_force_timetable;
//! Output frequency for forces
int m_force_outfreq{1};
//! Output start time for force
amrex::Real m_force_outstart{0.0};
moprak-nrel marked this conversation as resolved.
Show resolved Hide resolved

//! Velocity forcing time table
amrex::Vector<amrex::Real> m_time_table;

Expand Down
16 changes: 15 additions & 1 deletion amr-wind/equation_systems/icns/source_terms/ABLForcing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ ABLForcing::ABLForcing(const CFDSim& sim)
if (!m_vel_timetable.empty()) {
std::ifstream ifh(m_vel_timetable, std::ios::in);
if (!ifh.good()) {
amrex::Abort("Cannot find input file: " + m_vel_timetable);
amrex::Abort(
"Cannot find ABLForcing velocity_timetable file: " +
m_vel_timetable);
}
amrex::Real data_time;
amrex::Real data_speed;
Expand All @@ -43,6 +45,18 @@ ABLForcing::ABLForcing(const CFDSim& sim)
pp_incflo.getarr("velocity", m_target_vel);
}

m_write_force_timetable = pp_abl.contains("forcing_timetable_output_file");
if (m_write_force_timetable) {
pp_abl.get("forcing_timetable_output_file", m_force_timetable);
pp_abl.query("forcing_timetable_frequency", m_force_outfreq);
pp_abl.query("forcing_timetable_start_time", m_force_outstart);
if (amrex::ParallelDescriptor::IOProcessor()) {
std::ofstream outfile;
outfile.open(m_force_timetable, std::ios::out);
outfile << "time\tfx\tfy\tfz\n";
}
}

for (int i = 0; i < AMREX_SPACEDIM; ++i) {
m_mean_vel[i] = m_target_vel[i];
}
Expand Down
11 changes: 10 additions & 1 deletion amr-wind/equation_systems/icns/source_terms/BodyForce.H
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public:
const amrex::Array4<amrex::Real>& src_term) const override;

void read_bforce_profile(const std::string& filename);
void read_bforce_timetable(const std::string& filename);

private:
//! Time
Expand All @@ -44,7 +45,9 @@ private:
amrex::Vector<amrex::Real> m_body_force{{0.0, 0.0, 0.0}};

//! Body Force Type
std::string m_type{"constant"};
std::string m_type{"uniform_constant"};
//! Uniform time table file
std::string m_utt_file;

//! Angular frequency used in the oscillatory forcing
amrex::Real m_omega{0.0};
Expand All @@ -54,6 +57,12 @@ private:
amrex::Gpu::DeviceVector<amrex::Real> m_prof_x;
amrex::Gpu::DeviceVector<amrex::Real> m_prof_y;
amrex::Gpu::DeviceVector<amrex::Real> m_ht;

//! Vectors for storing uniform_timetable inputs
amrex::Vector<amrex::Real> m_time_table;
amrex::Vector<amrex::Real> m_fx_table;
amrex::Vector<amrex::Real> m_fy_table;
amrex::Vector<amrex::Real> m_fz_table;
};

} // namespace amr_wind::pde::icns
Expand Down
67 changes: 60 additions & 7 deletions amr-wind/equation_systems/icns/source_terms/BodyForce.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "amr-wind/equation_systems/icns/source_terms/BodyForce.H"
#include "amr-wind/CFDSim.H"
#include "amr-wind/utilities/trig_ops.H"
#include "amr-wind/utilities/linear_interpolation.H"

#include "AMReX_ParmParse.H"
#include "AMReX_Gpu.H"
Expand All @@ -16,18 +17,38 @@ namespace amr_wind::pde::icns {
BodyForce::BodyForce(const CFDSim& sim) : m_time(sim.time()), m_mesh(sim.mesh())
{

// Read the geostrophic wind speed vector (in m/s)
// Body Force arguments
amrex::ParmParse pp("BodyForce");
pp.query("type", m_type);
m_type = amrex::toLower(m_type);

if (m_type == "height-varying") {
pp.get("bodyforce-file", m_bforce_file);
bool no_type_specified = !pp.contains("type");
bool file_specified = pp.contains("uniform_timetable_file");

// Prepare type of body force distribution
if (m_type == "height_varying" || m_type == "height-varying") {
// Constant in time, varies with z
// Using underscores is preferred, remains backwards compatible
pp.query("bodyforce-file", m_bforce_file);
if (m_bforce_file.empty()) {
pp.get("bodyforce_file", m_bforce_file);
}
read_bforce_profile(m_bforce_file);
} else if (
m_type == "uniform_timetable" ||
(no_type_specified && file_specified)) {
// Still used if type not specified but file is
// Uniform in space, varies with time
pp.get("uniform_timetable_file", m_utt_file);
read_bforce_timetable(m_utt_file);
} else {
pp.getarr("magnitude", m_body_force);
if (m_type == "oscillatory") {
pp.get("angular_frequency", m_omega);
} else if (m_type != "uniform_constant") {
amrex::Abort(
"BodyForce type not supported. Please choose uniform_constant "
"(default), height_varying, oscillatory, or "
"uniform_timetable.\n");
moprak-nrel marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -68,14 +89,36 @@ void BodyForce::read_bforce_profile(const std::string& filename)
m_ht.begin());
}

void BodyForce::read_bforce_timetable(const std::string& filename)
{
std::ifstream ifh(filename, std::ios::in);
if (!ifh.good()) {
amrex::Abort(
"Cannot find BodyForce uniform_timetable_file: " + filename + "\n");
}
amrex::Real data_time;
amrex::Real data_fx;
amrex::Real data_fy;
amrex::Real data_fz;
// Skip first line (header)
ifh.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while (ifh >> data_time) {
ifh >> data_fx >> data_fy >> data_fz;
m_time_table.push_back(data_time);
m_fx_table.push_back(data_fx);
m_fy_table.push_back(data_fy);
m_fz_table.push_back(data_fz);
}
}

void BodyForce::operator()(
const int lev,
const amrex::MFIter& /*mfi*/,
const amrex::Box& bx,
const FieldState /*fstate*/,
const amrex::Array4<amrex::Real>& src_term) const
{
const auto& time = m_time.current_time();
const auto& nph_time = 0.5 * (m_time.current_time() + m_time.new_time());
const auto& problo = m_mesh.Geom(lev).ProbLoArray();
const auto& dx = m_mesh.Geom(lev).CellSizeArray();
const int lp1 = lev + 1;
Expand All @@ -85,7 +128,7 @@ void BodyForce::operator()(
const amrex::Real* force_x = m_prof_x.data();
const amrex::Real* force_y = m_prof_y.data();

if (m_type == "height-varying") {
if (m_type == "height_varying" || m_type == "height-varying") {

amrex::ParallelFor(
bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
Expand Down Expand Up @@ -113,8 +156,18 @@ void BodyForce::operator()(
amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> forcing{
{m_body_force[0], m_body_force[1], m_body_force[2]}};

if (!m_utt_file.empty()) {
// Populate forcing from file if supplied
forcing[0] =
amr_wind::interp::linear(m_time_table, m_fx_table, nph_time);
forcing[1] =
amr_wind::interp::linear(m_time_table, m_fy_table, nph_time);
forcing[2] =
amr_wind::interp::linear(m_time_table, m_fz_table, nph_time);
}

amrex::Real coeff =
(m_type == "oscillatory") ? std::cos(m_omega * time) : 1.0;
(m_type == "oscillatory") ? std::cos(m_omega * nph_time) : 1.0;
amrex::ParallelFor(
bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
src_term(i, j, k, 0) += coeff * forcing[0];
Expand Down
16 changes: 16 additions & 0 deletions amr-wind/equation_systems/icns/source_terms/GeostrophicForcing.H
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,24 @@ public:
const amrex::Array4<amrex::Real>& src_term) const override;

private:
const SimTime& m_time;
const amrex::AmrCore& m_mesh;

//! File name for target velocity time table
std::string m_vel_timetable;

//! Velocity forcing time table
amrex::Vector<amrex::Real> m_time_table;

//! Velocity forcing speed table
amrex::Vector<amrex::Real> m_speed_table;

//! Velocity forcing direction table
amrex::Vector<amrex::Real> m_direction_table;

//! Coriolis factor
amrex::Real m_coriolis_factor;

//! Activated when water is present in domain
bool m_use_phase_ramp{false};

Expand Down
55 changes: 47 additions & 8 deletions amr-wind/equation_systems/icns/source_terms/GeostrophicForcing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "amr-wind/core/vs/vstraits.H"
#include "amr-wind/physics/multiphase/MultiPhase.H"
#include "amr-wind/equation_systems/vof/volume_fractions.H"
#include "amr-wind/utilities/linear_interpolation.H"

#include "AMReX_ParmParse.H"
#include "AMReX_Gpu.H"
Expand All @@ -22,10 +23,9 @@ namespace amr_wind::pde::icns {
* GeostrophicForcing namespace
*
*/
GeostrophicForcing::GeostrophicForcing(const CFDSim& sim) : m_mesh(sim.mesh())
GeostrophicForcing::GeostrophicForcing(const CFDSim& sim)
: m_time(sim.time()), m_mesh(sim.mesh())
{
amrex::Real coriolis_factor = 0.0;

// Read the rotational time period (in seconds)
amrex::ParmParse ppc("CoriolisForcing");
// Read the rotational time period (in seconds) -- This is 23hrs and 56
Expand All @@ -39,18 +39,40 @@ GeostrophicForcing::GeostrophicForcing(const CFDSim& sim) : m_mesh(sim.mesh())
latitude = utils::radians(latitude);
amrex::Real sinphi = std::sin(latitude);

coriolis_factor = 2.0 * omega * sinphi;
m_coriolis_factor = 2.0 * omega * sinphi;
ppc.query("is_horizontal", m_is_horizontal);
amrex::Print() << "Geostrophic forcing: Coriolis factor = "
<< coriolis_factor << std::endl;
<< m_coriolis_factor << std::endl;

// Read the geostrophic wind speed vector (in m/s)
amrex::ParmParse ppg("GeostrophicForcing");
ppg.getarr("geostrophic_wind", m_target_vel);
ppg.query("geostrophic_wind_timetable", m_vel_timetable);
if (!m_vel_timetable.empty()) {
std::ifstream ifh(m_vel_timetable, std::ios::in);
if (!ifh.good()) {
amrex::Abort(
"Cannot find GeostrophicForcing geostrophic_wind_timetable "
"file: " +
m_vel_timetable);
}
amrex::Real data_time;
amrex::Real data_speed;
amrex::Real data_deg;
ifh.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while (ifh >> data_time) {
ifh >> data_speed >> data_deg;
amrex::Real data_rad = utils::radians(data_deg);
m_time_table.push_back(data_time);
m_speed_table.push_back(data_speed);
m_direction_table.push_back(data_rad);
}
} else {
ppg.getarr("geostrophic_wind", m_target_vel);
}

m_g_forcing = {
-coriolis_factor * m_target_vel[1], coriolis_factor * m_target_vel[0],
0.0};
-m_coriolis_factor * m_target_vel[1],
m_coriolis_factor * m_target_vel[0], 0.0};

// Set up relaxation toward 0 forcing near the air-water interface
if (sim.repo().field_exists("vof")) {
Expand Down Expand Up @@ -83,6 +105,8 @@ void GeostrophicForcing::operator()(
const amrex::Array4<amrex::Real>& src_term) const
{
amrex::Real hfac = (m_is_horizontal) ? 0. : 1.;
// Forces applied at n+1/2
const auto& nph_time = 0.5 * (m_time.current_time() + m_time.new_time());

const bool ph_ramp = m_use_phase_ramp;
const int n_band = m_n_band;
Expand All @@ -94,6 +118,21 @@ void GeostrophicForcing::operator()(
amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> forcing{
{m_g_forcing[0], m_g_forcing[1], m_g_forcing[2]}};

// Calculate forcing values if target velocity is a function of time
if (!m_vel_timetable.empty()) {
const amrex::Real nph_spd =
amr_wind::interp::linear(m_time_table, m_speed_table, nph_time);
const amrex::Real nph_dir = amr_wind::interp::linear_angle(
m_time_table, m_direction_table, nph_time, 2.0 * M_PI);

const amrex::Real target_u = nph_spd * std::cos(nph_dir);
const amrex::Real target_v = nph_spd * std::sin(nph_dir);

forcing[0] = -m_coriolis_factor * target_v;
forcing[1] = m_coriolis_factor * target_u;
forcing[2] = 0.0;
}

const auto& vof = (*m_vof)(lev).const_array(mfi);
amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
amrex::Real wfac = 1.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private:
const SimTime& m_time;
const amrex::AmrCore& m_mesh;

std::string m_type{"height-varying"};
std::string m_type{"height_varying"};
std::string m_bforce_file;
size_t m_bforce_profile_nhts;

Expand Down
10 changes: 7 additions & 3 deletions amr-wind/equation_systems/temperature/source_terms/BodyForce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ BodyForce::BodyForce(const CFDSim& sim) : m_time(sim.time()), m_mesh(sim.mesh())
pp.query("type", m_type);
m_type = amrex::toLower(m_type);

if (m_type == "height-varying") {
pp.get("bodyforce-file", m_bforce_file);
// Updated to underscores (more common) but still backwards-compatible
if (m_type == "height_varying" || m_type == "height-varying") {
pp.query("bodyforce-file", m_bforce_file);
if (m_bforce_file.empty()) {
pp.get("bodyforce_file", m_bforce_file);
}
read_bforce_profile(m_bforce_file);
}
}
Expand Down Expand Up @@ -74,7 +78,7 @@ void BodyForce::operator()(
const amrex::Real* force_ht = m_ht.data();
const amrex::Real* force_theta = m_prof_theta.data();

if (m_type == "height-varying") {
if (m_type == "height_varying" || m_type == "height-varying") {

amrex::ParallelFor(
bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
Expand Down
Loading