25 # include "SkdTreeUtils.hpp"
26 # include "MimmoCGUtils.hpp"
27 # include <bitpit_surfunstructured.hpp>
28 # include <surface_skd_tree.hpp>
34 namespace skdTreeUtils{
49 double distance(
const std::array<double,3> *point,
const bitpit::PatchSkdTree *tree,
long &
id,
double r)
52 double h = std::numeric_limits<double>::max();
54 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a void tree is detected.");
56 if(!
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()))){
57 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a not surface patch tree is detected.");
84 double signedDistance(
const std::array<double,3> *point,
const bitpit::PatchSkdTree *tree,
long &
id, std::array<double,3> &normal,
double r)
87 double h = std::numeric_limits<double>::max();
90 throw std::runtime_error(
"Invalid use of skdTreeUtils::signedDistance method: a void tree is detected.");
92 const bitpit::SurfUnstructured *spatch =
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()));
94 throw std::runtime_error(
"Invalid use of skdTreeUtils::signedDistance method: a not surface patch tree is detected.");
119 void distance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
double *distances,
double r)
121 std::vector<double> rs(nP, r);
122 distance(nP, points, tree, ids, distances, rs.data());
140 void distance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
double *distances,
double *r)
144 for (
int ip = 0; ip < nP; ip++){
145 distances[ip] = std::numeric_limits<double>::max();
149 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a void tree is detected.");
151 if(!
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()))){
152 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a not surface patch tree is detected.");
155 for (
int ip = 0; ip < nP; ip++){
156 const std::array<double,3> *point = &points[ip];
159 double rpoint = r[ip];
186 void signedDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
double *distances, std::array<double,3> *normals,
double r)
188 std::vector<double> rs(nP, r);
189 signedDistance(nP, points, tree, ids, distances, normals, rs.data());
213 void signedDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
double *distances, std::array<double,3> *normals,
double *r)
217 for (
int ip = 0; ip < nP; ip++){
218 distances[ip] = std::numeric_limits<double>::max();
222 throw std::runtime_error(
"Invalid use of skdTreeUtils::signedDistance method: a void tree is detected.");
224 const bitpit::SurfUnstructured *spatch =
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()));
226 throw std::runtime_error(
"Invalid use of skdTreeUtils::signedDistance method: a not surface patch tree is detected.");
229 for (
int ip = 0; ip < nP; ip++){
230 const std::array<double,3> *point = &points[ip];
233 double rpoint = r[ip];
251 std::vector<long>
selectByPatch(bitpit::PatchSkdTree *selection, bitpit::PatchSkdTree *target,
double tol){
253 int nleafs = selection->getLeafCount();
254 int nnodess = selection->getNodeCount();
255 std::vector<const bitpit::SkdNode*> leafSelection(nleafs);
257 for (
int i=0; i<nnodess; i++){
258 if (selection->getNode(i).isLeaf()){
259 if (bitpit::CGElem::intersectBoxBox(selection->getNode(i).getBoxMin(),
260 selection->getNode(i).getBoxMax(),
261 target->getNode(0).getBoxMin(),
262 target->getNode(0).getBoxMax(),
265 leafSelection[count] = &(selection->getNode(i));
271 leafSelection.resize(count);
274 std::vector<long> extracted;
296 void extractTarget(bitpit::PatchSkdTree *target,
const std::vector<const bitpit::SkdNode*> & leafSelection, std::vector<long> &extracted,
double tol){
298 if(leafSelection.empty())
return;
299 std::size_t rootId = 0;
301 std::vector<long> candidates;
302 std::vector<std::pair< std::size_t, std::vector<const bitpit::SkdNode*> > > nodeStack;
304 std::vector<const bitpit::SkdNode*> tocheck;
305 for (
int i=0; i<(int)leafSelection.size(); i++){
306 if (bitpit::CGElem::intersectBoxBox(leafSelection[i]->getBoxMin(),
307 leafSelection[i]->getBoxMax(),
308 target->getNode(rootId).getBoxMin(),
309 target->getNode(rootId).getBoxMax(),
313 tocheck.push_back(leafSelection[i]);
316 nodeStack.push_back(std::make_pair(rootId, tocheck) );
318 while(!nodeStack.empty()){
320 std::pair<long, std::vector<const bitpit::SkdNode*> > touple = nodeStack.back();
321 const bitpit::SkdNode & node = target->getNode(touple.first);
322 nodeStack.pop_back();
326 for (
int i = bitpit::SkdNode::CHILD_BEGIN; i != bitpit::SkdNode::CHILD_END; ++i) {
327 bitpit::SkdNode::ChildLocation childLocation =
static_cast<bitpit::SkdNode::ChildLocation
>(i);
328 std::size_t childId = node.getChildId(childLocation);
329 if (childId != bitpit::SkdNode::NULL_ID) {
332 for (
int i=0; i<(int)touple.second.size(); i++){
333 if (bitpit::CGElem::intersectBoxBox(touple.second[i]->getBoxMin(),
334 touple.second[i]->getBoxMax(),
335 target->getNode(childId).getBoxMin(),
336 target->getNode(childId).getBoxMax(),
340 tocheck.push_back(touple.second[i]);
343 if(!tocheck.empty()) nodeStack.push_back(std::make_pair(childId, tocheck) );
348 candidates.push_back(touple.first);
352 std::unordered_set<long> cellExtracted;
353 for(
const auto & nodeId: candidates){
354 const bitpit::SkdNode & node = target->getNode(nodeId);
355 std::vector<long> cellids = node.getCells();
356 cellExtracted.insert(cellids.begin(), cellids.end());
359 extracted.insert(extracted.end(), cellExtracted.begin(), cellExtracted.end());
379 projectPoint(1, point, skdtree, &projected_point, &
id, r);
380 return projected_point;
398 void projectPoint(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree, std::array<double,3> *projected_points,
long *ids,
double r )
400 std::vector<double> rs(nP, r);
401 projectPoint(nP, points, tree, projected_points, ids, rs.data());
419 void projectPoint(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree, std::array<double,3> *projected_points,
long *ids,
double *r )
423 for (
int ip = 0; ip < nP; ip++){
424 ids[ip] = bitpit::Cell::NULL_ID;
425 r[ip] = std::max(r[ip], tree->getPatch().getTol());
427 std::vector<darray3E> normals(nP);
429 std::vector<double> dist(nP, std::numeric_limits<double>::max());
430 double max_dist = std::numeric_limits<double>::max();
431 while (max_dist == std::numeric_limits<double>::max()){
433 signedDistance(nP, points, tree, ids, dist.data(), normals.data(), r);
434 for (
int ip = 0; ip < nP; ip++){
435 if (std::abs(dist[ip]) >= max_dist){
439 max_dist = std::abs(*std::max_element(dist.begin(), dist.end()));
440 max_dist = std::max(max_dist, std::abs(*std::min_element(dist.begin(), dist.end())));
443 for (
int ip = 0; ip < nP; ip++){
444 projected_points[ip] = points[ip] - dist[ip] * normals[ip];
458 if(!
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()))){
459 throw std::runtime_error(
"Invalid use of skdTreeUtils::locatePointOnPatch method: a non surface patch or void patch was detected.");
463 long id = bitpit::Cell::NULL_ID;
464 double distance = std::numeric_limits<double>::max();
467 long cellId = bitpit::Cell::NULL_ID;
471 bool checkBelong =
false;
473 bitpit::ElementType eltype = tree->getPatch().getCell(cellId).getType();
474 auto vList = tree->getPatch().getCell(cellId).getVertexIds();
477 for(
const auto & idV : vList){
478 vertCoords[counterList] = tree->getPatch().getVertexCoords(idV);
483 case bitpit::ElementType::LINE:
486 case bitpit::ElementType::TRIANGLE:
489 case bitpit::ElementType::PIXEL:
490 case bitpit::ElementType::QUAD:
491 case bitpit::ElementType::POLYGON:
495 throw std::runtime_error(
"Not supported cell type");
517 computePseudoNormal(
const std::array<double, 3> &point,
const bitpit::SurfUnstructured *surface_mesh,
long id, std::array<double, 3> &pseudo_normal)
520 pseudo_normal.fill(0.);
521 double h, s(std::numeric_limits<double>::max());
524 if (
id != bitpit::Cell::NULL_ID){
526 const bitpit::Cell & cell = surface_mesh->getCell(
id);
527 bitpit::ConstProxyVector<long> vertIds = cell.getVertexIds();
530 for (
const auto & iV: vertIds){
531 VS[count] = surface_mesh->getVertexCoords(iV);
538 if ( vertIds.size() == 3 ){
540 h = bitpit::CGElem::distancePointTriangle(point, VS[0], VS[1], VS[2],lambda);
542 for(
const auto &val: lambda){
543 normal += val * surface_mesh->evalVertexNormal(
id,count) ;
544 xP += val * VS[count];
547 }
else if ( vertIds.size() == 2 ){
549 h = bitpit::CGElem::distancePointSegment(point, VS[0], VS[1], lambda);
551 for(
const auto &val: lambda){
552 normal += val * surface_mesh->evalVertexNormal(
id,count) ;
553 xP += val * VS[count];
557 std::vector<double> lambda;
558 h = bitpit::CGElem::distancePointPolygon(point, VS,lambda);
560 for(
const auto &val: lambda){
561 normal += val * surface_mesh->evalVertexNormal(
id,count) ;
562 xP += val * VS[count];
567 s = sign( dotProduct(normal, point - xP) );
571 pseudo_normal = s * (point - xP);
572 double normX = norm2(pseudo_normal);
573 if(normX < surface_mesh->getTol()){
574 pseudo_normal = normal/norm2(normal);
576 pseudo_normal /= normX;
594 bool checkBelong =
false;
595 bitpit::ElementType eltype = surface_mesh->getCell(cellId).getType();
596 auto vList = surface_mesh->getCell(cellId).getVertexIds();
599 for(
const auto & idV : vList){
600 vertCoords[counterList] = surface_mesh->getVertexCoords(idV);
605 case bitpit::ElementType::LINE:
608 case bitpit::ElementType::TRIANGLE:
611 case bitpit::ElementType::PIXEL:
612 case bitpit::ElementType::QUAD:
613 case bitpit::ElementType::POLYGON:
617 throw std::runtime_error(
"Not supported cell type");
637 void globalDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks,
double *distances,
double r,
bool shared)
639 std::vector<double> rs(nP, r);
640 globalDistance(nP, points, tree, ids, ranks, distances, rs.data(), shared);
656 void globalDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks,
double *distances,
double* r,
bool shared)
660 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a void tree is detected.");
662 if(!
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()))){
663 throw std::runtime_error(
"Invalid use of skdTreeUtils::distance method: a not surface patch tree is detected.");
667 findSharedPointClosestGlobalCell(nP, points, tree, ids, ranks, distances, r);
669 static_cast<const bitpit::SurfaceSkdTree*
>(tree)->findPointClosestGlobalCell(nP, points, r, ids, ranks, distances);
690 void signedGlobalDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks, std::array<double,3> *normals,
double *distances,
double r,
bool shared)
692 std::vector<double> rs(nP, r);
693 signedGlobalDistance(nP, points, tree, ids, ranks, normals, distances, rs.data(), shared);
712 void signedGlobalDistance(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks, std::array<double,3> *normals,
double *distances,
double *r,
bool shared)
716 throw std::runtime_error(
"Invalid use of skdTreeUtils::signedGlobalDistance method: a void tree is detected.");
718 const bitpit::SurfUnstructured & spatch =
static_cast<const bitpit::SurfUnstructured&
>(tree->getPatch());
722 findSharedPointClosestGlobalCell(nP, points, tree, ids, ranks, distances, r);
725 static_cast<const bitpit::SurfaceSkdTree*
>(tree)->findPointClosestGlobalCell(nP, points, r, ids, ranks, distances);
729 int myrank = spatch.getRank();
733 std::map<int,std::vector<long>> ask_to_rank;
734 std::map<int,std::vector<std::array<double,3>>> point_to_rank;
735 std::map<int,std::vector<int>> point_index_received_from_rank;
738 std::vector<double> signs;
739 if(shared) signs.resize(nP, std::numeric_limits<double>::max());
742 for (
int ip = 0; ip < nP; ip++){
744 const std::array<double,3> & point = points[ip];
745 const long & cellId = ids[ip];
746 const int & cellRank = ranks[ip];
748 std::array<double,3> & pseudo_normal = normals[ip];
751 if (cellRank == myrank){
754 if(cellId != bitpit::Cell::NULL_ID){
765 pseudo_normal = std::array<double,3>({std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max()});
769 ask_to_rank[cellRank].push_back(cellId);
772 point_to_rank[cellRank].push_back(point);
775 point_index_received_from_rank[cellRank].push_back(ip);
782 int nProcessors = spatch.getProcessorCount();
784 if (nProcessors == 1 && shared){
785 for (
int ip = 0; ip < nP; ip++){
786 const long & cellId = ids[ip];
788 double & s = signs[ip];
789 if(cellId != bitpit::Cell::NULL_ID){
795 if (nProcessors > 1 && spatch.isPartitioned()){
799 MPI_Allreduce(MPI_IN_PLACE, normals, 3*nP, MPI_DOUBLE, MPI_MIN, tree->getPatch().getCommunicator());
800 MPI_Allreduce(MPI_IN_PLACE, signs.data(), nP, MPI_DOUBLE, MPI_MIN, tree->getPatch().getCommunicator());
801 for (
int ip = 0; ip < nP; ip++){
802 const long & cellId = ids[ip];
804 double & s = signs[ip];
805 if(cellId != bitpit::Cell::NULL_ID){
812 std::vector<int> n_send_to_rank(nProcessors, 0);
813 for (
int irank = 0; irank < nProcessors; irank++){
814 int n_ask_to_current_rank = ask_to_rank[irank].size();
815 MPI_Gather(&n_ask_to_current_rank, 1, MPI_INT, n_send_to_rank.data(), 1, MPI_INT, irank, tree->getPatch().getCommunicator());
819 std::map<int,std::vector<long>> send_to_rank;
820 std::map<int,std::vector<std::array<double,3>>> point_from_rank;
821 for (
int irank = 0; irank < nProcessors; irank++){
822 send_to_rank[irank].resize(n_send_to_rank[irank], bitpit::Cell::NULL_ID);
823 point_from_rank[irank].resize(n_send_to_rank[irank], std::array<double,3>({{0.,0.,0.}}));
827 for (
int irank = 0; irank < nProcessors; irank++){
828 if (myrank == irank){
829 for (
int jrank = 0; jrank < nProcessors; jrank++){
831 int n_send_to_current_rank = n_send_to_rank[jrank];
832 MPI_Recv(send_to_rank[jrank].data(), n_send_to_current_rank, MPI_LONG, jrank, 100, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
833 MPI_Recv(point_from_rank[jrank].data(), n_send_to_current_rank*3, MPI_DOUBLE, jrank, 101, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
837 int n_ask_to_current_rank = ask_to_rank[irank].size();
838 MPI_Send(ask_to_rank[irank].data(), n_ask_to_current_rank, MPI_LONG, irank, 100, tree->getPatch().getCommunicator());
839 MPI_Send(point_to_rank[irank].data(), n_ask_to_current_rank*3, MPI_DOUBLE, irank, 101, tree->getPatch().getCommunicator());
844 std::map<int, std::vector<std::array<double,3>>> normal_to_rank;
845 std::map<int, std::vector<double>> sign_to_rank;
847 for (
int irank = 0; irank < nProcessors; irank++){
848 normal_to_rank[irank].resize(n_send_to_rank[irank], std::array<double,3>({std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max()}));
849 sign_to_rank[irank].resize(n_send_to_rank[irank], std::numeric_limits<double>::max());
850 for (
int ip = 0; ip < n_send_to_rank[irank]; ip++){
852 const std::array<double,3> & point = point_from_rank[irank][ip];
853 const long & cellId = send_to_rank[irank][ip];
854 std::array<double,3> & pseudo_normal = normal_to_rank[irank][ip];
855 double & s = sign_to_rank[irank][ip];
863 std::map<int, std::vector<std::array<double,3>>> normal_from_rank;
864 std::map<int, std::vector<double>> sign_from_rank;
866 for (
int irank = 0; irank < nProcessors; irank++){
867 if (myrank == irank){
868 for (
int jrank = 0; jrank < nProcessors; jrank++){
870 int n_ask_to_current_rank = ask_to_rank[jrank].size();
871 normal_from_rank[jrank].resize(n_ask_to_current_rank);
872 MPI_Recv(normal_from_rank[jrank].data(), n_ask_to_current_rank*3, MPI_DOUBLE, jrank, 102, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
874 sign_from_rank[jrank].resize(n_ask_to_current_rank);
875 MPI_Recv(sign_from_rank[jrank].data(), n_ask_to_current_rank, MPI_DOUBLE, jrank, 103, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
878 for (
int ip = 0; ip < n_ask_to_current_rank; ip++){
879 int point_index = point_index_received_from_rank[jrank][ip];
880 normals[point_index] = normal_from_rank[jrank][ip];
881 distances[point_index] *= sign_from_rank[jrank][ip];
887 int n_send_to_current_rank = n_send_to_rank[irank];
888 MPI_Send(normal_to_rank[irank].data(), n_send_to_current_rank*3, MPI_DOUBLE, irank, 102, tree->getPatch().getCommunicator());
889 MPI_Send(sign_to_rank[irank].data(), n_send_to_current_rank, MPI_DOUBLE, irank, 103, tree->getPatch().getCommunicator());
910 void projectPointGlobal(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree, std::array<double,3> *projected_points,
long *ids,
int *ranks,
double r,
bool shared )
912 std::vector<double> rs(nP, r);
913 projectPointGlobal(nP, points, tree, projected_points, ids, ranks, rs.data(), shared);
930 void projectPointGlobal(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree, std::array<double,3> *projected_points,
long *ids,
int *ranks,
double *r,
bool shared )
933 for (
int ip = 0; ip < nP; ip++){
934 ids[ip] = bitpit::Cell::NULL_ID;
936 r[ip] = std::max(r[ip], tree->getPatch().getTol());
939 bool checkEmptyList = (nP == 0);
940 MPI_Allreduce(MPI_IN_PLACE, &checkEmptyList, 1, MPI_C_BOOL, MPI_LAND, tree->getPatch().getCommunicator());
942 std::vector<darray3E> workpoints(points, points+nP);
943 std::vector<long> workids(ids, ids+nP);
944 std::vector<int> workranks(ranks, ranks+nP);
945 std::vector<double> workradius(r, r+nP);
946 std::unordered_map<std::size_t,std::size_t> mapPosIndex;
947 for(std::size_t i=0; i<std::size_t(nP); ++i){
950 std::vector<darray3E> normals(nP), workNormals(nP);
951 std::vector<double> dist(nP, std::numeric_limits<double>::max()), workDist(nP);
957 while (!checkEmptyList && kiter < kmax){
959 signedGlobalDistance(workpoints.size(), workpoints.data(), tree, workids.data(), workranks.data(), workNormals.data(), workDist.data(), workradius.data(), shared);
962 std::vector<std::array<double,3>> failedPoints;
963 std::vector<double> failedRadii;
964 std::unordered_map<std::size_t, std::size_t> failedPosIndex;
965 failedPoints.reserve(workpoints.size());
966 failedRadii.reserve(workpoints.size());
968 for(
long & val : workids){
969 if(val == bitpit::Cell::NULL_ID){
970 failedPoints.push_back(workpoints[count]);
971 failedPosIndex[failedPoints.size()-1] = mapPosIndex[count];
972 failedRadii.push_back(workradius[count]);
974 dist[mapPosIndex[count]] = workDist[count];
975 normals[mapPosIndex[count]] = workNormals[count];
976 ids[mapPosIndex[count]] = workids[count];
977 ranks[mapPosIndex[count]] = workranks[count];
978 r[mapPosIndex[count]] = workradius[count];
982 workDist.resize(failedPoints.size());
983 workNormals.resize(failedPoints.size());
984 workids.resize(failedPoints.size());
985 workranks.resize(failedPoints.size());
987 std::swap(failedPoints, workpoints);
988 std::swap(failedPosIndex, mapPosIndex);
989 std::swap(failedRadii, workradius);
992 checkEmptyList = workpoints.empty();
993 MPI_Allreduce(MPI_IN_PLACE, &checkEmptyList, 1, MPI_C_BOOL, MPI_LAND, tree->getPatch().getCommunicator());
997 std::vector<double> temp(workradius.size(), std::numeric_limits<double>::max());
998 std::swap(temp, workradius);
1006 for (
int ip = 0; ip < nP; ip++){
1007 projected_points[ip] = points[ip] - dist[ip] * normals[ip];
1021 void locatePointOnGlobalPatch(
int nP,
const std::array<double,3> *points,
const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks,
bool shared)
1023 if(!
dynamic_cast<const bitpit::SurfUnstructured*
>(&(tree->getPatch()))){
1024 throw std::runtime_error(
"Invalid use of skdTreeUtils::locatePointOnPatch method: a non surface patch or void patch was detected.");
1026 const bitpit::SurfUnstructured & spatch =
static_cast<const bitpit::SurfUnstructured&
>(tree->getPatch());
1029 for (
int ip = 0; ip < nP; ip++){
1030 ids[ip] = bitpit::Cell::NULL_ID;
1032 std::vector<double> distances(nP, std::numeric_limits<double>::max());
1035 std::vector<long> cellIds(nP, bitpit::Cell::NULL_ID);
1036 std::vector<int> cellRanks(nP, -1);
1039 findSharedPointClosestGlobalCell(nP, points, tree, cellIds.data(), ranks, distances.data());
1042 static_cast<const bitpit::SurfaceSkdTree*
>(tree)->findPointClosestGlobalCell(nP, points, cellIds.data(), ranks, distances.data());
1045 int myrank = spatch.getRank();
1048 std::map<int,std::vector<long>> ask_to_rank;
1049 std::map<int,std::vector<std::array<double,3>>> point_to_rank;
1050 std::map<int,std::vector<int>> point_index_received_from_rank;
1053 for (
int ip = 0; ip < nP; ip++){
1055 const std::array<double,3> & point = points[ip];
1056 const long & cellId = cellIds[ip];
1057 const int & cellRank = ranks[ip];
1060 if (cellRank == myrank){
1075 ask_to_rank[cellRank].push_back(cellId);
1078 point_to_rank[cellRank].push_back(point);
1081 point_index_received_from_rank[cellRank].push_back(ip);
1089 int nProcessors = spatch.getProcessorCount();
1091 if (nProcessors > 1 && spatch.isPartitioned()){
1095 MPI_Allreduce(MPI_IN_PLACE, ids, nP, MPI_LONG, MPI_MAX, tree->getPatch().getCommunicator());
1100 std::vector<int> n_send_to_rank(nProcessors, 0);
1101 for (
int irank = 0; irank < nProcessors; irank++){
1102 int n_ask_to_current_rank = ask_to_rank[irank].size();
1103 MPI_Gather(&n_ask_to_current_rank, 1, MPI_INT, n_send_to_rank.data(), 1, MPI_INT, irank, tree->getPatch().getCommunicator());
1107 std::map<int,std::vector<long>> send_to_rank;
1108 std::map<int,std::vector<std::array<double,3>>> point_from_rank;
1109 for (
int irank = 0; irank < nProcessors; irank++){
1110 send_to_rank[irank].resize(n_send_to_rank[irank], bitpit::Cell::NULL_ID);
1111 point_from_rank[irank].resize(n_send_to_rank[irank], std::array<double,3>({{0.,0.,0.}}));
1115 for (
int irank = 0; irank < nProcessors; irank++){
1116 if (myrank == irank){
1117 for (
int jrank = 0; jrank < nProcessors; jrank++){
1118 if (jrank != irank){
1119 int n_send_to_current_rank = n_send_to_rank[jrank];
1120 MPI_Recv(send_to_rank[jrank].data(), n_send_to_current_rank, MPI_LONG, jrank, 100, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
1121 MPI_Recv(point_from_rank[jrank].data(), n_send_to_current_rank*3, MPI_DOUBLE, jrank, 101, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
1125 int n_ask_to_current_rank = ask_to_rank[irank].size();
1126 MPI_Send(ask_to_rank[irank].data(), n_ask_to_current_rank, MPI_LONG, irank, 100, tree->getPatch().getCommunicator());
1127 MPI_Send(point_to_rank[irank].data(), n_ask_to_current_rank*3, MPI_DOUBLE, irank, 101, tree->getPatch().getCommunicator());
1132 std::map<int, std::vector<int>> checkBelong_to_rank;
1133 for (
int irank = 0; irank < nProcessors; irank++){
1134 checkBelong_to_rank[irank].resize(n_send_to_rank[irank],
false);
1135 for (
int ip = 0; ip < n_send_to_rank[irank]; ip++){
1137 const std::array<double,3> & point = point_from_rank[irank][ip];
1138 const long & cellId = send_to_rank[irank][ip];
1139 int & checkBelong = checkBelong_to_rank[irank][ip];
1147 std::map<int, std::vector<int>> checkBelong_from_rank;
1149 for (
int irank = 0; irank < nProcessors; irank++){
1150 if (myrank == irank){
1151 for (
int jrank = 0; jrank < nProcessors; jrank++){
1152 if (jrank != irank){
1153 int n_ask_to_current_rank = ask_to_rank[jrank].size();
1154 checkBelong_from_rank[jrank].resize(n_ask_to_current_rank);
1155 MPI_Recv(checkBelong_from_rank[jrank].data(), n_ask_to_current_rank, MPI_INT, jrank, 102, tree->getPatch().getCommunicator(), MPI_STATUS_IGNORE);
1158 for (
int ip = 0; ip < n_ask_to_current_rank; ip++){
1159 int point_index = point_index_received_from_rank[jrank][ip];
1160 long cellId = ask_to_rank[jrank][ip];
1162 if (
bool(checkBelong_from_rank[jrank][ip])) {
1163 ids[point_index] = cellId;
1170 int n_send_to_current_rank = n_send_to_rank[irank];
1171 MPI_Send(checkBelong_to_rank[irank].data(), n_send_to_current_rank, MPI_INT, irank, 102, tree->getPatch().getCommunicator());
1190 std::vector<long> selectByGlobalPatch(bitpit::PatchSkdTree *selection, bitpit::PatchSkdTree *target,
double tol){
1192 if (!selection->getPatch().isPartitioned()){
1193 throw std::runtime_error(
"Error: selection PatchSkdTree communicators not set in selectByGlobalPatch");
1195 if (!target->getPatch().isPartitioned()){
1196 throw std::runtime_error(
"Error: target PatchSkdTree communicators not set in selectByGlobalPatch");
1205 int nprocs = selection->getPatch().getProcessorCount();
1206 int myRank = selection->getPatch().getRank();
1207 int nleafs = selection->getLeafCount();
1208 int nnodess = selection->getNodeCount();
1209 std::unordered_map<int, std::vector<const bitpit::SkdNode*>> rankLeafSelection;
1210 for (
int irank = 0; irank < nprocs; irank++){
1211 std::vector<const bitpit::SkdNode*> leafSelection(nleafs);
1213 for (
int i=0; i<nnodess; i++){
1214 if (selection->getNode(i).isLeaf()){
1215 if (bitpit::CGElem::intersectBoxBox(selection->getNode(i).getBoxMin(),
1216 selection->getNode(i).getBoxMax(),
1217 target->getPartitionBox(irank).getBoxMin(),
1218 target->getPartitionBox(irank).getBoxMax(),
1221 leafSelection[count] = &(selection->getNode(i));
1226 leafSelection.resize(count);
1227 rankLeafSelection[irank].swap(leafSelection);
1232 std::vector<bitpit::SkdBox> leafSelectionBoxes;
1236 std::vector<int> nLeafSend(nprocs, 0);
1237 std::vector<int> nLeafRecv(nprocs, 0);
1238 for (
int irank = 0; irank < nprocs; irank++){
1239 nLeafSend[irank] = rankLeafSelection[irank].size();
1242 for (
int irank = 0; irank < nprocs; irank++){
1244 int * recvbuff = &nLeafRecv[irank];
1245 MPI_Scatter(nLeafSend.data(), 1, MPI_INT, recvbuff, 1, MPI_INT, irank, selection->getPatch().getCommunicator());
1249 int nGlobalReceived = 0;
1250 for (
int val : nLeafRecv){
1251 nGlobalReceived += val;
1254 if (nGlobalReceived > 0){
1255 leafSelectionBoxes.reserve(nGlobalReceived);
1261 std::vector<double> recvBoxes;
1262 for (
int irank = 0; irank < nprocs; irank++){
1264 std::vector<double> sendBoxes;
1266 std::vector<int> recvDispls(nprocs, 0);
1267 std::vector<int> nRecvDataPerProc(nprocs, 0);
1268 if (irank == myRank){
1270 nRecvData = 6 * nGlobalReceived;
1271 recvBoxes.resize(nRecvData, std::numeric_limits<double>::max());
1273 nRecvDataPerProc[0] = nLeafRecv[0] * 6;
1274 for (
int jrank = 1; jrank < nprocs; jrank++){
1275 recvDispls[jrank] = recvDispls[jrank - 1] + nLeafRecv[jrank - 1] * 6;
1276 nRecvDataPerProc[jrank] = nLeafRecv[jrank] * 6;
1280 nSendData = 6 * nLeafSend[irank];
1281 sendBoxes.reserve(nSendData);
1282 for (
const bitpit::SkdNode* selectNode : rankLeafSelection[irank]){
1283 for (
const double val : selectNode->getBoxMin()){
1284 sendBoxes.push_back(val);
1286 for (
const double val : selectNode->getBoxMax()){
1287 sendBoxes.push_back(val);
1292 MPI_Gatherv(sendBoxes.data(), nSendData, MPI_DOUBLE, recvBoxes.data(), nRecvDataPerProc.data(), recvDispls.data(), MPI_DOUBLE, irank, selection->getPatch().getCommunicator());
1297 std::vector<double>::iterator itBox = recvBoxes.begin();
1298 for (
int ibox = 0; ibox < nGlobalReceived; ibox++){
1299 std::array<double, 3> minPoint;
1300 minPoint[0] = *(itBox++);
1301 minPoint[1] = *(itBox++);
1302 minPoint[2] = *(itBox++);
1303 std::array<double, 3> maxPoint;
1304 maxPoint[0] = *(itBox++);
1305 maxPoint[1] = *(itBox++);
1306 maxPoint[2] = *(itBox++);
1307 leafSelectionBoxes.emplace_back(bitpit::SkdBox(minPoint, maxPoint));
1310 std::vector<long> extracted;
1331 void extractTarget(bitpit::PatchSkdTree *target,
const std::vector<bitpit::SkdBox> &leafSelectionBoxes, std::vector<long> &extracted,
double tol)
1334 if(leafSelectionBoxes.empty())
return;
1335 std::size_t rootId = 0;
1338 std::unordered_set<std::size_t> candidates;
1341 for (
const bitpit::SkdBox & selectionBox : leafSelectionBoxes){
1344 std::queue<std::size_t> nodeStack;
1345 nodeStack.push(rootId);
1350 while(!nodeStack.empty()){
1352 std::size_t nodeId = nodeStack.front();
1354 const bitpit::SkdNode & node = target->getNode(nodeId);
1357 for (
int i = bitpit::SkdNode::CHILD_BEGIN; i != bitpit::SkdNode::CHILD_END; ++i) {
1358 bitpit::SkdNode::ChildLocation childLocation =
static_cast<bitpit::SkdNode::ChildLocation
>(i);
1359 std::size_t childId = node.getChildId(childLocation);
1360 if (childId != bitpit::SkdNode::NULL_ID) {
1362 if (bitpit::CGElem::intersectBoxBox(selectionBox.getBoxMin(), selectionBox.getBoxMax(),
1363 target->getNode(childId).getBoxMin(), target->getNode(childId).getBoxMax(),3, tol)){
1364 nodeStack.push(childId);
1369 candidates.insert(nodeId);
1376 std::unordered_set<long> cellExtracted;
1377 for(
long nodeId : candidates){
1378 const bitpit::SkdNode & node = target->getNode(nodeId);
1379 std::vector<long> cellids = node.getCells();
1380 cellExtracted.insert(cellids.begin(), cellids.end());
1383 extracted.insert(extracted.end(), cellExtracted.begin(), cellExtracted.end());
1407 long findSharedPointClosestGlobalCell(
int nPoints,
const std::array<double, 3> *points,
const bitpit::PatchSkdTree *tree,
1408 long *ids,
int *ranks,
double *distances,
double r)
1410 std::vector<double> rs(nPoints, r);
1411 return findSharedPointClosestGlobalCell(nPoints, points, tree, ids, ranks, distances, rs.data());
1434 long findSharedPointClosestGlobalCell(
int nPoints,
const std::array<double, 3> *points,
const bitpit::PatchSkdTree *tree,
1435 long *ids,
int *ranks,
double *distances,
double *r)
1440 long nDistanceEvaluations = 0;
1441 std::vector<double> maxDistances(nPoints, std::numeric_limits<double>::max());
1444 const bitpit::PatchKernel &patch = tree->getPatch();
1445 if (!patch.isPartitioned()) {
1446 for (
int i = 0; i < nPoints; ++i) {
1448 nDistanceEvaluations +=
findPointClosestCell(points[i], tree, maxDistances[i], ids + i, distances + i);
1451 ranks[i] = patch.getRank();
1455 return nDistanceEvaluations;
1461 if (!tree->getPatch().isPartitioned()){
1462 throw std::runtime_error (
"There is no communicator set for the patch.");
1465 int nprocs = tree->getPatch().getProcessorCount();
1468 std::vector<bitpit::SkdGlobalCellDistance> globalCellDistances(nPoints);
1471 for (
int i = 0; i < nPoints; ++i) {
1473 const std::array<double, 3> &point = points[i];
1478 double pointMaxDistance = maxDistances[i];
1479 for (
int rank = 0; rank < nprocs; ++rank) {
1480 pointMaxDistance = std::min(tree->getPartitionBox(rank).evalPointMaxDistance(point), pointMaxDistance);
1484 bitpit::SkdGlobalCellDistance &globalCellDistance = globalCellDistances[i];
1485 int &cellRank = globalCellDistance.getRank();
1486 long &cellId = globalCellDistance.getId();
1487 double &cellDistance = globalCellDistance.getDistance();
1490 bool interiorOnly =
true;
1491 nDistanceEvaluations +=
findPointClosestCell(point, tree, pointMaxDistance, interiorOnly, &cellId, &cellDistance);
1494 if (cellId != bitpit::Cell::NULL_ID) {
1495 cellRank = patch.getCellRank(cellId);
1502 MPI_Datatype globalCellDistanceDatatype = bitpit::SkdGlobalCellDistance::getMPIDatatype();
1503 MPI_Op globalCellDistanceMinOp = bitpit::SkdGlobalCellDistance::getMPIMinOperation();
1504 bitpit::SkdGlobalCellDistance *globalCellDistance = globalCellDistances.data();
1505 for (
int irank = 0; irank < nprocs; irank++){
1506 MPI_Allreduce(MPI_IN_PLACE, globalCellDistance, nPoints, globalCellDistanceDatatype, globalCellDistanceMinOp, tree->getPatch().getCommunicator());
1510 for (
int i = 0; i < nPoints; ++i) {
1511 int globalIndex = i;
1512 bitpit::SkdGlobalCellDistance &globalCellDistance = globalCellDistances[globalIndex];
1513 globalCellDistance.exportData(ranks + i, ids + i, distances + i);
1516 return nDistanceEvaluations;
1565 double maxDistance,
bool interiorOnly,
long *
id,
double *
distance)
1569 *
id = bitpit::Cell::NULL_ID;
1574 std::size_t rootId = 0;
1575 const bitpit::SkdNode &root = tree->getNode(rootId);
1576 *
distance = std::min(root.evalPointMaxDistance(point), maxDistance);
1581 std::vector<std::size_t> candidateIds;
1582 std::vector<double> candidateMinDistances;
1584 std::vector<std::size_t> nodeStack;
1585 nodeStack.push_back(rootId);
1586 while (!nodeStack.empty()) {
1587 std::size_t nodeId = nodeStack.back();
1588 const bitpit::SkdNode &node = tree->getNode(nodeId);
1589 nodeStack.pop_back();
1593 double nodeMinDistance = node.evalPointMinDistance(point);
1602 double nodeMaxDistance = node.evalPointMaxDistance(point);
1608 for (
int i = bitpit::SkdNode::CHILD_BEGIN; i != bitpit::SkdNode::CHILD_END; ++i) {
1609 bitpit::SkdNode::ChildLocation childLocation =
static_cast<bitpit::SkdNode::ChildLocation
>(i);
1610 std::size_t childId = node.getChildId(childLocation);
1611 if (childId != bitpit::SkdNode::NULL_ID) {
1613 nodeStack.push_back(childId);
1618 candidateIds.push_back(nodeId);
1619 candidateMinDistances.push_back(nodeMinDistance);
1624 long nDistanceEvaluations = 0;
1625 for (std::size_t k = 0; k < candidateIds.size(); ++k) {
1628 if (candidateMinDistances[k] > *
distance) {
1633 std::size_t nodeId = candidateIds[k];
1634 const bitpit::SkdNode &node = tree->getNode(nodeId);
1636 node.updatePointClosestCell(point, interiorOnly,
id,
distance);
1637 ++nDistanceEvaluations;
1642 if (*
id == bitpit::Cell::NULL_ID) {
1643 *
distance = std::numeric_limits<double>::max();
1646 return nDistanceEvaluations;
1649 #if MIMMO_ENABLE_MPI
1664 long findPointClosestGlobalCell(
int nPoints,
const std::array<double, 3> *points,
1665 const bitpit::PatchSkdTree *tree,
long *ids,
int *ranks,
double *distances)
1668 long nDistanceEvaluations = 0;
1670 std::vector<double> maxDistances(nPoints, std::numeric_limits<double>::max());
1673 const bitpit::PatchKernel &patch = tree->getPatch();
1674 if (!patch.isPartitioned()) {
1675 for (
int i = 0; i < nPoints; ++i) {
1677 nDistanceEvaluations +=
findPointClosestCell(points[i], tree, maxDistances[i], ids + i, distances + i);
1680 ranks[i] = patch.getRank();
1684 return nDistanceEvaluations;
1690 if (!tree->getPatch().isPartitioned()){
1691 throw std::runtime_error (
"There is no communicator set for the patch.");
1694 MPI_Comm communicator = tree->getPatch().getCommunicator();
1695 int nprocs = tree->getPatch().getProcessorCount();
1696 int myRank = tree->getPatch().getRank();
1699 std::vector<int> pointsCount(nprocs);
1700 MPI_Allgather(&nPoints, 1, MPI_INT, pointsCount.data(), 1, MPI_INT, communicator);
1703 std::vector<int> globalPointsDispls(nprocs, 0);
1704 std::vector<int> globalPointsOffsets(nprocs, 0);
1705 std::vector<int> globalPointsDataCount(nprocs, 0);
1707 globalPointsDataCount[0] = 3 * pointsCount[0];
1708 for (
int i = 1; i < nprocs; ++i) {
1709 globalPointsDispls[i] = globalPointsDispls[i - 1] + 3 * pointsCount[i - 1];
1710 globalPointsOffsets[i] = globalPointsOffsets[i - 1] + pointsCount[i - 1];
1711 globalPointsDataCount[i] = 3 * pointsCount[i];
1714 int nGlobalPoints = globalPointsDispls.back() + pointsCount.back();
1717 std::vector<std::array<double,3>> globalPoints(nGlobalPoints);
1718 int pointsDataCount = 3 * nPoints;
1719 MPI_Allgatherv(points, pointsDataCount, MPI_DOUBLE, globalPoints.data(),
1720 globalPointsDataCount.data(), globalPointsDispls.data(), MPI_DOUBLE, communicator);
1723 std::vector<double> globalMaxDistances(nGlobalPoints);
1724 MPI_Allgatherv(maxDistances.data(), nPoints, MPI_DOUBLE, globalMaxDistances.data(),
1725 pointsCount.data(), globalPointsOffsets.data(), MPI_DOUBLE, communicator);
1728 std::vector<bitpit::SkdGlobalCellDistance> globalCellDistances(nGlobalPoints);
1731 for (
int i = 0; i < nGlobalPoints; ++i) {
1733 const std::array<double, 3> &point = globalPoints[i];
1738 double pointMaxDistance = globalMaxDistances[i];
1739 for (
int rank = 0; rank < nprocs; ++rank) {
1740 pointMaxDistance = std::min(tree->getPartitionBox(rank).evalPointMaxDistance(point), pointMaxDistance);
1744 bitpit::SkdGlobalCellDistance &globalCellDistance = globalCellDistances[i];
1745 int &cellRank = globalCellDistance.getRank();
1746 long &cellId = globalCellDistance.getId();
1747 double &cellDistance = globalCellDistance.getDistance();
1750 bool interiorOnly =
true;
1751 nDistanceEvaluations +=
findPointClosestCell(point, tree, pointMaxDistance, interiorOnly, &cellId, &cellDistance);
1754 if (cellId != bitpit::Cell::NULL_ID) {
1755 cellRank = patch.getCellRank(cellId);
1760 MPI_Datatype globalCellDistanceDatatype = bitpit::SkdGlobalCellDistance::getMPIDatatype();
1761 MPI_Op globalCellDistanceMinOp = bitpit::SkdGlobalCellDistance::getMPIMinOperation();
1762 for (
int rank = 0; rank < nprocs; ++rank) {
1763 bitpit::SkdGlobalCellDistance *globalCellDistance = globalCellDistances.data() + globalPointsOffsets[rank];
1764 if (myRank == rank) {
1765 MPI_Reduce(MPI_IN_PLACE, globalCellDistance, pointsCount[rank], globalCellDistanceDatatype, globalCellDistanceMinOp, rank, communicator);
1767 MPI_Reduce(globalCellDistance, globalCellDistance, pointsCount[rank], globalCellDistanceDatatype, globalCellDistanceMinOp, rank, communicator);
1772 for (
int i = 0; i < nPoints; ++i) {
1773 int globalIndex = i + globalPointsOffsets[myRank];
1774 bitpit::SkdGlobalCellDistance &globalCellDistance = globalCellDistances[globalIndex];
1775 globalCellDistance.exportData(ranks + i, ids + i, distances + i);
1778 return nDistanceEvaluations;