13#include "AMReX_MultiFabUtil.H"
15#ifdef AMR_WIND_USE_W2A
17int evaluate_read_resize(
24 const amrex::Real wtinit,
25 const amrex::Real wdt,
26 const amrex::Real newtime)
31 if (new_ntime != ntime) {
35 if (new_ntime > ntime + 1) {
42 wtime = new_ntime * wdt + wtinit;
44 if (double_data == 1 && std::abs(wtime - newtime) <= 1e-10) {
50 if (t_last < -1e-10) {
57 if (std::abs(wtime - newtime) > 1e-10) {
65 }
else if (std::abs(t_last) < 1e-10) {
80void postprocess_velocity_mfab_liquid(
81 amrex::MultiFab& vel_mfab,
82 amrex::MultiFab& lvs_mfab,
83 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> dx)
85 auto vel = vel_mfab.arrays();
86 const auto phi = lvs_mfab.const_arrays();
88 vel_mfab, amrex::IntVect(3),
89 [=] AMREX_GPU_DEVICE(
int nbx,
int i,
int j,
int k)
noexcept {
91 const amrex::Real cell_length_2D =
92 std::sqrt(dx[0] * dx[0] + dx[2] * dx[2]);
93 if (phi[nbx](i, j, k) + cell_length_2D < 0) {
94 vel[nbx](i, j, k, 0) = 0.0;
95 vel[nbx](i, j, k, 1) = 0.0;
96 vel[nbx](i, j, k, 2) = 0.0;
99 amrex::Gpu::synchronize();
102void postprocess_velocity_field_liquid(
105 amrex::Vector<amrex::Geometry>& geom_all)
108 for (
int lev = 0; lev < nlevels; ++lev) {
109 const auto& dx_lev = geom_all[lev].CellSizeArray();
110 postprocess_velocity_mfab_liquid(
111 vel_field(lev), lvs_field(lev), dx_lev);
115int update_offset_timestep(
const int ntime,
const int n0)
121 return (-ntime + n0);
124void populate_fields_all_levels(
126 amrex::Vector<amrex::Geometry>& geom_all,
133 bool no_EOF = wdata.rmodes.get_data(
141 amrex::Print() <<
"WARNING (waves2amr_ops): end of mode data file "
142 "detected, resetting to beginning of mode data.\n";
144 no_EOF = wdata.rmodes.get_data(
146 wdata.
mZ, wdata.
mFS);
150 "waves2amr_ops: end of mode data file detected after "
151 "resetting to beginning; please evaluate HOS_init_time "
152 "or HOS_init_timestep and check the length of the mode "
158 modes_hosgrid::copy_complex(wdata.
n0, wdata.
n1, wdata.
mFS, wdata.eta_mptr);
159 modes_hosgrid::populate_hos_eta(
160 wdata.rmodes, wdata.plan, wdata.eta_mptr, wdata.
sp_eta_vec);
162 for (
int iht = 0; iht < wdata.
indvec.size(); ++iht) {
164 amrex::Real ht = wdata.
hvec[wdata.
indvec[iht]];
166 modes_hosgrid::populate_hos_vel(
167 wdata.rmodes, ht, wdata.
mX, wdata.
mY, wdata.
mZ, wdata.plan,
168 wdata.u_mptr, wdata.v_mptr, wdata.w_mptr, wdata.
sp_u_vec,
173 interp_to_mfab::interp_eta_to_levelset_field(
176 interp_to_mfab::interp_velocity_to_field(
182 postprocess_velocity_field_liquid(vel_field, lvs_field, geom_all);
196 const ::amr_wind::utils::MultiParser& pp)
199#ifndef AMR_WIND_USE_W2A
202 "ocean_waves/W2AWaves: AMR-Wind was not built with Waves2AMR "
203 "support; associated wave data cannot be processed for relaxation "
206 amrex::ignore_unused(data, pp);
208 auto& wdata = data.
meta();
209 auto& info = data.
info();
212 pp.get(
"HOS_modes_filename", wdata.
modes_file);
213 pp.query(
"HOS_init_timestep", wdata.
ntime);
214 if (!pp.contains(
"HOS_init_timestep")) {
215 pp.query(
"HOS_init_time", wdata.
t_winit);
219 std::string fftw_planner_flag{
"estimate"};
220 pp.query(
"fftw_planner_flag", fftw_planner_flag);
222 amrex::Vector<amrex::Real> prob_lo_input(AMREX_SPACEDIM);
223 amrex::ParmParse pp_geom(
"geometry");
224 pp_geom.getarr(
"prob_lo", prob_lo_input);
229 amrex::Real dz0 = 0.;
230 pp.get(
"number_interp_points_in_z", nheights);
231 pp.get(
"interp_spacing_at_surface", dz0);
232 pp.query(
"number_interp_above_surface", nh_above);
235 bool file_exists = wdata.rmodes.initialize(wdata.
modes_file);
240 "Waves2AMR ReadInputsOp: modes file requested does not exist");
244 wdata.
dt_modes = wdata.rmodes.get_dtout();
263 int vsize = wdata.rmodes.get_vector_size();
264 double initval = 0.0;
265 wdata.
mX.resize(vsize, initval);
266 wdata.
mY.resize(vsize, initval);
267 wdata.
mZ.resize(vsize, initval);
268 wdata.
mFS.resize(vsize, initval);
271 wdata.
n0 = wdata.rmodes.get_first_dimension();
272 wdata.
n1 = wdata.rmodes.get_second_dimension();
274 wdata.
dx0 = wdata.rmodes.get_xlen() / wdata.
n0;
275 wdata.
dx1 = wdata.rmodes.get_ylen() / wdata.
n1;
277 const amrex::Real depth = wdata.rmodes.get_depth();
279 wdata.
dimL = wdata.rmodes.get_L();
282 (int)((wdata.rmodes.get_Tstop() + 1e-8) / wdata.
dt_modes);
290 <<
"WARNING (waves2amr_ops): available mode data exceeded, "
291 "resetting to beginning of mode data.\n";
295 if (std::abs(depth - (wdata.
zsl - prob_lo_input[2])) > 1e-3 * depth) {
297 <<
"WARNING: Mismatch between water depths from AMR-Wind "
298 "domain and HOS data interpreted by Waves2AMR";
302 wdata.eta_mptr = modes_hosgrid::allocate_complex(wdata.
n0, wdata.
n1);
303 wdata.u_mptr = modes_hosgrid::allocate_complex(wdata.
n0, wdata.
n1);
304 wdata.v_mptr = modes_hosgrid::allocate_complex(wdata.
n0, wdata.
n1);
305 wdata.w_mptr = modes_hosgrid::allocate_complex(wdata.
n0, wdata.
n1);
308 auto plan_f = modes_hosgrid::planner_flags::estimate;
309 if (fftw_planner_flag ==
"patient") {
310 plan_f = modes_hosgrid::planner_flags::patient;
311 }
else if (fftw_planner_flag ==
"exhaustive") {
312 plan_f = modes_hosgrid::planner_flags::exhaustive;
313 }
else if (fftw_planner_flag ==
"measure") {
314 plan_f = modes_hosgrid::planner_flags::measure;
315 }
else if (!(fftw_planner_flag ==
"estimate")) {
317 <<
"WARNING (waves2amr_ops): invalid fftw_planner_flag "
318 "specified; defaulting to estimate (FFTW_ESTIMATE).\n";
321 wdata.plan = modes_hosgrid::plan_ifftw(
322 wdata.
n0, wdata.
n1, wdata.eta_mptr, plan_f);
326 int flag = interp_to_mfab::create_height_vector(
327 wdata.
hvec, nheights, dz0, wdata.
zsl, prob_lo_input[2], nh_above);
331 "Waves2AMR ReadInputsOp: create_height_vector error, failure "
333 std::to_string(flag));
339 bool no_EOF = wdata.rmodes.get_data(
348 <<
"WARNING (waves2amr_ops): end of mode data file "
349 "detected, resetting to beginning of mode data.\n";
351 no_EOF = wdata.rmodes.get_data(
357 "waves2amr_ops: end of mode data file detected after "
358 "resetting to beginning; please evaluate HOS_init_time "
359 "or HOS_init_timestep and check the length of the mode "
365 modes_hosgrid::copy_complex(
366 wdata.
n0, wdata.
n1, wdata.
mFS, wdata.eta_mptr);
368 static_cast<size_t>(wdata.
n0) *
static_cast<size_t>(wdata.
n1),
370 modes_hosgrid::populate_hos_eta(
371 wdata.rmodes, wdata.plan, wdata.eta_mptr, wdata.
sp_eta_vec);
373 const auto n_hts = wdata.
hvec.size();
375 static_cast<size_t>(wdata.
n0 * wdata.
n1) * n_hts);
377 static_cast<size_t>(wdata.
n0 * wdata.
n1) * n_hts);
379 static_cast<size_t>(wdata.
n0 * wdata.
n1) * n_hts);
380 for (
int iht = 0; iht < static_cast<int>(n_hts); ++iht) {
382 amrex::Real ht = wdata.
hvec[iht];
384 modes_hosgrid::populate_hos_vel(
385 wdata.rmodes, ht, wdata.
mX, wdata.
mY, wdata.
mZ, wdata.plan,
386 wdata.u_mptr, wdata.v_mptr, wdata.w_mptr, wdata.
sp_u_vec,
395 "w2a_velocity", AMREX_SPACEDIM, 3, 1);
399 w2a_velocity.set_default_fillpatch_bc(data.
sim().
time());
413#ifdef AMR_WIND_USE_W2A
414 auto& wdata = data.
meta();
416 auto& sim = data.
sim();
424 const auto& problo = geom.ProbLoArray();
425 const auto& probhi = geom.ProbHiArray();
426 const auto& dx = geom.CellSizeArray();
432 amrex::Vector<int> indvec(wdata.
hvec.size());
433 std::iota(indvec.begin(), indvec.end(), 0);
435 interp_to_mfab::interp_eta_to_levelset_multifab(
437 wdata.
sp_eta_vec, ow_levelset(level), problo, dx);
438 interp_to_mfab::interp_velocity_to_multifab(
443 postprocess_velocity_mfab_liquid(
444 ow_velocity(level), ow_levelset(level), dx);
447 const auto& ow_phi = ow_levelset(level).const_arrays();
448 const auto& ow_vel = ow_velocity(level).const_arrays();
449 const auto& phi = levelset(level).arrays();
450 const auto& vel = velocity(level).arrays();
452 const amrex::Real gen_length = wdata.
gen_length;
454 const amrex::Real zero_sea_level = wdata.
zsl;
460 velocity(level), amrex::IntVect(3),
461 [=] AMREX_GPU_DEVICE(
int nbx,
int i,
int j,
int k)
noexcept {
462 const amrex::Real x = problo[0] + (i + 0.5) * dx[0];
463 const amrex::Real z = problo[2] + (k + 0.5) * dx[2];
467 ow_vel[nbx](i, j, k, 0), ow_vel[nbx](i, j, k, 1),
468 ow_vel[nbx](i, j, k, 2), ow_phi[nbx](i, j, k) + z};
473 const auto bulk = init_wave_field ? wave_sol : quiescent;
474 const auto outlet = has_beach ? quiescent : wave_sol;
477 x, problo[0], gen_length, probhi[0], beach_length, wave_sol,
480 phi[nbx](i, j, k) = local_profile[3] - z;
481 const amrex::Real cell_length_2D =
482 std::sqrt(dx[0] * dx[0] + dx[2] * dx[2]);
483 if (phi[nbx](i, j, k) + cell_length_2D >= 0) {
484 vel[nbx](i, j, k, 0) = local_profile[0];
485 vel[nbx](i, j, k, 1) = local_profile[1];
486 vel[nbx](i, j, k, 2) = local_profile[2];
489 amrex::Gpu::synchronize();
492 auto& w2a_levelset = sim.repo().get_field(
"w2a_levelset");
493 auto& w2a_velocity = sim.repo().get_field(
"w2a_velocity");
494 w2a_levelset.setVal(0.0);
495 w2a_velocity.setVal(0.0);
497 amrex::ignore_unused(data, level, geom);
509#ifdef AMR_WIND_USE_W2A
510 auto& wdata = data.
meta();
511 auto& sim = data.
sim();
517 auto& m_ow_levelset = sim.repo().get_field(
"ow_levelset");
518 auto& m_ow_velocity = sim.repo().get_field(
"ow_velocity");
520 auto& w2a_levelset = sim.repo().get_field(
"w2a_levelset");
521 auto& w2a_velocity = sim.repo().get_field(
"w2a_velocity");
523 auto nlevels = sim.repo().num_active_levels();
524 auto geom = sim.mesh().Geom();
527 amrex::Real t_last = wdata.
t_last;
530 bool read_flag =
false;
533 wdata.rmodes.time2step(newtime + wdata.
t_winit, wdata.
ntime);
534 int double_data = evaluate_read_resize(
546 <<
"WARNING (waves2amr_ops): available mode data exceeded, "
547 "resetting to beginning of mode data.\n";
565 bool flag_xlo =
false;
566 bool flag_xhi =
false;
569 (interp_to_mfab::get_local_height_indices(
570 wdata.
indvec, wdata.
hvec, m_ow_velocity.vec_ptrs(),
577 (interp_to_mfab::check_lateral_overlap_lo(
578 wdata.
gen_length, dir, m_ow_velocity.vec_ptrs(),
584 (interp_to_mfab::check_lateral_overlap_hi(
589 if (flag_z && (flag_xlo || flag_xhi)) {
594 static_cast<size_t>(wdata.
n0) *
595 static_cast<size_t>(wdata.
n1),
598 static_cast<size_t>(wdata.
n0 * wdata.
n1) *
601 static_cast<size_t>(wdata.
n0 * wdata.
n1) *
604 static_cast<size_t>(wdata.
n0 * wdata.
n1) *
615 amrex::ParallelDescriptor::ReduceIntMax(wdata.
n_offset);
619 if (double_data == 1) {
621 populate_fields_all_levels(
622 wdata, geom, m_ow_levelset, m_ow_velocity, -1);
627 for (
int lev = nlevels - 1; lev > 0; --lev) {
629 m_ow_velocity(lev), m_ow_velocity(lev - 1), 0,
630 AMREX_SPACEDIM, sim.mesh().refRatio(lev - 1));
632 m_ow_levelset(lev), m_ow_levelset(lev - 1), 0, 1,
633 sim.mesh().refRatio(lev - 1));
636 m_ow_velocity.fillpatch(sim.time().new_time());
637 m_ow_levelset.fillpatch(sim.time().new_time());
641 }
else if (double_data == 2) {
644 m_ow_levelset.setVal(0.0);
645 m_ow_velocity.setVal(0.0);
651 populate_fields_all_levels(
652 wdata, geom, w2a_levelset, w2a_velocity);
657 for (
int lev = nlevels - 1; lev > 0; --lev) {
659 w2a_velocity(lev), w2a_velocity(lev - 1), 0, AMREX_SPACEDIM,
660 sim.mesh().refRatio(lev - 1));
662 w2a_levelset(lev), w2a_levelset(lev - 1), 0, 1,
663 sim.mesh().refRatio(lev - 1));
666 w2a_velocity.fillpatch(sim.time().new_time());
667 w2a_levelset.fillpatch(sim.time().new_time());
671 for (
int lev = 0; lev < nlevels; ++lev) {
672 auto phi = m_ow_levelset(lev).arrays();
673 auto vel = m_ow_velocity(lev).arrays();
674 auto W2A_phi = w2a_levelset(lev).arrays();
675 auto W2A_vel = w2a_velocity(lev).arrays();
677 const amrex::Real W2A_t = wdata.
t;
679 m_ow_levelset(lev), amrex::IntVect(3),
680 [=] AMREX_GPU_DEVICE(
int nbx,
int i,
int j,
int k)
noexcept {
683 (W2A_phi[nbx](i, j, k) - phi[nbx](i, j, k)) *
684 (newtime - t_last) / (W2A_t - t_last + 1e-16);
685 vel[nbx](i, j, k, 0) +=
686 (W2A_vel[nbx](i, j, k, 0) - vel[nbx](i, j, k, 0)) *
687 (newtime - t_last) / (W2A_t - t_last + 1e-16);
688 vel[nbx](i, j, k, 1) +=
689 (W2A_vel[nbx](i, j, k, 1) - vel[nbx](i, j, k, 1)) *
690 (newtime - t_last) / (W2A_t - t_last + 1e-16);
691 vel[nbx](i, j, k, 2) +=
692 (W2A_vel[nbx](i, j, k, 2) - vel[nbx](i, j, k, 2)) *
693 (newtime - t_last) / (W2A_t - t_last + 1e-16);
696 amrex::Gpu::synchronize();
698 amrex::ignore_unused(data);
FieldRepo & repo()
Return the field repository.
Definition CFDSim.H:66
SimTime & time()
Return simulation time control.
Definition CFDSim.H:62
FieldRepo & repo() const
FieldRepo instance that manages this field.
Definition Field.H:159
void set_default_fillpatch_bc(const SimTime &time, const amrex::BCType::mathematicalBndryTypes bctype=amrex::BCType::hoextrap) noexcept
Definition Field.cpp:377
amrex::Vector< amrex::MultiFab * > vec_ptrs() noexcept
Return a vector of MultiFab pointers for all levels.
Definition Field.cpp:142
Field & declare_field(const std::string &name, const int ncomp=1, const int ngrow=0, const int nstates=1, const FieldLoc floc=FieldLoc::CELL)
Definition FieldRepo.cpp:83
Field & get_field(const std::string &name, const FieldState fstate=FieldState::New) const
Definition FieldRepo.cpp:149
int num_active_levels() const noexcept
Total number of levels currently active in the AMR mesh.
Definition FieldRepo.H:361
AMREX_FORCE_INLINE int time_index() const
Definition SimTime.H:114
AMREX_FORCE_INLINE amrex::Real new_time() const
Definition SimTime.H:108
Definition OceanWavesTypes.H:59
OceanWavesTrait::MetaType & meta()
Definition OceanWavesTypes.H:89
CFDSim & sim()
Definition OceanWavesTypes.H:83
OceanWavesTrait::InfoType & info()
Definition OceanWavesTypes.H:86
Definition OceanWavesOps.H:8
void read_inputs(RelaxZonesBaseData &wdata, OceanWavesInfo &, const ::amr_wind::utils::MultiParser &pp)
Definition relaxation_zones_ops.cpp:15
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE WaveVec harmonize_profiles_1d(const amrex::Real x, const amrex::Real left_bdy, const amrex::Real left_length, const amrex::Real right_bdy, const amrex::Real right_length, const WaveVec left, const WaveVec bulk, const WaveVec right)
Definition wave_utils_K.H:67
amrex::GpuArray< amrex::Real, 4 > WaveVec
Definition wave_utils_K.H:9
bool has_beach
Definition RelaxationZones.H:34
bool has_outprofile
Definition RelaxationZones.H:35
amrex::Real beach_length
Definition RelaxationZones.H:27
bool init_wave_field
Definition RelaxationZones.H:30
amrex::Real gen_length
Definition RelaxationZones.H:25
bool regrid_occurred
Definition RelaxationZones.H:39
amrex::Real zsl
Definition RelaxationZones.H:17
amrex::Real dimL
Definition W2AWaves.H:24
amrex::Real dt_modes
Definition W2AWaves.H:26
amrex::Gpu::DeviceVector< amrex::Real > sp_v_vec
Definition W2AWaves.H:69
std::vector< std::complex< double > > mFS
Definition W2AWaves.H:47
amrex::Vector< int > indvec
Definition W2AWaves.H:63
int n1
Definition W2AWaves.H:19
amrex::Gpu::DeviceVector< amrex::Real > sp_u_vec
Definition W2AWaves.H:69
int n_winit
Definition W2AWaves.H:34
amrex::Vector< amrex::Real > hvec
Definition W2AWaves.H:61
int n_offset
Definition W2AWaves.H:38
amrex::Real dx0
Definition W2AWaves.H:21
int ntime
Definition W2AWaves.H:32
std::vector< std::complex< double > > mX
Definition W2AWaves.H:47
amrex::Real t_last
Definition W2AWaves.H:42
amrex::Gpu::DeviceVector< amrex::Real > sp_w_vec
Definition W2AWaves.H:70
int n0
Definition W2AWaves.H:18
std::vector< std::complex< double > > mY
Definition W2AWaves.H:47
amrex::Real dx1
Definition W2AWaves.H:22
amrex::Real t_winit
Definition W2AWaves.H:30
int n_wstop
Definition W2AWaves.H:36
std::string modes_file
Definition W2AWaves.H:16
std::vector< std::complex< double > > mZ
Definition W2AWaves.H:47
amrex::Gpu::DeviceVector< amrex::Real > sp_eta_vec
Definition W2AWaves.H:69
bool do_interp
Definition W2AWaves.H:65
bool resize_flag
Definition W2AWaves.H:67
amrex::Real t
Definition W2AWaves.H:44
void operator()(W2AWaves::DataType &data, int level, const amrex::Geometry &geom)
Definition waves2amr_ops.H:409
Definition OceanWavesOps.H:32
void operator()(W2AWaves::DataType &data)
Definition waves2amr_ops.H:506
Definition OceanWavesOps.H:35