Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding bittree interface to improve regridding performance in octree mode #3555

Merged
merged 10 commits into from
Oct 1, 2023
3 changes: 3 additions & 0 deletions GNUmakefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ endif
ifeq ($(USE_SUNDIALS),TRUE)
Pdirs += Extern/SUNDIALS
endif
ifeq ($(USE_BITTREE),TRUE)
Pdirs += Extern/Bittree
endif
Ppack := $(foreach dir, $(Pdirs), $(AMREX_HOME)/Src/$(dir)/Make.package)
include $(Ppack)

Expand Down
4 changes: 2 additions & 2 deletions Src/AmrCore/AMReX_AmrCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ AmrCore::regrid (int lbase, Real time, bool)
DistributionMapping level_dmap = dmap[lev];
if (ba_changed) {
level_grids = new_grids[lev];
level_dmap = DistributionMapping(level_grids);
level_dmap = MakeDistributionMap(lev, level_grids);
}
const auto old_num_setdm = num_setdm;
RemakeLevel(lev, time, level_grids, level_dmap);
Expand All @@ -117,7 +117,7 @@ AmrCore::regrid (int lbase, Real time, bool)
}
else // a new level
{
DistributionMapping new_dmap(new_grids[lev]);
DistributionMapping new_dmap = MakeDistributionMap(lev, new_grids[lev]);
const auto old_num_setdm = num_setdm;
MakeNewLevelFromCoarse(lev, time, new_grids[lev], new_dmap);
SetBoxArray(lev, new_grids[lev]);
Expand Down
11 changes: 11 additions & 0 deletions Src/AmrCore/AMReX_AmrMesh.H
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <AMReX_BoxArray.H>
#include <AMReX_TagBox.H>

#ifdef AMREX_USE_BITTREE
#include <Bittree_BittreeAmr.h>
#endif

namespace amrex {

struct AmrInfo {
Expand Down Expand Up @@ -253,13 +257,20 @@ public:

[[nodiscard]] long CountCells (int lev) noexcept;

[[nodiscard]] virtual DistributionMapping MakeDistributionMap (int lev, BoxArray const& ba);

protected:

int finest_level; //!< Current finest level.
Vector<Geometry> geom;
Vector<DistributionMapping> dmap;
Vector<BoxArray> grids;

#ifdef AMREX_USE_BITTREE
bool use_bittree;
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved
std::shared_ptr<bittree::BittreeAmr> btmesh;
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved
#endif

unsigned int num_setdm = 0;
unsigned int num_setba = 0;

Expand Down
161 changes: 157 additions & 4 deletions Src/AmrCore/AMReX_AmrMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
#include <AMReX_ParmParse.H>
#include <AMReX_ParallelDescriptor.H>
#include <AMReX_Print.H>
#include <AMReX_Vector.H>

#ifdef AMREX_USE_BITTREE
#include <AMReX_Bittree.H>
#endif

#include <memory>

namespace amrex {

Expand Down Expand Up @@ -376,6 +383,10 @@ AmrMesh::InitAmrMesh (int max_level_in, const Vector<int>& n_cell_in,

finest_level = -1;

#ifdef AMREX_USE_BITTREE
pp.get("use_bittree",use_bittree);
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved
#endif

if (check_input) { checkInput(); }
}

Expand Down Expand Up @@ -437,6 +448,41 @@ AmrMesh::LevelDefined (int lev) noexcept
return lev <= max_level && !grids[lev].empty() && !dmap[lev].empty();
}

DistributionMapping
AmrMesh::MakeDistributionMap (int lev, BoxArray const& ba)
{

BL_PROFILE("AmrMesh::MakeDistributionMap()");

// useful print statement to notify that a new distribution map is being created at lev
amrex::Print() << "creating new distribution map on level: " << lev + 1 << "\n";
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved

// initialize new distribution mapping
DistributionMapping dm;

#ifdef AMREX_USE_BITTREE
if(!use_bittree)
{
#endif
// create distribution mapping using boxarray
dm.define(ba);

#ifdef AMREX_USE_BITTREE
}
#endif

#ifdef AMREX_USE_BITTREE
// Bittree version
if(use_bittree)
{
// create distribution mapping
dm.define(ba);
}
#endif

return dm;
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved
}

void
AmrMesh::ChopGrids (int lev, BoxArray& ba, int target_size) const
{
Expand Down Expand Up @@ -514,6 +560,10 @@ AmrMesh::MakeNewGrids (int lbase, Real time, int& new_finest, Vector<BoxArray>&

if (new_grids.size() < max_crse+2) { new_grids.resize(max_crse+2); }

#ifdef AMREX_USE_BITTREE
if(!use_bittree) {
#endif

//
// Construct problem domain at each level.
//
Expand Down Expand Up @@ -774,6 +824,72 @@ AmrMesh::MakeNewGrids (int lbase, Real time, int& new_finest, Vector<BoxArray>&
}
}
}

#ifdef AMREX_USE_BITTREE
}
#endif

#ifdef AMREX_USE_BITTREE
// Bittree version
if(use_bittree) {
// Initialize BT refinement
btmesh->refine_init();

// -------------------------------------------------------------------
// Use tagging data to mark BT for refinement, then use the new bitmap
// to calculate the new grids.
auto tree0 = btmesh->getTree();

// [1] Error Estimation and tagging
// btTags is indexed by bitid, Bittree's internal indexing scheme.
// For any id, btTags = 1 if should be parent, -1 if should not be parent (or not exist).
std::vector<int> btTags(tree0->id_upper_bound(),0);

for (int lev=max_crse; lev>=lbase; --lev) {

TagBoxArray tags(grids[lev],dmap[lev], n_error_buf[lev]);
ErrorEst(lev, tags, time, 0);
tags.buffer(n_error_buf[lev]);

for (MFIter mfi(tags); mfi.isValid(); ++mfi) {
auto const& tagbox = tags.const_array(mfi);
bool has_set_tags = amrex::Reduce::AnyOf(mfi.validbox(),
[=] AMREX_GPU_DEVICE (int i, int j, int k)
{
return tagbox(i,j,k)!=TagBox::CLEAR;
});

// Set the values of btTags.
int bitid = btUnit::getBitid(btmesh.get(),false,lev,mfi.index());
// TODO Check lev == tree0->block_level(bitid)
if(has_set_tags) {
btTags[bitid] = 1;
}
else {
btTags[bitid] = -1;
}
}
}

// [2] btRefine - check for proper octree nesting and update bitmap
MPI_Comm comm = ParallelContext::CommunicatorSub();
int changed = btUnit::btRefine(btmesh.get(), btTags, max_crse, lbase, grids, dmap, comm);

// [3] btCalculateGrids - use new bitmap to generate new grids
if (changed>0) {
btUnit::btCalculateGrids(btmesh.get(),lbase,new_finest,new_grids,max_grid_size);
} else {
new_finest = finest_level;
for(int i=0; i<=finest_level; ++i) {
new_grids[i] = grids[i];
}
}

// Finalize BT refinement
btmesh->refine_apply();
}
#endif

}

void
Expand All @@ -783,11 +899,48 @@ AmrMesh::MakeNewGrids (Real time)
{
finest_level = 0;

const BoxArray& ba = MakeBaseGrids();
DistributionMapping dm(ba);
BoxArray ba;
DistributionMapping dm;
const auto old_num_setdm = num_setdm;
const auto old_num_setba = num_setba;

#ifdef AMREX_USE_BITTREE
if(!use_bittree) {
#endif
ba = MakeBaseGrids();
dm = MakeDistributionMap(0, ba);

#ifdef AMREX_USE_BITTREE
}
else {
//Initialize Bittree

// top = number of grids on coarsest level in each direction
std::vector<int> top(AMREX_SPACEDIM,0);
IntVect ncells = geom[0].Domain().length();
for(int i=0; i<AMREX_SPACEDIM; ++i) {
top[i] = ncells[i] / max_grid_size[0][i];
}

// includes = boolean to check each coarsest level grid exists
// (Bittree supports having "holes" in the mesh)
int ngrids = AMREX_D_TERM(top[0],*top[1],*top[2]);
std::vector<int> includes(ngrids,1);

btmesh = std::make_shared<bittree::BittreeAmr>(top.data(),includes.data());
akashdhruv marked this conversation as resolved.
Show resolved Hide resolved

// Set BCs
for(int d=0; d<AMREX_SPACEDIM; ++d) {
btUnit::bcPeriodic[d] = geom[0].isPeriodic(d);
}


// Use Bittree to make coarsest level (don't need MakeBaseGrids)
// Need to use Bittree, so the indices of grids[lev] will be compatible with BT.
btUnit::btCalculateLevel(btmesh.get(),0,ba,max_grid_size[0]);
dm = MakeDistributionMap(0, ba);
}
#endif
MakeNewLevelFromScratch(0, time, ba, dm);

if (old_num_setba == num_setba) {
Expand All @@ -812,7 +965,7 @@ AmrMesh::MakeNewGrids (Real time)
if (new_finest <= finest_level) { break; }
finest_level = new_finest;

DistributionMapping dm(new_grids[new_finest]);
DistributionMapping dm = MakeDistributionMap(new_finest, new_grids[new_finest]);
const auto old_num_setdm = num_setdm;

MakeNewLevelFromScratch(new_finest, time, new_grids[finest_level], dm);
Expand Down Expand Up @@ -843,7 +996,7 @@ AmrMesh::MakeNewGrids (Real time)
for (int lev = 1; lev <= new_finest; ++lev) {
if (new_grids[lev] != grids[lev]) {
grids_the_same = false;
DistributionMapping dm(new_grids[lev]);
DistributionMapping dm = MakeDistributionMap(lev, new_grids[lev]);
const auto old_num_setdm = num_setdm;

MakeNewLevelFromScratch(lev, time, new_grids[lev], dm);
Expand Down
3 changes: 2 additions & 1 deletion Src/AmrCore/Make.package
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

CEXE_headers += AMReX_AmrCore.H AMReX_Cluster.H AMReX_ErrorList.H AMReX_FillPatchUtil.H AMReX_FillPatchUtil_I.H AMReX_FluxRegister.H \
CEXE_headers += AMReX_AmrCore.H AMReX_Cluster.H AMReX_ErrorList.H AMReX_FillPatchUtil.H \
AMReX_FillPatchUtil_I.H AMReX_FluxRegister.H \
AMReX_Interpolater.H AMReX_MFInterpolater.H AMReX_TagBox.H AMReX_AmrMesh.H \
AMReX_InterpBase.H
CEXE_sources += AMReX_AmrCore.cpp AMReX_Cluster.cpp AMReX_ErrorList.cpp AMReX_FillPatchUtil.cpp AMReX_FluxRegister.cpp \
Expand Down
78 changes: 78 additions & 0 deletions Src/Extern/Bittree/AMReX_Bittree.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef BL_BITTREE_H_
#define BL_BITTREE_H_

#include <AMReX_IntVect.H>
#include <AMReX_BoxArray.H>
#include <AMReX_DistributionMapping.H>
#include <Bittree_BittreeAmr.h>

namespace amrex {

/*
Include in Make.local:
BITTREE_PATH = /path/to/bittree/installation
INCLUDE_LOCATIONS += $(BITTREE_PATH)/include
LIBRARY_LOCATIONS += $(BITTREE_PATH)/lib
LIBRARIES += -lbittree

Include in inputs:
amr.use_bittree = true
amr.bt_derefine = true
amr.infer_bt_grids = false

*/

class btUnit {
// Functions used in AmrMesh
public:
static int btRefine(bittree::BittreeAmr* const mesh,
std::vector<int>& btTags,
int max_crse, int lbase,
Vector<BoxArray>& grids, Vector<DistributionMapping>& dmap,
MPI_Comm comm);
static void btCalculateGrids(bittree::BittreeAmr* const mesh,
int lbase,
int& new_finest,
Vector<BoxArray>& new_grids,
Vector<IntVect> const& max_grid_size);
static void btCalculateLevel(bittree::BittreeAmr* const mesh,
int lev,
BoxArray& ba,
IntVect const& max_grid_size);
// Utils
public:
static int getBitid(bittree::BittreeAmr* const mesh, bool updated,
int lev, int idx_on_lev);
static int getIndex(bittree::BittreeAmr* const mesh, bool updated,
int lev, int bitid);

// Functions to implement strict octree logic
private:
static void btCheckRefine(bittree::BittreeAmr* const mesh,
std::vector<int>& btTags,
int max_crse, int lbase,
Vector<BoxArray>& grids, Vector<DistributionMapping>& dmap,
MPI_Comm comm);

static void btCheckDerefine(bittree::BittreeAmr* const mesh,
std::vector<int>& btTags,
int max_crse, int lbase,
Vector<BoxArray>& grids, Vector<DistributionMapping>& dmap,
MPI_Comm comm);

// Utility Functions
static bool checkNeighborsRefine(bittree::BittreeAmr* const mesh,
bittree::MortonTree::Block b);
static std::vector<int> neighIntCoords(bittree::BittreeAmr* const mesh,
unsigned lev, unsigned* lcoord,
int* gCell);

public:
// Represents whether domain has periodic BC in each direction
// true = Periodic, false = Non-Periodic
static bool bcPeriodic[AMREX_SPACEDIM];
};


}
#endif
Loading
Loading