/home/runner/work/amr-wind/amr-wind/amr-wind/ocean_waves/relaxation_zones/waves2amr_ops.H Source File

AMR-Wind API: /home/runner/work/amr-wind/amr-wind/amr-wind/ocean_waves/relaxation_zones/waves2amr_ops.H Source File
AMR-Wind API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
waves2amr_ops.H
Go to the documentation of this file.
1#ifndef W2A_WAVES_OPS_H
2#define W2A_WAVES_OPS_H
3
13#include "AMReX_MultiFabUtil.H"
14
15#ifdef AMR_WIND_USE_W2A
16namespace {
17int evaluate_read_resize(
18 int& ntime,
19 bool& read_flag,
20 bool& resize_flag,
21 amrex::Real& wtime,
22 amrex::Real& t_last,
23 const int new_ntime,
24 const amrex::Real wtinit,
25 const amrex::Real wdt,
26 const amrex::Real newtime)
27{
28 // Flag to indicate that data must be read twice for interpolation
29 int double_data = 0;
30 // Check if time indicates reading must take place
31 if (new_ntime != ntime) {
32 // New data is needed - reading should happen
33 read_flag = true;
34 // If time index has proceeded more than 1 step
35 if (new_ntime > ntime + 1) {
36 // Double reading is necessary
37 double_data = 1;
38 }
39 // Time index for reading
40 ntime = new_ntime;
41 // Sim time to go with recorded data
42 wtime = new_ntime * wdt + wtinit;
43 // If double reading is deemed necessary, check for convenience
44 if (double_data == 1 && std::abs(wtime - newtime) <= 1e-10) {
45 // Reading can be done just once, w2a fields replace ow fields
46 double_data = 2;
47 }
48 }
49 // Check if reading must take place for other reasons
50 if (t_last < -1e-10) {
51 // Signifies initialization from scratch without waves or a restart
52 read_flag = true;
53 // Resizing needs to happen for the first time
54 resize_flag = true;
55
56 // Confirm that new time is not coincident with modes time step
57 if (std::abs(wtime - newtime) > 1e-10) {
58 // Data must be read before and after wtime
59 double_data = 1;
60 } else {
61 // Data need only be read once, w2a fields will replace ow fields
62 double_data = 2;
63 }
64
65 } else if (std::abs(t_last) < 1e-10) {
66 // Signifies initialization with waves
67 read_flag = true;
68 // Resizing needs to happen for the first time
69 resize_flag = true;
70
71 // levelset and velocity fields are up-to-date at t=0
72 // interpolation is ready to go
73 }
74 // Record latest time as 'last' for next timestep
75 t_last = newtime;
76 // Return flag regarding double reading
77 return double_data;
78}
79
80void postprocess_velocity_mfab_liquid(
81 amrex::MultiFab& vel_mfab,
82 amrex::MultiFab& lvs_mfab,
83 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> dx)
84{
85 auto vel = vel_mfab.arrays();
86 const auto phi = lvs_mfab.const_arrays();
87 amrex::ParallelFor(
88 vel_mfab, amrex::IntVect(3),
89 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) noexcept {
90 // Set velocity to zero if no liquid present
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;
97 }
98 });
99 amrex::Gpu::synchronize();
100}
101
102void postprocess_velocity_field_liquid(
103 amr_wind::Field& vel_field,
104 amr_wind::Field& lvs_field,
105 amrex::Vector<amrex::Geometry>& geom_all)
106{
107 int nlevels = vel_field.repo().num_active_levels();
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);
112 }
113}
114
115int update_offset_timestep(const int ntime, const int n0)
116{
117 // Offending timestep (goes too far): ntime + offset
118 // Farthest back timesteps are permitted to go: n0
119 // Subtract offset by offending timestep, add back lower limit
120 // new offset = offset - (ntime + offset) + n0
121 return (-ntime + n0);
122}
123
124void populate_fields_all_levels(
126 amrex::Vector<amrex::Geometry>& geom_all,
127 amr_wind::Field& lvs_field,
128 amr_wind::Field& vel_field,
129 int ntime_off = 0)
130{
131
132 // Get data from modes
133 bool no_EOF = wdata.rmodes.get_data(
134 wdata.ntime + wdata.n_offset + ntime_off, wdata.mX, wdata.mY, wdata.mZ,
135 wdata.mFS);
136 // Navigate when end of file is reached
137 if (!no_EOF) {
138 // End of file detected, reset reading
139 wdata.n_offset = update_offset_timestep(wdata.ntime, wdata.n_winit);
140 // Print warning to screen
141 amrex::Print() << "WARNING (waves2amr_ops): end of mode data file "
142 "detected, resetting to beginning of mode data.\n";
143 // Read data again, now from a valid timestep
144 no_EOF = wdata.rmodes.get_data(
145 wdata.ntime + wdata.n_offset + ntime_off, wdata.mX, wdata.mY,
146 wdata.mZ, wdata.mFS);
147 // If no valid data is detected at this point, abort
148 if (!no_EOF) {
149 amrex::Abort(
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 "
153 "file.");
154 }
155 }
156
157 // Convert to spatial data in vectors
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);
161
162 for (int iht = 0; iht < wdata.indvec.size(); ++iht) {
163 // Get sample height
164 amrex::Real ht = wdata.hvec[wdata.indvec[iht]];
165 // Sample velocity
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,
169 wdata.sp_v_vec, wdata.sp_w_vec, iht * wdata.n0 * wdata.n1);
170 }
171
172 // Interpolate to fields (vector of MultiFabs)
173 interp_to_mfab::interp_eta_to_levelset_field(
174 wdata.n0, wdata.n1, wdata.dx0, wdata.dx1, wdata.zsl, wdata.sp_eta_vec,
175 lvs_field.vec_ptrs(), geom_all);
176 interp_to_mfab::interp_velocity_to_field(
177 wdata.n0, wdata.n1, wdata.dx0, wdata.dx1, wdata.indvec, wdata.hvec,
178 wdata.sp_u_vec, wdata.sp_v_vec, wdata.sp_w_vec, vel_field.vec_ptrs(),
179 geom_all);
180
181 // Zero velocity in pure gas cells
182 postprocess_velocity_field_liquid(vel_field, lvs_field, geom_all);
183}
184
185} // namespace
186#endif
187
189
190template <>
192{
194 // cppcheck-suppress constParameterReference
195 W2AWaves::DataType& data,
196 const ::amr_wind::utils::MultiParser& pp)
197 {
198// Check for W2A initialization
199#ifndef AMR_WIND_USE_W2A
200 // Assert Waves2AMR must be used for initial condition file
201 amrex::Abort(
202 "ocean_waves/W2AWaves: AMR-Wind was not built with Waves2AMR "
203 "support; associated wave data cannot be processed for relaxation "
204 "zones.");
205
206 amrex::ignore_unused(data, pp);
207#else
208 auto& wdata = data.meta();
209 auto& info = data.info();
210 relaxation_zones::read_inputs(wdata, info, pp);
211
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);
216 }
217
218 // Default fftw_plan is deterministic
219 std::string fftw_planner_flag{"estimate"};
220 pp.query("fftw_planner_flag", fftw_planner_flag);
221
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);
225
226 // Read user inputs to height vector
227 int nheights = 0;
228 int nh_above = 1;
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);
233
234 // Initialize mode reader
235 bool file_exists = wdata.rmodes.initialize(wdata.modes_file);
236
237 // Abort if file does not exist
238 if (!file_exists) {
239 amrex::Abort(
240 "Waves2AMR ReadInputsOp: modes file requested does not exist");
241 }
242
243 // Get dt of HOS data
244 wdata.dt_modes = wdata.rmodes.get_dtout();
245
246 // Get initial time and timestep synced
247 if (wdata.t_winit > 0.0) {
248 // If initial time was specified
249 // Get time index near requested time
250 wdata.ntime = wdata.rmodes.time2step(wdata.t_winit, wdata.ntime);
251 // Sync time to time index
252 wdata.t_winit = wdata.dt_modes * wdata.ntime;
253 // Save first timestep
254 wdata.n_winit = wdata.ntime;
255 } else {
256 // If initial timestep is being used
257 wdata.t_winit = wdata.dt_modes * wdata.ntime;
258 // Save first timestep
259 wdata.n_winit = wdata.ntime;
260 }
261
262 // Initialize variables to store modes
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);
269
270 // Get dimensions of data
271 wdata.n0 = wdata.rmodes.get_first_dimension();
272 wdata.n1 = wdata.rmodes.get_second_dimension();
273 // Get resolution
274 wdata.dx0 = wdata.rmodes.get_xlen() / wdata.n0;
275 wdata.dx1 = wdata.rmodes.get_ylen() / wdata.n1;
276 // Get depth
277 const amrex::Real depth = wdata.rmodes.get_depth();
278 // Get dimensional length
279 wdata.dimL = wdata.rmodes.get_L();
280 // Get nominal last timestep of data
281 wdata.n_wstop =
282 (int)((wdata.rmodes.get_Tstop() + 1e-8) / wdata.dt_modes);
283
284 // Check if stop time is exceeded, introduce offset to ntime
285 if (wdata.ntime + wdata.n_offset > wdata.n_wstop) {
286 // If exceeding stop step, calculate new offset
287 wdata.n_offset = update_offset_timestep(wdata.ntime, wdata.n_winit);
288 // Print warning to screen
289 amrex::Print()
290 << "WARNING (waves2amr_ops): available mode data exceeded, "
291 "resetting to beginning of mode data.\n";
292 }
293
294 // Warning if depth does not correspond to simulation
295 if (std::abs(depth - (wdata.zsl - prob_lo_input[2])) > 1e-3 * depth) {
296 amrex::Print()
297 << "WARNING: Mismatch between water depths from AMR-Wind "
298 "domain and HOS data interpreted by Waves2AMR";
299 }
300
301 // Allocate pointers for FFTW
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);
306
307 // Set up planner flag based on input
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")) {
316 amrex::Print()
317 << "WARNING (waves2amr_ops): invalid fftw_planner_flag "
318 "specified; defaulting to estimate (FFTW_ESTIMATE).\n";
319 }
320 // Set up plan for FFTW
321 wdata.plan = modes_hosgrid::plan_ifftw(
322 wdata.n0, wdata.n1, wdata.eta_mptr, plan_f);
323
324 // Create height vector for velocity mode conversion before
325 // interpolation, with prob_lo as bottom
326 int flag = interp_to_mfab::create_height_vector(
327 wdata.hvec, nheights, dz0, wdata.zsl, prob_lo_input[2], nh_above);
328 // Fail if flag indicates it should
329 if (flag > 0) {
330 amrex::Abort(
331 "Waves2AMR ReadInputsOp: create_height_vector error, failure "
332 "code " +
333 std::to_string(flag));
334 }
335
336 // If init_wave_field is activated and initialization will be done, get
337 // modes on every processor
338 if (wdata.init_wave_field && data.sim().time().time_index() == 0) {
339 bool no_EOF = wdata.rmodes.get_data(
340 wdata.ntime + wdata.n_offset, wdata.mX, wdata.mY, wdata.mZ,
341 wdata.mFS);
342 if (!no_EOF) {
343 // End of file detected, reset reading
344 wdata.n_offset =
345 update_offset_timestep(wdata.ntime, wdata.n_winit);
346 // Print warning to screen
347 amrex::Print()
348 << "WARNING (waves2amr_ops): end of mode data file "
349 "detected, resetting to beginning of mode data.\n";
350 // Read data again, now from a valid timestep
351 no_EOF = wdata.rmodes.get_data(
352 wdata.ntime + wdata.n_offset, wdata.mX, wdata.mY, wdata.mZ,
353 wdata.mFS);
354 // If no valid data is detected at this point, abort
355 if (!no_EOF) {
356 amrex::Abort(
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 "
360 "file.");
361 }
362 }
363
364 // Convert modes to spatial data
365 modes_hosgrid::copy_complex(
366 wdata.n0, wdata.n1, wdata.mFS, wdata.eta_mptr);
367 wdata.sp_eta_vec.resize(
368 static_cast<size_t>(wdata.n0) * static_cast<size_t>(wdata.n1),
369 0.0);
370 modes_hosgrid::populate_hos_eta(
371 wdata.rmodes, wdata.plan, wdata.eta_mptr, wdata.sp_eta_vec);
372 // Mesh is not yet created, so get data at every height
373 const auto n_hts = wdata.hvec.size();
374 wdata.sp_u_vec.resize(
375 static_cast<size_t>(wdata.n0 * wdata.n1) * n_hts);
376 wdata.sp_v_vec.resize(
377 static_cast<size_t>(wdata.n0 * wdata.n1) * n_hts);
378 wdata.sp_w_vec.resize(
379 static_cast<size_t>(wdata.n0 * wdata.n1) * n_hts);
380 for (int iht = 0; iht < static_cast<int>(n_hts); ++iht) {
381 // Get sample height
382 amrex::Real ht = wdata.hvec[iht];
383 // Sample velocity
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,
387 wdata.sp_v_vec, wdata.sp_w_vec, iht * wdata.n0 * wdata.n1);
388 }
389 }
390
391 // Declare fields for HOS
392 auto& w2a_levelset =
393 data.sim().repo().declare_field("w2a_levelset", 1, 3, 1);
394 auto& w2a_velocity = data.sim().repo().declare_field(
395 "w2a_velocity", AMREX_SPACEDIM, 3, 1);
396
397 // Extrapolation can work well when finer data is available
398 w2a_levelset.set_default_fillpatch_bc(data.sim().time());
399 w2a_velocity.set_default_fillpatch_bc(data.sim().time());
400#endif
401 }
402}; // namespace ops
403
404template <>
406{
407 void
408 // cppcheck-suppress constParameterReference
410 W2AWaves::DataType & data, int level, const amrex::Geometry & geom)
411 {
412
413#ifdef AMR_WIND_USE_W2A
414 auto& wdata = data.meta();
415
416 auto& sim = data.sim();
417
418 // Fill ow fields, then populate flow fields according to setup
419 auto& ow_levelset = sim.repo().get_field("ow_levelset");
420 auto& ow_velocity = sim.repo().get_field("ow_velocity");
421 auto& levelset = sim.repo().get_field("levelset");
422 auto& velocity = sim.repo().get_field("velocity");
423
424 const auto& problo = geom.ProbLoArray();
425 const auto& probhi = geom.ProbHiArray();
426 const auto& dx = geom.CellSizeArray();
427
428 // Set t_last to 0.0 to signify information read in
429 wdata.t_last = 0.0;
430
431 // indvec is complete upon initialization (all heights every proc)
432 amrex::Vector<int> indvec(wdata.hvec.size());
433 std::iota(indvec.begin(), indvec.end(), 0);
434 // Interpolate to MultiFabs (one level at a time)
435 interp_to_mfab::interp_eta_to_levelset_multifab(
436 wdata.n0, wdata.n1, wdata.dx0, wdata.dx1, wdata.zsl,
437 wdata.sp_eta_vec, ow_levelset(level), problo, dx);
438 interp_to_mfab::interp_velocity_to_multifab(
439 wdata.n0, wdata.n1, wdata.dx0, wdata.dx1, indvec, wdata.hvec,
440 wdata.sp_u_vec, wdata.sp_v_vec, wdata.sp_w_vec, ow_velocity(level),
441 problo, dx);
442 // Zero velocity in pure air cells
443 postprocess_velocity_mfab_liquid(
444 ow_velocity(level), ow_levelset(level), dx);
445
446 // Populate flow fields according to intended forcing and init setup
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();
451
452 const amrex::Real gen_length = wdata.gen_length;
453 const amrex::Real beach_length = wdata.beach_length;
454 const amrex::Real zero_sea_level = wdata.zsl;
455
456 const bool has_beach = wdata.has_beach;
457 const bool init_wave_field = wdata.init_wave_field;
458
459 amrex::ParallelFor(
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];
464
465 // Wave profile
466 const utils::WaveVec wave_sol{
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};
469 // Quiescent profile
470 const utils::WaveVec quiescent{0.0, 0.0, 0.0, zero_sea_level};
471
472 // Specify initial state for each region of domain
473 const auto bulk = init_wave_field ? wave_sol : quiescent;
474 const auto outlet = has_beach ? quiescent : wave_sol;
475
476 const auto local_profile = utils::harmonize_profiles_1d(
477 x, problo[0], gen_length, probhi[0], beach_length, wave_sol,
478 bulk, outlet);
479
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];
487 }
488 });
489 amrex::Gpu::synchronize();
490
491 // Start w2a fields at 0, some areas will not be modified
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);
496#else
497 amrex::ignore_unused(data, level, geom);
498#endif
499 }
500}; // namespace ocean_waves
501
502template <>
504{
505 // cppcheck-suppress constParameterReference
507 {
508
509#ifdef AMR_WIND_USE_W2A
510 auto& wdata = data.meta();
511 auto& sim = data.sim();
512
513 // Nudge the solution toward where it should be
514 const amrex::Real newtime = sim.time().new_time();
515
516 // Update ow fields every time
517 auto& m_ow_levelset = sim.repo().get_field("ow_levelset");
518 auto& m_ow_velocity = sim.repo().get_field("ow_velocity");
519 // Update HOS fields when necessary
520 auto& w2a_levelset = sim.repo().get_field("w2a_levelset");
521 auto& w2a_velocity = sim.repo().get_field("w2a_velocity");
522
523 auto nlevels = sim.repo().num_active_levels();
524 auto geom = sim.mesh().Geom();
525
526 // Get value for time interpolation
527 amrex::Real t_last = wdata.t_last;
528
529 // Check if new HOS data needs to be read
530 bool read_flag = false;
531 // Check if time indicates reading must take place
532 int new_ntime =
533 wdata.rmodes.time2step(newtime + wdata.t_winit, wdata.ntime);
534 int double_data = evaluate_read_resize(
535 wdata.ntime, read_flag, wdata.resize_flag, wdata.t, wdata.t_last,
536 new_ntime, wdata.t_winit, wdata.dt_modes, newtime);
537 // Check if stop time is exceeded, introduce offset to ntime
538 if (read_flag) {
539 // Need to only check when reading is occurring
540 if (wdata.ntime + wdata.n_offset > wdata.n_wstop) {
541 // If exceeding stop step, calculate new offset
542 wdata.n_offset =
543 update_offset_timestep(wdata.ntime, wdata.n_winit);
544 // Print warning to screen
545 amrex::Print()
546 << "WARNING (waves2amr_ops): available mode data exceeded, "
547 "resetting to beginning of mode data.\n";
548 }
549 }
550 // Resizing (assuming reading is taking place) must happen after regrid
551 if (wdata.regrid_occurred) {
552 // resize_flag remains true until resizing occurs, but
553 // regrid_occurred resets every timestep
554 wdata.resize_flag = true;
555 }
556
557 // Read HOS data if necessary based on time
558 if (read_flag) {
559
560 if (wdata.resize_flag) {
561 // Reset flag
562 wdata.resize_flag = false;
563 // Flags for indicating overlap, assume none at first
564 bool flag_z = false;
565 bool flag_xlo = false;
566 bool flag_xhi = false;
567 // Get heights for this processor, check overlap in z
568 flag_z =
569 (interp_to_mfab::get_local_height_indices(
570 wdata.indvec, wdata.hvec, m_ow_velocity.vec_ptrs(),
571 geom) == 1);
572 // No overlap from heights definitely means no interp
573
574 // Check lateral bounds (in x)
575 const int dir = 0;
576 flag_xlo =
577 (interp_to_mfab::check_lateral_overlap_lo(
578 wdata.gen_length, dir, m_ow_velocity.vec_ptrs(),
579 geom) == 1);
580 // No overlap with gen region means no interp, unless ...
581 if (wdata.has_outprofile) {
582 // ... if overlap exists here, needing interp
583 flag_xhi =
584 (interp_to_mfab::check_lateral_overlap_hi(
585 wdata.beach_length, dir, m_ow_velocity.vec_ptrs(),
586 geom) == 1);
587 }
588
589 if (flag_z && (flag_xlo || flag_xhi)) {
590 // Interpolation is needed
591 wdata.do_interp = true;
592 // Do resizing
593 wdata.sp_eta_vec.resize(
594 static_cast<size_t>(wdata.n0) *
595 static_cast<size_t>(wdata.n1),
596 0.0);
597 wdata.sp_u_vec.resize(
598 static_cast<size_t>(wdata.n0 * wdata.n1) *
599 wdata.indvec.size());
600 wdata.sp_v_vec.resize(
601 static_cast<size_t>(wdata.n0 * wdata.n1) *
602 wdata.indvec.size());
603 wdata.sp_w_vec.resize(
604 static_cast<size_t>(wdata.n0 * wdata.n1) *
605 wdata.indvec.size());
606 // Sizes will remain constant and need for interpolation
607 // will remain until a regrid occurs
608 } else {
609 // No overlapping with spatial data or no overlapping with
610 // relaxation zones, interpolation can be skipped
611 wdata.do_interp = false;
612 }
613 }
614 // Only perform reading where needed, communicate offset though
615 amrex::ParallelDescriptor::ReduceIntMax(wdata.n_offset);
616
617 // If double read is required, then copy older wave data to ow_
618 // fields and modify interpolation parameters to get things right
619 if (double_data == 1) {
620 if (wdata.do_interp) {
621 populate_fields_all_levels(
622 wdata, geom, m_ow_levelset, m_ow_velocity, -1);
623 }
624
625 // Average down to get fine information on coarse grid where
626 // possible (may be unnecessary)
627 for (int lev = nlevels - 1; lev > 0; --lev) {
628 amrex::average_down(
629 m_ow_velocity(lev), m_ow_velocity(lev - 1), 0,
630 AMREX_SPACEDIM, sim.mesh().refRatio(lev - 1));
631 amrex::average_down(
632 m_ow_levelset(lev), m_ow_levelset(lev - 1), 0, 1,
633 sim.mesh().refRatio(lev - 1));
634 }
635 // Fill patch to get correct ghost cells after average down
636 m_ow_velocity.fillpatch(sim.time().new_time());
637 m_ow_levelset.fillpatch(sim.time().new_time());
638
639 // Prior t_last (corresponding to ow fields)
640 t_last = (wdata.ntime - 1) * wdata.dt_modes;
641 } else if (double_data == 2) {
642 // Restarting simulation or taking a big step, new time at ntime
643 // Initialize ow fields to 0 for time interp, will be replaced
644 m_ow_levelset.setVal(0.0);
645 m_ow_velocity.setVal(0.0);
646 // No modification needed for t_last, leads to interp factor = 1
647 }
648
649 // After possible prior read, now read data for this ntime
650 if (wdata.do_interp) {
651 populate_fields_all_levels(
652 wdata, geom, w2a_levelset, w2a_velocity);
653 }
654
655 // Average down to get fine information on coarse grid where
656 // possible (may be unnecessary)
657 for (int lev = nlevels - 1; lev > 0; --lev) {
658 amrex::average_down(
659 w2a_velocity(lev), w2a_velocity(lev - 1), 0, AMREX_SPACEDIM,
660 sim.mesh().refRatio(lev - 1));
661 amrex::average_down(
662 w2a_levelset(lev), w2a_levelset(lev - 1), 0, 1,
663 sim.mesh().refRatio(lev - 1));
664 }
665 // Fill patch to get correct ghost cells after average down
666 w2a_velocity.fillpatch(sim.time().new_time());
667 w2a_levelset.fillpatch(sim.time().new_time());
668 }
669
670 // Temporally interpolate at every timestep to get target solution
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();
676
677 const amrex::Real W2A_t = wdata.t;
678 amrex::ParallelFor(
679 m_ow_levelset(lev), amrex::IntVect(3),
680 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) noexcept {
681 // Interpolate temporally every time
682 phi[nbx](i, j, k) +=
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);
694 });
695 }
696 amrex::Gpu::synchronize();
697#else
698 amrex::ignore_unused(data);
699#endif
700 }
701};
702
703} // namespace amr_wind::ocean_waves::ops
704
705#endif /* WAVES2AMR_OPS_H */
FieldRepo & repo()
Return the field repository.
Definition CFDSim.H:66
SimTime & time()
Return simulation time control.
Definition CFDSim.H:62
Definition Field.H:116
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
Definition W2AWaves.H:14
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
Definition W2AWaves.H:95
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, const ::amr_wind::utils::MultiParser &pp)
Definition waves2amr_ops.H:193
Definition OceanWavesOps.H:19
void operator()(W2AWaves::DataType &data)
Definition waves2amr_ops.H:506