40 return (ids[0] * nCells[1] + ids[1]) * nCells[2] + ids[2];
46 return (ids[0] * nCells[1] + ids[1]) * nCells[2] + ids[2];
64 const std::array<std::array<int, 3>, 8> neighbors2DIndex = {{{-1, -1, 0}, {-1, 0, 0}, {-1, 1, 0}, {0, -1, 0}, {0, 1, 0}, {1, -1, 0}, {1, 0, 0}, {1, 1, 0}}};
68 std::transform(neighbors2DIndex.
begin(), neighbors2DIndex.
end(), neighbors2D.begin(), [&nCells](
auto &v) { return zCurve(v, nCells); });
78 const std::array<std::array<int, 3>, 26> neighbors3DIndex = {{{-1, -1, -1}, {-1, -1, 0}, {-1, -1, 1}, {-1, 0, 0}, {-1, 0, 1}, {-1, 0, -1}, {-1, 1, 0}, {-1, 1, 1}, {-1, 1, -1}, {0, -1, -1}, {0, -1, 0}, {0, -1, 1}, {0, 0, 1}, {0, 0, -1}, {0, 1, 0}, {0, 1, 1}, {0, 1, -1}, {1, -1, -1}, {1, -1, 0}, {1, -1, 1}, {1, 0, 0}, {1, 0, 1}, {1, 0, -1}, {1, 1, 0}, {1, 1, 1}, {1, 1, -1}}};
81 std::transform(neighbors3DIndex.
begin(), neighbors3DIndex.
end(), neighbors3D.begin(), [&nCells](
auto &v) { return zCurve(v, nCells); });
98template <
typename ArrayType>
102 static_assert((neighborOffsets.size() == 26) || (neighborOffsets.size() == 8));
104 for (
auto off : neighborOffsets) {
113 VertexID neighborID = centerID + off;
115 if (neighborID >= 0 && neighborID <
static_cast<int>(vertices.
size())) {
116 auto &neighborVertex = vertices[neighborID];
117 auto ¢er = vertices[centerID];
118 if (!neighborVertex.isTagged() && (
computeSquaredDifference(center.rawCoords(), neighborVertex.rawCoords()) < math::pow_int<2>(radius))) {
138 if (!v.isTagged() && !mesh->index().isAnyVertexInsideBox(v, clusterRadius)) {
154 std::transform(clusterCenters.begin(), clusterCenters.end(), clusterCenters.begin(), [&](
auto &v) {
156 auto closestCenter = mesh->index().getClosestVertex(v.getCoords()).index;
157 return mesh::Vertex{mesh->vertex(closestCenter).getCoords(), v.getID()};
183 auto neighborOffsets = zCurveNeighborOffsets<dim>(nCells);
184 static_assert((neighborOffsets.size() == 8 && dim == 2) || (neighborOffsets.size() == 26 && dim == 3));
189 for (
auto &v : centers) {
191 auto ids = getNeighborsWithinSphere(centers, v.getID(), threshold, neighborOffsets);
207void removeTaggedVertices(Vertices &container)
209 container.erase(
std::remove_if(container.begin(), container.end(), [](
auto &v) { return v.isTagged(); }), container.end());
234 const auto bbCenter = bb.
center();
235 randomSamples.
emplace_back(inMesh->index().getClosestVertex(bbCenter).index);
247 for (
int d = 0; d < inMesh->getDimensions(); ++d) {
248 auto sample = bbCenter;
251 randomSamples.
emplace_back(inMesh->index().getClosestVertex(sample).index);
254 randomSamples.
emplace_back(inMesh->index().getClosestVertex(sample).index);
259 for (
auto s : randomSamples) {
261 auto kNearestVertexIDs = inMesh->index().getClosestVertices(inMesh->vertex(s).getCoords(), verticesPerCluster);
264 std::transform(kNearestVertexIDs.begin(), kNearestVertexIDs.end(), squaredRadius.
begin(), [&inMesh, s](
auto i) {
265 return computeSquaredDifference(inMesh->vertex(i).rawCoords(), inMesh->vertex(s).rawCoords());
273 PRECICE_ASSERT(sampledClusterRadii.
size() % 2 != 0,
"Median calculation is only valid for odd number of elements.");
275 unsigned int middle = sampledClusterRadii.
size() / 2;
277 double clusterRadius = sampledClusterRadii[middle];
279 return clusterRadius;
305 double relativeOverlap,
unsigned int verticesPerCluster,
306 bool projectClustersToInput)
312 PRECICE_ASSERT(inMesh->getDimensions() == outMesh->getDimensions());
315 if (inMesh->nVertices() == 0 || outMesh->nVertices() == 0)
323 const bool startGridAtEdge = projectClustersToInput;
326 PRECICE_DEBUG(
"Vertices per cluster: {}", verticesPerCluster);
353 if (inMesh->nVertices() < verticesPerCluster * 2)
358 auto globalBB = localBB;
368 const int inDim = inMesh->getDimensions();
369 const double maximumCenterDistance =
std::sqrt(4. / inDim) * clusterRadius * (1 - relativeOverlap);
374 for (
int d = 0; d < globalBB.getDimension(); ++d)
375 nClustersGlobal[d] =
std::ceil(
std::max(1., globalBB.getEdgeLength(d) / maximumCenterDistance));
386 for (
unsigned int d = 0; d < distances.
size(); ++d) {
389 distances[d] = globalBB.getEdgeLength(d) / (nClustersGlobal[d]);
390 start[d] = globalBB.minCorner()(d);
395 if (startGridAtEdge) {
396 for (
int d = 0; d < inDim; ++d) {
398 nClustersGlobal[d] += 1;
407 PRECICE_DEBUG(
"Global cluster distribution: {}", nClustersGlobal);
409 PRECICE_DEBUG(
"Global number of total clusters (tentative): {}", nTotalClustersGlobal);
416 for (
unsigned int d = 0; d < start.
size(); ++d) {
418 if (distances[d] > 0) {
429 PRECICE_DEBUG(
"Local cluster distribution: {}", nClustersLocal);
430 PRECICE_DEBUG(
"Local number of total clusters (tentative): {}", nTotalClustersLocal);
437 centerCoords[0] = start[0];
438 for (
unsigned int x = 0; x < nClustersLocal[0]; ++x, centerCoords[0] += distances[0]) {
439 centerCoords[1] = start[1];
440 for (
unsigned int y = 0; y < nClustersLocal[1]; ++y, centerCoords[1] += distances[1]) {
447 centerCoords[0] = start[0];
448 for (
unsigned int x = 0; x < nClustersLocal[0]; ++x, centerCoords[0] += distances[0]) {
449 centerCoords[1] = start[1];
450 for (
unsigned int y = 0; y < nClustersLocal[1]; ++y, centerCoords[1] += distances[1]) {
451 centerCoords[2] = start[2];
452 for (
unsigned int z = 0; z < nClustersLocal[2]; ++z, centerCoords[2] += distances[2]) {
464 tagEmptyClusters(centers, clusterRadius, inMesh);
465 tagEmptyClusters(centers, clusterRadius, outMesh);
466 PRECICE_DEBUG(
"Number of non-tagged centers after empty clusters were filtered: {}",
std::count_if(centers.
begin(), centers.
end(), [](
auto &v) { return !v.isTagged(); }));
469 if (projectClustersToInput) {
470 projectClusterCentersToinputMesh(centers, inMesh);
473 PRECICE_DEBUG(
"Tagging duplicates using the threshold value {} for the regular distances {}", duplicateThreshold, distances);
478 if (nClustersLocal[2] == 1) {
479 tagDuplicateCenters<2>(centers, nClustersLocal, duplicateThreshold);
481 tagDuplicateCenters<3>(centers, nClustersLocal, duplicateThreshold);
486 tagEmptyClusters(centers, clusterRadius, outMesh);
492 removeTaggedVertices(centers);
496 return {clusterRadius, centers};