From 24c0b30d48fc4722aa6d40ac4d0d163d15cf14f9 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Tue, 15 Mar 2022 21:38:49 +0100 Subject: [PATCH] ENH: mergePoints and patch gatherAndMerge improvements (#2402) - when writing surface formats (eg, vtk, ensight etc) the sampled surfaces merge the faces/points originating from different processors into a single surface (ie, patch gatherAndMerge). Previous versions of mergePoints simply merged all points possible, which proves to be rather slow for larger meshes. This has now been modified to only consider boundary points, which reduces the number of points to consider. As part of this change, the reference point is now always equivalent to the min of the bounding box, which reduces the number of search loops. The merged points retain their original order. - inplaceMergePoints version to simplify use and improve code robustness and efficiency. ENH: make PrimitivePatch::boundaryPoints() less costly - if edge addressing does not already exist, it will now simply walk the local face edges directly to define the boundary points. This avoids a rather large overhead of the full faceFaces, edgeFaces, faceEdges addressing. This operation is now more important since it is used in the revised patch gatherAndMerge. ENH: topological merge for mesh-based surfaces in surfaceFieldValue --- .../manipulation/polyDualMesh/meshDualiser.C | 4 +- src/OpenFOAM/meshes/meshTools/mergePoints.C | 515 ++++++++++++++---- src/OpenFOAM/meshes/meshTools/mergePoints.H | 217 +++++++- .../polyMesh/globalMeshData/globalMeshData.C | 12 +- .../primitiveMesh/PatchTools/PatchTools.H | 15 +- .../PatchTools/PatchToolsGatherAndMerge.C | 62 ++- .../PrimitivePatch/PrimitivePatch.H | 8 +- .../PrimitivePatch/PrimitivePatchAddressing.C | 4 +- .../PrimitivePatch/PrimitivePatchBdryPoints.C | 77 ++- src/dynamicMesh/polyMeshAdder/polyMeshAdder.C | 6 +- .../surfaceFieldValue/surfaceFieldValue.C | 26 +- .../snappyHexMeshDriver/snappyLayerDriver.C | 4 +- .../snappyHexMeshDriver/snappySnapDriver.C | 2 +- .../advancingFrontAMIParallelOps.C | 13 +- src/meshTools/edgeMesh/edgeMesh.C | 15 +- .../extendedEdgeMesh/extendedEdgeMesh.C | 2 +- .../surfaceIntersection/surfaceIntersection.C | 12 +- .../triSurfaceTools/triSurfaceTools.C | 17 +- .../distributedTriSurfaceMesh.C | 6 +- .../meshToMesh/meshToMeshParallelOps.C | 17 +- .../sampledSet/patchEdge/patchEdgeSet.C | 9 +- .../surface/isoSurface/isoSurfaceCell.C | 43 +- .../surface/isoSurface/isoSurfacePoint.C | 6 +- src/surfMesh/MeshedSurface/MeshedSurface.C | 17 +- src/surfMesh/surfaceFormats/tri/TRIReader.C | 1 + src/surfMesh/triSurface/triSurfaceStitch.C | 19 +- 26 files changed, 833 insertions(+), 296 deletions(-) diff --git a/applications/utilities/mesh/manipulation/polyDualMesh/meshDualiser.C b/applications/utilities/mesh/manipulation/polyDualMesh/meshDualiser.C index c512857b76..5fcf5d2f89 100644 --- a/applications/utilities/mesh/manipulation/polyDualMesh/meshDualiser.C +++ b/applications/utilities/mesh/manipulation/polyDualMesh/meshDualiser.C @@ -55,7 +55,7 @@ void Foam::meshDualiser::checkPolyTopoChange(const polyTopoChange& meshMod) } labelList oldToNew; - label nUnique = mergePoints + label nUnique = Foam::mergePoints ( points, 1e-6, @@ -223,7 +223,7 @@ Foam::label Foam::meshDualiser::addInternalFace pointField facePoints(meshMod.points(), newFace); labelList oldToNew; - label nUnique = mergePoints + label nUnique = Foam::mergePoints ( facePoints, 1e-6, diff --git a/src/OpenFOAM/meshes/meshTools/mergePoints.C b/src/OpenFOAM/meshes/meshTools/mergePoints.C index b5d6049755..56746484a8 100644 --- a/src/OpenFOAM/meshes/meshTools/mergePoints.C +++ b/src/OpenFOAM/meshes/meshTools/mergePoints.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2017-2019 OpenCFD Ltd. + Copyright (C) 2017-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,49 +26,47 @@ License \*---------------------------------------------------------------------------*/ -#include "ListOps.H" -#include "point.H" -#include "Field.H" +#include "ListOps.H" // sortedOrder, ListOps::identity -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Implementation * * * * * * * * * * * * * * // -template -Foam::label Foam::mergePoints +template +Foam::label Foam::Detail::mergePoints ( const PointList& points, + const IndexerOp& indexer, + const label nSubPoints, + labelList& pointToUnique, + labelList& uniquePoints, const scalar mergeTol, - const bool verbose, - labelList& pointMap, - typename PointList::const_reference origin + const bool verbose ) { - typedef typename PointList::value_type point_type; + const label nTotPoints = points.size(); - const label nPoints = points.size(); - - // Create an old to new point mapping array - pointMap.resize_nocopy(nPoints); - pointMap = -1; - - if (!nPoints) + if (!nTotPoints || !nSubPoints) { - return 0; + // Nothing to do + pointToUnique = identity(nTotPoints); + uniquePoints = pointToUnique; + return 0; // No points removed } - point_type compareOrigin = origin; - if (origin == point_type::max) + // Properly size for old to new mapping array + pointToUnique.resize_nocopy(nTotPoints); + + + // Use the boundBox minimum as the reference point. This + // stretches distances with fewer collisions than a mid-point + // reference would. + + auto comparePoint(points[indexer(0)]); + for (label pointi = 1; pointi < nSubPoints; ++pointi) { - // Use average of input points to define a comparison origin. - // Same as sum(points)/nPoints, but handles different list types - compareOrigin = points[0]; - for (label pointi=1; pointi < nPoints; ++pointi) - { - compareOrigin += points[pointi]; - } - compareOrigin /= nPoints; + comparePoint = min(comparePoint, points[indexer(pointi)]); } - // We're comparing distance squared to origin first. + // We're comparing distance squared to reference point first. // Say if starting from two close points: // x, y, z // x+mergeTol, y+mergeTol, z+mergeTol @@ -77,156 +75,445 @@ Foam::label Foam::mergePoints // x^2+y^2+z^2 + 2*mergeTol*(x+z+y) + mergeTol^2*... // so the difference will be 2*mergeTol*(x+y+z) - const scalar mergeTolSqr = Foam::sqr(mergeTol); + const scalar mergeTolSqr(magSqr(mergeTol)); - // Sort points by magSqr - List magSqrDist(nPoints); - forAll(points, pointi) + // Use magSqr distance for the points sort order + List sqrDist(nSubPoints); + for (label pointi = 0; pointi < nSubPoints; ++pointi) { - magSqrDist[pointi] = magSqr(points[pointi] - compareOrigin); + const auto& p = points[indexer(pointi)]; + + sqrDist[pointi] = + ( + // Use scalar precision + magSqr(scalar(p.x() - comparePoint.x())) + + magSqr(scalar(p.y() - comparePoint.y())) + + magSqr(scalar(p.z() - comparePoint.z())) + ); } - labelList order(Foam::sortedOrder(magSqrDist)); + labelList order(Foam::sortedOrder(sqrDist)); - - Field sortedTol(nPoints); + List sortedTol(nSubPoints); forAll(order, sorti) { - const point_type& pt = points[order[sorti]]; + const auto& p = points[indexer(order[sorti])]; - // Use scalar precision sortedTol[sorti] = + ( 2*mergeTol* ( - mag(scalar(pt.x() - compareOrigin.x())) - + mag(scalar(pt.y() - compareOrigin.y())) - + mag(scalar(pt.z() - compareOrigin.z())) - ); + // Use scalar precision + mag(scalar(p.x() - comparePoint.x())) + + mag(scalar(p.y() - comparePoint.y())) + + mag(scalar(p.z() - comparePoint.z())) + ) + ); } - label newPointi = 0; - // Handle 0th point separately (is always unique) - label pointi = order[0]; - pointMap[pointi] = newPointi++; + // Bookkeeping parameters + // ~~~~~~~~~~~~~~~~~~~~~~ - /// if (verbose) - /// { - /// Pout<< "Foam::mergePoints : [0] Uniq point " << pointi << endl; - /// } + // Will only be working on a subset of the points + // Can use a slice of pointToUnique (full length not needed until later). + SubList