28#include "bitpit_CG.hpp"
30#include "patch_skd_tree.hpp"
48 : m_patch(patch), m_cellRawIds(cellRawIds)
51 throw std::runtime_error(
"Unable to initialize the patch info. Provided patch is not valid.");
72 m_cellBoxes = std::unique_ptr<BoxCache>(
new BoxCache(1, &(m_patch->
getCells())));
73 for (
auto itr = cellRange.
cbegin(); itr != cellRange.
cend(); ++itr) {
74 std::size_t rawCellId = itr.getRawIndex();
77 std::array<std::array<double, 3>, 2> *cellBox = m_cellBoxes->rawData(rawCellId);
107 return *m_cellRawIds;
118 return (*m_cellRawIds)[n];
132 return m_cellBoxes->rawAt(rawId);
143 const std::array<std::array<double, 3>, 2> &cellBox = m_cellBoxes->rawAt(rawId);
145 return 0.5 * (cellBox[0] + cellBox[1]);
157 const std::array<std::array<double, 3>, 2> &cellBox = m_cellBoxes->rawAt(rawId);
159 return 0.5 * (cellBox[0][direction] + cellBox[1][direction]);
172 : m_boxMin{ std::numeric_limits<double>::
max(), std::numeric_limits<double>::
max(), std::numeric_limits<double>::
max()},
173 m_boxMax{- std::numeric_limits<double>::
max(), - std::numeric_limits<double>::
max(), - std::numeric_limits<double>::
max()}
183SkdBox::SkdBox(
const std::array<double,3> &boxMin,
const std::array<double,3> &boxMax)
199 for (
int d = 0; d < 3; ++d) {
200 if (m_boxMin[d] > m_boxMax[d]) {
241 return emptyDistance;
275 return emptySquareDistance;
293 double squareDistance = 0.;
294 for (
int d = 0; d < 3; ++d) {
295 squareDistance += std::pow(std::max({0., m_boxMin[d] - point[d], point[d] - m_boxMax[d]}), 2);
298 return squareDistance;
314 return emptyDistance;
348 return emptySquareDistance;
366 double squareDistance = 0.;
367 for (
int d = 0; d < 3; ++d) {
368 squareDistance += std::pow(std::max(point[d] - m_boxMin[d], m_boxMax[d] - point[d]), 2);
371 return squareDistance;
389 for (
int d = 0; d < 3; d++) {
390 if (point[d] < (m_boxMin[d] - offset)) {
394 if (point[d] > (m_boxMax[d] + offset)) {
419 std::array<double, 3> delta;
420 for (
int d = 0; d < 3; d++) {
421 delta[d] = std::min(std::max(center[d], m_boxMin[d]), m_boxMax[d]) - center[d];
425 return (distance < radius * radius);
437const std::size_t
SkdNode::NULL_ID = std::numeric_limits<std::size_t>::max();
443 : m_patchInfo(nullptr),
444 m_cellRangeBegin(0), m_cellRangeEnd(0),
459 : m_patchInfo(patchInfo),
460 m_cellRangeBegin(cellRangeBegin), m_cellRangeEnd(cellRangeEnd),
463 initializeBoundingBox();
469void SkdNode::initializeBoundingBox()
472 if (m_cellRangeBegin == m_cellRangeEnd){
473 m_boxMin.fill( std::numeric_limits<double>::max());
474 m_boxMax.fill(- std::numeric_limits<double>::max());
480 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
482 const std::array<std::array<double, 3>, 2> &firstCellBox = m_patchInfo->
getCachedBox(cellRawIds[m_cellRangeBegin]);
483 m_boxMin = firstCellBox[0];
484 m_boxMax = firstCellBox[1];
485 for (std::size_t n = m_cellRangeBegin + 1; n < m_cellRangeEnd; n++) {
486 const std::array<std::array<double, 3>, 2> &cellBox = m_patchInfo->
getCachedBox(cellRawIds[n]);
487 for (
int d = 0; d < 3; ++d) {
488 m_boxMin[d] = std::min(cellBox[0][d], m_boxMin[d]);
489 m_boxMax[d] = std::max(cellBox[1][d], m_boxMax[d]);
502 m_boxMin -= tolerance;
503 m_boxMax += tolerance;
514 return (m_cellRangeEnd - m_cellRangeBegin);
528 const std::size_t rawCellId = m_patchInfo->
getCellRawId(m_cellRangeBegin + n);
543 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
547 std::vector<long> cellList(nCells);
548 for (std::size_t n = m_cellRangeBegin; n < m_cellRangeEnd; ++n) {
549 const std::size_t rawCellId = cellRawIds[n];
552 cellList[n - m_cellRangeBegin] = cellId;
575 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
577 std::array<double, 3> boxWeightedMean = m_patchInfo->
evalCachedBoxMean(cellRawIds[m_cellRangeBegin]);
578 for (std::size_t n = m_cellRangeBegin + 1; n < m_cellRangeEnd; ++n) {
579 const std::size_t rawCellId = cellRawIds[n];
584 return boxWeightedMean;
597 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
599 double boxWeightedMean = m_patchInfo->
evalCachedBoxMean(cellRawIds[m_cellRangeBegin], direction);
600 for (std::size_t n = m_cellRangeBegin + 1; n < m_cellRangeEnd; ++n) {
601 const std::size_t rawCellId = cellRawIds[n];
606 return boxWeightedMean;
616 for (
int i = CHILD_BEGIN; i != CHILD_END; ++i) {
617 SkdNode::ChildLocation childLocation =
static_cast<ChildLocation
>(i);
634 return (m_children[
static_cast<std::size_t
>(child)] !=
NULL_ID);
645 return m_children[
static_cast<std::size_t
>(child)];
683 long *
id,
double *closestDistance)
const
686 *closestDistance = std::numeric_limits<double>::max();
710 long *closestId,
double *closestDistance)
const
718 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
720 for (std::size_t n = m_cellRangeBegin; n < m_cellRangeEnd; n++) {
721 std::size_t cellRawId = cellRawIds[n];
722 const Cell &cell = cells.
rawAt(cellRawId);
723 if (interiorCellsOnly && !cell.
isInterior()) {
729 BITPIT_CREATE_WORKSPACE(cellVertexCoordinates, std::array<double BITPIT_COMMA 3>, nCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
733 std::array<double, 3> cellProjection;
737 bool isCellClosest =
false;
739 if (*closestId == Cell::NULL_ID) {
740 isCellClosest =
true;
746 BITPIT_CREATE_WORKSPACE(closestCellVertexCoordinates, std::array<double BITPIT_COMMA 3>, nClosestCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
749 double closestCellDistance;
750 std::array<double, 3> closestCellProjection;
751 closest.
evalPointProjection(point, closestCellVertexCoordinates, &closestCellProjection, &closestCellDistance);
757 std::array<double, 3> cellNormal = cell.
evalNormal(cellVertexCoordinates);
758 std::array<double, 3> closestNormal = closest.
evalNormal(closestCellVertexCoordinates);
764 double cellAligement =
dotProduct(cellNormal, point - cellProjection);
765 double closestAligement =
dotProduct(closestNormal, point - closestCellProjection);
768 if (cellAligement > closestAligement) {
769 isCellClosest =
true;
772 }
else if (cellDistance < *closestDistance) {
773 isCellClosest =
true;
778 *closestId = cell.
getId();
779 *closestDistance = cellDistance;
803 std::vector<long> *closestIds,
double *closestDistance)
const
811 const std::vector<std::size_t> &cellRawIds = m_patchInfo->
getCellRawIds();
813 for (std::size_t n = m_cellRangeBegin; n < m_cellRangeEnd; n++) {
814 std::size_t cellRawId = cellRawIds[n];
815 const Cell &cell = cells.
rawAt(cellRawId);
816 if (interiorCellsOnly && !cell.
isInterior()) {
822 BITPIT_CREATE_WORKSPACE(cellVertexCoordinates, std::array<double BITPIT_COMMA 3>, nCellVertices, ReferenceElementInfo::MAX_ELEM_VERTICES);
826 std::array<double, 3> cellProjection;
836 closestIds->push_back(cell.
getId());
837 }
else if (cellDistance < *closestDistance) {
838 closestIds->assign(1, cell.
getId());
839 *closestDistance = cellDistance;
852bool SkdGlobalCellDistance::m_MPIDatatypeInitialized =
false;
853MPI_Datatype SkdGlobalCellDistance::m_MPIDatatype;
855bool SkdGlobalCellDistance::m_MPIMinOperationInitialized =
false;
856MPI_Op SkdGlobalCellDistance::m_MPIMinOperation;
865 if (!m_MPIDatatypeInitialized) {
866 int blocklengths[3] = {1, 1, 1};
868 MPI_Datatype types[3] = {MPI_DOUBLE, MPI_LONG, MPI_INT};
869 MPI_Type_create_struct(3, blocklengths, displacements, types, &m_MPIDatatype);
870 MPI_Type_commit(&m_MPIDatatype);
871 m_MPIDatatypeInitialized =
true;
874 return m_MPIDatatype;
884 if (!m_MPIMinOperationInitialized) {
886 m_MPIMinOperationInitialized =
true;
889 return m_MPIMinOperation;
904 int nDistances = *len;
905 for (
int i = 0; i < nDistances; ++i) {
906 bool updateDistance =
false;
907 if (in[i].m_id != Cell::NULL_ID) {
908 if (inout[i].m_id == Cell::NULL_ID) {
909 updateDistance =
true;
910 }
else if (std::abs(in[i].m_distance) < std::abs(inout[i].m_distance)) {
911 updateDistance =
true;
915 if (updateDistance) {
962 *distance = m_distance;
1024 : m_patchInfo(patch, &m_cellRawIds),
1025 m_cellRawIds(interiorCellsOnly ? patch->getInternalCellCount() : patch->getCellCount()),
1026 m_nLeafs(0), m_nMinLeafCells(0), m_nMaxLeafCells(0),
1027 m_interiorCellsOnly(interiorCellsOnly),
1028 m_threadSafeLookups(false)
1029#if BITPIT_ENABLE_MPI
1030 , m_rank(0), m_nProcessors(1), m_communicator(MPI_COMM_NULL)
1043 return m_nMinLeafCells;
1053 return m_nMaxLeafCells;
1089 if (m_interiorCellsOnly) {
1097 if (m_cellRawIds.size() != nCells) {
1098 m_cellRawIds.resize(nCells);
1102 for (
auto itr = cellRange.
begin(); itr != cellRange.
end(); ++itr) {
1103 m_cellRawIds[k++] = itr.getRawIndex();
1110 std::size_t nodesCount = std::max(1,
int(std::ceil(2. * nCells / leafThreshold - 1.)));
1111 m_nodes.reserve(nodesCount);
1114 m_nodes.emplace_back(&m_patchInfo, 0, nCells);
1117 std::queue<std::size_t> nodeStack;
1119 while (!nodeStack.empty()) {
1120 std::size_t nodeId = nodeStack.front();
1128 createChildren(nodeId, leafThreshold);
1132 for (
int i = SkdNode::CHILD_BEGIN; i != SkdNode::CHILD_END; ++i) {
1133 std::size_t childId = node.
getChildId(
static_cast<SkdNode::ChildLocation
>(i));
1135 nodeStack.push(childId);
1141 if (squeezeStorage) {
1142 m_nodes.shrink_to_fit();
1148#if BITPIT_ENABLE_MPI
1155 buildPartitionBoxes();
1172 m_nMinLeafCells = 0;
1173 m_nMaxLeafCells = 0;
1176 std::vector<SkdNode>().swap(m_nodes);
1177 std::vector<std::size_t>().swap(m_cellRawIds);
1180 m_cellRawIds.clear();
1183#if BITPIT_ENABLE_MPI
1186 std::vector<SkdBox>().swap(m_partitionBoxes);
1188 m_partitionBoxes.clear();
1210 return m_nodes.size();
1231 return m_nodes[nodeId];
1242 return m_nodes[nodeId];
1259 std::size_t depth = 0;
1260 for (
int i = SkdNode::CHILD_BEGIN; i != SkdNode::CHILD_END; ++i) {
1261 SkdNode::ChildLocation childLocation =
static_cast<SkdNode::ChildLocation
>(i);
1276void PatchSkdTree::createChildren(std::size_t parentId, std::size_t leafThreshold)
1282 if (parentCellCount <= leafThreshold) {
1283 createLeaf(parentId);
1291 const std::array<double, 3> &parentBoxMin = parent.
getBoxMin();
1292 const std::array<double, 3> &parentBoxMax = parent.
getBoxMax();
1294 int largerDirection = 0;
1295 double boxMaximumLength = parentBoxMax[largerDirection] - parentBoxMin[largerDirection];
1296 for (
int d = 1; d < 3; ++d) {
1297 double length = parentBoxMax[d] - parentBoxMin[d];
1298 if (length > boxMaximumLength) {
1299 largerDirection = d;
1300 boxMaximumLength = length;
1311 for (
int d = 0; d < 3; ++d) {
1313 int splitDirection = (largerDirection + d) % 3;
1323 std::size_t leftBegin = parent.m_cellRangeBegin;
1324 std::size_t leftEnd = parent.m_cellRangeEnd;
1325 std::size_t rightBegin = parent.m_cellRangeBegin;
1326 std::size_t rightEnd = parent.m_cellRangeEnd;
1329 while (rightBegin != leftEnd && m_patchInfo.
evalCachedBoxMean(m_cellRawIds[rightBegin], splitDirection) <= splitThreshold) {
1334 while (rightBegin != leftEnd && m_patchInfo.
evalCachedBoxMean(m_cellRawIds[leftEnd - 1], splitDirection) > splitThreshold) {
1339 if (rightBegin == leftEnd) {
1346 std::iter_swap(m_cellRawIds.begin() + (leftEnd - 1), m_cellRawIds.begin() + rightBegin);
1349 if (leftEnd <= leftBegin || rightEnd <= rightBegin) {
1357 long leftId = m_nodes.size();
1358 m_nodes.emplace_back(&m_patchInfo, leftBegin, leftEnd);
1359 _getNode(parentId).m_children[
static_cast<std::size_t
>(SkdNode::CHILD_LEFT)] = leftId;
1365 long rightId = m_nodes.size();
1366 m_nodes.emplace_back(&m_patchInfo, rightBegin, rightEnd);
1367 _getNode(parentId).m_children[
static_cast<std::size_t
>(SkdNode::CHILD_RIGHT)] = rightId;
1376 createLeaf(parentId);
1384void PatchSkdTree::createLeaf(std::size_t nodeId)
1386 const SkdNode &node =
getNode(nodeId);
1387 std::size_t nodeCellCount = node.getCellCount();
1390 m_nMinLeafCells = std::min(nodeCellCount, m_nMinLeafCells);
1391 m_nMaxLeafCells = std::max(nodeCellCount, m_nMaxLeafCells);
1401 m_threadSafeLookups = enable;
1411 return m_threadSafeLookups;
1414#if BITPIT_ENABLE_MPI
1425 throw std::runtime_error(
"Skd-tree communicator can be set just once.");
1429 if (communicator == MPI_COMM_NULL) {
1430 throw std::runtime_error(
"Skd-tree communicator is not valid.");
1438 MPI_Comm_dup(communicator, &m_communicator);
1441 MPI_Comm_size(m_communicator, &m_nProcessors);
1442 MPI_Comm_rank(m_communicator, &
m_rank);
1454 int finalizedCalled;
1455 MPI_Finalized(&finalizedCalled);
1456 if (finalizedCalled) {
1460 MPI_Comm_free(&m_communicator);
1481 return m_communicator;
1490void PatchSkdTree::buildPartitionBoxes()
1496 std::vector<int> count(m_nProcessors, 3);
1498 std::vector<int> displacements(m_nProcessors);
1499 for (
int i = 0; i < m_nProcessors; ++i) {
1500 displacements[i] = i*3;
1503 std::vector<std::array<double, 3>> minBoxes(m_nProcessors);
1505 MPI_Allgatherv(MPI_IN_PLACE, 3, MPI_DOUBLE, minBoxes.data(),
1506 count.data(), displacements.data(), MPI_DOUBLE, m_communicator);
1508 std::vector<std::array<double, 3>> maxBoxes(m_nProcessors);
1510 MPI_Allgatherv(MPI_IN_PLACE, 3, MPI_DOUBLE, maxBoxes.data(),
1511 count.data(), displacements.data(), MPI_DOUBLE, m_communicator);
1514 m_partitionBoxes.resize(
getPatch().getProcessorCount());
1515 for (
int i = 0; i < m_nProcessors; ++i) {
1516 m_partitionBoxes[i] = SkdBox(minBoxes[i], maxBoxes[i]);
1529 return m_partitionBoxes[rank];
The Cell class defines the cells.
void evalPointProjection(const std::array< double, 3 > &point, const std::array< double, 3 > *coordinates, std::array< double, 3 > *projection, double *distance) const
std::array< double, 3 > evalNormal(const std::array< double, 3 > *coordinates, const std::array< double, 3 > &orientation={{0., 0., 1.}}, const std::array< double, 3 > &point={{0.5, 0.5, 0.5}}) const
int getVertexCount() const
The PatchKernel class provides an interface for defining patches.
CellConstIterator cellConstBegin() const
CellConstIterator internalCellConstEnd() const
PiercedVector< Cell > & getCells()
CellConstIterator internalCellConstBegin() const
void evalElementBoundingBox(const Element &element, std::array< double, 3 > *minPoint, std::array< double, 3 > *maxPoint) const
ConstProxyVector< std::array< double BITPIT_COMMA 3 > > getElementVertexCoordinates(const Element &element) const
CellConstIterator cellConstEnd() const
const MPI_Comm & getCommunicator() const
bool isPartitioned() const
virtual long getCellCount() const
long getInternalCellCount() const
bool isCommunicatorSet() const
std::size_t evalMaxDepth(std::size_t rootId=0) const
const SkdBox & getPartitionBox(int rank) const
std::size_t getLeafMinCellCount() const
std::size_t getLeafMaxCellCount() const
bool areLookupsThreadSafe() const
void setCommunicator(MPI_Comm communicator)
std::size_t getLeafCount() const
SkdNode & _getNode(std::size_t nodeId)
void enableThreadSafeLookups(bool enable)
const SkdNode & getNode(std::size_t nodeId) const
void build(std::size_t leaftThreshold=1, bool squeezeStorage=false)
std::size_t getNodeCount() const
void clear(bool release=false)
PatchSkdTree(const PatchKernel *patch, bool interiorCellsOnly=false)
const MPI_Comm & getCommunicator() const
const PatchKernel & getPatch() const
id_t getId(const id_t &fallback=-1) const noexcept
Metafunction for generating a pierced kernel.
const_iterator rawFind(std::size_t pos) const noexcept
The PiercedStorageRange allow to iterate using range-based loops over a PiercedStorage.
const_iterator cbegin() const noexcept
iterator begin() noexcept
const_iterator cend() const noexcept
void initialize(const storage_t *storage)
Metafunction for generating a pierced storage.
__PVS_REFERENCE__ rawAt(std::size_t pos)
Metafunction for generating a pierced vector.
The SkdBox class defines a box.
bool boxIntersectsSphere(const std::array< double, 3 > ¢er, double radius) const
double evalPointMaxSquareDistance(const std::array< double, 3 > &point) const
const std::array< double, 3 > & getBoxMin() const
double evalPointMaxDistance(const std::array< double, 3 > &point) const
double evalPointMinDistance(const std::array< double, 3 > &point) const
double evalPointMinSquareDistance(const std::array< double, 3 > &point) const
const std::array< double, 3 > & getBoxMax() const
bool boxContainsPoint(const std::array< double, 3 > &point, double offset) const
The SkdPatchInfo class defines a node of the skd-tree.
double evalPointDistance(const std::array< double, 3 > &point, bool interiorCellsOnly) const
std::vector< long > getCells() const
long getCell(std::size_t n) const
void updatePointClosestCell(const std::array< double, 3 > &point, bool interiorCellsOnly, long *closestId, double *closestDistance) const
void findPointClosestCell(const std::array< double, 3 > &point, bool interiorCellsOnly, long *closestId, double *closestDistance) const
std::array< double, 3 > evalBoxWeightedMean() const
const SkdBox & getBoundingBox() const
void updatePointClosestCells(const std::array< double, 3 > &point, bool interiorCellsOnly, std::vector< long > *closestIds, double *closestDistance) const
static BITPIT_PUBLIC_API const std::size_t NULL_ID
std::size_t getChildId(ChildLocation child) const
bool hasChild(ChildLocation child) const
std::size_t getCellCount() const
T dotProduct(const std::array< T, d > &x, const std::array< T, d > &y)
std::array< T, d > max(const std::array< T, d > &x, const std::array< T, d > &y)
#define BITPIT_UNUSED(variable)
#define BITPIT_CREATE_WORKSPACE(workspace, item_type, size, stack_size)
The SkdGlobalCellDistance class allows to define a distance between a point and a cell.
static MPI_Datatype getMPIDatatype()
static void executeMPIMinOperation(SkdGlobalCellDistance *in, SkdGlobalCellDistance *inout, int *len, MPI_Datatype *datatype)
void exportData(int *rank, long *id, double *distance) const
static MPI_Op getMPIMinOperation()
The SkdPatchInfo class allows to store patch information needed for the construction and the utilizat...
std::array< double, 3 > evalCachedBoxMean(std::size_t rawId) const
SkdPatchInfo(const PatchKernel *patch, const std::vector< std::size_t > *cellRawIds)
const PatchKernel & getPatch() const
const std::vector< std::size_t > & getCellRawIds() const
const std::array< std::array< double, 3 >, 2 > & getCachedBox(std::size_t rawId) const
std::size_t getCellRawId(std::size_t n) const