Integration with AMReX¶
Warning
This example requires you to install AMReX
This example is given in Examples/AMReX_DCEL/main.cpp
and shows how to expose EBGeometry’s DCEL and BVH functionality to AMReX.
We will focus on the following parts of the code:
/* EBGeometry
* Copyright © 2022 Robert Marskar
* Please refer to Copyright.txt and LICENSE in the EBGeometry root directory.
*/
// AMReX includes
#include <AMReX.H>
#include <AMReX_EB2.H>
#include <AMReX_EB2_IF.H>
#include <AMReX_ParmParse.H>
#include <AMReX_PlotFileUtil.H>
// Our include
#include "../../EBGeometry.hpp"
using namespace amrex;
/*!
@brief This is an AMReX-capable version of the EBGeometry BVH accelerator. It
is templated as T, BV, K which indicate the EBGeometry precision, bounding
volume, and tree degree.
*/
template <class T, class BV, size_t K>
class AMReXSDF
{
public:
/*!
@brief Full constructor.
@param[in] a_filename File name. Must be an STL file.
*/
AMReXSDF(const std::string a_filename)
{
m_rootNode = EBGeometry::Parser::readIntoLinearBVH<T, BV, K>(a_filename);
}
/*!
@brief Copy constructor.
@param[in] a_other Other SDF.
*/
AMReXSDF(const AMReXSDF& a_other)
{
this->m_rootNode = a_other.m_rootNode;
}
/*!
@brief AMReX's implicit function definition.
*/
Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept
{
using Vec3 = EBGeometry::Vec3T<T>;
return m_rootNode->signedDistance(m_rootNode->transformPoint(Vec3(x, y, z)));
};
/*!
@brief Also an AMReX implicit function implementation
*/
inline Real
operator()(const RealArray& p) const noexcept
{
return this->operator()(AMREX_D_DECL(p[0], p[1], p[2]));
}
protected:
/*!
@brief Root node of the linearized BVH hierarchy.
*/
std::shared_ptr<EBGeometry::BVH::LinearBVH<T, EBGeometry::DCEL::FaceT<T>, BV, K>> m_rootNode;
};
int
main(int argc, char* argv[])
{
amrex::Initialize(argc, argv);
{
int n_cell = 128;
int max_grid_size = 16;
int which_geom = 0;
int num_coarsen_opt = 0;
std::string filename;
// read parameters
ParmParse pp;
pp.query("n_cell", n_cell);
pp.query("max_grid_size", max_grid_size);
pp.query("which_geom", which_geom);
pp.query("num_coarsen_opt", num_coarsen_opt);
Geometry geom;
{
RealBox rb;
if (which_geom == 0) { // Airfoil case
rb = RealBox({-100, -100, -75}, {400, 100, 125});
filename = "../Resources/airfoil.stl";
}
else if (which_geom == 1) { // Sphere case
rb = RealBox({-400, -400, -400}, {400, 400, 400});
filename = "../Resources/sphere.stl";
}
else if (which_geom == 2) { // Dodecahedron
rb = RealBox({-2., -2., -2.}, {2., 2., 2.});
filename = "../Resources/dodecahedron.stl";
}
else if (which_geom == 3) { // Horse
rb = RealBox({-0.12, -0.12, -0.12}, {0.12, 0.12, 0.12});
filename = "../Resources/horse.stl";
}
else if (which_geom == 4) { // Car
// rb = RealBox({-20,-20,-20}, {20,20,20}); // Doesn't work.
rb = RealBox({-10, -5, -5}, {10, 5, 5}); // Works.
filename = "../Resources/porsche.stl";
}
else if (which_geom == 5) { // Orion
rb = RealBox({-10, -5, -10}, {10, 10, 10});
filename = "../Resources/orion.stl";
}
else if (which_geom == 7) { // Adirondacks
rb = RealBox({0, 0, 0}, {200, 200, 50});
filename = "../Resources/adirondack.stl";
}
Array<int, AMREX_SPACEDIM> is_periodic{false, false, false};
Geometry::Setup(&rb, 0, is_periodic.data());
Box domain(IntVect(0), IntVect(n_cell - 1));
geom.define(domain);
}
// Create our signed distance function. K is the tree degree while T is the
// EBGeometry precision.
constexpr int K = 4;
using T = float;
using Vec3 = EBGeometry::Vec3T<T>;
using BV = EBGeometry::BoundingVolumes::AABBT<T>;
AMReXSDF<T, BV, K> sdf(filename);
auto gshop = EB2::makeShop(sdf);
EB2::Build(gshop, geom, 0, 0, 1, true, true, num_coarsen_opt);
// Put some data
MultiFab mf;
{
BoxArray boxArray(geom.Domain());
boxArray.maxSize(max_grid_size);
DistributionMapping dm{boxArray};
std::unique_ptr<EBFArrayBoxFactory> factory =
amrex::makeEBFabFactory(geom, boxArray, dm, {2, 2, 2}, EBSupport::full);
mf.define(boxArray, dm, 1, 0, MFInfo(), *factory);
mf.setVal(1.0);
}
EB_WriteSingleLevelPlotfile("plt", mf, {"rho"}, geom, 0.0, 0);
}
amrex::Finalize();
}
Constructing the BVH¶
When constructing the signed distance function we use the DCEL and BVH functionality directly in the constructor. Note that we are performing the following steps:
Using the STL parser for creating a DCEL mesh.
Constructing a BVH for the DCEL faces.
Flattening the BVH tree for performance.
Exposing signed distance functions¶
Next, we expose the signed distance function to AMReX by implementing the functions
Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept
Note that the AMReX DECL
macros expand to (Real x, Real y)
in 2D, but here we assume that the user has compiled for 3D.