REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_FillPatch.cpp
Go to the documentation of this file.
1#include <REMORA.H>
5
6using namespace amrex;
7
9
10/**
11 * Fill valid and ghost data in the MultiFab "mf"
12 * This version fills the MultiFab mf_to_fill in valid regions with
13 * the "state data" at the given time;
14 * values in mf when it is passed in are *not* used.
15 *
16 * @param[in ] lev level to FillPatch on
17 * @param[in ] time current time
18 * @param[inout] mf_to_fill MultiFab to fill
19 * @param[in ] mfs vector over levels of multifabs associated with mf_to_fill
20 * @param[in ] bccomp index into domain_bcs_type
21 * @param[in ] bdy_var_type when filling from NetCDF, which boundary data
22 * @param[in ] icomp component to fill
23 * @param[in ] fill_all whether to fill all components
24 * @param[in ] fill_set whether to use FillPatchers
25 * @param[in ] icomp_calc component to use in RHS boundary calculation
26 * @param[in ] dt_lev time step at this level
27 * @param[in ] mf_calc data to use in RHS boundary calculation
28 */
29void
31 const int bccomp,
33 const int bdy_var_type,
34#else
35 const int /*bdy_var_type*/,
36#endif
37 const int icomp,
38 const bool fill_all,
39 const bool fill_set,
40 const int n_not_fill,
42 const int icomp_calc,
43 const Real dt_lev,
44#else
45 const int /*icomp_calc*/,
46 const Real /*dt_lev*/,
47#endif
48 const MultiFab& mf_calc,
51{
52 BL_PROFILE_VAR("REMORA::FillPatch()",REMORA_FillPatch);
53 amrex::Interpolater* mapper = nullptr;
54
55 Box mf_box(mf_to_fill.boxArray()[0]);
56 bool is_2d = mf_box.length(2) == 1;
57
58 MultiFab* mask;
59
60 //
61 // ***************************************************************************
62 // The first thing we do is interpolate the momenta on the "valid" faces of
63 // the fine grids (where the interface is coarse/fine not fine/fine) -- this
64 // will not be over-written below because the FillPatch operators see these as
65 // valid faces.
66 // ***************************************************************************
67 if (lev>0 && fill_set) {
68 if (cf_set_width > 0 &&
69 mf_box.ixType() == IndexType(IntVect(0,0,0))) {
71 } else if (cf_set_width >= 0) {
72 if (!is_2d) {
73 if (mf_box.ixType() == IndexType(IntVect(1,0,0))) {
75 } else if (mf_box.ixType() == IndexType(IntVect(0,1,0))) {
77 } else if (mf_box.ixType() == IndexType(IntVect(0,0,1))) {
79 }
80 } else {
81 if (mf_box.ixType() == IndexType(IntVect(1,0,0))) {
83 } else if (mf_box.ixType() == IndexType(IntVect(0,1,0))) {
85 }
86 }
87 }
88 }
89
90 int ncomp;
91 if (fill_all) {
92 ncomp = mf_to_fill.nComp();
93 } else {
94 ncomp = 1;
95 }
96
97 if (mf_box.ixType() == IndexType(IntVect(0,0,0)))
98 {
100 mask = vec_mskr[lev].get();
101 }
102 else if (mf_box.ixType() == IndexType(IntVect(1,0,0)))
103 {
105 mask = vec_msku[lev].get();
106 }
107 else if (mf_box.ixType() == IndexType(IntVect(0,1,0)))
108 {
110 mask = vec_mskv[lev].get();
111 }
112 else {
114 mask = vec_mskr[lev].get();
115 }
116
117 if (lev == 0)
118 {
121 amrex::FillPatchSingleLevel(mf_to_fill, time, fmf, ftime, icomp, icomp, ncomp,
123 }
124 else
125 {
128 // A subcycled fine level asks for times inside the parent's step, so the coarse
129 // contribution has to be interpolated. Passing one MultiFab twice makes
130 // FillPatchTwoLevels return it whatever the time: fine in lockstep, wrong for
131 // subcycling.
132 Vector<MultiFab*> cmf = {mfs[lev-1], mfs[lev-1]};
134 if (do_substep && int(mfs_crse_old.size()) >= lev && int(mfs_crse_new.size()) >= lev) {
136 ctime = {t_old[lev-1], t_new[lev-1]};
137 mfs_crse_old[lev-1]->FillBoundary(geom[lev-1].periodicity());
138 mfs_crse_new[lev-1]->FillBoundary(geom[lev-1].periodicity());
139 }
140
141 mfs[lev-1]->FillBoundary(geom[lev-1].periodicity());
142 amrex::FillPatchTwoLevels(mf_to_fill, mf_to_fill.nGrowVect(), IntVect(0,0,0),
143 time, cmf, ctime, fmf, ftime,
144 icomp, icomp, ncomp, geom[lev-1], geom[lev],
145 //null_bc, bccomp, null_bc, bccomp,
146 refRatio(lev-1),
148 } // lev > 0
149
150 // This is currently unconditionally true, but do_bc flag should actually be passed in
151 const bool do_bc=true;
152 if (do_bc) {
153 // ***************************************************************************
154 // Physical bc's at domain boundary
155 // ***************************************************************************
156
157 // Enforce physical boundary conditions
159 *vec_msku[lev].get(), *vec_mskv[lev].get());
160
161#ifdef REMORA_USE_NETCDF
162 // Fill the data which is stored in the boundary data read from netcdf files
164 {
166 }
167#endif
168 // Fill corners of the domain with periodic data
169 if ( mf_box.ixType() == IndexType(IntVect(0,0,0)) ) {
170 mf_to_fill.EnforcePeriodicity(geom[lev].periodicity());
171 }
172
173 // Also enforce free-slip at top boundary (on xvel or yvel)
174 if ( (mf_box.ixType() == IndexType(IntVect(1,0,0))) ||
175 (mf_box.ixType() == IndexType(IntVect(0,1,0))) )
176 {
177 int khi = geom[lev].Domain().bigEnd(2);
178 for (MFIter mfi(mf_to_fill); mfi.isValid(); ++mfi)
179 {
180 Box gbx = mfi.growntilebox(); // Note this is face-centered since vel is
181 gbx.setSmall(2,khi+1);
182 if (gbx.ok()) {
184 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
185 {
186 vel_arr(i,j,k) = vel_arr(i,j,khi);
187 });
188 }
189 }
190 }
191 }
192}
193
194/**
195 * Fill valid and ghost data in the MultiFab "mf"
196 * This version fills the MultiFab mf_to_fill in valid regions with
197 * the "state data" at the given time;
198 * values in mf when it is passed in are *not* used.
199 * Unlike FillPatch, FillPatchNoBC does not apply boundary conditions
200 *
201 * @param[in ] lev level to FillPatch on
202 * @param[in ] time current time
203 * @param[inout] mf_to_fill MultiFab to fill
204 * @param[in ] mfs vector over levels of multifabs associated with mf_to_fill
205 * @param[in ] bdy_var_type when filling from NetCDF, which boundary data
206 * @param[in ] icomp component to fill
207 * @param[in ] fill_all whether to fill all components
208 * @param[in ] fill_set whether to use FillPatchers
209 */
210void
213 const int /*bdy_var_type*/,
214#else
215 const int /*bdy_var_type*/,
216#endif
217 const int icomp,
218 const bool fill_all,
219 const bool fill_set,
222{
223 // HACK: Note that this is hacky; should be able to have a single call to FillPatch with a
224 // flag for bcs, but for some reason it was acting weird, so we're splitting this out into
225 // two functions with repeated code for the time being
226 BL_PROFILE_VAR("REMORA::FillPatchNoBC()",REMORA_FillPatch);
227 int bccomp;
228 amrex::Interpolater* mapper = nullptr;
229
230 Box mf_box(mf_to_fill.boxArray()[0]);
231 bool is_2d = mf_box.length(2) == 1;
232
233 //
234 // ***************************************************************************
235 // The first thing we do is interpolate the momenta on the "valid" faces of
236 // the fine grids (where the interface is coarse/fine not fine/fine) -- this
237 // will not be over-written below because the FillPatch operators see these as
238 // valid faces.
239 // ***************************************************************************
240 if (lev>0 && fill_set) {
241 if (cf_set_width > 0 &&
242 mf_box.ixType() == IndexType(IntVect(0,0,0))) {
244 } else if (cf_set_width >= 0) {
245 if (!is_2d) {
246 if (mf_box.ixType() == IndexType(IntVect(1,0,0))) {
248 } else if (mf_box.ixType() == IndexType(IntVect(0,1,0))) {
250 } else if (mf_box.ixType() == IndexType(IntVect(0,0,1))) {
252 }
253 } else {
254 if (mf_box.ixType() == IndexType(IntVect(1,0,0))) {
256 } else if (mf_box.ixType() == IndexType(IntVect(0,1,0))) {
258 }
259 }
260 }
261 }
262
263 int ncomp;
264 if (fill_all) {
265 ncomp = mf_to_fill.nComp();
266 } else {
267 ncomp = 1;
268 }
269
270 if (mf_box.ixType() == IndexType(IntVect(0,0,0)))
271 {
272 bccomp = 0;
274 }
275 else if (mf_box.ixType() == IndexType(IntVect(1,0,0)))
276 {
277 bccomp = xvel_bc();
279 }
280 else if (mf_box.ixType() == IndexType(IntVect(0,1,0)))
281 {
282 bccomp = yvel_bc();
284 }
285 else {
286 bccomp = zvel_bc();
288 }
289
290 if (lev == 0)
291 {
294 amrex::FillPatchSingleLevel(mf_to_fill, time, fmf, ftime, icomp, icomp, ncomp,
296 }
297 else
298 {
301 // A subcycled fine level asks for times inside the parent's step, so the coarse
302 // contribution has to be interpolated. Passing one MultiFab twice makes
303 // FillPatchTwoLevels return it whatever the time: fine in lockstep, wrong for
304 // subcycling.
305 Vector<MultiFab*> cmf = {mfs[lev-1], mfs[lev-1]};
307 if (do_substep && int(mfs_crse_old.size()) >= lev && int(mfs_crse_new.size()) >= lev) {
309 ctime = {t_old[lev-1], t_new[lev-1]};
310 mfs_crse_old[lev-1]->FillBoundary(geom[lev-1].periodicity());
311 mfs_crse_new[lev-1]->FillBoundary(geom[lev-1].periodicity());
312 }
313
314 mfs[lev-1]->FillBoundary(geom[lev-1].periodicity());
315 amrex::FillPatchTwoLevels(mf_to_fill, mf_to_fill.nGrowVect(), IntVect(0,0,0),
316 time, cmf, ctime, fmf, ftime,
317 icomp, icomp, ncomp, geom[lev-1], geom[lev],
318 //null_bc, bccomp, null_bc, bccomp,
319 refRatio(lev-1),
321 } // lev > 0
322}
323
324
325// utility to copy in data from old/new data into a struct that holds data for FillPatching
327REMORA::GetDataAtTime (int /*lev*/, Real /*time*/)
328{
329 BL_PROFILE_VAR("GetDataAtTime()",GetDataAtTime);
331
332// HACK HACK HACK
333#if 0
334 const Real teps = (t_new[lev] - t_old[lev]) * 1.e-3_rt;
335
336 if (time > t_new[lev] - teps && time < t_new[lev] + teps)
337 {
338 for (int i = 0; i < Vars::NumTypes; ++i) {
339 data.add_var(&vars_new[lev][i], data.non_owning);
340 }
341 data.set_time(t_new[lev]);
342 }
343 else if (time > t_old[lev] - teps && time < t_old[lev] + teps)
344 {
345 for (int i = 0; i < Vars::NumTypes; ++i) {
346 data.add_var(&vars_old[lev][i], data.non_owning);
347 }
348 data.set_time(t_old[lev]);
349 }
350 else if (time > t_old[lev] && time < t_new[lev])
351 {
352 // do first order interpolation in time between [t_old[lev], t_new[lev]]
353 // time interpolation includes the ghost cells
354 for (int i = 0; i < Vars::NumTypes; ++i) {
355 MultiFab* mf_tmp = new MultiFab(vars_new[lev][i].boxArray(),
358 mf_tmp->setVal(0.0_rt);
359
360 const Real dt_fraction = (time - t_old[lev]) / (t_new[lev] - t_old[lev]);
361 MultiFab::Saxpy(*mf_tmp, 1.0_rt - dt_fraction, vars_old[lev][i], 0, 0, mf_tmp->nComp(), mf_tmp->nGrowVect());
362 MultiFab::Saxpy(*mf_tmp, dt_fraction, vars_new[lev][i], 0, 0, mf_tmp->nComp(), mf_tmp->nGrowVect());
363
364 data.add_var(mf_tmp, data.owning);
365 }
366 data.set_time(time);
367 }
368 else
369 {
370 amrex::Error("Requested data at a time outside the interval [t_old, t_new]");
371 }
372
373 // We need to make sure to fill these before we compute the viscosity
374 for (int i = 0; i < Vars::NumTypes; ++i) {
375 data.get_var(Vars::xvel).FillBoundary(geom[lev].periodicity());
376 data.get_var(Vars::yvel).FillBoundary(geom[lev].periodicity());
377 data.get_var(Vars::zvel).FillBoundary(geom[lev].periodicity());
378 data.get_var(Vars::cons).FillBoundary(geom[lev].periodicity());
379 }
380#endif
381 return data;
382}
383
384
385/**
386 * Like FillCoarsePatch but uses piecewise constant interpolater
387 *
388 * @param[in ] lev level to FillPatch on
389 * @param[in ] time current time
390 * @param[inout] mf_to_fill MultiFab to fill
391 * @param[inout] mf_crse MultiFab of coarse data
392 * @param[in ] bccomp index into domain_bcs_type
393 * @param[in ] bdy_var_type when filling from NetCDF, which boundary data
394 * @param[in ] icomp component to fill
395 * @param[in ] fill_all whether to fill all components
396 * @param[in ] icomp_calc component to use in RHS boundary calculation
397 * @param[in ] dt_lev time step at this level
398 * @param[in ] mf_calc data to use in RHS boundary calculation
399 */
400void
402 MultiFab* mf_crse,
403 const int bccomp,
404 const int bdy_var_type,
405 const int icomp,
406 const bool fill_all,
407 const int n_not_fill,
408 const int icomp_calc,
409 const Real dt_lev,
410 const MultiFab& mf_calc) {
411 amrex::Interpolater* mapper = &pc_interp;
414}
415
416/**
417 * Fill an entire multifab by interpolating from the coarser level --
418 * this is used only when a new level of refinement is being created
419 * during a run (i.e not at initialization)
420 * This will never be used with static refinement.
421 *
422 * @param[in ] lev level to FillPatch on
423 * @param[in ] time current time
424 * @param[inout] mf_to_fill MultiFab to fill
425 * @param[inout] mf_crse MultiFab of coarse data
426 * @param[in ] bccomp index into domain_bcs_type
427 * @param[in ] bdy_var_type when filling from NetCDF, which boundary data
428 * @param[in ] icomp component to fill
429 * @param[in ] fill_all whether to fill all components
430 * @param[in ] icomp_calc component to use in RHS boundary calculation
431 * @param[in ] dt_lev time step at this level
432 * @param[in ] mf_calc data to use in RHS boundary calculation
433 */
434void
436 MultiFab* mf_crse,
437 const int bccomp,
438 const int bdy_var_type,
439 const int icomp,
440 const bool fill_all,
441 const int n_not_fill,
442 const int icomp_calc,
443 const Real dt_lev,
444 const MultiFab& mf_calc) {
445 amrex::Interpolater* mapper = nullptr;
448}
449
450/**
451 * Fill an entire multifab by interpolating from the coarser level --
452 * this is used only when a new level of refinement is being created
453 * during a run (i.e not at initialization)
454 * This will never be used with static refinement.
455 *
456 * @param[in ] lev level to FillPatch on
457 * @param[in ] time current time
458 * @param[inout] mf_to_fill MultiFab to fill
459 * @param[inout] mf_crse MultiFab of coarse data
460 * @param[in ] bccomp index into domain_bcs_type
461 * @param[in ] bdy_var_type when filling from NetCDF, which boundary data
462 * @param[in ] icomp component to fill
463 * @param[in ] fill_all whether to fill all components
464 * @param[in ] icomp_calc component to use in RHS boundary calculation
465 * @param[in ] dt_lev time step at this level
466 * @param[in ] mf_calc data to use in RHS boundary calculation
467 */
468void
469REMORA::FillCoarsePatchMap (int lev, Real time, MultiFab* mf_to_fill, MultiFab* mf_crse,
470 const int bccomp,
472 const int bdy_var_type,
473#else
474 const int /*bdy_var_type*/,
475#endif
476 const int icomp,
477 const bool fill_all,
478 const int n_not_fill,
479 const int icomp_calc,
480 const Real dt_lev,
481 const MultiFab& mf_calc,
482 amrex::Interpolater* mapper)
483{
484 BL_PROFILE_VAR("FillCoarsePatch()",FillCoarsePatch);
485 AMREX_ASSERT(lev > 0);
486
487 MultiFab* mask = nullptr;
488
489 int ncomp;
490 if (fill_all) {
491 ncomp = mf_to_fill->nComp();
492 } else {
493 ncomp = 1;
494 }
495
496 Box box_mf(mf_to_fill->boxArray()[0]);
497
498 if (box_mf.ixType() == IndexType(IntVect(0,0,0)))
499 {
500 mask = vec_mskr[lev].get();
501 }
502 else if (box_mf.ixType() == IndexType(IntVect(1,0,0)))
503 {
504 mask = vec_msku[lev].get();
505 }
506 else if (box_mf.ixType() == IndexType(IntVect(0,1,0)))
507 {
508 mask = vec_mskv[lev].get();
509 }
510 else if (box_mf.ixType() == IndexType(IntVect(0,0,1)))
511 {
512 mask = vec_mskr[lev].get();
513 } else {
514 amrex::Abort("Dont recognize this box type in REMORA_FillPatch");
515 }
516
517 if (mapper == nullptr) {
518 if (box_mf.ixType() == IndexType(IntVect(0,0,0)))
519 {
521 }
522 else if (box_mf.ixType() == IndexType(IntVect(1,0,0)))
523 {
525 }
526 else if (box_mf.ixType() == IndexType(IntVect(0,1,0)))
527 {
529 }
530 else if (box_mf.ixType() == IndexType(IntVect(0,0,1)))
531 {
533 } else {
534 amrex::Abort("Dont recognize this box type in REMORA_FillPatch");
535 }
536 }
537
538 mf_crse->FillBoundary(geom[lev-1].periodicity());
539 amrex::InterpFromCoarseLevel(*mf_to_fill, mf_to_fill->nGrowVect(), IntVect(0,0,0),
540 *mf_crse, 0, icomp, ncomp, geom[lev-1], geom[lev],
541 refRatio(lev-1),
543
544 // ***************************************************************************
545 // Physical bc's at domain boundary
546 // ***************************************************************************
547
548 // The radiation conditions compare the field with its previous state (mf_calc),
549 // which a level being created does not have. Give them the interpolated field
550 // itself: the ghost cells then keep the coarse values and the nudging term,
551 // with no time step, is zero. Only the radiation conditions read it, so the
552 // copy is made only when one of them is set on this field, and only of the
553 // components being filled. It cannot be an alias of the field: the radiation
554 // kernels read the along-boundary neighbours of the column they write, so on a
555 // GPU a thread could read a cell another thread has already overwritten.
556 MultiFab calc_copy;
557 const MultiFab* calc = &mf_calc;
559 if (!mf_calc.ok()) {
560 bool radiation = false;
561 for (int n = 0; n < ncomp; ++n) {
562 const BCRec& bcr = domain_bcs_type[bccomp+n];
563 for (int dir = 0; dir < 2; ++dir) {
564 for (int bc : {bcr.lo(dir), bcr.hi(dir)}) {
567 }
568 }
569 }
570 if (radiation) {
571 calc_copy.define(mf_to_fill->boxArray(), mf_to_fill->DistributionMap(),
572 ncomp, mf_to_fill->nGrowVect());
573 MultiFab::Copy(calc_copy, *mf_to_fill, icomp, 0, ncomp,
574 mf_to_fill->nGrowVect());
575 calc = &calc_copy;
576 icomp_calc_used = 0;
577 }
578 }
579
580 // Enforce physical boundary conditions
581 (*physbcs[lev])(*mf_to_fill,*mask,icomp,ncomp,mf_to_fill->nGrowVect(),
583 *vec_msku[lev].get(), *vec_mskv[lev].get());
584
585#ifdef REMORA_USE_NETCDF
586 // Fill the data which is stored in the boundary data read from netcdf files
588 {
590 }
591#else
592 amrex::ignore_unused(icomp_calc_used, dt_lev);
593#endif
594 // Fill corners of the domain with periodic data
595 if ( box_mf.ixType() == IndexType(IntVect(0,0,0)) ) {
596 mf_to_fill->EnforcePeriodicity(geom[lev].periodicity());
597 } else {
598 // The face-centred analogue. InterpFromCoarseLevel fills a periodic ghost from the
599 // coarse level, which for a face tangential to the periodic direction does not
600 // reproduce the fine value it wraps to: on a new level of Channel_Test, vbar's x
601 // ghosts at the seam differed from their images by 2e-4 to 6e-4 where zeta's,
602 // corrected above, were exact. The first barotropic substep then sees different vbar
603 // at the two copies of the periodic u-face, and that one-shot asymmetry amplifies into
604 // a blow-up. Copying the ghosts from this level's own valid data, as every later
605 // FillPatch does, removes it.
606 mf_to_fill->FillBoundary(geom[lev].periodicity());
607 }
608
609 // Enforce free-slip at top boundary (on xvel or yvel)
610 if ( (box_mf.ixType() == IndexType(IntVect(1,0,0))) ||
611 (box_mf.ixType() == IndexType(IntVect(0,1,0))) )
612 {
613 int khi = geom[lev].Domain().bigEnd(2);
614 for (MFIter mfi(*mf_to_fill); mfi.isValid(); ++mfi)
615 {
616 Box gbx = mfi.growntilebox(); // Note this is face-centered since vel is
617 gbx.setSmall(2,khi+1);
618 if (gbx.ok()) {
620 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
621 {
622 vel_arr(i,j,k) = vel_arr(i,j,khi);
623 });
624 }
625 }
626 }
627
628}
629
630namespace {
631/**
632 * Sign for reflecting one cell-centered velocity component into a ghost cell.
633 * The normal velocity vanishes at a wall or symmetry plane; only a no-slip wall
634 * zeroes the tangential ones too. Anything else copies the adjacent valid cell.
635 *
636 * @param[in ] bc physical BC type for that component on that face
637 * @param[in ] is_normal whether the component is normal to the face
638 */
639Real
641{
642 if (is_normal) {
643 return ( (bc == REMORA_BC::slip_wall ) ||
645 (bc == REMORA_BC::symmetry ) ) ? -one : one;
646 }
647 return (bc == REMORA_BC::no_slip_wall) ? -one : one;
648}
649} // namespace
650
651/**
652 * Fill boundary ghost cells for cell-centered velocities. Each component takes
653 * the sign implied by its own BC, which with remora.boundary_per_variable can
654 * differ between u, v and w on one face.
655 *
656 * @param[in ] lev level to fill at
657 * @param[inout] mf_cc_vel MultiFab of cell-centered velocities
658 */
659void
661{
662 // Impose bc's at domain boundaries
663 Box domain(Geom(lev).Domain());
664
665 int ihi = domain.bigEnd(0);
666 int jhi = domain.bigEnd(1);
667 int khi = domain.bigEnd(2);
668
669 // Impose periodicity first
670 mf_cc_vel.FillBoundary(geom[lev].periodicity());
671
672 // Sign multipliers per face, per velocity component
674 for (OrientationIter oit; oit; ++oit) {
675 Orientation ori = oit();
676 for (int n = 0; n < AMREX_SPACEDIM; ++n) {
678 n == ori.coordDir());
679 }
680 }
681
682 // Callers pass different ghost widths (the plotfile ones carry none in z)
683 const IntVect ng = mf_cc_vel.nGrowVect();
684
685#ifdef _OPENMP
686#pragma omp parallel if (Gpu::notInLaunchRegion())
687#endif
688 for (MFIter mfi(mf_cc_vel, TilingIfNotGPU()); mfi.isValid(); ++mfi)
689 {
690 // Note that we don't fill corners here -- only the cells that share a face
691 // with interior cells -- this is all that is needed to calculate vorticity
692 const Box& bx = mfi.tilebox();
693 const Array4<Real>& vel_arr = mf_cc_vel.array(mfi);
694
695 if (!Geom(lev).isPeriodic(0) && ng[0] > 0) {
696 // Low-x side
697 if (bx.smallEnd(0) <= domain.smallEnd(0)) {
698 auto const m = mult[Orientation(Direction::x,Orientation::low)];
699 ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
700 {
701 vel_arr(-1,j,k,0) = m[0]*vel_arr(0,j,k,0); // u
702 vel_arr(-1,j,k,1) = m[1]*vel_arr(0,j,k,1); // v
703 vel_arr(-1,j,k,2) = m[2]*vel_arr(0,j,k,2); // w
704 });
705 }
706
707 // High-x side
708 if (bx.bigEnd(0) >= domain.bigEnd(0)) {
709 auto const m = mult[Orientation(Direction::x,Orientation::high)];
710 ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
711 {
712 vel_arr(ihi+1,j,k,0) = m[0]*vel_arr(ihi,j,k,0); // u
713 vel_arr(ihi+1,j,k,1) = m[1]*vel_arr(ihi,j,k,1); // v
714 vel_arr(ihi+1,j,k,2) = m[2]*vel_arr(ihi,j,k,2); // w
715 });
716 }
717 } // !periodic
718
719 if (!Geom(lev).isPeriodic(1) && ng[1] > 0) {
720 // Low-y side
721 if (bx.smallEnd(1) <= domain.smallEnd(1)) {
722 auto const m = mult[Orientation(Direction::y,Orientation::low)];
723 ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
724 {
725 vel_arr(i,-1,k,0) = m[0]*vel_arr(i,0,k,0); // u
726 vel_arr(i,-1,k,1) = m[1]*vel_arr(i,0,k,1); // v
727 vel_arr(i,-1,k,2) = m[2]*vel_arr(i,0,k,2); // w
728 });
729 }
730
731 // High-y side
732 if (bx.bigEnd(1) >= domain.bigEnd(1)) {
733 auto const m = mult[Orientation(Direction::y,Orientation::high)];
734 ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
735 {
736 vel_arr(i,jhi+1,k,0) = m[0]*vel_arr(i,jhi,k,0); // u
737 vel_arr(i,jhi+1,k,1) = m[1]*vel_arr(i,jhi,k,1); // v
738 vel_arr(i,jhi+1,k,2) = m[2]*vel_arr(i,jhi,k,2); // w
739 });
740 }
741 } // !periodic
742
743 if (!Geom(lev).isPeriodic(2) && ng[2] > 0) {
744 // Low-z side
745 if (bx.smallEnd(2) <= domain.smallEnd(2)) {
746 auto const m = mult[Orientation(Direction::z,Orientation::low)];
747 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
748 {
749 vel_arr(i,j,-1,0) = m[0]*vel_arr(i,j,0,0); // u
750 vel_arr(i,j,-1,1) = m[1]*vel_arr(i,j,0,1); // v
751 vel_arr(i,j,-1,2) = m[2]*vel_arr(i,j,0,2); // w
752 });
753 }
754
755 // High-z side
756 if (bx.bigEnd(2) >= domain.bigEnd(2)) {
757 auto const m = mult[Orientation(Direction::z,Orientation::high)];
758 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
759 {
760 vel_arr(i,j,khi+1,0) = m[0]*vel_arr(i,j,khi,0); // u
761 vel_arr(i,j,khi+1,1) = m[1]*vel_arr(i,j,khi,1); // v
762 vel_arr(i,j,khi+1,2) = m[2]*vel_arr(i,j,khi,2); // w
763 });
764 }
765 } // !periodic
766 } // MFIter
767}
constexpr amrex::Real one
PhysBCFunctNoOp null_bc
mf_h setVal(geomdata.ProbHi(2))
int zvel_bc() const noexcept
Definition REMORA.H:1487
int xvel_bc() const noexcept
Definition REMORA.H:1485
amrex::Vector< amrex::BCRec > domain_bcs_type
vector (over BCVars) of BCRecs
Definition REMORA.H:1772
void FillCoarsePatchMap(int lev, amrex::Real time, amrex::MultiFab *mf_fine, amrex::MultiFab *mf_crse, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab(), amrex::Interpolater *mapper=nullptr)
fill an entire multifab by interpolating from the coarser level, explicitly specifying interpolator t...
amrex::Vector< REMORAFillPatcher > FPr_v
Vector over levels of FillPatchers for v (3D)
Definition REMORA.H:1690
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr
land/sea mask at cell centers (2D)
Definition REMORA.H:584
int do_substep
Whether to substep fine levels in time.
Definition REMORA.H:1873
int yvel_bc() const noexcept
Definition REMORA.H:1486
void fill_from_bdyfiles(int lev, amrex::MultiFab &mf_to_fill, const amrex::MultiFab &mf_mask, const amrex::Real time, const int bccomp, const int bdy_var_type, const int icomp_to_fill, const int icomp_calc=0, const amrex::MultiFab &mf_calc=amrex::MultiFab(), const amrex::Real=zero)
Fill boundary data from netcdf file.
amrex::Vector< REMORAFillPatcher > FPr_u
Vector over levels of FillPatchers for u (3D)
Definition REMORA.H:1688
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_msku
land/sea mask at x-faces (2D)
Definition REMORA.H:586
amrex::Vector< amrex::GpuArray< REMORA_BC, AMREX_SPACEDIM *2 > > phys_bc_type
Array holding the "physical" boundary condition types (e.g. "inflow")
Definition REMORA.H:1783
amrex::Vector< REMORAFillPatcher > FPr_vbar
Vector over levels of FillPatchers for vbar (2D)
Definition REMORA.H:1698
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskv
land/sea mask at y-faces (2D)
Definition REMORA.H:588
amrex::Vector< std::unique_ptr< REMORAPhysBCFunct > > physbcs
Vector (over level) of functors to apply physical boundary conditions.
Definition REMORA.H:1754
void FillCoarsePatch(int lev, amrex::Real time, amrex::MultiFab *mf_fine, amrex::MultiFab *mf_crse, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab())
fill an entire multifab by interpolating from the coarser level
void FillBdyCCVels(int lev, amrex::MultiFab &mf_cc_vel)
Fill the physical boundary conditions for cell-centered velocity (diagnostic only)
TimeInterpolatedData GetDataAtTime(int lev, amrex::Real time)
utility to copy in data from old and/or new state into another multifab
amrex::Vector< REMORAFillPatcher > FPr_c
Vector over levels of FillPatchers for scalars.
Definition REMORA.H:1686
amrex::Vector< REMORAFillPatcher > FPr_w
Vector over levels of FillPatchers for w.
Definition REMORA.H:1692
amrex::Vector< amrex::Real > t_new
new time at each level, in seconds since start_time
Definition REMORA.H:1744
static SolverChoice solverChoice
Container for algorithmic choices.
Definition REMORA.H:2017
int cf_set_width
Width for fixing values at coarse-fine interface.
Definition REMORA.H:1683
void FillPatchNoBC(int lev, amrex::Real time, amrex::MultiFab &mf_to_be_filled, amrex::Vector< amrex::MultiFab * > const &mfs, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const bool fill_set=false, amrex::Vector< amrex::MultiFab * > const &mfs_crse_old={}, amrex::Vector< amrex::MultiFab * > const &mfs_crse_new={})
Fill a new MultiFab by copying in phi from valid region and filling ghost cells without applying boun...
void FillCoarsePatchPC(int lev, amrex::Real time, amrex::MultiFab *mf_fine, amrex::MultiFab *mf_crse, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab())
fill an entire multifab by interpolating from the coarser level using the piecewise constant interpol...
void FillPatch(int lev, amrex::Real time, amrex::MultiFab &mf_to_be_filled, amrex::Vector< amrex::MultiFab * > const &mfs, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const bool fill_set=false, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab(), amrex::Vector< amrex::MultiFab * > const &mfs_crse_old={}, amrex::Vector< amrex::MultiFab * > const &mfs_crse_new={})
Fill a new MultiFab by copying in phi from valid region and filling ghost cells.
amrex::Vector< REMORAFillPatcher > FPr_ubar
Vector over levels of FillPatchers for ubar (2D)
Definition REMORA.H:1696
amrex::Vector< amrex::Real > t_old
old time at each level, in seconds since start_time
Definition REMORA.H:1746
static constexpr int null