Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_EB2_Level.H
Go to the documentation of this file.
1#ifndef AMREX_EB2_LEVEL_H_
2#define AMREX_EB2_LEVEL_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_ParmParse.H>
6#include <AMReX_Geometry.H>
7#include <AMReX_MultiFab.H>
8#include <AMReX_iMultiFab.H>
9#include <AMReX_LayoutData.H>
10#include <AMReX_VisMF.H>
11#include <AMReX_Array.H>
12#include <AMReX_EBCellFlag.H>
13#include <AMReX_MultiCutFab.H>
14#if (AMREX_SPACEDIM == 3)
15# include <AMReX_MarchingCubes.H>
16#endif
17#include <AMReX_EB2_MultiGFab.H>
18#include <AMReX_EB2_C.H>
20
21#ifdef AMREX_USE_OMP
22#include <omp.h>
23#endif
24
25#include <cmath>
26#include <limits>
27#include <map>
28#include <type_traits>
29#include <unordered_map>
30
31namespace amrex
32{
33 class STLtools;
34}
35
36namespace amrex::EB2 {
37
38class IndexSpace;
39template <typename G> class GShopLevel;
40template <typename G> class IndexSpaceImp;
41
42class Level
43{
44public:
45
47 bool isAllRegular () const noexcept { return m_allregular; }
49 bool isOK () const noexcept { return m_ok; }
60 void fillVolFrac (MultiFab& vfrac, const Geometry& geom) const;
64 void fillCentroid (MultiCutFab& centroid, const Geometry& geom) const;
66 void fillCentroid ( MultiFab& centroid, const Geometry& geom) const;
70 void fillBndryArea (MultiCutFab& bndryarea, const Geometry& geom) const;
72 void fillBndryArea ( MultiFab& bndryarea, const Geometry& geom) const;
76 void fillBndryCent (MultiCutFab& bndrycent, const Geometry& geom) const;
78 void fillBndryCent ( MultiFab& bndrycent, const Geometry& geom) const;
82 void fillBndryNorm (MultiCutFab& bndrynorm, const Geometry& geom) const;
84 void fillBndryNorm ( MultiFab& bndrynorm, const Geometry& geom) const;
88 void fillAreaFrac (Array<MultiCutFab*,AMREX_SPACEDIM> const& areafrac, const Geometry& geom) const;
90 void fillAreaFrac (Array< MultiFab*,AMREX_SPACEDIM> const& areafrac, const Geometry& geom) const;
94 void fillFaceCent (Array<MultiCutFab*,AMREX_SPACEDIM> const& facecent, const Geometry& geom) const;
96 void fillFaceCent (Array< MultiFab*,AMREX_SPACEDIM> const& facecent, const Geometry& geom) const;
100 void fillEdgeCent (Array<MultiCutFab*,AMREX_SPACEDIM> const& edgecent, const Geometry& geom) const;
102 void fillEdgeCent (Array< MultiFab*,AMREX_SPACEDIM> const& edgecent, const Geometry& geom) const;
106 void fillLevelSet (MultiFab& levelset, const Geometry& geom) const;
107
109 const BoxArray& boxArray () const noexcept { return m_grids; }
111 const DistributionMapping& DistributionMap () const noexcept { return m_dmap; }
112
114 Level (IndexSpace const* is, const Geometry& geom) : m_geom(geom), m_parent(is) {}
118 void prepareForCoarsening (const Level& rhs, int max_grid_size, IntVect const& ngrow);
119
121 const Geometry& Geom () const noexcept { return m_geom; }
123 IndexSpace const* getEBIndexSpace () const noexcept { return m_parent; }
124
126 IntVect const& nGrowVect () const noexcept { return m_ngrow; }
127
135 void write_to_chkpt_file (const std::string& fname, bool extend_domain_face, int max_grid_size) const;
136
138 bool hasEBInfo () const noexcept { return m_has_eb_info; }
140 void fillCutCellMask (iMultiFab& cutcellmask, const Geometry& geom) const;
141
145 void setShift (int direction, int ncells);
146
150 struct FCData {
160 // Covered region of the refined level, coarsened onto this level. The refined level
161 // is transient, so this has to be captured while it exists. It is not the same as
162 // Level::m_covered_grids: the refined level resolves the body more finely, so once
163 // coarsened its covered region is the larger of the two, and it is the one that
164 // matches where the face-centered data was computed.
165 //
166 // The fill*FC functions apply it before their ParallelCopy, and deliberately do not
167 // shrink it first. A face-centered cell straddles two cell-centered cells, so the
168 // ones on the covered/cut interface may themselves be cut; clearing them here and
169 // letting the copy write over them is correct, because the copy writes exactly where
170 // the face-centered data is valid - the nodal span of the cut boxes, which reaches
171 // the interface and no further. Ordering does the shrinking, so no box has to be
172 // trimmed and two adjacent covered boxes need no special treatment.
174 bool m_built = false;
175 };
176
185 [[nodiscard]] static IntVect fcEdgeType (int idim, int face_dir) noexcept {
186 IntVect edge_type{1};
187 if (idim != face_dir) { edge_type[idim] = 0; }
188 return edge_type;
189 }
190
192 [[nodiscard]] bool hasFCData (int face_dir) const noexcept {
193 return face_dir >= 0 && face_dir < AMREX_SPACEDIM &&
194 m_fc_data[face_dir] && m_fc_data[face_dir]->m_built;
195 }
196
198 [[nodiscard]] const FCData& getFCData (int face_dir) const {
199 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(hasFCData(face_dir), "EB2::Level: FC data not available for face_dir");
200 return *m_fc_data[face_dir];
201 }
202
204 void fillVolFracFC (MultiFab& vfrac, int face_dir, const Geometry& geom) const;
206 void fillAreaFracFC (Array< MultiFab*,AMREX_SPACEDIM> const& areafrac, int face_dir, const Geometry& geom) const;
207 void fillAreaFracFC (Array<MultiCutFab*,AMREX_SPACEDIM> const& areafrac, int face_dir, const Geometry& geom) const;
209 void fillCentroidFC (MultiFab& centroid, int face_dir, const Geometry& geom) const;
210 void fillCentroidFC (MultiCutFab& centroid, int face_dir, const Geometry& geom) const;
212 void fillBndryAreaFC (MultiFab& bndryarea, int face_dir, const Geometry& geom) const;
213 void fillBndryAreaFC (MultiCutFab& bndryarea, int face_dir, const Geometry& geom) const;
215 void fillBndryCentFC (MultiFab& bndrycent, int face_dir, const Geometry& geom) const;
216 void fillBndryCentFC (MultiCutFab& bndrycent, int face_dir, const Geometry& geom) const;
218 void fillBndryNormFC (MultiFab& bndrynorm, int face_dir, const Geometry& geom) const;
219 void fillBndryNormFC (MultiCutFab& bndrynorm, int face_dir, const Geometry& geom) const;
221 void fillEBCellFlagFC (FabArray<EBCellFlagFab>& cellflag, int face_dir, const Geometry& geom) const;
223 void fillFaceCentFC (Array< MultiFab*,AMREX_SPACEDIM> const& facecent, int face_dir, const Geometry& geom) const;
224 void fillFaceCentFC (Array<MultiCutFab*,AMREX_SPACEDIM> const& facecent, int face_dir, const Geometry& geom) const;
226 void fillEdgeCentFC (Array< MultiFab*,AMREX_SPACEDIM> const& edgecent, int face_dir, const Geometry& geom) const;
227 void fillEdgeCentFC (Array<MultiCutFab*,AMREX_SPACEDIM> const& edgecent, int face_dir, const Geometry& geom) const;
228
229// public: // for cuda
237 int coarsenFromFine (Level& fineLevel, bool fill_boundary);
239 void buildCellFlag ();
241 void buildCellFlagFC (int face_dir);
243 void buildCutCellMask (Level const& fine_level);
244
245protected:
246
253#if (AMREX_SPACEDIM == 3)
254 std::map<int,std::unique_ptr<MC::MCFab>> m_marching_cubes;
255#endif
268 bool m_allregular = false;
269 bool m_ok = false;
270 bool m_has_eb_info = true;
273
276
277private:
278 template <typename G> friend class GShopLevel;
279 // So that it can update m_parent when a level changes owner.
280 template <typename G> friend class IndexSpaceImp;
281
282 // Need this function to work around a gcc bug.
283 void setRegularLevel () {
284 m_allregular = true;
285 m_ok = true;
286 m_has_eb_info = false;
287 }
288};
289
290template <typename G>
292 : public Level
293{
294public:
298 GShopLevel (IndexSpace const* is, G const& gshop, const Geometry& geom, int max_grid_size,
299 int ngrow, bool extend_domain_face, int num_crse_opt);
303 GShopLevel (IndexSpace const* is, int ilev, int max_grid_size, int ngrow,
304 const Geometry& geom, GShopLevel<G>& fineLevel);
306 GShopLevel (IndexSpace const* is, const Geometry& geom);
308 void define_fine (G const& gshop, const Geometry& geom,
309 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt);
310
311#if (AMREX_SPACEDIM == 3)
315 template <typename GS = G>
316 requires (std::same_as<GS,STLtools>)
317 void define_fine_mvmc (GS const& gshop, const Geometry& geom,
318 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt);
319#endif
320
324 static GShopLevel<G>
325 makeAllRegular(IndexSpace const* is, const Geometry& geom)
326 {
327 GShopLevel<G> r(is, geom);
328 r.setRegularLevel();
329 return r;
330 }
331
333 void buildFCData (G const& gshop, int face_dir, int max_grid_size);
334
335private:
336
337 Box m_bounding_box;
338
339 void prepare_grids (G const& gshop, Geometry const& geom, int max_grid_size, int ngrow,
340 bool extend_domain_face, int num_crse_opt);
341
342};
343
344template <typename G>
346 : Level(is, geom)
347{}
348
349template <typename G>
350GShopLevel<G>::GShopLevel (IndexSpace const* is, G const& gshop, const Geometry& geom,
351 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
352 : Level(is, geom)
353{
354 if (std::is_same_v<typename G::FunctionType, AllRegularIF>) {
355 m_allregular = true;
356 m_ok = true;
357 return;
358 }
359
360 define_fine(gshop, geom, max_grid_size, ngrow, extend_domain_face, num_crse_opt);
361}
362
363template <typename G>
364void
365GShopLevel<G>::prepare_grids (G const& gshop, const Geometry& geom,
366 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
367{
368 if (amrex::Verbose() > 0 && extend_domain_face == false) {
369 amrex::Print() << "AMReX WARNING: extend_domain_face=false is not recommended!\n";
370 }
371
372 BL_PROFILE("EB2::GShopLevel()-prepare_grids");
373
374 // make sure ngrow is multiple of 16
375 m_ngrow = IntVect{static_cast<int>(std::ceil(ngrow/16.)) * 16};
376
377 Box const& domain = geom.Domain();
378 Box domain_grown = domain;
379 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
380 if (geom.isPeriodic(idim)) {
381 m_ngrow[idim] = 0;
382 } else {
383 m_ngrow[idim] = std::min(m_ngrow[idim], domain_grown.length(idim));
384 }
385 }
386 domain_grown.grow(m_ngrow);
387 m_bounding_box = (extend_domain_face) ? domain : domain_grown;
388 m_bounding_box.surroundingNodes();
389
390 BoxList cut_boxes;
391 BoxList covered_boxes;
392
393 const int nprocs = ParallelContext::NProcsSub();
394 const int iproc = ParallelContext::MyProcSub();
395
396 num_crse_opt = std::max(0,std::min(8,num_crse_opt));
397 for (int clev = num_crse_opt; clev >= 0; --clev) {
398 IntVect crse_ratio(1 << clev);
399 if (domain.coarsenable(crse_ratio)) {
400 Box const& crse_bounding_box = amrex::coarsen(m_bounding_box, crse_ratio);
401 Geometry const& crse_geom = amrex::coarsen(geom, crse_ratio);
402 BoxList test_boxes;
403 if (cut_boxes.isEmpty()) {
404 covered_boxes.clear();
405 test_boxes = BoxList(crse_geom.Domain());
406 test_boxes.maxSize(max_grid_size);
407 } else {
408 test_boxes.swap(cut_boxes);
409 test_boxes.coarsen(crse_ratio);
410 test_boxes.maxSize(max_grid_size);
411 }
412
413 const Long nboxes = test_boxes.size();
414 const auto& boxes = test_boxes.data();
415 for (Long i = iproc; i < nboxes; i += nprocs) {
416 const Box& vbx = boxes[i];
417 const Box& gbx = amrex::surroundingNodes(amrex::grow(vbx,1));
418 auto box_type = gshop.getBoxType(gbx&crse_bounding_box,crse_geom,RunOn::Gpu,
419 crse_bounding_box);
420 if (box_type == gshop.allcovered) {
421 covered_boxes.push_back(amrex::refine(vbx, crse_ratio));
422 } else if (box_type == gshop.mixedcells) {
423 cut_boxes.push_back(amrex::refine(vbx, crse_ratio));
424 }
425 }
426
427 amrex::AllGatherBoxes(cut_boxes.data());
428 }
429 }
430
431 amrex::AllGatherBoxes(covered_boxes.data());
432
433 if (m_ngrow != 0) {
434 auto grow_at_domain_boundary = [&] (BoxList& bl)
435 {
436 const IntVect& domlo = domain.smallEnd();
437 const IntVect& domhi = domain.bigEnd();
438 for (auto& b : bl) {
439 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
440 if (m_ngrow[idim] != 0) {
441 if (b.smallEnd(idim) == domlo[idim]) {
442 b.growLo(idim,m_ngrow[idim]);
443 }
444 if (b.bigEnd(idim) == domhi[idim]) {
445 b.growHi(idim,m_ngrow[idim]);
446 }
447 }
448 }
449 }
450 };
451 grow_at_domain_boundary(covered_boxes);
452 grow_at_domain_boundary(cut_boxes);
453 }
454
455 if ( cut_boxes.isEmpty() &&
456 !covered_boxes.isEmpty())
457 {
458 amrex::Abort("AMReX_EB2_Level.H: Domain is completely covered");
459 }
460
461 if (!covered_boxes.isEmpty()) {
462 if (num_crse_opt > 2) { // don't want the box too big
463 covered_boxes.maxSize(max_grid_size*4);
464 }
465 m_covered_grids = BoxArray(std::move(covered_boxes));
466 }
467
468 if (cut_boxes.isEmpty()) {
469 m_grids = BoxArray();
470 m_dmap = DistributionMapping();
471 m_allregular = true;
472 m_ok = true;
473 } else {
474 m_grids = BoxArray(std::move(cut_boxes));
475 m_dmap = DistributionMapping(m_grids);
476 }
477}
478
479template <typename G>
480void
481GShopLevel<G>::define_fine (G const& gshop, const Geometry& geom,
482 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
483{
484 BL_PROFILE("EB2::GShopLevel()-fine");
485
486#ifdef AMREX_USE_FLOAT
487 Real small_volfrac = 1.e-5_rt;
488#else
489 Real small_volfrac = 1.e-12;
490#endif
491 bool cover_multiple_cuts = false;
492 int maxiter = 32;
493 {
494 ParmParse pp("eb2");
495 pp.queryAdd("small_volfrac", small_volfrac);
496 pp.queryAdd("cover_multiple_cuts", cover_multiple_cuts);
497 pp.queryAdd("maxiter", maxiter);
498 }
499 maxiter = std::min(100000, maxiter);
500
501 prepare_grids(gshop, geom, max_grid_size, ngrow, extend_domain_face, num_crse_opt);
502
503 if (m_allregular) { return; }
504
505 m_mgf.define(m_grids, m_dmap);
506 const int ng = GFab::ng;
507 MFInfo mf_info;
508 mf_info.SetTag("EB2::Level");
509 m_cellflag.define(m_grids, m_dmap, 1, ng, mf_info);
510 m_volfrac.define(m_grids, m_dmap, 1, ng, mf_info);
511 m_centroid.define(m_grids, m_dmap, AMREX_SPACEDIM, ng, mf_info);
512 m_bndryarea.define(m_grids, m_dmap, 1, ng, mf_info);
513 m_bndrycent.define(m_grids, m_dmap, AMREX_SPACEDIM, ng, mf_info);
514 m_bndrynorm.define(m_grids, m_dmap, AMREX_SPACEDIM, ng, mf_info);
515 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
517 m_dmap, 1, ng, mf_info);
519 m_dmap, AMREX_SPACEDIM-1, ng, mf_info);
520 IntVect edge_type{1}; edge_type[idim] = 0;
521 m_edgecent[idim].define(amrex::convert(m_grids, edge_type), m_dmap, 1, ng, mf_info);
522 }
523
524 const auto dx = geom.CellSizeArray();
525 const auto problo = geom.ProbLoArray();
526
527 auto bounding_box = m_bounding_box;
528 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
529 if (!extend_domain_face || geom.isPeriodic(idim)) {
530 bounding_box.grow(idim,GFab::ng);
531 }
532 }
533
534 RunOn gshop_run_on = (Gpu::inLaunchRegion() && gshop.isGPUable())
536
537 bool hybrid = Gpu::inLaunchRegion() && (gshop_run_on == RunOn::Cpu);
539
540 int iter = 0;
541 for (; iter < maxiter; ++iter)
542 {
543 int nsmallcells = 0;
544 int nmulticuts = 0;
545#ifdef AMREX_USE_OMP
546#pragma omp parallel if (Gpu::notInLaunchRegion()) reduction(+:nsmallcells,nmulticuts)
547#endif
548 {
549#if (AMREX_SPACEDIM == 3)
550 Array<BaseFab<Real>, AMREX_SPACEDIM> M2;
551 EBCellFlagFab cellflagtmp;
552#endif
553 for (MFIter mfi(m_mgf); mfi.isValid(); ++mfi)
554 {
555 auto& gfab = m_mgf[mfi];
556 const Box& vbx = gfab.validbox();
557
558 auto& levelset = gfab.getLevelSet();
559 if (iter == 0) {
560 gshop.fillFab(levelset, geom, gshop_run_on, bounding_box);
561#ifdef AMREX_USE_GPU
562 if (hybrid) {
563 levelset.prefetchToDevice();
564 }
565#endif
566 }
567
568 auto& cellflag = m_cellflag[mfi];
569
570 // From the second iteration on, repeat a box until it stops covering
571 // cells, so a cascade advances a box per iteration instead of a cell.
572 for (int biter = 0; biter < maxiter; ++biter) {
573 gfab.buildTypes(cellflag);
574
575 Array4<Real const> const& clst = levelset.const_array();
576 Array4<Real > const& lst = levelset.array();
577 Array4<EBCellFlag> const& cfg = m_cellflag.array(mfi);
578 Array4<Real> const& vfr = m_volfrac.array(mfi);
579 Array4<Real> const& ctr = m_centroid.array(mfi);
580 Array4<Real> const& bar = m_bndryarea.array(mfi);
581 Array4<Real> const& bct = m_bndrycent.array(mfi);
582 Array4<Real> const& bnm = m_bndrynorm.array(mfi);
583 AMREX_D_TERM(Array4<Real> const& apx = m_areafrac[0].array(mfi);,
584 Array4<Real> const& apy = m_areafrac[1].array(mfi);,
585 Array4<Real> const& apz = m_areafrac[2].array(mfi););
586 AMREX_D_TERM(Array4<Real> const& fcx = m_facecent[0].array(mfi);,
587 Array4<Real> const& fcy = m_facecent[1].array(mfi);,
588 Array4<Real> const& fcz = m_facecent[2].array(mfi););
589
590 auto& facetype = gfab.getFaceType();
591 AMREX_D_TERM(Array4<Type_t> const& ftx = facetype[0].array();,
592 Array4<Type_t> const& fty = facetype[1].array();,
593 Array4<Type_t> const& ftz = facetype[2].array(););
594
595 int nmc = 0;
596 int nsm = 0;
597
598#if (AMREX_SPACEDIM == 3)
599 auto& edgetype = gfab.getEdgeType();
600 Array4<Type_t const> const& xdg = edgetype[0].const_array();
601 Array4<Type_t const> const& ydg = edgetype[1].const_array();
602 Array4<Type_t const> const& zdg = edgetype[2].const_array();
603
604 Array4<Real> const& xip = m_edgecent[0].array(mfi);
605 Array4<Real> const& yip = m_edgecent[1].array(mfi);
606 Array4<Real> const& zip = m_edgecent[2].array(mfi);
607
608 if (iter == 0 && biter == 0) {
609#ifdef AMREX_USE_GPU
610 if (hybrid) {
612 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
613 edgetype[idim].prefetchToHost();
614 m_edgecent[idim][mfi].prefetchToHost();
615 }
616 }
617#endif
618
619 gshop.getIntercept({xip,yip,zip}, {xdg,ydg,zdg}, clst,
620 geom, gshop_run_on, bounding_box);
621
622#ifdef AMREX_USE_GPU
623 if (hybrid) {
624 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
625 edgetype[idim].prefetchToDevice();
626 m_edgecent[idim][mfi].prefetchToDevice();
627 }
628 }
629#endif
630 } else {
631 gshop.updateIntercept({xip,yip,zip}, {xdg,ydg,zdg}, clst, geom);
632 }
633
634 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
635 const Box& b = facetype[idim].box();
636 M2[idim].resize(b,3);
637 }
638 Array4<Real> const& xm2 = M2[0].array();
639 Array4<Real> const& ym2 = M2[1].array();
640 Array4<Real> const& zm2 = M2[2].array();
641
642 nmc = build_faces(vbx, cfg, ftx, fty, ftz, xdg, ydg, zdg, lst,
643 xip, yip, zip, apx, apy, apz, fcx, fcy, fcz,
644 xm2, ym2, zm2, dx, problo, cover_multiple_cuts);
645
646 cellflagtmp.resize(m_cellflag[mfi].box());
647 Elixir cellflagtmp_eli = cellflagtmp.elixir();
648 Array4<EBCellFlag> const& cfgtmp = cellflagtmp.array();
649
650 build_cells(vbx, cfg, ftx, fty, ftz, apx, apy, apz,
651 fcx, fcy, fcz, xm2, ym2, zm2, dx, vfr, ctr,
652 bar, bct, bnm, cfgtmp, lst,
653 small_volfrac, geom, extend_domain_face, cover_multiple_cuts,
654 nsm, nmc);
655
656 // Because it is used in a synchronous reduction kernel in
657 // build_cells, we do not need to worry about M2's lifetime.
658 // But we still need to use Elixir to extend the life of
659 // cellflagtmp.
660
661#elif (AMREX_SPACEDIM == 2)
662 Array4<Real> const& xip = m_edgecent[0].array(mfi);
663 Array4<Real> const& yip = m_edgecent[1].array(mfi);
664
665 if (iter == 0 && biter == 0) {
666#ifdef AMREX_USE_GPU
667 if (hybrid) {
669 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
670 facetype[idim].prefetchToHost();
671 m_edgecent[idim][mfi].prefetchToHost();
672 }
673 }
674#endif
675
676 // yes, factype[1] and then [0]
677 gshop.getIntercept({xip,yip},
678 {facetype[1].const_array(), facetype[0].const_array()},
679 clst, geom, gshop_run_on, bounding_box);
680
681#ifdef AMREX_USE_GPU
682 if (hybrid) {
683 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
684 facetype[idim].prefetchToDevice();
685 m_edgecent[idim][mfi].prefetchToDevice();
686 }
687 }
688#endif
689 } else {
690 gshop.updateIntercept({xip,yip},
691 {facetype[1].const_array(), facetype[0].const_array()},
692 clst, geom);
693 }
694
695 nmc = build_faces(vbx, cfg, ftx, fty, lst, xip, yip, apx, apy, fcx, fcy,
696 dx, problo, cover_multiple_cuts, nsm);
697
698 build_cells(vbx, cfg, ftx, fty, apx, apy, dx, vfr, ctr,
699 bar, bct, bnm, lst, small_volfrac, geom, extend_domain_face,
700 nsm, nmc);
701#endif
702 nsmallcells += nsm;
703 nmulticuts += nmc;
704 if (iter == 0 || (nsm == 0 && nmc == 0)) { break; }
705 }
706 }
707 }
708
710 if (nsmallcells == 0 && nmulticuts == 0) {
711 break;
712 } else {
713 auto ls = m_mgf.getLevelSet();
714 // This is an alias MultiFab, therefore FillBoundary on it is fine.
715 ls.FillBoundary(geom.periodicity());
716 if (amrex::Verbose() > 0) {
717 if (nsmallcells) {
718 amrex::Print() << "AMReX EB: Iter. " << iter+1 << " fixed " << nsmallcells
719 << " small cells" << '\n';
720 }
721 if (nmulticuts) {
722 amrex::Print() << "AMReX EB: Iter. " << iter+1 << " fixed " << nmulticuts
723 << " multicuts" << '\n';
724 }
725 }
726 }
727 }
728
729 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(iter < maxiter, "EB: failed to fix small cells");
730
731#ifdef AMREX_USE_OMP
732#pragma omp parallel if (Gpu::notInLaunchRegion())
733#endif
734 for (MFIter mfi(m_mgf); mfi.isValid(); ++mfi)
735 {
736 auto& gfab = m_mgf[mfi];
737 auto const& levelset = gfab.getLevelSet();
738 Array4<Real const> const& clst = levelset.const_array();
739
740 AMREX_D_TERM(Array4<Real> const& xip = m_edgecent[0].array(mfi);,
741 Array4<Real> const& yip = m_edgecent[1].array(mfi);,
742 Array4<Real> const& zip = m_edgecent[2].array(mfi);)
743#if (AMREX_SPACEDIM == 3)
744 auto const& edgetype = gfab.getEdgeType();
745 Array4<Type_t const> const& xdg = edgetype[0].const_array();
746 Array4<Type_t const> const& ydg = edgetype[1].const_array();
747 Array4<Type_t const> const& zdg = edgetype[2].const_array();
748
749 intercept_to_edge_centroid(xip, yip, zip, xdg, ydg, zdg, clst, dx, problo);
750
751#elif (AMREX_SPACEDIM == 2)
752 auto& facetype = gfab.getFaceType();
753 Array4<Type_t const> const& ftx = facetype[0].const_array();
754 Array4<Type_t const> const& fty = facetype[1].const_array();
755 // fty then ftx
756 intercept_to_edge_centroid(xip, yip, fty, ftx, clst, dx, problo);
757#endif
758 }
759
760 m_levelset = m_mgf.getLevelSet();
761
762 m_ok = true;
763}
764
765#if (AMREX_SPACEDIM == 3)
766template <typename G>
767template <typename GS>
768requires (std::same_as<GS,STLtools>)
769void
770GShopLevel<G>::define_fine_mvmc (GS const& gshop, const Geometry& geom,
771 int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
772{
773 BL_PROFILE("EB2::GShopLevel()-fine-mvmc");
774
775 prepare_grids(gshop, geom, max_grid_size, ngrow, extend_domain_face, num_crse_opt);
776
777 if (m_allregular) { return; }
778
780
781 m_sdf.define(amrex::convert(m_grids,IntVect(1)), m_dmap, 1, IntVect(1));
782 gshop.fillSignedDistance(m_sdf, m_sdf.nGrowVect(), geom);
783
784 for (MFIter mfi(m_sdf,MFItInfo().DisableDeviceSync()); mfi.isValid(); ++mfi) {
785 m_marching_cubes[mfi.index()] = std::make_unique<MC::MCFab>();
786 }
787
788 MFItInfo info{};
789
790#if defined(AMREX_USE_OMP) && !defined(AMREX_USE_GPU)
791 info.SetDynamic(true);
792#pragma omp parallel
793#endif
794 for (MFIter mfi(m_sdf,info); mfi.isValid(); ++mfi) {
795 amrex::MC::marching_cubes(geom, m_sdf[mfi], *m_marching_cubes[mfi.index()]);
796 }
797
798 MC::write_stl("test.stl", m_marching_cubes);
799
800 m_ok = false; // xxxxx TODO
801}
802#endif
803
804template <typename G>
805GShopLevel<G>::GShopLevel (IndexSpace const* is, int /*ilev*/, int max_grid_size, int /*ngrow*/,
806 const Geometry& geom, GShopLevel<G>& fineLevel)
807 : Level(is, geom)
808{
809 if (fineLevel.isAllRegular()) {
810 m_allregular = true;
811 m_ok = true;
812 return;
813 }
814
815 BL_PROFILE("EB2::GShopLevel()-coarse");
816
817 const BoxArray& fine_grids = fineLevel.m_grids;
818 const BoxArray& fine_covered_grids = fineLevel.m_covered_grids;
819
820 const int coarse_ratio = 2;
821 const int min_width = 8;
822 bool coarsenable = fine_grids.coarsenable(coarse_ratio, min_width)
823 && (fine_covered_grids.empty() || fine_covered_grids.coarsenable(coarse_ratio));
824
825 m_ngrow = amrex::coarsen(fineLevel.m_ngrow,2);
826 if (amrex::scale(m_ngrow,2) != fineLevel.m_ngrow) {
827 m_ngrow = IntVect::TheZeroVector();
828 }
829
830 if (coarsenable)
831 {
832 int ierr = coarsenFromFine(fineLevel, true);
833 m_ok = (ierr == 0);
834 }
835 else
836 {
837 Level fine_level_2(is, fineLevel.m_geom);
838 fine_level_2.prepareForCoarsening(fineLevel, max_grid_size, amrex::scale(m_ngrow,2));
839 if (fine_level_2.isAllRegular()) {
840 m_allregular = true;
841 m_ok = true;
842 return;
843 }
844 int ierr = coarsenFromFine(fine_level_2, false);
845 m_ok = (ierr == 0);
846 }
847}
848
849template <typename G>
850void
851GShopLevel<G>::buildFCData (G const& gshop, int face_dir, int max_grid_size)
852{
853 BL_PROFILE("EB2::GShopLevel::buildFCData");
854
855 AMREX_ASSERT(face_dir >= 0 && face_dir < AMREX_SPACEDIM);
856
857 // Allocate FC data structure if needed
858 if (!m_fc_data[face_dir]) {
859 m_fc_data[face_dir] = std::make_unique<FCData>();
860 }
861
862 if (m_fc_data[face_dir]->m_built) { return; }
863
864 if (m_allregular) {
865 // An all-regular level carries no MultiFabs, and there is nothing to coarsen. Mark the
866 // face-centered data built anyway so that hasFCData() is true and a face-centered factory
867 // can be constructed: the fill*FC functions fill the regular values for such a level
868 // without reading anything, exactly as their cell-centered counterparts do.
869 m_fc_data[face_dir]->m_built = true;
870 return;
871 }
872
873 // **********************************************************************
874 // STEP1: Get or build the one-level-finer CC data
875 // **********************************************************************
876
877 Level const* refined_cc_level = nullptr;
878 std::unique_ptr<GShopLevel<G>> transient_level;
879
880 // An even max_grid_size keeps the refined grids coarsenable by 2, and a doubled ngrow
881 // makes the face-centered data reach at least as far outside the domain as m_ngrow.
882 Geometry refined_geom = amrex::refine(m_geom, 2);
883 transient_level = std::make_unique<GShopLevel<G>>(
884 m_parent, gshop, refined_geom,
885 std::max(2, max_grid_size - max_grid_size%2), std::max(4, 2*m_ngrow.max()), true, 0); // xxxxx TODO: should we use IndexSpace's member variables extend_domain_face and num_crse_opt?
886
887 if (!transient_level->isOK()) {
888 amrex::Abort("GShopLevel::buildFCData: failed to build refined level");
889 }
890 refined_cc_level = transient_level.get();
891
892 // Leave the data unbuilt; a face-centered factory on this level would then fail.
893 auto skip = [&] (char const* why) {
894 if (amrex::Verbose() > 0) {
895 amrex::Print() << "AMReX EB: no face-centered data for face_dir " << face_dir
896 << " on domain " << m_geom.Domain() << ": " << why << '\n';
897 }
898 m_fc_data[face_dir].reset();
899 };
900
901 // Coarse levels can have features too thin for their 2x rebuild to see.
902 if (refined_cc_level->isAllRegular()) {
903 skip("refined level has no cut cells");
904 return;
905 }
906
908 refined_cc_level->m_grids.coarsenable(2) &&
909 (refined_cc_level->m_covered_grids.empty() ||
910 refined_cc_level->m_covered_grids.coarsenable(2)),
911 "GShopLevel::buildFCData: refined grids are not coarsenable");
912
913 // **********************************************************************
914 // STEP2: Check multi-cut error
915 // **********************************************************************
916
917 // Everything below is local. m_grids, m_dmap and m_levelset describe the cell-centered
918 // level that the IndexSpace hands to every EBFArrayBoxFactory built from it, so building
919 // face-centered data must not touch them: overwriting m_grids would leave Level::boxArray()
920 // describing a different region than the cell-centered data it belongs to, and redefining
921 // m_levelset on those grids would silently change the level set that cell-centered
922 // factories created afterwards report.
923 //
924 // The grids are coarsened from the refined level rather than taken from m_grids so that the
925 // DistributionMapping stays compatible with the refined data we read below.
926 const BoxArray fc_base_grids = amrex::coarsen(refined_cc_level->m_grids, 2);
927 if (!refined_cc_level->m_covered_grids.empty()) {
928 m_fc_data[face_dir]->m_covered_grids_fc =
929 amrex::coarsen(refined_cc_level->m_covered_grids, 2).simplified();
930 }
931 const DistributionMapping fc_dmap = refined_cc_level->m_dmap;
932
933 // Face-centered data provides no level set, so nothing here coarsens one. The multi-cut check
934 // below only needs an MFIter over the coarse boxes, walking alongside the refined level set
935 // that shares this DistributionMapping, so this MultiFab is declared without data.
936 auto const& f_levelset = refined_cc_level->m_levelset;
937 MultiFab crse_boxes(amrex::convert(fc_base_grids,IntVect::TheNodeVector()), fc_dmap, 1, 0,
938 MFInfo{}.SetAlloc(false));
939
940 int mvmc_error = 0;
941
943 {
944#ifdef AMREX_USE_OMP
945#pragma omp parallel reduction(max:mvmc_error)
946#endif
947 for (MFIter mfi(crse_boxes,true); mfi.isValid(); ++mfi)
948 {
949 const Box& ccbx = mfi.tilebox(IntVect::TheCellVector());
950 auto const& fine = f_levelset.const_array(mfi);
951
952 int tile_error = 0;
953 amrex::LoopOnCpu(ccbx,
954 [=,&tile_error] (int i, int j, int k) noexcept
955 {
956 int ierror = check_mvmc(i,j,k,fine);
957 tile_error = std::max(tile_error,ierror);
958 });
959
960 mvmc_error = std::max(mvmc_error, tile_error);
961 }
962 }
963 else
964 {
965 ReduceOps<ReduceOpMax> reduce_op;
966 ReduceData<int> reduce_data(reduce_op);
967 using ReduceTuple = typename decltype(reduce_data)::Type;
968
969 for (MFIter mfi(crse_boxes); mfi.isValid(); ++mfi)
970 {
971 const Box& ndbx = mfi.validbox();
972 const Box& ccbx = amrex::enclosedCells(ndbx);
973 auto const& fine = f_levelset.const_array(mfi);
974 reduce_op.eval(ndbx, reduce_data,
975 [=] AMREX_GPU_DEVICE (int i, int j, int k) -> ReduceTuple
976 {
977 int ierror;
978 if (ccbx.contains(IntVect{AMREX_D_DECL(i,j,k)})) {
979 ierror = check_mvmc(i,j,k,fine);
980 } else {
981 ierror = 0;
982 }
983 return {ierror};
984 });
985 }
986 ReduceTuple rv = reduce_data.value(reduce_op);
987 mvmc_error = amrex::max(0, amrex::get<0>(rv));
988 }
989
990 {
991 bool b = mvmc_error;
993 mvmc_error = b;
994 }
995 if (mvmc_error) {
996 amrex::Abort("GShopLevel::buildFCData: MVMC error");
997 }
998
999 // **********************************************************************
1000 // STEP3: Define FC data structures
1001 // **********************************************************************
1002
1003 // FC MultiFabs
1004 auto& fc_cellflag = m_fc_data[face_dir]->m_cellflag_fc;
1005 MultiFab& fc_volfrac = m_fc_data[face_dir]->m_volfrac_fc;
1006 MultiFab& fc_centroid = m_fc_data[face_dir]->m_centroid_fc;
1007 MultiFab& fc_bndryarea = m_fc_data[face_dir]->m_bndryarea_fc;
1008 MultiFab& fc_bndrycent = m_fc_data[face_dir]->m_bndrycent_fc;
1009 MultiFab& fc_bndrynorm = m_fc_data[face_dir]->m_bndrynorm_fc;
1010 auto& fc_areafrac = m_fc_data[face_dir]->m_areafrac_fc;
1011 auto& fc_facecent = m_fc_data[face_dir]->m_facecent_fc;
1012 auto& fc_edgecent = m_fc_data[face_dir]->m_edgecent_fc;
1013
1014 // Index types of the face-centered data. One rule covers all of it: face_dir is nodal,
1015 // because that is how a box spans staggered cells - there is one more of them than there
1016 // are cell-centered cells, and nodal is how AMReX says so. The remaining directions carry
1017 // whatever type the cell-centered path would give.
1018 //
1019 // cellflag / volfrac / centroid / bndry* nodal in face_dir alone, i.e. (N,C,C) for
1020 // face_dir=0, (C,N,C) for 1, (C,C,N) for 2.
1021 // These are the staggered cells themselves.
1022 // areafrac[idim] / facecent[idim] the same, for every idim.
1023 // edgecent[idim] cell in idim and nodal elsewhere, as in the
1024 // cell-centered path, with face_dir forced nodal.
1025 //
1026 // areafrac and facecent are kept uniform across idim on purpose. The cell-centered path
1027 // gives each direction its own nodal index type (areafrac[0] is (N,C,C), areafrac[1] is
1028 // (C,N,C), ...); carrying that over to a grid already staggered in face_dir would put three
1029 // different index types in play at once for no real gain. Here all three are simply indexed
1030 // by the staggered cell they belong to, and areafrac[idim](i,j,k) is that cell's low face in
1031 // direction idim, with areafrac[idim](i+1,j,k) its high one.
1032 //
1033 // Indexing by the staggered cell is why face_dir has to be nodal even here. The valid box
1034 // then holds every staggered cell the box owns, which is what coarsen_from_fine below fills
1035 // and what the fill*FC ParallelCopy can hand out. A cell-typed face_dir would stop one short
1036 // and leave the last staggered cell of every box in the ghost region, where the copy cannot
1037 // reach it: the covered-region mask in fill*FC would clear that plane with nothing able to
1038 // write it back.
1039
1040 // Define FC MultiFabs
1041 BoxArray fc_grids = amrex::convert(fc_base_grids, IntVect::TheDimensionVector(face_dir));
1042 const int ng = 3;
1043 fc_cellflag.define(fc_grids, fc_dmap, 1, ng);
1044 fc_volfrac.define(fc_grids, fc_dmap, 1, ng);
1045 fc_centroid.define(fc_grids, fc_dmap, AMREX_SPACEDIM, ng);
1046 fc_bndryarea.define(fc_grids, fc_dmap, 1, ng);
1047 fc_bndrycent.define(fc_grids, fc_dmap, AMREX_SPACEDIM, ng);
1048 fc_bndrynorm.define(fc_grids, fc_dmap, AMREX_SPACEDIM, ng);
1049
1050 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1051 fc_areafrac[idim].define(fc_grids, fc_dmap, 1, ng);
1052 fc_facecent[idim].define(fc_grids, fc_dmap, AMREX_SPACEDIM-1, ng);
1053 fc_edgecent[idim].define(amrex::convert(fc_base_grids, Level::fcEdgeType(idim,face_dir)),
1054 fc_dmap, 1, ng);
1055 }
1056
1057 // **********************************************************************
1058 // STEP4: Coarsen from refined CC to FC with staggered averaging
1059 // **********************************************************************
1060
1061 // Fine CC MultiFabs
1062 auto const& cc_cellflag = refined_cc_level->m_cellflag;
1063 MultiFab const& cc_volfrac = refined_cc_level->m_volfrac;
1064 MultiFab const& cc_centroid = refined_cc_level->m_centroid;
1065 MultiFab const& cc_bndryarea = refined_cc_level->m_bndryarea;
1066 MultiFab const& cc_bndrycent = refined_cc_level->m_bndrycent;
1067 MultiFab const& cc_bndrynorm = refined_cc_level->m_bndrynorm;
1068 auto const& cc_areafrac = refined_cc_level->m_areafrac;
1069 auto const& cc_facecent = refined_cc_level->m_facecent;
1070 auto const& cc_edgecent = refined_cc_level->m_edgecent;
1071
1072 int error = 0;
1073
1075 {
1076#ifdef AMREX_USE_OMP
1077#pragma omp parallel reduction(max:error)
1078#endif
1079 for (MFIter mfi(fc_volfrac,true); mfi.isValid(); ++mfi)
1080 {
1081 // Coarse FC arrays
1082 auto const& cvol = fc_volfrac.array(mfi);
1083 auto const& ccent = fc_centroid.array(mfi);
1084 auto const& cba = fc_bndryarea.array(mfi);
1085 auto const& cbc = fc_bndrycent.array(mfi);
1086 auto const& cbn = fc_bndrynorm.array(mfi);
1087 AMREX_D_TERM(auto const& capx = fc_areafrac[0].array(mfi);,
1088 auto const& capy = fc_areafrac[1].array(mfi);,
1089 auto const& capz = fc_areafrac[2].array(mfi););
1090 AMREX_D_TERM(auto const& cfcx = fc_facecent[0].array(mfi);,
1091 auto const& cfcy = fc_facecent[1].array(mfi);,
1092 auto const& cfcz = fc_facecent[2].array(mfi););
1093 AMREX_D_TERM(auto const& cecx = fc_edgecent[0].array(mfi);,
1094 auto const& cecy = fc_edgecent[1].array(mfi);,
1095 auto const& cecz = fc_edgecent[2].array(mfi););
1096 auto const& cflag = fc_cellflag.array(mfi);
1097
1098 // Fine CC arrays
1099 auto const& fvol = cc_volfrac.const_array(mfi);
1100 auto const& fcent = cc_centroid.const_array(mfi);
1101 auto const& fba = cc_bndryarea.const_array(mfi);
1102 auto const& fbc = cc_bndrycent.const_array(mfi);
1103 auto const& fbn = cc_bndrynorm.const_array(mfi);
1104 AMREX_D_TERM(auto const& fapx = cc_areafrac[0].const_array(mfi);,
1105 auto const& fapy = cc_areafrac[1].const_array(mfi);,
1106 auto const& fapz = cc_areafrac[2].const_array(mfi););
1107 AMREX_D_TERM(auto const& ffcx = cc_facecent[0].const_array(mfi);,
1108 auto const& ffcy = cc_facecent[1].const_array(mfi);,
1109 auto const& ffcz = cc_facecent[2].const_array(mfi););
1110 AMREX_D_TERM(auto const& fecx = cc_edgecent[0].const_array(mfi);,
1111 auto const& fecy = cc_edgecent[1].const_array(mfi);,
1112 auto const& fecz = cc_edgecent[2].const_array(mfi););
1113 auto const& fflag = cc_cellflag.const_array(mfi);
1114
1115 Box const& bx = mfi.validbox();
1116 Box const& ndgbx = mfi.grownnodaltilebox(-1,2);
1117
1118 int tile_error = 0;
1119 amrex::LoopOnCpu(ndgbx,
1120 [=,&tile_error] (int i, int j, int k) noexcept
1121 {
1123 int ierr = coarsen_from_fine(AMREX_D_DECL(i,j,k), bx, 2,
1124 cvol,ccent,cba,cbc,cbn,
1125 AMREX_D_DECL(capx,capy,capz),
1126 AMREX_D_DECL(cfcx,cfcy,cfcz),
1127 AMREX_D_DECL(cecx,cecy,cecz),
1128 cflag,fvol,fcent,fba,fbc,fbn,
1129 AMREX_D_DECL(fapx,fapy,fapz),
1130 AMREX_D_DECL(ffcx,ffcy,ffcz),
1131 AMREX_D_DECL(fecx,fecy,fecz),
1132 fflag, face_dir);
1133 tile_error = std::max(tile_error,ierr);
1134 });
1135
1136 error = std::max(error,tile_error);
1137 }
1138 }
1139 else
1140 {
1141 ReduceOps<ReduceOpMax> reduce_op;
1142 ReduceData<int> reduce_data(reduce_op);
1143 using ReduceTuple = typename decltype(reduce_data)::Type;
1144
1145 for (MFIter mfi(fc_volfrac); mfi.isValid(); ++mfi)
1146 {
1147 auto const& cvol = fc_volfrac.array(mfi);
1148 auto const& ccent = fc_centroid.array(mfi);
1149 auto const& cba = fc_bndryarea.array(mfi);
1150 auto const& cbc = fc_bndrycent.array(mfi);
1151 auto const& cbn = fc_bndrynorm.array(mfi);
1152 AMREX_D_TERM(auto const& capx = fc_areafrac[0].array(mfi);,
1153 auto const& capy = fc_areafrac[1].array(mfi);,
1154 auto const& capz = fc_areafrac[2].array(mfi););
1155 AMREX_D_TERM(auto const& cfcx = fc_facecent[0].array(mfi);,
1156 auto const& cfcy = fc_facecent[1].array(mfi);,
1157 auto const& cfcz = fc_facecent[2].array(mfi););
1158 // We use MultiArray4 instead of Array4 here
1159 // to be below the 2 kB kernel parameter limit for SYCL
1160 AMREX_D_TERM(auto const& cecx = fc_edgecent[0].arrays();,
1161 auto const& cecy = fc_edgecent[1].arrays();,
1162 auto const& cecz = fc_edgecent[2].arrays(););
1163 auto const& cflag = fc_cellflag.array(mfi);
1164
1165 auto const& fvol = cc_volfrac.const_array(mfi);
1166 auto const& fcent = cc_centroid.const_array(mfi);
1167 auto const& fba = cc_bndryarea.const_array(mfi);
1168 auto const& fbc = cc_bndrycent.const_array(mfi);
1169 auto const& fbn = cc_bndrynorm.const_array(mfi);
1170 AMREX_D_TERM(auto const& fapx = cc_areafrac[0].const_array(mfi);,
1171 auto const& fapy = cc_areafrac[1].const_array(mfi);,
1172 auto const& fapz = cc_areafrac[2].const_array(mfi););
1173 AMREX_D_TERM(auto const& ffcx = cc_facecent[0].const_array(mfi);,
1174 auto const& ffcy = cc_facecent[1].const_array(mfi);,
1175 auto const& ffcz = cc_facecent[2].const_array(mfi););
1176 AMREX_D_TERM(auto const& fecx = cc_edgecent[0].const_arrays();,
1177 auto const& fecy = cc_edgecent[1].const_arrays();,
1178 auto const& fecz = cc_edgecent[2].const_arrays(););
1179 auto const& fflag = cc_cellflag.const_array(mfi);
1180
1181 const int lidx = mfi.LocalIndex();
1182 Box const& bx = mfi.validbox();
1183 Box const& gbx = amrex::grow(bx,2);
1184 Box const& ndgbx = amrex::surroundingNodes(gbx);
1185
1186 reduce_op.eval(ndgbx, reduce_data,
1187 [=] AMREX_GPU_DEVICE (int i, int j, int k) -> ReduceTuple
1188 {
1190 int ierr = coarsen_from_fine(AMREX_D_DECL(i,j,k), bx, 2,
1191 cvol,ccent,cba,cbc,cbn,
1192 AMREX_D_DECL(capx,capy,capz),
1193 AMREX_D_DECL(cfcx,cfcy,cfcz),
1194 AMREX_D_DECL(cecx[lidx],cecy[lidx],cecz[lidx]),
1195 cflag,fvol,fcent,fba,fbc,fbn,
1196 AMREX_D_DECL(fapx,fapy,fapz),
1197 AMREX_D_DECL(ffcx,ffcy,ffcz),
1198 AMREX_D_DECL(fecx[lidx],fecy[lidx],fecz[lidx]),
1199 fflag, face_dir);
1200 return {ierr};
1201 });
1202 }
1203
1204 ReduceTuple rv = reduce_data.value(reduce_op);
1205 error = amrex::max(0, amrex::get<0>(rv));
1206 }
1207
1208 {
1209 bool b = error;
1211 error = b;
1212 }
1213
1214 if (error) {
1215 skip("coarsening failed");
1216 return;
1217 }
1218
1219 m_fc_data[face_dir]->m_built = true;
1220
1221 buildCellFlagFC(face_dir);
1222}
1223
1224}
1225
1226#endif
Fixed-size array types for use on GPU and CPU.
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
Problem-domain geometry: maps between index space and physical space.
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
void resize(const Box &b, int N=1, Arena *ar=nullptr)
This function resizes a BaseFab so it covers the Box b with N components.
Definition AMReX_BaseFab.H:1776
Array4< T const > array() const noexcept
Create an Array4 view over all components.
Definition AMReX_BaseFab.H:475
Elixir elixir() noexcept
Transfer owned storage to an Elixir when running in a GPU launch region.
Definition AMReX_BaseFab.H:1819
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:681
bool coarsenable(int refinement_ratio, int min_width=1) const
Check whether every Box is coarsenable by refinement_ratio.
Definition AMReX_BoxArray.cpp:628
bool empty() const noexcept
Return whether the BoxArray is empty.
Definition AMReX_BoxArray.H:764
__host__ __device__ BoxND & grow(int i) noexcept
Grow in all directions by i cells (negative shrinks).
Definition AMReX_Box.H:668
__host__ __device__ bool contains(const IntVectND< dim > &p) const noexcept
Return true if argument is contained within BoxND.
Definition AMReX_Box.H:233
GpuArray< Real, 3 > CellSizeArray() const noexcept
Returns the cell sizes as a GpuArray for use on host or device.
Definition AMReX_CoordSys.H:85
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
static constexpr int ng
Definition AMReX_EB2_MultiGFab.H:26
Definition AMReX_EB2_Level.H:293
void define_fine(G const &gshop, const Geometry &geom, int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
Define data for the finest level using the supplied GeometryShop.
Definition AMReX_EB2_Level.H:481
void buildFCData(G const &gshop, int face_dir, int max_grid_size)
Build face-centered EB data for face_dir. Builds refined CC transiently.
Definition AMReX_EB2_Level.H:851
GShopLevel(IndexSpace const *is, G const &gshop, const Geometry &geom, int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
Build a level directly from a GeometryShop object.
Definition AMReX_EB2_Level.H:350
static GShopLevel< G > makeAllRegular(IndexSpace const *is, const Geometry &geom)
Build a regular (no EB) level.
Definition AMReX_EB2_Level.H:325
void define_fine_mvmc(GS const &gshop, const Geometry &geom, int max_grid_size, int ngrow, bool extend_domain_face, int num_crse_opt)
Definition AMReX_EB2_Level.H:770
Definition AMReX_EB2.H:84
Definition AMReX_EB2.H:28
Definition AMReX_EB2_Level.H:43
MultiFab m_bndryarea
Definition AMReX_EB2_Level.H:261
bool isOK() const noexcept
Definition AMReX_EB2_Level.H:49
void fillFaceCent(Array< MultiCutFab *, 3 > const &facecent, const Geometry &geom) const
Populate face centroids for each direction.
Definition AMReX_EB2_Level.cpp:803
MultiFab m_volfrac
Definition AMReX_EB2_Level.H:259
MultiGFab m_mgf
Definition AMReX_EB2_Level.H:256
bool m_allregular
Definition AMReX_EB2_Level.H:268
IntVect m_shift
Definition AMReX_EB2_Level.H:271
iMultiFab m_cutcellmask
Definition AMReX_EB2_Level.H:267
Array< MultiFab, 3 > m_facecent
Definition AMReX_EB2_Level.H:265
void fillBndryAreaFC(MultiFab &bndryarea, int face_dir, const Geometry &geom) const
Fill face-centered boundary areas for face_dir.
Definition AMReX_EB2_Level.cpp:1227
Array< MultiFab, 3 > m_edgecent
Definition AMReX_EB2_Level.H:266
void fillBndryNormFC(MultiFab &bndrynorm, int face_dir, const Geometry &geom) const
Fill face-centered boundary normals for face_dir.
Definition AMReX_EB2_Level.cpp:1263
void prepareForCoarsening(const Level &rhs, int max_grid_size, IntVect const &ngrow)
Prepare for coarsening by copying from rhs, respecting max grid size and grow vector.
Definition AMReX_EB2_Level.cpp:10
void fillCutCellMask(iMultiFab &cutcellmask, const Geometry &geom) const
Populate the cut-cell mask into cutcellmask.
Definition AMReX_EB2_Level.cpp:956
MultiFab m_centroid
Definition AMReX_EB2_Level.H:260
FabArray< EBCellFlagFab > m_cellflag
Definition AMReX_EB2_Level.H:258
const DistributionMapping & DistributionMap() const noexcept
Definition AMReX_EB2_Level.H:111
BoxArray m_covered_grids
Definition AMReX_EB2_Level.H:250
void fillLevelSet(MultiFab &levelset, const Geometry &geom) const
Write the implicit function values into levelset.
Definition AMReX_EB2_Level.cpp:917
Geometry m_geom
Definition AMReX_EB2_Level.H:247
Array< MultiFab, 3 > m_areafrac
Definition AMReX_EB2_Level.H:264
IntVect m_ngrow
Definition AMReX_EB2_Level.H:248
void fillEBCellFlagFC(FabArray< EBCellFlagFab > &cellflag, int face_dir, const Geometry &geom) const
Fill face-centered EBCellFlags for face_dir.
Definition AMReX_EB2_Level.cpp:1281
IndexSpace const * m_parent
Definition AMReX_EB2_Level.H:272
const FCData & getFCData(int face_dir) const
Get reference to face-centered data for face_dir (0=x, 1=y, 2=z).
Definition AMReX_EB2_Level.H:198
BoxArray m_grids
Definition AMReX_EB2_Level.H:249
void fillEdgeCentFC(Array< MultiFab *, 3 > const &edgecent, int face_dir, const Geometry &geom) const
Fill face-centered edge centroids for face_dir.
Definition AMReX_EB2_Level.cpp:1365
const Geometry & Geom() const noexcept
Definition AMReX_EB2_Level.H:121
std::map< int, std::unique_ptr< MC::MCFab > > m_marching_cubes
Definition AMReX_EB2_Level.H:254
bool hasEBInfo() const noexcept
Definition AMReX_EB2_Level.H:138
void write_to_chkpt_file(const std::string &fname, bool extend_domain_face, int max_grid_size) const
Write this level’s EB data to a checkpoint file fname.
Definition AMReX_EB2_Level.cpp:966
void fillEBCellFlag(FabArray< EBCellFlagFab > &cellflag, const Geometry &geom) const
Fill cellflag with EBCellFlag data using geometry geom.
Definition AMReX_EB2_Level.cpp:437
void fillEdgeCent(Array< MultiCutFab *, 3 > const &edgecent, const Geometry &geom) const
Populate edge centroids for each direction.
Definition AMReX_EB2_Level.cpp:844
int coarsenFromFine(Level &fineLevel, bool fill_boundary)
Coarsen EB data from fineLevel into this level.
Definition AMReX_EB2_Level.cpp:92
MultiFab m_bndrynorm
Definition AMReX_EB2_Level.H:263
bool m_has_eb_info
Definition AMReX_EB2_Level.H:270
void fillAreaFrac(Array< MultiCutFab *, 3 > const &areafrac, const Geometry &geom) const
Populate face area fractions for each direction.
Definition AMReX_EB2_Level.cpp:649
MultiFab m_bndrycent
Definition AMReX_EB2_Level.H:262
MultiFab m_levelset
Definition AMReX_EB2_Level.H:257
void setShift(int direction, int ncells)
Shift this level by ncells cells along direction direction (for periodic tiling).
Definition AMReX_EB2_Level.cpp:1057
friend class IndexSpaceImp
Definition AMReX_EB2_Level.H:280
void buildCellFlagFC(int face_dir)
Build the face-centered EBCellFlag connectivity for face_dir from its area fractions.
Definition AMReX_EB2_Level.cpp:1072
bool isAllRegular() const noexcept
Definition AMReX_EB2_Level.H:47
static IntVect fcEdgeType(int idim, int face_dir) noexcept
Index type of the face-centered edge centroids for edge direction idim.
Definition AMReX_EB2_Level.H:185
void fillBndryCent(MultiCutFab &bndrycent, const Geometry &geom) const
Populate boundary centroids into bndrycent.
Definition AMReX_EB2_Level.cpp:601
void fillCentroidFC(MultiFab &centroid, int face_dir, const Geometry &geom) const
Fill face-centered centroids for face_dir.
Definition AMReX_EB2_Level.cpp:1209
void fillBndryNorm(MultiCutFab &bndrynorm, const Geometry &geom) const
Populate boundary normals into bndrynorm.
Definition AMReX_EB2_Level.cpp:625
void fillBndryCentFC(MultiFab &bndrycent, int face_dir, const Geometry &geom) const
Fill face-centered boundary centroids for face_dir.
Definition AMReX_EB2_Level.cpp:1245
MultiFab m_sdf
Definition AMReX_EB2_Level.H:252
IntVect const & nGrowVect() const noexcept
Definition AMReX_EB2_Level.H:126
void fillAreaFracFC(Array< MultiFab *, 3 > const &areafrac, int face_dir, const Geometry &geom) const
Fill face-centered area fractions for face_dir.
Definition AMReX_EB2_Level.cpp:1143
void fillVolFrac(MultiFab &vfrac, const Geometry &geom) const
Populate volume fractions into vfrac using geom.
Definition AMReX_EB2_Level.cpp:491
const BoxArray & boxArray() const noexcept
Definition AMReX_EB2_Level.H:109
Level(IndexSpace const *is, const Geometry &geom)
Construct a Level bound to EB index space is and Geometry geom.
Definition AMReX_EB2_Level.H:114
friend class GShopLevel
Definition AMReX_EB2_Level.H:278
bool m_ok
Definition AMReX_EB2_Level.H:269
void fillCentroid(MultiCutFab &centroid, const Geometry &geom) const
Populate cut-cell centroids into a MultiCutFab.
Definition AMReX_EB2_Level.cpp:553
Array< std::unique_ptr< FCData >, 3 > m_fc_data
Face-centered data storage: [0]=x-face, [1]=y-face, [2]=z-face.
Definition AMReX_EB2_Level.H:275
DistributionMapping m_dmap
Definition AMReX_EB2_Level.H:251
void fillBndryArea(MultiCutFab &bndryarea, const Geometry &geom) const
Populate boundary-face areas into bndryarea.
Definition AMReX_EB2_Level.cpp:577
void buildCellFlag()
Build EBCellFlag data from the current implicit function field.
Definition AMReX_EB2_Level.cpp:411
void buildCutCellMask(Level const &fine_level)
Build the cut-cell mask by coarsening from fine_level.
Definition AMReX_EB2_Level.cpp:976
bool hasFCData(int face_dir) const noexcept
Check if face-centered data is available for face_dir (0=x, 1=y, 2=z).
Definition AMReX_EB2_Level.H:192
IndexSpace const * getEBIndexSpace() const noexcept
Definition AMReX_EB2_Level.H:123
void fillVolFracFC(MultiFab &vfrac, int face_dir, const Geometry &geom) const
Fill face-centered volume fractions for face_dir.
Definition AMReX_EB2_Level.cpp:1103
void fillFaceCentFC(Array< MultiFab *, 3 > const &facecent, int face_dir, const Geometry &geom) const
Fill face-centered face centroids for face_dir.
Definition AMReX_EB2_Level.cpp:1333
LayoutData wrapper that allocates a GFab per FAB/Box.
Definition AMReX_EB2_MultiGFab.H:86
FAB storing EBCellFlag data per cell.
Definition AMReX_EBCellFlag.H:324
An Array of FortranArrayBox(FAB)-like Objects.
Definition AMReX_FabArray.H:356
Array4< typename FabArray< FAB >::value_type const > array(const MFIter &mfi) const noexcept
Read-only Array4 view for the FAB referenced by iterator mfi.
Definition AMReX_FabArray.H:621
Array4< typename FabArray< FAB >::value_type const > const_array(const MFIter &mfi) const noexcept
Synonym for array(const MFIter&) that highlights read-only semantics.
Definition AMReX_FabArray.H:649
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:87
const Box & Domain() const noexcept
Returns our rectangular domain.
Definition AMReX_Geometry.H:246
Periodicity periodicity() const noexcept
Return the Periodicity based on the length of the domain.
Definition AMReX_Geometry.H:426
GpuArray< Real, 3 > ProbLoArray() const noexcept
Return the lo end of the problem domain in a GpuArray for device code.
Definition AMReX_Geometry.H:219
bool isPeriodic(int dir) const noexcept
Is the domain periodic in the specified direction?
Definition AMReX_Geometry.H:399
Definition AMReX_GpuElixir.H:13
__host__ static __device__ constexpr IntVectND< dim > TheCellVector() noexcept
Definition AMReX_IntVect.H:832
__host__ static __device__ constexpr IntVectND< dim > TheNodeVector() noexcept
Definition AMReX_IntVect.H:823
__host__ static __device__ constexpr IntVectND< dim > TheDimensionVector(int d) noexcept
Definition AMReX_IntVect.H:790
Iterator for looping ever tiles and boxes of amrex::FabArray based containers.
Definition AMReX_MFIter.H:88
bool isValid() const noexcept
Is the iterator valid i.e. is it associated with a FAB?
Definition AMReX_MFIter.H:176
FabArray façade that only allocates cut-cell Fabs (skipping regular cells).
Definition AMReX_MultiCutFab.H:87
A collection (stored as an array) of FArrayBox objects.
Definition AMReX_MultiFab.H:40
void define(const BoxArray &bxs, const DistributionMapping &dm, int nvar, int ngrow, const MFInfo &info=MFInfo(), const FabFactory< FArrayBox > &factory=FArrayBoxFactory())
Definition AMReX_MultiFab.cpp:524
Parse Parameters From Command Line and Input Files.
Definition AMReX_ParmParse.H:354
int queryAdd(std::string_view name, T &ref)
If name is found, the value in the ParmParse database will be stored in the ref argument....
Definition AMReX_ParmParse.H:1061
This class provides the user with a few print options.
Definition AMReX_Print.H:35
Definition AMReX_Reduce.H:556
Type value()
Definition AMReX_Reduce.H:591
Definition AMReX_Reduce.H:715
void eval(MF const &mf, IntVect const &nghost, D &reduce_data, F &&f)
Definition AMReX_Reduce.H:852
Utility class that loads STL meshes and samples them onto AMReX grids.
Definition AMReX_EB_STL_utils.H:26
A Collection of IArrayBoxes.
Definition AMReX_iMultiFab.H:34
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
amrex_long Long
Definition AMReX_INT.H:30
ArrayND< T, 4, true > Array4
Convenient alias for a 4D ArrayND with three spatial dimensions plus a component dimension.
Definition AMReX_Array4.H:1340
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1632
__host__ __device__ BoxND< dim > surroundingNodes(const BoxND< dim > &b, int dir) noexcept
Return a BoxND with NODE based coordinates in direction dir that encloses BoxND b.
Definition AMReX_Box.H:1584
__host__ __device__ BoxND< dim > coarsen(const BoxND< dim > &b, int ref_ratio) noexcept
Return a copy of b coarsened by the isotropic ratio ref_ratio.
Definition AMReX_Box.H:1471
__host__ __device__ BoxND< dim > enclosedCells(const BoxND< dim > &b, int dir) noexcept
Return a BoxND with CELL based coordinates in direction dir that is enclosed by b.
Definition AMReX_Box.H:1666
__host__ __device__ BoxND< dim > grow(const BoxND< dim > &b, int i) noexcept
Return a copy of b grown uniformly by i cells in every direction.
Definition AMReX_Box.H:1328
__host__ __device__ BoxND< dim > refine(const BoxND< dim > &b, int ref_ratio) noexcept
Return a copy of b refined by the isotropic ratio ref_ratio.
Definition AMReX_Box.H:1512
std::array< T, N > Array
Definition AMReX_Array.H:31
void Or(bool &v, MPI_Comm comm)
Definition AMReX_ParallelReduce.H:236
void Sum(Gpu::DeviceVector< T > &v, MPI_Comm comm)
Definition AMReX_GpuParallelReduce.H:37
__host__ __device__ constexpr const T & max(const T &a, const T &b) noexcept
Definition AMReX_Algorithm.H:54
Type flags representing regular/covered/etc.
Definition AMReX_EB2_Graph.H:49
Definition AMReX_FabArrayBase.H:38
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:329
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:88
bool notInLaunchRegion() noexcept
Definition AMReX_GpuControl.H:89
void write_stl(std::string const &filename, std::map< int, std::unique_ptr< MCFab > > const &mc_fabs)
Write the collected marching-cubes output to an STL file.
Definition AMReX_MarchingCubes.cpp:925
void marching_cubes(Geometry const &geom, FArrayBox &sdf_fab, MCFab &mc_fab)
Run marching cubes on signed-distance field sdf_fab.
Definition AMReX_MarchingCubes.cpp:693
void Initialize()
Initialize internal lookup tables and device buffers for marching cubes.
Definition AMReX_MarchingCubes.cpp:651
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
Definition AMReX_Amr.cpp:50
@ hybrid
Definition AMReX_MLMG.H:34
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
RunOn
Definition AMReX_GpuControl.H:65
@ Gpu
Definition AMReX_GpuControl.H:65
@ Cpu
Definition AMReX_GpuControl.H:65
void AllGatherBoxes(Vector< Box > &bxs, int n_extra_reserve)
Gather boxes from all MPI ranks into bxs.
Definition AMReX_Box.cpp:124
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
__host__ __device__ constexpr IntVectND< dim > scale(const IntVectND< dim > &p, int s) noexcept
Returns a IntVectND obtained by multiplying each of the components of this IntVectND by s.
Definition AMReX_IntVect.H:1128
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
int Verbose() noexcept
Return the verbosity level configured via ParmParse or SetVerbose().
Definition AMReX.cpp:184
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
void LoopOnCpu(Dim3 lo, Dim3 hi, F const &f) noexcept
Definition AMReX_Loop.H:365
@ bndryarea
Definition AMReX_EBData.H:25
@ levelset
Definition AMReX_EBData.H:20
@ centroid
Definition AMReX_EBData.H:22
@ apy
Definition AMReX_EBData.H:26
@ bndrycent
Definition AMReX_EBData.H:23
@ fcx
Definition AMReX_EBData.H:27
@ apx
Definition AMReX_EBData.H:26
@ bndrynorm
Definition AMReX_EBData.H:24
@ fcz
Definition AMReX_EBData.H:27
@ fcy
Definition AMReX_EBData.H:27
@ apz
Definition AMReX_EBData.H:26
@ cellflag
Definition AMReX_EBData.H:29
__host__ __device__ constexpr int get(IntVectND< dim > const &iv) noexcept
Get the Idx-th element of IntVectND<dim>.
Definition AMReX_IntVect.H:1360
Face-centered EB data storage structure.
Definition AMReX_EB2_Level.H:150
bool m_built
Definition AMReX_EB2_Level.H:174
Array< MultiFab, 3 > m_areafrac_fc
Definition AMReX_EB2_Level.H:157
MultiFab m_bndryarea_fc
Definition AMReX_EB2_Level.H:154
Array< MultiFab, 3 > m_edgecent_fc
Definition AMReX_EB2_Level.H:159
BoxArray m_covered_grids_fc
Definition AMReX_EB2_Level.H:173
MultiFab m_bndrycent_fc
Definition AMReX_EB2_Level.H:155
MultiFab m_centroid_fc
Definition AMReX_EB2_Level.H:153
MultiFab m_bndrynorm_fc
Definition AMReX_EB2_Level.H:156
MultiFab m_volfrac_fc
Definition AMReX_EB2_Level.H:152
Array< MultiFab, 3 > m_facecent_fc
Definition AMReX_EB2_Level.H:158
FabArray< EBCellFlagFab > m_cellflag_fc
Definition AMReX_EB2_Level.H:151
FabArray memory allocation information.
Definition AMReX_FabArray.H:73
MFInfo & SetTag() noexcept
Terminate a variadic SetTag() call.
Definition AMReX_FabArray.H:90
MFInfo & SetAlloc(bool a) noexcept
Control whether FAB storage is allocated when the FabArray is defined.
Definition AMReX_FabArray.H:81
Definition AMReX_MFIter.H:20
MFItInfo & SetDynamic(bool f) noexcept
Definition AMReX_MFIter.H:43