38 return (ids[0] * nCells[1] + ids[1]) * nCells[2] + ids[2];
44 return (ids[0] * nCells[1] + ids[1]) * nCells[2] + ids[2];
62 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}}};
66 std::transform(neighbors2DIndex.
begin(), neighbors2DIndex.
end(), neighbors2D.begin(), [&nCells](
auto &v) { return zCurve(v, nCells); });
76 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}}};
79 std::transform(neighbors3DIndex.
begin(), neighbors3DIndex.
end(), neighbors3D.begin(), [&nCells](
auto &v) { return zCurve(v, nCells); });
96template <
typename ArrayType>
100 static_assert((neighborOffsets.size() == 26) || (neighborOffsets.size() == 8));
102 for (
auto off : neighborOffsets) {
111 VertexID neighborID = centerID + off;
113 if (neighborID >= 0 && neighborID <
static_cast<int>(vertices.
size())) {
114 auto &neighborVertex = vertices[neighborID];
115 auto ¢er = vertices[centerID];
116 if (!neighborVertex.isTagged() && (
computeSquaredDifference(center.rawCoords(), neighborVertex.rawCoords()) < math::pow_int<2>(radius))) {
136 if (!v.isTagged() && !mesh->index().isAnyVertexInsideBox(v, clusterRadius)) {
152 std::transform(clusterCenters.begin(), clusterCenters.end(), clusterCenters.begin(), [&](
auto &v) {
154 auto closestCenter = mesh->index().getClosestVertex(v.getCoords()).index;
155 return mesh::Vertex{mesh->vertex(closestCenter).getCoords(), v.getID()};
181 auto neighborOffsets = zCurveNeighborOffsets<dim>(nCells);
182 static_assert((neighborOffsets.size() == 8 && dim == 2) || (neighborOffsets.size() == 26 && dim == 3));
187 for (
auto &v : centers) {
189 auto ids = getNeighborsWithinSphere(centers, v.getID(), threshold, neighborOffsets);
205void removeTaggedVertices(Vertices &container)
207 container.erase(
std::remove_if(container.begin(), container.end(), [](
auto &v) { return v.isTagged(); }), container.end());
232 const auto bbCenter = bb.
center();
233 randomSamples.
emplace_back(inMesh->index().getClosestVertex(bbCenter).index);
245 for (
int d = 0; d < inMesh->getDimensions(); ++d) {
246 auto sample = bbCenter;
249 randomSamples.
emplace_back(inMesh->index().getClosestVertex(sample).index);
252 randomSamples.
emplace_back(inMesh->index().getClosestVertex(sample).index);
257 for (
auto s : randomSamples) {
259 auto kNearestVertexIDs = inMesh->index().getClosestVertices(inMesh->vertex(s).getCoords(), verticesPerCluster);
262 std::transform(kNearestVertexIDs.begin(), kNearestVertexIDs.end(), squaredRadius.
begin(), [&inMesh, s](
auto i) {
263 return computeSquaredDifference(inMesh->vertex(i).rawCoords(), inMesh->vertex(s).rawCoords());
271 PRECICE_ASSERT(sampledClusterRadii.
size() % 2 != 0,
"Median calculation is only valid for odd number of elements.");
273 unsigned int middle = sampledClusterRadii.
size() / 2;
275 double clusterRadius = sampledClusterRadii[middle];
277 return clusterRadius;
303 double relativeOverlap,
unsigned int verticesPerCluster,
304 bool projectClustersToInput)
310 PRECICE_ASSERT(inMesh->getDimensions() == outMesh->getDimensions());
313 if (inMesh->empty() || (outMesh->empty() && !outMesh->isJustInTime())) {
322 const bool startGridAtEdge = projectClustersToInput;
325 PRECICE_DEBUG(
"Vertices per cluster: {}", verticesPerCluster);
352 if (inMesh->nVertices() < verticesPerCluster * 2) {
355 PRECICE_WARN(
"Determining a cluster radius failed. This is most likely a result of a coupling mesh consisting of just a single vertex. Setting the cluster radius to 1.");
362 auto globalBB = localBB;
372 const int inDim = inMesh->getDimensions();
373 const double maximumCenterDistance =
std::sqrt(4. / inDim) * clusterRadius * (1 - relativeOverlap);
378 for (
int d = 0; d < globalBB.getDimension(); ++d)
379 nClustersGlobal[d] =
std::ceil(
std::max(1., globalBB.getEdgeLength(d) / maximumCenterDistance));
390 for (
unsigned int d = 0; d < distances.
size(); ++d) {
393 distances[d] = globalBB.getEdgeLength(d) / (nClustersGlobal[d]);
394 start[d] = globalBB.minCorner()(d);
399 if (startGridAtEdge) {
400 for (
int d = 0; d < inDim; ++d) {
401 if (globalBB.getEdgeLength(d) > math::NUMERICAL_ZERO_DIFFERENCE) {
402 nClustersGlobal[d] += 1;
411 PRECICE_DEBUG(
"Global cluster distribution: {}", nClustersGlobal);
413 PRECICE_DEBUG(
"Global number of total clusters (tentative): {}", nTotalClustersGlobal);
420 for (
unsigned int d = 0; d < start.
size(); ++d) {
422 if (distances[d] > 0) {
423 start[d] +=
std::ceil(((localBB.
minCorner()(d) - start[d]) / distances[d]) - math::NUMERICAL_ZERO_DIFFERENCE) * distances[d];
425 nClustersLocal[d] = 1 +
std::floor(((localBB.
maxCorner()(d) - start[d]) / distances[d]) + math::NUMERICAL_ZERO_DIFFERENCE);
433 PRECICE_DEBUG(
"Local cluster distribution: {}", nClustersLocal);
434 PRECICE_DEBUG(
"Local number of total clusters (tentative): {}", nTotalClustersLocal);
441 centerCoords[0] = start[0];
442 for (
unsigned int x = 0; x < nClustersLocal[0]; ++x, centerCoords[0] += distances[0]) {
443 centerCoords[1] = start[1];
444 for (
unsigned int y = 0; y < nClustersLocal[1]; ++y, centerCoords[1] += distances[1]) {
451 centerCoords[0] = start[0];
452 for (
unsigned int x = 0; x < nClustersLocal[0]; ++x, centerCoords[0] += distances[0]) {
453 centerCoords[1] = start[1];
454 for (
unsigned int y = 0; y < nClustersLocal[1]; ++y, centerCoords[1] += distances[1]) {
455 centerCoords[2] = start[2];
456 for (
unsigned int z = 0; z < nClustersLocal[2]; ++z, centerCoords[2] += distances[2]) {
468 tagEmptyClusters(centers, clusterRadius, inMesh);
469 if (!outMesh->isJustInTime()) {
470 tagEmptyClusters(centers, clusterRadius, outMesh);
472 PRECICE_DEBUG(
"Number of non-tagged centers after empty clusters were filtered: {}",
std::count_if(centers.
begin(), centers.
end(), [](
auto &v) { return !v.isTagged(); }));
475 if (projectClustersToInput) {
476 projectClusterCentersToinputMesh(centers, inMesh);
479 PRECICE_DEBUG(
"Tagging duplicates using the threshold value {} for the regular distances {}", duplicateThreshold, distances);
484 if (nClustersLocal[2] == 1) {
485 tagDuplicateCenters<2>(centers, nClustersLocal, duplicateThreshold);
487 tagDuplicateCenters<3>(centers, nClustersLocal, duplicateThreshold);
492 if (!outMesh->isJustInTime()) {
493 tagEmptyClusters(centers, clusterRadius, outMesh);
500 removeTaggedVertices(centers);
504 return {clusterRadius, centers};