3D mesh adaptation using voloctreeThis example creates a 3D octree mesh on the square domain [0,1]x[0,1]. On this domain two fields, a scalar and a vector, are defined.
Mesh is first refined and then coarsened, during each mesh adaption step fields are remapped on the updated mesh.
#include <array>
#if BITPIT_ENABLE_MPI==1
#include <mpi.h>
#endif
#include "bitpit_common.hpp"
#include "bitpit_voloctree.hpp"
using namespace bitpit;
public:
: m_patch(patch), m_scalarField(scalarField), m_vectorField(vectorField)
{
};
{
if (name == "scalarField") {
long id = cell.getId();
}
} else if (name == "vectorField") {
long id = cell.getId();
}
}
};
private:
};
int main(int argc, char *argv[])
{
#if BITPIT_ENABLE_MPI == 1
MPI_Init(&argc, &argv);
#endif
log::cout() << " Initializing mesh..." << std::endl;
double length = 1.0;
std::array<double, 3> center = {{0.0,0.0,0.0}};
std::array<double, 3> minimum = center - length / 2.;
double dh = length / 16.;
#if BITPIT_ENABLE_MPI
VolOctree mesh(3, minimum, length, dh, MPI_COMM_NULL);
#else
#endif
mesh.initializeAdjacencies();
mesh.update();
log::cout() << "Initializing fields..." << std::endl;
for (
const Cell &cell : mesh.getCells()) {
const long cellId = cell.getId();
std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
scalarField.
set(cellId, r);
vectorField.
set(cellId, {{cellCentroid[0] / r, cellCentroid[1] / r, cellCentroid[2] / r}});
}
mesh.getVTK().setName("voloctree_adaptation_example_00001");
mesh.getVTK().setCounter();
mesh.getVTK().addData<double>("scalarField", VTKFieldType::SCALAR, VTKLocation::CELL, &dataStreamer);
mesh.getVTK().addData<std::array<double, 3>>("vectorField", VTKFieldType::VECTOR, VTKLocation::CELL, &dataStreamer);
mesh.write();
bool trackAdaptation = true;
bool squeeshPatchStorage = false;
std::vector<adaption::Info> adaptionData;
log::cout() << "Performing refinement..." << std::endl;
int nRefinements = 2;
for (int i = 0; i < nRefinements; ++i) {
log::cout() << " Marking cells that need refinement..." << std::endl;
for (
const Cell &cell : mesh.getCells()) {
long cellId = cell.getId();
std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
if (r < 0.2) {
mesh.markCellForRefinement(cellId);
}
}
adaptionData = mesh.adaptionPrepare(trackAdaptation);
if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
continue;
} else if (adaptionInfo.type != adaption::TYPE_REFINEMENT) {
continue;
}
for (long previousId : adaptionInfo.previous) {
previousScalarField.
insert(previousId, std::move(scalarField.
at(previousId)));
previousVectorField.
insert(previousId, std::move(vectorField.
at(previousId)));
}
}
adaptionData = mesh.adaptionAlter(trackAdaptation, squeeshPatchStorage);
if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
continue;
} else if (adaptionInfo.type != adaption::TYPE_REFINEMENT) {
continue;
}
long parentId = adaptionInfo.previous.front();
for (long currentId : adaptionInfo.current) {
scalarField.
set(currentId, previousScalarField.
at(parentId));
vectorField.
set(currentId, previousVectorField.
at(parentId));
}
}
mesh.adaptionCleanup();
mesh.write();
}
int nofCoarsening = 1;
for (int i = 0; i < nofCoarsening; ++i) {
for (
const Cell &cell : mesh.getCells()) {
long cellId = cell.getId();
std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
if (r < 0.15) {
mesh.markCellForCoarsening(cellId);
}
}
adaptionData = mesh.adaptionPrepare(trackAdaptation);
if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
continue;
} else if (adaptionInfo.type != adaption::TYPE_COARSENING) {
continue;
}
for (long previousId : adaptionInfo.previous) {
previousScalarField.
insert(previousId, std::move(scalarField.
at(previousId)));
previousVectorField.
insert(previousId, std::move(vectorField.
at(previousId)));
}
}
adaptionData = mesh.adaptionAlter(trackAdaptation, squeeshPatchStorage);
if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
continue;
} else if (adaptionInfo.type != adaption::TYPE_COARSENING) {
continue;
}
int nParents = adaptionInfo.previous.size();
double scalarParentAverage = 0.;
std::array<double, 3> vectorParentAverage = {{0., 0., 0.}};
for (long parentId : adaptionInfo.previous) {
scalarParentAverage += previousScalarField.
at(parentId);
vectorParentAverage += previousVectorField.
at(parentId);
}
scalarParentAverage /= nParents;
vectorParentAverage /= (double) nParents;
long childId = adaptionInfo.current.front();
scalarField.
set(childId, scalarParentAverage);
vectorField.
set(childId, vectorParentAverage);
}
mesh.adaptionCleanup();
mesh.write();
}
#if BITPIT_ENABLE_MPI == 1
MPI_Finalize();
#endif
}
void flushData(std::fstream &stream, const std::string &name, VTKFormat format) override
The Cell class defines the cells.
The PatchKernel class provides an interface for defining patches.
const CellConstRange getVTKCellWriteRange() const
void setDynamicKernel(const PiercedKernel< id_t > *kernel, PiercedSyncMaster::SyncMode syncMode)
Metafunction for generating a pierced storage.
void set(id_t id, const value_t &value)
__PS_REFERENCE__ at(id_t id, std::size_t k=0)
__PVS_REFERENCE__ at(id_t id)
Metafunction for generating a pierced vector.
iterator insert(id_t id, const value_t &value)
The base class to be used to derive VTK streamers form.
void flushValue(std::fstream &, VTKFormat, const T &value) const
The VolOctree defines a Octree patch.
#define BITPIT_UNUSED(variable)
The Info struct defines the information associated to an adaption.