From fd8eebab13b3881f2ba20e9c58c8c0ae9dbc8b77 Mon Sep 17 00:00:00 2001 From: laurence <laurence> Date: Tue, 11 Dec 2012 17:22:06 +0000 Subject: [PATCH] ENH: Latest version of cvMesh. Squash of commits. --- .../utilities/mesh/generation/cvMesh/Allwmake | 3 +- .../mesh/generation/cvMesh/Make/options | 9 +- .../cellSizeAndAlignmentGrid/Make/files | 2 + .../cellSizeAndAlignmentGrid/Make/options | 40 + .../cellSizeAndAlignmentGrid.C | 711 +++++ .../cvMesh/checkCvMesh/meshQualityDict | 73 + .../DelaunayMesh/DelaunayMesh.C | 233 ++ .../DelaunayMesh/DelaunayMesh.H | 238 ++ .../DelaunayMesh/DelaunayMeshI.H | 119 + .../DelaunayMesh/DelaunayMeshIO.C | 406 +++ .../DelaunayMesh/DistributedDelaunayMesh.C | 932 ++++++ .../DelaunayMesh/DistributedDelaunayMesh.H | 207 ++ .../cvMesh/conformalVoronoiMesh/Make/files | 18 +- .../cvMesh/conformalVoronoiMesh/Make/options | 7 +- .../PrintTable/PrintTable.C | 241 ++ .../PrintTable/PrintTable.H | 137 + .../PrintTable/PrintTableI.H | 42 + .../backgroundMeshDecomposition.C | 725 ++--- .../backgroundMeshDecomposition.H | 70 +- .../backgroundMeshDecompositionI.H | 7 +- .../cellAspectRatioControl.C | 110 + .../cellAspectRatioControl.H | 115 + .../cellShapeControl/cellShapeControl.C | 920 ++++++ .../cellShapeControl/cellShapeControl.H | 212 ++ .../cellShapeControl/cellShapeControlI.H | 55 + .../cellShapeControlMesh.C | 760 +++++ .../cellShapeControlMesh.H | 168 ++ .../cellShapeControlMeshI.H | 68 + .../cellSizeAndAlignmentControl.C | 121 + .../cellSizeAndAlignmentControl.H | 166 + .../cellSizeAndAlignmentControls.C | 78 + .../cellSizeAndAlignmentControls.H | 110 + .../fileControl/fileControl.C | 236 ++ .../fileControl/fileControl.H | 134 + .../searchableSurfaceControl.C | 640 ++++ .../searchableSurfaceControl.H | 166 + .../cellSizeControlSurfaces.C | 452 ++- .../cellSizeControlSurfaces.H | 110 + .../cellSizeFunction/cellSizeFunction.C | 7 +- .../cellSizeFunction/cellSizeFunction.H | 14 +- .../automatic/automatic.C | 85 +- .../automatic/automatic.H | 5 + .../CGALTriangulation3DKernel.H | 62 + .../CGALTriangulation3Ddefs.H | 77 +- .../conformalVoronoiMesh.C | 1243 ++++---- .../conformalVoronoiMesh.H | 604 ++-- .../conformalVoronoiMeshCalcDualMesh.C | 2670 +++++++---------- .../conformalVoronoiMeshConformToSurface.C | 2417 ++++++--------- ...alVoronoiMeshFeaturePointSpecialisations.C | 116 +- .../conformalVoronoiMeshFeaturePoints.C | 999 +++--- .../conformalVoronoiMeshI.H | 253 +- .../conformalVoronoiMeshIO.C | 832 ++++- .../{ => indexedCell}/indexedCell.C | 48 +- .../{ => indexedCell}/indexedCell.H | 46 +- .../indexedCell/indexedCellChecks.C | 128 + .../indexedCell/indexedCellChecks.H | 77 + .../indexedCell/indexedCellEnum.C | 46 + .../indexedCell/indexedCellEnum.H | 80 + .../{ => indexedCell}/indexedCellI.H | 304 +- .../conformalVoronoiMesh/indexedVertex.C | 115 - .../indexedVertex/indexedVertex.C | 185 ++ .../{ => indexedVertex}/indexedVertex.H | 222 +- .../indexedVertex/indexedVertexEnum.C | 88 + .../indexedVertex/indexedVertexEnum.H | 95 + .../{ => indexedVertex}/indexedVertexI.H | 237 +- .../conformalVoronoiMesh/pointConversion.H | 99 + .../pointFeatureEdgesTypes.H | 48 +- .../conformationSurfaces.C | 8 +- .../conformationSurfaces.H | 3 - .../cvControls/cvControls.C | 346 +-- .../cvControls/cvControls.H | 216 +- .../cvControls/cvControlsI.H | 94 +- .../autoDensity/autoDensity.C | 8 +- .../bodyCentredCubic/bodyCentredCubic.C | 2 +- .../faceCentredCubic/faceCentredCubic.C | 2 +- .../initialPointsMethod/pointFile/pointFile.C | 2 +- .../uniformGrid/uniformGrid.C | 2 +- .../utilities/mesh/generation/cvMesh/cvMesh.C | 21 +- .../cvMesh/cvMeshBackgroundMesh/Make/options | 6 +- .../cvMeshBackgroundMesh.C | 17 +- .../mesh/generation/cvMesh/cvMeshDict | 42 +- wmake/rules/General/CGAL | 1 + 82 files changed, 14545 insertions(+), 6268 deletions(-) create mode 100644 applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/files create mode 100644 applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/options create mode 100644 applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/cellSizeAndAlignmentGrid.C create mode 100644 applications/utilities/mesh/generation/cvMesh/checkCvMesh/meshQualityDict create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshI.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshIO.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTableI.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControlI.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMeshI.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3DKernel.H rename applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/{ => indexedCell}/indexedCell.C (67%) rename applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/{ => indexedCell}/indexedCell.H (84%) create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.H create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.H rename applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/{ => indexedCell}/indexedCellI.H (51%) delete mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.C rename applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/{ => indexedVertex}/indexedVertex.H (57%) create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H rename applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/{ => indexedVertex}/indexedVertexI.H (56%) create mode 100644 applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointConversion.H diff --git a/applications/utilities/mesh/generation/cvMesh/Allwmake b/applications/utilities/mesh/generation/cvMesh/Allwmake index eb453138ce5..d88e8cee4af 100755 --- a/applications/utilities/mesh/generation/cvMesh/Allwmake +++ b/applications/utilities/mesh/generation/cvMesh/Allwmake @@ -4,7 +4,8 @@ set -x wmake libso conformalVoronoiMesh wmake -wmake cvMeshBackgroundMesh +#wmake cvMeshBackgroundMesh (cd cvMeshSurfaceSimplify && ./Allwmake) +wmake cellSizeAndAlignmentGrid # ----------------------------------------------------------------- end-of-file diff --git a/applications/utilities/mesh/generation/cvMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/Make/options index 27241b29656..9461fa3725d 100644 --- a/applications/utilities/mesh/generation/cvMesh/Make/options +++ b/applications/utilities/mesh/generation/cvMesh/Make/options @@ -2,7 +2,7 @@ EXE_DEBUG = -DFULLDEBUG -g -O0 EXE_FROUNDING_MATH = -frounding-math EXE_NDEBUG = -DNDEBUG -CGAL_EXACT = +CGAL_EXACT = /*-DCGAL_DONT_USE_LAZY_KERNEL*/ CGAL_INEXACT = -DCGAL_INEXACT include $(GENERAL_RULES)/CGAL @@ -19,7 +19,9 @@ EXE_INC = \ -I$(LIB_SRC)/edgeMesh/lnInclude \ -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/dynamicMesh/lnInclude \ - -I$(LIB_SRC)/triSurface/lnInclude + -I$(LIB_SRC)/triSurface/lnInclude \ + -I$(LIB_SRC)/sampling/lnInclude \ + -IvectorTools EXE_LIBS = \ $(CGAL_LIBS) \ @@ -32,4 +34,5 @@ EXE_LIBS = \ -ledgeMesh \ -lfileFormats \ -ltriSurface \ - -ldynamicMesh + -ldynamicMesh \ + -lsampling diff --git a/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/files b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/files new file mode 100644 index 00000000000..83b77fdc77e --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/files @@ -0,0 +1,2 @@ +cellSizeAndAlignmentGrid.C +EXE = $(FOAM_USER_APPBIN)/cellSizeAndAlignmentGrid diff --git a/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/options b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/options new file mode 100644 index 00000000000..31d0d80858f --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/Make/options @@ -0,0 +1,40 @@ +EXE_DEBUG = -DFULLDEBUG -g -O0 +EXE_FROUNDING_MATH = -frounding-math +EXE_NDEBUG = -DNDEBUG + +CGAL_EXACT = /*-DCGAL_DONT_USE_LAZY_KERNEL*/ +CGAL_INEXACT = -DCGAL_INEXACT + +include $(GENERAL_RULES)/CGAL + + +EXE_INC = \ + ${EXE_FROUNDING_MATH} \ + ${EXE_NDEBUG} \ + ${CGAL_INEXACT} \ + ${CGAL_INC} \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/dynamicMesh/lnInclude \ + -I$(LIB_SRC)/triSurface/lnInclude \ + -I$(LIB_SRC)/fileFormats/lnInclude \ + -I$(LIB_SRC)/sampling/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \ + -I$(LIB_SRC)/edgeMesh/lnInclude \ + -I$(HOME)/OpenFOAM/OpenFOAM-dev/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/lnInclude \ + -I$(HOME)/OpenFOAM/OpenFOAM-dev/applications/utilities/mesh/generation/cvMesh/vectorTools + +EXE_LIBS = \ + $(CGAL_LIBS) \ + -lmpfr \ + -lboost_thread \ + -lconformalVoronoiMesh \ + -lfiniteVolume \ + -lmeshTools \ + -ldecompositionMethods \ + -L$(FOAM_LIBBIN)/dummy -lptscotchDecomp \ + -ledgeMesh \ + -ltriSurface \ + -ldynamicMesh \ + -lsampling \ + -lfileFormats diff --git a/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/cellSizeAndAlignmentGrid.C b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/cellSizeAndAlignmentGrid.C new file mode 100644 index 00000000000..27cc47f823f --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/cellSizeAndAlignmentGrid/cellSizeAndAlignmentGrid.C @@ -0,0 +1,711 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Application + Test-distributedDelaunayMesh + +Description + +\*---------------------------------------------------------------------------*/ + +#include "CGALTriangulation3DKernel.H" + +#include "indexedVertex.H" +#include "indexedCell.H" + +#include "argList.H" +#include "Time.H" +#include "DistributedDelaunayMesh.H" +#include "backgroundMeshDecomposition.H" +#include "searchableSurfaces.H" +#include "conformationSurfaces.H" +#include "PrintTable.H" +#include "Random.H" +#include "boundBox.H" +#include "point.H" +#include "cellShapeControlMesh.H" +#include "triadField.H" +#include "scalarIOField.H" +#include "pointIOField.H" +#include "triadIOField.H" + +using namespace Foam; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Main program: + +template <class Triangulation, class Type> +Foam::tmp<Foam::Field<Type> > filterFarPoints +( + const Triangulation& mesh, + const Field<Type>& field +) +{ + tmp<Field<Type> > tNewField(new Field<Type>(field.size())); + Field<Type>& newField = tNewField(); + + label added = 0; + label count = 0; + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + newField[added++] = field[count]; + } + + count++; + } + + newField.resize(added); + + return tNewField; +} + + +template <class T> +autoPtr<mapDistribute> buildMap +( + const T& mesh, + labelListList& pointPoints +) +{ + pointPoints.setSize(mesh.vertexCount()); + + globalIndex globalIndexing(mesh.vertexCount()); + + for + ( + typename T::Finite_vertices_iterator vit = mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + std::list<typename T::Vertex_handle> adjVerts; + mesh.finite_adjacent_vertices(vit, std::back_inserter(adjVerts)); + + DynamicList<label> indices(adjVerts.size()); + + for + ( + typename std::list<typename T::Vertex_handle>::const_iterator + adjVertI = adjVerts.begin(); + adjVertI != adjVerts.end(); + ++adjVertI + ) + { + typename T::Vertex_handle vh = *adjVertI; + + if (!vh->farPoint()) + { + indices.append + ( + globalIndexing.toGlobal(vh->procIndex(), vh->index()) + ); + } + } + + pointPoints[vit->index()].transfer(indices); + } + + List<Map<label> > compactMap; + + return autoPtr<mapDistribute> + ( + new mapDistribute + ( + globalIndexing, + pointPoints, + compactMap + ) + ); +} + + +template <class T> +Foam::tmp<Foam::triadField> buildAlignmentField(const T& mesh) +{ + tmp<triadField> tAlignments + ( + new triadField(mesh.vertexCount(), triad::unset) + ); + triadField& alignments = tAlignments(); + + for + ( + typename T::Finite_vertices_iterator vit = mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + alignments[vit->index()] = triad + ( + vit->alignment().x(), + vit->alignment().y(), + vit->alignment().z() + ); + } + + return tAlignments; +} + + +template <class T> +Foam::tmp<Foam::pointField> buildPointField(const T& mesh) +{ + tmp<pointField> tPoints + ( + new pointField(mesh.vertexCount(), point(GREAT, GREAT, GREAT)) + ); + pointField& points = tPoints(); + + for + ( + typename T::Finite_vertices_iterator vit = mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + points[vit->index()] = topoint(vit->point()); + } + + return tPoints; +} + + +int main(int argc, char *argv[]) +{ + #include "setRootCase.H" + #include "createTime.H" + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + label maxRefinementIterations = 0; + label maxSmoothingIterations = 200; + scalar minResidual = 0; + scalar defaultCellSize = 0.0004; + scalar nearFeatDistSqrCoeff = 1e-8; + + + // Need to decouple vertex and cell type from this class? + // Vertex must have: + // + index + // + procIndex + // - type should be optional + cellShapeControlMesh mesh(runTime); + + IOdictionary cvMeshDict + ( + IOobject + ( + "cvMeshDict", + runTime.system(), + runTime, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ); + + Random rndGen(64293*Pstream::myProcNo()); + + searchableSurfaces allGeometry + ( + IOobject + ( + "cvSearchableSurfaces", + runTime.constant(), + "triSurface", + runTime, + IOobject::MUST_READ, + IOobject::NO_WRITE + ), + cvMeshDict.subDict("geometry") + ); + + conformationSurfaces geometryToConformTo + ( + runTime, + rndGen, + allGeometry, + cvMeshDict.subDict("surfaceConformation") + ); + + autoPtr<backgroundMeshDecomposition> bMesh; + if (Pstream::parRun()) + { + bMesh.set + ( + new backgroundMeshDecomposition + ( + runTime, + rndGen, + geometryToConformTo, + cvMeshDict.subDict("backgroundMeshDecomposition") + ) + ); + } + + // Nice to have IO for the delaunay mesh + // IO depend on vertex type. + // + // Define a delaunay mesh as: + // + list of points of the triangulation + // + optionally a list of cells + + Info<< nl << "Loop over surfaces" << endl; + + forAll(geometryToConformTo.surfaces(), sI) + { + const label surfI = geometryToConformTo.surfaces()[sI]; + + const searchableSurface& surface = + geometryToConformTo.geometry()[surfI]; + + Info<< nl << "Inserting points from surface " << surface.name() + << " (" << surface.type() << ")" << endl; + + const tmp<pointField> tpoints = surface.points(); + const pointField& points = tpoints(); + + Info<< " Number of points = " << points.size() << endl; + + forAll(points, pI) + { + // Is the point in the extendedFeatureEdgeMesh? If so get the + // point normal, otherwise get the surface normal from + // searchableSurface + + pointIndexHit info; + label infoFeature; + geometryToConformTo.findFeaturePointNearest + ( + points[pI], + nearFeatDistSqrCoeff, + info, + infoFeature + ); + + + autoPtr<triad> pointAlignment; + + if (info.hit()) + { + const extendedFeatureEdgeMesh& features = + geometryToConformTo.features()[infoFeature]; + + vectorField norms = features.featurePointNormals(info.index()); + + // Create a triad from these norms. + pointAlignment.set(new triad()); + forAll(norms, nI) + { + pointAlignment() += norms[nI]; + } + + pointAlignment().normalize(); + pointAlignment().orthogonalize(); + } + else + { + geometryToConformTo.findEdgeNearest + ( + points[pI], + nearFeatDistSqrCoeff, + info, + infoFeature + ); + + if (info.hit()) + { + const extendedFeatureEdgeMesh& features = + geometryToConformTo.features()[infoFeature]; + + vectorField norms = features.edgeNormals(info.index()); + + // Create a triad from these norms. + pointAlignment.set(new triad()); + forAll(norms, nI) + { + pointAlignment() += norms[nI]; + } + + pointAlignment().normalize(); + pointAlignment().orthogonalize(); + } + else + { + pointField ptField(1, points[pI]); + scalarField distField(1, nearFeatDistSqrCoeff); + List<pointIndexHit> infoList(1, pointIndexHit()); + + surface.findNearest(ptField, distField, infoList); + + vectorField normals(1); + surface.getNormal(infoList, normals); + + pointAlignment.set(new triad(normals[0])); + } + } + + if (Pstream::parRun()) + { + if (bMesh().positionOnThisProcessor(points[pI])) + { + CellSizeDelaunay::Vertex_handle vh = mesh.insert + ( + points[pI], + defaultCellSize, + pointAlignment() + ); + } + } + else + { + CellSizeDelaunay::Vertex_handle vh = mesh.insert + ( + points[pI], + defaultCellSize, + pointAlignment() + ); + } + } + } + + + for (label iter = 0; iter < maxRefinementIterations; ++iter) + { + DynamicList<point> ptsToInsert; + + for + ( + CellSizeDelaunay::Finite_cells_iterator cit = + mesh.finite_cells_begin(); + cit != mesh.finite_cells_end(); + ++cit + ) + { + const point newPoint = + topoint + ( + CGAL::centroid + ( + cit->vertex(0)->point(), + cit->vertex(1)->point(), + cit->vertex(2)->point(), + cit->vertex(3)->point() + ) + ); + + if (geometryToConformTo.inside(newPoint)) + { + ptsToInsert.append(newPoint); + } + } + + Info<< " Adding " << returnReduce(ptsToInsert.size(), sumOp<label>()) + << endl; + + forAll(ptsToInsert, ptI) + { + mesh.insert + ( + ptsToInsert[ptI], + defaultCellSize, + triad::unset + ); + } + } + + + if (Pstream::parRun()) + { + mesh.distribute(bMesh); + } + + labelListList pointPoints; + autoPtr<mapDistribute> meshDistributor = buildMap(mesh, pointPoints); + + triadField alignments = buildAlignmentField(mesh); + pointField points = buildPointField(mesh); + + mesh.printInfo(Info); + + + // Setup the sizes and alignments on each point + triadField fixedAlignments(mesh.vertexCount(), triad::unset); + + for + ( + CellSizeDelaunay::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + const tensor& alignment = vit->alignment(); + + fixedAlignments[vit->index()] = triad + ( + alignment.x(), + alignment.y(), + alignment.z() + ); + } + } + + + Info<< nl << "Smoothing alignments" << endl; + + for (label iter = 0; iter < maxSmoothingIterations; iter++) + { + Info<< "Iteration " << iter; + + meshDistributor().distribute(points); + meshDistributor().distribute(alignments); + + scalar residual = 0; + + triadField triadAv(alignments.size(), triad::unset); + + forAll(pointPoints, pI) + { + const labelList& pPoints = pointPoints[pI]; + + if (pPoints.empty()) + { + continue; + } + + const triad& oldTriad = alignments[pI]; + triad& newTriad = triadAv[pI]; + + forAll(pPoints, adjPointI) + { + const label adjPointIndex = pPoints[adjPointI]; + + scalar dist = mag(points[pI] - points[adjPointIndex]); + + dist = max(dist, SMALL); + + triad tmpTriad = alignments[adjPointIndex]; + + for (direction dir = 0; dir < 3; dir++) + { + if (tmpTriad.set(dir)) + { + tmpTriad[dir] *= (1.0/dist); + } + } + + newTriad += tmpTriad; + } + + newTriad.normalize(); + newTriad.orthogonalize(); + newTriad = newTriad.sortxyz(); + + // Enforce the boundary conditions + const triad& fixedAlignment = fixedAlignments[pI]; + + label nFixed = 0; + + forAll(fixedAlignment, dirI) + { + if (fixedAlignment[dirI] != triad::unset[dirI]) + { + nFixed++; + } + } + + if (nFixed == 1) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad.align(fixedAlignment[dirI]); + } + } + } + else if (nFixed == 2) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad[dirI] = fixedAlignment[dirI]; + } + else + { + newTriad[dirI] = triad::unset[dirI]; + } + } + + newTriad.orthogonalize(); + } + else if (nFixed == 3) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad[dirI] = fixedAlignment[dirI]; + } + } + } + + if (newTriad.set(vector::X) && oldTriad.set(vector::X)) + { + scalar dotProd = (oldTriad.x() & newTriad.x()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + if (newTriad.set(vector::Y) && oldTriad.set(vector::Y)) + { + scalar dotProd = (oldTriad.y() & newTriad.y()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + if (newTriad.set(vector::Z) && oldTriad.set(vector::Z)) + { + scalar dotProd = (oldTriad.z() & newTriad.z()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + } + + forAll(alignments, pI) + { + alignments[pI] = triadAv[pI].sortxyz(); + } + + reduce(residual, sumOp<scalar>()); + + Info<< ", Residual = " << residual << endl; + + if (residual <= minResidual) + { + break; + } + } + + + // Write alignments to a .obj file + OFstream str(runTime.path()/"alignments.obj"); + + forAll(alignments, pI) + { + const triad& tri = alignments[pI]; + + if (tri.set()) + { + forAll(tri, dirI) + { + meshTools::writeOBJ(str, points[pI], tri[dirI] + points[pI]); + } + } + } + + + // Remove the far points + pointIOField pointsIO + ( + IOobject + ( + "points", + runTime.constant(), + runTime, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + filterFarPoints(mesh, points) + ); + + scalarField sizes(points.size(), defaultCellSize); + scalarIOField sizesIO + ( + IOobject + ( + "sizes", + runTime.constant(), + runTime, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + filterFarPoints(mesh, sizes) + ); + + triadIOField alignmentsIO + ( + IOobject + ( + "alignments", + runTime.constant(), + runTime, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + filterFarPoints(mesh, alignments) + ); + + pointsIO.write(); + sizesIO.write(); + alignmentsIO.write(); + + Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s" + << " ClockTime = " << runTime.elapsedClockTime() << " s" + << nl << endl; + + Info<< "\nEnd\n" << endl; + + return 0; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/checkCvMesh/meshQualityDict b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/meshQualityDict new file mode 100644 index 00000000000..fa5319e087c --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/checkCvMesh/meshQualityDict @@ -0,0 +1,73 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: dev | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +FoamFile +{ + version 2.0; + format ascii; + + root ""; + case ""; + instance ""; + local ""; + + class dictionary; + object meshQualityDict; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- Maximum non-orthogonality allowed. Set to 180 to disable. +maxNonOrtho 65; + +//- Max skewness allowed. Set to <0 to disable. +maxBoundarySkewness 50; +maxInternalSkewness 10; + +//- Max concaveness allowed. Is angle (in degrees) below which concavity +// is allowed. 0 is straight face, <0 would be convex face. +// Set to 180 to disable. +maxConcave 80; + +//- Minimum quality of the tet formed by the face-centre +// and variable base point minimum decomposition triangles and +// the cell centre. This has to be a positive number for tracking +// to work. Set to very negative number (e.g. -1E30) to +// disable. +// <0 = inside out tet, +// 0 = flat tet +// 1 = regular tet +minTetQuality 1e-30; + +//- Minimum pyramid volume. Is absolute volume of cell pyramid. +// Set to a sensible fraction of the smallest cell volume expected. +// Set to very negative number (e.g. -1E30) to disable. +minVol 1e-20; + +//- Minimum face area. Set to <0 to disable. +minArea -1; + +//- Minimum face twist. Set to <-1 to disable. dot product of face normal +//- and face centre triangles normal +minTwist 0.001; + +//- minimum normalised cell determinant +//- 1 = hex, <= 0 = folded or flattened illegal cell +minDeterminant 0.001; + +//- minFaceWeight (0 -> 0.5) +minFaceWeight 0.02; + +//- minVolRatio (0 -> 1) +minVolRatio 0.01; + +//must be >0 for Fluent compatibility +minTriangleTwist -1; + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.C new file mode 100644 index 00000000000..a0327ce04f9 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.C @@ -0,0 +1,233 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "DelaunayMesh.H" +#include "labelPair.H" +#include "PrintTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class Triangulation> +Foam::DelaunayMesh<Triangulation>::DelaunayMesh() +: + Triangulation(), + vertexCount_(0), + cellCount_(0) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +template<class Triangulation> +Foam::DelaunayMesh<Triangulation>::~DelaunayMesh() +{} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::reset() +{ + Info<< "Clearing triangulation" << endl; + + this->clear(); + + resetVertexCount(); + resetCellCount(); +} + + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::insertPoints(const List<Vb>& vertices) +{ + rangeInsertWithInfo + ( + vertices.begin(), + vertices.end(), + true + ); +} + + +template<class Triangulation> +bool Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_x_3:: +operator() +( + const Point_3& p, + const Point_3& q +) const +{ + return typename Gt::Less_x_3()(*(p.first), *(q.first)); +} + +template<class Triangulation> +bool Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_y_3:: +operator() +( + const Point_3& p, + const Point_3& q +) const +{ + return typename Gt::Less_y_3()(*(p.first), *(q.first)); +} + +template<class Triangulation> +bool Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_z_3:: +operator() +( + const Point_3& p, + const Point_3& q +) const +{ + return typename Gt::Less_z_3()(*(p.first), *(q.first)); +} + +template<class Triangulation> +typename Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_x_3 +Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::less_x_3_object() +const +{ + return Less_x_3(); +} + +template<class Triangulation> +typename Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_y_3 +Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::less_y_3_object() +const +{ + return Less_y_3(); +} + +template<class Triangulation> +typename Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::Less_z_3 +Foam::DelaunayMesh<Triangulation>::Traits_for_spatial_sort::less_z_3_object() +const +{ + return Less_z_3(); +} + + +template<class Triangulation> +template<class PointIterator> +void Foam::DelaunayMesh<Triangulation>::rangeInsertWithInfo +( + PointIterator begin, + PointIterator end, + bool printErrors +) +{ + typedef DynamicList + < + std::pair + < + const typename Triangulation::Point*, + label + > + > vectorPairPointIndex; + + vectorPairPointIndex points; + + label count = 0; + for (PointIterator it = begin; it != end; ++it) + { + points.append + ( + std::make_pair(&(it->point()), count++) + ); + } + + std::random_shuffle(points.begin(), points.end()); + + spatial_sort + ( + points.begin(), + points.end(), + Traits_for_spatial_sort() + ); + + Vertex_handle hint; + + for + ( + typename vectorPairPointIndex::const_iterator p = points.begin(); + p != points.end(); + ++p + ) + { + const size_t checkInsertion = Triangulation::number_of_vertices(); + + hint = this->insert(*(p->first), hint); + + const Vb& vert = *(begin + p->second); + + if (checkInsertion != Triangulation::number_of_vertices() - 1) + { + if (printErrors) + { + Vertex_handle nearV = + Triangulation::nearest_vertex(*(p->first)); + + Pout<< "Failed insertion : " << vert.info() + << " nearest : " << nearV->info(); + } + } + else + { + hint->index() = getNewVertexIndex(); + hint->type() = vert.type(); + hint->procIndex() = vert.procIndex(); + hint->targetCellSize() = vert.targetCellSize(); + hint->alignment() = vert.alignment(); + } + } +} + + +// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "DelaunayMeshIO.C" + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.H new file mode 100644 index 00000000000..bdeee880e78 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMesh.H @@ -0,0 +1,238 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::DelaunayMesh + +Description + The vertex and cell classes must have an index defined + +SourceFiles + DelaunayMeshI.H + DelaunayMesh.C + DelaunayMeshIO.C + +\*---------------------------------------------------------------------------*/ + +#ifndef DelaunayMesh_H +#define DelaunayMesh_H + +#include "Pair.H" +#include "HashSet.H" +#include "FixedList.H" +#include "boundBox.H" +#include "indexedVertex.H" +#include "CGALTriangulation3Ddefs.H" +#include "autoPtr.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class fvMesh; + +/*---------------------------------------------------------------------------*\ + Class DelaunayMesh Declaration +\*---------------------------------------------------------------------------*/ + +template<class Triangulation> +class DelaunayMesh +: + public Triangulation +{ +public: + + typedef typename Triangulation::Cell_handle Cell_handle; + typedef typename Triangulation::Vertex_handle Vertex_handle; + typedef typename Triangulation::Point Point; + typedef typename Triangulation::Facet Facet; + + typedef typename Triangulation::Finite_vertices_iterator + Finite_vertices_iterator; + typedef typename Triangulation::Finite_cells_iterator + Finite_cells_iterator; + typedef typename Triangulation::Finite_facets_iterator + Finite_facets_iterator; + + typedef HashSet + < + Pair<label>, + FixedList<label, 2>::Hash<> + > labelPairHashSet; + + +private: + + // Private data + + //- Keep track of the number of vertices that have been added. + // This allows a unique index to be assigned to each vertex. + mutable label vertexCount_; + + //- Keep track of the number of cells that have been added. + // This allows a unique index to be assigned to each cell. + mutable label cellCount_; + + //- Spatial sort traits to use with a pair of point pointers and an int. + // Taken from a post on the CGAL lists: 2010-01/msg00004.html by + // Sebastien Loriot (Geometry Factory). + struct Traits_for_spatial_sort + : + public Triangulation::Geom_traits + { + typedef typename Triangulation::Geom_traits Gt; + + typedef std::pair<const typename Triangulation::Point*, int> + Point_3; + + struct Less_x_3 + { + bool operator()(const Point_3& p, const Point_3& q) const; + }; + + struct Less_y_3 + { + bool operator()(const Point_3& p, const Point_3& q) const; + }; + + struct Less_z_3 + { + bool operator()(const Point_3& p, const Point_3& q) const; + }; + + Less_x_3 less_x_3_object() const; + Less_y_3 less_y_3_object() const; + Less_z_3 less_z_3_object() const; + }; + + + // Private Member Functions + + void sortFaces + ( + faceList& faces, + labelList& owner, + labelList& neighbour + ) const; + + void addPatches + ( + const label nInternalFaces, + faceList& faces, + labelList& owner, + labelList& patchSizes, + labelList& patchStarts, + const List<DynamicList<face> >& patchFaces, + const List<DynamicList<label> >& patchOwners + ) const; + + //- Disallow default bitwise copy construct + DelaunayMesh(const DelaunayMesh<Triangulation>&); + + //- Disallow default bitwise assignment + void operator=(const DelaunayMesh<Triangulation>&); + + +public: + + // Constructors + + //- Construct from components + DelaunayMesh(); + + + //- Destructor + ~DelaunayMesh(); + + + // Member Functions + + inline label getNewVertexIndex() const; + + inline label getNewCellIndex() const; + + inline label cellCount() const; + + inline void resetCellCount(); + + inline label vertexCount() const; + + inline void resetVertexCount(); + + + //- Remove the entire triangulation + void reset(); + + void insertPoints(const List<Vb>& vertices); + + //- Function inserting points into a triangulation and setting the + // index and type data of the point in the correct order. This is + // faster than inserting points individually. + // + // Adapted from a post on the CGAL lists: 2010-01/msg00004.html by + // Sebastien Loriot (Geometry Factory). + template<class PointIterator> + void rangeInsertWithInfo + ( + PointIterator begin, + PointIterator end, + bool printErrors = true + ); + + + // Queries + + void printInfo(Ostream& os) const; + + //- Create an fvMesh from the triangulation. + // The mesh is not parallel consistent - only used for viewing + autoPtr<fvMesh> createMesh + ( + const fileName& name, + const Time& runTime, + labelList& vertexMap, + labelList& cellMap + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "DelaunayMeshI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "DelaunayMesh.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshI.H new file mode 100644 index 00000000000..841e5c9024b --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshI.H @@ -0,0 +1,119 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * Destructors * * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class Triangulation> +inline Foam::label Foam::DelaunayMesh<Triangulation>::getNewVertexIndex() const +{ + label id = vertexCount_++; + + if (id == labelMax) + { + WarningIn + ( + "Foam::DelaunayMesh<Triangulation>::getNewVertexIndex() const" + ) << "Vertex counter has overflowed." << endl; + } + + return id; +} + + +template<class Triangulation> +inline Foam::label Foam::DelaunayMesh<Triangulation>::getNewCellIndex() const +{ + label id = cellCount_++; + + if (id == labelMax) + { + WarningIn + ( + "Foam::DelaunayMesh<Triangulation>::getNewCellIndex() const" + ) << "Cell counter has overflowed." << endl; + } + + return id; +} + + +template<class Triangulation> +Foam::label Foam::DelaunayMesh<Triangulation>::cellCount() const +{ + return cellCount_; +} + + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::resetCellCount() +{ + cellCount_ = 0; +} + + +template<class Triangulation> +Foam::label Foam::DelaunayMesh<Triangulation>::vertexCount() const +{ + return vertexCount_; +} + + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::resetVertexCount() +{ + vertexCount_ = 0; +} + + +// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshIO.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshIO.C new file mode 100644 index 00000000000..4cf7077657d --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DelaunayMeshIO.C @@ -0,0 +1,406 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "DelaunayMesh.H" +#include "fvMesh.H" +#include "pointConversion.H" +#include "wallPolyPatch.H" +#include "processorPolyPatch.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::sortFaces +( + faceList& faces, + labelList& owner, + labelList& neighbour +) const +{ + // Upper triangular order: + // + owner is sorted in ascending cell order + // + within each block of equal value for owner, neighbour is sorted in + // ascending cell order. + // + faces sorted to correspond + // e.g. + // owner | neighbour + // 0 | 2 + // 0 | 23 + // 0 | 71 + // 1 | 23 + // 1 | 24 + // 1 | 91 + + List<labelPair> ownerNeighbourPair(owner.size()); + + forAll(ownerNeighbourPair, oNI) + { + ownerNeighbourPair[oNI] = labelPair(owner[oNI], neighbour[oNI]); + } + + Info<< nl + << "Sorting faces, owner and neighbour into upper triangular order" + << endl; + + labelList oldToNew; + + sortedOrder(ownerNeighbourPair, oldToNew); + + oldToNew = invert(oldToNew.size(), oldToNew); + + inplaceReorder(oldToNew, faces); + inplaceReorder(oldToNew, owner); + inplaceReorder(oldToNew, neighbour); +} + + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::addPatches +( + const label nInternalFaces, + faceList& faces, + labelList& owner, + labelList& patchSizes, + labelList& patchStarts, + const List<DynamicList<face> >& patchFaces, + const List<DynamicList<label> >& patchOwners +) const +{ + label nPatches = patchFaces.size(); + + patchSizes.setSize(nPatches, -1); + patchStarts.setSize(nPatches, -1); + + label nBoundaryFaces = 0; + + forAll(patchFaces, p) + { + patchSizes[p] = patchFaces[p].size(); + patchStarts[p] = nInternalFaces + nBoundaryFaces; + + nBoundaryFaces += patchSizes[p]; + } + + faces.setSize(nInternalFaces + nBoundaryFaces); + owner.setSize(nInternalFaces + nBoundaryFaces); + + label faceI = nInternalFaces; + + forAll(patchFaces, p) + { + forAll(patchFaces[p], f) + { + faces[faceI] = patchFaces[p][f]; + owner[faceI] = patchOwners[p][f]; + + faceI++; + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +//template<class Triangulation> +//Foam::DelaunayMesh<Triangulation>::DelaunayMesh(Istream& is) +//: +// base1(is), +// base2(is), +// member1(is), +// member2(is) +//{ +// // Check state of Istream +// is.check("Foam::DelaunayMesh<Triangulation>::DelaunayMesh(Foam::Istream&)"); +//} + + +// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // + +template<class Triangulation> +void Foam::DelaunayMesh<Triangulation>::printInfo(Ostream& os) const +{ + PrintTable<word, label> triInfoTable("Mesh Statistics"); + + triInfoTable.add("Points", Triangulation::number_of_vertices()); + triInfoTable.add("Edges", Triangulation::number_of_finite_edges()); + triInfoTable.add("Faces", Triangulation::number_of_finite_facets()); + triInfoTable.add("Cells", Triangulation::number_of_finite_cells()); + + scalar minSize = GREAT; + scalar maxSize = 0; + + for + ( + Finite_vertices_iterator vit = Triangulation::finite_vertices_begin(); + vit != Triangulation::finite_vertices_end(); + ++vit + ) + { + if (!vit->farPoint()) + { + minSize = min(vit->targetCellSize(), minSize); + maxSize = max(vit->targetCellSize(), maxSize); + } + } + + Info<< incrIndent; + triInfoTable.print(Info, true, true); + + Info<< "Size (Min/Max) = " + << returnReduce(minSize, minOp<scalar>()) << " " + << returnReduce(maxSize, maxOp<scalar>()) << endl; + + Info<< decrIndent; +} + + +template<class Triangulation> +Foam::autoPtr<Foam::fvMesh> +Foam::DelaunayMesh<Triangulation>::createMesh +( + const fileName& name, + const Time& runTime, + labelList& vertexMap, + labelList& cellMap +) const +{ + pointField points(Triangulation::number_of_vertices()); + faceList faces(Triangulation::number_of_finite_facets()); + labelList owner(Triangulation::number_of_finite_facets()); + labelList neighbour(Triangulation::number_of_finite_facets()); + + wordList patchNames(1, "cvMesh_defaultPatch"); + wordList patchTypes(1, wallPolyPatch::typeName); + + labelList patchSizes(1, 0); + labelList patchStarts(1, 0); + + List<DynamicList<face> > patchFaces(1, DynamicList<face>()); + List<DynamicList<label> > patchOwners(1, DynamicList<label>()); + + vertexMap.setSize(Triangulation::number_of_vertices()); + cellMap.setSize(Triangulation::number_of_finite_cells()); + + // Calculate pts and a map of point index to location in pts. + label vertI = 0; + + for + ( + Finite_vertices_iterator vit = Triangulation::finite_vertices_begin(); + vit != Triangulation::finite_vertices_end(); + ++vit + ) + { + if (!vit->farPoint()) + { + vertexMap[vit->index()] = vertI; + points[vertI] = topoint(vit->point()); + vertI++; + } + } + + points.setSize(vertI); + + // Index the cells + label cellI = 0; + + for + ( + Finite_cells_iterator cit = Triangulation::finite_cells_begin(); + cit != Triangulation::finite_cells_end(); + ++cit + ) + { + if + ( + !cit->hasFarPoint() + && !Triangulation::is_infinite(cit) + ) + { + cellMap[cit->cellIndex()] = cellI++; + } + } + + label faceI = 0; + labelList verticesOnTriFace(3, -1); + face newFace(verticesOnTriFace); + + for + ( + Finite_facets_iterator fit = Triangulation::finite_facets_begin(); + fit != Triangulation::finite_facets_end(); + ++fit + ) + { + const Cell_handle c1(fit->first); + const int oppositeVertex = fit->second; + const Cell_handle c2(c1->neighbor(oppositeVertex)); + + label c1I = Cb::ctFar; + bool c1Real = false; + if (!c1->hasFarPoint() && !Triangulation::is_infinite(c1)) + { + c1I = cellMap[c1->cellIndex()]; + c1Real = true; + } + + label c2I = Cb::ctFar; + bool c2Real = false; + if (!c2->hasFarPoint() && !Triangulation::is_infinite(c2)) + { + c2I = cellMap[c2->cellIndex()]; + c2Real = true; + } + + if (!c1Real && !c2Real) + { + // Both tets are outside, skip + continue; + } + + label ownerCell = -1; + label neighbourCell = -1; + + for (label i = 0; i < 3; i++) + { + verticesOnTriFace[i] = vertexMap + [ + c1->vertex + ( + Triangulation::vertex_triple_index(oppositeVertex, i) + )->index() + ]; + } + + newFace = face(verticesOnTriFace); + + if (!c1Real || !c2Real) + { + // Boundary face... + if (!c1Real) + { + //... with c1 outside + ownerCell = c2I; + } + else + { + // ... with c2 outside + ownerCell = c1I; + + reverse(newFace); + } + + patchFaces[0].append(newFace); + patchOwners[0].append(ownerCell); + } + else + { + // Internal face... + if (c1I < c2I) + { + // ...with c1 as the ownerCell + ownerCell = c1I; + neighbourCell = c2I; + + reverse(newFace); + } + else + { + // ...with c2 as the ownerCell + ownerCell = c2I; + neighbourCell = c1I; + } + + faces[faceI] = newFace; + owner[faceI] = ownerCell; + neighbour[faceI] = neighbourCell; + faceI++; + } + } + + faces.setSize(faceI); + owner.setSize(faceI); + neighbour.setSize(faceI); + + sortFaces(faces, owner, neighbour); + + addPatches + ( + faceI, + faces, + owner, + patchSizes, + patchStarts, + patchFaces, + patchOwners + ); + + autoPtr<fvMesh> meshPtr + ( + new fvMesh + ( + IOobject + ( + name, + runTime.timeName(), + runTime, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + xferMove(points), + xferMove(faces), + xferMove(owner), + xferMove(neighbour) + ) + ); + + List<polyPatch*> patches(patchStarts.size()); + + label nValidPatches = 0; + + forAll(patches, p) + { + patches[nValidPatches] = polyPatch::New + ( + patchTypes[p], + patchNames[p], + patchSizes[p], + patchStarts[p], + nValidPatches, + meshPtr().boundaryMesh() + ).ptr(); + + nValidPatches++; + } + + patches.setSize(nValidPatches); + + meshPtr().addFvPatches(patches); + + return meshPtr; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.C new file mode 100644 index 00000000000..ded70e95299 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.C @@ -0,0 +1,932 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "DistributedDelaunayMesh.H" +#include "meshSearch.H" +#include "mapDistribute.H" +#include "zeroGradientFvPatchFields.H" +#include "pointConversion.H" +#include "indexedVertexEnum.H" +#include "IOmanip.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * // + +template<class Triangulation> +Foam::autoPtr<Foam::mapDistribute> +Foam::DistributedDelaunayMesh<Triangulation>::buildMap +( + const List<label>& toProc +) +{ + // Determine send map + // ~~~~~~~~~~~~~~~~~~ + + // 1. Count + labelList nSend(Pstream::nProcs(), 0); + + forAll(toProc, i) + { + label procI = toProc[i]; + + nSend[procI]++; + } + + // Send over how many I need to receive + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelListList sendSizes(Pstream::nProcs()); + + sendSizes[Pstream::myProcNo()] = nSend; + + combineReduce(sendSizes, UPstream::listEq()); + + // 2. Size sendMap + labelListList sendMap(Pstream::nProcs()); + + forAll(nSend, procI) + { + sendMap[procI].setSize(nSend[procI]); + + nSend[procI] = 0; + } + + // 3. Fill sendMap + forAll(toProc, i) + { + label procI = toProc[i]; + + sendMap[procI][nSend[procI]++] = i; + } + + // Determine receive map + // ~~~~~~~~~~~~~~~~~~~~~ + + labelListList constructMap(Pstream::nProcs()); + + // Local transfers first + constructMap[Pstream::myProcNo()] = identity + ( + sendMap[Pstream::myProcNo()].size() + ); + + label constructSize = constructMap[Pstream::myProcNo()].size(); + + forAll(constructMap, procI) + { + if (procI != Pstream::myProcNo()) + { + label nRecv = sendSizes[procI][Pstream::myProcNo()]; + + constructMap[procI].setSize(nRecv); + + for (label i = 0; i < nRecv; i++) + { + constructMap[procI][i] = constructSize++; + } + } + } + + return autoPtr<mapDistribute> + ( + new mapDistribute + ( + constructSize, + sendMap.xfer(), + constructMap.xfer() + ) + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class Triangulation> +Foam::DistributedDelaunayMesh<Triangulation>::DistributedDelaunayMesh() +: + DelaunayMesh<Triangulation>(), + allBackgroundMeshBounds_() +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +template<class Triangulation> +Foam::DistributedDelaunayMesh<Triangulation>::~DistributedDelaunayMesh() +{} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +template<class Triangulation> +bool Foam::DistributedDelaunayMesh<Triangulation>::distributeBoundBoxes +( + const boundBox& bb +) +{ + allBackgroundMeshBounds_.reset(new List<boundBox>(Pstream::nProcs())); + + // Give the bounds of every processor to every other processor + allBackgroundMeshBounds_()[Pstream::myProcNo()] = bb; + + Pstream::gatherList(allBackgroundMeshBounds_()); + Pstream::scatterList(allBackgroundMeshBounds_()); + + return true; +} + + +template<class Triangulation> +bool Foam::DistributedDelaunayMesh<Triangulation>::isLocal +( + const Vertex_handle& v +) const +{ + return isLocal(v->procIndex()); +} + + +template<class Triangulation> +bool Foam::DistributedDelaunayMesh<Triangulation>::isLocal +( + const label localProcIndex +) const +{ + return localProcIndex == Pstream::myProcNo(); +} + + +template<class Triangulation> +Foam::labelList Foam::DistributedDelaunayMesh<Triangulation>::overlapProcessors +( + const point& centre, + const scalar radiusSqr +) const +{ + DynamicList<label> toProc(Pstream::nProcs()); + + forAll(allBackgroundMeshBounds_(), procI) + { + // Test against the bounding box of the processor + if + ( + !isLocal(procI) + && allBackgroundMeshBounds_()[procI].overlaps(centre, radiusSqr) + ) + { + toProc.append(procI); + } + } + + return toProc; +} + + +template<class Triangulation> +bool Foam::DistributedDelaunayMesh<Triangulation>::checkProcBoundaryCell +( + const Cell_handle& cit, + Map<labelList>& circumsphereOverlaps +) const +{ + const Foam::point& cc = cit->dual(); + + const scalar crSqr = magSqr + ( + cc - topoint(cit->vertex(0)->point()) + ); + + labelList circumsphereOverlap = overlapProcessors + ( + cc, + sqr(1.01)*crSqr + ); + + cit->cellIndex() = this->getNewCellIndex(); + + if (!circumsphereOverlap.empty()) + { + circumsphereOverlaps.insert(cit->cellIndex(), circumsphereOverlap); + + return true; + } + + return false; +} + + +template<class Triangulation> +void Foam::DistributedDelaunayMesh<Triangulation>::findProcessorBoundaryCells +( + Map<labelList>& circumsphereOverlaps +) const +{ + // Start by assuming that all the cells have no index + // If they do, they have already been visited so ignore them + + labelHashSet cellToCheck + ( + Triangulation::number_of_finite_cells() + /Pstream::nProcs() + ); + + for + ( + All_cells_iterator cit = Triangulation::all_cells_begin(); + cit != Triangulation::all_cells_end(); + ++cit + ) + { + if (Triangulation::is_infinite(cit)) + { + // Index of infinite vertex in this cell. + int i = cit->index(Triangulation::infinite_vertex()); + + Cell_handle c = cit->neighbor(i); + + if (c->unassigned()) + { + c->cellIndex() = this->getNewCellIndex(); + + if (checkProcBoundaryCell(c, circumsphereOverlaps)) + { + cellToCheck.insert(c->cellIndex()); + } + } + } + else if (cit->parallelDualVertex()) + { + if (cit->unassigned()) + { + if (checkProcBoundaryCell(cit, circumsphereOverlaps)) + { + cellToCheck.insert(cit->cellIndex()); + } + } + } + } + + for + ( + Finite_cells_iterator cit = Triangulation::finite_cells_begin(); + cit != Triangulation::finite_cells_end(); + ++cit + ) + { + if (cellToCheck.found(cit->cellIndex())) + { + // Get the neighbours and check them + for (label adjCellI = 0; adjCellI < 4; ++adjCellI) + { + Cell_handle citNeighbor = cit->neighbor(adjCellI); + + // Ignore if has far point or previously visited + if + ( + !citNeighbor->unassigned() + || !citNeighbor->internalOrBoundaryDualVertex() + || Triangulation::is_infinite(citNeighbor) + ) + { + continue; + } + + checkProcBoundaryCell + ( + citNeighbor, + circumsphereOverlaps + ); + } + } + } +} + + +template<class Triangulation> +void Foam::DistributedDelaunayMesh<Triangulation>::markVerticesToRefer +( + const Map<labelList>& circumsphereOverlaps, + PtrList<labelPairHashSet>& referralVertices, + DynamicList<label>& targetProcessor, + DynamicList<Vb>& parallelInfluenceVertices +) +{ + // Relying on the order of iteration of cells being the same as before + for + ( + Finite_cells_iterator cit = Triangulation::finite_cells_begin(); + cit != Triangulation::finite_cells_end(); + ++cit + ) + { + if (Triangulation::is_infinite(cit)) + { + continue; + } + + Map<labelList>::const_iterator iter = + circumsphereOverlaps.find(cit->cellIndex()); + + // Pre-tested circumsphere potential influence + if (iter != circumsphereOverlaps.cend()) + { + const labelList& citOverlaps = iter(); + + forAll(citOverlaps, cOI) + { + label procI = citOverlaps[cOI]; + + for (int i = 0; i < 4; i++) + { + Vertex_handle v = cit->vertex(i); + + if (v->farPoint()) + { + continue; + } + + label vProcIndex = v->procIndex(); + label vIndex = v->index(); + + const labelPair procIndexPair(vProcIndex, vIndex); + + // Using the hashSet to ensure that each vertex is only + // referred once to each processor. + // Do not refer a vertex to its own processor. + if (vProcIndex != procI) + { + if (referralVertices[procI].insert(procIndexPair)) + { + targetProcessor.append(procI); + + parallelInfluenceVertices.append + ( + Vb + ( + v->point(), + v->index(), + v->type(), + v->procIndex() + ) + ); + + parallelInfluenceVertices.last().targetCellSize() = + v->targetCellSize(); + parallelInfluenceVertices.last().alignment() = + v->alignment(); + } + } + } + } + } + } +} + + +template<class Triangulation> +Foam::label Foam::DistributedDelaunayMesh<Triangulation>::referVertices +( + const DynamicList<label>& targetProcessor, + DynamicList<Vb>& parallelVertices, + PtrList<labelPairHashSet>& referralVertices, + labelPairHashSet& receivedVertices +) +{ + DynamicList<Vb> referredVertices(targetProcessor.size()); + + const label preDistributionSize = parallelVertices.size(); + + mapDistribute pointMap = buildMap(targetProcessor); + + // Make a copy of the original list. + DynamicList<Vb> originalParallelVertices(parallelVertices); + + pointMap.distribute(parallelVertices); + + for (label procI = 0; procI < Pstream::nProcs(); procI++) + { + const labelList& constructMap = pointMap.constructMap()[procI]; + + if (constructMap.size()) + { + forAll(constructMap, i) + { + const Vb& v = parallelVertices[constructMap[i]]; + + if + ( + v.procIndex() != Pstream::myProcNo() + && !receivedVertices.found(labelPair(v.procIndex(), v.index())) + ) + { + referredVertices.append(v); + + receivedVertices.insert + ( + labelPair(v.procIndex(), v.index()) + ); + } + } + } + } + + label preInsertionSize = Triangulation::number_of_vertices(); + + labelPairHashSet pointsNotInserted = rangeInsertReferredWithInfo + ( + referredVertices.begin(), + referredVertices.end() + ); + + if (!pointsNotInserted.empty()) + { + for + ( + typename labelPairHashSet::const_iterator iter + = pointsNotInserted.begin(); + iter != pointsNotInserted.end(); + ++iter + ) + { + if (receivedVertices.found(iter.key())) + { + receivedVertices.erase(iter.key()); + } + } + } + + boolList pointInserted(parallelVertices.size(), true); + + forAll(parallelVertices, vI) + { + const labelPair procIndexI + ( + parallelVertices[vI].procIndex(), + parallelVertices[vI].index() + ); + + if (pointsNotInserted.found(procIndexI)) + { + pointInserted[vI] = false; + } + } + + pointMap.reverseDistribute(preDistributionSize, pointInserted); + + forAll(originalParallelVertices, vI) + { + const label procIndex = targetProcessor[vI]; + + if (!pointInserted[vI]) + { + if (referralVertices[procIndex].size()) + { + if + ( + !referralVertices[procIndex].unset + ( + labelPair + ( + originalParallelVertices[vI].procIndex(), + originalParallelVertices[vI].index() + ) + ) + ) + { + Pout<< "*** not found " + << originalParallelVertices[vI].procIndex() + << " " << originalParallelVertices[vI].index() << endl; + } + + } + } + } + + label postInsertionSize = Triangulation::number_of_vertices(); + + reduce(preInsertionSize, sumOp<label>()); + reduce(postInsertionSize, sumOp<label>()); + + label nTotalToInsert = referredVertices.size(); + + reduce(nTotalToInsert, sumOp<label>()); + + if (preInsertionSize + nTotalToInsert != postInsertionSize) + { + label nNotInserted = + returnReduce(pointsNotInserted.size(), sumOp<label>()); + + Info<< " Inserted = " + << setw(name(label(Triangulation::number_of_finite_cells())).size()) + << nTotalToInsert - nNotInserted + << " / " << nTotalToInsert << endl; + + nTotalToInsert -= nNotInserted; + } + else + { + Info<< " Inserted = " << nTotalToInsert << endl; + } + + return nTotalToInsert; +} + + +template<class Triangulation> +void Foam::DistributedDelaunayMesh<Triangulation>::sync +( + const boundBox& bb, + PtrList<labelPairHashSet>& referralVertices, + labelPairHashSet& receivedVertices, + bool iterateReferral +) +{ + if (!Pstream::parRun()) + { + return; + } + + if (allBackgroundMeshBounds_.empty()) + { + distributeBoundBoxes(bb); + } + + label nVerts = Triangulation::number_of_vertices(); + label nCells = Triangulation::number_of_finite_cells(); + + DynamicList<Vb> parallelInfluenceVertices(0.1*nVerts); + DynamicList<label> targetProcessor(0.1*nVerts); + + // Some of these values will not be used, i.e. for non-real cells + DynamicList<Foam::point> circumcentre(0.1*nVerts); + DynamicList<scalar> circumradiusSqr(0.1*nVerts); + + Map<labelList> circumsphereOverlaps(nCells); + + findProcessorBoundaryCells(circumsphereOverlaps); + + Info<< " Influences = " + << setw(name(nCells).size()) + << returnReduce(circumsphereOverlaps.size(), sumOp<label>()) << " / " + << returnReduce(nCells, sumOp<label>()); + + markVerticesToRefer + ( + circumsphereOverlaps, + referralVertices, + targetProcessor, + parallelInfluenceVertices + ); + + referVertices + ( + targetProcessor, + parallelInfluenceVertices, + referralVertices, + receivedVertices + ); + + if (iterateReferral) + { + label oldNReferred = 0; + label nIterations = 1; + + Info<< incrIndent << indent + << "Iteratively referring referred vertices..." + << endl; + do + { + Info<< indent << "Iteration " << nIterations++ << ":"; + + circumsphereOverlaps.clear(); + targetProcessor.clear(); + parallelInfluenceVertices.clear(); + + findProcessorBoundaryCells(circumsphereOverlaps); + + nCells = Triangulation::number_of_finite_cells(); + + Info<< " Influences = " + << setw(name(nCells).size()) + << returnReduce(circumsphereOverlaps.size(), sumOp<label>()) + << " / " + << returnReduce(nCells, sumOp<label>()); + + markVerticesToRefer + ( + circumsphereOverlaps, + referralVertices, + targetProcessor, + parallelInfluenceVertices + ); + + label nReferred = referVertices + ( + targetProcessor, + parallelInfluenceVertices, + referralVertices, + receivedVertices + ); + + if (nReferred == 0 || nReferred == oldNReferred) + { + break; + } + + oldNReferred = nReferred; + + } while (true); + + Info<< decrIndent; + } +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +template<class Triangulation> +bool Foam::DistributedDelaunayMesh<Triangulation>::distribute +( + const boundBox& bb +) +{ + notImplemented + ( + "Foam::DistributedDelaunayMesh<Triangulation>::distribute" + "(" + " const boundBox& bb" + ")" + ); + + if (!Pstream::parRun()) + { + return false; + } + + distributeBoundBoxes(bb); + + return true; +} + + +template<class Triangulation> +Foam::autoPtr<Foam::mapDistribute> +Foam::DistributedDelaunayMesh<Triangulation>::distribute +( + const backgroundMeshDecomposition& decomposition +) +{ + if (!Pstream::parRun()) + { + return autoPtr<mapDistribute>(); + } + + distributeBoundBoxes(decomposition.procBounds()); + + DynamicList<point> points(Triangulation::number_of_vertices()); + + for + ( + Finite_vertices_iterator vit = Triangulation::finite_vertices_begin(); + vit != Triangulation::finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + points.append(topoint(vit->point())); + } + } + + autoPtr<mapDistribute> mapDist = decomposition.distributePoints(points); + + return mapDist; +} + + +template<class Triangulation> +void Foam::DistributedDelaunayMesh<Triangulation>::sync(const boundBox& bb) +{ + if (!Pstream::parRun()) + { + return; + } + + if (allBackgroundMeshBounds_.empty()) + { + distributeBoundBoxes(bb); + } + + const label nApproxReferred = + Triangulation::number_of_vertices() + /Pstream::nProcs(); + + PtrList<labelPairHashSet> referralVertices(Pstream::nProcs()); + forAll(referralVertices, procI) + { + if (!isLocal(procI)) + { + referralVertices.set(procI, new labelPairHashSet(nApproxReferred)); + } + } + + labelPairHashSet receivedVertices(nApproxReferred); + + sync + ( + bb, + referralVertices, + receivedVertices, + true + ); +} + + +template<class Triangulation> +template<class PointIterator> +typename Foam::DistributedDelaunayMesh<Triangulation>::labelPairHashSet +Foam::DistributedDelaunayMesh<Triangulation>::rangeInsertReferredWithInfo +( + PointIterator begin, + PointIterator end, + bool printErrors +) +{ + const boundBox& bb = allBackgroundMeshBounds_()[Pstream::myProcNo()]; + + typedef DynamicList + < + std::pair<scalar, label> + > vectorPairPointIndex; + + vectorPairPointIndex pointsBbDistSqr; + + label count = 0; + for (PointIterator it = begin; it != end; ++it) + { + const scalar distFromBbSqr = bb.distanceFromBoxSqr + ( + topoint(it->point()) + ); + + pointsBbDistSqr.append + ( + std::make_pair(distFromBbSqr, count++) + ); + } + + std::random_shuffle(pointsBbDistSqr.begin(), pointsBbDistSqr.end()); + + // Sort in ascending order by the distance of the point from the centre + // of the processor bounding box + sort(pointsBbDistSqr.begin(), pointsBbDistSqr.end()); + + typename Triangulation::Vertex_handle hint; + + typename Triangulation::Locate_type lt; + int li, lj; + + label nNotInserted = 0; + + labelPairHashSet uninserted + ( + Triangulation::number_of_vertices() + /Pstream::nProcs() + ); + + for + ( + typename vectorPairPointIndex::const_iterator p = + pointsBbDistSqr.begin(); + p != pointsBbDistSqr.end(); + ++p + ) + { + const size_t checkInsertion = Triangulation::number_of_vertices(); + + const Vb& vert = *(begin + p->second); + const Point& pointToInsert = vert.point(); + + // Locate the point + Cell_handle c = Triangulation::locate(pointToInsert, lt, li, lj, hint); + + if (lt == Triangulation::VERTEX) + { + if (printErrors) + { + Vertex_handle nearV = + Triangulation::nearest_vertex(pointToInsert); + + Pout<< "Failed insertion, point already exists" << nl + << "Failed insertion : " << vert.info() + << " nearest : " << nearV->info(); + } + + uninserted.insert(labelPair(vert.procIndex(), vert.index())); + nNotInserted++; + + continue; + } + + // Get the cells that conflict with p in a vector V, + // and a facet on the boundary of this hole in f. + std::vector<Cell_handle> V; + typename Triangulation::Facet f; + + Triangulation::find_conflicts + ( + pointToInsert, + c, + CGAL::Oneset_iterator<typename Triangulation::Facet>(f), + std::back_inserter(V) + ); + + bool insert = false; + for (size_t i = 0; i < V.size(); ++i) + { + if (V[i]->real() || V[i]->hasFarPoint()) + { + insert = true; + break; + } + } + + if (insert) + { + hint = Triangulation::insert_in_hole + ( + pointToInsert, + V.begin(), + V.end(), + f.first, + f.second + ); + + if (checkInsertion != Triangulation::number_of_vertices() - 1) + { + if (printErrors) + { + Vertex_handle nearV = + Triangulation::nearest_vertex(pointToInsert); + + Pout<< "Failed insertion : " << vert.info() + << " nearest : " << nearV->info(); + } + } + else + { + hint->index() = vert.index(); + hint->type() = vert.type(); + hint->procIndex() = vert.procIndex(); + hint->targetCellSize() = vert.targetCellSize(); + hint->alignment() = vert.alignment(); + } + } + else + { + uninserted.insert(labelPair(vert.procIndex(), vert.index())); + nNotInserted++; + } + } + + return uninserted; +} + + +// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.H new file mode 100644 index 00000000000..124f4b39dc1 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/DelaunayMesh/DistributedDelaunayMesh.H @@ -0,0 +1,207 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::DistributedDelaunayMesh + +Description + +SourceFiles + DistributedDelaunayMeshI.H + DistributedDelaunayMesh.C + DistributedDelaunayMeshIO.C + +\*---------------------------------------------------------------------------*/ + +#ifndef DistributedDelaunayMesh_H +#define DistributedDelaunayMesh_H + +#include "DelaunayMesh.H" +#include "backgroundMeshDecomposition.H" +#include "autoPtr.H" +#include "boundBox.H" +#include "indexedVertex.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class mapDistribute; + +/*---------------------------------------------------------------------------*\ + Class DistributedDelaunayMesh Declaration +\*---------------------------------------------------------------------------*/ + +template<class Triangulation> +class DistributedDelaunayMesh +: + public DelaunayMesh<Triangulation> +{ +public: + + typedef typename Triangulation::Vertex_handle Vertex_handle; + typedef typename Triangulation::Cell_handle Cell_handle; + typedef typename Triangulation::Point Point; + + typedef typename Triangulation::Finite_vertices_iterator + Finite_vertices_iterator; + typedef typename Triangulation::Finite_cells_iterator + Finite_cells_iterator; + typedef typename Triangulation::All_cells_iterator + All_cells_iterator; + + typedef typename DelaunayMesh<Triangulation>::labelPairHashSet + labelPairHashSet; + + +private: + + autoPtr<List<boundBox> > allBackgroundMeshBounds_; + + + // Private Member Functions + + //- + bool distributeBoundBoxes(const boundBox& bb); + + //- + bool isLocal(const Vertex_handle& v) const; + + bool isLocal(const label localProcIndex) const; + + labelList overlapProcessors + ( + const point& centre, + const scalar radiusSqr + ) const; + + bool checkProcBoundaryCell + ( + const Cell_handle& cit, + Map<labelList>& circumsphereOverlaps + ) const; + + void findProcessorBoundaryCells + ( + Map<labelList>& circumsphereOverlaps + ) const; + + void markVerticesToRefer + ( + const Map<labelList>& circumsphereOverlaps, + PtrList<labelPairHashSet>& referralVertices, + DynamicList<label>& targetProcessor, + DynamicList<Vb>& parallelInfluenceVertices + ); + + label referVertices + ( + const DynamicList<label>& targetProcessor, + DynamicList<Vb>& parallelVertices, + PtrList<labelPairHashSet>& referralVertices, + labelPairHashSet& receivedVertices + ); + + //- Disallow default bitwise copy construct + DistributedDelaunayMesh(const DistributedDelaunayMesh<Triangulation>&); + + //- Disallow default bitwise assignment + void operator=(const DistributedDelaunayMesh<Triangulation>&); + + +public: + + // Constructors + + //- Construct from components + DistributedDelaunayMesh(); + + + //- Destructor + ~DistributedDelaunayMesh(); + + + // Member Functions + + //- Build a mapDistribute for the supplied destination processor data + static autoPtr<mapDistribute> buildMap(const List<label>& toProc); + + //- + bool distribute(const boundBox& bb); + + autoPtr<mapDistribute> distribute + ( + const backgroundMeshDecomposition& decomposition + ); + + //- Refer vertices so that the processor interfaces are consistent + void sync(const boundBox& bb); + + //- Refer vertices so that the processor interfaces are consistent + void sync + ( + const boundBox& bb, + PtrList<labelPairHashSet>& referralVertices, + labelPairHashSet& receivedVertices, + bool iterateReferral = true + ); + + //- Inserts points into the triangulation if the point is within + // the circumsphere of another cell + template<class PointIterator> + labelPairHashSet rangeInsertReferredWithInfo + ( + PointIterator begin, + PointIterator end, + bool printErrors = true + ); + +// distributeField(); + + + // Queries + + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//#include "DistributedDelaunayMeshI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "DistributedDelaunayMesh.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files index 3974c7df757..c6e553f64c3 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/files @@ -1,5 +1,8 @@ #include CGAL_FILES +conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C +conformalVoronoiMesh/indexedCell/indexedCellEnum.C + conformalVoronoiMesh/conformalVoronoiMesh.C conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C @@ -13,7 +16,20 @@ conformationSurfaces/conformationSurfaces.C backgroundMeshDecomposition/backgroundMeshDecomposition.C -cellSizeControlSurfaces/cellSizeControlSurfaces.C +cellShapeControl/cellShapeControl/cellShapeControl.C + +cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C + +cellSizeAndAlignmentControl = cellShapeControl/cellSizeAndAlignmentControl +$(cellSizeAndAlignmentControl)/cellSizeAndAlignmentControls.C +$(cellSizeAndAlignmentControl)/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.C +$(cellSizeAndAlignmentControl)/fileControl/fileControl.C +$(cellSizeAndAlignmentControl)/searchableSurfaceControl/searchableSurfaceControl.C +/*cellShapeControl/pQuadCoorControl/pQuadCoorControl.C*/ + +cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.C + +/*cellSizeControlSurfaces/cellSizeControlSurfaces.C*/ cellSizeFunctions = cellSizeControlSurfaces/cellSizeFunction $(cellSizeFunctions)/cellSizeFunction/cellSizeFunction.C diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options index 2082f88ff04..4a072aa5931 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/Make/options @@ -2,7 +2,7 @@ EXE_DEBUG = -DFULLDEBUG -g -O0 EXE_FROUNDING_MATH = -frounding-math EXE_NDEBUG = -DNDEBUG -CGAL_EXACT = +CGAL_EXACT = /*-DCGAL_DONT_USE_LAZY_KERNEL*/ CGAL_INEXACT = -DCGAL_INEXACT include $(GENERAL_RULES)/CGAL @@ -20,6 +20,8 @@ EXE_INC = \ -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/dynamicMesh/lnInclude \ -I$(LIB_SRC)/triSurface/lnInclude \ + -I$(LIB_SRC)/sampling/lnInclude \ + -IPrintTable \ -I../vectorTools EXE_LIBS = \ @@ -27,4 +29,5 @@ EXE_LIBS = \ -ledgeMesh \ -lfileFormats \ -ltriSurface \ - -ldynamicMesh + -ldynamicMesh \ + -lsampling diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.C new file mode 100644 index 00000000000..ee46bff3669 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.C @@ -0,0 +1,241 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "PrintTable.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +template<class KeyType, class DataType> +Foam::PrintTable<KeyType, DataType>::PrintTable() +: + table_(), + title_(string::null) +{} + + +template<class KeyType, class DataType> +Foam::PrintTable<KeyType, DataType>::PrintTable(const string& title) +: + table_(), + title_(title) +{} + + +template<class KeyType, class DataType> +Foam::PrintTable<KeyType, DataType>::PrintTable +( + const PrintTable<KeyType, DataType>& table +) +: + table_(table.table_), + title_(table.title_) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +template<class KeyType, class DataType> +Foam::PrintTable<KeyType, DataType>::~PrintTable() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +template<class KeyType, class DataType> +void Foam::PrintTable<KeyType, DataType>::print +( + Ostream& os, + const bool printSum, + const bool printAverage +) const +{ + HashTable<HashTable<DataType, label>, KeyType> combinedTable; + + List<HashTable<DataType, KeyType> > procData + ( + Pstream::nProcs(), + HashTable<DataType, KeyType>() + ); + + procData[Pstream::myProcNo()] = table_; + + Pstream::gatherList(procData); + + if (Pstream::master()) + { + label largestKeyLength = 6; + label largestDataLength = 0; + + List<label> largestProcSize(Pstream::nProcs(), 0); + + forAll(procData, procI) + { + const HashTable<DataType, KeyType>& procIData + = procData[procI]; + + for + ( + typename HashTable<DataType, KeyType> + ::const_iterator iter = procIData.begin(); + iter != procIData.end(); + ++iter + ) + { + if (!combinedTable.found(iter.key())) + { + combinedTable.insert + ( + iter.key(), + HashTable<DataType, label>() + ); + } + + HashTable<DataType, label>& key + = combinedTable[iter.key()]; + + key.insert(procI, iter()); + + for + ( + typename HashTable<DataType, label> + ::const_iterator dataIter = key.begin(); + dataIter != key.end(); + ++dataIter + ) + { + std::ostringstream buf; + buf << dataIter(); + + largestDataLength = max + ( + largestDataLength, + label(buf.str().length()) + ); + } + + std::ostringstream buf; + buf << iter.key(); + + largestKeyLength = max + ( + largestKeyLength, + label(buf.str().length()) + ); + } + } + + os.width(largestKeyLength); + os << nl << indent << tab << title_.c_str() << endl; + + os.width(largestKeyLength); + os << indent << "Proc #"; + forAll(procData, procI) + { + os << tab; + os.width(largestDataLength); + os << procI; + } + + if (printSum) + { + os << tab; + os.width(largestDataLength); + os << "Sum"; + } + + if (printAverage) + { + os << tab; + os.width(largestDataLength); + os << "Average"; + } + + os << endl; + + const List<KeyType>& sortedTable = combinedTable.sortedToc(); + + forAll(sortedTable, keyI) + { + const HashTable<DataType, label>& procDataList + = combinedTable[sortedTable[keyI]]; + + os.width(largestKeyLength); + os << indent << sortedTable[keyI]; + + forAll(procDataList, elemI) + { + os << tab; + os.width(largestDataLength); + os << procDataList[elemI]; + } + + if (printSum) + { + DataType sum = 0; + forAll(procDataList, elemI) + { + sum += procDataList[elemI]; + } + + os << tab; + os.width(largestDataLength); + os << sum; + + if (printAverage) + { + os << tab; + os.width(largestDataLength); + os << sum/Pstream::nProcs(); + } + } + + os << endl; + } + } +} + + +// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // + +template<class KeyType, class DataType> +void Foam::PrintTable<KeyType, DataType>::operator= +( + const PrintTable<KeyType, DataType>& rhs +) +{ + // Check for assignment to self + if (this == &rhs) + { + FatalErrorIn + ( + "Foam::PrintTable<KeyType, DataType>::operator=" + "(const Foam::PrintTable<KeyType, DataType>&)" + ) << "Attempted assignment to self" + << abort(FatalError); + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.H new file mode 100644 index 00000000000..7f9ed788713 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTable.H @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::PrintTable + +Description + Print a table in parallel, e.g.; + + \verbatim + Vertex Type Information + Proc # 0 1 2 3 + Total 145680 145278 145751 145359 + Unassigned 0 0 0 0 + nExternalFeatureEdge 883 829 828 960 + nExternalFeaturePoint 8 10 10 12 + nExternalSurface 9533 9488 9502 9482 + nFar 0 0 0 0 + nInternal 125494 125198 125642 125174 + nInternalFeatureEdge 238 241 241 240 + nInternalFeaturePoint 2 2 2 2 + nInternalNearBoundary 0 0 0 0 + nInternalSurface 9522 9510 9526 9489 + nReferred 7545 7497 7500 7587 + \endverbatim + +SourceFiles + PrintTableI.H + PrintTable.C + +\*---------------------------------------------------------------------------*/ + +#ifndef PrintTable_H +#define PrintTable_H + +#include "HashTable.H" +#include "Ostream.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class PrintTable Declaration +\*---------------------------------------------------------------------------*/ + +template<class KeyType, class DataType> +class PrintTable +{ + // Private data + + //- Hash table holding the data + HashTable<DataType, KeyType> table_; + + //- Title of the table + string title_; + + + // Private Member Functions + + //- Disallow default bitwise assignment + void operator=(const PrintTable<KeyType, DataType>&); + + +public: + + // Constructors + + //- Null constructor + PrintTable(); + + //- Construct with a title + explicit PrintTable(const string& title); + + //- Copy constructor + PrintTable(const PrintTable<KeyType, DataType>& table); + + + //- Destructor + ~PrintTable(); + + + // Member Functions + + //- Add an entry (D) to the given key(K) + void add(const KeyType& K, const DataType& D); + + //- Print the table + void print + ( + Ostream& os, + const bool printSum = false, + const bool printAverage = false + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "PrintTableI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "PrintTable.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTableI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTableI.H new file mode 100644 index 00000000000..6c093bc13a2 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/PrintTable/PrintTableI.H @@ -0,0 +1,42 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class KeyType, class DataType> +void Foam::PrintTable<KeyType, DataType>::add +( + const KeyType& K, + const DataType& D +) +{ + table_.set(K, D); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C index cf7a1eb9021..6e49d111a0b 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.C @@ -25,6 +25,10 @@ License #include "backgroundMeshDecomposition.H" #include "meshSearch.H" +#include "conformationSurfaces.H" +#include "zeroGradientFvPatchFields.H" +#include "Time.H" +#include "Random.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -377,7 +381,7 @@ void Foam::backgroundMeshDecomposition::initialRefinement() if (oldCellI == -1) { newVolumeStatus[newCellI] = - searchableSurface::UNKNOWN;; + searchableSurface::UNKNOWN; } else { @@ -413,8 +417,10 @@ void Foam::backgroundMeshDecomposition::initialRefinement() fvMeshDistribute distributor(mesh_, mergeDist_); - autoPtr<mapDistributePolyMesh> mapDist = - distributor.distribute(newDecomp); + autoPtr<mapDistributePolyMesh> mapDist = distributor.distribute + ( + newDecomp + ); meshCutter_.distribute(mapDist); @@ -527,87 +533,87 @@ bool Foam::backgroundMeshDecomposition::refineCell if (volType == searchableSurface::MIXED) { - // Assess the cell size at the nearest point on the surface for the - // MIXED cells, if the cell is large with respect to the cell size, - // then refine it. - - pointField samplePoints - ( - volRes_*volRes_*volRes_, - vector::zero - ); - - // scalar sampleVol = cellBb.volume()/samplePoints.size(); - - vector delta = cellBb.span()/volRes_; - - label pI = 0; - - for (label i = 0; i < volRes_; i++) - { - for (label j = 0; j < volRes_; j++) - { - for (label k = 0; k < volRes_; k++) - { - samplePoints[pI++] = - cellBb.min() - + vector - ( - delta.x()*(i + 0.5), - delta.y()*(j + 0.5), - delta.z()*(k + 0.5) - ); - } - } - } - - List<pointIndexHit> hitInfo; - labelList hitSurfaces; - - geometry.findSurfaceNearest - ( - samplePoints, - scalarField(samplePoints.size(), sqr(GREAT)), - hitInfo, - hitSurfaces - ); - - // weightEstimate = 0.0; - - scalar minCellSize = GREAT; - - forAll(samplePoints, i) - { - scalar s = cellSizeControl_.cellSize - ( - hitInfo[i].hitPoint() - ); - - // Info<< "cellBb.midpoint() " << cellBb.midpoint() << nl - // << samplePoints[i] << nl - // << hitInfo[i] << nl - // << "cellBb.span() " << cellBb.span() << nl - // << "cellBb.mag() " << cellBb.mag() << nl - // << s << endl; - - if (s < minCellSize) - { - minCellSize = max(s, minCellSizeLimit_); - } - - // Estimate the number of points in the cell by the surface size, - // this is likely to be too small, so reduce. - // weightEstimate += sampleVol/pow3(s); - } - - if (sqr(spanScale_)*sqr(minCellSize) < magSqr(cellBb.span())) - { - return true; - } +// // Assess the cell size at the nearest point on the surface for the +// // MIXED cells, if the cell is large with respect to the cell size, +// // then refine it. +// +// pointField samplePoints +// ( +// volRes_*volRes_*volRes_, +// vector::zero +// ); +// +// // scalar sampleVol = cellBb.volume()/samplePoints.size(); +// +// vector delta = cellBb.span()/volRes_; +// +// label pI = 0; +// +// for (label i = 0; i < volRes_; i++) +// { +// for (label j = 0; j < volRes_; j++) +// { +// for (label k = 0; k < volRes_; k++) +// { +// samplePoints[pI++] = +// cellBb.min() +// + vector +// ( +// delta.x()*(i + 0.5), +// delta.y()*(j + 0.5), +// delta.z()*(k + 0.5) +// ); +// } +// } +// } +// +// List<pointIndexHit> hitInfo; +// labelList hitSurfaces; +// +// geometry.findSurfaceNearest +// ( +// samplePoints, +// scalarField(samplePoints.size(), sqr(GREAT)), +// hitInfo, +// hitSurfaces +// ); +// +// // weightEstimate = 0.0; +// +// scalar minCellSize = GREAT; +// +// forAll(samplePoints, i) +// { +// scalar s = cellShapeControl_.cellSize +// ( +// hitInfo[i].hitPoint() +// ); +// +// // Info<< "cellBb.midpoint() " << cellBb.midpoint() << nl +// // << samplePoints[i] << nl +// // << hitInfo[i] << nl +// // << "cellBb.span() " << cellBb.span() << nl +// // << "cellBb.mag() " << cellBb.mag() << nl +// // << s << endl; +// +// if (s < minCellSize) +// { +// minCellSize = max(s, minCellSizeLimit_); +// } +// +// // Estimate the number of points in the cell by the surface size, +// // this is likely to be too small, so reduce. +// // weightEstimate += sampleVol/pow3(s); +// } +// +// if (sqr(spanScale_)*sqr(minCellSize) < magSqr(cellBb.span())) +// { +// return true; +// } } else if (volType == searchableSurface::INSIDE) { - // scalar s = cvMesh_.cellSizeControl().cellSize(cellBb.midpoint()); + // scalar s = cvMesh_.cellShapeControl_.cellSize(cellBb.midpoint()); // Estimate the number of points in the cell by the size at the cell // midpoint @@ -724,9 +730,7 @@ void Foam::backgroundMeshDecomposition::buildPatchAndTree() globalBackgroundBounds_ = treeBoundBox(bbMin, bbMax); - octreeNearestDistances_ = bFTreePtr_().calcNearestDistance(); - - if (cvMeshControls_.objOutput()) + if (false) { OFstream fStr ( @@ -773,15 +777,15 @@ void Foam::backgroundMeshDecomposition::buildPatchAndTree() Foam::backgroundMeshDecomposition::backgroundMeshDecomposition ( - const dictionary& coeffsDict, - const conformalVoronoiMesh& cvMesh + const Time& runTime, + Random& rndGen, + const conformationSurfaces& geometryToConformTo, + const dictionary& coeffsDict ) : - runTime_(cvMesh.time()), - geometryToConformTo_(cvMesh.geometryToConformTo()), - cellSizeControl_(cvMesh.cellSizeControl()), - rndGen_(cvMesh.rndGen()), - cvMeshControls_(cvMesh.cvMeshControls()), + runTime_(runTime), + geometryToConformTo_(geometryToConformTo), + rndGen_(rndGen), mesh_ ( IOobject @@ -800,7 +804,6 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition ), boundaryFacesPtr_(), bFTreePtr_(), - octreeNearestDistances_(), allBackgroundMeshBounds_(Pstream::nProcs()), globalBackgroundBounds_(), decomposeDict_ @@ -857,74 +860,6 @@ Foam::backgroundMeshDecomposition::backgroundMeshDecomposition } -Foam::backgroundMeshDecomposition::backgroundMeshDecomposition -( - const scalar spanScale, - const scalar minCellSizeLimit, - const label minLevels, - const label volRes, - const scalar maxCellWeightCoeff, - - const Time& runTime, - const conformationSurfaces& geometryToConformTo, - const cellSizeControlSurfaces& cellSizeControl, - Random& rndGen, - const cvControls& cvMeshControls -) -: - runTime_(runTime), - geometryToConformTo_(geometryToConformTo), - cellSizeControl_(cellSizeControl), - rndGen_(rndGen), - cvMeshControls_(cvMeshControls), - mesh_ - ( - IOobject - ( - fvMesh::defaultRegion, - runTime_.timeName(), - runTime_, - IOobject::MUST_READ - ) - ), - meshCutter_ - ( - mesh_, - labelList(mesh_.nCells(), 0), - labelList(mesh_.nPoints(), 0) - ), - boundaryFacesPtr_(), - bFTreePtr_(), - octreeNearestDistances_(), - allBackgroundMeshBounds_(Pstream::nProcs()), - globalBackgroundBounds_(), - decomposeDict_ - ( - IOobject - ( - "decomposeParDict", - runTime_.system(), - runTime_, - IOobject::MUST_READ_IF_MODIFIED, - IOobject::NO_WRITE - ) - ), - decomposerPtr_(decompositionMethod::New(decomposeDict_)), - mergeDist_(1e-6*mesh_.bounds().mag()), - spanScale_(spanScale), - minCellSizeLimit_(minCellSizeLimit), - minLevels_(minLevels), - volRes_(volRes), - maxCellWeightCoeff_(maxCellWeightCoeff) -{ - // Stand-alone operation - - Info<< nl << "Building initial background mesh decomposition" << endl; - - initialRefinement(); -} - - // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // Foam::backgroundMeshDecomposition::~backgroundMeshDecomposition() @@ -936,10 +871,7 @@ Foam::backgroundMeshDecomposition::~backgroundMeshDecomposition() Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::backgroundMeshDecomposition::distribute ( - volScalarField& cellWeights, - List<DynamicList<point> >& cellVertices, - List<DynamicList<label> >& cellVertexIndices, - List<DynamicList<label> >& cellVertexTypes + volScalarField& cellWeights ) { if (debug) @@ -982,10 +914,8 @@ Foam::backgroundMeshDecomposition::distribute { Info<< " cellWeightLimit " << cellWeightLimit << endl; - Pout<< " sum(cellWeights) " - << sum(cellWeights.internalField()) - << " max(cellWeights) " - << max(cellWeights.internalField()) + Pout<< " sum(cellWeights) " << sum(cellWeights.internalField()) + << " max(cellWeights) " << max(cellWeights.internalField()) << endl; } @@ -1049,94 +979,6 @@ Foam::backgroundMeshDecomposition::distribute // Update numbering of cells/vertices. meshCutter_.updateMesh(map); - { - // Map cellVertices, cellVertexIndices and cellVertexTypes - - meshSearch cellSearch(mesh_, polyMesh::FACEPLANES); - - const labelList& reverseCellMap = map().reverseCellMap(); - - List<DynamicList<point> > newCellVertices(mesh_.nCells()); - List<DynamicList<label> > newCellVertexIndices(mesh_.nCells()); - List<DynamicList<label> > newCellVertexTypes(mesh_.nCells()); - - forAll(cellVertices, oldCellI) - { - DynamicList<point>& oldCellVertices = - cellVertices[oldCellI]; - - DynamicList<label>& oldCellVertexIndices = - cellVertexIndices[oldCellI]; - - DynamicList<label>& oldCellVertexTypes = - cellVertexTypes[oldCellI]; - - if (findIndex(newCellsToRefine, oldCellI) >= 0) - { - // This old cell was refined so the cell for the vertices - // in the new mesh needs to be searched for. - - forAll(oldCellVertices, oPI) - { - const point& v = oldCellVertices[oPI]; - - label newCellI = cellSearch.findCell(v); - - if (newCellI == -1) - { - // Pout<< "findCell backgroundMeshDecomposition " - // << v << " " - // << oldCellI - // << newCellI - // << " find nearest cellI "; - - newCellI = cellSearch.findNearestCell(v); - - // Pout<< newCellI << endl; - } - - newCellVertices[newCellI].append(v); - - newCellVertexIndices[newCellI].append - ( - oldCellVertexIndices[oPI] - ); - - newCellVertexTypes[newCellI].append - ( - oldCellVertexTypes[oPI] - ); - } - } - else - { - label newCellI = reverseCellMap[oldCellI]; - - forAll(oldCellVertices, oPI) - { - newCellVertices[newCellI].append - ( - oldCellVertices[oPI] - ); - - newCellVertexIndices[newCellI].append - ( - oldCellVertexIndices[oPI] - ); - - newCellVertexTypes[newCellI].append - ( - oldCellVertexTypes[oPI] - ); - } - } - } - - cellVertices.transfer(newCellVertices); - cellVertexIndices.transfer(newCellVertexIndices); - cellVertexTypes.transfer(newCellVertexTypes); - } - Info<< " Background mesh refined from " << returnReduce(map().nOldCells(), sumOp<label>()) << " to " << mesh_.globalData().nTotalCells() @@ -1193,10 +1035,6 @@ Foam::backgroundMeshDecomposition::distribute cellWeights.write(); } - mapDist().distributeCellData(cellVertices); - mapDist().distributeCellData(cellVertexIndices); - mapDist().distributeCellData(cellVertexTypes); - buildPatchAndTree(); return mapDist; @@ -1227,8 +1065,10 @@ bool Foam::backgroundMeshDecomposition::positionOnThisProcessor // return bFTreePtr_().findAnyOverlap(pt, 0.0); return + ( bFTreePtr_().getVolumeType(pt) - == indexedOctree<treeDataBPatch>::INSIDE; + == indexedOctree<treeDataBPatch>::INSIDE + ); } @@ -1247,6 +1087,7 @@ Foam::boolList Foam::backgroundMeshDecomposition::positionOnThisProcessor return posProc; } + bool Foam::backgroundMeshDecomposition::overlapsThisProcessor ( const treeBoundBox& box @@ -1660,110 +1501,304 @@ Foam::backgroundMeshDecomposition::intersectsProcessors } -Foam::labelListList Foam::backgroundMeshDecomposition::overlapsProcessors +bool Foam::backgroundMeshDecomposition::overlapsOtherProcessors ( - const List<point>& centres, - const List<scalar>& radiusSqrs, - bool includeOwnProcessor + const point& centre, + const scalar& radiusSqr ) const { - DynamicList<label> toCandidateProc; - DynamicList<point> testCentres; - DynamicList<scalar> testRadiusSqrs; - labelList sphereBlockStart(centres.size(), -1); - labelList sphereBlockSize(centres.size(), -1); - - label nTotalCandidates = 0; - - forAll(centres, sI) + forAll(allBackgroundMeshBounds_, procI) { - const point& c = centres[sI]; - scalar rSqr = radiusSqrs[sI]; - - label nCandidates = 0; - - forAll(allBackgroundMeshBounds_, procI) + if (bFTreePtr_().findNearest(centre, radiusSqr).hit()) { - // It is assumed that the sphere in question overlaps the source - // processor, so don't test it, unless includeOwnProcessor is true - if - ( - (includeOwnProcessor || procI != Pstream::myProcNo()) - && allBackgroundMeshBounds_[procI].overlaps(c, rSqr) - ) - { - toCandidateProc.append(procI); - testCentres.append(c); - testRadiusSqrs.append(rSqr); - - nCandidates++; - } + return true; } - - sphereBlockStart[sI] = nTotalCandidates; - sphereBlockSize[sI] = nCandidates; - - nTotalCandidates += nCandidates; } - // Needed for reverseDistribute - label preDistributionToCandidateProcSize = toCandidateProc.size(); - - autoPtr<mapDistribute> map(buildMap(toCandidateProc)); - - map().distribute(testCentres); - map().distribute(testRadiusSqrs); - - List<bool> sphereOverlapsCandidate(testCentres.size(), false); - - // Test candidate spheres on candidate processors - forAll(testCentres, sI) - { - const point& c = testCentres[sI]; - scalar rSqr = testRadiusSqrs[sI]; - - // If the sphere finds a nearest element of the patch, then it overlaps - sphereOverlapsCandidate[sI] = bFTreePtr_().findNearest(c, rSqr).hit(); - //sphereOverlapsCandidate[sI] = bFTreePtr_().findAnyOverlap(c, rSqr); - } - - map().reverseDistribute - ( - preDistributionToCandidateProcSize, - sphereOverlapsCandidate - ); + return false; +} - labelListList sphereProcs(centres.size()); - // Working storage for assessing processors - DynamicList<label> tmpProcs; +Foam::labelList Foam::backgroundMeshDecomposition::overlapProcessors +( + const point& centre, + const scalar radiusSqr +) const +{ + DynamicList<label> toProc(Pstream::nProcs()); - forAll(centres, sI) + forAll(allBackgroundMeshBounds_, procI) { - tmpProcs.clear(); - - // Extract the sub list of results for this point - - SubList<bool> sphereProcResults + // Test against the bounding box of the processor + if ( - sphereOverlapsCandidate, - sphereBlockSize[sI], - sphereBlockStart[sI] - ); - - forAll(sphereProcResults, sPRI) + procI != Pstream::myProcNo() + && allBackgroundMeshBounds_[procI].overlaps(centre, radiusSqr) + ) { - if (sphereProcResults[sPRI]) + // Expensive test +// if (bFTreePtr_().findNearest(centre, radiusSqr).hit()) { - tmpProcs.append(toCandidateProc[sphereBlockStart[sI] + sPRI]); + toProc.append(procI); } } - - sphereProcs[sI] = tmpProcs; } - return sphereProcs; + return toProc; } +//Foam::labelListList Foam::backgroundMeshDecomposition::overlapsProcessors +//( +// const List<point>& centres, +// const List<scalar>& radiusSqrs, +// const Delaunay& T, +// bool includeOwnProcessor +//) const +//{ +// DynamicList<label> toCandidateProc; +// DynamicList<point> testCentres; +// DynamicList<scalar> testRadiusSqrs; +// labelList sphereBlockStart(centres.size(), -1); +// labelList sphereBlockSize(centres.size(), -1); +// +// label nTotalCandidates = 0; +// +// forAll(centres, sI) +// { +// const point& c = centres[sI]; +// scalar rSqr = radiusSqrs[sI]; +// +// label nCandidates = 0; +// +// forAll(allBackgroundMeshBounds_, procI) +// { +// // It is assumed that the sphere in question overlaps the source +// // processor, so don't test it, unless includeOwnProcessor is true +// if +// ( +// (includeOwnProcessor || procI != Pstream::myProcNo()) +// && allBackgroundMeshBounds_[procI].overlaps(c, rSqr) +// ) +// { +// if (bFTreePtr_().findNearest(c, rSqr).hit()) +// { +// toCandidateProc.append(procI); +// testCentres.append(c); +// testRadiusSqrs.append(rSqr); +// +// nCandidates++; +// } +// } +// } +// +// sphereBlockStart[sI] = nTotalCandidates; +// sphereBlockSize[sI] = nCandidates; +// +// nTotalCandidates += nCandidates; +// } +// +// // Needed for reverseDistribute +//// label preDistributionToCandidateProcSize = toCandidateProc.size(); +//// +//// autoPtr<mapDistribute> map(buildMap(toCandidateProc)); +//// +//// map().distribute(testCentres); +//// map().distribute(testRadiusSqrs); +// +// // @todo This is faster, but results in more vertices being referred +// boolList sphereOverlapsCandidate(testCentres.size(), true); +//// boolList sphereOverlapsCandidate(testCentres.size(), false); +//// +//// // Test candidate spheres on candidate processors +//// forAll(testCentres, sI) +//// { +//// const point& c = testCentres[sI]; +//// const scalar rSqr = testRadiusSqrs[sI]; +//// +//// const bool flagOverlap = bFTreePtr_().findNearest(c, rSqr).hit(); +//// +//// if (flagOverlap) +//// { +//// //if (vertexOctree.findAnyOverlap(c, rSqr)) +////// if (vertexOctree.findNearest(c, rSqr*1.001).hit()) +////// { +////// sphereOverlapsCandidate[sI] = true; +////// } +//// +////// Vertex_handle nearestVertex = T.nearest_vertex +////// ( +////// toPoint<Point>(c) +////// ); +////// +////// const scalar distSqr = magSqr +////// ( +////// topoint(nearestVertex->point()) - c +////// ); +////// +////// if (distSqr <= rSqr) +////// { +////// // If the sphere finds a nearest element of the patch, then it +////// // overlaps +//// sphereOverlapsCandidate[sI] = true; +////// } +//// } +//// } +// +//// map().reverseDistribute +//// ( +//// preDistributionToCandidateProcSize, +//// sphereOverlapsCandidate +//// ); +// +// labelListList sphereProcs(centres.size()); +// +// // Working storage for assessing processors +// DynamicList<label> tmpProcs; +// +// forAll(centres, sI) +// { +// tmpProcs.clear(); +// +// // Extract the sub list of results for this point +// +// SubList<bool> sphereProcResults +// ( +// sphereOverlapsCandidate, +// sphereBlockSize[sI], +// sphereBlockStart[sI] +// ); +// +// forAll(sphereProcResults, sPRI) +// { +// if (sphereProcResults[sPRI]) +// { +// tmpProcs.append(toCandidateProc[sphereBlockStart[sI] + sPRI]); +// } +// } +// +// sphereProcs[sI] = tmpProcs; +// } +// +// return sphereProcs; +//} + + +//Foam::labelListList Foam::backgroundMeshDecomposition::overlapProcessors +//( +// const point& cc, +// const scalar rSqr +//) const +//{ +// DynamicList<label> toCandidateProc; +// label sphereBlockStart(-1); +// label sphereBlockSize(-1); +// +// label nCandidates = 0; +// +// forAll(allBackgroundMeshBounds_, procI) +// { +// // It is assumed that the sphere in question overlaps the source +// // processor, so don't test it, unless includeOwnProcessor is true +// if +// ( +// (includeOwnProcessor || procI != Pstream::myProcNo()) +// && allBackgroundMeshBounds_[procI].overlaps(cc, rSqr) +// ) +// { +// toCandidateProc.append(procI); +// +// nCandidates++; +// } +// } +// +// sphereBlockSize = nCandidates; +// nTotalCandidates += nCandidates; +// +// // Needed for reverseDistribute +// label preDistributionToCandidateProcSize = toCandidateProc.size(); +// +// autoPtr<mapDistribute> map(buildMap(toCandidateProc)); +// +// map().distribute(testCentres); +// map().distribute(testRadiusSqrs); +// +// // @todo This is faster, but results in more vertices being referred +//// boolList sphereOverlapsCandidate(testCentres.size(), true); +// boolList sphereOverlapsCandidate(testCentres.size(), false); +// +// // Test candidate spheres on candidate processors +// forAll(testCentres, sI) +// { +// const point& c = testCentres[sI]; +// const scalar rSqr = testRadiusSqrs[sI]; +// +// const bool flagOverlap = bFTreePtr_().findNearest(c, rSqr).hit(); +// +// if (flagOverlap) +// { +// //if (vertexOctree.findAnyOverlap(c, rSqr)) +//// if (vertexOctree.findNearest(c, rSqr*1.001).hit()) +//// { +//// sphereOverlapsCandidate[sI] = true; +//// } +// +//// Vertex_handle nearestVertex = T.nearest_vertex +//// ( +//// toPoint<Point>(c) +//// ); +//// +//// const scalar distSqr = magSqr +//// ( +//// topoint(nearestVertex->point()) - c +//// ); +//// +//// if (distSqr <= rSqr) +//// { +//// // If the sphere finds a nearest element of the patch, then it +//// // overlaps +// sphereOverlapsCandidate[sI] = true; +//// } +// } +// } +// +// map().reverseDistribute +// ( +// preDistributionToCandidateProcSize, +// sphereOverlapsCandidate +// ); +// +// labelListList sphereProcs(centres.size()); +// +// // Working storage for assessing processors +// DynamicList<label> tmpProcs; +// +// forAll(centres, sI) +// { +// tmpProcs.clear(); +// +// // Extract the sub list of results for this point +// +// SubList<bool> sphereProcResults +// ( +// sphereOverlapsCandidate, +// sphereBlockSize[sI], +// sphereBlockStart[sI] +// ); +// +// forAll(sphereProcResults, sPRI) +// { +// if (sphereProcResults[sPRI]) +// { +// tmpProcs.append(toCandidateProc[sphereBlockStart[sI] + sPRI]); +// } +// } +// +// sphereProcs[sI] = tmpProcs; +// } +// +// return sphereProcs; +//} + + // ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H index bcdd1638345..4fe772b9328 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecomposition.H @@ -53,7 +53,6 @@ SourceFiles #ifndef backgroundMeshDecomposition_H #define backgroundMeshDecomposition_H -#include "conformalVoronoiMesh.H" #include "fvMesh.H" #include "hexRef8.H" #include "cellSet.H" @@ -81,6 +80,10 @@ namespace Foam typedef PrimitivePatch<face, List, const pointField, point> bPatch; typedef treeDataPrimitivePatch<bPatch> treeDataBPatch; +class Time; +class Random; +class conformationSurfaces; + /*---------------------------------------------------------------------------*\ Class backgroundMeshDecomposition Declaration \*---------------------------------------------------------------------------*/ @@ -98,15 +101,9 @@ class backgroundMeshDecomposition //- Reference to surface const conformationSurfaces& geometryToConformTo_; - //- The cell size control object - const cellSizeControlSurfaces& cellSizeControl_; - //- Random number generator Random& rndGen_; - //- Controls - const cvControls& cvMeshControls_; - //- Mesh stored on for this processor, specifiying the domain that it // is responsible for. fvMesh mesh_; @@ -121,8 +118,6 @@ class backgroundMeshDecomposition //- Search tree for the boundaryFaces_ patch autoPtr<indexedOctree<treeDataBPatch> > bFTreePtr_; - List<scalar> octreeNearestDistances_; - //- The bounds of all background meshes on all processors treeBoundBoxList allBackgroundMeshBounds_; @@ -204,24 +199,10 @@ public: //- Construct from components in cvMesh operation backgroundMeshDecomposition ( - const dictionary& coeffsDict, - const conformalVoronoiMesh& cvMesh - ); - - //- Construct from components for standalone operation - backgroundMeshDecomposition - ( - const scalar spanScale, - const scalar minCellSizeLimit, - const label minLevels, - const label volRes, - const scalar maxCellWeightCoeff, - const Time& runTime, - const conformationSurfaces& geometryToConformTo, - const cellSizeControlSurfaces& cellSizeControl, Random& rndGen, - const cvControls& cvMeshControls + const conformationSurfaces& geometryToConformTo, + const dictionary& coeffsDict ); @@ -238,10 +219,7 @@ public: // returning a map to use to redistribute vertices. autoPtr<mapDistributePolyMesh> distribute ( - volScalarField& cellWeights, - List<DynamicList<point> >& cellVertices, - List<DynamicList<label> >& cellVertexIndices, - List<DynamicList<label> >& cellVertexTypes + volScalarField& cellWeights ); //- Distribute supplied the points to the appropriate processor @@ -300,18 +278,31 @@ public: bool includeOwnProcessor = false ) const; - //- Which processors overlap the given sphere, returns all processors - // whose boundary patch is touched by the sphere or whom the sphere is - // inside. By default this does not return the processor that the - // query is launched from, it is assumed that the point is on that - // processor. - labelListList overlapsProcessors + bool overlapsOtherProcessors ( - const List<point>& centres, - const List<scalar>& radiusSqrs, - bool includeOwnProcessor = false + const point& centre, + const scalar& radiusSqr + ) const; + + labelList overlapProcessors + ( + const point& centre, + const scalar radiusSqr ) const; +// //- Which processors overlap the given sphere, returns all processors +// // whose boundary patch is touched by the sphere or whom the sphere is +// // inside. By default this does not return the processor that the +// // query is launched from, it is assumed that the point is on that +// // processor. +// labelListList overlapsProcessors +// ( +// const List<point>& centres, +// const List<scalar>& radiusSqrs, +// const Delaunay& T, +// bool includeOwnProcessor +// ) const; + // Access //- Return access to the underlying mesh @@ -320,9 +311,6 @@ public: //- Return access to the underlying tree inline const indexedOctree<treeDataBPatch>& tree() const; - //- Return access to the nearest distance of the octree nodes - inline const List<scalar>& octreeNearestDistances() const; - //- Return the boundBox of this processor inline const treeBoundBox& procBounds() const; diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H index 44a007193d8..1f8b7b0a327 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/backgroundMeshDecomposition/backgroundMeshDecompositionI.H @@ -30,18 +30,13 @@ const Foam::fvMesh& Foam::backgroundMeshDecomposition::mesh() const return mesh_; } + const Foam::indexedOctree<Foam::treeDataBPatch>& Foam::backgroundMeshDecomposition::tree() const { return bFTreePtr_(); } -const Foam::List<Foam::scalar>& -Foam::backgroundMeshDecomposition::octreeNearestDistances() const -{ - return octreeNearestDistances_; -} - const Foam::treeBoundBox& Foam::backgroundMeshDecomposition::procBounds() const diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.C new file mode 100644 index 00000000000..dfba259e674 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.C @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellAspectRatioControl.H" +#include "vectorTools.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellAspectRatioControl::cellAspectRatioControl +( + const dictionary& motionDict +) +: + aspectRatioDict_(motionDict.subOrEmptyDict("cellAspectRatioControl")), + aspectRatio_(aspectRatioDict_.lookupOrDefault<scalar>("aspectRatio", 1.0)), + aspectRatioDirection_ + ( + aspectRatioDict_.lookupOrDefault<vector> + ( + "aspectRatioDirection", + vector(0, 0, 0) + ) + ) +{ + Info<< nl << " Cell Aspect Ratio Control" << nl + << " Ratio : " << aspectRatio_ << nl + << " Direction : " << aspectRatioDirection_ << nl << endl; +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellAspectRatioControl::~cellAspectRatioControl() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::cellAspectRatioControl::updateCellSizeAndFaceArea +( + vector& alignmentDir, + scalar& targetFaceArea, + scalar& targetCellSize +) const +{ + const scalar cosAngle = mag + ( + vectorTools::cosPhi(alignmentDir, aspectRatioDirection_) + ); + + // Change target face area based on aspect ratio + targetFaceArea + += targetFaceArea + *(aspectRatio_ - 1.0) + *(1.0 - cosAngle); + + // Change target cell size based on aspect ratio + targetCellSize + += targetCellSize + *(aspectRatio_ - 1.0) + *cosAngle; + + alignmentDir *= 0.5*targetCellSize; +} + + +void Foam::cellAspectRatioControl::updateDeltaVector +( + const vector& alignmentDir, + const scalar targetCellSize, + const scalar rABMag, + vector& delta +) const +{ + const scalar cosAngle = mag + ( + vectorTools::cosPhi(alignmentDir, aspectRatioDirection_) + ); + + delta += 0.5 + *delta + *cosAngle + *(targetCellSize/rABMag) + *(aspectRatio_ - 1.0); +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.H new file mode 100644 index 00000000000..ac47311940a --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellAspectRatioControl/cellAspectRatioControl.H @@ -0,0 +1,115 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellAspectRatioControl + +Description + +SourceFiles + cellAspectRatioControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellAspectRatioControl_H +#define cellAspectRatioControl_H + +#include "dictionary.H" +#include "vector.H" +#include "scalar.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class cellAspectRatioControl Declaration +\*---------------------------------------------------------------------------*/ + +class cellAspectRatioControl +{ + // Private data + + const dictionary aspectRatioDict_; + + const scalar aspectRatio_; + + const vector aspectRatioDirection_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + cellAspectRatioControl(const cellAspectRatioControl&); + + //- Disallow default bitwise assignment + void operator=(const cellAspectRatioControl&); + + +public: + + // Constructors + + //- Construct from dictionary + cellAspectRatioControl + ( + const dictionary& motionDict + ); + + + //- Destructor + virtual ~cellAspectRatioControl(); + + + // Member Functions + + // Query + + void updateCellSizeAndFaceArea + ( + vector& alignmentDir, + scalar& targetFaceArea, + scalar& targetCellSize + ) const; + + void updateDeltaVector + ( + const vector& alignmentDir, + const scalar targetCellSize, + const scalar rABMag, + vector& delta + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.C new file mode 100644 index 00000000000..102f637c097 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.C @@ -0,0 +1,920 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellShapeControl.H" +#include "pointField.H" +#include "scalarField.H" +#include "cellSizeAndAlignmentControl.H" +#include "searchableSurfaceControl.H" +#include "cellSizeFunction.H" +#include "triad.H" + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + +template <class Triangulation, class Type> +Foam::tmp<Foam::Field<Type> > Foam::cellShapeControl::filterFarPoints +( + const Triangulation& mesh, + const Field<Type>& field +) +{ + tmp<Field<Type> > tNewField(new Field<Type>(field.size())); + Field<Type>& newField = tNewField(); + + label added = 0; + label count = 0; + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + newField[added++] = field[count]; + } + + count++; + } + + newField.resize(added); + + return tNewField; +} + + +template <class Triangulation> +Foam::autoPtr<Foam::mapDistribute> Foam::cellShapeControl::buildReferredMap +( + const Triangulation& mesh, + labelList& indices +) +{ + globalIndex globalIndexing(mesh.vertexCount()); + + DynamicList<label> dynIndices(mesh.vertexCount()/10); + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (vit->referred()) + { + dynIndices.append + ( + globalIndexing.toGlobal(vit->procIndex(), vit->index()) + ); + } + } + + indices.transfer(dynIndices); + + List<Map<label> > compactMap; + return autoPtr<mapDistribute> + ( + new mapDistribute + ( + globalIndexing, + indices, + compactMap + ) + ); +} + + +template <class Triangulation> +Foam::autoPtr<Foam::mapDistribute> Foam::cellShapeControl::buildMap +( + const Triangulation& mesh, + labelListList& pointPoints +) +{ + pointPoints.setSize(mesh.vertexCount()); + + globalIndex globalIndexing(mesh.vertexCount()); + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + std::list<typename Triangulation::Vertex_handle> adjVerts; + mesh.finite_adjacent_vertices(vit, std::back_inserter(adjVerts)); + + DynamicList<label> indices(adjVerts.size()); + + for + ( + typename std::list<typename Triangulation::Vertex_handle>:: + const_iterator adjVertI = adjVerts.begin(); + adjVertI != adjVerts.end(); + ++adjVertI + ) + { + typename Triangulation::Vertex_handle vh = *adjVertI; + + if (!vh->farPoint()) + { + indices.append + ( + globalIndexing.toGlobal(vh->procIndex(), vh->index()) + ); + } + } + + pointPoints[vit->index()].transfer(indices); + } + + List<Map<label> > compactMap; + return autoPtr<mapDistribute> + ( + new mapDistribute + ( + globalIndexing, + pointPoints, + compactMap + ) + ); +} + + +template <class Triangulation> +Foam::tmp<Foam::triadField> Foam::cellShapeControl::buildAlignmentField +( + const Triangulation& mesh +) +{ + tmp<triadField> tAlignments + ( + new triadField(mesh.vertexCount(), triad::unset) + ); + triadField& alignments = tAlignments(); + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + alignments[vit->index()] = triad + ( + vit->alignment().x(), + vit->alignment().y(), + vit->alignment().z() + ); + } + + return tAlignments; +} + + +template <class Triangulation> +Foam::tmp<Foam::pointField> Foam::cellShapeControl::buildPointField +( + const Triangulation& mesh +) +{ + tmp<pointField> tPoints + ( + new pointField(mesh.vertexCount(), point(GREAT, GREAT, GREAT)) + ); + pointField& points = tPoints(); + + for + ( + typename Triangulation::Finite_vertices_iterator vit = + mesh.finite_vertices_begin(); + vit != mesh.finite_vertices_end(); + ++vit + ) + { + if (!vit->real()) + { + continue; + } + + points[vit->index()] = topoint(vit->point()); + } + + return tPoints; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellShapeControl::cellShapeControl +( + const Time& runTime, + const dictionary& motionDict, + const searchableSurfaces& allGeometry, + const conformationSurfaces& geometryToConformTo +) +: + dictionary(motionDict), + runTime_(runTime), + allGeometry_(allGeometry), + geometryToConformTo_(geometryToConformTo), + defaultCellSize_(readScalar(lookup("defaultCellSize"))), + shapeControlMesh_(runTime), + aspectRatio_(motionDict), + sizeAndAlignment_ + ( + runTime, + motionDict.subDict("shapeControlFunctions"), + geometryToConformTo + ) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellShapeControl::~cellShapeControl() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +Foam::scalarField Foam::cellShapeControl::cellSize +( + const pointField& pts +) const +{ + scalarField cellSizes(pts.size()); + + forAll(pts, i) + { + cellSizes[i] = cellSize(pts[i]); + } + + return cellSizes; +} + + +Foam::scalar Foam::cellShapeControl::cellSize(const point& pt) const +{ + scalarList bary; + cellShapeControlMesh::Cell_handle ch; + + shapeControlMesh_.barycentricCoords(pt, bary, ch); + + scalar size = 0; + + label nFarPoints = 0; + for (label pI = 0; pI < 4; ++pI) + { + if (ch->vertex(pI)->farPoint()) + { + nFarPoints++; + } + } + + if (shapeControlMesh_.is_infinite(ch)) + { +// if (nFarPoints != 0) +// { +// for (label pI = 0; pI < 4; ++pI) +// { +// if (!ch->vertex(pI)->farPoint()) +// { +// size = ch->vertex(pI)->targetCellSize(); +// return size; +// } +// } +// } + + // Look up nearest point + cellShapeControlMesh::Vertex_handle nearV = + shapeControlMesh_.nearest_vertex + ( + toPoint<cellShapeControlMesh::Point>(pt) + ); + + size = nearV->targetCellSize(); + } + else + { + if (nFarPoints != 0) + { + for (label pI = 0; pI < 4; ++pI) + { + if (!ch->vertex(pI)->farPoint()) + { + size = ch->vertex(pI)->targetCellSize(); + return size; + } + } + } + else + { + forAll(bary, pI) + { + size += bary[pI]*ch->vertex(pI)->targetCellSize(); + } + } + } + + return size; +} + + +//- Return the cell alignment at the given location +Foam::tensor Foam::cellShapeControl::cellAlignment(const point& pt) const +{ + scalarList bary; + cellShapeControlMesh::Cell_handle ch; + + shapeControlMesh_.barycentricCoords(pt, bary, ch); + + tensor alignment = tensor::zero; + + label nFarPoints = 0; + for (label pI = 0; pI < 4; ++pI) + { + if (ch->vertex(pI)->farPoint()) + { + nFarPoints++; + } + } + + if (shapeControlMesh_.is_infinite(ch) || nFarPoints == 4) + { + Pout<< "At Infinite vertex" << endl; + + if (nFarPoints != 0) + { + for (label pI = 0; pI < 4; ++pI) + { + if (!ch->vertex(pI)->farPoint()) + { + alignment = ch->vertex(pI)->alignment(); + return alignment; + } + } + } + +// cellShapeControlMesh::Vertex_handle nearV = +// shapeControlMesh_.nearest_vertex +// ( +// toPoint<cellShapeControlMesh::Point>(pt) +// ); +// +// alignment = nearV->alignment(); + } + else + { +// forAll(bary, pI) +// { +// alignment += bary[pI]*ch->vertex(pI)->alignment(); +// } + + cellShapeControlMesh::Vertex_handle nearV = + shapeControlMesh_.nearest_vertex_in_cell + ( + toPoint<cellShapeControlMesh::Point>(pt), + ch + ); + + alignment = nearV->alignment(); + } + + return alignment; +} + + +void Foam::cellShapeControl::cellSizeAndAlignment +( + const point& pt, + scalar& size, + tensor& alignment +) const +{ + scalarList bary; + cellShapeControlMesh::Cell_handle ch; + + shapeControlMesh_.barycentricCoords(pt, bary, ch); + + alignment = tensor::zero; + size = 0; + + label nFarPoints = 0; + for (label pI = 0; pI < 4; ++pI) + { + if (ch->vertex(pI)->farPoint()) + { + nFarPoints++; + } + } + + if (shapeControlMesh_.is_infinite(ch)) + { + if (nFarPoints != 0) + { + for (label pI = 0; pI < 4; ++pI) + { + if (!ch->vertex(pI)->farPoint()) + { + size = ch->vertex(pI)->targetCellSize(); + alignment = ch->vertex(pI)->alignment(); + return; + } + } + } + +// cellShapeControlMesh::Vertex_handle nearV = +// shapeControlMesh_.nearest_vertex +// ( +// toPoint<cellShapeControlMesh::Point>(pt) +// ); +// +// size = nearV->targetCellSize(); +// alignment = nearV->alignment(); + } + else + { + if (nFarPoints != 0) + { + for (label pI = 0; pI < 4; ++pI) + { + if (!ch->vertex(pI)->farPoint()) + { + size = ch->vertex(pI)->targetCellSize(); + alignment = ch->vertex(pI)->alignment(); + return; + } + } + } + else + { + triad tri; + + forAll(bary, pI) + { + size += bary[pI]*ch->vertex(pI)->targetCellSize(); + + triad triTmp2 + ( + ch->vertex(pI)->alignment().x(), + ch->vertex(pI)->alignment().y(), + ch->vertex(pI)->alignment().z() + ); + + tri += triTmp2*bary[pI]; + } + + tri.normalize(); + tri.orthogonalize(); + tri = tri.sortxyz(); + + alignment = tensor + ( + tri.x(), tri.y(), tri.z() + ); + } + } +} + + +void Foam::cellShapeControl::initialMeshPopulation +( + const autoPtr<backgroundMeshDecomposition>& decomposition +) +{ + // Need to pass in the background mesh decomposition so that can test if + // a point to insert is on the processor. + if (Pstream::parRun()) + { + shapeControlMesh_.insertBoundingPoints(decomposition().procBounds()); + } + else + { + shapeControlMesh_.insertBoundingPoints(allGeometry_.bounds()); + } + + const PtrList<cellSizeAndAlignmentControl>& controlFunctions = + sizeAndAlignment_.controlFunctions(); + + forAll(controlFunctions, fI) + { + const cellSizeAndAlignmentControl& controlFunction = + controlFunctions[fI]; + + Info<< "Inserting points from " << controlFunction.name() + << " (" << controlFunction.type() << ")" << endl; + + pointField pts(1); + scalarField sizes(1); + Field<triad> alignments(1); + + controlFunction.initialVertices(pts, sizes, alignments); + + label nRejected = 0; + + forAll(pts, pI) + { + if (Pstream::parRun()) + { + if (!decomposition().positionOnThisProcessor(pts[pI])) + { + nRejected++; + continue; + } + } + + shapeControlMesh_.insert + ( + pts[pI], + sizes[pI], + alignments[pI] + ); + } + + Info<< " Inserted " << (pts.size() - nRejected) << "/" << pts.size() + << endl; + } +} + + +Foam::label Foam::cellShapeControl::refineMesh +( + const autoPtr<backgroundMeshDecomposition>& decomposition +) +{ + const pointField cellCentres = shapeControlMesh_.cellCentres(); + + Info<< " Created cell centres" << endl; + + const PtrList<cellSizeAndAlignmentControl>& controlFunctions = + sizeAndAlignment_.controlFunctions(); + + DynamicList<Vb> verts(shapeControlMesh_.number_of_vertices()); + + forAll(cellCentres, cellI) + { + const Foam::point& pt = cellCentres[cellI]; + + if (!geometryToConformTo_.inside(pt)) + { + continue; + } + + scalarList bary; + cellShapeControlMesh::Cell_handle ch; + + shapeControlMesh_.barycentricCoords(pt, bary, ch); + + if (shapeControlMesh_.is_infinite(ch)) + { + continue; + } + + scalar interpolatedSize = 0; + forAll(bary, pI) + { + interpolatedSize += bary[pI]*ch->vertex(pI)->targetCellSize(); + } + + label lastPriority = labelMax; + scalar lastCellSize = GREAT; + forAll(controlFunctions, fI) + { + const cellSizeAndAlignmentControl& controlFunction = + controlFunctions[fI]; + + if (controlFunction.priority() > lastPriority) + { + continue; + } + + if (isA<searchableSurfaceControl>(controlFunction)) + { + const cellSizeFunction& sizeFunction = + dynamicCast<const searchableSurfaceControl> + ( + controlFunction + ).sizeFunction(); + + scalar cellSize = 0; + if (sizeFunction.cellSize(pt, cellSize)) + { + if (controlFunction.priority() == lastPriority) + { + if (cellSize < lastCellSize) + { + lastCellSize = cellSize; + } + } + else + { + lastCellSize = cellSize; + } + + lastPriority = controlFunction.priority(); + } + } + } + + if + ( + lastCellSize < GREAT + && mag(interpolatedSize - lastCellSize)/lastCellSize > 0.2 + ) + { + if (Pstream::parRun()) + { + if (!decomposition().positionOnThisProcessor(pt)) + { + continue; + } + } + + verts.append + ( + Vb + ( + toPoint<cellShapeControlMesh::Point>(pt), + Vb::vtInternal + ) + ); + verts.last().targetCellSize() = lastCellSize; + verts.last().alignment() = tensor::I; + } + } + + shapeControlMesh_.insertPoints(verts); + + return verts.size(); +} + + +void Foam::cellShapeControl::smoothMesh() +{ + label maxSmoothingIterations = 200; + scalar minResidual = 0; + + labelListList pointPoints; + autoPtr<mapDistribute> meshDistributor = buildMap + ( + shapeControlMesh_, + pointPoints + ); + + triadField alignments = buildAlignmentField(shapeControlMesh_); + pointField points = buildPointField(shapeControlMesh_); + // Setup the sizes and alignments on each point + triadField fixedAlignments(shapeControlMesh_.vertexCount(), triad::unset); + + for + ( + CellSizeDelaunay::Finite_vertices_iterator vit = + shapeControlMesh_.finite_vertices_begin(); + vit != shapeControlMesh_.finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + const tensor& alignment = vit->alignment(); + + fixedAlignments[vit->index()] = triad + ( + alignment.x(), + alignment.y(), + alignment.z() + ); + } + } + + Info<< nl << "Smoothing alignments" << endl; + + for (label iter = 0; iter < maxSmoothingIterations; iter++) + { + Info<< "Iteration " << iter; + + meshDistributor().distribute(points); + meshDistributor().distribute(alignments); + + scalar residual = 0; + + triadField triadAv(alignments.size(), triad::unset); + + forAll(pointPoints, pI) + { + const labelList& pPoints = pointPoints[pI]; + + if (pPoints.empty()) + { + continue; + } + + triad& newTriad = triadAv[pI]; + + forAll(pPoints, adjPointI) + { + const label adjPointIndex = pPoints[adjPointI]; + + scalar dist = mag(points[pI] - points[adjPointIndex]); + + dist = max(dist, SMALL); + + triad tmpTriad = alignments[adjPointIndex]; + + for (direction dir = 0; dir < 3; dir++) + { + if (tmpTriad.set(dir)) + { + tmpTriad[dir] *= (1.0/dist); + } + } + + newTriad += tmpTriad; + } + + newTriad.normalize(); + newTriad.orthogonalize(); + newTriad = newTriad.sortxyz(); + + // Enforce the boundary conditions + const triad& fixedAlignment = fixedAlignments[pI]; + + label nFixed = 0; + + forAll(fixedAlignment, dirI) + { + if (fixedAlignment[dirI] != triad::unset[dirI]) + { + nFixed++; + } + } + + if (nFixed == 1) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad.align(fixedAlignment[dirI]); + } + } + } + else if (nFixed == 2) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad[dirI] = fixedAlignment[dirI]; + } + else + { + newTriad[dirI] = triad::unset[dirI]; + } + } + + newTriad.orthogonalize(); + } + else if (nFixed == 3) + { + forAll(fixedAlignment, dirI) + { + if (fixedAlignment.set(dirI)) + { + newTriad[dirI] = fixedAlignment[dirI]; + } + } + } + + const triad& oldTriad = alignments[pI]; + + if (newTriad.set(vector::X) && oldTriad.set(vector::X)) + { + scalar dotProd = (oldTriad.x() & newTriad.x()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + if (newTriad.set(vector::Y) && oldTriad.set(vector::Y)) + { + scalar dotProd = (oldTriad.y() & newTriad.y()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + if (newTriad.set(vector::Z) && oldTriad.set(vector::Z)) + { + scalar dotProd = (oldTriad.z() & newTriad.z()); + + scalar diff = mag(dotProd) - 1.0; + residual += mag(diff); + } + } + + forAll(alignments, pI) + { + alignments[pI] = triadAv[pI].sortxyz(); + } + + reduce(residual, sumOp<scalar>()); + + Info<< ", Residual = " << residual << endl; + + if (residual <= minResidual) + { + break; + } + } + + meshDistributor().distribute(alignments); + + for + ( + CellSizeDelaunay::Finite_vertices_iterator vit = + shapeControlMesh_.finite_vertices_begin(); + vit != shapeControlMesh_.finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + vit->alignment() = tensor + ( + alignments[vit->index()].x(), + alignments[vit->index()].y(), + alignments[vit->index()].z() + ); + } + } + + labelList referredPoints; + autoPtr<mapDistribute> referredDistributor = buildReferredMap + ( + shapeControlMesh_, + referredPoints + ); + + alignments.setSize(shapeControlMesh_.vertexCount()); + referredDistributor().distribute(alignments); + + label referredI = 0; + for + ( + CellSizeDelaunay::Finite_vertices_iterator vit = + shapeControlMesh_.finite_vertices_begin(); + vit != shapeControlMesh_.finite_vertices_end(); + ++vit + ) + { + if (vit->referred()) + { + const triad& t = alignments[referredPoints[referredI++]]; + + vit->alignment() = tensor(t.x(), t.y(), t.z()); + } + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.H new file mode 100644 index 00000000000..3bffe717f70 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControl.H @@ -0,0 +1,212 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellShapeControl + +Description + +SourceFiles + cellShapeControlI.H + cellShapeControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellShapeControl_H +#define cellShapeControl_H + +#include "dictionary.H" +#include "autoPtr.H" +#include "tensor.H" +#include "point.H" +#include "primitiveFieldsFwd.H" +#include "pointFieldFwd.H" +#include "triadField.H" +#include "Time.H" +#include "searchableSurfaces.H" +#include "conformationSurfaces.H" +#include "cellAspectRatioControl.H" +#include "cellSizeAndAlignmentControls.H" +#include "cellShapeControlMesh.H" +#include "backgroundMeshDecomposition.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class cellShapeControl Declaration +\*---------------------------------------------------------------------------*/ + +class cellShapeControl +: + public dictionary +{ + // Private data + + const Time& runTime_; + + const searchableSurfaces& allGeometry_; + + const conformationSurfaces& geometryToConformTo_; + + const scalar defaultCellSize_; + + cellShapeControlMesh shapeControlMesh_; + + cellAspectRatioControl aspectRatio_; + + cellSizeAndAlignmentControls sizeAndAlignment_; + + + // Private Member Functions + + template <class Triangulation, class Type> + tmp<Field<Type> > filterFarPoints + ( + const Triangulation& mesh, + const Field<Type>& field + ); + + template <class Triangulation> + autoPtr<mapDistribute> buildMap + ( + const Triangulation& mesh, + labelListList& pointPoints + ); + + template <class Triangulation> + autoPtr<mapDistribute> buildReferredMap + ( + const Triangulation& mesh, + labelList& indices + ); + + template <class Triangulation> + tmp<triadField> buildAlignmentField(const Triangulation& mesh); + + template <class Triangulation> + tmp<pointField> buildPointField(const Triangulation& mesh); + + //- Disallow default bitwise copy construct + cellShapeControl(const cellShapeControl&); + + //- Disallow default bitwise assignment + void operator=(const cellShapeControl&); + + +public: + + //- Runtime type information + ClassName("cellShapeControl"); + + + // Constructors + + //- Construct from dictionary and references to conformalVoronoiMesh and + // searchableSurfaces + cellShapeControl + ( + const Time& runTime, + const dictionary& cellShapeControlDict, + const searchableSurfaces& allGeometry, + const conformationSurfaces& geometryToConformTo + ); + + + //- Destructor + ~cellShapeControl(); + + + // Member Functions + + // Access + + inline const scalar& defaultCellSize() const; + + inline cellShapeControlMesh& shapeControlMesh(); + + inline const cellShapeControlMesh& shapeControlMesh() const; + + inline const cellAspectRatioControl& aspectRatio() const; + + inline const cellSizeAndAlignmentControls& sizeAndAlignment() const; + + + // Query + + //- Return the cell size at the given location + scalar cellSize(const point& pt) const; + + scalarField cellSize(const pointField& pts) const; + + //- Return the cell alignment at the given location + tensor cellAlignment(const point& pt) const; + + void cellSizeAndAlignment + ( + const point& pt, + scalar& size, + tensor& alignment + ) const; + + + // Edit + + void initialMeshPopulation + ( + const autoPtr<backgroundMeshDecomposition>& decomposition + ); + + label refineMesh + ( + const autoPtr<backgroundMeshDecomposition>& decomposition + ); + + void smoothMesh(); + + //- Add a control point with a specified size and alignment +// virtual void addControlPoint +// ( +// const point& pt, +// const scalar& size, +// const tensor& alignment +// ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "cellShapeControlI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControlI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControlI.H new file mode 100644 index 00000000000..f7fdebc9319 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControl/cellShapeControlI.H @@ -0,0 +1,55 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +inline Foam::cellShapeControlMesh& +Foam::cellShapeControl::shapeControlMesh() +{ + return shapeControlMesh_; +} + + +inline const Foam::cellShapeControlMesh& +Foam::cellShapeControl::shapeControlMesh() const +{ + return shapeControlMesh_; +} + + +inline const Foam::scalar& Foam::cellShapeControl::defaultCellSize() const +{ + return defaultCellSize_; +} + + +inline const Foam::cellAspectRatioControl& +Foam::cellShapeControl::aspectRatio() const +{ + return aspectRatio_; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C new file mode 100644 index 00000000000..bdcbf5a8857 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.C @@ -0,0 +1,760 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellShapeControlMesh.H" +#include "pointIOField.H" +#include "scalarIOField.H" +#include "tensorIOField.H" +#include "tetrahedron.H" +#include "plane.H" +#include "transform.H" +#include "meshTools.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(cellShapeControlMesh, 0); + +} + + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + +//Foam::tensor Foam::cellShapeControlMesh::requiredAlignment +//( +// const Foam::point& pt, +// const searchableSurfaces& allGeometry, +// const conformationSurfaces& geometryToConformTo +//) const +//{ +// pointIndexHit surfHit; +// label hitSurface; +// +// geometryToConformTo.findSurfaceNearest +// ( +// pt, +// sqr(GREAT), +// surfHit, +// hitSurface +// ); +// +// if (!surfHit.hit()) +// { +// FatalErrorIn +// ( +// "Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment" +// ) << "findSurfaceNearest did not find a hit across the surfaces." +// << exit(FatalError) << endl; +// } +// +// // Primary alignment +// +// vectorField norm(1); +// +// allGeometry[hitSurface].getNormal +// ( +// List<pointIndexHit>(1, surfHit), +// norm +// ); +// +// const vector np = norm[0]; +// +// // Generate equally spaced 'spokes' in a circle normal to the +// // direction from the vertex to the closest point on the surface +// // and look for a secondary intersection. +// +// const vector d = surfHit.hitPoint() - pt; +// +// const tensor Rp = rotationTensor(vector(0,0,1), np); +// +// const label s = 36;//cvMeshControls().alignmentSearchSpokes(); +// +// scalar closestSpokeHitDistance = GREAT; +// +// pointIndexHit closestSpokeHit; +// +// label closestSpokeSurface = -1; +// +// const scalar spanMag = geometryToConformTo.globalBounds().mag(); +// +// for (label i = 0; i < s; i++) +// { +// vector spoke +// ( +// Foam::cos(i*constant::mathematical::twoPi/s), +// Foam::sin(i*constant::mathematical::twoPi/s), +// 0 +// ); +// +// spoke *= spanMag; +// +// spoke = Rp & spoke; +// +// pointIndexHit spokeHit; +// +// label spokeSurface = -1; +// +// // internal spoke +// +// geometryToConformTo.findSurfaceNearestIntersection +// ( +// pt, +// pt + spoke, +// spokeHit, +// spokeSurface +// ); +// +// if (spokeHit.hit()) +// { +// scalar spokeHitDistance = mag +// ( +// spokeHit.hitPoint() - pt +// ); +// +// if (spokeHitDistance < closestSpokeHitDistance) +// { +// closestSpokeHit = spokeHit; +// closestSpokeSurface = spokeSurface; +// closestSpokeHitDistance = spokeHitDistance; +// } +// } +// +// //external spoke +// +// Foam::point mirrorPt = pt + 2*d; +// +// geometryToConformTo.findSurfaceNearestIntersection +// ( +// mirrorPt, +// mirrorPt + spoke, +// spokeHit, +// spokeSurface +// ); +// +// if (spokeHit.hit()) +// { +// scalar spokeHitDistance = mag +// ( +// spokeHit.hitPoint() - mirrorPt +// ); +// +// if (spokeHitDistance < closestSpokeHitDistance) +// { +// closestSpokeHit = spokeHit; +// closestSpokeSurface = spokeSurface; +// closestSpokeHitDistance = spokeHitDistance; +// } +// } +// } +// +// if (closestSpokeSurface == -1) +// { +//// WarningIn +//// ( +//// "conformalVoronoiMesh::requiredAlignment" +//// "(" +//// "const Foam::point& pt" +//// ") const" +//// ) << "No secondary surface hit found in spoke search " +//// << "using " << s +//// << " spokes, try increasing alignmentSearchSpokes." +//// << endl; +// +// return I; +// } +// +// // Auxiliary alignment generated by spoke intersection normal. +// +// allGeometry[closestSpokeSurface].getNormal +// ( +// List<pointIndexHit>(1, closestSpokeHit), +// norm +// ); +// +// const vector& na = norm[0]; +// +// // Secondary alignment +// vector ns = np ^ na; +// +// if (mag(ns) < SMALL) +// { +// FatalErrorIn("conformalVoronoiMesh::requiredAlignment") +// << "Parallel normals detected in spoke search." << nl +// << "point: " << pt << nl +// << "closest surface point: " << surfHit.hitPoint() << nl +// << "closest spoke hit: " << closestSpokeHit.hitPoint() << nl +// << "np: " << surfHit.hitPoint() + np << nl +// << "ns: " << closestSpokeHit.hitPoint() + na << nl +// << exit(FatalError); +// } +// +// ns /= mag(ns); +// +// tensor Rs = rotationTensor((Rp & vector(0,1,0)), ns); +// +// return (Rs & Rp); +//} + + +Foam::label Foam::cellShapeControlMesh::removePoints() +{ + label nRemoved = 0; + for + ( + CellSizeDelaunay::Finite_vertices_iterator vit = + finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + std::list<Vertex_handle> verts; + adjacent_vertices(vit, std::back_inserter(verts)); + + bool removePt = true; + for + ( + std::list<Vertex_handle>::iterator aVit = verts.begin(); + aVit != verts.end(); + ++aVit + ) + { + Vertex_handle avh = *aVit; + + scalar diff = + mag(avh->targetCellSize() - vit->targetCellSize()) + /max(vit->targetCellSize(), 1e-6); + + if (diff > 0.05) + { + removePt = false; + } + } + + if (removePt) + { + remove(vit); + nRemoved++; + } + } + + return nRemoved; +} + + +Foam::tmp<Foam::pointField> Foam::cellShapeControlMesh::cellCentres() const +{ + tmp<pointField> tcellCentres(new pointField(number_of_finite_cells())); + pointField& cellCentres = tcellCentres(); + + label count = 0; + for + ( + CellSizeDelaunay::Finite_cells_iterator c = finite_cells_begin(); + c != finite_cells_end(); + ++c + ) + { + if (c->hasFarPoint()) + { + continue; + } + + scalarList bary; + cellShapeControlMesh::Cell_handle ch; + + const Foam::point centre = topoint + ( + CGAL::centroid<baseK> + ( + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point() + ) + ); + + cellCentres[count++] = centre; + } + + cellCentres.resize(count); + + return tcellCentres; +} + + +void Foam::cellShapeControlMesh::writeTriangulation() +{ + OFstream str + ( + "refinementTriangulation_" + + name(Pstream::myProcNo()) + + ".obj" + ); + + label count = 0; + + Info<< "Write refinementTriangulation" << endl; + + for + ( + CellSizeDelaunay::Finite_edges_iterator e = finite_edges_begin(); + e != finite_edges_end(); + ++e + ) + { + Cell_handle c = e->first; + Vertex_handle vA = c->vertex(e->second); + Vertex_handle vB = c->vertex(e->third); + + // Don't write far edges + if (vA->farPoint() || vB->farPoint()) + { + continue; + } + + // Don't write unowned edges + if (vA->referred() && vB->referred()) + { + continue; + } + + pointFromPoint p1 = topoint(vA->point()); + pointFromPoint p2 = topoint(vB->point()); + + meshTools::writeOBJ(str, p1, p2, count); + } + + if (is_valid()) + { + Info<< " Triangulation is valid" << endl; + } + else + { + FatalErrorIn + ( + "Foam::triangulatedMesh::writeRefinementTriangulation()" + ) << "Triangulation is not valid" + << abort(FatalError); + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellShapeControlMesh::cellShapeControlMesh(const Time& runTime) +: + runTime_(runTime), + defaultCellSize_(0.0) +{} + + +//Foam::triangulatedMesh::triangulatedMesh +//( +// const Time& runTime, +// const fileName& pointsFile, +// const fileName& sizesFile, +// const fileName& alignmentsFile, +// const scalar& defaultCellSize +//) +//: +// defaultCellSize_(defaultCellSize) +//{ +// Info<< " Reading points from file : " << pointsFile << endl; +// +// pointIOField points +// ( +// IOobject +// ( +// pointsFile, +// runTime.constant(), +// runTime, +// IOobject::MUST_READ, +// IOobject::NO_WRITE +// ) +// ); +// +// Info<< " Reading sizes from file : " << sizesFile << endl; +// +// scalarIOField sizes +// ( +// IOobject +// ( +// sizesFile, +// runTime.constant(), +// runTime, +// IOobject::MUST_READ, +// IOobject::NO_WRITE +// ) +// ); +// +// Info<< " Reading alignments from file : " << alignmentsFile << endl; +// +// tensorIOField alignments +// ( +// IOobject +// ( +// alignmentsFile, +// runTime.constant(), +// runTime, +// IOobject::MUST_READ, +// IOobject::NO_WRITE +// ) +// ); +// +// Info<< " Number of points : " << points.size() << endl; +// Info<< " Minimum size : " << min(sizes) << endl; +// Info<< " Average size : " << average(sizes) << endl; +// Info<< " Maximum size : " << max(sizes) << endl; +// +// forAll(points, pI) +// { +// size_t nVert = number_of_vertices(); +// +// Vertex_handle v = insert +// ( +// Point(points[pI].x(), points[pI].y(), points[pI].z()) +// ); +// +// if (number_of_vertices() == nVert) +// { +// Info<< " Failed to insert point : " << points[pI] << endl; +// } +// +// v->targetCellSize() = sizes[pI]; +// +// const tensor& alignment = alignments[pI]; +// +// +// +// v->alignment() = alignment; +// } +// +//// scalar factor = 1.0; +//// label maxIteration = 1; +//// +//// for (label iteration = 0; iteration < maxIteration; ++iteration) +//// { +//// Info<< "Iteration : " << iteration << endl; +//// +//// label nRefined = refineTriangulation(factor); +//// +//// Info<< " Number of cells refined in refinement iteration : " +//// << nRefined << nl << endl; +//// +//// if (nRefined <= 0 && iteration != 0) +//// { +//// break; +//// } +//// +//// factor *= 1.5; +//// } +// +// //writeRefinementTriangulation(); +//} + + +//Foam::triangulatedMesh::triangulatedMesh +//( +// const Time& runTime, +// const DynamicList<Foam::point>& points, +// const DynamicList<scalar>& sizes, +// const DynamicList<tensor>& alignments, +// const scalar& defaultCellSize +//) +//: +// defaultCellSize_(defaultCellSize) +//{ +// forAll(points, pI) +// { +// size_t nVert = number_of_vertices(); +// +// Vertex_handle v = insert +// ( +// Point(points[pI].x(), points[pI].y(), points[pI].z()) +// ); +// +// if (number_of_vertices() == nVert) +// { +// Info<< "Failed to insert point : " << points[pI] << endl; +// } +// +// v->targetCellSize() = sizes[pI]; +// +// v->alignment() = alignments[pI]; +// } +// +// //writeRefinementTriangulation(); +// +// Info<< nl << "Refinement triangulation information: " << endl; +// Info<< " Number of vertices: " << label(number_of_vertices()) << endl; +// Info<< " Number of cells : " +// << label(number_of_finite_cells()) << endl; +// Info<< " Number of faces : " +// << label(number_of_finite_facets()) << endl; +// Info<< " Number of edges : " +// << label(number_of_finite_edges()) << endl; +// Info<< " Dimensionality : " << label(dimension()) << nl << endl; +//} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellShapeControlMesh::~cellShapeControlMesh() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::cellShapeControlMesh::barycentricCoords +( + const Foam::point& pt, + scalarList& bary, + Cell_handle& ch +) const +{ + // Use the previous cell handle as a hint on where to start searching + ch = locate + ( + Point(pt.x(), pt.y(), pt.z()) + ); + + if (!is_infinite(ch)) + { + oldCellHandle_ = ch; + + tetPointRef tet + ( + topoint(ch->vertex(0)->point()), + topoint(ch->vertex(1)->point()), + topoint(ch->vertex(2)->point()), + topoint(ch->vertex(3)->point()) + ); + + tet.barycentric(pt, bary); + } +} + + +Foam::boundBox Foam::cellShapeControlMesh::bounds() const +{ + DynamicList<Foam::point> pts(number_of_vertices()); + + for + ( + Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + pts.append(topoint(vit->point())); + } + } + + boundBox bb(pts); + + return bb; +} + + +void Foam::cellShapeControlMesh::distribute +( + const backgroundMeshDecomposition& decomposition +) +{ + if (!Pstream::parRun()) + { + return; + } + + autoPtr<mapDistribute> mapDist = + DistributedDelaunayMesh<CellSizeDelaunay>::distribute(decomposition); + + DynamicList<Foam::point> points(number_of_vertices()); + DynamicList<scalar> sizes(number_of_vertices()); + DynamicList<tensor> alignments(number_of_vertices()); + + for + ( + Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + points.append(topoint(vit->point())); + sizes.append(vit->targetCellSize()); + alignments.append(vit->alignment()); + } + } + + mapDist().distribute(points); + mapDist().distribute(sizes); + mapDist().distribute(alignments); + + // Reset the entire tessellation + DelaunayMesh<CellSizeDelaunay>::reset(); + + Info<< nl << " Inserting distributed tessellation" << endl; + + insertBoundingPoints(decomposition.procBounds()); + + // Internal points have to be inserted first + + DynamicList<Vb> verticesToInsert(points.size()); + + forAll(points, pI) + { + verticesToInsert.append + ( + Vb + ( + toPoint<Point>(points[pI]), + -1, + Vb::vtInternal, + Pstream::myProcNo() + ) + ); + + verticesToInsert.last().targetCellSize() = sizes[pI]; + verticesToInsert.last().alignment() = alignments[pI]; + } + + this->rangeInsertWithInfo + ( + verticesToInsert.begin(), + verticesToInsert.end(), + true + ); + + sync(decomposition.procBounds()); + + Info<< " Total number of vertices after redistribution " + << returnReduce(label(number_of_vertices()), sumOp<label>()) << endl; +} + + +Foam::tensorField Foam::cellShapeControlMesh::dumpAlignments() const +{ + tensorField alignmentsTmp(number_of_vertices(), tensor::zero); + + label count = 0; + for + ( + Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + alignmentsTmp[count++] = vit->alignment(); + } + + return alignmentsTmp; +} + + +void Foam::cellShapeControlMesh::insertBoundingPoints(const boundBox& bb) +{ + boundBox bbInflate = bb; + bbInflate.inflate(10); + + pointField pts = bbInflate.points(); + + forAll(pts, pI) + { + insertFar(pts[pI]); + } +} + + +void Foam::cellShapeControlMesh::write() const +{ + Info<< "Writing cell size and alignment mesh" << endl; + + const fileName name("cellSizeAndAlignmentMesh"); + + // Reindex the cells + label cellCount = 0; + for + ( + Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) + { + if (!cit->hasFarPoint() && !is_infinite(cit)) + { + cit->cellIndex() = cellCount++; + } + } + + labelList vertexMap; + labelList cellMap; + + autoPtr<fvMesh> meshPtr = DelaunayMesh<CellSizeDelaunay>::createMesh + ( + name, + runTime_, + vertexMap, + cellMap + ); + const fvMesh& mesh = meshPtr(); + + pointScalarField sizes + ( + IOobject + ( + "sizes", + mesh.time().timeName(), + mesh, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + pointMesh::New(mesh), + scalar(0) + ); + + for + ( + Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (!vit->farPoint()) + { + sizes[vertexMap[vit->index()]] = vit->targetCellSize(); + } + } + + mesh.write(); +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.H new file mode 100644 index 00000000000..e6cb37a2c3b --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMesh.H @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellShapeControlMesh + +Description + +SourceFiles + cellShapeControlMeshI.H + cellShapeControlMesh.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellShapeControlMesh_H +#define cellShapeControlMesh_H + +#include "Time.H" +#include "scalar.H" +#include "point.H" +#include "tensor.H" +#include "triad.H" +#include "fileName.H" +#include "searchableSurfaces.H" +#include "conformationSurfaces.H" +#include "DistributedDelaunayMesh.H" +#include "CGALTriangulation3Ddefs.H" +#include "backgroundMeshDecomposition.H" +#include "boundBox.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class cellShapeControlMesh Declaration +\*---------------------------------------------------------------------------*/ + +class cellShapeControlMesh +: + public DistributedDelaunayMesh<CellSizeDelaunay> +{ +public: + + typedef CellSizeDelaunay::Cell_handle Cell_handle; + typedef CellSizeDelaunay::Vertex_handle Vertex_handle; + typedef CellSizeDelaunay::Point Point; + + +private: + + // Private data + + const Time& runTime_; + + mutable Cell_handle oldCellHandle_; + + const scalar defaultCellSize_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + cellShapeControlMesh(const cellShapeControlMesh&); + + //- Disallow default bitwise assignment + void operator=(const cellShapeControlMesh&); + + +public: + + //- Runtime type information + ClassName("cellShapeControlMesh"); + + + // Constructors + + explicit cellShapeControlMesh(const Time& runTime); + + + //- Destructor + ~cellShapeControlMesh(); + + + // Member Functions + + // Query + + //- Calculate and return the barycentric coordinates for + // interpolating quantities on the background mesh + void barycentricCoords + ( + const Foam::point& pt, + scalarList& bary, + Cell_handle& ch + ) const; + + boundBox bounds() const; + + + // Edit + + label removePoints(); + + //- Get the centres of all the tets + tmp<pointField> cellCentres() const; + + inline Vertex_handle insert + ( + const Foam::point& pt, + const scalar& size, + const triad& alignment, + const Foam::indexedVertexEnum::vertexType type = Vb::vtInternal + ); + + inline Vertex_handle insertFar + ( + const Foam::point& pt + ); + + void distribute + ( + const backgroundMeshDecomposition& decomposition + ); + + tensorField dumpAlignments() const; + + void insertBoundingPoints(const boundBox& bb); + + void writeTriangulation(); + + void write() const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "cellShapeControlMeshI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMeshI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMeshI.H new file mode 100644 index 00000000000..305256d4cca --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellShapeControlMesh/cellShapeControlMeshI.H @@ -0,0 +1,68 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::cellShapeControlMesh::Vertex_handle Foam::cellShapeControlMesh::insert +( + const Foam::point& pt, + const scalar& size, + const triad& alignment, + const Foam::indexedVertexEnum::vertexType type +) +{ + Vertex_handle v = CellSizeDelaunay::insert + ( + Point(pt.x(), pt.y(), pt.z()) + ); + v->type() = type; + v->index() = getNewVertexIndex(); + v->procIndex() = Pstream::myProcNo(); + v->targetCellSize() = size; + v->alignment() = tensor(alignment.x(), alignment.y(), alignment.z()); + + return v; +} + + +Foam::cellShapeControlMesh::Vertex_handle Foam::cellShapeControlMesh::insertFar +( + const Foam::point& pt +) +{ + Vertex_handle v = CellSizeDelaunay::insert + ( + Point(pt.x(), pt.y(), pt.z()) + ); + v->type() = Vb::vtFar; +// v->type() = Vb::vtExternalFeaturePoint; + v->index() = getNewVertexIndex(); + v->procIndex() = Pstream::myProcNo(); + + return v; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.C new file mode 100644 index 00000000000..3dce1d518e5 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.C @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellSizeAndAlignmentControl.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(cellSizeAndAlignmentControl, 0); +defineRunTimeSelectionTable(cellSizeAndAlignmentControl, dictionary); + +} + + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellSizeAndAlignmentControl::cellSizeAndAlignmentControl +( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry +) +: + runTime_(runTime), + name_(name), + priority_(readLabel(controlFunctionDict.lookup("priority"))) +{} + + +// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::cellSizeAndAlignmentControl> +Foam::cellSizeAndAlignmentControl::New +( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry +) +{ + word cellSizeAndAlignmentControlTypeName + ( + controlFunctionDict.lookup("type") + ); + + Info<< nl << "Selecting cellSizeAndAlignmentControl " + << cellSizeAndAlignmentControlTypeName << endl; + + dictionaryConstructorTable::iterator cstrIter = + dictionaryConstructorTablePtr_->find + ( + cellSizeAndAlignmentControlTypeName + ); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalErrorIn + ( + "cellSizeAndAlignmentControl::New()" + ) << "Unknown cellSizeAndAlignmentControl type " + << cellSizeAndAlignmentControlTypeName + << endl << endl + << "Valid cellSizeAndAlignmentControl types are :" << endl + << dictionaryConstructorTablePtr_->toc() + << exit(FatalError); + } + + return autoPtr<cellSizeAndAlignmentControl> + ( + cstrIter() + ( + runTime, + name, + controlFunctionDict, + allGeometry + ) + ); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellSizeAndAlignmentControl::~cellSizeAndAlignmentControl() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.H new file mode 100644 index 00000000000..d8589ba6ef4 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControl.H @@ -0,0 +1,166 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellSizeAndAlignmentControl + +Description + +SourceFiles + cellSizeAndAlignmentControlI.H + cellSizeAndAlignmentControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellSizeAndAlignmentControl_H +#define cellSizeAndAlignmentControl_H + +#include "dictionary.H" +#include "conformationSurfaces.H" +#include "Time.H" +#include "quaternion.H" +#include "triad.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class cellSizeAndAlignmentControl Declaration +\*---------------------------------------------------------------------------*/ + +class cellSizeAndAlignmentControl +{ +protected: + + const Time& runTime_; + + +private: + + // Private data + + const word name_; + + //- Priority of this cellSizeFunction + label priority_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + cellSizeAndAlignmentControl(const cellSizeAndAlignmentControl&); + + //- Disallow default bitwise assignment + void operator=(const cellSizeAndAlignmentControl&); + + +public: + + //- Runtime type information + TypeName("cellSizeAndAlignmentControl"); + + + // Declare run-time constructor selection table + + declareRunTimeSelectionTable + ( + autoPtr, + cellSizeAndAlignmentControl, + dictionary, + ( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry + ), + (runTime, name, controlFunctionDict, allGeometry) + ); + + + // Constructors + + //- Construct from dictionary and references to conformalVoronoiMesh and + // searchableSurfaces + cellSizeAndAlignmentControl + ( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry + ); + + + // Selectors + + //- Return a reference to the selected cellShapeControl + static autoPtr<cellSizeAndAlignmentControl> New + ( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry + ); + + + //- Destructor + virtual ~cellSizeAndAlignmentControl(); + + + // Member Functions + + // Access + + const word& name() const + { + return name_; + } + + inline label priority() const + { + return priority_; + } + + + // Query + + virtual void initialVertices + ( + pointField& pts, + scalarField& sizes, + Field<triad>& alignments + ) const = 0; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.C new file mode 100644 index 00000000000..44c8852abfc --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.C @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellSizeAndAlignmentControls.H" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellSizeAndAlignmentControls::cellSizeAndAlignmentControls +( + const Time& runTime, + const dictionary& shapeControlDict, + const conformationSurfaces& allGeometry +) +: + shapeControlDict_(shapeControlDict), + allGeometry_(allGeometry), + controlFunctions_(shapeControlDict_.size()) +{ + label functionI = 0; + + forAllConstIter(dictionary, shapeControlDict_, iter) + { + word shapeControlEntryName = iter().keyword(); + + const dictionary& controlFunctionDict + ( + shapeControlDict_.subDict(shapeControlEntryName) + ); + + controlFunctions_.set + ( + functionI, + cellSizeAndAlignmentControl::New + ( + runTime, + shapeControlEntryName, + controlFunctionDict, + allGeometry + ) + ); + + functionI++; + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellSizeAndAlignmentControls::~cellSizeAndAlignmentControls() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.H new file mode 100644 index 00000000000..dac3ffc13ce --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/cellSizeAndAlignmentControls.H @@ -0,0 +1,110 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellSizeAndAlignmentControls + +Description + +SourceFiles + cellSizeAndAlignmentControls.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellSizeAndAlignmentControls_H +#define cellSizeAndAlignmentControls_H + +#include "dictionary.H" +#include "cellShapeControlMesh.H" +#include "cellSizeAndAlignmentControl.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class cellSizeAndAlignmentControls Declaration +\*---------------------------------------------------------------------------*/ + +class cellSizeAndAlignmentControls +{ + // Private data + + const dictionary& shapeControlDict_; + + const conformationSurfaces& allGeometry_; + + PtrList<cellSizeAndAlignmentControl> controlFunctions_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + cellSizeAndAlignmentControls(const cellSizeAndAlignmentControls&); + + //- Disallow default bitwise assignment + void operator=(const cellSizeAndAlignmentControls&); + + +public: + + // Constructors + + //- Construct from dictionary + cellSizeAndAlignmentControls + ( + const Time& runTime, + const dictionary& shapeControlDict, + const conformationSurfaces& allGeometry + ); + + + //- Destructor + virtual ~cellSizeAndAlignmentControls(); + + + // Member Functions + + // Access + + const PtrList<cellSizeAndAlignmentControl>& controlFunctions() const + { + return controlFunctions_; + } + + + // Query +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C new file mode 100644 index 00000000000..4d83468fc4c --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.C @@ -0,0 +1,236 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "fileControl.H" +#include "addToRunTimeSelectionTable.H" +#include "tetrahedron.H" +#include "scalarList.H" +#include "vectorTools.H" +#include "pointIOField.H" +#include "scalarIOField.H" +#include "triadIOField.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(fileControl, 0); +addToRunTimeSelectionTable +( + cellSizeAndAlignmentControl, + fileControl, + dictionary +); + +} + + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::fileControl::fileControl +( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry +) +: + cellSizeAndAlignmentControl(runTime, name, controlFunctionDict, allGeometry), + pointsFile_(controlFunctionDict.lookup("pointsFile")), + sizesFile_(controlFunctionDict.lookup("sizesFile")), + alignmentsFile_(controlFunctionDict.lookup("alignmentsFile")) +{ + Info<< indent << "Loading from file... " << nl + << indent << " points : " << pointsFile_ << nl + << indent << " sizes : " << sizesFile_ << nl + << indent << " alignments : " << alignmentsFile_ + << endl; +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::fileControl::~fileControl() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // +// +//Foam::scalar Foam::fileControl::cellSize(const point& pt) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_.barycentricCoords(pt, bary, ch); +// +// scalar size = 0; +// forAll(bary, pI) +// { +// size += bary[pI]*ch->vertex(pI)->size(); +// } +// +// return size; +//} +// +// +////- Return the cell alignment at the given location +//Foam::tensor Foam::fileControl::cellAlignment(const point& pt) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_.barycentricCoords(pt, bary, ch); +// +// label nearest = 0; +// +// tensor alignment = Foam::tensor::zero; +// forAll(bary, pI) +// { +// //alignment += bary[pI]*ch->vertex(pI)->alignment(); +// +// // Find nearest point +// if (bary[pI] > nearest) +// { +// alignment = ch->vertex(pI)->alignment(); +// nearest = bary[pI]; +// } +// } +// +// return alignment; +//} +// +// +////- Return the cell alignment at the given location +//void Foam::fileControl::cellSizeAndAlignment +//( +// const point& pt, +// scalar& size, +// tensor& alignment +//) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_.barycentricCoords(pt, bary, ch); +// +// size = 0; +// forAll(bary, pI) +// { +// size += bary[pI]*ch->vertex(pI)->size(); +// } +// +//// alignment = Foam::tensor::zero; +//// forAll(bary, pI) +//// { +//// alignment += bary[pI]*ch->vertex(pI)->alignment(); +//// } +// +// alignment = cellAlignment(pt); +//} + + +void Foam::fileControl::initialVertices +( + pointField& pts, + scalarField& sizes, + Field<triad>& alignments +) const +{ + Info<< " Reading points from file : " << pointsFile_ << endl; + + pointIOField pointsTmp + ( + IOobject + ( + pointsFile_, + runTime_.constant(), + runTime_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ); + + pts.transfer(pointsTmp); + + Info<< " Reading sizes from file : " << sizesFile_ << endl; + + scalarIOField sizesTmp + ( + IOobject + ( + sizesFile_, + runTime_.constant(), + runTime_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ); + + sizes.transfer(sizesTmp); + + Info<< " Reading alignments from file : " << alignmentsFile_ << endl; + + triadIOField alignmentsTmp + ( + IOobject + ( + alignmentsFile_, + runTime_.constant(), + runTime_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ); + + alignments.transfer(alignmentsTmp); + + if ((pts.size() != sizes.size()) || (pts.size() != alignments.size())) + { + FatalErrorIn + ( + "Foam::fileControl::initialVertices" + "(" + " pointField&," + " scalarField&," + " Field<triad>&" + ")" + ) << "Size of list of points, sizes and alignments do not match:" + << nl + << "Points size = " << pts.size() << nl + << "Sizes size = " << sizes.size() << nl + << "Alignments size = " << alignments.size() + << abort(FatalError); + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.H new file mode 100644 index 00000000000..9c84b516d1a --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/fileControl/fileControl.H @@ -0,0 +1,134 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::fileControl + +Description + +SourceFiles + fileControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef fileControl_H +#define fileControl_H + +#include "cellSizeAndAlignmentControl.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class fileControl Declaration +\*---------------------------------------------------------------------------*/ + +class fileControl +: + public cellSizeAndAlignmentControl +{ + // Private data + + const fileName pointsFile_; + + const fileName sizesFile_; + + const fileName alignmentsFile_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + fileControl(const fileControl&); + + //- Disallow default bitwise assignment + void operator=(const fileControl&); + + +public: + + //- Runtime type information + TypeName("fileControl"); + + + // Constructors + + //- Construct from dictionary and references to conformalVoronoiMesh and + // searchableSurfaces + fileControl + ( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry + ); + + //- Destructor + ~fileControl(); + + + // Member Functions + + // Access + + + // Query + +// //- Return the cell size at the given location +// virtual scalar cellSize(const point& pt) const; +// +// //- Return the cell alignment at the given location +// virtual tensor cellAlignment(const point& pt) const; +// +// virtual void cellSizeAndAlignment +// ( +// const point& pt, +// scalar& size, +// tensor& alignment +// ) const; + + + // Edit + + virtual void initialVertices + ( + pointField& pts, + scalarField& sizes, + Field<triad>& alignments + ) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C new file mode 100644 index 00000000000..b5e3be42f88 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.C @@ -0,0 +1,640 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "searchableSurfaceControl.H" +#include "addToRunTimeSelectionTable.H" +#include "cellSizeFunction.H" +#include "triSurfaceMesh.H" +#include "searchableBox.H" +#include "tetrahedron.H" +#include "vectorTools.H" +#include "quaternion.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(searchableSurfaceControl, 0); +addToRunTimeSelectionTable +( + cellSizeAndAlignmentControl, + searchableSurfaceControl, + dictionary +); + +} + + +// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // + +//Foam::tensor Foam::surfaceControl::requiredAlignment +//( +// const Foam::point& pt, +// const vectorField& ptNormals +//) const +//{ +//// pointIndexHit surfHit; +//// label hitSurface; +//// +//// geometryToConformTo_.findSurfaceNearest +//// ( +//// pt, +//// sqr(GREAT), +//// surfHit, +//// hitSurface +//// ); +//// +//// if (!surfHit.hit()) +//// { +//// FatalErrorIn +//// ( +//// "Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment" +//// ) +//// << "findSurfaceNearest did not find a hit across the surfaces." +//// << exit(FatalError) << endl; +//// } +//// +////// Primary alignment +//// +//// vectorField norm(1); +//// +//// allGeometry_[hitSurface].getNormal +//// ( +//// List<pointIndexHit>(1, surfHit), +//// norm +//// ); +//// +//// const vector np = norm[0]; +//// +//// const tensor Rp = rotationTensor(vector(0,0,1), np); +//// +//// return (Rp); +// +//// Info<< "Point : " << pt << endl; +//// forAll(ptNormals, pnI) +//// { +//// Info<< " normal " << pnI << " : " << ptNormals[pnI] << endl; +//// } +// +// vector np = ptNormals[0]; +// +// const tensor Rp = rotationTensor(vector(0,0,1), np); +// +// vector na = vector::zero; +// +// scalar smallestAngle = GREAT; +// +// for (label pnI = 1; pnI < ptNormals.size(); ++pnI) +// { +// const vector& nextNormal = ptNormals[pnI]; +// +// const scalar cosPhi = vectorTools::cosPhi(np, nextNormal); +// +// if (mag(cosPhi) < smallestAngle) +// { +// na = nextNormal; +// smallestAngle = cosPhi; +// } +// } +// +// // Secondary alignment +// vector ns = np ^ na; +// +// if (mag(ns) < SMALL) +// { +// WarningIn("conformalVoronoiMesh::requiredAlignment") +// << "Parallel normals detected in spoke search." << nl +// << "point: " << pt << nl +// << "np : " << np << nl +// << "na : " << na << nl +// << "ns : " << ns << nl +// << endl; +// +// ns = np; +// } +// +// ns /= mag(ns); +// +// tensor Rs = rotationTensor((Rp & vector(0,1,0)), ns); +// +//// Info<< "Point " << pt << nl +//// << " np : " << np << nl +//// << " ns : " << ns << nl +//// << " Rp : " << Rp << nl +//// << " Rs : " << Rs << nl +//// << " Rs&Rp: " << (Rs & Rp) << endl; +// +// return (Rs & Rp); +//} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::searchableSurfaceControl::searchableSurfaceControl +( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry +) +: + cellSizeAndAlignmentControl(runTime, name, controlFunctionDict, allGeometry), + searchableSurface_(allGeometry.geometry()[name]), + allGeometry_(allGeometry), + cellSizeFunction_ + ( + cellSizeFunction::New(controlFunctionDict, searchableSurface_) + ) +// geometryToConformTo_(geometryToConformTo), +// surfaces_(), +// cellSizeFunctions_(), +// triangulatedMesh_() +{ +// const dictionary& surfacesDict = coeffDict(); +// +// Info<< nl << "Reading cellSizeControlGeometry" << endl; +// +// surfaces_.setSize(surfacesDict.size()); +// +// cellSizeFunctions_.setSize(surfacesDict.size()); +// +// label surfI = 0; +// +// DynamicList<point> pointsToInsert; +// DynamicList<scalar> sizesToInsert; +// DynamicList<tensor> alignmentsToInsert; +// +// forAllConstIter(dictionary, surfacesDict, iter) +// { +// const dictionary& surfaceSubDict +// ( +// surfacesDict.subDict(iter().keyword()) +// ); +// +// // If the "surface" keyword is not found in the dictionary, assume that +// // the name of the dictionary is the surface. Distinction required to +// // allow the same surface to be used multiple times to supply multiple +// // cellSizeFunctions +// +// word surfaceName = surfaceSubDict.lookupOrDefault<word> +// ( +// "surface", +// iter().keyword() +// ); +// +// surfaces_[surfI] = allGeometry_.findSurfaceID(surfaceName); +// +// if (surfaces_[surfI] < 0) +// { +// FatalErrorIn +// ( +// "Foam::surfaceControl::surfaceControl" +// ) << "No surface " << surfaceName << " found. " +// << "Valid geometry is " << nl << allGeometry_.names() +// << exit(FatalError); +// } +// +// const searchableSurface& surface = allGeometry_[surfaces_[surfI]]; +// +// Info<< nl << " " << iter().keyword() << nl +// << " surface: " << surfaceName << nl +// << " size : " << surface.size() << endl; +// +// cellSizeFunctions_.set +// ( +// surfI, +// cellSizeFunction::New +// ( +// surfaceSubDict, +// surface +// ) +// ); +// +// surfI++; +// +// if (isA<triSurfaceMesh>(surface)) +// { +// const triSurfaceMesh& tsm +// = refCast<const triSurfaceMesh>(surface); +// +// const pointField& points = tsm.points(); +// const vectorField& faceNormals = tsm.faceNormals(); +// const labelListList& pointFaces = tsm.pointFaces(); +// +// Info<< " Number of points: " << tsm.nPoints() << endl; +// +// forAll(points, pI) +// { +// const Foam::point& pt = points[pI]; +// const labelList& ptFaces = pointFaces[pI]; +// +// vectorField pointNormals(ptFaces.size()); +// +// forAll(pointNormals, pnI) +// { +// pointNormals[pnI] = faceNormals[ptFaces[pnI]]; +// } +// +// pointsToInsert.append(pt); +// +// // Get the value of the point from surfaceCellSizeFunction. If +// // adding points internally then will need to interpolate. +// scalar newSize = 0; +// +// cellSizeFunctions_[surfI - 1].cellSize(pt, newSize); +// sizesToInsert.append(newSize); +// +// tensor newAlignment = requiredAlignment(pt, pointNormals); +// +// alignmentsToInsert.append(newAlignment); +// } +// } +// } +// +// // Add the global bound box to ensure that all internal point queries +// // will return sizes and alignments +//// boundBox bb = allGeometry_.bounds(); +//// +//// pointField bbPoints = bb.points(); +//// +//// forAll(bbPoints, pI) +//// { +//// pointsToInsert.append(bbPoints[pI]); +//// sizesToInsert.append(defaultCellSize()); +//// alignmentsToInsert.append(tensor(1,0,0,0,1,0,0,0,1)); +//// } +// +// triangulatedMesh_.set +// ( +// new triangulatedMesh +// ( +// runTime, +// pointsToInsert, +// sizesToInsert, +// alignmentsToInsert, +// defaultCellSize() +// ) +// ); +// +// scalar factor = 1.0; +// label maxIteration = cellShapeControlDict.lookupOrDefault<label> +// ( +// "maxRefinementIterations", 1 +// ); +// +// +// for (label iteration = 0; iteration < maxIteration; ++iteration) +// { +// Info<< "Iteration : " << iteration << endl; +// +// label nRefined = triangulatedMesh_().refineTriangulation +// ( +// factor, +// allGeometry_, +// geometryToConformTo_ +// ); +// +// Info<< " Number of cells refined in refinement iteration : " +// << nRefined << nl << endl; +// +// if (nRefined <= 0 && iteration != 0) +// { +// break; +// } +// +// factor *= 1.5; +// } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::searchableSurfaceControl::~searchableSurfaceControl() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +//Foam::scalar Foam::surfaceControl::cellSize(const point& pt) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_().barycentricCoords(pt, bary, ch); +// +// scalar size = 0; +// forAll(bary, pI) +// { +// size += bary[pI]*ch->vertex(pI)->size(); +// } +// +// return size; +//} +// +// +////- Return the cell alignment at the given location +//Foam::tensor Foam::surfaceControl::cellAlignment(const point& pt) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_().barycentricCoords(pt, bary, ch); +// +//// vectorField cartesianDirections(3); +//// +//// cartesianDirections[0] = vector(0,0,1); +//// cartesianDirections[1] = vector(0,1,0); +//// cartesianDirections[2] = vector(1,0,0); +//// +//// // Rearrange each alignment tensor so that the x/y/z components are +//// // in order of whichever makes the smallest angle with the global coordinate +//// // system +//// FixedList<tensor, 4> alignments; +//// +//// forAll(alignments, aI) +//// { +//// tensor a = ch->vertex(aI)->alignment(); +//// +//// tensor tmpA = a; +//// +////// Info<< nl << indent<< a << endl; +//// +//// scalar minAngle = 0; +//// +//// scalar axx = vectorTools::cosPhi(a.x(), cartesianDirections[0]); +//// scalar axy = vectorTools::cosPhi(a.y(), cartesianDirections[0]); +//// scalar axz = vectorTools::cosPhi(a.z(), cartesianDirections[0]); +//// +//// scalar ayx = vectorTools::cosPhi(a.x(), cartesianDirections[1]); +//// scalar ayy = vectorTools::cosPhi(a.y(), cartesianDirections[1]); +//// scalar ayz = vectorTools::cosPhi(a.z(), cartesianDirections[1]); +//// +//// scalar azx = vectorTools::cosPhi(a.x(), cartesianDirections[2]); +//// scalar azy = vectorTools::cosPhi(a.y(), cartesianDirections[2]); +//// scalar azz = vectorTools::cosPhi(a.z(), cartesianDirections[2]); +//// +////// Info<< indent << axx << " " << axy << " " << axz << nl +////// << indent << ayx << " " << ayy << " " << ayz << nl +////// << indent << azx << " " << azy << " " << azz << endl; +//// +//// if (mag(axx) >= minAngle) +//// { +//// tmpA.xx() = mag(a.xx()); tmpA.xy() = mag(a.xy()); tmpA.xz() = mag(a.xz()); +//// minAngle = mag(axx); +//// } +//// if (mag(axy) >= minAngle) +//// { +//// tmpA.xx() = mag(a.yx()); tmpA.xy() = mag(a.yy()); tmpA.xz() = mag(a.yz()); +//// minAngle = mag(axy); +//// } +//// if (mag(axz) >= minAngle) +//// { +//// tmpA.xx() = mag(a.zx()); tmpA.xy() = mag(a.zy()); tmpA.xz() = mag(a.zz()); +//// } +//// +//// minAngle = 0; +//// +//// if (mag(ayx) >= minAngle) +//// { +//// tmpA.yx() = mag(a.xx()); tmpA.yy() = mag(a.xy()); tmpA.yz() = mag(a.xz()); +//// minAngle = mag(ayx); +//// } +//// if (mag(ayy) >= minAngle) +//// { +//// tmpA.yx() = mag(a.yx()); tmpA.yy() = mag(a.yy()); tmpA.yz() = mag(a.yz()); +//// minAngle = mag(ayy); +//// } +//// if (mag(ayz) >= minAngle) +//// { +//// tmpA.yx() = mag(a.zx()); tmpA.yy() = mag(a.zy()); tmpA.yz() = mag(a.zz()); +//// } +//// +//// minAngle = 0; +//// +//// if (mag(azx) >= minAngle) +//// { +//// tmpA.zx() = mag(a.xx()); tmpA.zy() = mag(a.xy()); tmpA.zz() = mag(a.xz()); +//// minAngle = mag(azx); +//// } +//// if (mag(azy) >= minAngle) +//// { +//// tmpA.zx() = mag(a.yx()); tmpA.zy() = mag(a.yy()); tmpA.zz() = mag(a.yz()); +//// minAngle = mag(azy); +//// } +//// if (mag(azz) >= minAngle) +//// { +//// tmpA.zx() = mag(a.zx()); tmpA.zy() = mag(a.zy()); tmpA.zz() = mag(a.zz()); +//// } +//// +//// alignments[aI] = tmpA; +//// } +// +// scalar nearest = 0; +// +//// Info<< nl << "Point " << pt << endl; +//// +//// FixedList<quaternion, 4> qAlignments; +//// forAll(qAlignments, aI) +//// { +////// Info<< " Direction " << aI << endl; +////// Info<< " Rot tensor" << alignments[aI] << endl; +//// qAlignments[aI] = quaternion(alignments[aI]); +//// qAlignments[aI].normalize(); +////// Info<< " Quaternion: " << qAlignments[aI] << endl; +////// Info<< " Rot tensor from quat: " << qAlignments[aI].R() << endl; +//// } +// +// tensor alignment = Foam::tensor::zero; +// forAll(bary, pI) +// { +//// alignment += bary[pI]*ch->vertex(pI)->alignment(); +// +//// alignment += bary[pI]*alignments[pI]; +// +// // Try slerp with quaternions +// +// // Find nearest point +// if (bary[pI] > nearest) +// { +// alignment = ch->vertex(pI)->alignment(); +// nearest = bary[pI]; +// } +// } +// +//// quaternion alignment; +// +//// alignment = qAlignments[0]*bary[0] +//// + qAlignments[1]*bary[1] +//// + qAlignments[2]*bary[2] +//// + qAlignments[3]*bary[3]; +// +//// alignment = slerp(qAlignments[0], qAlignments[1], bary[0]+bary[1]+bary[2]); +//// alignment = slerp(alignment, qAlignments[2], bary[0]+bary[1]+bary[2]); +//// alignment = slerp(alignment, qAlignments[3], bary[0]+bary[1]+bary[2]); +//// alignment = slerp(alignment, qAlignments[0], bary[0]/(bary[0]+bary[1]+bary[2])); +// +//// Info<< " Interp alignment : " << alignment << endl; +//// Info<< " Interp rot tensor: " << alignment.R() << endl; +// +// return alignment; +//} +// +// +//void Foam::surfaceControl::cellSizeAndAlignment +//( +// const point& pt, +// scalar& size, +// tensor& alignment +//) const +//{ +// scalarList bary; +// Cell_handle ch; +// +// triangulatedMesh_().barycentricCoords(pt, bary, ch); +// +// size = 0; +// forAll(bary, pI) +// { +// size += bary[pI]*ch->vertex(pI)->size(); +// } +// +//// alignment = Foam::tensor::zero; +//// forAll(bary, pI) +//// { +//// alignment += bary[pI]*ch->vertex(pI)->alignment(); +//// } +// +// alignment = cellAlignment(pt); +//} + + +void Foam::searchableSurfaceControl::initialVertices +( + pointField& pts, + scalarField& sizes, + Field<triad>& alignments +) const +{ + pts = searchableSurface_.points(); + + const scalar nearFeatDistSqrCoeff = 1e-8; + + sizes.setSize(pts.size()); + alignments.setSize(pts.size()); + + forAll(pts, pI) + { + // Is the point in the extendedFeatureEdgeMesh? If so get the + // point normal, otherwise get the surface normal from + // searchableSurface + + pointIndexHit info; + label infoFeature; + allGeometry_.findFeaturePointNearest + ( + pts[pI], + nearFeatDistSqrCoeff, + info, + infoFeature + ); + + autoPtr<triad> pointAlignment; + + if (info.hit()) + { + const extendedFeatureEdgeMesh& features = + allGeometry_.features()[infoFeature]; + + vectorField norms = features.featurePointNormals(info.index()); + + // Create a triad from these norms. + pointAlignment.set(new triad()); + forAll(norms, nI) + { + pointAlignment() += norms[nI]; + } + + pointAlignment().normalize(); + pointAlignment().orthogonalize(); + } + else + { + allGeometry_.findEdgeNearest + ( + pts[pI], + nearFeatDistSqrCoeff, + info, + infoFeature + ); + + if (info.hit()) + { + const extendedFeatureEdgeMesh& features = + allGeometry_.features()[infoFeature]; + + vectorField norms = features.edgeNormals(info.index()); + + // Create a triad from these norms. + pointAlignment.set(new triad()); + forAll(norms, nI) + { + pointAlignment() += norms[nI]; + } + + pointAlignment().normalize(); + pointAlignment().orthogonalize(); + } + else + { + pointField ptField(1, pts[pI]); + scalarField distField(1, nearFeatDistSqrCoeff); + List<pointIndexHit> infoList(1, pointIndexHit()); + + searchableSurface_.findNearest(ptField, distField, infoList); + + vectorField normals(1); + searchableSurface_.getNormal(infoList, normals); + + pointAlignment.set(new triad(normals[0])); + } + } + + if (!cellSizeFunction_().cellSize(pts[pI], sizes[pI])) + { + FatalErrorIn + ( + "Foam::searchableSurfaceControl::initialVertices" + "(pointField&, scalarField&, tensorField&)" + ) << "Could not calculate cell size" + << abort(FatalError); + } + + alignments[pI] = pointAlignment(); + } +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.H new file mode 100644 index 00000000000..87f807d1347 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellShapeControl/cellSizeAndAlignmentControl/searchableSurfaceControl/searchableSurfaceControl.H @@ -0,0 +1,166 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::searchableSurfaceControl + +Description + +SourceFiles + searchableSurfaceControl.C + +\*---------------------------------------------------------------------------*/ + +#ifndef searchableSurfaceControl_H +#define searchableSurfaceControl_H + +#include "cellShapeControl.H" +#include "cellSizeFunction.H" +#include "triad.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + + +/*---------------------------------------------------------------------------*\ + Class surfaceControl Declaration +\*---------------------------------------------------------------------------*/ + +class searchableSurfaceControl +: + public cellSizeAndAlignmentControl +{ + // Private data + +// //- Reference to the searchableSurfaces object holding all geometry data + const searchableSurface& searchableSurface_; + + const conformationSurfaces& allGeometry_; + + autoPtr<cellSizeFunction> cellSizeFunction_; + + +// const conformationSurfaces& geometryToConformTo_; +// +// //- Indices of surfaces in allGeometry that are to be conformed to +// labelList surfaces_; +// +// //- A list of all of the cellSizeFunction objects +// PtrList<cellSizeFunction> cellSizeFunctions_; +// +// autoPtr<triangulatedMesh> triangulatedMesh_; +// +// +// // Private Member Functions +// +// //- +// tensor requiredAlignment +// ( +// const point& pt, +// const vectorField& ptNormals +// ) const; + + //- Disallow default bitwise copy construct + searchableSurfaceControl(const searchableSurfaceControl&); + + //- Disallow default bitwise assignment + void operator=(const searchableSurfaceControl&); + + +public: + + //- Runtime type information + TypeName("searchableSurfaceControl"); + + + // Constructors + + //- Construct from dictionary and references to conformalVoronoiMesh and + // searchableSurfaces + searchableSurfaceControl + ( + const Time& runTime, + const word& name, + const dictionary& controlFunctionDict, + const conformationSurfaces& allGeometry + ); + + //- Destructor + ~searchableSurfaceControl(); + + + // Member Functions + + // Access + +// //- Return reference to the searchableSurfaces object containing all +// // of the geometry +// inline const searchableSurfaces& geometry() const; +// +// //- Return the surface indices +// inline const labelList& surfaces() const; +// +// +// // Query +// +// //- Return the cell size at the given location +// virtual scalar cellSize(const point& pt) const; +// +// //- Return the cell alignment at the given location +// virtual tensor cellAlignment(const point& pt) const; +// +// virtual void cellSizeAndAlignment +// ( +// const point& pt, +// scalar& size, +// tensor& alignment +// ) const; + + virtual void initialVertices + ( + pointField& pts, + scalarField& sizes, + Field<triad>& alignments + ) const; + + const cellSizeFunction& sizeFunction() const + { + return cellSizeFunction_(); + } + + // Edit + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.C index 0b6acc5ca08..1cc41dc29cc 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.C @@ -26,6 +26,9 @@ License #include "cellSizeControlSurfaces.H" #include "conformalVoronoiMesh.H" #include "cellSizeFunction.H" +#include "triSurfaceMesh.H" +#include "tetrahedron.H" +#include "OFstream.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -149,15 +152,358 @@ bool Foam::cellSizeControlSurfaces::evalCellSizeFunctions } +bool Foam::cellSizeControlSurfaces::checkCoplanarTet +( + Cell_handle c, + const scalar tol +) const +{ + plane triPlane + ( + topoint(c->vertex(0)->point()), + topoint(c->vertex(1)->point()), + topoint(c->vertex(2)->point()) + ); + + // Check if the four points are roughly coplanar. If they are then we + // cannot calculate the circumcentre. Better test might be the volume + // of the tet. + if (triPlane.distance(topoint(c->vertex(3)->point())) < tol) + { + return true; + } + + return false; +} + + +bool Foam::cellSizeControlSurfaces::checkClosePoints +( + Cell_handle c, + const scalar tol +) const +{ + for (label v = 0; v < 4; ++v) + { + for (label vA = v + 1; vA < 4; ++vA) + { + if + ( + mag + ( + topoint(c->vertex(v)->point()) + - topoint(c->vertex(vA)->point()) + ) + < tol + ) + { + return true; + } + } + } + + return false; +} + + +Foam::label Foam::cellSizeControlSurfaces::refineTriangulation +( + const scalar factor +) +{ + // Check the tets and insert new points if necessary + List<Foam::point> corners(4); + List<scalar> values(4); + + DynamicList<Foam::point> pointsToInsert(T_.number_of_vertices()); + DynamicList<scalar> valuesToInsert(T_.number_of_vertices()); + + for + ( + Delaunay::Finite_cells_iterator c = T_.finite_cells_begin(); + c != T_.finite_cells_end(); + ++c + ) + { + //const point& newPoint = tet.centre(); + //Cell_handle ch = c; + +// Info<< count++ << endl; +// Info<< " " << topoint(c->vertex(0)->point()) << nl +// << " " << topoint(c->vertex(1)->point()) << nl +// << " " << topoint(c->vertex(2)->point()) << nl +// << " " << topoint(c->vertex(3)->point()) << endl; + + scalar minDist = 1e-6*defaultCellSize_; + + if (checkClosePoints(c, minDist) || checkCoplanarTet(c, minDist)) + { + continue; + } + + const Point circumcenter = CGAL::circumcenter + ( + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point() + ); + + pointFromPoint newPoint = topoint(circumcenter); + + if (geometryToConformTo_.outside(newPoint)) + { + continue; + } + + Cell_handle ch = T_.locate + ( + Point(newPoint.x(), newPoint.y(), newPoint.z()) + ); + + forAll(corners, pI) + { + corners[pI] = topoint(ch->vertex(pI)->point()); + values[pI] = ch->vertex(pI)->value(); + } + + tetPointRef tet(corners[0], corners[1], corners[2], corners[3]); + + scalarList bary; + tet.barycentric(newPoint, bary); + + scalar interpolatedSize = 0; + forAll(bary, pI) + { + interpolatedSize += bary[pI]*ch->vertex(pI)->value(); + } + + // Find largest gradient + label maxGradCorner = -1; + scalar maxGradient = 0.0; + forAll(corners, pI) + { + const scalar distance = mag(newPoint - corners[pI]); + const scalar diffSize = interpolatedSize - values[pI]; + + const scalar gradient = diffSize/distance; + + if (gradient > maxGradient) + { + maxGradient = gradient; + maxGradCorner = pI; + } + } + +// if (wallSize < 0.5*defaultCellSize_) +// { +// Info<< "Centre : " << centre +// << " (Default Size: " << defaultCellSize_ << ")" << nl +// << "Interpolated Size : " << interpolatedSize << nl +// << "Distance from wall : " << distanceSize << nl +// << "Wall size : " << wallSize << nl +// << "distanceGradient : " << distanceGradient << nl +// << "interpGradient : " << interpolatedGradient << nl << endl; +// } + + scalar minCellSize = 1e-6; + scalar initialMaxGradient = 0;//0.2*factor; + scalar initialMinGradient = 0;//0.01*(1.0/factor); + scalar idealGradient = 0.2; + + + + // Reduce strong gradients + if (maxGradient > initialMaxGradient) + { + const scalar distance2 = mag(newPoint - corners[maxGradCorner]); + + scalar newSize + = values[maxGradCorner] + idealGradient*distance2; + + pointsToInsert.append(newPoint); + valuesToInsert.append + ( + max(min(newSize, defaultCellSize_), minCellSize) + ); + } + else if (maxGradient < -initialMaxGradient) + { + const scalar distance2 = mag(newPoint - corners[maxGradCorner]); + + scalar newSize + = values[maxGradCorner] - idealGradient*distance2; + + pointsToInsert.append(newPoint); + valuesToInsert.append + ( + max(min(newSize, defaultCellSize_), minCellSize) + ); + } + + // Increase small gradients + if + ( + maxGradient < initialMinGradient + && maxGradient > 0 + && interpolatedSize < 0.5*defaultCellSize_ + ) + { + const scalar distance2 = mag(newPoint - corners[maxGradCorner]); + + scalar newSize + = values[maxGradCorner] + idealGradient*distance2; + + pointsToInsert.append(newPoint); + valuesToInsert.append + ( + max(min(newSize, defaultCellSize_), minCellSize) + ); + } + else if + ( + maxGradient > -initialMinGradient + && maxGradient < 0 + && interpolatedSize > 0.5*defaultCellSize_ + ) + { + const scalar distance2 = mag(newPoint - corners[maxGradCorner]); + + scalar newSize + = values[maxGradCorner] - idealGradient*distance2; + + pointsToInsert.append(newPoint); + valuesToInsert.append + ( + max(min(newSize, defaultCellSize_), minCellSize) + ); + } + } + + if (!pointsToInsert.empty()) + { + Info<< " Minimum Cell Size : " << min(valuesToInsert) << nl + << " Average Cell Size : " << average(valuesToInsert) << nl + << " Maximum Cell Size : " << max(valuesToInsert) << endl; + + forAll(pointsToInsert, pI) + { + Foam::point p = pointsToInsert[pI]; + + Vertex_handle v = T_.insert(Point(p.x(), p.y(), p.z())); + + v->value(valuesToInsert[pI]); + } + } + + return pointsToInsert.size(); +} + + +void Foam::cellSizeControlSurfaces::writeRefinementTriangulation() +{ + OFstream str("refinementTriangulation.obj"); + + label count = 0; + + Info<< "Write refinementTriangulation" << endl; + + for + ( + Delaunay::Finite_edges_iterator e = T_.finite_edges_begin(); + e != T_.finite_edges_end(); + ++e + ) + { + Cell_handle c = e->first; + Vertex_handle vA = c->vertex(e->second); + Vertex_handle vB = c->vertex(e->third); + + pointFromPoint p1 = topoint(vA->point()); + pointFromPoint p2 = topoint(vB->point()); + + meshTools::writeOBJ(str, p1, p2, count); + } + + + OFstream strPoints("refinementObject.obj"); + + Info<< "Write refinementObject" << endl; + + for + ( + Delaunay::Finite_vertices_iterator v = T_.finite_vertices_begin(); + v != T_.finite_vertices_end(); + ++v + ) + { + pointFromPoint p = topoint(v->point()); + + meshTools::writeOBJ + ( + strPoints, + p, + point(p.x() + v->value(), p.y(), p.z()) + ); + } + +// OFstream strDual("refinementDualPoints.obj"); +// +// Info<< "Write refinementDualPoints" << endl; +// +// for +// ( +// Delaunay::Finite_cells_iterator c = T_.finite_cells_begin(); +// c != T_.finite_cells_end(); +// ++c +// ) +// { +// Point circumcenter = CGAL::circumcenter +// ( +// c->vertex(0)->point(), +// c->vertex(1)->point(), +// c->vertex(2)->point(), +// c->vertex(3)->point() +// ); +// +// pointFromPoint p = topoint(circumcenter); +// +// if (geometryToConformTo_.inside(p)) +// { +// meshTools::writeOBJ +// ( +// strDual, +// p +// ); +// } +// } + + if (T_.is_valid()) + { + Info<< " Triangulation is valid" << endl; + } + else + { + FatalErrorIn + ( + "Foam::cellSizeControlSurfaces::writeRefinementTriangulation()" + ) << "Triangulation is not valid" + << abort(FatalError); + } +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::cellSizeControlSurfaces::cellSizeControlSurfaces ( const searchableSurfaces& allGeometry, + const conformationSurfaces& geometryToConformTo, const dictionary& motionControlDict ) : allGeometry_(allGeometry), + geometryToConformTo_(geometryToConformTo), surfaces_(), cellSizeFunctions_(), defaultCellSize_(readScalar(motionControlDict.lookup("defaultCellSize"))), @@ -214,7 +560,8 @@ Foam::cellSizeControlSurfaces::cellSizeControlSurfaces const searchableSurface& surface = allGeometry_[surfaces_[surfI]]; Info<< nl << " " << iter().keyword() << nl - << " surface: " << surfaceName << endl; + << " surface: " << surfaceName << nl + << " size : " << surface.size() << endl; cellSizeFunctions_.set ( @@ -229,11 +576,78 @@ Foam::cellSizeControlSurfaces::cellSizeControlSurfaces priorities[surfI] = cellSizeFunctions_[surfI].priority(); surfI++; + + if (isA<triSurfaceMesh>(surface)) + { + const triSurfaceMesh& tsm + = refCast<const triSurfaceMesh>(surface); + + const pointField& points = tsm.points(); + + Info<< " number of points: " << tsm.nPoints() << endl; + + std::vector<std::pair<Point, scalar> > pointsToInsert; + + forAll(points, pI) + { + size_t nVert = T_.number_of_vertices(); + + Vertex_handle v = T_.insert + ( + Point(points[pI].x(), points[pI].y(), points[pI].z()) + ); + + if (T_.number_of_vertices() == nVert) + { + Info<< "Failed to insert point : " << points[pI] << endl; + } + + // Get the value of the point from surfaceCellSizeFunction. If + // adding points internally then will need to interpolate. + scalar newSize = 0; + cellSizeFunctions_[surfI-1].cellSize(points[pI], newSize); + v->value(newSize); + } + } } + scalar factor = 1.0; + label maxIteration = 1; + + for (label iteration = 0; iteration < maxIteration; ++iteration) + { + Info<< "Iteration : " << iteration << endl; + + label nRefined = refineTriangulation(factor); + + Info<< " Number of cells refined in refinement iteration : " + << nRefined << nl << endl; + + if (nRefined <= 0 && iteration != 0) + { + break; + } + + factor *= 1.5; + } + + writeRefinementTriangulation(); + + Info<< nl << "Refinement triangulation information: " << endl; + Info<< " Number of vertices: " << label(T_.number_of_vertices()) << endl; + Info<< " Number of cells : " + << label(T_.number_of_finite_cells()) << endl; + Info<< " Number of faces : " + << label(T_.number_of_finite_facets()) << endl; + Info<< " Number of edges : " + << label(T_.number_of_finite_edges()) << endl; + Info<< " Dimensionality : " << label(T_.dimension()) << nl << endl; + + // Sort cellSizeFunctions_ and surfaces_ by priority. Cut off any surfaces // where priority < defaultPriority_ + labelList sortedIndices; sortedOrder(priorities, sortedIndices); @@ -282,8 +696,40 @@ Foam::scalar Foam::cellSizeControlSurfaces::cellSize { scalar size = defaultCellSize_; -// bool anyFunctionFound = evalCellSizeFunctions(pt, size); - evalCellSizeFunctions(pt, size); + bool refinementTriangulationSwitch = true; + + if (!refinementTriangulationSwitch) + { + evalCellSizeFunctions(pt, size); + } + else + { + Cell_handle ch = T_.locate + ( + Point(pt.x(), pt.y(), pt.z()), + oldCellHandle_ + ); + + oldCellHandle_ = ch; + + pointFromPoint pA = topoint(ch->vertex(0)->point()); + pointFromPoint pB = topoint(ch->vertex(1)->point()); + pointFromPoint pC = topoint(ch->vertex(2)->point()); + pointFromPoint pD = topoint(ch->vertex(3)->point()); + + tetPointRef tet(pA, pB, pC, pD); + + scalarList bary; + tet.barycentric(pt, bary); + + scalar value = 0; + forAll(bary, pI) + { + value += bary[pI]*ch->vertex(pI)->value(); + } + + size = value; + } //if (!anyFunctionFound) //{ diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H index 9f522f0dfcf..de3e9d75c11 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeControlSurfaces.H @@ -37,9 +37,92 @@ SourceFiles #include "searchableSurfaces.H" #include "searchableSurfacesQueries.H" +#include "conformationSurfaces.H" + +#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> +#include <CGAL/Delaunay_triangulation_3.h> +#include <CGAL/Triangulation_vertex_base_with_info_3.h> // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +template < class GT, class Vb = CGAL::Triangulation_vertex_base_3<GT> > +class vertexWithInfo +: + public Vb +{ +public: + + Foam::scalar value_; + + Foam::tensor alignment_; + + typedef typename Vb::Vertex_handle Vertex_handle; + typedef typename Vb::Cell_handle Cell_handle; + typedef typename Vb::Point Point; + + template < class TDS2 > + struct Rebind_TDS + { + typedef typename Vb::template Rebind_TDS<TDS2>::Other Vb2; + typedef vertexWithInfo<GT, Vb2> Other; + }; + + vertexWithInfo() + : + Vb(), + value_(0.0), + alignment_(Foam::tensor::zero) + {} + + explicit vertexWithInfo(const Point& p) + : + Vb(p), + value_(0.0), + alignment_(Foam::tensor::zero) + {} + + vertexWithInfo(const Point& p, const Foam::scalar& value) + : + Vb(p), + value_(value), + alignment_(Foam::tensor::zero) + {} + + vertexWithInfo + ( + const Point& p, + const Foam::scalar& value, + const Foam::tensor& alignment + ) + : + Vb(p), + value_(value), + alignment_(alignment) + {} + + + const Foam::scalar& value() const + { + return value_; + } + + void value(const Foam::scalar& value) + { + value_ = value; + } + + const Foam::tensor& alignment() const + { + return alignment_; + } + + void alignment(const Foam::tensor& alignment) + { + alignment_ = alignment; + } +}; + + namespace Foam { @@ -55,11 +138,29 @@ class cellSizeFunction; class cellSizeControlSurfaces { + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + typedef CGAL::Triangulation_data_structure_3<vertexWithInfo<K> > Tds; + + typedef CGAL::Delaunay_triangulation_3<K, Tds, CGAL::Fast_location> + Delaunay; + + typedef Delaunay::Cell_handle Cell_handle; + typedef Delaunay::Vertex_handle Vertex_handle; + typedef Delaunay::Locate_type Locate_type; + typedef Delaunay::Point Point; + + Delaunay T_; + + mutable Cell_handle oldCellHandle_; + + // Private data //- Reference to the searchableSurfaces object holding all geometry data const searchableSurfaces& allGeometry_; + const conformationSurfaces& geometryToConformTo_; + //- Indices of surfaces in allGeometry that are to be conformed to labelList surfaces_; @@ -84,6 +185,14 @@ class cellSizeControlSurfaces scalar& minSize ) const; + bool checkCoplanarTet(Cell_handle c, const scalar tol) const; + + bool checkClosePoints(Cell_handle c, const scalar tol) const; + + label refineTriangulation(const scalar factor); + + void writeRefinementTriangulation(); + //- Disallow default bitwise copy construct cellSizeControlSurfaces(const cellSizeControlSurfaces&); @@ -104,6 +213,7 @@ public: cellSizeControlSurfaces ( const searchableSurfaces& allGeometry, + const conformationSurfaces& geometryToConformTo, const dictionary& motionControlDict ); diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.C index 12761336234..995d10fdc37 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.C @@ -56,8 +56,7 @@ Foam::cellSizeFunction::cellSizeFunction ) ), coeffsDict_(subDict(type + "Coeffs")), - sideMode_(), - priority_(readLabel(cellSizeFunctionDict.lookup("priority"))) + sideMode_() { word mode = cellSizeFunctionDict.lookup("mode"); @@ -77,7 +76,7 @@ Foam::cellSizeFunction::cellSizeFunction } else { - FatalErrorIn("cellSizeFunction::cellSizeFunction") + FatalErrorIn("searchableSurfaceControl::searchableSurfaceControl") << "Unknown mode, expected: inside, outside or bothSides" << nl << exit(FatalError); } @@ -86,7 +85,7 @@ Foam::cellSizeFunction::cellSizeFunction { if (mode != "bothSides") { - WarningIn("cellSizeFunction::cellSizeFunction") + WarningIn("searchableSurfaceControl::searchableSurfaceControl") << "surface does not support volumeType, defaulting mode to " << "bothSides." << endl; diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.H index 1e6fd4442eb..58ee5d5e0fd 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/cellSizeFunction/cellSizeFunction/cellSizeFunction.H @@ -59,9 +59,6 @@ class cellSizeFunction public: - //- Runtime type information - TypeName("cellSizeFunction"); - //- Surface side mode enum sideMode { @@ -70,6 +67,9 @@ public: rmBothsides // Control on both sides of a surface }; + //- Runtime type information + TypeName("cellSizeFunction"); + protected: @@ -97,9 +97,6 @@ protected: //- Mode of size specification, i.e. inside, outside or bothSides sideMode sideMode_; - //- Priority of this cellSizeFunction - label priority_; - private: @@ -162,11 +159,6 @@ public: return coeffsDict_; } - inline label priority() const - { - return priority_; - } - //- Modify scalar argument to the cell size specified by function. // Return a boolean specifying if the function was used, i.e. false if // the point was not in range of the surface for a spatially varying diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.C index d30cc2a5ffe..e8f09cf5f11 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.C @@ -26,6 +26,7 @@ License #include "automatic.H" #include "addToRunTimeSelectionTable.H" #include "triSurfaceMesh.H" +#include "vtkSurfaceWriter.H" #include "Time.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -36,6 +37,59 @@ namespace Foam addToRunTimeSelectionTable(cellSizeCalculationType, automatic, dictionary); } + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::automatic::smoothField(triSurfaceScalarField& surf) +{ + label nSmoothingIterations = 10; + + for (label iter = 0; iter < nSmoothingIterations; ++iter) + { + const pointField& faceCentres = surface_.faceCentres(); + + forAll(surf, sI) + { + const labelList& faceFaces = surface_.faceFaces()[sI]; + + const point& fC = faceCentres[sI]; + const scalar value = surf[sI]; + + scalar newValue = 0; + scalar totalDist = 0; + + label nFaces = 0; + + forAll(faceFaces, fI) + { + const label faceLabel = faceFaces[fI]; + const point& faceCentre = faceCentres[faceLabel]; + + const scalar faceValue = surf[faceLabel]; + const scalar distance = mag(faceCentre - fC); + + newValue += faceValue/distance; + + totalDist += 1.0/distance; + + if (value < faceValue) + { + nFaces++; + } + } + + // Do not smooth out the peak values + if (nFaces == faceFaces.size()) + { + //continue; + } + + surf[sI] = newValue/totalDist; + } + } +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::automatic::automatic @@ -90,7 +144,8 @@ Foam::triSurfaceScalarField Foam::automatic::load() if (readCurvature_) { - Info<< indent << "Reading curvature: " << curvatureFile_ << endl; + Info<< indent << "Reading curvature : " + << curvatureFile_ << endl; triSurfacePointScalarField curvature ( @@ -174,7 +229,7 @@ Foam::triSurfaceScalarField Foam::automatic::load() if (readFeatureProximity_) { - Info<< indent << "Reading feature proximity: " + Info<< indent << "Reading feature proximity : " << featureProximityFile_ << endl; triSurfaceScalarField featureProximity @@ -204,8 +259,34 @@ Foam::triSurfaceScalarField Foam::automatic::load() } } + smoothField(surfaceCellSize); + surfaceCellSize.write(); + debug = 1; + + if (debug) + { + faceList faces(surface_.size()); + + forAll(surface_, fI) + { + faces[fI] = surface_.triSurface::operator[](fI).triFaceFace(); + } + + vtkSurfaceWriter().write + ( + surface_.searchableSurface::time().constant()/"triSurface", + surfaceName_, + surface_.points(), + faces, + "cellSize", + surfaceCellSize, + false, + true + ); + } + return surfaceCellSize; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.H index 04d8ed7ddb2..4288176e8f3 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cellSizeControlSurfaces/surfaceCellSizeFunction/cellSizeCalculationType/automatic/automatic.H @@ -85,6 +85,11 @@ private: const scalar maximumCellSize_; + // Private Member Functions + + void smoothField(triSurfaceScalarField& surf); + + public: //- Runtime type information diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3DKernel.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3DKernel.H new file mode 100644 index 00000000000..e80b3fb8f4b --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3DKernel.H @@ -0,0 +1,62 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Typedefs + CGALTriangulation3DKernel + +Description + +\*---------------------------------------------------------------------------*/ + +#ifndef CGALTriangulation3DKernel_H +#define CGALTriangulation3DKernel_H + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "CGAL/Delaunay_triangulation_3.h" + +#ifdef CGAL_INEXACT + + // Fast kernel using a double as the storage type but the triangulation may + // fail. Adding robust circumcentre traits + #include "CGAL/Exact_predicates_inexact_constructions_kernel.h" + typedef CGAL::Exact_predicates_inexact_constructions_kernel baseK; +// #include <CGAL/Robust_circumcenter_traits_3.h> + #include <CGAL/Robust_circumcenter_filtered_traits_3.h> +// typedef CGAL::Robust_circumcenter_traits_3<baseK> K; + typedef CGAL::Robust_circumcenter_filtered_traits_3<baseK> K; + +#else + + // Very robust but expensive kernel + #include "CGAL/Exact_predicates_exact_constructions_kernel.h" + typedef CGAL::Exact_predicates_exact_constructions_kernel baseK; + typedef CGAL::Exact_predicates_exact_constructions_kernel K; + +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H index 72d44618a21..4e7dd48c38c 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/CGALTriangulation3Ddefs.H @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Typedefs CGALTriangulation3Ddefs @@ -43,76 +38,20 @@ Description // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#include "CGAL/Delaunay_triangulation_3.h" +#include "CGALTriangulation3DKernel.H" #include "indexedVertex.H" #include "indexedCell.H" -#ifdef CGAL_INEXACT - // Fast kernel using a double as the storage type but the triangulation may - // fail. Adding robust circumcentre traits - #include "CGAL/Exact_predicates_inexact_constructions_kernel.h" - #include <CGAL/Robust_circumcenter_traits_3.h> - typedef CGAL::Exact_predicates_inexact_constructions_kernel inexactK; - typedef CGAL::Robust_circumcenter_traits_3<inexactK> K; -#else - // Very robust but expensive kernel - #include "CGAL/Exact_predicates_exact_constructions_kernel.h" - typedef CGAL::Exact_predicates_exact_constructions_kernel K; -#endif +typedef CGAL::indexedVertex<K> Vb; +typedef CGAL::indexedCell<K> Cb; -typedef CGAL::indexedVertex<K> Vb; -typedef CGAL::indexedCell<K> Cb; - -typedef CGAL::Triangulation_data_structure_3<Vb, Cb> Tds; -typedef CGAL::Delaunay_triangulation_3<K, Tds, CGAL::Fast_location> Delaunay; - -typedef Delaunay::Vertex_handle Vertex_handle; -typedef Delaunay::Cell_handle Cell_handle; -typedef Delaunay::Point Point; - - -//- Spatial sort traits to use with a pair of point pointers and an integer. -// Taken from a post on the CGAL lists: 2010-01/msg00004.html by -// Sebastien Loriot (Geometry Factory). -template<class Triangulation> -struct Traits_for_spatial_sort -: - public Triangulation::Geom_traits -{ - typedef typename Triangulation::Geom_traits Gt; - - typedef std::pair<const typename Triangulation::Point*, int> Point_3; - - struct Less_x_3 - { - bool operator()(const Point_3& p, const Point_3& q) const - { - return typename Gt::Less_x_3()(*(p.first), *(q.first)); - } - }; - - struct Less_y_3 - { - bool operator()(const Point_3& p, const Point_3& q) const - { - return typename Gt::Less_y_3()(*(p.first), *(q.first)); - } - }; - - struct Less_z_3 - { - bool operator()(const Point_3& p, const Point_3& q) const - { - return typename Gt::Less_z_3()(*(p.first), *(q.first)); - } - }; - - Less_x_3 less_x_3_object () const {return Less_x_3();} - Less_y_3 less_y_3_object () const {return Less_y_3();} - Less_z_3 less_z_3_object () const {return Less_z_3();} -}; +typedef CGAL::Compact_location CompactLocator; +typedef CGAL::Fast_location FastLocator; +typedef CGAL::Triangulation_data_structure_3<Vb, Cb> Tds; +typedef CGAL::Delaunay_triangulation_3<K, Tds, CompactLocator> Delaunay; +typedef CGAL::Delaunay_triangulation_3<K, Tds, FastLocator> CellSizeDelaunay; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C index de23690ea43..8f229fdbc14 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.C @@ -27,8 +27,11 @@ License #include "initialPointsMethod.H" #include "relaxationModel.H" #include "faceAreaWeightModel.H" -#include "backgroundMeshDecomposition.H" #include "meshSearch.H" +#include "vectorTools.H" +#include "IOmanip.H" +#include "indexedCellChecks.H" + // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -72,7 +75,7 @@ Foam::scalar Foam::conformalVoronoiMesh::requiredSize << exit(FatalError) << endl; } - cellSizeHits.append(cellSizeControl().cellSize(pt)); + cellSizeHits.append(cellShapeControls().cellSize(pt)); // Primary alignment @@ -135,7 +138,7 @@ Foam::scalar Foam::conformalVoronoiMesh::requiredSize cellSizeHits.append ( - cellSizeControl().cellSize(hitPt) + cellShapeControls().cellSize(hitPt) ); totalDist += spokeHitDistance; @@ -161,7 +164,7 @@ Foam::scalar Foam::conformalVoronoiMesh::requiredSize cellSizeHits.append ( - cellSizeControl().cellSize(hitPt) + cellShapeControls().cellSize(hitPt) ); totalDist += spokeHitDistance; @@ -176,7 +179,7 @@ Foam::scalar Foam::conformalVoronoiMesh::requiredSize } return cellSize/cellSizeHits.size(); - //return cellSizeControl().cellSize(pt); + //return cellShapeControls().cellSize(pt); } @@ -355,14 +358,12 @@ Foam::tensor Foam::conformalVoronoiMesh::requiredAlignment } -void Foam::conformalVoronoiMesh::insertPoints +void Foam::conformalVoronoiMesh::insertInternalPoints ( List<Point>& points, bool distribute ) { - label preInsertionSize(number_of_vertices()); - label nPoints = points.size(); if (Pstream::parRun()) @@ -374,37 +375,12 @@ void Foam::conformalVoronoiMesh::insertPoints if (Pstream::parRun() && distribute) { - label preDistributionSize(points.size()); - - DynamicList<Foam::point> transferPoints; - - DynamicList<Point> pointsOnProcessor; - - for - ( - List<Point>::iterator pit = points.begin(); - pit != points.end(); - ++pit - ) - { - Foam::point p(topoint(*pit)); - - if (!positionOnThisProc(p)) - { - transferPoints.append(p); - } - else - { - pointsOnProcessor.append(*pit); - } - } + List<Foam::point> transferPoints(points.size()); - points.setSize(pointsOnProcessor.size()); - forAll(pointsOnProcessor, pI) + forAll(points, pI) { - points[pI] = pointsOnProcessor[pI]; + transferPoints[pI] = topoint(points[pI]); } - pointsOnProcessor.clear(); // Send the points that are not on this processor to the appropriate // place @@ -413,41 +389,7 @@ void Foam::conformalVoronoiMesh::insertPoints decomposition_().distributePoints(transferPoints) ); - const label oldSize = points.size(); - - points.setSize(oldSize + transferPoints.size()); - - forAll(transferPoints, tPI) - { - points[tPI + oldSize] = toPoint(transferPoints[tPI]); - } - - label sizeChange = preDistributionSize - points.size(); - - // if (mag(sizeChange) > 0) - // { - // Pout<< " distribution points size change " << sizeChange - // << endl; - // } - - label totalMagSizeChange = returnReduce - ( - mag(sizeChange), sumOp<label>() - ); - - if (totalMagSizeChange > 0) - { - Info<< " distribution points size change total " - << totalMagSizeChange/2 - << endl; - } - - nPoints = points.size(); - - reduce(nPoints, sumOp<label>()); - - Info<< " " << nPoints - << " points to insert after distribution..." << endl; + map().distribute(points); } label nVert = number_of_vertices(); @@ -455,25 +397,18 @@ void Foam::conformalVoronoiMesh::insertPoints // using the range insert (faster than inserting points one by one) insert(points.begin(), points.end()); -// Info<< "USING INDIVIDUAL INSERTION TO DETECT FAILURE" << endl; -// for -// ( -// List<Point>::iterator pit=points.begin(); -// pit != points.end(); -// ++pit -// ) -// { -// insertPoint(topoint(*pit), Vb::vtInternal); -// } - - label nInserted(number_of_vertices() - preInsertionSize); + label nInserted(number_of_vertices() - nVert); if (Pstream::parRun()) { reduce(nInserted, sumOp<label>()); } - Info<< " " << nInserted << " points inserted" << endl; + Info<< " " << nInserted << " points inserted" + << ", failed to insert " << nPoints - nInserted + << " (" + << 100.0*(nPoints - nInserted)/nInserted + << " %)"<< endl; for ( @@ -484,7 +419,8 @@ void Foam::conformalVoronoiMesh::insertPoints { if (vit->uninitialised()) { - vit->index() = nVert++; + vit->index() = getNewVertexIndex(); + vit->type() = Vb::vtInternal; } } } @@ -492,30 +428,22 @@ void Foam::conformalVoronoiMesh::insertPoints void Foam::conformalVoronoiMesh::insertPoints ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types, + List<Vb>& vertices, bool distribute ) { - // The pts, indices and types lists must be intact and up-to-date at the - // end of this function as they may also be used by other functions - // subsequently. - if (Pstream::parRun() && distribute) { - // The link between vertices that form the boundary via pairs cannot be - // strict because both points may end up on different processors. The - // only important thing is that each vertex knows its own role. - // Therefore, index and type are set to 0 or 1, then on the destination - // processor add back the new index to both. + const label preDistributionSize = vertices.size(); + + List<Foam::point> pts(preDistributionSize); - // Each of points generated in this process are pair points, so there - // is no risk of underflowing "type". + forAll(vertices, vI) + { + const Foam::point& pt = topoint(vertices[vI].point()); - // Pout<< "Points before " - // << pts.size() << " " << indices.size() << " " << types.size() - // << endl; + pts[vI] = pt; + } // Distribute points to their appropriate processor autoPtr<mapDistribute> map @@ -523,97 +451,71 @@ void Foam::conformalVoronoiMesh::insertPoints decomposition_().distributePoints(pts) ); - map().distribute(indices); - map().distribute(types); + map().distribute(vertices); - // Pout<< "Points after " - // << pts.size() << " " << indices.size() << " " << types.size() - // << endl; - - // Info<< returnReduce(pts.size(), sumOp<label>()) - // << " points in total" << endl; + forAll(vertices, vI) + { + vertices[vI].procIndex() = Pstream::myProcNo(); + } } -// -// forAll(pts, pI) -// { -// // creation of points and indices is done assuming that it will be -// // relative to the instantaneous number_of_vertices() at insertion. -// -// label type = types[pI]; -// -// if (type > Vb::vtFar) -// { -// // This is a member of a point pair, don't use the type directly -// // (note that this routine never gets called for referredPoints -// // so type will never be -procI) -// type += number_of_vertices(); -// } -// -// insertPoint -// ( -// pts[pI], -// indices[pI] + number_of_vertices(), -// type -// ); -// } rangeInsertWithInfo ( - pts.begin(), - pts.end(), - *this, - indices, - types + vertices.begin(), + vertices.end(), + true ); } void Foam::conformalVoronoiMesh::insertSurfacePointPairs ( - const List<pointIndexHit>& surfaceHits, - const List<label>& hitSurfaces, + const pointIndexHitAndFeatureList& surfaceHits, const fileName fName ) { - if (surfaceHits.size() != hitSurfaces.size()) - { - FatalErrorIn("Foam::conformalVoronoiMesh::insertPointPairs") - << "surfaceHits and hitSurfaces are not the same size. Sizes " - << surfaceHits.size() << ' ' - << hitSurfaces.size() - << exit(FatalError); - } - - DynamicList<Foam::point> pts; - DynamicList<label> indices; - DynamicList<label> types; + DynamicList<Vb> pts(2.0*surfaceHits.size()); forAll(surfaceHits, i) { vectorField norm(1); - allGeometry_[hitSurfaces[i]].getNormal + const pointIndexHit surfaceHit = surfaceHits[i].first(); + const label featureIndex = surfaceHits[i].second(); + + allGeometry_[featureIndex].getNormal ( - List<pointIndexHit>(1, surfaceHits[i]), + List<pointIndexHit>(1, surfaceHit), norm ); const vector& normal = norm[0]; - const Foam::point& surfacePt(surfaceHits[i].hitPoint()); + const Foam::point& surfacePt(surfaceHit.hitPoint()); - createPointPair - ( - pointPairDistance(surfacePt), - surfacePt, - normal, - pts, - indices, - types - ); + if (geometryToConformTo_.isBaffle(featureIndex)) + { + createBafflePointPair + ( + pointPairDistance(surfacePt), + surfacePt, + normal, + pts + ); + } + else + { + createPointPair + ( + pointPairDistance(surfacePt), + surfacePt, + normal, + pts + ); + } } - insertPoints(pts, indices, types, true); + insertPoints(pts, true); if (cvMeshControls().objOutput() && fName != fileName::null) { @@ -624,35 +526,25 @@ void Foam::conformalVoronoiMesh::insertSurfacePointPairs void Foam::conformalVoronoiMesh::insertEdgePointGroups ( - const List<pointIndexHit>& edgeHits, - const labelList& featuresHit, + const pointIndexHitAndFeatureList& edgeHits, const fileName fName ) { - if (edgeHits.size() != featuresHit.size()) - { - FatalErrorIn("Foam::conformalVoronoiMesh::insertEdgePointGroups") - << "edgeHits and featuresHit are not the same size. Sizes " - << edgeHits.size() << ' ' - << featuresHit.size() - << exit(FatalError); - } - - DynamicList<Foam::point> pts; - DynamicList<label> indices; - DynamicList<label> types; + DynamicList<Vb> pts(3.0*edgeHits.size()); forAll(edgeHits, i) { const extendedFeatureEdgeMesh& feMesh ( - geometryToConformTo_.features()[featuresHit[i]] + geometryToConformTo_.features()[edgeHits[i].second()] ); - createEdgePointGroup(feMesh, edgeHits[i], pts, indices, types); + createEdgePointGroup(feMesh, edgeHits[i].first(), pts); } - insertPoints(pts, indices, types, true); + pts.shrink(); + + insertPoints(pts, true); if (cvMeshControls().objOutput() && fName != fileName::null) { @@ -680,20 +572,6 @@ bool Foam::conformalVoronoiMesh::nearFeaturePt(const Foam::point& pt) const } -void Foam::conformalVoronoiMesh::reset(const bool distribute) -{ - this->clear(); - - reinsertBoundingPoints(); - - // Reinsert feature points, distributing them as necessary. - reinsertFeaturePoints(distribute); - //insertFeaturePoints(); - - startOfInternalPoints_ = number_of_vertices(); -} - - void Foam::conformalVoronoiMesh::insertInitialPoints() { Info<< nl << "Inserting initial points" << endl; @@ -706,13 +584,43 @@ void Foam::conformalVoronoiMesh::insertInitialPoints() // Assume that the initial points method made the correct decision for // which processor each point should be on, so give distribute = false - insertPoints(initPts, false); + insertInternalPoints(initPts); +} - if (cvMeshControls().objOutput()) + +Foam::scalar Foam::conformalVoronoiMesh::calculateLoadUnbalance() const +{ + label nRealVertices = 0; + + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) { - writePoints("initialPoints.obj", true); + // Only store real vertices that are not feature vertices + if (vit->real() && !vit->featurePoint()) + { + nRealVertices++; + } } + scalar globalNRealVertices = returnReduce + ( + nRealVertices, + sumOp<label>() + ); + + scalar unbalance = returnReduce + ( + mag(1.0 - nRealVertices/(globalNRealVertices/Pstream::nProcs())), + maxOp<scalar>() + ); + + Info<< " Processor unbalance " << unbalance << endl; + + return unbalance; } @@ -729,52 +637,29 @@ bool Foam::conformalVoronoiMesh::distributeBackground() label iteration = 0; + scalar previousLoadUnbalance = 0; + while (true) { - label nRealVertices = 0; + scalar maxLoadUnbalance = calculateLoadUnbalance(); - for + if ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ + maxLoadUnbalance <= cvMeshControls().maxLoadUnbalance() + || maxLoadUnbalance <= previousLoadUnbalance ) - { - // Only store real vertices that are not feature vertices - if (vit->real() && vit->index() >= startOfInternalPoints_) - { - nRealVertices++; - } - } - - scalar globalNRealVertices = returnReduce - ( - nRealVertices, - sumOp<label>() - ); - - scalar unbalance = returnReduce - ( - mag(1.0 - nRealVertices/(globalNRealVertices/Pstream::nProcs())), - maxOp<scalar>() - ); - - Info<< " Processor unbalance " << unbalance << endl; - - if (unbalance <= cvMeshControls().maxLoadUnbalance()) { // If this is the first iteration, return false, if it was a // subsequent one, return true; return iteration != 0; } + previousLoadUnbalance = maxLoadUnbalance; + Info<< " Total number of vertices before redistribution " << returnReduce(label(number_of_vertices()), sumOp<label>()) << endl; - // Pout<< " Real vertices before distribution " - // << nRealVertices << endl; - const fvMesh& bMesh = decomposition_().mesh(); volScalarField cellWeights @@ -794,42 +679,36 @@ bool Foam::conformalVoronoiMesh::distributeBackground() meshSearch cellSearch(bMesh, polyMesh::FACEPLANES); - List<DynamicList<Foam::point> > cellVertices(bMesh.nCells()); - List<DynamicList<label> > cellVertexIndices(bMesh.nCells()); - List<DynamicList<label> > cellVertexTypes(bMesh.nCells()); + labelList cellVertices(bMesh.nCells(), 0); for ( Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); - vit++ + ++vit ) { // Only store real vertices that are not feature vertices - if (vit->real() && vit->index() >= startOfInternalPoints_) + if (vit->real() && !vit->featurePoint()) { - Foam::point v = topoint(vit->point()); + pointFromPoint v = topoint(vit->point()); label cellI = cellSearch.findCell(v); if (cellI == -1) { - // Pout<< "findCell conformalVoronoiMesh::distribute " - // << "findCell " - // << vit->type() << " " - // << vit->index() << " " - // << v << " " - // << cellI - // << " find nearest cellI "; +// Pout<< "findCell conformalVoronoiMesh::distribute " +// << "findCell " +// << vit->type() << " " +// << vit->index() << " " +// << v << " " +// << cellI +// << " find nearest cellI "; cellI = cellSearch.findNearestCell(v); - - Pout<< cellI << endl; } - cellVertices[cellI].append(topoint(vit->point())); - cellVertexIndices[cellI].append(vit->index()); - cellVertexTypes[cellI].append(vit->type()); + cellVertices[cellI]++; } } @@ -840,76 +719,150 @@ bool Foam::conformalVoronoiMesh::distributeBackground() // the sum of the normalised weight field. cellWeights.internalField()[cI] = max ( - cellVertices[cI].size(), + cellVertices[cI], 1e-2 ); } autoPtr<mapDistributePolyMesh> mapDist = decomposition_().distribute ( - cellWeights, - cellVertices, - cellVertexIndices, - cellVertexTypes + cellWeights ); - // Reset the entire tessellation - reset(true); + cellShapeControl_.shapeControlMesh().distribute(decomposition_); - timeCheck("Distribution performed"); + distribute(); - Info<< nl << " Inserting distributed tessellation" << endl; + timeCheck("After distribute"); - DynamicList<Foam::point> pointsToInsert; - DynamicList<label> indices; - DynamicList<label> types; + iteration++; + } - forAll(cellVertices, cI) - { - forAll(cellVertices[cI], cVPI) - { - pointsToInsert.append(cellVertices[cI][cVPI]); + return true; +} - // All insertions relative to index of zero - indices.append(0); - label type = cellVertexTypes[cI][cVPI]; +void Foam::conformalVoronoiMesh::distribute() +{ + if (!Pstream::parRun()) + { + return ; + } - if (type > Vb::vtFar) - { - // This is a member of a point pair, don't use the type - // directly, make type relative to the index in preparation - // for insertion. + autoPtr<mapDistribute> mapDist = + DistributedDelaunayMesh<Delaunay>::distribute(decomposition_()); - type -= cellVertexIndices[cI][cVPI]; - } + DynamicList<Foam::point> points(number_of_vertices()); + DynamicList<Foam::indexedVertexEnum::vertexType> types + ( + number_of_vertices() + ); + DynamicList<scalar> sizes(number_of_vertices()); + DynamicList<tensor> alignments(number_of_vertices()); - types.append(type); - } + for + ( + Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->real()) + { + points.append(topoint(vit->point())); + types.append(vit->type()); + sizes.append(vit->targetCellSize()); + alignments.append(vit->alignment()); } + } - // Assume that the distribution made the correct decision for which - // processor each point should be on, so give distribute = false - insertPoints(pointsToInsert, indices, types, false); + mapDist().distribute(points); + mapDist().distribute(types); + mapDist().distribute(sizes); + mapDist().distribute(alignments); - Info<< " Total number of vertices after redistribution " - << returnReduce(label(number_of_vertices()), sumOp<label>()) - << endl; + // Reset the entire tessellation + DelaunayMesh<Delaunay>::reset(); - // Pout<< " Real vertices after distribution " - // << label(number_of_vertices() - 8) << endl; + Info<< nl << " Inserting distributed tessellation" << endl; - if (cvMeshControls().objOutput()) + // Internal points have to be inserted first + + DynamicList<Vb> verticesToInsert(points.size()); + + forAll(points, pI) + { + verticesToInsert.append + ( + Vb + ( + toPoint<Point>(points[pI]), + -1, + types[pI], + Pstream::myProcNo() + ) + ); + + verticesToInsert.last().targetCellSize() = sizes[pI]; + verticesToInsert.last().alignment() = alignments[pI]; + } + + this->rangeInsertWithInfo + ( + verticesToInsert.begin(), + verticesToInsert.end(), + true + ); + + Info<< " Total number of vertices after redistribution " + << returnReduce + ( + label(number_of_vertices()), sumOp<label>() + ) + << endl; +} + + +void Foam::conformalVoronoiMesh::buildCellSizeAndAlignmentMesh() +{ + cellShapeControl_.initialMeshPopulation(decomposition_); + + cellShapeControlMesh& cellSizeMesh = cellShapeControl_.shapeControlMesh(); + + if (Pstream::parRun()) + { + cellSizeMesh.distribute(decomposition_); + } + + label nMaxIter = 2; + + for (label i = 0; i < nMaxIter; ++i) + { + label nAdded = cellShapeControl_.refineMesh(decomposition_); + reduce(nAdded, sumOp<label>()); + +// label nRemoved = cellShapeControl_.shapeControlMesh().removePoints(); + + if (Pstream::parRun()) { - writePoints("distributedPoints.obj", true); + cellSizeMesh.distribute(decomposition_); } - timeCheck("After distribute"); + if (nAdded == 0) + { + break; + } - iteration++; + Info<< " Iteration " << i << ": Added = " << nAdded << " points" + << endl; } - return true; + cellShapeControl_.smoothMesh(); + + Info<< "Background cell size and alignment mesh:" << endl; + cellSizeMesh.printInfo(Info); + +// cellSizeMesh.write(); } @@ -941,41 +894,48 @@ void Foam::conformalVoronoiMesh::storeSizesAndAlignments const List<Point>& storePts ) { - timeCheck("Start of storeSizesAndAlignments"); - - Info << nl << "Store size and alignment" << endl; - - sizeAndAlignmentLocations_.setSize(storePts.size()); - - storedSizes_.setSize(sizeAndAlignmentLocations_.size()); - - storedAlignments_.setSize(sizeAndAlignmentLocations_.size()); - - label i = 0; - - checkCellSizing(); - - for - ( - List<Point>::const_iterator pit = storePts.begin(); - pit != storePts.end(); - ++pit - ) - { - sizeAndAlignmentLocations_[i] = topoint(*pit); - - storedSizes_[i] = requiredSize(sizeAndAlignmentLocations_[i]); - - storedAlignments_[i] = requiredAlignment(sizeAndAlignmentLocations_[i]); - - i++; - } - - timeCheck("Sizes and alignments calculated, build tree"); - - buildSizeAndAlignmentTree(); - - timeCheck("Size and alignment tree built"); +// timeCheck("Start of storeSizesAndAlignments"); +// +// Info << nl << "Store size and alignment" << endl; +// +// sizeAndAlignmentLocations_.setSize(storePts.size()); +// +// storedSizes_.setSize(sizeAndAlignmentLocations_.size()); +// +// storedAlignments_.setSize(sizeAndAlignmentLocations_.size()); +// +// label i = 0; +// +// //checkCellSizing(); +// +// for +// ( +// List<Point>::const_iterator pit = storePts.begin(); +// pit != storePts.end(); +// ++pit +// ) +// { +// pointFromPoint pt = topoint(*pit); +// +//// storedAlignments_[i] = requiredAlignment(pt); +//// +//// storedSizes_[i] = cellShapeControls().cellSize(pt); +// +// cellShapeControls().cellSizeAndAlignment +// ( +// pt, +// storedSizes_[i], +// storedAlignments_[i] +// ); +// +// i++; +// } +// +// timeCheck("Sizes and alignments calculated, build tree"); +// +// buildSizeAndAlignmentTree(); +// +// timeCheck("Size and alignment tree built"); } @@ -1016,9 +976,51 @@ Foam::conformalVoronoiMesh::sizeAndAlignmentTree() const void Foam::conformalVoronoiMesh::setVertexSizeAndAlignment() { - Info<< nl << "Looking up target cell alignment and size" << endl; +// Info<< nl << "Looking up target cell alignment and size" << endl; +// +// const indexedOctree<treeDataPoint>& tree = sizeAndAlignmentTree(); +// +// for +// ( +// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +// vit != finite_vertices_end(); +// vit++ +// ) +// { +// if +// ( +// vit->internalOrBoundaryPoint() +// || vit->referredInternalOrBoundaryPoint() +// ) +// { +// pointFromPoint pt = topoint(vit->point()); +// +// pointIndexHit info = tree.findNearest(pt, sqr(GREAT)); +// +// if (info.hit()) +// { +// vit->alignment() = storedAlignments_[info.index()]; +// +// vit->targetCellSize() = storedSizes_[info.index()]; +// } +// else +// { +// WarningIn +// ( +// "void " +// "Foam::conformalVoronoiMesh::setVertexSizeAndAlignment()" +// ) +// << "Point " << pt << " did not find a nearest point " +// << " for alignment and size lookup." << endl; +// +// vit->alignment() = cellShapeControls().cellAlignment(pt); +// +// vit->targetCellSize() = cellShapeControls().cellSize(pt); +// } +// } +// } - const indexedOctree<treeDataPoint>& tree = sizeAndAlignmentTree(); + Info<< nl << "Calculating target cell alignment and size" << endl; for ( @@ -1027,57 +1029,23 @@ void Foam::conformalVoronoiMesh::setVertexSizeAndAlignment() vit++ ) { - if - ( - vit->internalOrBoundaryPoint() - || vit->referredInternalOrBoundaryPoint() - ) + if (vit->internalOrBoundaryPoint()) { - Foam::point pt(topoint(vit->point())); + pointFromPoint pt = topoint(vit->point()); - pointIndexHit info = tree.findNearest(pt, sqr(GREAT)); - - if (info.hit()) - { - vit->alignment() = storedAlignments_[info.index()]; - - vit->targetCellSize() = storedSizes_[info.index()]; - } - else - { - WarningIn - ( - "void " - "Foam::conformalVoronoiMesh::setVertexSizeAndAlignment()" - ) - << "Point " << pt << " did not find a nearest point " - << " for alignment and size lookup." << endl; + cellShapeControls().cellSizeAndAlignment + ( + pt, + vit->targetCellSize(), + vit->alignment() + ); - vit->alignment() = requiredAlignment(pt); +// vit->alignment() = tensor(1,0,0,0,1,0,0,0,1); + //vit->alignment() = requiredAlignment(pt); - vit->targetCellSize() = cellSizeControl().cellSize(pt); - } + //vit->targetCellSize() = cellShapeControls().cellSize(pt); } } - - // Info<< nl << "Calculating target cell alignment and size" << endl; - - // for - // ( - // Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - // vit != finite_vertices_end(); - // vit++ - // ) - // { - // if (vit->internalOrBoundaryPoint()) - // { - // point pt(topoint(vit->point())); - - // vit->alignment() = requiredAlignment(pt); - - // vit->targetCellSize() = targetCellSize(pt); - // } - // } } @@ -1100,7 +1068,7 @@ Foam::face Foam::conformalVoronoiMesh::buildDualFace do { - if (cc1->farCell() || cc2->farCell()) + if (cc1->hasFarPoint() || cc2->hasFarPoint()) { Cell_handle c = eit->first; Vertex_handle vA = c->vertex(eit->second); @@ -1138,6 +1106,8 @@ Foam::face Foam::conformalVoronoiMesh::buildDualFace } while (cc1 != ccStart); + verticesOnFace.shrink(); + if (verticesOnFace.size() >= 3 && nUniqueVertices < 3) { // There are not enough unique vertices on this face to @@ -1172,7 +1142,7 @@ Foam::label Foam::conformalVoronoiMesh::maxFilterCount do { - if (cc->farCell()) + if (cc->hasFarPoint()) { Cell_handle c = eit->first; Vertex_handle vA = c->vertex(eit->second); @@ -1215,14 +1185,14 @@ bool Foam::conformalVoronoiMesh::ownerAndNeighbour label dualCellIndexA = vA->index(); - if (!vA->internalOrBoundaryPoint()) + if (!vA->internalOrBoundaryPoint() || vA->referred()) { dualCellIndexA = -1; } label dualCellIndexB = vB->index(); - if (!vB->internalOrBoundaryPoint()) + if (!vB->internalOrBoundaryPoint() || vB->referred()) { dualCellIndexB = -1; } @@ -1289,7 +1259,7 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh const dictionary& cvMeshDict ) : - Delaunay(), + DistributedDelaunayMesh<Delaunay>(), runTime_(runTime), rndGen_(64293*Pstream::myProcNo()), cvMeshControls_(cvMeshDict), @@ -1313,12 +1283,13 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh allGeometry_, cvMeshDict.subDict("surfaceConformation") ), - cellSizeControl_ + cellShapeControl_ ( + runTime_, + cvMeshDict.subDict("motionControl"), allGeometry_, - cvMeshDict.subDict("motionControl") + geometryToConformTo_ ), - startOfInternalPoints_(0), limitBounds_(), featureVertices_(), featurePointLocations_(), @@ -1354,67 +1325,112 @@ Foam::conformalVoronoiMesh::conformalVoronoiMesh ), decomposition_() { + if (cvMeshControls().objOutput()) + { + geometryToConformTo_.writeFeatureObj("cvMesh"); + } + if (Pstream::parRun()) { decomposition_.reset ( new backgroundMeshDecomposition ( - cvMeshDict.subDict("backgroundMeshDecomposition"), - *this + runTime_, + rndGen_, + geometryToConformTo_, + cvMeshDict.subDict("backgroundMeshDecomposition") ) ); } - if (cvMeshControls().objOutput()) - { - geometryToConformTo_.writeFeatureObj("cvMesh"); - } + buildCellSizeAndAlignmentMesh(); - insertBoundingPoints(); + insertInitialPoints(); insertFeaturePoints(); - startOfInternalPoints_ = number_of_vertices(); + setVertexSizeAndAlignment(); + + // Test for full containment + { + cellShapeControlMesh& cellSizeMesh = + cellShapeControl_.shapeControlMesh(); + + DynamicList<Foam::point> pts(number_of_vertices()); + + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->internalOrBoundaryPoint()) + { + pts.append(topoint(vit->point())); + } + } + + boundBox bb(pts); + + boundBox cellSizeMeshBb = cellSizeMesh.bounds(); + + bool fullyContained = true; + + if (!cellSizeMeshBb.contains(bb)) + { + Pout<< "Triangulation not fully contained in cell size mesh." + << endl; + + Pout<< "Cell Size Mesh Bounds = " << cellSizeMesh.bounds() << endl; + Pout<< "cvMesh Bounds = " << bb << endl; + + fullyContained = false; + } + + reduce(fullyContained, andOp<unsigned int>()); + + Info<< "Triangulation is " + << (fullyContained ? "fully" : "not fully") + << " contained in the cell size mesh" + << endl; + } - insertInitialPoints(); // Improve the guess that the backgroundMeshDecomposition makes with the // initial positions. Use before building the surface conformation to // better balance the surface conformation load. distributeBackground(); -// conformToSurface(); - - buildSurfaceConformation(rmCoarse); + buildSurfaceConformation(); // The introduction of the surface conformation may have distorted the // balance of vertices, distribute if necessary. - if (distributeBackground()) - { - // distributeBackground has destroyed all referred vertices, so the - // parallel interface needs to be rebuilt. - buildParallelInterface("rebuild"); - } + distributeBackground(); // Do not store the surface conformation until after it has been // (potentially) redistributed. storeSurfaceConformation(); // Use storeSizesAndAlignments with no feed points because all background - // points may have been distributed. It is a requirement that none of the - // preceding functions requires look up of sizes or alignments from the - // Delaunay vertices, i.e. setVertexSizeAndAlignment cannot be called - // before this point. + // points may have been distributed. storeSizesAndAlignments(); // Report any Delaunay vertices that do not think that they are in the // domain the processor they are on. // reportProcessorOccupancy(); + printVertexInfo(); + if (cvMeshControls().objOutput()) { - writePoints("allInitialPoints.obj", false); + writePoints + ( + "internalPoints_" + runTime_.timeName() + ".obj", + Foam::indexedVertexEnum::vtUnassigned, + Foam::indexedVertexEnum::vtExternalFeaturePoint + ); } } @@ -1435,9 +1451,9 @@ void Foam::conformalVoronoiMesh::move() Info<< nl << "Relaxation = " << relaxation << endl; - pointField dualVertices(number_of_cells()); + pointField dualVertices(number_of_finite_cells()); - label dualVertI = 0; + this->resetCellCount(); // Find the dual point of each tetrahedron and assign it an index. for @@ -1447,19 +1463,22 @@ void Foam::conformalVoronoiMesh::move() ++cit ) { - cit->cellIndex() = Cb::ctFar; + cit->cellIndex() = Cb::ctUnassigned; if (cit->anyInternalOrBoundaryDualVertex()) { - cit->cellIndex() = dualVertI; + cit->cellIndex() = getNewCellIndex(); - dualVertices[dualVertI] = cit->dual(); + dualVertices[cit->cellIndex()] = cit->dual(); + } - dualVertI++; + if (cit->hasFarPoint()) + { + cit->cellIndex() = Cb::ctFar; } } - dualVertices.setSize(dualVertI); + dualVertices.setSize(cellCount()); setVertexSizeAndAlignment(); @@ -1469,9 +1488,9 @@ void Foam::conformalVoronoiMesh::move() vectorField cartesianDirections(3); - cartesianDirections[0] = vector(0,0,1); - cartesianDirections[1] = vector(0,1,0); - cartesianDirections[2] = vector(1,0,0); + cartesianDirections[0] = vector(1, 0, 0); + cartesianDirections[1] = vector(0, 1, 0); + cartesianDirections[2] = vector(0, 0, 1); vectorField displacementAccumulator ( @@ -1498,25 +1517,29 @@ void Foam::conformalVoronoiMesh::move() Vertex_handle vA = c->vertex(eit->second); Vertex_handle vB = c->vertex(eit->third); - if (!vA->internalOrBoundaryPoint() && !vB->internalOrBoundaryPoint()) - { - // At least one vertex has to be a real internalOrBoundaryPoint - continue; - } - if ( - vA->anyInternalOrBoundaryPoint() - && vB->anyInternalOrBoundaryPoint() + ( + vA->internalPoint() && !vA->referred() + && vB->internalOrBoundaryPoint() + ) + || ( + vB->internalPoint() && !vB->referred() + && vA->internalOrBoundaryPoint() + ) ) { - face dualFace = buildDualFace(eit); - - Foam::point dVA = topoint(vA->point()); - Foam::point dVB = topoint(vB->point()); + pointFromPoint dVA = topoint(vA->point()); + pointFromPoint dVB = topoint(vB->point()); - Field<vector> alignmentDirsA(vA->alignment() & cartesianDirections); - Field<vector> alignmentDirsB(vB->alignment() & cartesianDirections); + Field<vector> alignmentDirsA + ( + vA->alignment().T() & cartesianDirections + ); + Field<vector> alignmentDirsB + ( + vB->alignment().T() & cartesianDirections + ); Field<vector> alignmentDirs(3); @@ -1551,7 +1574,11 @@ void Foam::conformalVoronoiMesh::move() { // Removal of close points - if (vA->internalPoint() && vB->internalPoint()) + if + ( + vA->internalPoint() && !vA->referred() + && vB->internalPoint() && !vB->referred() + ) { // Only insert a point at the midpoint of // the short edge if neither attached @@ -1566,17 +1593,17 @@ void Foam::conformalVoronoiMesh::move() { pointsToInsert.append ( - toPoint(0.5*(dVA + dVB)) + toPoint<Point>(0.5*(dVA + dVB)) ); } } - if (vA->internalPoint()) + if (vA->internalPoint() && !vA->referred()) { pointToBeRetained[vA->index()] = false; } - if (vB->internalPoint()) + if (vB->internalPoint() && !vB->referred()) { pointToBeRetained[vB->index()] = false; } @@ -1590,14 +1617,17 @@ void Foam::conformalVoronoiMesh::move() { vector& alignmentDir = alignmentDirs[aD]; - if ((rAB & alignmentDir) < 0) + scalar dotProd = rAB & alignmentDir; + + if (dotProd < 0) { // swap the direction of the alignment so that has the // same sense as rAB alignmentDir *= -1; + dotProd *= -1; } - const scalar alignmentDotProd = ((rAB/rABMag) & alignmentDir); + const scalar alignmentDotProd = dotProd/rABMag; if ( @@ -1605,19 +1635,55 @@ void Foam::conformalVoronoiMesh::move() > cvMeshControls().cosAlignmentAcceptanceAngle() ) { - const scalar targetCellSize = averageCellSize(vA, vB); + scalar targetCellSize = averageCellSize(vA, vB); - const scalar targetFaceArea = sqr(targetCellSize); + scalar targetFaceArea = sqr(targetCellSize); - alignmentDir *= 0.5*targetCellSize; + const vector originalAlignmentDir = alignmentDir; + + // Update cell size and face area + cellShapeControls().aspectRatio().updateCellSizeAndFaceArea + ( + alignmentDir, + targetFaceArea, + targetCellSize + ); // Vector to move end points around middle of vector // to align edge (i.e. dual face normal) with alignment // directions. vector delta = alignmentDir - 0.5*rAB; + face dualFace = buildDualFace(eit); + const scalar faceArea = dualFace.mag(dualVertices); + // Update delta vector + cellShapeControls().aspectRatio().updateDeltaVector + ( + originalAlignmentDir, + targetCellSize, + rABMag, + delta + ); + + if (targetFaceArea == 0) + { + Pout<< vA->info() << vB->info(); + + Cell_handle ch = locate(vA->point()); + if (is_infinite(ch)) + { + Pout<< "vA " << vA->targetCellSize() << endl; + } + + ch = locate(vB->point()); + if (is_infinite(ch)) + { + Pout<< "vB " << vB->targetCellSize() << endl; + } + } + delta *= faceAreaWeightModel_->faceAreaWeight ( faceArea/targetFaceArea @@ -1625,8 +1691,15 @@ void Foam::conformalVoronoiMesh::move() if ( - vA->internalPoint() - && vB->internalPoint() + ( + (vA->internalPoint() && vB->internalPoint()) + && (!vA->referred() || !vB->referred()) +// || +// ( +// vA->referredInternalPoint() +// && vB->referredInternalPoint() +// ) + ) && rABMag > cvMeshControls().insertionDistCoeff()*targetCellSize && faceArea @@ -1636,7 +1709,6 @@ void Foam::conformalVoronoiMesh::move() ) { // Point insertion - if ( !geometryToConformTo_.findSurfaceAnyIntersection @@ -1646,23 +1718,32 @@ void Foam::conformalVoronoiMesh::move() ) ) { - // Prevent insertions spanning surfaces - pointsToInsert.append - ( - toPoint(0.5*(dVA + dVB)) - ); + const Foam::point& newPt = 0.5*(dVA + dVB); + + if (positionOnThisProc(newPt)) + { + // Prevent insertions spanning surfaces + pointsToInsert.append(toPoint<Point>(newPt)); + } } } else if ( - (vA->internalPoint() || vB->internalPoint()) + ( + (vA->internalPoint() && !vA->referred()) + || (vB->internalPoint() && !vB->referred()) + ) && rABMag - < cvMeshControls().removalDistCoeff()*targetCellSize + < cvMeshControls().removalDistCoeff() + *targetCellSize ) { // Point removal - - if (vA->internalPoint() && vB->internalPoint()) + if + ( + vA->internalPoint() && !vA->referred() + && vB->internalPoint() && !vB->referred() + ) { // Only insert a point at the midpoint of // the short edge if neither attached @@ -1676,31 +1757,31 @@ void Foam::conformalVoronoiMesh::move() { pointsToInsert.append ( - toPoint(0.5*(dVA + dVB)) + toPoint<Point>(0.5*(dVA + dVB)) ); } } - if (vA->internalPoint()) + if (vA->internalPoint() && !vA->referred()) { pointToBeRetained[vA->index()] = false; } - if (vB->internalPoint()) + if (vB->internalPoint() && !vB->referred()) { pointToBeRetained[vB->index()] = false; } } else { - if (vA->internalPoint()) + if (vA->internalPoint() && !vA->referred()) { displacementAccumulator[vA->index()] += delta; } - if (vB->internalPoint()) + if (vB->internalPoint() && !vB->referred()) { - displacementAccumulator[vB->index()] += -delta; + displacementAccumulator[vB->index()] -= delta; } } } @@ -1708,6 +1789,8 @@ void Foam::conformalVoronoiMesh::move() } } + Info<< "Limit displacements" << endl; + // Limit displacements that pierce, or get too close to the surface for ( @@ -1716,22 +1799,26 @@ void Foam::conformalVoronoiMesh::move() ++vit ) { - if (vit->internalPoint()) + if (vit->internalPoint() && !vit->referred()) { - limitDisplacement - ( - vit, - displacementAccumulator[vit->index()] - ); + if (pointToBeRetained[vit->index()] == true) + { + limitDisplacement + ( + vit, + displacementAccumulator[vit->index()] + ); + } } } vector totalDisp = gSum(displacementAccumulator); scalar totalDist = gSum(mag(displacementAccumulator)); - // Relax the calculated displacement displacementAccumulator *= relaxation; + Info<< "Sum displacements" << endl; + for ( Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); @@ -1739,7 +1826,7 @@ void Foam::conformalVoronoiMesh::move() ++vit ) { - if (vit->internalPoint()) + if (vit->internalPoint() && !vit->referred()) { if (pointToBeRetained[vit->index()] == true) { @@ -1755,7 +1842,7 @@ void Foam::conformalVoronoiMesh::move() pointsToInsert.append ( - toPoint + toPoint<Point> ( topoint(vit->point()) + displacementAccumulator[vit->index()] @@ -1780,7 +1867,7 @@ void Foam::conformalVoronoiMesh::move() ++vit ) { - if (vit->internalPoint()) + if (vit->internalPoint() && !vit->referred()) { if (pointToBeRetained[vit->index()] == true) { @@ -1797,45 +1884,44 @@ void Foam::conformalVoronoiMesh::move() } // Remove the entire tessellation - reset(); - - if (cvMeshControls().objOutput() && runTime_.outputTime()) - { - writePoints("featurePoints_" + runTime_.timeName() + ".obj", false); - } + DelaunayMesh<Delaunay>::reset(); timeCheck("Displacement calculated"); Info<< nl << "Inserting displaced tessellation" << endl; - insertPoints(pointsToInsert); - - // Remove internal points that have been inserted outside the surface. - label internalPtIsOutside = 0; + insertInternalPoints(pointsToInsert, true); - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - ++vit - ) - { - if (vit->internalPoint()) - { - bool inside - = geometryToConformTo_.inside(topoint(vit->point())); - - if (!inside) - { - remove(vit); - internalPtIsOutside++; - } - } - } + reinsertFeaturePoints(false); - Info<< " " << internalPtIsOutside - << " internal points were inserted outside the domain. " - << "They have been removed." << endl; + // Remove internal points that have been inserted outside the surface. +// label internalPtIsOutside = 0; +// +// for +// ( +// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +// vit != finite_vertices_end(); +// ++vit +// ) +// { +// if (vit->internalPoint() && !vit->referred()) +// { +// bool inside = geometryToConformTo_.inside +// ( +// topoint(vit->point()) +// ); +// +// if (!inside) +// { +// remove(vit); +// internalPtIsOutside++; +// } +// } +// } +// +// Info<< " " << internalPtIsOutside +// << " internal points were inserted outside the domain. " +// << "They have been removed." << endl; // Fix points that have not been significantly displaced // for @@ -1858,15 +1944,39 @@ void Foam::conformalVoronoiMesh::move() // } // } - if (cvMeshControls().objOutput() && runTime_.outputTime()) + timeCheck("Internal points inserted"); + { - writePoints("points_" + runTime_.timeName() + ".obj", true); + // Check that no index is shared between any of the local points + labelHashSet usedIndices; + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (!vit->referred() && !usedIndices.insert(vit->index())) + { + FatalErrorIn("Foam::conformalVoronoiMesh::move()") + << "Index already used! Could not insert: " << nl + << vit->info() + << abort(FatalError); + } + } } - timeCheck("Internal points inserted"); - conformToSurface(); + if (cvMeshControls().objOutput()) + { + writePoints + ( + "internalPoints_" + runTime_.timeName() + ".obj", + Foam::indexedVertexEnum::vtInternal + ); + } + if (cvMeshControls().objOutput() && runTime_.outputTime()) { writeBoundaryPoints("boundaryPoints_" + runTime_.timeName() + ".obj"); @@ -1874,10 +1984,12 @@ void Foam::conformalVoronoiMesh::move() timeCheck("After conformToSurface"); + printVertexInfo(); + // Write the intermediate mesh, do not filter the dual faces. if (runTime_.outputTime()) { - writeMesh(runTime_.timeName(), false); + writeMesh(runTime_.timeName()); } updateSizesAndAlignments(pointsToInsert); @@ -1947,18 +2059,131 @@ Foam::conformalVoronoiMesh::intersectsProc } -Foam::labelListList Foam::conformalVoronoiMesh::overlapsProc -( - const List<Foam::point>& centres, - const List<scalar>& radiusSqrs -) const +//Foam::labelListList Foam::conformalVoronoiMesh::overlapsProc +//( +// const List<Foam::point>& centres, +// const List<scalar>& radiusSqrs +//) const +//{ +// if (!Pstream::parRun()) +// { +// return labelListList(centres.size(), labelList(0)); +// } +// +//// DynamicList<Foam::point> pts(number_of_vertices()); +// +//// for +//// ( +//// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +//// vit != finite_vertices_end(); +//// vit++ +//// ) +//// { +//// pts.append(topoint(vit->point())); +//// } +//// +//// dynamicIndexedOctree<dynamicTreeDataPoint> vertexOctree +//// ( +//// dynamicTreeDataPoint(pts), +//// treeBoundBox(min(pts), max(pts)), +//// 10, // maxLevel +//// 10, // leafSize +//// 3.0 // duplicity +//// ); +// +// return decomposition_().overlapsProcessors +// ( +// centres, +// radiusSqrs, +// *this, +// false//, +//// vertexOctree +// ); +//} + + +void Foam::conformalVoronoiMesh::checkCoPlanarCells() const { - if (!Pstream::parRun()) + typedef CGAL::Exact_predicates_exact_constructions_kernel Kexact; + typedef CGAL::Point_3<Kexact> PointExact; + + if (!is_valid()) { - return labelListList(centres.size(), labelList(0)); + Pout<< "Triangulation is invalid!" << endl; + } + + OFstream str("badCells.obj"); + + label badCells = 0; + + for + ( + Delaunay::Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) + { + const scalar quality = cvMeshChecks::coplanarTet(cit, 1e-16); + + if (quality == 0) + { + Pout<< "COPLANAR: " << cit->info() << nl + << " quality = " << quality << nl + << " dual = " << topoint(cit->dual()) << endl; + + drawDelaunayCell(str, cit, badCells++); + + FixedList<PointExact, 4> cellVerticesExact(PointExact(0,0,0)); + forAll(cellVerticesExact, vI) + { + cellVerticesExact[vI] = PointExact + ( + cit->vertex(vI)->point().x(), + cit->vertex(vI)->point().y(), + cit->vertex(vI)->point().z() + ); + } + + PointExact synchronisedDual = CGAL::circumcenter<Kexact> + ( + cellVerticesExact[0], + cellVerticesExact[1], + cellVerticesExact[2], + cellVerticesExact[3] + ); + + Foam::point exactPt + ( + CGAL::to_double(synchronisedDual.x()), + CGAL::to_double(synchronisedDual.y()), + CGAL::to_double(synchronisedDual.z()) + ); + + Info<< "inexact = " << cit->dual() << nl + << "exact = " << exactPt << endl; + } + } + + Pout<< "There are " << badCells << " bad cells out of " + << number_of_finite_cells() << endl; + + + label nNonGabriel = 0; + for + ( + Delaunay::Finite_facets_iterator fit = finite_facets_begin(); + fit != finite_facets_end(); + ++fit + ) + { + if (!is_Gabriel(*fit)) + { + nNonGabriel++;//Pout<< "Non-gabriel face" << endl; + } } - return decomposition_().overlapsProcessors(centres, radiusSqrs, false); + Pout<< "There are " << nNonGabriel << " non-Gabriel faces out of " + << number_of_finite_facets() << endl; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H index 3be6dab81c2..7ff0e64170c 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMesh.H @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Class Foam::conformalVoronoiMesh @@ -50,7 +45,7 @@ SourceFiles #include "ulong.H" #include "searchableSurfaces.H" #include "conformationSurfaces.H" -#include "cellSizeControlSurfaces.H" +#include "cellShapeControl.H" #include "cvControls.H" #include "DynamicList.H" #include "PackedBoolList.H" @@ -77,6 +72,11 @@ SourceFiles #include "zeroGradientFvPatchFields.H" #include "globalIndex.H" #include "pointFeatureEdgesTypes.H" +#include "pointConversion.H" +#include "Tuple2.H" +#include "DistributedDelaunayMesh.H" +#include "tensorIOField.H" + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -98,24 +98,25 @@ class backgroundMeshDecomposition; class conformalVoronoiMesh : - public Delaunay + public DistributedDelaunayMesh<Delaunay> { public: enum reconformationMode { - rmNone, // Do not rebuild the surface conformation - rmCoarse, // Rebuild the conformation with coarse tolerances (faster) - rmFine // Rebuild the conformation with fine tolerances (slower) + rmOff, // Do not rebuild the surface conformation + rmOn }; - enum faceCollapseMode - { - fcmNone, // Do not collapse face - fcmEdge, // Collapse face to a single edge - fcmPoint, // Collapse face to a point - fcmDeferredMultiEdge // Collapse face to several edges - }; + typedef Delaunay::Vertex_handle Vertex_handle; + typedef Delaunay::Cell_handle Cell_handle; + typedef Delaunay::Point Point; + + typedef List<DynamicList<Pair<labelPair> > > labelPairPairDynListList; + + typedef Tuple2<pointIndexHit, label> pointIndexHitAndFeature; + typedef List<pointIndexHitAndFeature> pointIndexHitAndFeatureList; + typedef DynamicList<pointIndexHitAndFeature> pointIndexHitAndFeatureDynList; private: @@ -147,12 +148,8 @@ private: //- The surfaces to conform to conformationSurfaces geometryToConformTo_; - //- The cell size control object - cellSizeControlSurfaces cellSizeControl_; - - //- Keep track of the start index of the internal points. Needs - // careful bookkeeping within several functions. - label startOfInternalPoints_; + //- The cell shape control object + cellShapeControl cellShapeControl_; //- Limiting bound box before infinity begins treeBoundBox limitBounds_; @@ -167,11 +164,15 @@ private: //- Search tree for edge point locations mutable autoPtr<dynamicIndexedOctree<dynamicTreeDataPoint> > - edgeLocationTreePtr_; + edgeLocationTreePtr_; + + mutable DynamicList<Foam::point> existingEdgeLocations_; //- Search tree for surface point locations mutable autoPtr<dynamicIndexedOctree<dynamicTreeDataPoint> > - surfacePtLocationTreePtr_; + surfacePtLocationTreePtr_; + + mutable DynamicList<Foam::point> existingSurfacePtLocations_; //- Store locations where the cell size and alignments will be // pre-calculated and looked up @@ -205,6 +206,8 @@ private: // Private Member Functions + inline scalar defaultCellSize() const; + //- Return the local target cell size at the given location. Takes // boolean argument to allow speed-up of queries if the point is going // to be on a surface. @@ -271,82 +274,82 @@ private: //- Return the required alignment directions at the given location tensor requiredAlignment(const Foam::point& pt) const; - //- Insert Foam::point and return its auto-generated index - inline label insertPoint - ( - const Foam::point& p, - const label type - ); - //- Insert Point and return its auto-generated index - inline label insertPoint + inline bool insertPoint ( const Point& P, - const label type + const indexedVertexEnum::vertexType type ); //- Insert Foam::point with specified index and type - inline void insertPoint + inline bool insertPoint ( const Foam::point& p, - const label index, - const label type + const indexedVertexEnum::vertexType type ); - //- Insert Point with specified index and type - inline void insertPoint + //- Insert Point with specified index, type and original processor + inline bool insertReferredPoint ( const Point& P, const label index, - const label type + const indexedVertexEnum::vertexType type, + const label processor + ); + + inline bool insertReferredPoint(const Vb& P); + + //- Insert Foam::point with specified index, type and original processor + inline bool insertReferredPoint + ( + const Foam::point& p, + const label index, + const indexedVertexEnum::vertexType type, + const label processor ); //- Insert Delaunay vertices using the CGAL range insertion method, // optionally check processor occupancy and distribute to other // processors - void insertPoints + void insertInternalPoints ( List<Point>& points, - bool distribute = true + const bool distribute = false ); - //- Insert indexed and typed Delaunay vertices, optionally check - // processor occupancy and distribute to other processors void insertPoints ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types, + List<Vb>& vertices, bool distribute = true ); - //- Insert a point-pair at a ppDist distance either side of + //- Create a point-pair at a ppDist distance either side of // surface point surfPt, in the direction n - inline void insertPointPair + inline void createPointPair ( const scalar ppDist, const Foam::point& surfPt, - const vector& n + const vector& n, + DynamicList<Vb>& pts ); + inline Foam::point perturbPoint(const Foam::point& pt) const; + //- Create a point-pair at a ppDist distance either side of // surface point surfPt, in the direction n - inline void createPointPair + inline void createBafflePointPair ( const scalar ppDist, const Foam::point& surfPt, const vector& n, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Insert pairs of points on the surface with the given normals, at the // specified spacing void insertSurfacePointPairs ( - const List<pointIndexHit>& surfaceHits, - const List<label>& hitSurfaces, + const pointIndexHitAndFeatureList& surfaceHits, const fileName fName = fileName::null ); @@ -355,8 +358,7 @@ private: // to be conformed to on the corresponding entry in featureHit void insertEdgePointGroups ( - const List<pointIndexHit>& edgeHits, - const labelList& featuresHit, + const pointIndexHitAndFeatureList& edgeHits, const fileName fName = fileName::null ); @@ -365,9 +367,7 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Create points to conform to an external edge @@ -375,9 +375,7 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Create points to conform to an internal edge @@ -385,9 +383,7 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Create points to conform to a flat edge @@ -395,9 +391,7 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Create points to conform to an open edge @@ -405,9 +399,7 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Create points to conform to multiply connected edge @@ -415,39 +407,54 @@ private: ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Determine and insert point groups at the feature points void insertFeaturePoints(); - bool edgesShareNormal(const label e1, const label e2) const; + //- Create point groups at mixed feature points + void createMixedFeaturePoints(DynamicList<Vb>& pts); - //- Create point groups at convex feature points - void createConvexFeaturePoints + void addMasterAndSlavePoints ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types - ); + const DynamicList<Foam::point>& masterPoints, + const DynamicList<indexedVertexEnum::vertexType>&masterPointsTypes, + const Map<DynamicList<autoPtr<plane> > >& masterPointReflections, + DynamicList<Vb>& pts, + const label ptI + ) const; + + label getSign(const extendedFeatureEdgeMesh::edgeStatus eStatus) const; - //- Create point groups at concave feature points - void createConcaveFeaturePoints + void createMasterAndSlavePoints ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types - ); + const extendedFeatureEdgeMesh& feMesh, + const label ptI, + DynamicList<Vb>& pts + ) const; - //- Create point groups at mixed feature points - void createMixedFeaturePoints + void createFeaturePoints(DynamicList<Vb>& pts); + + vector sharedFaceNormal ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types - ); + const extendedFeatureEdgeMesh& feMesh, + const label edgeI, + const label nextEdgeI + ) const; + + List<Foam::point> reflectPointInPlanes + ( + const Foam::point p, + const DynamicList<autoPtr<plane> >& planes + ) const; + + Foam::point reflectPointInPlane + ( + const Foam::point p, + const plane& planeN + ) const; + //- Fill the pointFeatureEdgesType struct with the types of feature // edges that are attached to the point. @@ -467,9 +474,7 @@ private: const pointFeatureEdgesTypes& pFEdgeTypes, const List<extendedFeatureEdgeMesh::edgeStatus>& allEdStat, const label ptI, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ); //- Store the locations of all of the features to be conformed to @@ -486,28 +491,24 @@ private: //- Check if a location is in exclusion range around a feature point bool nearFeaturePt(const Foam::point& pt) const; - //- Clear the entire tesselation - // Reinsert bounding points, feature points and recalculate - // startOfInternalPoints_ - void reset(const bool distribute = false); - - //- Insert far points in a large bounding box to avoid dual edges - // spanning huge distances - void insertBoundingPoints(); - - //- Reinsert the bounding points - void reinsertBoundingPoints(); - //- Insert the initial points into the triangulation, based on the // initialPointsMethod void insertInitialPoints(); + //- Calculate the worst load balance + scalar calculateLoadUnbalance() const; + //- In parallel redistribute the backgroundMeshDecomposition and // vertices to balance the number of vertices on each processor. // Returns true if the background mesh changes as this removes all // referred vertices, so the parallel interface may need rebuilt. bool distributeBackground(); + //- + void distribute(); + + void buildCellSizeAndAlignmentMesh(); + //- Store data for sizeAndAlignmentLocations_, storedSizes_ and // storedAlignments_ and initialise the sizeAndAlignmentTreePtr_, // determining the appropriate sizeAndAlignmentLocations_ @@ -568,9 +569,28 @@ private: // conformation reconformationMode reconformationControl() const; + //- Determines geometrically whether a vertex is close to a surface + // This is an optimisation + label findVerticesNearBoundaries(); + //- Create and insert the necessary point pairs to conform to the // surface, then store the result - void buildSurfaceConformation(reconformationMode reconfMode); + void buildSurfaceConformation(); + + label synchroniseEdgeTrees + ( + pointIndexHitAndFeatureList& featureEdgeHits + ); + + label synchroniseSurfaceTrees + ( + pointIndexHitAndFeatureList& surfaceHits + ); + + bool locationConformsToInside + ( + const pointIndexHitAndFeature& info + ) const; //- Check to see if dual cell specified by given vertex iterator // intersects the boundary and hence reqires a point-pair @@ -583,8 +603,7 @@ private: bool dualCellSurfaceAllIntersections ( const Delaunay::Finite_vertices_iterator& vit, - DynamicList<pointIndexHit>& info, - DynamicList<label>& hitSurface + pointIndexHitAndFeatureDynList& info ) const; //- Return false if the line is entirely outside the current processor @@ -599,64 +618,6 @@ private: Foam::point& b ) const; - label removeProcessorBoundarySeeds(bool reinsertBoundPts); - - void seedProcessorBoundarySurfaces(bool seedProcessors); - - label numberOfUnusedReferredPoints() const; - - //- Build the parallelInterfaces of the mesh - void buildParallelInterface - ( - const word& outputName - ); - - //- Build the parallelInterfaces of the mesh, supply hash sets - // externally to allow updates - void buildParallelInterface - ( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - bool initialEdgeReferral, - const word& outputName - ); - - //- Refer all vertices to all processors - void buildParallelInterfaceAll - ( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName - ); - - //- Refer vertices where there dual edge pierces other processors - void buildParallelInterfaceIntersection - ( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName - ); - - //- Refer vertices that are attached to Delaunay tets whose - // circumspheres touch other processors - void buildParallelInterfaceInfluence - ( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName - ); - - //- Refer vertices to their required processors - void referVertices - ( - const DynamicList<label>& targetProcessor, - DynamicList<Foam::point>& parallelPoints, - DynamicList<label>& parallelIndices, - List<labelHashSet>& receivedVertices, - const word& stageName, - const word& outputName - ); - //- Find the "worst" protrusion of a dual cell through the surface, // subject to the maxSurfaceProtrusion tolerance void dualCellLargestSurfaceProtrusion @@ -681,7 +642,7 @@ private: //- Write out debugging information about the surface conformation // quality - void reportSurfaceConformationQuality(); +// void reportSurfaceConformationQuality(); //- Limit the displacement of a point so that it doesn't penetrate the // surface to be meshed or come too close to it @@ -698,23 +659,19 @@ private: //- Check if a surface point is near another. bool nearSurfacePoint ( - pointIndexHit& pHit, - label& surfaceHit, - DynamicList<Foam::point>& existingSurfacePtLocations + pointIndexHitAndFeature& pHit ) const; //- Append a point to the surface point tree and the existing list bool appendToSurfacePtTree ( - const Foam::point& pt, - DynamicList<Foam::point>& existingSurfacePtLocations + const Foam::point& pt ) const; //- Append a point to the edge location tree and the existing list bool appendToEdgeLocationTree ( - const Foam::point& pt, - DynamicList<Foam::point>& existingEdgeLocations + const Foam::point& pt ) const; //- Return a list of the nearest feature edge locations @@ -745,8 +702,7 @@ private: //- edge conformation location bool nearFeatureEdgeLocation ( - pointIndexHit& pHit, - DynamicList<Foam::point>& existingEdgeLocations + pointIndexHit& pHit ) const; //- Build or rebuild the edge location tree @@ -769,18 +725,11 @@ private: void addSurfaceAndEdgeHits ( const Delaunay::Finite_vertices_iterator& vit, - const Foam::point& vert, - const DynamicList<pointIndexHit>& surfHit, - const DynamicList<label>& hitSurface, + const pointIndexHitAndFeatureDynList& surfaceIntersections, scalar surfacePtReplaceDistCoeffSqr, scalar edgeSearchDistCoeffSqr, - DynamicList<pointIndexHit>& surfaceHits, - DynamicList<label>& hitSurfaces, - DynamicList<pointIndexHit>& featureEdgeHits, - DynamicList<label>& featureEdgeFeaturesHit, - DynamicList<Foam::point>& newEdgeLocations, - DynamicList<Foam::point>& existingEdgeLocations, - DynamicList<Foam::point>& existingSurfacePtLocations + pointIndexHitAndFeatureDynList& surfaceHits, + pointIndexHitAndFeatureDynList& featureEdgeHits ) const; //- Store the surface conformation with the indices offset to be @@ -791,10 +740,19 @@ private: // relative to new number of internal vertices void reinsertSurfaceConformation(); + void checkCells(); + + void checkDuals(); + + void checkVertices(); + + void checkCoPlanarCells() const; + //- Dual calculation void calcDualMesh ( pointField& points, + labelList& boundaryPts, faceList& faces, labelList& owner, labelList& neighbour, @@ -806,7 +764,7 @@ private: pointField& cellCentres, labelList& cellToDelaunayVertex, labelListList& patchToDelaunayVertex, - bool filterFaces + PackedBoolList& boundaryFacesToRemove ); //- Tet mesh calculation @@ -844,77 +802,27 @@ private: const Delaunay::Finite_facets_iterator& fit ) const; - //- Merge adjacent edges that are not attached to other faces - label mergeNearlyParallelEdges + //- Determines if the dual face constructed by the Delaunay + // edge is a processor boundary face + inline bool isProcBoundaryEdge ( - const pointField& pts, - const scalar maxCosAngle - ); + const Delaunay::Finite_edges_iterator& eit + ) const; - //- Merge vertices that are very close together - void mergeCloseDualVertices + //- Merge vertices that are identical + void mergeIdenticalDualVertices ( const pointField& pts, - const PackedBoolList& boundaryPts + const labelList& boundaryPts ); - label mergeCloseDualVertices + label mergeIdenticalDualVertices ( const pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap - ) const; - - //- Smooth the dual vertices of the dual faces on the boundary - // so that they conform to the surface and remove any - // small, normal oriented faces - void smoothSurface - ( - pointField& pts, - const PackedBoolList& boundaryPts - ); - - label smoothSurfaceDualFaces - ( - pointField& pts, - const PackedBoolList& boundaryPts, + const labelList& boundaryPts, Map<label>& dualPtIndexMap ) const; - //- Collapse a face to a point or an edge, modifying and - // mapping the points, returns the true if the face was - // collapsed in this operation - void collapseFaces - ( - pointField& pts, - const PackedBoolList& boundaryPts, - HashSet<labelPair, labelPair::Hash<> >& deferredCollapseFaces - ); - - label collapseFaces - ( - pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap, - HashSet<labelPair, labelPair::Hash<> >& deferredCollapseFaces - ) const; - - //- Collapse a face to an edge, updating the point and point - // map. Returns the collapse mode that was applied. - faceCollapseMode collapseFace - ( - const face& f, - pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap, - scalar targetFaceSize, - scalar collapseSizeLimitCoeff, - label maxFC - ) const; - - //- Identify the index of the longest edge on the face - label longestEdge(const face& f, const pointField& pts) const; - //- Identify the face labels of the deferred collapse faces void deferredCollapseFaceSet ( @@ -943,12 +851,19 @@ private: void indexDualVertices ( pointField& pts, - PackedBoolList& boundaryPts + labelList& boundaryPts ); - //- Re-index all of the the Delaunay cells + //- Re-index all of the Delaunay cells void reindexDualVertices(const Map<label>& dualPtIndexMap); + label createPatchInfo + ( + wordList& patchNames, + wordList& patchTypes, + labelList& procNeighbours + ) const; + //- Create all of the internal and boundary faces void createFacesOwnerNeighbourAndPatches ( @@ -961,6 +876,7 @@ private: labelList& patchStarts, labelList& procNeighbours, labelListList& patchPointPairSlaves, + PackedBoolList& boundaryFacesToRemove, bool includeEmptyPatches = false ) const; @@ -987,7 +903,7 @@ private: List<DynamicList<face> >& patchFaces, List<DynamicList<label> >& patchOwners, List<DynamicList<label> >& patchPointPairSlaves, - List<Pair<DynamicList<label> > >& patchSortingIndices + labelPairPairDynListList& patchSortingIndices ) const; //- Add the faces and owner information for the patches @@ -998,15 +914,18 @@ private: labelList& owner, labelList& patchSizes, labelList& patchStarts, + PackedBoolList& boundaryFacesToRemove, const List<DynamicList<face> >& patchFaces, - const List<DynamicList<label> >& patchOwners + const List<DynamicList<label> >& patchOwners, + const List<DynamicList<bool> >& indirectPatchFace ) const; //- Remove points that are no longer used by any faces void removeUnusedPoints ( faceList& faces, - pointField& pts + pointField& pts, + labelList& boundaryPts ) const; //- Remove dual cells that are not used by any faces. Return compaction @@ -1031,6 +950,21 @@ private: //- Create a polyMesh from points. autoPtr<polyMesh> createPolyMeshFromPoints(const pointField& pts) const; + void checkProcessorPatchesMatch + ( + const wordList& patchTypes, + const labelList& patchSizes, + const labelList& procNeighbours + ) const; + + void reorderPoints + ( + pointField& points, + labelList& boundaryPts, + faceList& faces, + const label nInternalFaces + ) const; + //- Rotate the faces on processor patches if necessary void reorderProcessorPatches ( @@ -1078,6 +1012,8 @@ public: // surface as required void move(); + void printVertexInfo() const; + //- Check if the point is in the domain handled by this processor bool positionOnThisProc(const Foam::point& pt) const; @@ -1094,30 +1030,18 @@ public: const List<Foam::point>& ends ) const; - //- Which other processors does each sphere overlap - labelListList overlapsProc - ( - const List<Foam::point>& centres, - const List<scalar>& radiusSqrs - ) const; - - //- Conversion functions between point (FOAM::) and Point (CGAL) - -# ifdef CGAL_INEXACT - typedef const Foam::point& pointFromPoint; - typedef const Point& PointFrompoint; -# else - typedef Foam::point pointFromPoint; - typedef Point PointFrompoint; -# endif - - inline pointFromPoint topoint(const Point&) const; - inline PointFrompoint toPoint(const Foam::point&) const; +// //- Which other processors does each sphere overlap +// labelListList overlapsProc +// ( +// const List<Foam::point>& centres, +// const List<scalar>& radiusSqrs +// ) const; typedef K::Vector_3 CGALVector; inline CGALVector toCGALVector(const Foam::vector& v) const; + // Access //- Return the Time object @@ -1135,8 +1059,8 @@ public: //- Return the backgroundMeshDecomposition inline const backgroundMeshDecomposition& decomposition() const; - //- Return the cellSizeControlSurfaces object - inline const cellSizeControlSurfaces& cellSizeControl() const; + //- Return the cellShapeControl object + inline const cellShapeControl& cellShapeControls() const; //- Return the cvMeshControls object inline const cvControls& cvMeshControls() const; @@ -1159,8 +1083,21 @@ public: label offset = 0 ) const; - //- Write Delaunay points to .obj file - void writePoints(const fileName& fName, bool internalOnly) const; + //- Write Delaunay points in the range between (and including) + // type startPointType and endPointType to .obj file + void writePoints + ( + const fileName& fName, + const Foam::indexedVertexEnum::vertexType startPointType, + const Foam::indexedVertexEnum::vertexType endPointType + ) const; + + //- Write Delaunay points of type pointType to .obj file + void writePoints + ( + const fileName& fName, + const Foam::indexedVertexEnum::vertexType pointType + ) const; //- Write the boundary Delaunay points to .obj file void writeBoundaryPoints(const fileName& fName) const; @@ -1172,17 +1109,20 @@ public: const List<Foam::point>& points ) const; + //- Write list of points to file + void writePoints + ( + const fileName& fName, + const List<Vb>& points + ) const; + //- Write the internal Delaunay vertices of the tessellation as a // pointField that may be used to restart the meshing process void writeInternalDelaunayVertices(const fileName& instance) const; //- Prepare data and call writeMesh for polyMesh and // tetDualMesh - void writeMesh - ( - const fileName& instance, - bool filterFaces = true - ); + void writeMesh(const fileName& instance); //- Write mesh to disk void writeMesh @@ -1190,6 +1130,7 @@ public: const word& meshName, const fileName& instance, pointField& points, + labelList& boundaryPts, faceList& faces, labelList& owner, labelList& neighbour, @@ -1198,7 +1139,8 @@ public: const labelList& patchSizes, const labelList& patchStarts, const labelList& procNeighbours, - const pointField& cellCentres + const pointField& cellCentres, + const PackedBoolList& boundaryFacesToRemove ) const; //- Write points and faces as .obj file @@ -1214,6 +1156,8 @@ public: // actual cell size (cbrt(actual cell volume)). void writeCellSizes(const fvMesh& mesh) const; + void writeCellAlignments(const fvMesh& mesh) const; + //- Calculate and write the cell centres. void writeCellCentres(const fvMesh& mesh) const; @@ -1226,90 +1170,6 @@ public: const fileName& fName, const faceList& faces ) const; - - //- Function inserting points into a triangulation and setting the - // index and type data of the point in the correct order. This is - // faster than inserting points individually. - // - // Adapted from a post on the CGAL lists: 2010-01/msg00004.html by - // Sebastien Loriot (Geometry Factory). - // - // @todo problems putting declaration in the .C file. Function - // prototype is not recognised. - template<class Triangulation, class Point_iterator> - void rangeInsertWithInfo - ( - Point_iterator begin, - Point_iterator end, - Triangulation& T, - DynamicList<label>& indices, - DynamicList<label>& types - ) - { - typedef std::vector - < - std::pair<const typename Triangulation::Point*, label> - > vectorPairPointIndex; - - vectorPairPointIndex points; - label index = 0; - - for (Point_iterator it = begin; it != end; ++it) - { - points.push_back - ( - std::make_pair(&(toPoint(*it)), index++) - ); - } - - std::random_shuffle(points.begin(), points.end()); - - spatial_sort - ( - points.begin(), - points.end(), - Traits_for_spatial_sort<Triangulation>() - ); - - typename Triangulation::Vertex_handle hint; - - for - ( - typename vectorPairPointIndex::const_iterator - p = points.begin(); - p != points.end(); - ++p - ) - { - const size_t checkInsertion = T.number_of_vertices(); - - hint = T.insert(*(p->first), hint); - - if (checkInsertion != T.number_of_vertices() - 1) - { - Pout<< "Failed to insert point " - << topoint(*(p->first)) << endl; - } - else - { - label oldIndex = p->second; - - label type = types[oldIndex]; - - if (type > Vb::vtFar) - { - // This is a member of a point pair, don't use the - // type directly (note that this routine never gets - // called for referredPoints so type will never be - // -procI - type += checkInsertion; - } - - hint->index() = indices[oldIndex] + checkInsertion; - hint->type() = type; - } - } - } }; @@ -1321,10 +1181,6 @@ public: #include "conformalVoronoiMeshI.H" -//#ifdef NoRepository -//# include "conformalVoronoiMeshTemplates.C" -//#endif - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C index ec81b1e944a..db9fb09ac0f 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshCalcDualMesh.C @@ -27,35 +27,21 @@ License #include "motionSmoother.H" #include "backgroundMeshDecomposition.H" #include "polyMeshGeometry.H" +#include "indexedCellChecks.H" + +#include "CGAL/Exact_predicates_exact_constructions_kernel.h" // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // -void Foam::conformalVoronoiMesh::calcDualMesh -( - pointField& points, - faceList& faces, - labelList& owner, - labelList& neighbour, - wordList& patchTypes, - wordList& patchNames, - labelList& patchSizes, - labelList& patchStarts, - labelList& procNeighbours, - pointField& cellCentres, - labelList& cellToDelaunayVertex, - labelListList& patchToDelaunayVertex, - bool filterFaces -) +void Foam::conformalVoronoiMesh::checkCells() { - timeCheck("Start calcDualMesh"); - - setVertexSizeAndAlignment(); + List<List<FixedList<Foam::point, 4> > > cellListList(Pstream::nProcs()); - timeCheck("After setVertexSizeAndAlignment"); + List<FixedList<Foam::point, 4> > cells(number_of_finite_cells()); - // Make all filterCount values zero except on cells that are attached - // points that are on the parallel interface. These will not be moved. + globalIndex gIndex(number_of_vertices()); + label count = 0; for ( Delaunay::Finite_cells_iterator cit = finite_cells_begin(); @@ -63,214 +49,507 @@ void Foam::conformalVoronoiMesh::calcDualMesh ++cit ) { - if - ( - !cit->vertex(0)->real() - || !cit->vertex(1)->real() - || !cit->vertex(2)->real() - || !cit->vertex(3)->real() - ) + if (tetrahedron(cit).volume() == 0) { - cit->filterCount() = - cvMeshControls().filterCountSkipThreshold() + 1; + Pout<< "ZERO VOLUME TET" << endl; + Pout<< cit->info(); + Pout<< cit->dual(); } - else + + if (cit->hasFarPoint()) + { + continue; + } + + List<labelPair> cellVerticesPair(4); + List<Foam::point> cellVertices(4); + + for (label vI = 0; vI < 4; ++vI) + { + cellVerticesPair[vI] = labelPair + ( + cit->vertex(vI)->procIndex(), + cit->vertex(vI)->index() + ); + cellVertices[vI] = topoint(cit->vertex(vI)->point()); + } + + List<Foam::point> cellVerticesOld(cellVertices); + labelList oldToNew; + sortedOrder(cellVerticesPair, oldToNew); + oldToNew = invert(oldToNew.size(), oldToNew); + inplaceReorder(oldToNew, cellVerticesPair); + inplaceReorder(oldToNew, cellVertices); + +// Pout<< "old " << cellVerticesOld << nl << "new " << cellVertices << endl; + +// +// FixedList<label, 4> globalTetCell(cit->globallyOrderedCellVertices(gIndex)); +// +// FixedList<Point, 4> cellVertices(Point(0,0,0)); +// +// forAll(globalTetCell, gvI) +// { +// label gI = globalTetCell[gvI]; +// +// cellVertices[gvI] = cit->vertex(gI)->point(); +// } + +// if (cit->hasFarPoint()) +// { +// continue; +// } + + for (label i = 0; i < 4; ++i) { - cit->filterCount() = 0; + //cells[count][i] = topoint(cit->vertex(i)->point()); + cells[count][i] = cellVertices[i]; } + + count++; } - // THIS CODE STOPS ALL FACES NEAR ANY PROCESSOR BOUNDARY BEING FILTERED. - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ - ) + cells.setSize(count); + + cellListList[Pstream::myProcNo()] = cells; + + Pstream::gatherList(cellListList); + + if (Pstream::master()) { - std::list<Cell_handle> cells; - incident_cells(vit, std::back_inserter(cells)); + Info<< "Checking on master processor the cells of each " << nl + << "processor point list against the master cell list." << nl + << "There are " << cellListList.size() << " processors" << nl + << "The size of each processor's cell list is:" << endl; - bool hasProcPt = false; + forAll(cellListList, cfI) + { + Info<< " Proc " << cfI << " has " << cellListList[cfI].size() + << " cells" << endl; + } - for - ( - std::list<Cell_handle>::iterator cit = cells.begin(); - cit != cells.end(); - ++cit - ) + label nMatches = 0, nMatchFoundDiffOrder = 0; + + forAll(cellListList[0], cmI) { - // Allow filtering if any vertices are far points. Otherwise faces - // with boundary points attached to a cell with a far point will - // not be filtered. - if - ( - (!(*cit)->vertex(0)->real() && !(*cit)->vertex(0)->farPoint()) - || (!(*cit)->vertex(1)->real() && !(*cit)->vertex(1)->farPoint()) - || (!(*cit)->vertex(2)->real() && !(*cit)->vertex(2)->farPoint()) - || (!(*cit)->vertex(3)->real() && !(*cit)->vertex(3)->farPoint()) - ) + const FixedList<Foam::point, 4>& masterCell = cellListList[0][cmI]; + + bool matchFound = false; + bool matchFoundDiffOrder = false; + + forAll(cellListList, cpI) { - hasProcPt = true; + if (cpI == 0) + { + continue; + } + + forAll(cellListList[cpI], csI) + { + const FixedList<Foam::point, 4>& slaveCell + = cellListList[cpI][csI]; + + if (masterCell == slaveCell) + { + matchFound = true; + break; + } + else + { + label samePt = 0; + + forAll(masterCell, mI) + { + const Foam::point& mPt = masterCell[mI]; + + forAll(slaveCell, sI) + { + const Foam::point& sPt = slaveCell[sI]; + + if (mPt == sPt) + { + samePt++; + } + } + } - break; + if (samePt == 4) + { + matchFoundDiffOrder = true; + + Pout<< masterCell << nl << slaveCell << endl; + + break; + } + } + } } - } - if (hasProcPt) - { - for - ( - std::list<Cell_handle>::iterator cit = cells.begin(); - cit != cells.end(); - ++cit - ) + if (matchFound) + { + nMatches++; + } + + if (matchFoundDiffOrder) { - (*cit)->filterCount() = - cvMeshControls().filterCountSkipThreshold() + 1; + nMatchFoundDiffOrder++; } } + + Info<< "Found " << nMatches << " matching cells and " + << nMatchFoundDiffOrder << " matching cells with different " + << "vertex ordering"<< endl; } +} - PackedBoolList boundaryPts(number_of_cells(), false); - indexDualVertices(points, boundaryPts); +void Foam::conformalVoronoiMesh::checkDuals() +{ + List<List<Point> > pointFieldList(Pstream::nProcs()); + + List<Point> duals(number_of_finite_cells()); + + typedef CGAL::Exact_predicates_exact_constructions_kernel EK2; + typedef CGAL::Regular_triangulation_euclidean_traits_3<EK2> EK; + typedef CGAL::Cartesian_converter<typename baseK::Kernel, EK2> To_exact; + typedef CGAL::Cartesian_converter<EK2, typename baseK::Kernel> Back_from_exact; + +// PackedBoolList bPoints(number_of_finite_cells()); +// indexDualVertices(duals, bPoints); + + label count = 0;//duals.size(); + + duals.setSize(number_of_finite_cells()); + + globalIndex gIndex(number_of_vertices()); + + for + ( + Delaunay::Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) { - // Ideally requires a no-risk face filtering to get rid of zero area - // faces and establish if the mesh can be produced at all to the - // specified criteria + if (cit->hasFarPoint()) + { + continue; + } - Info<< nl << "Merging close points" << endl; + duals[count++] = cit->circumcenter(); - // There is no guarantee that a merge of close points is no-risk - mergeCloseDualVertices(points, boundaryPts); +// List<labelPair> cellVerticesPair(4); +// List<Point> cellVertices(4); +// +// for (label vI = 0; vI < 4; ++vI) +// { +// cellVerticesPair[vI] = labelPair +// ( +// cit->vertex(vI)->procIndex(), +// cit->vertex(vI)->index() +// ); +// cellVertices[vI] = cit->vertex(vI)->point(); +// } +// +// labelList oldToNew; +// sortedOrder(cellVerticesPair, oldToNew); +// oldToNew = invert(oldToNew.size(), oldToNew); +// inplaceReorder(oldToNew, cellVerticesPair); +// inplaceReorder(oldToNew, cellVertices); +// +// duals[count++] = CGAL::circumcenter +// ( +// cellVertices[0], +// cellVertices[1], +// cellVertices[2], +// cellVertices[3] +// ); + +// To_exact to_exact; +// Back_from_exact back_from_exact; +// EK::Construct_circumcenter_3 exact_circumcenter = +// EK().construct_circumcenter_3_object(); +// +// duals[count++] = topoint +// ( +// back_from_exact +// ( +// exact_circumcenter +// ( +// to_exact(cit->vertex(0)->point()), +// to_exact(cit->vertex(1)->point()), +// to_exact(cit->vertex(2)->point()), +// to_exact(cit->vertex(3)->point()) +// ) +// ) +// ); } - timeCheck("After initial close point merge"); + Pout<< "Duals Calculated " << count << endl; - if (filterFaces) - { - label nInitialBadQualityFaces = checkPolyMeshQuality(points).size(); + duals.setSize(count); - reduce(nInitialBadQualityFaces, sumOp<label>()); + pointFieldList[Pstream::myProcNo()] = duals; - Info<< nl << "Initial check before face collapse, found " - << nInitialBadQualityFaces << " bad quality faces" - << endl; + Pstream::gatherList(pointFieldList); - HashSet<labelPair, labelPair::Hash<> > deferredCollapseFaces; + if (Pstream::master()) + { + Info<< "Checking on master processor the dual locations of each " << nl + << "processor point list against the master dual list." << nl + << "There are " << pointFieldList.size() << " processors" << nl + << "The size of each processor's dual list is:" << endl; - if (nInitialBadQualityFaces > 0) + forAll(pointFieldList, pfI) { - Info<< nl - << "A mesh could not be produced to satisfy the specified " - << "quality criteria." << nl - << "The quality and the surface conformation controls " - << "can be altered and the " << nl - << "internalDelaunayVertices read in to try again, or more " - << "cell size resolution " << nl - << "and motion iterations can be applied in areas where " - << "problems are occurring." - << endl; + Info<< " Proc " << pfI << " has " << pointFieldList[pfI].size() + << " duals" << endl; } - if - ( - nInitialBadQualityFaces == 0 - || cvMeshControls().continueFilteringOnBadInitialPolyMesh() - ) + label nNonMatches = 0; + label nNearMatches = 0; + label nExactMatches = 0; + + forAll(pointFieldList[0], pI) { - label nBadQualityFaces = 0; + const Point& masterPoint = pointFieldList[0][pI]; - labelHashSet lastWrongFaces; + bool foundMatch = false; + bool foundNearMatch = false; - label nConsecutiveEqualFaceSets = 0; + scalar minCloseness = GREAT; + Point closestPoint(0, 0, 0); - do + forAll(pointFieldList, pfI) { - // Reindexing the Delaunay cells and regenerating the - // points resets the mesh to the starting condition. + if (pfI == 0) + { + continue; + } - indexDualVertices(points, boundaryPts); +// label pfI = 1; + forAll(pointFieldList[pfI], pISlave) { - Info<< nl << "Merging close points" << endl; + const Point& slavePoint + = pointFieldList[pfI][pISlave]; + + if (masterPoint == slavePoint) + { + foundMatch = true; + break; + } + + const scalar closeness = mag + ( + topoint(masterPoint) - topoint(slavePoint) + ); - mergeCloseDualVertices(points, boundaryPts); + if (closeness < 1e-12) + { + foundNearMatch = true; + } + else + { + if (closeness < minCloseness) + { + minCloseness = closeness; + closestPoint = slavePoint; + } + } } + if (!foundMatch) { - // Risky and undo-able face filtering to reduce - // the face count as much as possible, staying - // within the specified criteria + if (foundNearMatch) + { + CGAL::Gmpq x(CGAL::to_double(masterPoint.x())); + CGAL::Gmpq y(CGAL::to_double(masterPoint.y())); + CGAL::Gmpq z(CGAL::to_double(masterPoint.z())); - Info<< nl << "Smoothing surface" << endl; + std::cout<< "master = " << x << " " << y << " " << z + << std::endl; - smoothSurface(points, boundaryPts); - Info<< nl << "Collapsing unnecessary faces" << endl; + CGAL::Gmpq xs(CGAL::to_double(closestPoint.x())); + CGAL::Gmpq ys(CGAL::to_double(closestPoint.y())); + CGAL::Gmpq zs(CGAL::to_double(closestPoint.z())); + std::cout<< "slave = " << xs << " " << ys << " " << zs + << std::endl; - collapseFaces(points, boundaryPts, deferredCollapseFaces); + nNearMatches++; + } + else + { + nNonMatches++; + Info<< " Closest point to " << masterPoint << " is " + << closestPoint << nl + << " Separation is " << minCloseness << endl; - const scalar maxCosAngle - = cos(degToRad(cvMeshControls().edgeMergeAngle())); + CGAL::Gmpq x(CGAL::to_double(masterPoint.x())); + CGAL::Gmpq y(CGAL::to_double(masterPoint.y())); + CGAL::Gmpq z(CGAL::to_double(masterPoint.z())); - Info<< nl << "Merging adjacent edges which have an angle " - << "of greater than " - << cvMeshControls().edgeMergeAngle() << ": " << endl; + std::cout<< "master = " << x << " " << y << " " << z << endl; - label nRemovedEdges = - mergeNearlyParallelEdges(points, maxCosAngle); - reduce(nRemovedEdges, sumOp<label>()); + CGAL::Gmpq xs(CGAL::to_double(closestPoint.x())); + CGAL::Gmpq ys(CGAL::to_double(closestPoint.y())); + CGAL::Gmpq zs(CGAL::to_double(closestPoint.z())); + std::cout<< "slave = " << xs << " " << ys << " " << zs << endl; - Info<< " Merged " << nRemovedEdges << " edges" << endl; + } + } + else + { + nExactMatches++; } + } + } + + Info<< "Found " << nNonMatches << " non-matching duals" << nl + << " and " << nNearMatches << " near matches" + << " and " << nExactMatches << " exact matches" << endl; + } +} + + +void Foam::conformalVoronoiMesh::checkVertices() +{ + List<pointField> pointFieldList(Pstream::nProcs()); + + pointField points(number_of_vertices()); + + labelPairHashSet duplicateVertices; + + label count = 0; + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (duplicateVertices.found(labelPair(vit->procIndex(), vit->index()))) + { + Pout<< "DUPLICATE " << vit->procIndex() << vit->index() << endl; + } + else + { + duplicateVertices.insert(labelPair(vit->procIndex(), vit->index())); + } - labelHashSet wrongFaces = checkPolyMeshQuality(points); + points[count++] = topoint(vit->point()); + } + + pointFieldList[Pstream::myProcNo()] = points; - nBadQualityFaces = wrongFaces.size(); + Pstream::gatherList(pointFieldList); - reduce(nBadQualityFaces, sumOp<label>()); + OFstream str("missingPoints.obj"); + + if (Pstream::master()) + { + Info<< "Checking on master processor the point locations of each " << nl + << "processor point list against the master point list." << nl + << "There are " << pointFieldList.size() << " processors" << nl + << "The size of each processor's point list is:" << endl; - Info<< nl << "Found " << nBadQualityFaces - << " bad quality faces" << endl; + forAll(pointFieldList, pfI) + { + Info<< " Proc " << pfI << " has " << pointFieldList[pfI].size() + << " points" << endl; + } - bool sameFacesAsLastTime(lastWrongFaces == wrongFaces); + label nNonMatches = 0; - reduce(sameFacesAsLastTime, andOp<bool>()); + forAll(pointFieldList[0], pI) + { + const Foam::point& masterPoint = pointFieldList[0][pI]; - if (sameFacesAsLastTime) + forAll(pointFieldList, pfI) + { + if (pI == 0) { - Info<< nl << "Consecutive iterations found the same set " - << "of bad quality faces." << endl; + continue; + } - if - ( - ++nConsecutiveEqualFaceSets - >= cvMeshControls().maxConsecutiveEqualFaceSets() - ) - { - Info<< nl << nConsecutiveEqualFaceSets - << " consecutive iterations produced the same " - << "bad quality faceSet, stopping filtering" - << endl; + bool foundMatch = false; + + forAll(pointFieldList[pfI], pISlave) + { + const Foam::point& slavePoint + = pointFieldList[pfI][pISlave]; + if (masterPoint == slavePoint) + { + foundMatch = true; break; } } - else + + if (!foundMatch) { - nConsecutiveEqualFaceSets = 0; + Info<< " Proc " << pfI << " Master != Slave -> " + << masterPoint << endl; - lastWrongFaces = wrongFaces; + meshTools::writeOBJ(str, masterPoint); + + nNonMatches++; } + } + } + + Info<< "Found a total of " << nNonMatches << " non-matching points" + << endl; + } +} - timeCheck("End of filtering iteration"); - } while (nBadQualityFaces > 0); //nInitialBadQualityFaces); - } +void Foam::conformalVoronoiMesh::calcDualMesh +( + pointField& points, + labelList& boundaryPts, + faceList& faces, + labelList& owner, + labelList& neighbour, + wordList& patchTypes, + wordList& patchNames, + labelList& patchSizes, + labelList& patchStarts, + labelList& procNeighbours, + pointField& cellCentres, + labelList& cellToDelaunayVertex, + labelListList& patchToDelaunayVertex, + PackedBoolList& boundaryFacesToRemove +) +{ + timeCheck("Start calcDualMesh"); + +// if (debug) +// { +// Pout<< nl << "Perfoming some checks . . ." << nl << nl +// << "Total number of vertices = " << number_of_vertices() << nl +// << "Total number of cells = " << number_of_finite_cells() << endl; +// +// checkVertices(); +// checkCells(); +// checkDuals(); +// +// Info<< nl << "Finished checks" << nl << endl; +// } + + setVertexSizeAndAlignment(); + + timeCheck("After setVertexSizeAndAlignment"); + + indexDualVertices(points, boundaryPts); + + { + Info<< nl << "Merging identical points" << endl; + + // There is no guarantee that a merge of close points is no-risk + mergeIdenticalDualVertices(points, boundaryPts); } // Final dual face and owner neighbour construction @@ -288,6 +567,7 @@ void Foam::conformalVoronoiMesh::calcDualMesh patchStarts, procNeighbours, patchToDelaunayVertex, // from patch face to Delaunay vertex (slavePp) + boundaryFacesToRemove, false ); @@ -299,7 +579,7 @@ void Foam::conformalVoronoiMesh::calcDualMesh cellCentres = pointField(cellCentres, cellToDelaunayVertex); - removeUnusedPoints(faces, points); + removeUnusedPoints(faces, points, boundaryPts); timeCheck("End of calcDualMesh"); } @@ -332,7 +612,7 @@ void Foam::conformalVoronoiMesh::calcTetMesh ++vit ) { - if (vit->internalPoint() || vit->pairPoint()) + if (vit->internalPoint() || vit->boundaryPoint()) { vertexMap[vit->index()] = vertI; points[vertI] = topoint(vit->point()); @@ -376,11 +656,11 @@ void Foam::conformalVoronoiMesh::calcTetMesh List<DynamicList<label> > patchOwners(nPatches, DynamicList<label>(0)); - faces.setSize(number_of_facets()); + faces.setSize(number_of_finite_facets()); - owner.setSize(number_of_facets()); + owner.setSize(number_of_finite_facets()); - neighbour.setSize(number_of_facets()); + neighbour.setSize(number_of_finite_facets()); label faceI = 0; @@ -399,7 +679,7 @@ void Foam::conformalVoronoiMesh::calcTetMesh const int oppositeVertex = fit->second; const Cell_handle c2(c1->neighbor(oppositeVertex)); - if (c1->farCell() && c2->farCell()) + if (c1->hasFarPoint() && c2->hasFarPoint()) { // Both tets are outside, skip continue; @@ -421,10 +701,10 @@ void Foam::conformalVoronoiMesh::calcTetMesh newFace = face(verticesOnTriFace); - if (c1->farCell() || c2->farCell()) + if (c1->hasFarPoint() || c2->hasFarPoint()) { // Boundary face... - if (c1->farCell()) + if (c1->hasFarPoint()) { //... with c1 outside ownerCell = c2I; @@ -490,23 +770,23 @@ void Foam::conformalVoronoiMesh::calcTetMesh sortFaces(faces, owner, neighbour); - addPatches - ( - nInternalFaces, - faces, - owner, - patchSizes, - patchStarts, - patchFaces, - patchOwners - ); +// addPatches +// ( +// nInternalFaces, +// faces, +// owner, +// patchSizes, +// patchStarts, +// patchFaces, +// patchOwners +// ); } -void Foam::conformalVoronoiMesh::mergeCloseDualVertices +void Foam::conformalVoronoiMesh::mergeIdenticalDualVertices ( const pointField& pts, - const PackedBoolList& boundaryPts + const labelList& boundaryPts ) { // Assess close points to be merged @@ -518,18 +798,13 @@ void Foam::conformalVoronoiMesh::mergeCloseDualVertices { Map<label> dualPtIndexMap; - nPtsMerged = mergeCloseDualVertices + nPtsMerged = mergeIdenticalDualVertices ( pts, boundaryPts, dualPtIndexMap ); - // if (nPtsMerged > 0) - // { - // Pout<< " Merged " << nPtsMerged << " points " << endl; - // } - reindexDualVertices(dualPtIndexMap); reduce(nPtsMerged, sumOp<label>()); @@ -545,30 +820,15 @@ void Foam::conformalVoronoiMesh::mergeCloseDualVertices } -Foam::label Foam::conformalVoronoiMesh::mergeCloseDualVertices +Foam::label Foam::conformalVoronoiMesh::mergeIdenticalDualVertices ( const pointField& pts, - const PackedBoolList& boundaryPts, + const labelList& boundaryPts, Map<label>& dualPtIndexMap ) const { label nPtsMerged = 0; - label nIdentical = 0; - label nProcEdge = 0; - - // Relative distance for points to be merged - scalar closenessTolerance = cvMeshControls().mergeClosenessCoeff(); - - // Absolute distance for points to be considered coincident. Bit adhoc - // but points were seen with distSqr ~ 1e-30 which is SMALL^2. Add a few - // digits to account for truncation errors. - scalar coincidentDistanceSqr = sqr - ( - SMALL*1E2*geometryToConformTo_.globalBounds().mag() - ); - - for ( Delaunay::Finite_facets_iterator fit = finite_facets_begin(); @@ -580,1260 +840,309 @@ Foam::label Foam::conformalVoronoiMesh::mergeCloseDualVertices const int oppositeVertex = fit->second; const Cell_handle c2(c1->neighbor(oppositeVertex)); - label& c1I = c1->cellIndex(); - label& c2I = c2->cellIndex(); - - if (dualPtIndexMap.found(c1I) || dualPtIndexMap.found(c2I)) + if (is_infinite(c1) || is_infinite(c2)) { - // One of the points of this edge has already been - // merged this sweep, leave for next sweep - continue; } - if ((c1I != c2I) && !c1->farCell() && !c2->farCell()) - { - scalar distSqr = magSqr(pts[c1I] - pts[c2I]); - - if (pts[c1I] == pts[c2I] || distSqr < coincidentDistanceSqr) - { - nIdentical++; - - if (boundaryPts[c2I] == true) - { - // If c2I is a boundary point, then it is kept. - // If both are boundary points then c2I is chosen - // arbitrarily to be kept. + label& c1I = c1->cellIndex(); + label& c2I = c2->cellIndex(); - dualPtIndexMap.insert(c1I, c2I); - dualPtIndexMap.insert(c2I, c2I); - nPtsMerged++; - } - else - { - dualPtIndexMap.insert(c1I, c1I); - dualPtIndexMap.insert(c2I, c1I); - nPtsMerged++; - } + if ((c1I != c2I) && !c1->hasFarPoint() && !c2->hasFarPoint()) + { + const Foam::point& p1 = pts[c1I]; + const Foam::point& p2 = pts[c2I]; - } - else if (distSqr < sqr(averageAnyCellSize(fit)*closenessTolerance)) + if (p1 == p2) { - if (c1->parallelDualVertex() || c2->parallelDualVertex()) - //if (isParallelDualEdge(fit)) - { - // Skip if face uses any edge that becomes a processor - // dual face. - // Note: the real test should be whether the Delaunay edge - // will form a processor patch. - nProcEdge++; - } - else if (boundaryPts[c2I] == true) - { - // If c2I is a boundary point, then it is kept. - // If both are boundary points then c2I is chosen - // arbitrarily to be kept. - - dualPtIndexMap.insert(c1I, c2I); - dualPtIndexMap.insert(c2I, c2I); - nPtsMerged++; - } - else + if (c1I < c2I) { dualPtIndexMap.insert(c1I, c1I); dualPtIndexMap.insert(c2I, c1I); - nPtsMerged++; - } - } - } - } - - if (debug) - { - Info<< "mergeCloseDualVertices:" - << " coincident distance:" << coincidentDistanceSqr - << " closenessTolerance:" << closenessTolerance << endl - << " zero-length edges : " - << returnReduce(nIdentical, sumOp<label>()) << endl - << " protected processor edges : " - << returnReduce(nProcEdge, sumOp<label>()) << endl - << " collapsed edges : " - << returnReduce(nPtsMerged, sumOp<label>()) << endl - << endl; - } - - return nPtsMerged; -} - - -Foam::label Foam::conformalVoronoiMesh::mergeNearlyParallelEdges -( - const pointField& pts, - const scalar maxCosAngle -) -{ - List<HashSet<label> > pointFaceCount(number_of_cells()); - labelList pointNeighbour(number_of_cells(), -1); - - Map<label> dualPtIndexMap; - - for - ( - Delaunay::Finite_edges_iterator eit = finite_edges_begin(); - eit != finite_edges_end(); - ++eit - ) - { - Cell_handle c = eit->first; - Vertex_handle vA = c->vertex(eit->second); - Vertex_handle vB = c->vertex(eit->third); - - if (isBoundaryDualFace(eit)) - { - const face f = buildDualFace(eit); - - forAll(f, pI) - { - const label pIndex = f[pI]; - - const label prevPointI = f.prevLabel(pI); - const label nextPointI = f.nextLabel(pI); - - pointFaceCount[pIndex].insert(prevPointI); - pointFaceCount[pIndex].insert(nextPointI); - pointNeighbour[pIndex] = nextPointI; - } - } - else if - ( - vA->internalOrBoundaryPoint() - || vB->internalOrBoundaryPoint() - ) - { - const face f = buildDualFace(eit); - const boolList faceBoundaryPoints = dualFaceBoundaryPoints(eit); - - forAll(f, pI) - { - const label pIndex = f[pI]; - - const label prevPointI = f.prevLabel(pI); - const label nextPointI = f.nextLabel(pI); - - pointFaceCount[pIndex].insert(prevPointI); - pointFaceCount[pIndex].insert(nextPointI); - - if (faceBoundaryPoints[pI] == false) - { - pointNeighbour[pIndex] = nextPointI; } else { - if (faceBoundaryPoints[prevPointI] == true) - { - pointNeighbour[pIndex] = prevPointI; - } - else if (faceBoundaryPoints[nextPointI] == true) - { - pointNeighbour[pIndex] = nextPointI; - } - else - { - pointNeighbour[pIndex] = pIndex; - } - } - } - } - } - - forAll(pointFaceCount, pI) - { - if (pointFaceCount[pI].size() == 2) - { - List<vector> edges(2, vector(0, 0, 0)); - - label count = 0; - forAllConstIter(HashSet<label>, pointFaceCount[pI], iter) - { - edges[count] = pts[pI] - pts[iter.key()]; - edges[count] /= mag(edges[count]) + VSMALL; - count++; - } - - if (mag(edges[0] & edges[1]) > maxCosAngle) - { - dualPtIndexMap.insert(pI, pointNeighbour[pI]); - } - } - } - - reindexDualVertices(dualPtIndexMap); - - return dualPtIndexMap.size(); -} - - -void Foam::conformalVoronoiMesh::smoothSurface -( - pointField& pts, - const PackedBoolList& boundaryPts -) -{ - label nCollapsedFaces = 0; - - label iterI = 0; - - do - { - Map<label> dualPtIndexMap; - - nCollapsedFaces = smoothSurfaceDualFaces - ( - pts, - boundaryPts, - dualPtIndexMap - ); - - reduce(nCollapsedFaces, sumOp<label>()); - - reindexDualVertices(dualPtIndexMap); - - mergeCloseDualVertices(pts, boundaryPts); - - if (nCollapsedFaces > 0) - { - Info<< " Collapsed " << nCollapsedFaces << " boundary faces" - << endl; - } - - if (++iterI > cvMeshControls().maxCollapseIterations()) - { - Info<< " maxCollapseIterations reached, stopping collapse" - << endl; - - break; - } - - } while (nCollapsedFaces > 0); - - // Force all points of boundary faces to be on the surface - for - ( - Delaunay::Finite_cells_iterator cit = finite_cells_begin(); - cit != finite_cells_end(); - ++cit - ) - { - label ptI = cit->cellIndex(); - - label fC = cit->filterCount(); - - if (fC > cvMeshControls().filterCountSkipThreshold()) - { - // This vertex has been limited too many times, skip - continue; - } - - // Only cells with indices > -1 are valid - if (ptI > -1) - { - if (boundaryPts[ptI] == true) - { - Foam::point& pt = pts[ptI]; - - pointIndexHit surfHit; - label hitSurface; - - geometryToConformTo_.findSurfaceNearest - ( - pt, - sqr(GREAT), - surfHit, - hitSurface - ); - - if (surfHit.hit()) - { - pt += - (surfHit.hitPoint() - pt) - *pow(cvMeshControls().filterErrorReductionCoeff(), fC); - } - } - } - } - - mergeCloseDualVertices(pts, boundaryPts); -} - - -Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces -( - pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap -) const -{ - label nCollapsedFaces = 0; - - const scalar cosPerpendicularToleranceAngle = cos - ( - degToRad(cvMeshControls().surfaceStepFaceAngle()) - ); - - for - ( - Delaunay::Finite_edges_iterator eit = finite_edges_begin(); - eit != finite_edges_end(); - ++eit - ) - { - Cell_circulator ccStart = incident_cells(*eit); - Cell_circulator cc = ccStart; - - bool skipFace = false; - - do - { - if (dualPtIndexMap.found(cc->cellIndex())) - { - // One of the points of this face has already been - // collapsed this sweep, leave for next sweep - - skipFace = true; - - break; - } - - } while (++cc != ccStart); - - if (skipFace) - { - continue; - } - - if (isBoundaryDualFace(eit)) - { - face dualFace = buildDualFace(eit); - - if (dualFace.size() < 3) - { - // This face has been collapsed already - continue; - } - - label maxFC = maxFilterCount(eit); - - if (maxFC > cvMeshControls().filterCountSkipThreshold()) - { - // A vertex on this face has been limited too many - // times, skip - continue; - } - - pointIndexHit surfHit; - label hitSurface; - - geometryToConformTo_.findSurfaceNearest - ( - dualFace.centre(pts), - sqr(GREAT), - surfHit, - hitSurface - ); - - vectorField norm(1); - - allGeometry_[hitSurface].getNormal - ( - List<pointIndexHit>(1, surfHit), - norm - ); - - const vector& surfaceNormal = norm[0]; - - // Orient the face correctly before calculating the normal - - Cell_handle c = eit->first; - Vertex_handle vA = c->vertex(eit->second); - Vertex_handle vB = c->vertex(eit->third); - - if (!vA->internalOrBoundaryPoint()) - { - reverse(dualFace); - } - - vector faceNormal = dualFace.normal(pts); - - if (mag(faceNormal) < VSMALL) - { - // If the face is essentially zero area, then force it - // to be collapsed by making the dot product result -1 - faceNormal = -surfaceNormal; - } - else - { - faceNormal /= mag(faceNormal); - } - - if ((faceNormal & surfaceNormal) < cosPerpendicularToleranceAngle) - { - scalar targetFaceSize = averageAnyCellSize(vA, vB); - - // Selecting faces to collapse based on angle to - // surface, so set collapseSizeLimitCoeff to GREAT to - // allow collapse of all faces - - faceCollapseMode mode = collapseFace - ( - dualFace, - pts, - boundaryPts, - dualPtIndexMap, - targetFaceSize, - GREAT, - maxFC - ); - - if (mode == fcmPoint || mode == fcmEdge) - { - nCollapsedFaces++; - } - } - } - } - - return nCollapsedFaces; -} - - -void Foam::conformalVoronoiMesh::collapseFaces -( - pointField& pts, - const PackedBoolList& boundaryPts, - HashSet<labelPair, labelPair::Hash<> >& deferredCollapseFaces -) -{ - label nCollapsedFaces = 0; - - label iterI = 0; - - do - { - Map<label> dualPtIndexMap; - - deferredCollapseFaces.clear(); - - nCollapsedFaces = collapseFaces - ( - pts, - boundaryPts, - dualPtIndexMap, - deferredCollapseFaces - ); - - reduce(nCollapsedFaces, sumOp<label>()); - - reindexDualVertices(dualPtIndexMap); - - mergeCloseDualVertices(pts, boundaryPts); - - - if (nCollapsedFaces > 0) - { - Info<< " Collapsed " << nCollapsedFaces << " faces" << endl; - // Info<< "dualPtIndexMap" << nl << dualPtIndexMap << endl; - } - - if (++iterI > cvMeshControls().maxCollapseIterations()) - { - Info<< nl << "maxCollapseIterations reached, stopping collapse" - << endl; - - break; - } - - } while (nCollapsedFaces > 0); - -} - - -Foam::label Foam::conformalVoronoiMesh::collapseFaces -( - pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap, - HashSet<labelPair, labelPair::Hash<> >& deferredCollapseFaces -) const -{ - label nCollapsedFaces = 0; - - scalar collapseSizeLimitCoeff = cvMeshControls().filterSizeCoeff(); - - for - ( - Delaunay::Finite_edges_iterator eit = finite_edges_begin(); - eit != finite_edges_end(); - ++eit - ) - { - Cell_circulator ccStart = incident_cells(*eit); - Cell_circulator cc = ccStart; - - bool skipFace = false; - - do - { - if (dualPtIndexMap.found(cc->cellIndex())) - { - // One of the points of this face has already been - // collapsed this sweep, leave for next sweep - - skipFace = true; - - break; - } - - } while (++cc != ccStart); - - if (skipFace) - { - continue; - } - - Cell_handle c = eit->first; - Vertex_handle vA = c->vertex(eit->second); - Vertex_handle vB = c->vertex(eit->third); - - if - ( - vA->internalOrBoundaryPoint() - || vB->internalOrBoundaryPoint() - ) - { - face dualFace = buildDualFace(eit); - - if (dualFace.size() < 3) - { - continue; - } - - label maxFC = maxFilterCount(eit); - - if (maxFC > cvMeshControls().filterCountSkipThreshold()) - { - continue; - } - - scalar targetFaceSize = averageAnyCellSize(vA, vB); - - faceCollapseMode mode = collapseFace - ( - dualFace, - pts, - boundaryPts, - dualPtIndexMap, - targetFaceSize, - collapseSizeLimitCoeff, - maxFC - ); - - if (mode != fcmNone) - { - if (mode == fcmDeferredMultiEdge) - { - // Determine the owner and neighbour labels - - Pair<label> ownAndNei(-1, -1); - - ownerAndNeighbour - ( - vA, - vB, - ownAndNei.first(), - ownAndNei.second() - ); - - // Record the owner and neighbour of this face for a - // deferredMultiEdge collapse - - deferredCollapseFaces.insert(ownAndNei); - } - else - { - nCollapsedFaces++; - } - } - } - } - - return nCollapsedFaces; -} - - -Foam::conformalVoronoiMesh::faceCollapseMode -Foam::conformalVoronoiMesh::collapseFace -( - const face& f, - pointField& pts, - const PackedBoolList& boundaryPts, - Map<label>& dualPtIndexMap, - scalar targetFaceSize, - scalar collapseSizeLimitCoeff, - label maxFC -) const -{ - bool limitToQuadsOrTris = false; - - bool allowEarlyCollapseToPoint = true; - - -// // Quick exit -// label smallEdges = 0; -// const edgeList& fEdges = f.edges(); -// forAll(fEdges, eI) -// { -// const edge& e = fEdges[eI]; -// -// if (e.mag(pts) < 0.2*targetFaceSize) -// { -// smallEdges++; -// } -// } -// if (smallEdges == 0) -// { -// return fcmNone; -// } - - - // if (maxFC > cvMeshControls().filterCountSkipThreshold() - 3) - // { - // limitToQuadsOrTris = true; - - // allowEarlyCollapseToPoint = false; - // } - - - collapseSizeLimitCoeff *= pow - ( - cvMeshControls().filterErrorReductionCoeff(), - maxFC - ); - - labelList facePts(f); - - const Foam::point fC = f.centre(pts); - - vector fN = f.normal(pts); - - const scalar fA = mag(fN); - - tensor J = f.inertia(pts, fC); - - // Find the dominant collapse direction by finding the eigenvector - // that corresponds to the normal direction, discarding it. The - // eigenvector corresponding to the smaller of the two remaining - // eigenvalues is the dominant axis in a high aspect ratio face. - - scalar magJ = mag(J); - - scalar detJ = SMALL; - - if (magJ > VSMALL) - { - // Normalise inertia tensor to remove problems with small values - - J /= mag(J); - // J /= cmptMax(J); - // J /= max(eigenValues(J).x(), SMALL); - - // Calculating determinant, including stabilisation for zero or - // small negative values - - detJ = max(det(J), SMALL); - } - - vector collapseAxis = vector::zero; - - scalar aspectRatio = 1.0; - - if (detJ < 1e-5) - { - collapseAxis = f.edges()[longestEdge(f, pts)].vec(pts); - - collapseAxis /= mag(collapseAxis); - - // Empirical correlation for high aspect ratio faces - - aspectRatio = sqrt(0.35/detJ); - } - else - { - vector eVals = eigenValues(J); - - if (mag(eVals.y() - eVals.x()) < 100*SMALL) - { - // First two eigenvalues are the same: i.e. a square face - - // Cannot necessarily determine linearly independent - // eigenvectors, or any at all, use longest edge direction. - - collapseAxis = f.edges()[longestEdge(f, pts)].vec(pts); - - collapseAxis /= mag(collapseAxis); - - aspectRatio = 1.0; - } - else - { - // The maximum eigenvalue (z()) must be the direction of the - // normal, as it has the greatest value. The minimum eigenvalue - // is the dominant collapse axis for high aspect ratio faces. - - collapseAxis = eigenVector(J, eVals.x()); - - // The inertia calculation describes the mass distribution as a - // function of distance squared to the axis, so the square root of - // the ratio of face-plane moments gives a good indication of the - // aspect ratio. - - aspectRatio = sqrt(eVals.y()/max(eVals.x(), SMALL)); - } - } - - - scalar maxDist = 0; - scalar minDist = GREAT; -// -// if (f.size() <= 3) -// { -// const edgeList& fEdges = f.edges(); -// -// forAll(fEdges, eI) -// { -// const edge& e = fEdges[eI]; -// const scalar d = e.mag(pts); -// -// if (d > maxDist) -// { -// maxDist = d; -// collapseAxis = e.vec(pts); -// } -// else if (d < minDist && d != 0) -// { -// minDist = d; -// } -// } -// } -// else -// { -// forAll(f, pI) -// { -// for (label i = pI + 1; i < f.size(); ++i) -// { -// if -// ( -// f[i] != f.nextLabel(pI) -// && f[i] != f.prevLabel(pI) -// ) -// { -// scalar d = mag(pts[f[pI]] - pts[f[i]]); -// -// if (d > maxDist) -// { -// maxDist = d; -// collapseAxis = pts[f[pI]] - pts[f[i]]; -// } -// else if (d < minDist && d != 0) -// { -// minDist = d; -// } -// } -// } -// } -// } -// -// const edgeList& fEdges = f.edges(); -// -// scalar perimeter = 0; -// -// forAll(fEdges, eI) -// { -// const edge& e = fEdges[eI]; -// const scalar d = e.mag(pts); -// -// perimeter += d; -// -//// collapseAxis += e.vec(pts); -// -// if (d > maxDist) -// { -// collapseAxis = e.vec(pts); -// maxDist = d; -// } -// else if (d < minDist && d != 0) -// { -// minDist = d; -// } -// } -// -// collapseAxis /= mag(collapseAxis); -// -//// Info<< f.size() << " " << minDist << " " << maxDist << " | " -//// << collapseAxis << endl; -// -// aspectRatio = maxDist/minDist; -// -// aspectRatio = min(aspectRatio, sqr(perimeter)/(16.0*fA)); - - if (magSqr(collapseAxis) < VSMALL) - { - WarningIn - ( - "Foam::conformalVoronoiMesh::collapseFace" - ) - << "No collapse axis found for face, not collapsing." - << endl; - - // Output face and collapse axis for visualisation - - Pout<< "# Aspect ratio = " << aspectRatio << nl -// << "# inertia = " << J << nl -// << "# determinant = " << detJ << nl -// << "# eigenvalues = " << eigenValues(J) << nl - << "# collapseAxis = " << collapseAxis << nl - << "# facePts = " << facePts << nl - << endl; - - forAll(f, fPtI) - { - meshTools::writeOBJ(Pout, pts[f[fPtI]]); - } - - Pout<< "f"; - - forAll(f, fPtI) - { - Pout << " " << fPtI + 1; - } - - Pout<< endl; - - return fcmNone; - } - - // The signed distance along the collapse axis passing through the - // face centre that each vertex projects to. - - Field<scalar> d(f.size()); - - forAll(f, fPtI) - { - const Foam::point& pt = pts[f[fPtI]]; - - d[fPtI] = (collapseAxis & (pt - fC)); - } - - // Sort the projected distances and the corresponding vertex - // indices along the collapse axis - - labelList oldToNew; - - sortedOrder(d, oldToNew); - - oldToNew = invert(oldToNew.size(), oldToNew); - - inplaceReorder(oldToNew, d); - - inplaceReorder(oldToNew, facePts); - - // Shift the points so that they are relative to the centre of the - // collapse line. - - scalar dShift = -0.5*(d.first() + d.last()); - - d += dShift; - - // Form two lists, one for each half of the set of points - // projected along the collapse axis. - - // Middle value, index of first entry in the second half - label middle = -1; - - forAll(d, dI) - { - if (d[dI] > 0) - { - middle = dI; - - break; - } - } - - // Negative half - SubList<scalar> dNeg(d, middle, 0); - SubList<label> facePtsNeg(facePts, middle, 0); - - // Positive half - SubList<scalar> dPos(d, d.size() - middle, middle); - SubList<label> facePtsPos(facePts, d.size() - middle, middle); - - // Defining how close to the midpoint (M) of the projected - // vertices line a projected vertex (X) can be before making this - // an invalid edge collapse - // - // X---X-g----------------M----X-----------g----X--X - // - // Only allow a collapse if all projected vertices are outwith - // guardFraction (g) of the distance form the face centre to the - // furthest vertex in the considered direction - - if (dNeg.size() == 0 || dPos.size() == 0) - { - WarningIn - ( - "Foam::conformalVoronoiMesh::collapseFace" - ) - << "All points on one side of face centre, not collapsing." - << endl; - } - - faceCollapseMode mode = fcmNone; - - if - ( - (fA < aspectRatio*sqr(targetFaceSize*collapseSizeLimitCoeff)) - && (!limitToQuadsOrTris || f.size() <= 4) - ) - { - scalar guardFraction = cvMeshControls().edgeCollapseGuardFraction(); - - if - ( - allowEarlyCollapseToPoint - && (d.last() - d.first()) - < targetFaceSize - *0.2*cvMeshControls().maxCollapseFaceToPointSideLengthCoeff() - ) - { - mode = fcmPoint; - } - else if - ( - (dNeg.last() < guardFraction*dNeg.first()) - && (dPos.first() > guardFraction*dPos.last()) - ) - { - mode = fcmEdge; - } - else if - ( - (d.last() - d.first()) - < targetFaceSize - *cvMeshControls().maxCollapseFaceToPointSideLengthCoeff() - ) - { - // If the face can't be collapsed to an edge, and it has a - // small enough span, collapse it to a point. - - mode = fcmPoint; - } - else - { - // Alternatively, do not topologically collapse face here, - // but push all points onto a line, so that the face area - // is zero and then collapse to a string of edges later. - // The fcmDeferredMultiEdge collapse must be performed at - // the polyMesh stage as this type of collapse can't be - // performed and still maintain topological dual - // consistency with the Delaunay structure - - mode = fcmDeferredMultiEdge; - } - } - - switch (mode) - { - case fcmEdge: - { - // Negative half - - label collapseToPtI = facePtsNeg.first(); - - Foam::point collapseToPt = - collapseAxis*(sum(dNeg)/dNeg.size() - dShift) + fC; - -// DynamicList<label> faceBoundaryPts(f.size()); - - forAll(facePtsNeg, fPtI) - { - if (boundaryPts[facePtsNeg[fPtI]] == true) - { - // If there is a point which is on the boundary, - // use it as the point to collapse others to, will - // use the first boundary point encountered if - // there are multiple boundary points. - - collapseToPtI = facePtsNeg[fPtI]; - - collapseToPt = pts[collapseToPtI]; - - break; - -// faceBoundaryPts.append(facePtsNeg[fPtI]); - } - } - -// if (!faceBoundaryPts.empty()) -// { -// if (faceBoundaryPts.size() == 2) -// { -// collapseToPtI = faceBoundaryPts[0]; -// -// collapseToPt = -// 0.5 -// *( -// pts[faceBoundaryPts[0]] -// + pts[faceBoundaryPts[1]] -// ); -// } -// else if (faceBoundaryPts.size() < f.size()) -// { -// face bFace(faceBoundaryPts); -// -// collapseToPtI = faceBoundaryPts.first(); -// -// collapseToPt = bFace.centre(pts); -// } -// } -// -// faceBoundaryPts.clear(); - - // ...otherwise arbitrarily choosing the most distant - // point as the index to collapse to. - - forAll(facePtsNeg, fPtI) - { - dualPtIndexMap.insert(facePtsNeg[fPtI], collapseToPtI); - } - - pts[collapseToPtI] = collapseToPt; - - // Positive half - - collapseToPtI = facePtsPos.last(); - - collapseToPt = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC; - - forAll(facePtsPos, fPtI) - { - if (boundaryPts[facePtsPos[fPtI]] == true) - { - // If there is a point which is on the boundary, - // use it as the point to collapse others to, will - // use the first boundary point encountered if - // there are multiple boundary points. - - collapseToPtI = facePtsPos[fPtI]; - - collapseToPt = pts[collapseToPtI]; - - break; - -// faceBoundaryPts.append(facePtsNeg[fPtI]); - } - } - -// if (!faceBoundaryPts.empty()) -// { -// if (faceBoundaryPts.size() == 2) -// { -// collapseToPtI = faceBoundaryPts[0]; -// -// collapseToPt = -// 0.5 -// *( -// pts[faceBoundaryPts[0]] -// + pts[faceBoundaryPts[1]] -// ); -// } -// else if (faceBoundaryPts.size() < f.size()) -// { -// face bFace(faceBoundaryPts); -// -// collapseToPtI = faceBoundaryPts.first(); -// -// collapseToPt = bFace.centre(pts); -// } -// } - - // ...otherwise arbitrarily choosing the most distant - // point as the index to collapse to. - - forAll(facePtsPos, fPtI) - { - dualPtIndexMap.insert(facePtsPos[fPtI], collapseToPtI); - } - - pts[collapseToPtI] = collapseToPt; - - break; - } - - case fcmPoint: - { - label collapseToPtI = facePts.first(); - - Foam::point collapseToPt = fC; - - DynamicList<label> faceBoundaryPts(f.size()); - - forAll(facePts, fPtI) - { - if (boundaryPts[facePts[fPtI]] == true) - { - // If there is a point which is on the boundary, - // use it as the point to collapse others to, will - // use the first boundary point encountered if - // there are multiple boundary points. - -// collapseToPtI = facePts[fPtI]; -// -// collapseToPt = pts[collapseToPtI]; -// -// break; - - faceBoundaryPts.append(facePts[fPtI]); - } - } - - if (!faceBoundaryPts.empty()) - { - if (faceBoundaryPts.size() == 2) - { - collapseToPtI = faceBoundaryPts[0]; - - collapseToPt = - 0.5*(pts[faceBoundaryPts[0]] + pts[faceBoundaryPts[1]]); - } - else if (faceBoundaryPts.size() < f.size()) - { - face bFace(faceBoundaryPts); - - collapseToPtI = faceBoundaryPts.first(); - - collapseToPt = bFace.centre(pts); - } - } - - // ...otherwise arbitrarily choosing the first point as - // the index to collapse to. Collapse to the face centre. - - forAll(facePts, fPtI) - { - dualPtIndexMap.insert(facePts[fPtI], collapseToPtI); - } - - pts[collapseToPtI] = collapseToPt; - - break; - } - - case fcmDeferredMultiEdge: - { - // forAll(facePts, fPtI) - // { - // label ptI = facePts[fPtI]; - - // pts[ptI] = collapseAxis*(d[fPtI] - dShift) + fC; - - // dualPtIndexMap.insert(ptI, ptI); - // } - - break; - } - - case fcmNone: - { - break; - } - } - - // if (mode == fcmDeferredMultiEdge) - // if (mode != fcmNone) - // { - // // Output face and collapse axis for visualisation - - // Pout<< "# Aspect ratio = " << aspectRatio << nl - // << "# determinant = " << detJ << nl - // << "# collapseAxis = " << collapseAxis << nl - // << "# mode = " << mode << nl - // << "# facePts = " << facePts << nl - // // << "# eigenvalues = " << eVals - // << endl; - - // scalar scale = 2.0*mag(fC - pts[f[0]]); - - // meshTools::writeOBJ(Pout, fC); - // meshTools::writeOBJ(Pout, fC + scale*collapseAxis); - - // Pout<< "f 1 2" << endl; - - // forAll(f, fPtI) - // { - // meshTools::writeOBJ(Pout, pts[f[fPtI]]); - // } - - // Pout<< "f"; - - // forAll(f, fPtI) - // { - // Pout << " " << fPtI + 3; - // } - - // Pout<< nl << "# " << d << endl; - - // Pout<< "# " << d.first() << " " << d.last() << endl; - - // forAll(d, dI) - // { - // meshTools::writeOBJ(Pout, fC + (d[dI] - dShift)*collapseAxis); - // } - - // Pout<< endl; - // } - - return mode; -} - - -Foam::label Foam::conformalVoronoiMesh::longestEdge -( - const face& f, - const pointField& pts -) const -{ - const edgeList& eds = f.edges(); - - label longestEdgeI = -1; + dualPtIndexMap.insert(c1I, c2I); + dualPtIndexMap.insert(c2I, c2I); + } - scalar longestEdgeLength = -SMALL; + nPtsMerged++; + } + } + } - forAll(eds, edI) + if (debug) { - scalar edgeLength = eds[edI].mag(pts); - - if (edgeLength > longestEdgeLength) - { - longestEdgeI = edI; - - longestEdgeLength = edgeLength; - } + Info<< "mergeIdenticalDualVertices:" << endl + << " zero-length edges : " + << returnReduce(nPtsMerged, sumOp<label>()) << endl + << endl; } - return longestEdgeI; + return nPtsMerged; } +//void Foam::conformalVoronoiMesh::smoothSurface +//( +// pointField& pts, +// const labelList& boundaryPts +//) +//{ +// label nCollapsedFaces = 0; +// +// label iterI = 0; +// +// do +// { +// Map<label> dualPtIndexMap; +// +// nCollapsedFaces = smoothSurfaceDualFaces +// ( +// pts, +// boundaryPts, +// dualPtIndexMap +// ); +// +// reduce(nCollapsedFaces, sumOp<label>()); +// +// reindexDualVertices(dualPtIndexMap); +// +// mergeIdenticalDualVertices(pts, boundaryPts); +// +// if (nCollapsedFaces > 0) +// { +// Info<< " Collapsed " << nCollapsedFaces << " boundary faces" +// << endl; +// } +// +// if (++iterI > cvMeshControls().maxCollapseIterations()) +// { +// Info<< " maxCollapseIterations reached, stopping collapse" +// << endl; +// +// break; +// } +// +// } while (nCollapsedFaces > 0); +// +// // Force all points of boundary faces to be on the surface +//// for +//// ( +//// Delaunay::Finite_cells_iterator cit = finite_cells_begin(); +//// cit != finite_cells_end(); +//// ++cit +//// ) +//// { +//// label ptI = cit->cellIndex(); +//// +//// label fC = cit->filterCount(); +//// +//// if (fC > cvMeshControls().filterCountSkipThreshold()) +//// { +//// // This vertex has been limited too many times, skip +//// continue; +//// } +//// +//// // Only cells with indices > -1 are valid +//// if (ptI > -1) +//// { +//// if (boundaryPts[ptI] != -1) +//// { +//// Foam::point& pt = pts[ptI]; +//// +//// pointIndexHit surfHit; +//// label hitSurface; +//// +//// geometryToConformTo_.findSurfaceNearest +//// ( +//// pt, +//// sqr(GREAT), +//// surfHit, +//// hitSurface +//// ); +//// +//// if (surfHit.hit()) +//// { +//// pt += +//// (surfHit.hitPoint() - pt) +//// *pow(cvMeshControls().filterErrorReductionCoeff(), fC); +//// } +//// } +//// } +//// } +//// +//// mergeCloseDualVertices(pts, boundaryPts); +//} +// +// +//Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces +//( +// pointField& pts, +// const labelList& boundaryPts, +// Map<label>& dualPtIndexMap +//) const +//{ +// label nCollapsedFaces = 0; +// +// const scalar cosPerpendicularToleranceAngle = cos +// ( +// degToRad(cvMeshControls().surfaceStepFaceAngle()) +// ); +// +// for +// ( +// Delaunay::Finite_edges_iterator eit = finite_edges_begin(); +// eit != finite_edges_end(); +// ++eit +// ) +// { +// Cell_circulator ccStart = incident_cells(*eit); +// Cell_circulator cc = ccStart; +// +// bool skipFace = false; +// +// do +// { +// if (dualPtIndexMap.found(cc->cellIndex())) +// { +// // One of the points of this face has already been +// // collapsed this sweep, leave for next sweep +// +// skipFace = true; +// +// break; +// } +// +// } while (++cc != ccStart); +// +// if (skipFace) +// { +// continue; +// } +// +// if (isBoundaryDualFace(eit)) +// { +// face dualFace = buildDualFace(eit); +// +// if (dualFace.size() < 3) +// { +// // This face has been collapsed already +// continue; +// } +// +// label maxFC = maxFilterCount(eit); +// +// if (maxFC > cvMeshControls().filterCountSkipThreshold()) +// { +// // A vertex on this face has been limited too many +// // times, skip +// continue; +// } +// +// Cell_handle c = eit->first; +// Vertex_handle vA = c->vertex(eit->second); +// Vertex_handle vB = c->vertex(eit->third); +// +// if +// ( +// vA->internalBoundaryPoint() && vA->surfacePoint() +// && vB->externalBoundaryPoint() && vB->surfacePoint() +// ) +// { +// if (vA->index() == vB->index() - 1) +// { +// continue; +// } +// } +// else if +// ( +// vA->externalBoundaryPoint() && vA->surfacePoint() +// && vB->internalBoundaryPoint() && vB->surfacePoint() +// ) +// { +// if (vA->index() == vB->index() + 1) +// { +// continue; +// } +// } +//// else if +//// ( +//// vA->internalBoundaryPoint() && vA->featureEdgePoint() +//// && vB->externalBoundaryPoint() && vB->featureEdgePoint() +//// ) +//// { +//// if (vA->index() == vB->index() - 1) +//// { +//// continue; +//// } +//// } +//// else if +//// ( +//// vA->externalBoundaryPoint() && vA->featureEdgePoint() +//// && vB->internalBoundaryPoint() && vB->featureEdgePoint() +//// ) +//// { +//// if (vA->index() == vB->index() + 1) +//// { +//// continue; +//// } +//// } +//// else if +//// ( +//// vA->internalBoundaryPoint() && vA->featurePoint() +//// && vB->externalBoundaryPoint() && vB->featurePoint() +//// ) +//// { +//// if (vA->index() == vB->index() - 1) +//// { +//// continue; +//// } +//// } +//// else if +//// ( +//// vA->externalBoundaryPoint() && vA->featurePoint() +//// && vB->internalBoundaryPoint() && vB->featurePoint() +//// ) +//// { +//// if (vA->index() == vB->index() + 1) +//// { +//// continue; +//// } +//// } +// +// +//// if ((faceNormal & surfaceNormal) < cosPerpendicularToleranceAngle) +//// { +// scalar targetFaceSize = averageAnyCellSize(vA, vB); +// +// // Selecting faces to collapse based on angle to +// // surface, so set collapseSizeLimitCoeff to GREAT to +// // allow collapse of all faces +// +// faceCollapseMode mode = collapseFace +// ( +// dualFace, +// pts, +// boundaryPts, +// dualPtIndexMap, +// targetFaceSize, +// GREAT, +// maxFC +// ); +// +// if (mode == fcmPoint || mode == fcmEdge) +// { +// nCollapsedFaces++; +// } +//// } +// } +// } +// +// return nCollapsedFaces; +//} + + void Foam::conformalVoronoiMesh::deferredCollapseFaceSet ( labelList& owner, @@ -1871,6 +1180,7 @@ Foam::conformalVoronoiMesh::createPolyMeshFromPoints labelList procNeighbours; pointField cellCentres; labelListList patchToDelaunayVertex; + PackedBoolList boundaryFacesToRemove; timeCheck("Start of checkPolyMeshQuality"); @@ -1887,6 +1197,7 @@ Foam::conformalVoronoiMesh::createPolyMeshFromPoints patchStarts, procNeighbours, patchToDelaunayVertex, + boundaryFacesToRemove, false ); @@ -1926,7 +1237,6 @@ Foam::conformalVoronoiMesh::createPolyMeshFromPoints if (patchTypes[p] == processorPolyPatch::typeName) { // Do not create empty processor patches - if (patchSizes[p] > 0) { patches[nValidPatches] = new processorPolyPatch @@ -1937,7 +1247,8 @@ Foam::conformalVoronoiMesh::createPolyMeshFromPoints nValidPatches, pMesh.boundaryMesh(), Pstream::myProcNo(), - procNeighbours[p] + procNeighbours[p], + coupledPolyPatch::COINCIDENTFULLMATCH ); nValidPatches++; @@ -1991,13 +1302,13 @@ void Foam::conformalVoronoiMesh::checkCellSizing() timeCheck("Start of Cell Sizing"); - PackedBoolList boundaryPts(number_of_cells(), false); + labelList boundaryPts(number_of_finite_cells(), -1); pointField ptsField; indexDualVertices(ptsField, boundaryPts); // Merge close dual vertices. - mergeCloseDualVertices(ptsField, boundaryPts); + mergeIdenticalDualVertices(ptsField, boundaryPts); autoPtr<polyMesh> meshPtr = createPolyMeshFromPoints(ptsField); const polyMesh& pMesh = meshPtr(); @@ -2092,10 +1403,10 @@ void Foam::conformalVoronoiMesh::checkCellSizing() } } - Info<< " Automatically re-sizing " << cellsToResize.size() + Info<< " DISABLED: Automatically re-sizing " << cellsToResize.size() << " cells that are attached to the bad faces: " << endl; - cellSizeControl_.setCellSizes(cellsToResize); + //cellSizeControl_.setCellSizes(cellsToResize); } timeCheck("End of Cell Sizing"); @@ -2181,8 +1492,6 @@ Foam::labelHashSet Foam::conformalVoronoiMesh::checkPolyMeshQuality labelHashSet wrongFaces(pMesh.nFaces()/100); - Info << endl; - DynamicList<label> checkFaces(pMesh.nFaces()); const vectorField& fAreas = pMesh.faceAreas(); @@ -2197,7 +1506,7 @@ Foam::labelHashSet Foam::conformalVoronoiMesh::checkPolyMeshQuality } } - Info<< "Excluding " + Info<< nl << "Excluding " << returnReduce(fAreas.size() - checkFaces.size(), sumOp<label>()) << " faces from check, < " << faceAreaLimit << " area" << endl; @@ -2371,18 +1680,16 @@ Foam::labelHashSet Foam::conformalVoronoiMesh::checkPolyMeshQuality void Foam::conformalVoronoiMesh::indexDualVertices ( pointField& pts, - PackedBoolList& boundaryPts + labelList& boundaryPts ) { // Indexing Delaunay cells, which are the dual vertices - label dualVertI = 0; - - pts.setSize(number_of_cells()); + this->resetCellCount(); - boundaryPts.setSize(number_of_cells(), false); + pts.setSize(number_of_finite_cells()); - boundaryPts = false; + boundaryPts.setSize(number_of_finite_cells(), -1); for ( @@ -2391,19 +1698,83 @@ void Foam::conformalVoronoiMesh::indexDualVertices ++cit ) { - if (cit->internalOrBoundaryDualVertex()) +// if (tetrahedron(cit).volume() == 0) +// { +// Pout<< "ZERO VOLUME TET" << endl; +// Pout<< cit->info(); +// Pout<< "Dual = " << cit->dual(); +// } + + if (!cit->hasFarPoint()) { - cit->cellIndex() = dualVertI; + cit->cellIndex() = getNewCellIndex(); - pts[dualVertI] = cit->dual(); + // For nearly coplanar Delaunay cells that are present on different + // processors the result of the circumcentre calculation depends on + // the ordering of the vertices, so synchronise it across processors - if (cit->boundaryDualVertex()) + if (Pstream::parRun() && cit->parallelDualVertex()) + { + typedef CGAL::Exact_predicates_exact_constructions_kernel Exact; + typedef CGAL::Point_3<Exact> ExactPoint; + + List<labelPair> cellVerticesPair(4); + List<ExactPoint> cellVertices(4); + + for (label vI = 0; vI < 4; ++vI) + { + cellVerticesPair[vI] = labelPair + ( + cit->vertex(vI)->procIndex(), + cit->vertex(vI)->index() + ); + + cellVertices[vI] = ExactPoint + ( + cit->vertex(vI)->point().x(), + cit->vertex(vI)->point().y(), + cit->vertex(vI)->point().z() + ); + } + + // Sort the vertices so that they will be in the same order on + // each processor + labelList oldToNew; + sortedOrder(cellVerticesPair, oldToNew); + oldToNew = invert(oldToNew.size(), oldToNew); + inplaceReorder(oldToNew, cellVertices); + + ExactPoint synchronisedDual = CGAL::circumcenter + ( + cellVertices[0], + cellVertices[1], + cellVertices[2], + cellVertices[3] + ); + + pts[cit->cellIndex()] = Foam::point + ( + CGAL::to_double(synchronisedDual.x()), + CGAL::to_double(synchronisedDual.y()), + CGAL::to_double(synchronisedDual.z()) + ); + } + else { - // This is a boundary dual vertex - boundaryPts[dualVertI] = true; + pts[cit->cellIndex()] = cit->dual(); } - dualVertI++; + if (cit->boundaryDualVertex()) + { + if (cit->featureEdgeDualVertex()) + { + boundaryPts[cit->cellIndex()] = 1; + } + else + { + boundaryPts[cit->cellIndex()] = 0; + } + } } else { @@ -2411,9 +1782,9 @@ void Foam::conformalVoronoiMesh::indexDualVertices } } - pts.setSize(dualVertI); + pts.setSize(this->cellCount()); - boundaryPts.setSize(dualVertI); + boundaryPts.setSize(this->cellCount()); } @@ -2437,18 +1808,11 @@ void Foam::conformalVoronoiMesh::reindexDualVertices } -void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches +Foam::label Foam::conformalVoronoiMesh::createPatchInfo ( - faceList& faces, - labelList& owner, - labelList& neighbour, - wordList& patchTypes, wordList& patchNames, - labelList& patchSizes, - labelList& patchStarts, - labelList& procNeighbours, - labelListList& patchPointPairSlaves, - bool includeEmptyPatches + wordList& patchTypes, + labelList& procNeighbours ) const { patchNames = geometryToConformTo_.patchNames(); @@ -2467,7 +1831,13 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches if (Pstream::parRun()) { - boolList procUsed(Pstream::nProcs(), false); + List<boolList> procUsedList + ( + Pstream::nProcs(), + boolList(Pstream::nProcs(), false) + ); + + boolList& procUsed = procUsedList[Pstream::myProcNo()]; // Determine which processor patches are required for @@ -2477,12 +1847,30 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches vit++ ) { + // This test is not sufficient if one of the processors does + // not receive a referred vertex from another processor, but does + // send one to the other processor. if (vit->referred()) { procUsed[vit->procIndex()] = true; } } + // Because the previous test was insufficient, combine the lists. + Pstream::gatherList(procUsedList); + Pstream::scatterList(procUsedList); + + forAll(procUsedList, procI) + { + if (procI != Pstream::myProcNo()) + { + if (procUsedList[procI][Pstream::myProcNo()]) + { + procUsed[procI] = true; + } + } + } + forAll(procUsed, pUI) { if (procUsed[pUI]) @@ -2493,9 +1881,9 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches label nNonProcPatches = patchNames.size(); + patchNames.setSize(nNonProcPatches + nProcPatches); patchTypes.setSize(nNonProcPatches + nProcPatches); procNeighbours.setSize(nNonProcPatches + nProcPatches, -1); - patchNames.setSize(nNonProcPatches + nProcPatches); label procAddI = 0; @@ -2519,25 +1907,46 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches } } - // Pout<< patchTypes << " " << patchNames << endl; + return defaultPatchIndex; +} - label nPatches = patchNames.size(); - List<DynamicList<face> > patchFaces(nPatches, DynamicList<face>(0)); +void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches +( + faceList& faces, + labelList& owner, + labelList& neighbour, + wordList& patchTypes, + wordList& patchNames, + labelList& patchSizes, + labelList& patchStarts, + labelList& procNeighbours, + labelListList& patchPointPairSlaves, + PackedBoolList& boundaryFacesToRemove, + bool includeEmptyPatches +) const +{ + const label defaultPatchIndex = createPatchInfo + ( + patchNames, + patchTypes, + procNeighbours + ); - List<DynamicList<label> > patchOwners(nPatches, DynamicList<label>(0)); + const label nPatches = patchNames.size(); + List<DynamicList<face> > patchFaces(nPatches, DynamicList<face>(0)); + List<DynamicList<label> > patchOwners(nPatches, DynamicList<label>(0)); // Per patch face the index of the slave node of the point pair List<DynamicList<label> > patchPPSlaves(nPatches, DynamicList<label>(0)); + List<DynamicList<bool> > indirectPatchFace(nPatches, DynamicList<bool>(0)); - faces.setSize(number_of_edges()); + faces.setSize(number_of_finite_edges()); + owner.setSize(number_of_finite_edges()); + neighbour.setSize(number_of_finite_edges()); - owner.setSize(number_of_edges()); - - neighbour.setSize(number_of_edges()); - - List<Pair<DynamicList<label> > > procPatchSortingIndex(nPatches); + labelPairPairDynListList procPatchSortingIndex(nPatches); label dualFaceI = 0; @@ -2554,8 +1963,8 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches if ( - vA->internalOrBoundaryPoint() - || vB->internalOrBoundaryPoint() + (vA->internalOrBoundaryPoint() && !vA->referred()) + || (vB->internalOrBoundaryPoint() && !vB->referred()) ) { face newDualFace = buildDualFace(eit); @@ -2574,44 +1983,56 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches { // boundary face - Foam::point ptA = topoint(vA->point()); - Foam::point ptB = topoint(vB->point()); + pointFromPoint ptA = topoint(vA->point()); + pointFromPoint ptB = topoint(vB->point()); label patchIndex = -1; - if - ( - vA->referredInternalOrBoundaryPoint() - || vB->referredInternalOrBoundaryPoint() - ) + if (isProcBoundaryEdge(eit)) { // One (and only one) of the points is an internal // point from another processor label procIndex = max(vA->procIndex(), vB->procIndex()); - patchIndex = findIndex(procNeighbours, procIndex); + patchIndex = max + ( + findIndex(procNeighbours, vA->procIndex()), + findIndex(procNeighbours, vB->procIndex()) + ); // The lower processor index is the owner of the - // two for the purposed of sorting the patch faces. + // two for the purpose of sorting the patch faces. if (Pstream::myProcNo() < procIndex) { // Use this processor's vertex index as the master // for sorting - Pair<DynamicList<label> >& sortingIndex = - procPatchSortingIndex[patchIndex]; + DynamicList<Pair<labelPair> >& sortingIndex = + procPatchSortingIndex[patchIndex]; - if (vB->referredInternalOrBoundaryPoint()) + if (vB->internalOrBoundaryPoint() && vB->referred()) { - sortingIndex.first().append(vA->index()); - sortingIndex.second().append(vB->index()); + sortingIndex.append + ( + Pair<labelPair> + ( + labelPair(vA->index(), vA->procIndex()), + labelPair(vB->index(), vB->procIndex()) + ) + ); } else { - sortingIndex.first().append(vB->index()); - sortingIndex.second().append(vA->index()); + sortingIndex.append + ( + Pair<labelPair> + ( + labelPair(vB->index(), vB->procIndex()), + labelPair(vA->index(), vA->procIndex()) + ) + ); } } else @@ -2619,30 +2040,42 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches // Use the other processor's vertex index as the // master for sorting - Pair<DynamicList<label> >& sortingIndex = + DynamicList<Pair<labelPair> >& sortingIndex = procPatchSortingIndex[patchIndex]; - if (vA->referredInternalOrBoundaryPoint()) + if (vA->internalOrBoundaryPoint() && vA->referred()) { - sortingIndex.first().append(vA->index()); - sortingIndex.second().append(vB->index()); + sortingIndex.append + ( + Pair<labelPair> + ( + labelPair(vA->index(), vA->procIndex()), + labelPair(vB->index(), vB->procIndex()) + ) + ); } else { - sortingIndex.first().append(vB->index()); - sortingIndex.second().append(vA->index()); + sortingIndex.append + ( + Pair<labelPair> + ( + labelPair(vB->index(), vB->procIndex()), + labelPair(vA->index(), vA->procIndex()) + ) + ); } } - // Pout<< ptA << " " << ptB - // << " proc indices " - // << vA->procIndex() << " " << vB->procIndex() - // << " indices " << vA->index() - // << " " << vB->index() - // << " my proc " << Pstream::myProcNo() - // << " addedIndex " - // << procPatchSortingIndex[patchIndex].last() - // << endl; +// Pout<< ptA << " " << ptB +// << " proc indices " +// << vA->procIndex() << " " << vB->procIndex() +// << " indices " << vA->index() +// << " " << vB->index() +// << " my proc " << Pstream::myProcNo() +// << " addedIndex " +// << procPatchSortingIndex[patchIndex].last() +// << endl; } else { @@ -2667,6 +2100,17 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches patchFaces[patchIndex].append(newDualFace); patchOwners[patchIndex].append(own); + // If the two vertices are a pair, then the patch face is + // a desired one. + if (vA->type() == vB->index()) + { + indirectPatchFace[patchIndex].append(true); + } + else + { + indirectPatchFace[patchIndex].append(false); + } + // Store the non-internal or boundary point if (vA->internalOrBoundaryPoint()) { @@ -2680,7 +2124,6 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches else { // internal face - faces[dualFaceI] = newDualFace; owner[dualFaceI] = own; neighbour[dualFaceI] = nei; @@ -2727,8 +2170,10 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches owner, patchSizes, patchStarts, + boundaryFacesToRemove, patchFaces, - patchOwners + patchOwners, + indirectPatchFace ); // Return patchPointPairSlaves.setSize(nPatches); @@ -2738,14 +2183,28 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches patchPointPairSlaves[patchI].transfer(patchPPSlaves[patchI]); } - if (cvMeshControls().objOutput()) +// if (cvMeshControls().objOutput()) { + Info<< "Writing processor interfaces" << endl; + forAll(procNeighbours, nbI) { if (patchFaces[nbI].size() > 0) { const label neighbour = procNeighbours[nbI]; + faceList procPatchFaces = patchFaces[nbI]; + + // Reverse faces as it makes it easier to analyse the output + // using a diff + if (neighbour < Pstream::myProcNo()) + { + forAll(procPatchFaces, fI) + { + procPatchFaces[fI] = procPatchFaces[fI].reverseFace(); + } + } + if (neighbour != -1) { word fName = @@ -2755,11 +2214,7 @@ void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches + name(neighbour) + "_interface.obj"; - writeProcessorInterface - ( - fName, - patchFaces[nbI] - ); + writeProcessorInterface(fName, procPatchFaces); } } } @@ -2785,9 +2240,7 @@ void Foam::conformalVoronoiMesh::createCellCentres { if (vit->internalOrBoundaryPoint()) { - cellCentres[vit->index()] = topoint(vit->point()); - - vertI++; + cellCentres[vertI++] = topoint(vit->point()); } } @@ -2800,6 +2253,8 @@ Foam::tmp<Foam::pointField> Foam::conformalVoronoiMesh::allPoints() const tmp<pointField> tpts(new pointField(number_of_vertices(), point::max)); pointField& pts = tpts(); + label nVert = 0; + for ( Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); @@ -2809,7 +2264,7 @@ Foam::tmp<Foam::pointField> Foam::conformalVoronoiMesh::allPoints() const { if (vit->internalOrBoundaryPoint()) { - pts[vit->index()] = topoint(vit->point()); + pts[nVert++] = topoint(vit->point()); } } @@ -2838,8 +2293,12 @@ void Foam::conformalVoronoiMesh::sortFaces // 1 | 24 // 1 | 91 - // Two stage sort: - // 1) sort by owner + List<labelPair> ownerNeighbourPair(owner.size()); + + forAll(ownerNeighbourPair, oNI) + { + ownerNeighbourPair[oNI] = labelPair(owner[oNI], neighbour[oNI]); + } Info<< nl << "Sorting faces, owner and neighbour into upper triangular order" @@ -2847,71 +2306,13 @@ void Foam::conformalVoronoiMesh::sortFaces labelList oldToNew; - sortedOrder(owner, oldToNew); + sortedOrder(ownerNeighbourPair, oldToNew); oldToNew = invert(oldToNew.size(), oldToNew); inplaceReorder(oldToNew, faces); inplaceReorder(oldToNew, owner); inplaceReorder(oldToNew, neighbour); - - // 2) in each block of owners sort by neighbour - - // Reset map. Elements that are not sorted will retain their -1 - // value, which will mean that they are ignored by inplaceReorder - - oldToNew = -1; - - label blockStart = 0; - - for (label i = 1; i < owner.size(); i++) - { - label blockLength = -1; - - if (owner[i] > owner[i - 1]) - { - blockLength = i - blockStart; - } - else if (i == owner.size() - 1) - { - // If the last element is not a jump in owner, then it - // needs to trigger a sort of the last block, but with a - // block length that is one element longer so that it - // sorts itself. - - // If it is a jump in owner, then it will form a block of - // length one, and so will not need sorted. - - blockLength = i - blockStart + 1; - } - - if (blockLength >= 1) - { - labelList blockIndices = identity(blockLength) + blockStart; - - SubList<label> neighbourBlock - ( - neighbour, - blockLength, - blockStart - ); - - sortedOrder(neighbourBlock, blockIndices); - - blockIndices = invert(blockIndices.size(), blockIndices); - - forAll(blockIndices, b) - { - oldToNew[blockStart + b] = blockIndices[b] + blockStart; - } - - blockStart = i; - } - } - - // owner does not need re-sorted - inplaceReorder(oldToNew, faces); - inplaceReorder(oldToNew, neighbour); } @@ -2920,7 +2321,7 @@ void Foam::conformalVoronoiMesh::sortProcPatches List<DynamicList<face> >& patchFaces, List<DynamicList<label> >& patchOwners, List<DynamicList<label> >& patchPointPairSlaves, - List<Pair<DynamicList<label> > >& patchSortingIndices + labelPairPairDynListList& patchSortingIndices ) const { if (!Pstream::parRun()) @@ -2934,18 +2335,16 @@ void Foam::conformalVoronoiMesh::sortProcPatches labelList& owner = patchOwners[patchI]; DynamicList<label>& slaves = patchPointPairSlaves[patchI]; - Pair<DynamicList<label> >& sortingIndices = patchSortingIndices[patchI]; - - List<label>& primary = sortingIndices.first(); - List<label>& secondary = sortingIndices.second(); + DynamicList<Pair<labelPair> >& sortingIndices + = patchSortingIndices[patchI]; - if (!primary.empty()) + if (!sortingIndices.empty()) { if ( - faces.size() != primary.size() - || owner.size() != primary.size() - || slaves.size() != primary.size() + faces.size() != sortingIndices.size() + || owner.size() != sortingIndices.size() + || slaves.size() != sortingIndices.size() ) { FatalErrorIn @@ -2962,80 +2361,18 @@ void Foam::conformalVoronoiMesh::sortProcPatches << " faces.size() " << faces.size() << nl << " owner.size() " << owner.size() << nl << " slaves.size() " << slaves.size() << nl - << " sortingIndices.first().size() " - << sortingIndices.first().size() + << " sortingIndices.size() " + << sortingIndices.size() << exit(FatalError) << endl; } - // Two stage sort: - // 1) sort by primary - labelList oldToNew; - sortedOrder(primary, oldToNew); + sortedOrder(sortingIndices, oldToNew); oldToNew = invert(oldToNew.size(), oldToNew); - inplaceReorder(oldToNew, primary); - inplaceReorder(oldToNew, secondary); - inplaceReorder(oldToNew, faces); - inplaceReorder(oldToNew, owner); - inplaceReorder(oldToNew, slaves); - - // 2) in each block of primary sort by secondary - - // Reset map. Elements that are not sorted will retain their -1 - // value, which will mean that they are ignored by inplaceReorder - - oldToNew = -1; - - label blockStart = 0; - - for (label i = 1; i < primary.size(); i++) - { - label blockLength = -1; - - if (primary[i] > primary[i - 1]) - { - blockLength = i - blockStart; - } - else if (i == primary.size() - 1) - { - // If the last element is not a jump in index, then it - // needs to trigger a sort of the last block, but with a - // block length that is one element longer so that it - // sorts itself. - - // If it is a jump in index, then it will form a block of - // length one, and so will not need sorted. - - blockLength = i - blockStart + 1; - } - - if (blockLength >= 1) - { - labelList blockIndices = identity(blockLength) + blockStart; - - SubList<label> secondaryBlock - ( - secondary, - blockLength, - blockStart - ); - - sortedOrder(secondaryBlock, blockIndices); - - blockIndices = invert(blockIndices.size(), blockIndices); - - forAll(blockIndices, b) - { - oldToNew[blockStart + b] = blockIndices[b] + blockStart; - } - - blockStart = i; - } - } - + inplaceReorder(oldToNew, sortingIndices); inplaceReorder(oldToNew, faces); inplaceReorder(oldToNew, owner); inplaceReorder(oldToNew, slaves); @@ -3051,8 +2388,10 @@ void Foam::conformalVoronoiMesh::addPatches labelList& owner, labelList& patchSizes, labelList& patchStarts, + PackedBoolList& boundaryFacesToRemove, const List<DynamicList<face> >& patchFaces, - const List<DynamicList<label> >& patchOwners + const List<DynamicList<label> >& patchOwners, + const List<DynamicList<bool> >& indirectPatchFace ) const { label nPatches = patchFaces.size(); @@ -3081,6 +2420,7 @@ void Foam::conformalVoronoiMesh::addPatches { faces[faceI] = patchFaces[p][f]; owner[faceI] = patchOwners[p][f]; + boundaryFacesToRemove[faceI] = indirectPatchFace[p][f]; faceI++; } @@ -3091,7 +2431,8 @@ void Foam::conformalVoronoiMesh::addPatches void Foam::conformalVoronoiMesh::removeUnusedPoints ( faceList& faces, - pointField& pts + pointField& pts, + labelList& boundaryPts ) const { Info<< nl << "Removing unused points" << endl; @@ -3126,6 +2467,7 @@ void Foam::conformalVoronoiMesh::removeUnusedPoints } inplaceReorder(oldToNew, pts); + inplaceReorder(oldToNew, boundaryPts); Info<< " Removing " << returnReduce(pts.size() - pointI, sumOp<label>()) @@ -3133,6 +2475,7 @@ void Foam::conformalVoronoiMesh::removeUnusedPoints << endl; pts.setSize(pointI); + boundaryPts.setSize(pointI); // Renumber the faces to use the new point numbers @@ -3198,8 +2541,9 @@ Foam::labelList Foam::conformalVoronoiMesh::removeUnusedCells if (unusedCells.size() > 0) { - // Pout<< "Removing " << unusedCells.size() << " unused cell labels" - // << endl; + Info<< " Removing " + << returnReduce(unusedCells.size(), sumOp<label>()) + << " unused cell labels" << endl; forAll(owner, oI) { diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C index 2d850aff09f..14c5428c816 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshConformToSurface.C @@ -26,6 +26,8 @@ License #include "conformalVoronoiMesh.H" #include "backgroundMeshDecomposition.H" #include "vectorTools.H" +#include "indexedCellChecks.H" +#include "IOmanip.H" using namespace Foam::vectorTools; @@ -35,34 +37,44 @@ const Foam::scalar Foam::conformalVoronoiMesh::searchConeAngle const Foam::scalar Foam::conformalVoronoiMesh::searchAngleOppositeSurface = Foam::cos(degToRad(150)); + // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // void Foam::conformalVoronoiMesh::conformToSurface() { - reconformationMode reconfMode = reconformationControl(); - -// if (Pstream::parRun()) -// { -// seedProcessorBoundarySurfaces(true); -// } + this->resetCellCount(); + // Index the cells + for + ( + Delaunay::Finite_cells_iterator cit = finite_cells_begin(); + cit != finite_cells_end(); + ++cit + ) + { + cit->cellIndex() = Cb::ctUnassigned; + } - if (reconfMode == rmNone) + if (reconformationControl() == rmOff) { // Reinsert stored surface conformation reinsertSurfaceConformation(); - buildParallelInterface("move_" + runTime_.timeName()); + if (Pstream::parRun()) + { + sync(decomposition_().procBounds()); + } } else { // Rebuild, insert and store new surface conformation - buildSurfaceConformation(reconfMode); + buildSurfaceConformation(); if (distributeBackground()) { - // distributeBackground has destroyed all referred vertices, so the - // parallel interface needs to be rebuilt. - buildParallelInterface("rebuild"); + if (Pstream::parRun()) + { + sync(decomposition_().procBounds()); + } // Use storeSizesAndAlignments with no feed points because all // background points may have been distributed. @@ -74,16 +86,6 @@ void Foam::conformalVoronoiMesh::conformToSurface() storeSurfaceConformation(); } -// if (Pstream::parRun()) -// { -// label nFarPoints = removeProcessorBoundarySeeds(true); -// -// reduce(nFarPoints, sumOp<label>()); -// -// Info<< " Removed " << nFarPoints -// << " far points from the mesh." << endl; -// } - // reportSurfaceConformationQuality(); } @@ -91,47 +93,143 @@ void Foam::conformalVoronoiMesh::conformToSurface() Foam::conformalVoronoiMesh::reconformationMode Foam::conformalVoronoiMesh::reconformationControl() const { - if (!runTime_.run()) - { - Info<< nl << "Rebuilding surface conformation for final output" - << endl; - - return rmFine; - } - else if + if ( runTime_.timeIndex() % cvMeshControls().surfaceConformationRebuildFrequency() == 0 ) { - Info<< nl << "Rebuilding surface conformation for more iterations" - << endl; - - return rmCoarse; + return rmOn; } - return rmNone; + return rmOff; } -void Foam::conformalVoronoiMesh::buildSurfaceConformation -( - reconformationMode reconfMode -) +// @todo Investigate topological tests +Foam::label Foam::conformalVoronoiMesh::findVerticesNearBoundaries() { - timeCheck("Start buildSurfaceConformation"); + label countNearBoundaryVertices = 0; - if (reconfMode == rmCoarse) + for + ( + Delaunay::Finite_facets_iterator fit = finite_facets_begin(); + fit != finite_facets_end(); + ++fit + ) { - Info<< nl << "Build coarse surface conformation" << endl; + if + ( + is_infinite(fit->first) + || is_infinite(fit->first->neighbor(fit->second)) + ) + { + continue; + } + + Cell_handle c1 = fit->first; + Cell_handle c2 = fit->first->neighbor(fit->second); + + pointFromPoint dE0 = c1->dual(); + pointFromPoint dE1 = c2->dual(); + + if (!geometryToConformTo_.findSurfaceAnyIntersection(dE0, dE1)) + { + continue; + } + + for (label cellI = 0; cellI < 4; ++cellI) + { + Vertex_handle v = c1->vertex(cellI); + + if + ( + !is_infinite(v) + && v->internalPoint() + && fit->second != cellI + ) + { + v->setNearBoundary(); + } + } + + for (label cellI = 0; cellI < 4; ++cellI) + { + Vertex_handle v = c2->vertex(cellI); + + if + ( + !is_infinite(v) + && v->internalPoint() + && fit->second != cellI + ) + { + v->setNearBoundary(); + } + } } - else if (reconfMode == rmFine) + + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) { - Info<< nl << "Build fine surface conformation" << endl; + if (vit->nearBoundary()) + { + countNearBoundaryVertices++; + } } - else if (reconfMode == rmNone) + + // Geometric test. +// for +// ( +// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +// vit != finite_vertices_end(); +// ++vit +// ) +// { +// if (vit->internalPoint() && !vit->nearBoundary()) +// { +// pointFromPoint pt = topoint(vit->point()); +// +// const scalar range = sqr +// ( +// cvMeshControls().nearBoundaryDistanceCoeff() +// *targetCellSize(pt) +// ); +// +// pointIndexHit pHit; +// label hitSurface; +// +// geometryToConformTo_.findSurfaceNearest +// ( +// pt, +// range, +// pHit, +// hitSurface +// ); +// +// if (pHit.hit()) +// { +// vit->setNearBoundary(); +// countNearBoundaryVertices++; +// } +// } +// } + + return countNearBoundaryVertices; +} + + +void Foam::conformalVoronoiMesh::buildSurfaceConformation() +{ + timeCheck("Start buildSurfaceConformation"); + + if (reconformationControl() == rmOff) { - WarningIn("buildSurfaceConformation(reconformationMode reconfMode)") + WarningIn("buildSurfaceConformation()") << "reconformationMode rmNone specified, not building conformation" << endl; @@ -139,21 +237,15 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation } else { - WarningIn("buildSurfaceConformation(reconformationMode reconfMode)") - << "Unknown reconformationMode " << reconfMode - << " not building conformation" << endl; - - return; + Info<< nl << "Rebuilding surface conformation for more iterations" + << endl; } - // Initialise containers to store the edge conformation locations - DynamicList<Foam::point> newEdgeLocations; - - DynamicList<Foam::point> existingEdgeLocations; - DynamicList<Foam::point> existingSurfacePtLocations; + existingEdgeLocations_.clearStorage(); + existingSurfacePtLocations_.clearStorage(); - buildEdgeLocationTree(existingEdgeLocations); - buildSurfacePtLocationTree(existingSurfacePtLocations); + buildEdgeLocationTree(existingEdgeLocations_); + buildSurfacePtLocationTree(existingSurfacePtLocations_); label initialTotalHits = 0; @@ -177,7 +269,7 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation // -------- // // Shoot ray and find intersection with outside segment (x) and - // introduce pointpair (..) + // introduce point pair (..) // // | // \ . / @@ -185,57 +277,27 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation // \ . / // ---x---- - label countNearBoundaryVertices = 0; - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ - ) - { - if (vit->internalPoint() && !vit->nearBoundary()) - { - pointFromPoint pt = topoint(vit->point()); - const scalar range = sqr(2.0*targetCellSize(pt)); - - pointIndexHit pHit; - label hitSurface; - - geometryToConformTo_.findSurfaceNearest - ( - pt, - range, - pHit, - hitSurface - ); - - if (pHit.hit()) - { - vit->setNearBoundary(); - countNearBoundaryVertices++; - } - } - } + // Find vertices near boundaries to speed up subsequent checks. + label countNearBoundaryVertices = findVerticesNearBoundaries(); Info<< " Vertices marked as being near a boundary: " - << countNearBoundaryVertices << " (estimated)" << endl; + << returnReduce(countNearBoundaryVertices, sumOp<label>()) + << " (estimated)" << endl; timeCheck("After set near boundary"); - // Initial surface protrusion conformation - nearest surface point - { - const scalar edgeSearchDistCoeffSqr = - cvMeshControls().edgeSearchDistCoeffSqrInitial(reconfMode); + const scalar edgeSearchDistCoeffSqr = + cvMeshControls().edgeSearchDistCoeffSqr(); - const scalar surfacePtReplaceDistCoeffSqr = - cvMeshControls().surfacePtReplaceDistCoeffSqrInitial(reconfMode); + const scalar surfacePtReplaceDistCoeffSqr = + cvMeshControls().surfacePtReplaceDistCoeffSqr(); - DynamicList<pointIndexHit> surfaceHits; - DynamicList<label> hitSurfaces; + const label AtoV = label(6/Foam::pow(scalar(number_of_vertices()), 3)); - DynamicList<pointIndexHit> featureEdgeHits; - DynamicList<label> featureEdgeFeaturesHit; + // Initial surface protrusion conformation - nearest surface point + { + pointIndexHitAndFeatureDynList featureEdgeHits(AtoV/4); + pointIndexHitAndFeatureDynList surfaceHits(AtoV); for ( @@ -244,25 +306,16 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation vit++ ) { - if (vit->internalPoint() && vit->nearBoundary()) + if (vit->nearBoundary()) { - const Foam::point vert = topoint(vit->point()); - - if (!positionOnThisProc(vert)) - { - continue; - } - - DynamicList<pointIndexHit> surfHitList; - DynamicList<label> hitSurfaceList; + pointIndexHitAndFeatureDynList surfaceIntersections(AtoV); if ( dualCellSurfaceAllIntersections ( vit, - surfHitList, - hitSurfaceList + surfaceIntersections ) ) { @@ -273,18 +326,11 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation addSurfaceAndEdgeHits ( vit, - vert, - surfHitList, - hitSurfaceList, + surfaceIntersections, surfacePtReplaceDistCoeffSqr, edgeSearchDistCoeffSqr, surfaceHits, - hitSurfaces, - featureEdgeHits, - featureEdgeFeaturesHit, - newEdgeLocations, - existingEdgeLocations, - existingSurfacePtLocations + featureEdgeHits ); } else @@ -296,7 +342,7 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation } Info<< " Vertices marked as being near a boundary: " - << countNearBoundaryVertices + << returnReduce(countNearBoundaryVertices, sumOp<label>()) << " (after dual surface intersection)" << endl; label nVerts = number_of_vertices(); @@ -316,17 +362,27 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation << " Number of edge hits " << nFeatEdHits << endl; + // In parallel, synchronise the surface trees + if (Pstream::parRun()) + { + synchroniseSurfaceTrees(surfaceHits); + } + insertSurfacePointPairs ( surfaceHits, - hitSurfaces, "surfaceConformationLocations_initial.obj" ); + // In parallel, synchronise the edge trees + if (Pstream::parRun()) + { + synchroniseEdgeTrees(featureEdgeHits); + } + insertEdgePointGroups ( featureEdgeHits, - featureEdgeFeaturesHit, "edgeConformationLocations_initial.obj" ); @@ -337,32 +393,56 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation // Remember which vertices were referred to each processor so only updates // are sent. - List<labelHashSet> referralVertices(Pstream::nProcs()); + PtrList<labelPairHashSet> referralVertices(Pstream::nProcs()); // Store the vertices that have been received and added from each processor // already so that there is no attempt to add them more than once. - List<labelHashSet> receivedVertices(Pstream::nProcs()); + autoPtr<labelPairHashSet> receivedVertices; + + if (Pstream::parRun()) + { + forAll(referralVertices, procI) + { + if (procI != Pstream::myProcNo()) + { + referralVertices.set + ( + procI, + new labelPairHashSet(number_of_vertices()/Pstream::nProcs()) + ); + } + } + + receivedVertices.set + ( + new labelPairHashSet(number_of_vertices()/Pstream::nProcs()) + ); - // Build the parallel interface the initial surface conformation - buildParallelInterface(referralVertices, receivedVertices, true, "initial"); + // Build the parallel interface the initial surface conformation + sync + ( + decomposition_().procBounds(), + referralVertices, + receivedVertices() + ); + } label iterationNo = 0; - label maxIterations = - cvMeshControls().maxConformationIterations(reconfMode); + label maxIterations = cvMeshControls().maxConformationIterations(); scalar iterationToInitialHitRatioLimit = - cvMeshControls().iterationToInitialHitRatioLimit(reconfMode); + cvMeshControls().iterationToInitialHitRatioLimit(); label hitLimit = label(iterationToInitialHitRatioLimit*initialTotalHits); Info<< nl << "Stopping iterations when: " << nl - <<" total number of hits drops below " - << iterationToInitialHitRatioLimit << " of initial hits (" - << hitLimit << ")" << nl + << " total number of hits drops below " + << iterationToInitialHitRatioLimit + << " of initial hits (" << hitLimit << ")" << nl << " or " << nl - << " maximum number of iterations (" - << maxIterations << ") is reached" + << " maximum number of iterations (" << maxIterations + << ") is reached" << endl; // Set totalHits to a large enough positive value to enter the while loop on @@ -376,17 +456,8 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation && iterationNo < maxIterations ) { - scalar edgeSearchDistCoeffSqr = - cvMeshControls().edgeSearchDistCoeffSqrIteration(reconfMode); - - scalar surfacePtReplaceDistCoeffSqr = - cvMeshControls().surfacePtReplaceDistCoeffSqrIteration(reconfMode); - - DynamicList<pointIndexHit> surfaceHits; - DynamicList<label> hitSurfaces; - - DynamicList<pointIndexHit> featureEdgeHits; - DynamicList<label> featureEdgeFeaturesHit; + pointIndexHitAndFeatureDynList surfaceHits(0.5*AtoV); + pointIndexHitAndFeatureDynList featureEdgeHits(0.25*AtoV); for ( @@ -402,11 +473,11 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation if ( vit->nearBoundary() - || vit->ppMaster() - || vit->referredInternalOrBoundaryPoint() + || vit->internalBoundaryPoint() + || (vit->internalOrBoundaryPoint() && vit->referred()) ) { - const Foam::point vert = topoint(vit->point()); + pointIndexHitAndFeatureDynList surfaceIntersections(0.5*AtoV); pointIndexHit surfHit; label hitSurface; @@ -417,37 +488,34 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation if (surfHit.hit()) { - DynamicList<pointIndexHit> tmpPIH; - tmpPIH.append(surfHit); - - DynamicList<label> tmpHS; - tmpHS.append(hitSurface); + surfaceIntersections.append + ( + pointIndexHitAndFeature(surfHit, hitSurface) + ); addSurfaceAndEdgeHits ( vit, - vert, - tmpPIH, - tmpHS, + surfaceIntersections, surfacePtReplaceDistCoeffSqr, edgeSearchDistCoeffSqr, surfaceHits, - hitSurfaces, - featureEdgeHits, - featureEdgeFeaturesHit, - newEdgeLocations, - existingEdgeLocations, - existingSurfacePtLocations + featureEdgeHits ); } -// else -// { -// vit->setInternal(); -// } + else + { + // No surface hit detected so if internal then don't check + // again + if (vit->nearBoundary()) + { + vit->setInternal(); + } + } } - else if (vit->ppSlave() || vit->referredExternal()) + else if (vit->externalBoundaryPoint()) { - const Foam::point vert = topoint(vit->point()); + pointIndexHitAndFeatureDynList surfaceIntersections(0.5*AtoV); pointIndexHit surfHit; label hitSurface; @@ -458,33 +526,21 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation if (surfHit.hit()) { - DynamicList<pointIndexHit> tmpPIH; - tmpPIH.append(surfHit); - - DynamicList<label> tmpHS; - tmpHS.append(hitSurface); + surfaceIntersections.append + ( + pointIndexHitAndFeature(surfHit, hitSurface) + ); addSurfaceAndEdgeHits ( vit, - vert, - tmpPIH, - tmpHS, + surfaceIntersections, surfacePtReplaceDistCoeffSqr, edgeSearchDistCoeffSqr, surfaceHits, - hitSurfaces, - featureEdgeHits, - featureEdgeFeaturesHit, - newEdgeLocations, - existingEdgeLocations, - existingSurfacePtLocations + featureEdgeHits ); } -// else -// { -// vit->setInternal(); -// } } } @@ -507,41 +563,47 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation totalHits = nSurfHits + nFeatEdHits; + label nNotInserted = 0; + if (totalHits > 0) { + // In parallel, synchronise the surface trees + if (Pstream::parRun()) + { + nNotInserted += synchroniseSurfaceTrees(surfaceHits); + } + insertSurfacePointPairs ( surfaceHits, - hitSurfaces, - fileName - ( - "surfaceConformationLocations_" + name(iterationNo) + ".obj" - ) + "surfaceConformationLocations_" + name(iterationNo) + ".obj" ); + // In parallel, synchronise the edge trees + if (Pstream::parRun()) + { + nNotInserted += synchroniseEdgeTrees(featureEdgeHits); + } + insertEdgePointGroups ( featureEdgeHits, - featureEdgeFeaturesHit, "edgeConformationLocations_" + name(iterationNo) + ".obj" ); + + if (Pstream::parRun()) + { + sync + ( + decomposition_().procBounds(), + referralVertices, + receivedVertices() + ); + } } timeCheck("Conformation iteration " + name(iterationNo)); - // Only need to update the interface if there are surface/edge hits - if (totalHits > 0) - { - // Update the parallel interface - buildParallelInterface - ( - referralVertices, - receivedVertices, - false, - name(iterationNo) - ); - } - iterationNo++; if (iterationNo == maxIterations) @@ -551,6 +613,14 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation << maxIterations << ") reached." << endl; } + if (totalHits <= nNotInserted) + { + Info<< nl << "Total hits (" << totalHits + << ") less than number of failed insertions (" << nNotInserted + << "), stopping iterations" << endl; + break; + } + if (totalHits < hitLimit) { Info<< nl << "Total hits (" << totalHits @@ -558,76 +628,286 @@ void Foam::conformalVoronoiMesh::buildSurfaceConformation << "), stopping iterations" << endl; } } + + edgeLocationTreePtr_.clear(); + surfacePtLocationTreePtr_.clear(); } -bool Foam::conformalVoronoiMesh::dualCellSurfaceAnyIntersection +Foam::label Foam::conformalVoronoiMesh::synchroniseSurfaceTrees ( - const Delaunay::Finite_vertices_iterator& vit -) const + pointIndexHitAndFeatureList& surfaceHits +) { - std::list<Facet> facets; - incident_facets(vit, std::back_inserter(facets)); + Info<< " Surface tree synchronisation" << endl; - for + pointIndexHitAndFeatureDynList synchronisedSurfLocations ( - std::list<Facet>::iterator fit=facets.begin(); - fit != facets.end(); - ++fit - ) + surfaceHits.size() + ); + + List<pointIndexHitAndFeatureDynList> procSurfLocations(Pstream::nProcs()); + + procSurfLocations[Pstream::myProcNo()] = surfaceHits; + + Pstream::gatherList(procSurfLocations); + Pstream::scatterList(procSurfLocations); + + List<labelHashSet> hits(Pstream::nProcs()); + + label nStoppedInsertion = 0; + + // Do the nearness tests here + for (label procI = 0; procI < Pstream::nProcs(); ++procI) { - if - ( - is_infinite(fit->first) - || is_infinite(fit->first->neighbor(fit->second)) - ) + // Skip own points + if (procI >= Pstream::myProcNo()) { continue; } - Foam::point dE0 = fit->first->dual(); - Foam::point dE1 = fit->first->neighbor(fit->second)->dual(); + const pointIndexHitAndFeatureList& otherSurfEdges = + procSurfLocations[procI]; - if (Pstream::parRun()) + forAll(otherSurfEdges, peI) { - Foam::point& a = dE0; - Foam::point& b = dE1; + const Foam::point& pt = otherSurfEdges[peI].first().hitPoint(); - bool inProc = clipLineToProc(topoint(vit->point()), a, b); + pointIndexHit nearest; + pointIsNearSurfaceLocation(pt, nearest); - // Check for the edge passing through a surface - if - ( - inProc - && geometryToConformTo_.findSurfaceAnyIntersection(a, b) - ) + pointIndexHit nearestEdge; + pointIsNearFeatureEdgeLocation(pt, nearestEdge); + + bool isNearFeaturePt = nearFeaturePt(pt); + + if (nearest.hit() || nearestEdge.hit() || isNearFeaturePt) { - // Pout<< "# findSurfaceAnyIntersection" << endl; - // meshTools::writeOBJ(Pout, a); - // meshTools::writeOBJ(Pout, b); - // Pout<< "l cr0 cr1" << endl; + nStoppedInsertion++; - return true; + if (!hits[procI].found(peI)) + { + hits[procI].insert(peI); + } } } - else + } + + Pstream::listCombineGather(hits, plusEqOp<labelHashSet>()); + Pstream::listCombineScatter(hits); + + forAll(surfaceHits, eI) + { + if (!hits[Pstream::myProcNo()].found(eI)) { - if (geometryToConformTo_.findSurfaceAnyIntersection(dE0, dE1)) - { - return true; - } + synchronisedSurfLocations.append(surfaceHits[eI]); } } - return false; + forAll(synchronisedSurfLocations, pI) + { + appendToSurfacePtTree + ( + synchronisedSurfLocations[pI].first().hitPoint() + ); + } + + const label nNotInserted = returnReduce(nStoppedInsertion, sumOp<label>()); + + Info<< " Not inserting total of " << nNotInserted << " locations" + << endl; + + surfaceHits = synchronisedSurfLocations; + + return nNotInserted; +} + + +Foam::label Foam::conformalVoronoiMesh::synchroniseEdgeTrees +( + pointIndexHitAndFeatureList& featureEdgeHits +) +{ + Info<< " Edge tree synchronisation" << endl; + + pointIndexHitAndFeatureDynList synchronisedEdgeLocations + ( + featureEdgeHits.size() + ); + + List<pointIndexHitAndFeatureDynList> procEdgeLocations(Pstream::nProcs()); + + procEdgeLocations[Pstream::myProcNo()] = featureEdgeHits; + + Pstream::gatherList(procEdgeLocations); + Pstream::scatterList(procEdgeLocations); + + List<labelHashSet> hits(Pstream::nProcs()); + + label nStoppedInsertion = 0; + + // Do the nearness tests here + for (label procI = 0; procI < Pstream::nProcs(); ++procI) + { + // Skip own points + if (procI >= Pstream::myProcNo()) + { + continue; + } + + pointIndexHitAndFeatureList& otherProcEdges = procEdgeLocations[procI]; + + forAll(otherProcEdges, peI) + { + const Foam::point& pt = otherProcEdges[peI].first().hitPoint(); + + pointIndexHit nearest; + pointIsNearFeatureEdgeLocation(pt, nearest); + + bool isNearFeaturePt = nearFeaturePt(pt); + + if (nearest.hit() || isNearFeaturePt) + { + nStoppedInsertion++; + + if (!hits[procI].found(peI)) + { + hits[procI].insert(peI); + } + } + } + } + + Pstream::listCombineGather(hits, plusEqOp<labelHashSet>()); + Pstream::listCombineScatter(hits); + + forAll(featureEdgeHits, eI) + { + if (!hits[Pstream::myProcNo()].found(eI)) + { + synchronisedEdgeLocations.append(featureEdgeHits[eI]); + } + } + + forAll(synchronisedEdgeLocations, pI) + { + appendToEdgeLocationTree + ( + synchronisedEdgeLocations[pI].first().hitPoint() + ); + } + + const label nNotInserted = returnReduce(nStoppedInsertion, sumOp<label>()); + + Info<< " Not inserting total of " << nNotInserted << " locations" + << endl; + + featureEdgeHits = synchronisedEdgeLocations; + + return nNotInserted; +} + + +bool Foam::conformalVoronoiMesh::locationConformsToInside +( + const pointIndexHitAndFeature& info +) const +{ + bool keepLocation = true; + + if (info.first().hit()) + { + vectorField norm(1); + + allGeometry_[info.second()].getNormal + ( + List<pointIndexHit>(1, info.first()), + norm + ); + + const vector& n = norm[0]; + + const scalar ppDist = pointPairDistance(info.first().hitPoint()); + + const Foam::point innerPoint = info.first().hitPoint() - ppDist*n; + + if (!geometryToConformTo_.inside(innerPoint)) + { + keepLocation = false; + } + } + else + { + keepLocation = false; + } + + return keepLocation; +} + + +bool Foam::conformalVoronoiMesh::dualCellSurfaceAnyIntersection +( + const Delaunay::Finite_vertices_iterator& vit +) const +{ + std::list<Facet> facets; + incident_facets(vit, std::back_inserter(facets)); + + for + ( + std::list<Facet>::iterator fit=facets.begin(); + fit != facets.end(); + ++fit + ) + { + if + ( + is_infinite(fit->first) + || is_infinite(fit->first->neighbor(fit->second)) + || !fit->first->hasInternalPoint() + || !fit->first->neighbor(fit->second)->hasInternalPoint() + ) + { + continue; + } + + Foam::point dE0 = fit->first->dual(); + Foam::point dE1 = fit->first->neighbor(fit->second)->dual(); + + if (Pstream::parRun()) + { + Foam::point& a = dE0; + Foam::point& b = dE1; + + bool inProc = clipLineToProc(topoint(vit->point()), a, b); + + // Check for the edge passing through a surface + if + ( + inProc + && geometryToConformTo_.findSurfaceAnyIntersection(a, b) + ) + { + return true; + } + } + else + { + if (geometryToConformTo_.findSurfaceAnyIntersection(dE0, dE1)) + { + return true; + } + } + } + + return false; } bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections ( const Delaunay::Finite_vertices_iterator& vit, - DynamicList<pointIndexHit>& infoList, - DynamicList<label>& hitSurfaceList + pointIndexHitAndFeatureDynList& infoList ) const { bool flagIntersection = false; @@ -646,6 +926,10 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections ( is_infinite(fit->first) || is_infinite(fit->first->neighbor(fit->second)) + || !fit->first->hasInternalPoint() + || !fit->first->neighbor(fit->second)->hasInternalPoint() +// || fit->first->hasFarPoint() +// || fit->first->neighbor(fit->second)->hasFarPoint() ) { continue; @@ -689,7 +973,7 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections const vector& n = norm[0]; - const Foam::point vertex = topoint(vit->point()); + pointFromPoint vertex = topoint(vit->point()); const plane p(infoIntersection.hitPoint(), n); @@ -699,36 +983,45 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections const Foam::point newPoint = vertex + d*n; - pointIndexHit info; - label hitSurface = -1; + pointIndexHitAndFeature info; geometryToConformTo_.findSurfaceNearest ( newPoint, surfaceSearchDistanceSqr(newPoint), - info, - hitSurface + info.first(), + info.second() ); bool rejectPoint = false; - if (info.hit()) + if (!locationConformsToInside(info)) + { + rejectPoint = true; + } + + if (!rejectPoint && info.first().hit()) { if (!infoList.empty()) { forAll(infoList, hitI) { // Reject point if the point is already added - if (infoList[hitI].index() == info.index()) + if + ( + infoList[hitI].first().index() + == info.first().index() + ) { rejectPoint = true; break; } - const Foam::point& p = infoList[hitI].hitPoint(); + const Foam::point& p + = infoList[hitI].first().hitPoint(); const scalar separationDistance = - mag(p - info.hitPoint()); + mag(p - info.first().hitPoint()); const scalar minSepDist = sqr @@ -751,1059 +1044,59 @@ bool Foam::conformalVoronoiMesh::dualCellSurfaceAllIntersections // The normal ray from the vertex will not always result in a hit // because another surface may be in the way. - if (!rejectPoint && info.hit()) + if (!rejectPoint && info.first().hit()) { flagIntersection = true; infoList.append(info); - hitSurfaceList.append(hitSurface); } } } - return flagIntersection; -} - - -bool Foam::conformalVoronoiMesh::clipLineToProc -( - const Foam::point& pt, - Foam::point& a, - Foam::point& b -) const -{ - bool inProc = false; - - pointIndexHit findAnyIntersection = decomposition_().findLine(a, b); - - if (!findAnyIntersection.hit()) - { - pointIndexHit info = decomposition_().findLine(a, pt); - - if (!info.hit()) - { - inProc = true; - } - else - { - inProc = false; - } - } - else - { - pointIndexHit info = decomposition_().findLine(a, pt); - - if (!info.hit()) - { - inProc = true; - b = findAnyIntersection.hitPoint(); - } - else - { - inProc = true; - a = findAnyIntersection.hitPoint(); - } - } - - return inProc; -} - - -void Foam::conformalVoronoiMesh::buildParallelInterface -( - const word& outputName -) -{ - List<labelHashSet> referralVertices(Pstream::nProcs()); - List<labelHashSet> receivedVertices(Pstream::nProcs()); - - buildParallelInterface - ( - referralVertices, - receivedVertices, - true, - outputName - ); -} - - -Foam::label Foam::conformalVoronoiMesh::removeProcessorBoundarySeeds -( - bool reinsertBoundPts -) -{ - label nFarPoints = 0; - - - - std::list<Vertex_handle> toRemove; - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - ++vit - ) - { - if (vit->farPoint()) - { - //remove(vit); - toRemove.push_back(vit); - nFarPoints++; - } - } - - // This function removes the points in the iterator range and then - // retriangulates. - timeCheck("Start Removing Seeded Points " + name(toRemove.size())); - - remove_cluster(toRemove.begin(), toRemove.end()); - - - // Need to do this to make sure the triangulation is well-behaved - if (reinsertBoundPts) - { - reinsertBoundingPoints(); - } - - - -// DynamicList<Foam::point> toAdd; -// DynamicList<label> indices; -// DynamicList<label> types; -// -// for -// ( -// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); -// vit != finite_vertices_end(); -// ++vit -// ) -// { -// if (!vit->farPoint()) -// { -// toAdd.append(topoint(vit->point())); -// indices.append(vit->index()); -// types.append(vit->type()); -// -// nFarPoints++; -// } -// } -// -// this->clear(); -// -// // Need to do this to make sure the triangulation is well-behaved -// if (reinsertBoundPts) -// { -// reinsertBoundingPoints(); -// } -// -// forAll(toAdd, pI) -// { -// insertPoint(toAdd[pI], indices[pI], types[pI]); -// } - - - timeCheck("End Removing Seeded Points"); - - return nFarPoints; -} - - -void Foam::conformalVoronoiMesh::seedProcessorBoundarySurfaces -( - bool seedProcessors -) -{ - //removeProcessorBoundarySeeds(false); - - // Loop over processor patch faces and insert a point in the centre of the - // face - const fvMesh& mesh = decomposition_().mesh(); - const polyBoundaryMesh& bMesh = mesh.boundaryMesh(); - - DynamicList<Foam::point> pts; - DynamicList<label> indices; - DynamicList<label> types; - - label nFarPoints = 0; - - const scalar normalDistance = 2.0; - const scalar pert = 0.1*(rndGen_.scalar01() - 0.5); - - forAll(bMesh, patchI) - { - const polyPatch& patch = bMesh[patchI]; - - if (!seedProcessors && isA<processorPolyPatch>(patch)) - { - continue; - } - - forAll(patch, faceI) - { - if (faceI % 1 == 0) - { - const face& f = patch[faceI]; - - pts.append - ( - f.centre(mesh.points()) - + pert*normalDistance*f.normal(mesh.points()) - ); - indices.append(nFarPoints++); - types.append(Vb::vtFar); - } - } - } - - insertPoints(pts, indices, types, false); - - reduce(nFarPoints, sumOp<label>()); - - Info<< " Inserted " << nFarPoints - << " far points into the mesh." << endl; -} - - -void Foam::conformalVoronoiMesh::buildParallelInterface -( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - bool initialEdgeReferral, - const word& outputName -) -{ - if (!Pstream::parRun()) - { - return; - } - - Info<< nl << "Parallel interface construction" << endl; - - timeCheck("Before buildParallelInterface"); - - // Hard coded switch, can be turned on for testing and debugging purposes - - // all vertices will be referred to all processors, use with caution for - // big cases. - bool allPointReferral = false; - - if (allPointReferral) - { - buildParallelInterfaceAll - ( - referralVertices, - receivedVertices, - outputName - ); - - timeCheck("After buildParallelInterfaceAll"); - } - - - // Reject points that are not near the boundary from the subsequent - // searches - -// label nearProcCount = 0; -// label notNearProcCount = 0; -// boundBox quickRejectionBox(decomposition_().procBounds()); -// -//// Pout<< "Processor boundBox: " << quickRejectionBox << endl; -// -// quickRejectionBox.inflate(-0.1); -// -// OFstream str("rejectionBox_" + name(Pstream::myProcNo()) + ".obj"); -// -// meshTools::writeOBJ -// ( -// str, -// boundBox::faces(), -// quickRejectionBox.points() -// ); -// -// Pout<< "Inflated rejection boundBox: " << quickRejectionBox << endl; - -// for -// ( -// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); -// vit != finite_vertices_end(); -// vit++ -// ) -// { -// if (vit->real() && !vit->nearProcBoundary()) -// { -// const Foam::point& pt = topoint(vit->point()); -// const scalar range = targetCellSize(pt); -// -//// if -//// ( -//// decomposition_().overlapsThisProcessor -//// ( -//// pt, -//// range -//// ) -//// ) -// if (!quickRejectionBox.contains(pt)) -// { -// vit->setNearProcBoundary(); -// nearProcCount++; -// } -// else -// { -// //vit->setNearProcBoundary(); -// notNearProcCount++; -// } -// } -// } -// -// reduce(nearProcCount, sumOp<label>()); -// reduce(notNearProcCount, sumOp<label>()); -// -// timeCheck -// ( -// "End of potential intersection search. " -// + name(nearProcCount) + " are near a processor boundary. " -// + name(notNearProcCount) + " are not." -// ); - -// if (initialEdgeReferral) -// { -// // Used as an initial pass to localise the vertex referring - find -// // vertices whose dual edges pierce nearby processor volumes and refer -// // them to establish a sensible boundary interface region before -// // running a circumsphere assessment. -// -// buildParallelInterfaceIntersection -// ( -// referralVertices, -// receivedVertices, -// outputName -// ); -// -// timeCheck("After buildParallelInterfaceIntersection"); -// } - - buildParallelInterfaceInfluence - ( - referralVertices, - receivedVertices, - outputName - ); - - timeCheck("After buildParallelInterface"); - - // Check all referred vertices are actually used on the processor. - label nUnusedReferred = numberOfUnusedReferredPoints(); - - reduce(nUnusedReferred, sumOp<label>()); - - Info<< " Number of referred points that are not used : " - << nUnusedReferred << " (approximate)" << endl; -} - - -Foam::label Foam::conformalVoronoiMesh::numberOfUnusedReferredPoints() const -{ - label nUnusedPoints = 0; - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - ++vit - ) - { - if (vit->referred()) - { - std::list<Vertex_handle> adjVertices; - finite_adjacent_vertices(vit, std::back_inserter(adjVertices)); - - bool isUsed = false; - - for - ( - std::list<Vertex_handle>::iterator adjVit = adjVertices.begin(); - adjVit != adjVertices.end(); - ++adjVit - ) - { - if ((*adjVit)->real()) - { - isUsed = true; - } - } - - if (!isUsed) - { - nUnusedPoints++; - } - } - } - - return nUnusedPoints; -} - - -void Foam::conformalVoronoiMesh::buildParallelInterfaceAll -( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName -) -{ - // Refer all points to all processors - - DynamicList<Foam::point> parallelAllPoints; - DynamicList<label> targetProcessor; - DynamicList<label> parallelAllIndices; - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - ++vit - ) - { - if (!vit->farPoint()) - { - for (label procI = 0; procI < Pstream::nProcs(); procI++) - { - if (procI == Pstream::myProcNo()) - { - continue; - } - - label vIndex = vit->index(); - - // Using the hashSet to ensure that each vertex is - // only referred once to each processor - if (!referralVertices[procI].found(vIndex)) - { - referralVertices[procI].insert(vIndex); - - parallelAllPoints.append - ( - topoint(vit->point()) - ); - - targetProcessor.append(procI); - - if (vit->internalOrBoundaryPoint()) - { - parallelAllIndices.append(vIndex); - } - else - { - parallelAllIndices.append(-vIndex); - } - } - } - } - } - - referVertices - ( - targetProcessor, - parallelAllPoints, - parallelAllIndices, - receivedVertices, - "all", - outputName - ); -} - -void Foam::conformalVoronoiMesh::buildParallelInterfaceIntersection -( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName -) -{ - DynamicList<Foam::point> parallelIntersectionPoints; - DynamicList<label> targetProcessor; - DynamicList<label> parallelIntersectionIndices; - - // End points of dual edges. Some of these values will not be used, - // i.e. for edges with non-real vertices. - DynamicList<Foam::point> dE0; - DynamicList<Foam::point> dE1; - - PackedBoolList testFacetIntersection(number_of_facets(), false); - - // Index outer (all) Delaunauy facets for whether they are potential - // intersections, index (inner) the list of tests an results. - label fIInner = 0; - label fIOuter = 0; - - for - ( - Delaunay::Finite_facets_iterator fit = finite_facets_begin(); - fit != finite_facets_end(); - ++fit - ) - { - const Cell_handle c1(fit->first); - const Cell_handle c2(c1->neighbor(fit->second)); - - // If either Delaunay cell at the end of the Dual edge is infinite, - // skip. - if - ( - !is_infinite(c1) && !is_infinite(c2) - ) - { - // The Delaunauy cells at either end of the dual edge need to be - // real, i.e. all vertices form part of the internal or boundary - // definition - if - ( - c1->internalOrBoundaryDualVertex() - && c2->internalOrBoundaryDualVertex() - ) - { - const Foam::point& a = c1->dual(); - const Foam::point& b = c2->dual(); - - // Only if the dual edge cuts the boundary of this processor is - // it going to be counted. - pointIndexHit info = decomposition_().findLineAny(a, b); - - if (info.hit()) - { - dE0.append(a); - dE1.append(b); - - testFacetIntersection[fIOuter] = true; - } - } - } - - fIOuter++; - } - - reduce(fIOuter, sumOp<label>()); - - timeCheck - ( - "End of actual intersection search over " - + name(fIOuter) - + " faces." - ); - - // Preform intersections in both directions, as there is no sense - // associated with the Dual edge - List<List<pointIndexHit> > intersectionForward(intersectsProc(dE0, dE1)); - List<List<pointIndexHit> > intersectionReverse(intersectsProc(dE1, dE0)); - - timeCheck("End of find processor intersection"); - - // Reset counter - fIOuter = 0; - - // Relying on the order of iteration of facets being the same as before - for - ( - Delaunay::Finite_facets_iterator fit = finite_facets_begin(); - fit != finite_facets_end(); - ++fit - ) - { - const Cell_handle c1(fit->first); - const Cell_handle c2(c1->neighbor(fit->second)); - - // Pre-tested facet intersection potential - if (testFacetIntersection[fIOuter]) - { - const Foam::point a = dE0[fIInner]; - const Foam::point b = dE1[fIInner]; - - scalar hitDistSqr = GREAT; - label closestHitProc = -1; - scalar closestHitDistSqr = GREAT; - - // Find the closest intersection with the other background meshes - // of the other processors in each direction, finding the closest. - forAll(intersectionForward[fIInner], iFI) - { - const pointIndexHit& info = intersectionForward[fIInner][iFI]; - - if (info.hit()) - { - // Line was a -> hit - hitDistSqr = magSqr(a - info.hitPoint()); - } - - if (hitDistSqr < closestHitDistSqr) - { - closestHitProc = info.index(); - closestHitDistSqr = hitDistSqr; - } - } - - forAll(intersectionReverse[fIInner], iRI) - { - const pointIndexHit& info = intersectionReverse[fIInner][iRI]; - - if (info.hit()) - { - // Line was b -> hit - hitDistSqr = magSqr(b - info.hitPoint()); - } - - if (hitDistSqr < closestHitDistSqr) - { - closestHitProc = info.index(); - closestHitDistSqr = hitDistSqr; - } - } - - if (closestHitProc >= 0) - { - // This dual edge pierces a processor, refer all vertices from - // both Delaunauy cells to it. - - for (int i = 0; i < 4; i++) - { - Vertex_handle v = c1->vertex(i); - - label vIndex = v->index(); - - if (v->farPoint() || v->referred()) - { - continue; - } - - // Using the hashSet to ensure that each vertex is only - // referred once to each processor - if (!referralVertices[closestHitProc].found(vIndex)) - { - referralVertices[closestHitProc].insert(vIndex); - - parallelIntersectionPoints.append(topoint(v->point())); - - targetProcessor.append(closestHitProc); - - if (v->internalOrBoundaryPoint()) - { - parallelIntersectionIndices.append(vIndex); - } - else - { - parallelIntersectionIndices.append(-vIndex); - } - - // Pout<< "Refer " - // << parallelIntersectionPoints.last() - // << " " << parallelIntersectionIndices.last() - // << " " << closestHitProc - // << endl; - } - } - - for (int i = 0; i < 4; i++) - { - Vertex_handle v = c2->vertex(i); - - label vIndex = v->index(); - - if (v->farPoint() || v->referred()) - { - continue; - } - - // Using the hashSet to ensure that each vertex is only - // referred once to each processor - if (!referralVertices[closestHitProc].found(vIndex)) - { - referralVertices[closestHitProc].insert(vIndex); - - parallelIntersectionPoints.append(topoint(v->point())); - - targetProcessor.append(closestHitProc); - - if (v->internalOrBoundaryPoint()) - { - parallelIntersectionIndices.append(vIndex); - } - else - { - parallelIntersectionIndices.append(-vIndex); - } - - // Pout<< "Refer " - // << parallelIntersectionPoints.last() - // << " " << parallelIntersectionIndices.last() - // << " " << closestHitProc - // << endl; - } - } - } - - fIInner++; - } - - fIOuter++; - } - - referVertices - ( - targetProcessor, - parallelIntersectionPoints, - parallelIntersectionIndices, - receivedVertices, - "intersection", - outputName - ); -} - - -void Foam::conformalVoronoiMesh::buildParallelInterfaceInfluence -( - List<labelHashSet>& referralVertices, - List<labelHashSet>& receivedVertices, - const word& outputName -) -{ - DynamicList<Foam::point> parallelInfluencePoints; - DynamicList<label> targetProcessor; - DynamicList<label> parallelInfluenceIndices; - - // Some of these values will not be used, i.e. for non-real cells - DynamicList<Foam::point> circumcentre; - DynamicList<scalar> circumradiusSqr; - - - // Index outer (all) Delaunauy cells for whether they are potential - // overlaps, index (inner) the list of tests an results. - label cIInner = 0; - label cIOuter = 0; - - seedProcessorBoundarySurfaces(true); - - label cellIndexCount = 0; - for - ( - Delaunay::Finite_cells_iterator cit = finite_cells_begin(); - cit != finite_cells_end(); - ++cit - ) - { - cit->cellIndex() = cellIndexCount++; - } - - - timeCheck("End of cell Indexing"); - - labelList testCellInfluence(number_of_cells(), 0); - - label nQuickRejections = 0; - - for - ( - Delaunay::Finite_cells_iterator cit = finite_cells_begin(); - cit != finite_cells_end(); - ++cit - ) - { - const Foam::point& cc = cit->dual(); - - const scalar crSqr = magSqr(cc - topoint(cit->vertex(0)->point())); - - if - ( - decomposition_().tree().quickCircumsphereRejection - ( - cc, - crSqr, - decomposition_().octreeNearestDistances() - ) - ) - { - nQuickRejections++; - //testCellInfluence[cit->cellIndex()] = -1; - } - } - - timeCheck("End of octreeNearestDistances calculation"); - - for - ( - Delaunay::Finite_cells_iterator cit = finite_cells_begin(); - cit != finite_cells_end(); - ++cit - ) - { - // Assess the influence of the circumsphere of each Delaunay cell with - // the defining volumes for all processors. Any processor touched by - // the circumsphere requires all points of the cell to be referred to - // it. - - // The Delaunay cells to assess have to be real, i.e. all vertices form - // part of the internal or any part of the boundary definition - if - ( - (testCellInfluence[cit->cellIndex()] == 0) - && (cit->real() || cit->hasFarPoint()) - ) - { - const Foam::point& cc = cit->dual(); - - const scalar crSqr = magSqr(cc - topoint(cit->vertex(0)->point())); - - // Only if the circumsphere overlaps the boundary of this processor - // is there a chance of it overlapping others - if (decomposition_().overlapsThisProcessor(cc, sqr(1.01)*crSqr)) - { - circumcentre.append(cc); - circumradiusSqr.append(crSqr); - - testCellInfluence[cit->cellIndex()] = 1; - } - } - - cIOuter++; - } - - timeCheck("End of testing cell influence"); - -// Pout<< "Number of quick rejections = " << nQuickRejections << endl; - Pout<< "Number of influences = " << circumcentre.size() << endl; - - // Increasing the circumspheres to increase the overlaps and compensate for - // floating point errors missing some referrals - labelListList circumsphereOverlaps - = decomposition_().overlapsProcessors - ( - circumcentre, - sqr(1.01)*circumradiusSqr, - false - ); - - timeCheck("End of increasing overlaps"); - - // Reset counters - cIOuter = 0; - - // Relying on the order of iteration of cells being the same as before - for - ( - Delaunay::Finite_cells_iterator cit = finite_cells_begin(); - cit != finite_cells_end(); - ++cit - ) - { - // Pre-tested circumsphere potential influence - if (testCellInfluence[cit->cellIndex()] == 1) - { - const labelList& citOverlaps = circumsphereOverlaps[cIInner]; - - forAll(citOverlaps, cOI) - { - label procI = citOverlaps[cOI]; - - for (int i = 0; i < 4; i++) - { - Vertex_handle v = cit->vertex(i); - - label vIndex = v->index(); - - if (v->farPoint() || v->referred()) - { - continue; - } - - // Using the hashSet to ensure that each vertex is only - // referred once to each processor - if (!referralVertices[procI].found(vIndex)) - { - referralVertices[procI].insert(vIndex); - - parallelInfluencePoints.append(topoint(v->point())); - - targetProcessor.append(procI); - - if (v->internalOrBoundaryPoint()) - { - parallelInfluenceIndices.append(vIndex); - } - else - { - parallelInfluenceIndices.append(-vIndex); - } - } - } - } - - cIInner++; - } - - cIOuter++; - } - - label nFarPoints = removeProcessorBoundarySeeds(true); - - reduce(nFarPoints, sumOp<label>()); - - Info<< " Removed " << nFarPoints - << " far points from the mesh." << endl; - - -// seedProcessorBoundarySurfaces(false); - -// cIInner = 0; -// cIOuter = 0; - - - // Relying on the order of iteration of cells being the same as before -// for -// ( -// Delaunay::Finite_cells_iterator cit = finite_cells_begin(); -// cit != finite_cells_end(); -// ++cit -// ) -// { -// // Pre-tested circumsphere potential influence -// if (testCellInfluence[cIOuter]) -// { -// const labelList& citOverlaps = circumsphereOverlaps[cIInner]; -// -// forAll(citOverlaps, cOI) -// { -// label procI = citOverlaps[cOI]; -// -// recursiveCircumsphereSearch -// ( -// cit, -// procI, -// referralVertices, -// checkedCells, -// parallelInfluencePoints, -// parallelInfluenceIndices, -// targetProcessor -// ); -// } -// -// cIInner++; -// } -// -// cIOuter++; -// } - -// for -// ( -// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); -// vit != finite_vertices_end(); -// ++vit -// ) -// { -// if (vit->referred()) -// { -// //Pout << "REMOVE: " << topoint(vit->point()) << endl; -// remove(vit); -// } -// } - - referVertices - ( - targetProcessor, - parallelInfluencePoints, - parallelInfluenceIndices, - receivedVertices, - "influence", - outputName - ); -} - - -void Foam::conformalVoronoiMesh::referVertices -( - const DynamicList<label>& targetProcessor, - DynamicList<Foam::point>& parallelPoints, - DynamicList<label>& parallelIndices, - List<labelHashSet>& receivedVertices, - const word& stageName, - const word& outputName -) -{ - timeCheck("Start of referVertices " + stageName); - - if (cvMeshControls().objOutput()) - { - writePoints - ( - "parallel_" + stageName +"_pointsToSend_" + outputName + ".obj", - parallelPoints - ); - } - - mapDistribute pointMap = backgroundMeshDecomposition::buildMap - ( - targetProcessor - ); - - label totalVertices = parallelPoints.size(); + return flagIntersection; +} - reduce(totalVertices, sumOp<label>()); - pointMap.distribute(parallelPoints); +bool Foam::conformalVoronoiMesh::clipLineToProc +( + const Foam::point& pt, + Foam::point& a, + Foam::point& b +) const +{ + bool inProc = false; - pointMap.distribute(parallelIndices); + pointIndexHit findAnyIntersection = decomposition_().findLine(a, b); - if (cvMeshControls().objOutput()) + if (!findAnyIntersection.hit()) { - writePoints - ( - "parallel_" + stageName +"_pointsReceived_" + outputName + ".obj", - parallelPoints - ); - } - - timeCheck("Start of referVertices " + stageName + " insertion."); - - label inserted = 0; + pointIndexHit info = decomposition_().findLine(a, pt); - for (label procI = 0; procI < Pstream::nProcs(); procI++) + if (!info.hit()) + { + inProc = true; + } + else + { + inProc = false; + } + } + else { - const labelList& constructMap = pointMap.constructMap()[procI]; + pointIndexHit info = decomposition_().findLine(a, pt); - if (constructMap.size()) + if (!info.hit()) { - forAll(constructMap, i) - { - label origIndex = parallelIndices[constructMap[i]]; - - if (!receivedVertices[procI].found(origIndex)) - { - // For the initial referred vertices, the original - // processor is the one that is sending it. - label encodedProcI = Vb::encodeProcIndex(procI); - - // Pout<< "Insert " - // << parallelPoints[constructMap[i]] - // << " " << origIndex - // << " " << procI - // << endl; - - insertPoint - ( - parallelPoints[constructMap[i]], - origIndex, - encodedProcI - ); - - inserted++; - - receivedVertices[procI].insert(origIndex); - } - } + inProc = true; + b = findAnyIntersection.hitPoint(); + } + else + { + inProc = true; + a = findAnyIntersection.hitPoint(); } } - reduce(inserted, sumOp<label>()); - - Info<< " Inserted " << stageName << " vertices " << inserted << endl; - - Info<< " Total " << stageName << " vertices " << totalVertices << endl; - - timeCheck("End of referVertices " + stageName); + return inProc; } @@ -1821,7 +1114,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion std::list<Facet> facets; finite_incident_facets(vit, std::back_inserter(facets)); - const Foam::point vert = topoint(vit->point()); + pointFromPoint vert = topoint(vit->point()); scalar maxProtrusionDistance = maxSurfaceProtrusion(vert); @@ -1832,12 +1125,20 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceProtrusion ++fit ) { - const Foam::point edgeMid = - 0.5 - *( - fit->first->dual() - + fit->first->neighbor(fit->second)->dual() - ); + Cell_handle c1 = fit->first; + Cell_handle c2 = fit->first->neighbor(fit->second); + + if + ( + is_infinite(c1) || is_infinite(c2) + || !c1->hasInternalPoint() || !c2->hasInternalPoint() + || !c1->real() || !c2->real() + ) + { + continue; + } + + Foam::point edgeMid = 0.5*(c1->dual() + c2->dual()); pointIndexHit surfHit; label hitSurface; @@ -1906,7 +1207,7 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceIncursion std::list<Facet> facets; finite_incident_facets(vit, std::back_inserter(facets)); - const Foam::point vert = topoint(vit->point()); + pointFromPoint vert = topoint(vit->point()); scalar minIncursionDistance = -maxSurfaceProtrusion(vert); @@ -1917,12 +1218,20 @@ void Foam::conformalVoronoiMesh::dualCellLargestSurfaceIncursion ++fit ) { - const Foam::point edgeMid = - 0.5 - *( - fit->first->dual() - + fit->first->neighbor(fit->second)->dual() - ); + Cell_handle c1 = fit->first; + Cell_handle c2 = fit->first->neighbor(fit->second); + + if + ( + is_infinite(c1) || is_infinite(c2) + || !c1->hasInternalPoint() || !c2->hasInternalPoint() + || !c1->real() || !c2->real() + ) + { + continue; + } + + Foam::point edgeMid = 0.5*(c1->dual() + c2->dual()); pointIndexHit surfHit; label hitSurface; @@ -2003,111 +1312,110 @@ void Foam::conformalVoronoiMesh::reportProcessorOccupancy() } -void Foam::conformalVoronoiMesh::reportSurfaceConformationQuality() -{ - Info<< nl << "Check surface conformation quality" << endl; - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ - ) - { - if (vit->internalOrBoundaryPoint()) - { - Foam::point vert(topoint(vit->point())); - pointIndexHit surfHit; - label hitSurface; - - dualCellLargestSurfaceProtrusion(vit, surfHit, hitSurface); - - if (surfHit.hit()) - { - Pout<< nl << "Residual penetration: " << nl - << vit->index() << nl - << vit->type() << nl - << vit->ppMaster() << nl - << "nearFeaturePt " - << nearFeaturePt(surfHit.hitPoint()) << nl - << vert << nl - << surfHit.hitPoint() - << endl; - } - } - } - - { - // Assess close surface points - - setVertexSizeAndAlignment(); - - for - ( - Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); - vit != finite_vertices_end(); - vit++ - ) - { - if (vit->ppMaster()) - { - std::list<Vertex_handle> adjacentVertices; - - adjacent_vertices(vit, std::back_inserter(adjacentVertices)); - - Foam::point pt = topoint(vit->point()); - - // Pout<< nl << "vit: " << vit->index() << " " - // << topoint(vit->point()) - // << endl; - - // Pout<< adjacentVertices.size() << endl; - - for - ( - std::list<Vertex_handle>::iterator - avit = adjacentVertices.begin(); - avit != adjacentVertices.end(); - ++avit - ) - { - Vertex_handle avh = *avit; - - // The lower indexed vertex will perform the assessment - if - ( - avh->ppMaster() - && vit->index() < avh->index() - && vit->type() != avh->type() - ) - { - scalar targetSize = 0.2*averageAnyCellSize(vit, avh); - - // Pout<< "diff " << mag(pt - topoint(avh->point())) - // << " " << targetSize << endl; - - if - ( - magSqr(pt - topoint(avh->point())) - < sqr(targetSize) - ) - { - Pout<< nl << "vit: " << vit->index() << " " - << topoint(vit->point()) - << endl; - - Pout<< " adjacent too close: " - << avh->index() << " " - << topoint(avh->point()) - << endl; - } - } - } - } - } - } -} - +//void Foam::conformalVoronoiMesh::reportSurfaceConformationQuality() +//{ +// Info<< nl << "Check surface conformation quality" << endl; +// +// for +// ( +// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +// vit != finite_vertices_end(); +// vit++ +// ) +// { +// if (vit->internalOrBoundaryPoint()) +// { +// Foam::point vert(topoint(vit->point())); +// pointIndexHit surfHit; +// label hitSurface; +// +// dualCellLargestSurfaceProtrusion(vit, surfHit, hitSurface); +// +// if (surfHit.hit()) +// { +// Pout<< nl << "Residual penetration: " << nl +// << vit->index() << nl +// << vit->type() << nl +// << vit->ppMaster() << nl +// << "nearFeaturePt " +// << nearFeaturePt(surfHit.hitPoint()) << nl +// << vert << nl +// << surfHit.hitPoint() +// << endl; +// } +// } +// } +// +// { +// // Assess close surface points +// +// setVertexSizeAndAlignment(); +// +// for +// ( +// Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); +// vit != finite_vertices_end(); +// vit++ +// ) +// { +// if (vit->ppMaster()) +// { +// std::list<Vertex_handle> adjacentVertices; +// +// adjacent_vertices(vit, std::back_inserter(adjacentVertices)); +// +// Foam::point pt = topoint(vit->point()); +// +// // Pout<< nl << "vit: " << vit->index() << " " +// // << topoint(vit->point()) +// // << endl; +// +// // Pout<< adjacentVertices.size() << endl; +// +// for +// ( +// std::list<Vertex_handle>::iterator +// avit = adjacentVertices.begin(); +// avit != adjacentVertices.end(); +// ++avit +// ) +// { +// Vertex_handle avh = *avit; +// +// // The lower indexed vertex will perform the assessment +// if +// ( +// avh->ppMaster() +// && vit->index() < avh->index() +// && vit->type() != avh->type() +// ) +// { +// scalar targetSize = 0.2*averageAnyCellSize(vit, avh); +// +// // Pout<< "diff " << mag(pt - topoint(avh->point())) +// // << " " << targetSize << endl; +// +// if +// ( +// magSqr(pt - topoint(avh->point())) +// < sqr(targetSize) +// ) +// { +// Pout<< nl << "vit: " << vit->index() << " " +// << topoint(vit->point()) +// << endl; +// +// Pout<< " adjacent too close: " +// << avh->index() << " " +// << topoint(avh->point()) +// << endl; +// } +// } +// } +// } +// } +// } +//} void Foam::conformalVoronoiMesh::limitDisplacement ( @@ -2124,7 +1432,7 @@ void Foam::conformalVoronoiMesh::limitDisplacement return; } - Foam::point pt = topoint(vit->point()); + pointFromPoint pt = topoint(vit->point()); Foam::point dispPt = pt + displacement; bool limit = false; @@ -2205,6 +1513,11 @@ Foam::scalar Foam::conformalVoronoiMesh::angleBetweenSurfacePoints pAsurfaceHit ); + if (!pAhit.hit()) + { + return constant::mathematical::pi; + } + vectorField norm(1); allGeometry_[pAsurfaceHit].getNormal @@ -2226,6 +1539,11 @@ Foam::scalar Foam::conformalVoronoiMesh::angleBetweenSurfacePoints pBsurfaceHit ); + if (!pBhit.hit()) + { + return constant::mathematical::pi; + } + allGeometry_[pBsurfaceHit].getNormal ( List<pointIndexHit>(1, pBhit), @@ -2240,84 +1558,81 @@ Foam::scalar Foam::conformalVoronoiMesh::angleBetweenSurfacePoints bool Foam::conformalVoronoiMesh::nearSurfacePoint ( - pointIndexHit& pHit, - label& surfaceHit, - DynamicList<Foam::point>& existingSurfacePtLocations + pointIndexHitAndFeature& pHit ) const { - const Foam::point& pt = pHit.hitPoint(); + const Foam::point& pt = pHit.first().hitPoint(); pointIndexHit closePoint; const bool closeToSurfacePt = pointIsNearSurfaceLocation(pt, closePoint); - if (closeToSurfacePt) - { - const scalar cosAngle - = angleBetweenSurfacePoints(pt, closePoint.hitPoint()); - - // @todo make this tolerance run-time selectable? - if (cosAngle < searchAngleOppositeSurface) - { - pointIndexHit pCloseHit; - label pCloseSurfaceHit = -1; - - const scalar searchDist = targetCellSize(closePoint.hitPoint()); - - geometryToConformTo_.findSurfaceNearest - ( - closePoint.hitPoint(), - searchDist, - pCloseHit, - pCloseSurfaceHit - ); - - vectorField norm(1); - - allGeometry_[pCloseSurfaceHit].getNormal - ( - List<pointIndexHit>(1, pCloseHit), - norm - ); - - const vector nA = norm[0]; - - pointIndexHit oppositeHit; - label oppositeSurfaceHit = -1; - - geometryToConformTo_.findSurfaceNearestIntersection - ( - closePoint.hitPoint() + SMALL*nA, - closePoint.hitPoint() + mag(pt - closePoint.hitPoint())*nA, - oppositeHit, - oppositeSurfaceHit - ); - - if (oppositeHit.hit()) - { - // Replace point - pHit = oppositeHit; - surfaceHit = oppositeSurfaceHit; - - Foam::point newPt = oppositeHit.hitPoint(); - - appendToSurfacePtTree(newPt, existingSurfacePtLocations); - - return !closeToSurfacePt; - - if (debug) - { - Info<< "Point " << pt - << " is close to " << closePoint.hitPoint() - << " so will be moved to " << oppositeHit.hitPoint() - << endl; - } - } - } - } - else +// if +// ( +// closeToSurfacePt +// && mag(pt - closePoint.hitPoint()) > pointPairDistance(pt) +// ) +// { +// const scalar cosAngle +// = angleBetweenSurfacePoints(pt, closePoint.hitPoint()); +// +// // @todo make this tolerance run-time selectable? +// if (cosAngle < searchAngleOppositeSurface) +// { +// pointIndexHit pCloseHit; +// label pCloseSurfaceHit = -1; +// +// const scalar searchDist = targetCellSize(closePoint.hitPoint()); +// +// if (searchDist < SMALL) +// { +// Pout<< "WARNING: SMALL CELL SIZE" << endl; +// } +// +// geometryToConformTo_.findSurfaceNearest +// ( +// closePoint.hitPoint(), +// searchDist, +// pCloseHit, +// pCloseSurfaceHit +// ); +// +// vectorField norm(1); +// +// allGeometry_[pCloseSurfaceHit].getNormal +// ( +// List<pointIndexHit>(1, pCloseHit), +// norm +// ); +// +// const vector nA = norm[0]; +// +// pointIndexHit oppositeHit; +// label oppositeSurfaceHit = -1; +// +// geometryToConformTo_.findSurfaceNearestIntersection +// ( +// closePoint.hitPoint() + SMALL*nA, +// closePoint.hitPoint() + mag(pt - closePoint.hitPoint())*nA, +// oppositeHit, +// oppositeSurfaceHit +// ); +// +// if (oppositeHit.hit()) +// { +// // Replace point +// pHit.first() = oppositeHit; +// pHit.second() = oppositeSurfaceHit; +// +// appendToSurfacePtTree(pHit.first().hitPoint()); +// +// return !closeToSurfacePt; +// } +// } +// } +// else { - appendToSurfacePtTree(pt, existingSurfacePtLocations); + appendToSurfacePtTree(pt); } return closeToSurfacePt; @@ -2326,15 +1641,14 @@ bool Foam::conformalVoronoiMesh::nearSurfacePoint bool Foam::conformalVoronoiMesh::appendToSurfacePtTree ( - const Foam::point& pt, - DynamicList<Foam::point>& existingSurfacePtLocations + const Foam::point& pt ) const { - label startIndex = existingSurfacePtLocations.size(); + label startIndex = existingSurfacePtLocations_.size(); - existingSurfacePtLocations.append(pt); + existingSurfacePtLocations_.append(pt); - label endIndex = existingSurfacePtLocations.size(); + label endIndex = existingSurfacePtLocations_.size(); return surfacePtLocationTreePtr_().insert(startIndex, endIndex); } @@ -2342,15 +1656,14 @@ bool Foam::conformalVoronoiMesh::appendToSurfacePtTree bool Foam::conformalVoronoiMesh::appendToEdgeLocationTree ( - const Foam::point& pt, - DynamicList<Foam::point>& existingEdgeLocations + const Foam::point& pt ) const { - label startIndex = existingEdgeLocations.size(); + label startIndex = existingEdgeLocations_.size(); - existingEdgeLocations.append(pt); + existingEdgeLocations_.append(pt); - label endIndex = existingEdgeLocations.size(); + label endIndex = existingEdgeLocations_.size(); return edgeLocationTreePtr_().insert(startIndex, endIndex); } @@ -2442,8 +1755,7 @@ bool Foam::conformalVoronoiMesh::pointIsNearSurfaceLocation bool Foam::conformalVoronoiMesh::nearFeatureEdgeLocation ( - pointIndexHit& pHit, - DynamicList<Foam::point>& existingEdgeLocations + pointIndexHit& pHit ) const { Foam::point pt = pHit.hitPoint(); @@ -2513,7 +1825,7 @@ bool Foam::conformalVoronoiMesh::nearFeatureEdgeLocation if (!closeToFeatureEdge) { - appendToEdgeLocationTree(pt, existingEdgeLocations); + appendToEdgeLocationTree(pt); } return closeToFeatureEdge; @@ -2609,57 +1921,34 @@ void Foam::conformalVoronoiMesh::buildSizeAndAlignmentTree() const void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits ( const Delaunay::Finite_vertices_iterator& vit, - const Foam::point& vert, - const DynamicList<pointIndexHit>& surfHit, - const DynamicList<label>& hitSurface, + const pointIndexHitAndFeatureDynList& surfaceIntersections, scalar surfacePtReplaceDistCoeffSqr, scalar edgeSearchDistCoeffSqr, - DynamicList<pointIndexHit>& surfaceHits, - DynamicList<label>& hitSurfaces, - DynamicList<pointIndexHit>& featureEdgeHits, - DynamicList<label>& featureEdgeFeaturesHit, - DynamicList<Foam::point>& newEdgeLocations, - DynamicList<Foam::point>& existingEdgeLocations, - DynamicList<Foam::point>& existingSurfacePtLocations + pointIndexHitAndFeatureDynList& surfaceHits, + pointIndexHitAndFeatureDynList& featureEdgeHits ) const { - const scalar cellSize = targetCellSize(vert); + const scalar cellSize = targetCellSize(topoint(vit->point())); const scalar cellSizeSqr = sqr(cellSize); - forAll(surfHit, sI) + forAll(surfaceIntersections, sI) { - bool keepSurfacePoint = true; + pointIndexHitAndFeature surfHitI = surfaceIntersections[sI]; - pointIndexHit surfHitI = surfHit[sI]; - label hitSurfaceI = hitSurface[sI]; + bool keepSurfacePoint = true; - if (!surfHitI.hit()) + if (!surfHitI.first().hit()) { continue; } - bool isNearFeaturePt = nearFeaturePt(surfHitI.hitPoint()); + bool isNearFeaturePt = nearFeaturePt(surfHitI.first().hitPoint()); - bool isNearSurfacePt = nearSurfacePoint - ( - surfHitI, - hitSurfaceI, - existingSurfacePtLocations - ); + bool isNearSurfacePt = nearSurfacePoint(surfHitI); if (isNearFeaturePt || isNearSurfacePt) { keepSurfacePoint = false; - - // If the triggering Vertex is part of a feature point, allow it to - // conform to the surface. - // @todo Is this needed?! Shouldn't be any feature points here... - if (vit->index() < startOfInternalPoints_) - { - surfaceHits.append(surfHitI); - - hitSurfaces.append(hitSurfaceI); - } } List<List<pointIndexHit> > edHitsByFeature; @@ -2670,7 +1959,7 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits geometryToConformTo_.findAllNearestEdges ( - surfHitI.hitPoint(), + surfHitI.first().hitPoint(), searchRadiusSqr, edHitsByFeature, featuresHit @@ -2688,11 +1977,13 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits if (edHit.hit()) { - if (!nearFeaturePt(edHit.hitPoint())) + const Foam::point& edPt = edHit.hitPoint(); + + if (!nearFeaturePt(edPt)) { if ( - magSqr(edHit.hitPoint() - surfHitI.hitPoint()) + magSqr(edPt - surfHitI.first().hitPoint()) < surfacePtReplaceDistCoeffSqr*cellSizeSqr ) { @@ -2703,25 +1994,26 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits keepSurfacePoint = false; // NEED TO REMOVE FROM THE SURFACE TREE... - surfacePtLocationTreePtr_().remove - ( - existingSurfacePtLocations.size() - 1 - ); +// surfacePtLocationTreePtr_().remove +// ( +// existingSurfacePtLocations_.size() - 1 +// ); } if ( !nearFeatureEdgeLocation ( - edHit, - existingEdgeLocations + edHit ) ) { // Do not place edge control points too close to a // feature point or existing edge control points - featureEdgeHits.append(edHit); - featureEdgeFeaturesHit.append(featureHit); + featureEdgeHits.append + ( + pointIndexHitAndFeature(edHit, featureHit) + ); } } } @@ -2731,7 +2023,6 @@ void Foam::conformalVoronoiMesh::addSurfaceAndEdgeHits if (keepSurfacePoint) { surfaceHits.append(surfHitI); - hitSurfaces.append(hitSurfaceI); } } } @@ -2758,8 +2049,8 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation() if ( !vit->referred() - && vit->pairPoint() - && vit->index() >= startOfInternalPoints_ + && vit->boundaryPoint() + && !vit->featurePoint() ) { tempSurfaceVertices.append @@ -2767,8 +2058,7 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation() Vb ( vit->point(), - 0, // index, reset to zero - vit->type() - vit->index() // type, relative to index + vit->type() ) ); } @@ -2784,7 +2074,7 @@ void Foam::conformalVoronoiMesh::storeSurfaceConformation() label(surfaceConformationVertices_.size()), sumOp<label>() ) - << " vertices" << endl; + << " vertices" << nl << endl; } @@ -2792,35 +2082,24 @@ void Foam::conformalVoronoiMesh::reinsertSurfaceConformation() { Info<< nl << "Reinserting stored surface conformation" << endl; - label preReinsertionSize(number_of_vertices()); + const label preReinsertionSize(number_of_vertices()); // It is assumed that the stored surface conformation is on the correct // processor and does not need distributed - - for + rangeInsertWithInfo ( - List<Vb>::iterator vit=surfaceConformationVertices_.begin(); - vit != surfaceConformationVertices_.end(); - ++vit - ) - { - // Assuming that all of the reinsertions are pair points, and that the - // index and type are relative, i.e. index 0 and type relative to it. - insertPoint - ( - vit->point(), - vit->index() + number_of_vertices(), - vit->type() + number_of_vertices() - ); - } + surfaceConformationVertices_.begin(), + surfaceConformationVertices_.end(), + true + ); - Info<< " Reinserted " - << returnReduce - ( - label(number_of_vertices()) - preReinsertionSize, - sumOp<label>() - ) - << " vertices" << endl; + const label nInserted = label(number_of_vertices()) - preReinsertionSize; + const label nFailed = surfaceConformationVertices_.size() - nInserted; + + Info<< " " << returnReduce(nInserted, sumOp<label>()) + << " points reinserted, failed to insert " + << returnReduce(nFailed, sumOp<label>()) + << endl; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C index 2882be0c6ff..2f7579cbbff 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePointSpecialisations.C @@ -48,39 +48,7 @@ Foam::conformalVoronoiMesh::calcPointFeatureEdgesTypes eS = feMesh.getEdgeStatus(edgeI); - switch (eS) - { - case extendedFeatureEdgeMesh::EXTERNAL: - { - pFEdgeTypes.nExternal++; - break; - } - case extendedFeatureEdgeMesh::INTERNAL: - { - pFEdgeTypes.nInternal++; - break; - } - case extendedFeatureEdgeMesh::FLAT: - { - pFEdgeTypes.nFlat++; - break; - } - case extendedFeatureEdgeMesh::OPEN: - { - pFEdgeTypes.nOpen++; - break; - } - case extendedFeatureEdgeMesh::MULTIPLE: - { - pFEdgeTypes.nMultiple++; - break; - } - case extendedFeatureEdgeMesh::NONE: - { - pFEdgeTypes.nNonFeature++; - break; - } - } + pFEdgeTypes(eS)++; } if (debug) @@ -99,15 +67,22 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint const pointFeatureEdgesTypes& pFEdgesTypes, const List<extendedFeatureEdgeMesh::edgeStatus>& allEdStat, const label ptI, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { if ( - pFEdgesTypes.nExternal == 2 - && pFEdgesTypes.nInternal == 1 + !pFEdgesTypes.found(extendedFeatureEdgeMesh::EXTERNAL) + || !pFEdgesTypes.found(extendedFeatureEdgeMesh::INTERNAL) + ) + { + return false; + } + + if + ( + pFEdgesTypes[extendedFeatureEdgeMesh::EXTERNAL] == 2 + && pFEdgesTypes[extendedFeatureEdgeMesh::INTERNAL] == 1 && pEds.size() == 3 ) { @@ -120,6 +95,8 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint return false; } + label nVert = number_of_vertices(); + const label initialNumOfPoints = pts.size(); const scalar ppDist = pointPairDistance(featPt); @@ -212,18 +189,20 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint - 2.0*planeA.distance(concaveEdgeExternalPt) *concaveEdgePlaneANormal; - pts.append(internalPtA); - indices.append(0); - types.append(4); + pts.append + ( + Vb(internalPtA, Vb::vtInternalFeaturePoint) + ); const Foam::point internalPtB = concaveEdgeExternalPt - 2.0*planeB.distance(concaveEdgeExternalPt) *concaveEdgePlaneBNormal; - pts.append(internalPtB); - indices.append(0); - types.append(3); + pts.append + ( + Vb(internalPtB, Vb::vtInternalFeaturePoint) + ); // Add the external points @@ -295,8 +274,7 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint for (label i = 0; i < 2; ++i) { pts.remove(); - indices.remove(); - types.remove(); + nVert--; } return false; @@ -325,9 +303,10 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint + 2.0*planeC.distance(internalPtA) *convexEdgePlaneCNormal; - pts.append(externalPtD); - indices.append(0); - types.append(-2); + pts.append + ( + Vb(externalPtD, Vb::vtExternalFeaturePoint) + ); } } } @@ -355,17 +334,19 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint + 2.0*planeD.distance(internalPtB) *convexEdgePlaneDNormal; - pts.append(externalPtE); - indices.append(0); - types.append(-2); + pts.append + ( + Vb(externalPtE, Vb::vtExternalFeaturePoint) + ); } } } } - pts.append(concaveEdgeExternalPt); - indices.append(0); - types.append(-4); + pts.append + ( + Vb(concaveEdgeExternalPt, Vb::vtExternalFeaturePoint) + ); const scalar totalAngle = radToDeg ( @@ -375,12 +356,13 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint if (totalAngle > cvMeshControls().maxQuadAngle()) { - // Add additional mitering points + // Add additional mitreing points //scalar angleSign = 1.0; vector convexEdgesPlaneNormal = 0.5*(convexEdgePlaneCNormal + convexEdgePlaneDNormal); + plane planeM(featPt, convexEdgesPlaneNormal); // if @@ -410,17 +392,19 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint //+ (2.0 + guard)*(concaveEdgeLocalFeatPt - concaveEdgeExternalPt); + 2.0*(concaveEdgeLocalFeatPt - concaveEdgeExternalPt); - pts.append(internalPtF); - indices.append(0); - types.append(1); + pts.append + ( + Vb(internalPtF, Vb::vtInternalFeaturePoint) + ); const Foam::point externalPtG = internalPtF + 2.0*planeM.distance(internalPtF)*convexEdgesPlaneNormal; - pts.append(externalPtG); - indices.append(0); - types.append(-1); + pts.append + ( + Vb(externalPtG, Vb::vtExternalFeaturePoint) + ); } if (debug) @@ -428,13 +412,17 @@ bool Foam::conformalVoronoiMesh::createSpecialisedFeaturePoint for (label ptI = initialNumOfPoints; ptI < pts.size(); ++ptI) { Info<< "Point " << ptI << " : "; - meshTools::writeOBJ(Info, pts[ptI]); + meshTools::writeOBJ(Info, topoint(pts[ptI].point())); } } return true; } - else if (pFEdgesTypes.nExternal == 1 && pFEdgesTypes.nInternal == 2) + else if + ( + pFEdgesTypes[extendedFeatureEdgeMesh::EXTERNAL] == 1 + && pFEdgesTypes[extendedFeatureEdgeMesh::INTERNAL] == 2 + ) { // Info<< "nExternal == 1 && nInternal == 2" << endl; diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C index 407de61b398..028dd5a0df0 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshFeaturePoints.C @@ -25,40 +25,19 @@ License #include "conformalVoronoiMesh.H" #include "vectorTools.H" +#include "triangle.H" +#include "tetrahedron.H" +#include "const_circulator.H" using namespace Foam::vectorTools; // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // -void Foam::conformalVoronoiMesh::insertBoundingPoints() -{ - pointField farPts(geometryToConformTo_.globalBounds().points()); - - // Shift corners of bounds relative to origin - farPts -= geometryToConformTo_.globalBounds().midpoint(); - - // Scale the box up - farPts *= 10.0; - - // Shift corners of bounds back to be relative to midpoint - farPts += geometryToConformTo_.globalBounds().midpoint(); - - limitBounds_ = treeBoundBox(farPts); - - forAll(farPts, fPI) - { - insertPoint(farPts[fPI], Vb::vtFar); - } -} - - void Foam::conformalVoronoiMesh::createEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { label edgeI = edHit.index(); @@ -69,27 +48,27 @@ void Foam::conformalVoronoiMesh::createEdgePointGroup { case extendedFeatureEdgeMesh::EXTERNAL: { - createExternalEdgePointGroup(feMesh, edHit, pts, indices, types); + createExternalEdgePointGroup(feMesh, edHit, pts); break; } case extendedFeatureEdgeMesh::INTERNAL: { - createInternalEdgePointGroup(feMesh, edHit, pts, indices, types); + createInternalEdgePointGroup(feMesh, edHit, pts); break; } case extendedFeatureEdgeMesh::FLAT: { - createFlatEdgePointGroup(feMesh, edHit, pts, indices, types); + createFlatEdgePointGroup(feMesh, edHit, pts); break; } case extendedFeatureEdgeMesh::OPEN: { - //createOpenEdgePointGroup(feMesh, edHit, pts, indices, types); + createOpenEdgePointGroup(feMesh, edHit, pts); break; } case extendedFeatureEdgeMesh::MULTIPLE: { - //createMultipleEdgePointGroup(feMesh, edHit, pts, indices, types); + createMultipleEdgePointGroup(feMesh, edHit, pts); break; } case extendedFeatureEdgeMesh::NONE: @@ -104,9 +83,7 @@ void Foam::conformalVoronoiMesh::createExternalEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { const Foam::point& edgePt = edHit.hitPoint(); @@ -158,22 +135,30 @@ void Foam::conformalVoronoiMesh::createExternalEdgePointGroup // Insert the master point pairing the the first slave - pts.append(refPt); - indices.append(0); - types.append(1); + if (!geometryToConformTo_.inside(refPt)) + { + return; + } + + pts.append + ( + Vb(refPt, Vb::vtInternalFeatureEdge) + ); // Insert the slave points by reflecting refPt in both faces. // with each slave refering to the master Foam::point reflectedA = refPt + 2*ppDist*nA; - pts.append(reflectedA); - indices.append(0); - types.append(-1); + pts.append + ( + Vb(reflectedA, Vb::vtExternalFeatureEdge) + ); Foam::point reflectedB = refPt + 2*ppDist*nB; - pts.append(reflectedB); - indices.append(0); - types.append(-2); + pts.append + ( + Vb(reflectedB, Vb::vtExternalFeatureEdge) + ); } @@ -181,9 +166,7 @@ void Foam::conformalVoronoiMesh::createInternalEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { const Foam::point& edgePt = edHit.hitPoint(); @@ -245,9 +228,6 @@ void Foam::conformalVoronoiMesh::createInternalEdgePointGroup // required number of quadrants. int nAddPoints = min(max(nQuads - 2, 0), 2); - // index of reflMaster - label reflectedMaster = 2 + nAddPoints; - // Add number_of_vertices() at insertion of first vertex to all numbers: // Result for nAddPoints 1 when the points are eventually inserted // pt index type @@ -270,41 +250,56 @@ void Foam::conformalVoronoiMesh::createInternalEdgePointGroup // reflectedBb 3 4 // reflMasterPt 4 0 + if + ( + !geometryToConformTo_.inside(reflectedA) + || !geometryToConformTo_.inside(reflectedB) + ) + { + return; + } + // Master A is inside. - pts.append(reflectedA); - indices.append(0); - types.append(reflectedMaster--); + pts.append + ( + Vb(reflectedA, Vb::vtInternalFeatureEdge) + ); // Master B is inside. - pts.append(reflectedB); - indices.append(0); - types.append(reflectedMaster--); + pts.append + ( + Vb(reflectedB, Vb::vtInternalFeatureEdge) + ); if (nAddPoints == 1) { // One additinal point is the reflection of the slave point, // i.e. the original reference point - pts.append(refPt); - indices.append(0); - types.append(reflectedMaster--); + pts.append + ( + Vb(refPt, Vb::vtInternalFeatureEdge) + ); } else if (nAddPoints == 2) { Foam::point reflectedAa = refPt + ppDist*nB; - pts.append(reflectedAa); - indices.append(0); - types.append(reflectedMaster--); + pts.append + ( + Vb(reflectedAa, Vb::vtInternalFeatureEdge) + ); Foam::point reflectedBb = refPt + ppDist*nA; - pts.append(reflectedBb); - indices.append(0); - types.append(reflectedMaster--); + pts.append + ( + Vb(reflectedBb, Vb::vtInternalFeatureEdge) + ); } // Slave is outside. - pts.append(reflMasterPt); - indices.append(0); - types.append(-(nAddPoints + 2)); + pts.append + ( + Vb(reflMasterPt, Vb::vtExternalFeatureEdge) + ); } @@ -312,9 +307,7 @@ void Foam::conformalVoronoiMesh::createFlatEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { const Foam::point& edgePt = edHit.hitPoint(); @@ -337,8 +330,8 @@ void Foam::conformalVoronoiMesh::createFlatEdgePointGroup // is a flat edge vector s = ppDist*(feMesh.edgeDirections()[edHit.index()] ^ n); - createPointPair(ppDist, edgePt + s, n, pts, indices, types); - createPointPair(ppDist, edgePt - s, n, pts, indices, types); + createPointPair(ppDist, edgePt + s, n, pts); + createPointPair(ppDist, edgePt - s, n, pts); } @@ -346,11 +339,33 @@ void Foam::conformalVoronoiMesh::createOpenEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { +// // Assume it is a baffle and insert flat edge point pairs +// const Foam::point& edgePt = edHit.hitPoint(); +// +// const scalar ppDist = pointPairDistance(edgePt); +// +// const vectorField& feNormals = feMesh.normals(); +// const labelList& edNormalIs = feMesh.edgeNormals()[edHit.index()]; +// +// // As this is a flat edge, there are two normals by definition +// const vector& nA = feNormals[edNormalIs[0]]; +// const vector& nB = feNormals[edNormalIs[1]]; +// +// // Average normal to remove any bias to one side, although as this +// // is a flat edge, the normals should be essentially the same +// const vector n = 0.5*(nA + nB); +// +// // Direction along the surface to the control point, sense of edge +// // direction not important, as +s and -s can be used because this +// // is a flat edge +// vector s = ppDist*(feMesh.edgeDirections()[edHit.index()] ^ n); +// +// createBafflePointPair(ppDist, edgePt + s, n, pts); +// createBafflePointPair(ppDist, edgePt - s, n, pts); + Info<< "NOT INSERTING OPEN EDGE POINT GROUP, NOT IMPLEMENTED" << endl; } @@ -359,279 +374,34 @@ void Foam::conformalVoronoiMesh::createMultipleEdgePointGroup ( const extendedFeatureEdgeMesh& feMesh, const pointIndexHit& edHit, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { Info<< "NOT INSERTING MULTIPLE EDGE POINT GROUP, NOT IMPLEMENTED" << endl; } -void Foam::conformalVoronoiMesh::reinsertBoundingPoints() -{ - tmp<pointField> farPts = limitBounds_.points(); - - forAll(farPts(), fPI) - { - insertPoint(farPts()[fPI], Vb::vtFar); - } -} - - void Foam::conformalVoronoiMesh::reinsertFeaturePoints(bool distribute) { Info<< nl << "Reinserting stored feature points" << endl; label preReinsertionSize(number_of_vertices()); - if (distribute) - { - DynamicList<Foam::point> pointsToInsert; - DynamicList<label> indices; - DynamicList<label> types; - - for - ( - List<Vb>::iterator vit=featureVertices_.begin(); - vit != featureVertices_.end(); - ++vit - ) - { - pointsToInsert.append(topoint(vit->point())); - indices.append(vit->index()); - types.append(vit->type()); - } - - // Insert distributed points - insertPoints(pointsToInsert, indices, types, true); - - // Save points in new distribution - featureVertices_.clear(); - featureVertices_.setSize(pointsToInsert.size()); - - forAll(pointsToInsert, pI) - { - featureVertices_[pI] = - Vb(toPoint(pointsToInsert[pI]), indices[pI], types[pI]); - } - } - else - { - for - ( - List<Vb>::iterator vit=featureVertices_.begin(); - vit != featureVertices_.end(); - ++vit - ) - { - // Assuming that all of the reinsertions are pair points, and that - // the index and type are relative, i.e. index 0 and type relative - // to it. - insertPoint - ( - vit->point(), - vit->index() + number_of_vertices(), - vit->type() + number_of_vertices() - ); - } - } - - Info<< " Reinserted " - << returnReduce - ( - label(number_of_vertices()) - preReinsertionSize, - sumOp<label>() - ) - << " vertices" << endl; -} - - -bool Foam::conformalVoronoiMesh::edgesShareNormal -( - const label e1, - const label e2 -) const -{ - const PtrList<extendedFeatureEdgeMesh>& feMeshes - ( - geometryToConformTo_.features() - ); - - forAll(feMeshes, i) - { - const extendedFeatureEdgeMesh& feMesh(feMeshes[i]); - - const vectorField& e1normals = feMesh.edgeNormals(e1); - const vectorField& e2normals = feMesh.edgeNormals(e2); - - forAll(e1normals, nI1) - { - forAll(e2normals, nI2) - { - if (degAngleBetween(e1normals[nI1], e2normals[nI2]) < 1) - { - return true; - } - } - } - } - - return false; -} - - -void Foam::conformalVoronoiMesh::createConvexFeaturePoints -( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types -) -{ - const PtrList<extendedFeatureEdgeMesh>& feMeshes - ( - geometryToConformTo_.features() - ); - - forAll(feMeshes, i) - { - const extendedFeatureEdgeMesh& feMesh(feMeshes[i]); - - for - ( - label ptI = feMesh.convexStart(); - ptI < feMesh.concaveStart(); - ptI++ - ) - { - const Foam::point& featPt = feMesh.points()[ptI]; - - if (!positionOnThisProc(featPt)) - { - continue; - } - - const vectorField& featPtNormals = feMesh.featurePointNormals(ptI); - - const scalar ppDist = - pointPairDistance(featPt); - - vector cornerNormal = sum(featPtNormals); - cornerNormal /= mag(cornerNormal); - - Foam::point internalPt = featPt + ppDist*cornerNormal; - - // Result when the points are eventually inserted (example n = 4) - // Add number_of_vertices() at insertion of first vertex to all - // numbers: - // pt index type - // internalPt 0 1 - // externalPt0 1 0 - // externalPt1 2 0 - // externalPt2 3 0 - // externalPt3 4 0 + insertPoints(featureVertices_, distribute); - pts.append(internalPt); - indices.append(0); - types.append(1); - - label internalPtIndex = -1; - - forAll(featPtNormals, nI) - { - const vector& n = featPtNormals[nI]; - - plane planeN = plane(featPt, n); - - Foam::point externalPt = - internalPt + 2.0 * planeN.distance(internalPt) * n; - - pts.append(externalPt); - indices.append(0); - types.append(internalPtIndex--); - } - } - } -} - - -void Foam::conformalVoronoiMesh::createConcaveFeaturePoints -( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types -) -{ - const PtrList<extendedFeatureEdgeMesh>& feMeshes + const label nReinserted = returnReduce ( - geometryToConformTo_.features() + label(number_of_vertices()) - preReinsertionSize, + sumOp<label>() ); - forAll(feMeshes, i) - { - const extendedFeatureEdgeMesh& feMesh(feMeshes[i]); - - for - ( - label ptI = feMesh.concaveStart(); - ptI < feMesh.mixedStart(); - ptI++ - ) - { - const Foam::point& featPt = feMesh.points()[ptI]; - - if (!positionOnThisProc(featPt)) - { - continue; - } - - const vectorField& featPtNormals = feMesh.featurePointNormals(ptI); - const scalar ppDist = pointPairDistance(featPt); - - vector cornerNormal = sum(featPtNormals); - cornerNormal /= mag(cornerNormal); - - Foam::point externalPt = featPt + ppDist*cornerNormal; - - label externalPtIndex = featPtNormals.size(); - - // Result when the points are eventually inserted (example n = 5) - // Add number_of_vertices() at insertion of first vertex to all - // numbers: - // pt index type - // internalPt0 0 5 - // internalPt1 1 5 - // internalPt2 2 5 - // internalPt3 3 5 - // internalPt4 4 5 - // externalPt 5 4 - - forAll(featPtNormals, nI) - { - const vector& n = featPtNormals[nI]; - - const plane planeN = plane(featPt, n); - - const Foam::point internalPt = - externalPt - 2.0 * planeN.distance(externalPt) * n; - - pts.append(internalPt); - indices.append(0); - types.append(externalPtIndex--); - } - - pts.append(externalPt); - indices.append(0); - types.append(-1); - } - } + Info<< " Reinserted " << nReinserted << " vertices" << endl; } void Foam::conformalVoronoiMesh::createMixedFeaturePoints ( - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { if (cvMeshControls().mixedFeaturePointPPDistanceCoeff() < 0) @@ -659,6 +429,13 @@ void Foam::conformalVoronoiMesh::createMixedFeaturePoints ptI++ ) { + const Foam::point& featPt = points[ptI]; + + if (!positionOnThisProc(featPt)) + { + continue; + } + const labelList& pEds = pointsEdges[ptI]; pointFeatureEdgesTypes pFEdgeTypes(ptI); @@ -672,8 +449,7 @@ void Foam::conformalVoronoiMesh::createMixedFeaturePoints { specialisedSuccess = createSpecialisedFeaturePoint ( - feMesh, pEds, pFEdgeTypes, allEdStat, ptI, - pts, indices, types + feMesh, pEds, pFEdgeTypes, allEdStat, ptI, pts ); } @@ -715,12 +491,9 @@ void Foam::conformalVoronoiMesh::createMixedFeaturePoints continue; } - const Foam::point& pt = points[ptI]; +// createFeaturePoints(feMesh, ptI, pts, types); - if (!positionOnThisProc(pt)) - { - continue; - } + const Foam::point pt = points[ptI]; const scalar edgeGroupDistance = mixedFeaturePointDistance(pt); @@ -733,13 +506,13 @@ void Foam::conformalVoronoiMesh::createMixedFeaturePoints const pointIndexHit edgeHit(true, edgePt, edgeI); - createEdgePointGroup(feMesh, edgeHit, pts, indices, types); + createEdgePointGroup(feMesh, edgeHit, pts); } } } } } - +// // //void Foam::conformalVoronoiMesh::createFeaturePoints //( @@ -787,7 +560,7 @@ void Foam::conformalVoronoiMesh::createMixedFeaturePoints // surfaceConformationVertices_[indices[pI]]; // } // -// forAll() +// forAll(feMesh.) // // // Now find the nearest points within the edge cones. // @@ -803,22 +576,36 @@ void Foam::conformalVoronoiMesh::insertFeaturePoints() { Info<< nl << "Conforming to feature points" << endl; - DynamicList<Foam::point> pts; - DynamicList<label> indices; - DynamicList<label> types; + DynamicList<Vb> pts; const label preFeaturePointSize = number_of_vertices(); - createConvexFeaturePoints(pts, indices, types); + createFeaturePoints(pts); - createConcaveFeaturePoints(pts, indices, types); + createMixedFeaturePoints(pts); -// createFeaturePoints(pts, indices, types); + // Points added using the createEdgePointGroup function will be labelled as + // internal/external feature edges. Relabel them as feature points, + // otherwise they are inserted as both feature points and surface points. + forAll(pts, pI) + { + Vb& pt = pts[pI]; - createMixedFeaturePoints(pts, indices, types); + if (pt.featureEdgePoint()) + { + if (pt.internalBoundaryPoint()) + { + pt.type() = Vb::vtInternalFeaturePoint; + } + else if (pt.externalBoundaryPoint()) + { + pt.type() = Vb::vtExternalFeaturePoint; + } + } + } // Insert the created points, distributing to the appropriate processor - insertPoints(pts, indices, types, true); + insertPoints(pts, true); if (cvMeshControls().objOutput()) { @@ -843,7 +630,7 @@ void Foam::conformalVoronoiMesh::insertFeaturePoints() forAll(pts, pI) { - featureVertices_[pI] = Vb(toPoint(pts[pI]), indices[pI], types[pI]); + featureVertices_[pI] = pts[pI]; } constructFeaturePointLocations(); @@ -924,3 +711,525 @@ Foam::conformalVoronoiMesh::findSurfacePtLocationsNearFeaturePoint return dynPointList.shrink(); } + + +void Foam::conformalVoronoiMesh::addMasterAndSlavePoints +( + const DynamicList<Foam::point>& masterPoints, + const DynamicList<Foam::indexedVertexEnum::vertexType>& masterPointsTypes, + const Map<DynamicList<autoPtr<plane> > >& masterPointReflections, + DynamicList<Vb>& pts, + const label ptI +) const +{ + typedef DynamicList<autoPtr<plane> > planeDynList; + typedef Foam::indexedVertexEnum::vertexType vertexType; + + forAll(masterPoints, pI) + { + // Append master to the list of points + +// OFstream strMasters("fpm_" + name(ptI) + ".obj"); +// OFstream strSlaves("fps_" + name(ptI) + ".obj"); + + const Foam::point& masterPt = masterPoints[pI]; + const vertexType masterType = masterPointsTypes[pI]; + + pts.append + ( + Vb + ( + masterPt, + masterType + ) + ); + +// meshTools::writeOBJ(strMasters, masterPt); + + const planeDynList& masterPointPlanes = masterPointReflections[pI]; + + forAll(masterPointPlanes, planeI) + { + // Reflect master points in the planes and insert the slave points + + const plane& reflPlane = masterPointPlanes[planeI](); + + const Foam::point slavePt = + reflectPointInPlane(masterPt, reflPlane); + + const vertexType slaveType = + ( + masterType == Vb::vtInternalFeaturePoint + ? Vb::vtExternalFeaturePoint // true + : Vb::vtInternalFeaturePoint // false + ); + + pts.append + ( + Vb + ( + slavePt, + slaveType + ) + ); + +// meshTools::writeOBJ(strSlaves, slavePt); + } + } +} + + +Foam::label Foam::conformalVoronoiMesh::getSign +( + const extendedFeatureEdgeMesh::edgeStatus eStatus +) const +{ + if (eStatus == extendedFeatureEdgeMesh::EXTERNAL) + { + return -1; + } + else if (eStatus == extendedFeatureEdgeMesh::INTERNAL) + { + return 1; + } + + return 0; +} + + +void Foam::conformalVoronoiMesh::createMasterAndSlavePoints +( + const extendedFeatureEdgeMesh& feMesh, + const label ptI, + DynamicList<Vb>& pts +) const +{ + typedef DynamicList<autoPtr<plane> > planeDynList; + typedef Foam::indexedVertexEnum::vertexType vertexType; + typedef Foam::extendedFeatureEdgeMesh::edgeStatus edgeStatus; + + const Foam::point& featPt = feMesh.points()[ptI]; + + if (!positionOnThisProc(featPt)) + { + return; + } + + const scalar ppDist = pointPairDistance(featPt); + + // Maintain a list of master points and the planes to relect them in + DynamicList<Foam::point> masterPoints; + DynamicList<vertexType> masterPointsTypes; + Map<planeDynList> masterPointReflections; + + const labelList& featPtEdges = feMesh.featurePointEdges()[ptI]; + + const_circulator<labelList> circ(featPtEdges); + +// Info<< "Point = " << ptI << endl; + + // Loop around the edges of the feature point + if (circ.size()) do + { +// const edgeStatus eStatusPrev = feMesh.getEdgeStatus(circ.prev()); + const edgeStatus eStatusCurr = feMesh.getEdgeStatus(circ()); +// const edgeStatus eStatusNext = feMesh.getEdgeStatus(circ.next()); + +// Info<< "Prev = " +// << extendedFeatureEdgeMesh::edgeStatusNames_[eStatusPrev] +// << " Curr = " +// << extendedFeatureEdgeMesh::edgeStatusNames_[eStatusCurr] +//// << " Next = " +//// << extendedFeatureEdgeMesh::edgeStatusNames_[eStatusNext] +// << endl; + + // Get the direction in which to move the point in relation to the + // feature point + label sign = getSign(eStatusCurr); + + const vector n = sharedFaceNormal(feMesh, circ(), circ.next()); + + const vector pointMotionDirection = sign*0.5*ppDist*n; + + if (masterPoints.empty()) + { + // Initialise with the first master point + + Foam::point pt = featPt + pointMotionDirection; + + planeDynList firstPlane; + firstPlane.append(autoPtr<plane>(new plane(featPt, n))); + + masterPoints.append(pt); + + masterPointsTypes.append + ( + sign == 1 + ? Vb::vtExternalFeaturePoint // true + : Vb::vtInternalFeaturePoint // false + ); + + if + ( + masterPointsTypes.last() == Vb::vtInternalFeaturePoint + && !geometryToConformTo_.inside(masterPoints.last()) + ) + { + return; + } + + const Foam::point reflectedPoint = reflectPointInPlane + ( + masterPoints.last(), + firstPlane.last()() + ); + + if + ( + masterPointsTypes.last() == Vb::vtExternalFeaturePoint + && !geometryToConformTo_.inside(reflectedPoint) + ) + { + return; + } + + masterPointReflections.insert + ( + masterPoints.size() - 1, + firstPlane + ); + } +// else if +// ( +// eStatusPrev == extendedFeatureEdgeMesh::INTERNAL +// && eStatusCurr == extendedFeatureEdgeMesh::EXTERNAL +// ) +// { +// // Insert a new master point. +// Foam::point pt = featPt + pointMotionDirection; +// +// planeDynList firstPlane; +// firstPlane.append(autoPtr<plane>(new plane(featPt, n))); +// +// masterPoints.append(pt); +// +// masterPointsTypes.append +// ( +// sign == 1 +// ? Vb::vtExternalFeaturePoint // true +// : Vb::vtInternalFeaturePoint // false +// ); +// +// masterPointReflections.insert +// ( +// masterPoints.size() - 1, +// firstPlane +// ); +// } +// else if +// ( +// eStatusPrev == extendedFeatureEdgeMesh::EXTERNAL +// && eStatusCurr == extendedFeatureEdgeMesh::INTERNAL +// ) +// { +// +// } + else + { + // Just add this face contribution to the latest master point + + masterPoints.last() += pointMotionDirection; + + masterPointReflections[masterPoints.size() - 1].append + ( + autoPtr<plane>(new plane(featPt, n)) + ); + } + + } while (circ.circulate(CirculatorBase::CLOCKWISE)); + + addMasterAndSlavePoints + ( + masterPoints, + masterPointsTypes, + masterPointReflections, + pts, + ptI + ); +} + + +void Foam::conformalVoronoiMesh::createFeaturePoints(DynamicList<Vb>& pts) +{ + const PtrList<extendedFeatureEdgeMesh>& feMeshes + ( + geometryToConformTo_.features() + ); + + forAll(feMeshes, i) + { + Info<< indent << "Edge mesh = " << feMeshes[i].name() << nl << endl; + + const extendedFeatureEdgeMesh& feMesh(feMeshes[i]); + + for + ( + label ptI = feMesh.convexStart(); + ptI < feMesh.mixedStart(); + ptI++ + ) + { + createMasterAndSlavePoints(feMesh, ptI, pts); + } + } +} + + +//Foam::scalar Foam::conformalVoronoiMesh::pyramidVolume +//( +// const Foam::point& apex, +// const Foam::point& a, +// const Foam::point& b, +// const Foam::point& c, +// const bool printInfo +//) const +//{ +// triPointRef tri(a, b, c); +// +// tetPointRef tet(tri.a(), tri.b(), tri.c(), apex); +// +// scalar volume = tet.mag(); +// +//// scalar volume = (1.0/3.0)*constant::mathematical::pi; +//// +//// K::Circle_3 circle(toPoint(a), toPoint(b), toPoint(c)); +//// +//// scalar height = mag(topoint(circle.center()) - apex); +//// +//// volume *= circle.squared_radius()*height; +// +// if (printInfo) +// { +// Info<< "Calculating volume of pyramid..." << nl +// << " Apex : " << apex << nl +// << " Point a : " << a << nl +// << " Point b : " << b << nl +// << " Point c : " << c << nl +// << " Center : " << tri.centre() << nl +// << " Volume : " << volume << endl; +// } +// +// return volume; +//} + + +//void Foam::conformalVoronoiMesh::createPyramidMasterPoint +//( +// const Foam::point& apex, +// const vectorField& edgeDirections, +// Foam::point& masterPoint, +// vectorField& norms +//) const +//{ +// pointField basePoints(edgeDirections.size() + 1); +// +// forAll(edgeDirections, eI) +// { +// basePoints[eI] = edgeDirections[eI] + apex; +// } +// +// basePoints[edgeDirections.size() + 1] = apex; +// +// face f(identity(edgeDirections.size())); +// +// pyramidPointFaceRef p(f, apex); +// +// const scalar ppDist = pointPairDistance(apex); +// +// +// vector unitDir = f.centre(); +// unitDir /= mag(unitDir); +// +// masterPoint = apex + ppDist*unitDir; +// +// norms.setSize(edgeDirections.size()); +// +// forAll(norms, nI) +// { +// norms[nI] = +// } +//} + + +//void Foam::conformalVoronoiMesh::createConvexConcaveFeaturePoints +//( +// DynamicList<Foam::point>& pts, +// DynamicList<label>& indices, +// DynamicList<label>& types +//) +//{ +// const PtrList<extendedFeatureEdgeMesh>& feMeshes +// ( +// geometryToConformTo_.features() +// ); +// +// forAll(feMeshes, i) +// { +// const extendedFeatureEdgeMesh& feMesh(feMeshes[i]); +// +// for +// ( +// label ptI = feMesh.convexStart(); +// ptI < feMesh.mixedStart(); +// ptI++ +// ) +// { +// const Foam::point& apex = feMesh.points()[ptI]; +// +// if (!positionOnThisProc(apex)) +// { +// continue; +// } +// +// const vectorField& featPtEdgeDirections +// = feMesh.featurePointEdgeDirections(ptI); +// +// Foam::point masterPoint; +// vectorField tetNorms; +// +// createPyramidMasterPoint +// ( +// apex, +// featPtEdgeDirections, +// masterPoint, +// tetNorms +// ); +// +// +// +// // Result when the points are eventually inserted (example n = 4) +// // Add number_of_vertices() at insertion of first vertex to all +// // numbers: +// // pt index type +// // internalPt 0 1 +// // externalPt0 1 0 +// // externalPt1 2 0 +// // externalPt2 3 0 +// // externalPt3 4 0 +// +// // Result when the points are eventually inserted (example n = 5) +// // Add number_of_vertices() at insertion of first vertex to all +// // numbers: +// // pt index type +// // internalPt0 0 5 +// // internalPt1 1 5 +// // internalPt2 2 5 +// // internalPt3 3 5 +// // internalPt4 4 5 +// // externalPt 5 4 +// +// if (geometryToConformTo_.inside(masterPoint)) +// { +// +// } +// else +// { +// +// } +// +// pts.append(masterPoint); +// indices.append(0); +// types.append(1); +// +// label internalPtIndex = -1; +// +// forAll(tetNorms, nI) +// { +// const vector& n = tetNorms[nI]; +// +// Foam::point reflectedPoint +// = reflectPoint(featPt, masterPoint, n); +// +// pts.append(reflectedPoint); +// indices.append(0); +// types.append(internalPtIndex--); +// } +// } +// } +//} + + +Foam::vector Foam::conformalVoronoiMesh::sharedFaceNormal +( + const extendedFeatureEdgeMesh& feMesh, + const label edgeI, + const label nextEdgeI +) const +{ + const labelList& edgeInormals = feMesh.edgeNormals()[edgeI]; + const labelList& nextEdgeInormals = feMesh.edgeNormals()[nextEdgeI]; + + const vector& A1 = feMesh.normals()[edgeInormals[0]]; + const vector& A2 = feMesh.normals()[edgeInormals[1]]; + + const vector& B1 = feMesh.normals()[nextEdgeInormals[0]]; + const vector& B2 = feMesh.normals()[nextEdgeInormals[1]]; + + const scalar A1B1 = mag(A1 ^ B1); + const scalar A1B2 = mag(A1 ^ B2); + const scalar A2B1 = mag(A2 ^ B1); + const scalar A2B2 = mag(A2 ^ B2); + + if (A1B1 < A1B2 && A1B1 < A2B1 && A1B1 < A2B2) + { + return 0.5*(A1 + B1); + } + else if (A1B2 < A1B1 && A1B2 < A2B1 && A1B2 < A2B2) + { + return 0.5*(A1 + B2); + } + else if (A2B1 < A1B1 && A2B1 < A1B2 && A2B1 < A2B2) + { + return 0.5*(A2 + B1); + } + else + { + return 0.5*(A2 + B2); + } +} + + +Foam::List<Foam::point> Foam::conformalVoronoiMesh::reflectPointInPlanes +( + const Foam::point p, + const DynamicList<autoPtr<plane> >& planes +) const +{ + List<Foam::point> reflectedPoints(planes.size()); + + forAll(planes, planeI) + { + reflectedPoints[planeI] = reflectPointInPlane(p, planes[planeI]()); + } + + return reflectedPoints; +} + + +Foam::point Foam::conformalVoronoiMesh::reflectPointInPlane +( + const Foam::point p, + const plane& planeN +) const +{ + const vector reflectedPtDir = p - planeN.nearestPoint(p); + + if ((planeN.normal() & reflectedPtDir) > 0) + { + return p - 2.0*planeN.distance(p)*planeN.normal(); + } + else + { + return p + 2.0*planeN.distance(p)*planeN.normal(); + } +} diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H index 43d8c077fc7..7d664407dcb 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshI.H @@ -21,21 +21,28 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - \*---------------------------------------------------------------------------*/ // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +inline Foam::scalar Foam::conformalVoronoiMesh::defaultCellSize() const +{ + return readScalar + ( + cvMeshControls().cvMeshDict().subDict("motionControl").lookup + ( + "defaultCellSize" + ) + ); +} + + inline Foam::scalar Foam::conformalVoronoiMesh::targetCellSize ( const Foam::point& pt ) const { - return cellSizeControl().cellSize(pt); + return cellShapeControls().cellSize(pt); } @@ -66,8 +73,8 @@ inline Foam::scalar Foam::conformalVoronoiMesh::averageAnyCellSize { if ( - !vA->internalOrBoundaryPoint() - && !vB->internalOrBoundaryPoint() + (!vA->internalOrBoundaryPoint() || vA->referred()) + && (!vB->internalOrBoundaryPoint() || vB->referred()) ) { // There are no internalOrBoundaryPoints available, determine @@ -80,11 +87,11 @@ inline Foam::scalar Foam::conformalVoronoiMesh::averageAnyCellSize *targetCellSize(topoint(vB->point())) ); } - else if (!vB->internalOrBoundaryPoint()) + else if (!vB->internalOrBoundaryPoint() || vB->referred()) { return vA->targetCellSize(); } - else if (!vA->internalOrBoundaryPoint()) + else if (!vA->internalOrBoundaryPoint() || vA->referred()) { return vB->targetCellSize(); } @@ -98,9 +105,10 @@ inline Foam::scalar Foam::conformalVoronoiMesh::averageAnyCellSize const Delaunay::Finite_facets_iterator& fit ) const { - // Geometric mean + // Arithmetic mean + + scalar sizeSum = 0; - scalar sizeProduct = 1; label nProducts = 0; const Cell_handle c(fit->first); @@ -110,10 +118,10 @@ inline Foam::scalar Foam::conformalVoronoiMesh::averageAnyCellSize { Vertex_handle v = c->vertex(vertex_triple_index(oppositeVertex, i)); - if (v->internalOrBoundaryPoint()) + if (v->internalOrBoundaryPoint() && !v->referred()) { - sizeProduct *= v->targetCellSize(); + sizeSum += v->targetCellSize(); nProducts++; } @@ -128,13 +136,22 @@ inline Foam::scalar Foam::conformalVoronoiMesh::averageAnyCellSize { Vertex_handle v = c->vertex(vertex_triple_index(oppositeVertex, i)); - sizeProduct *= targetCellSize(topoint(v->point())); + sizeSum += targetCellSize(topoint(v->point())); } nProducts = 3; } - return pow(sizeProduct, (1.0/nProducts)); + if (sizeSum < 0) + { + WarningIn("averageAnyCellSize(const Delaunay::Finite_facets_iterator&)") + << "sizeSum = " << sizeSum + << endl; + + return 0; + } + + return pow(sizeSum, (1.0/nProducts)); } @@ -219,125 +236,155 @@ inline Foam::scalar Foam::conformalVoronoiMesh::maxSurfaceProtrusion } -inline Foam::label Foam::conformalVoronoiMesh::insertPoint +inline bool Foam::conformalVoronoiMesh::insertPoint ( const Foam::point& p, - const label type + const indexedVertexEnum::vertexType type ) { - return insertPoint(toPoint(p), type); + return insertPoint(toPoint<Point>(p), type); } -inline Foam::label Foam::conformalVoronoiMesh::insertPoint +inline bool Foam::conformalVoronoiMesh::insertPoint ( const Point& P, - const label type + const indexedVertexEnum::vertexType type ) { uint nVert = number_of_vertices(); Vertex_handle vh = insert(P); + bool pointInserted = true; + if (nVert == number_of_vertices()) { - Pout << "Failed to insert point " << topoint(P) << endl; + Pout<< "Failed to insert point : " << topoint(P) + << " of type " << type << endl; + pointInserted = false; } else { - vh->index() = nVert; + vh->index() = getNewVertexIndex(); vh->type() = type; } - return vh->index(); + return pointInserted; } -inline void Foam::conformalVoronoiMesh::insertPoint +inline bool Foam::conformalVoronoiMesh::insertReferredPoint(const Vb& P) +{ + return insertReferredPoint(P.point(), P.index(), P.type(), P.procIndex()); +} + + +inline bool Foam::conformalVoronoiMesh::insertReferredPoint ( const Foam::point& p, const label index, - const label type + const indexedVertexEnum::vertexType type, + const label processor ) { - insertPoint(toPoint(p), index, type); + return insertReferredPoint(toPoint<Point>(p), index, type, processor); } -inline void Foam::conformalVoronoiMesh::insertPoint +inline bool Foam::conformalVoronoiMesh::insertReferredPoint ( const Point& P, const label index, - const label type + const indexedVertexEnum::vertexType type, + const label processor ) { uint nVert = number_of_vertices(); Vertex_handle vh = insert(P); + bool pointInserted = true; + if (nVert == number_of_vertices()) { - Pout << "Failed to insert point " << topoint(P) << endl; + Pout<< "Failed to insert point " << topoint(P) + << " type: " << type << " index: " << index + << " proc: " << processor << endl; + pointInserted = false; } else { vh->index() = index; vh->type() = type; + vh->procIndex() = processor; } + + return pointInserted; } -inline void Foam::conformalVoronoiMesh::insertPointPair +inline void Foam::conformalVoronoiMesh::createPointPair ( const scalar ppDist, const Foam::point& surfPt, - const vector& n + const vector& n, + DynamicList<Vb>& pts ) { - Pout<< "insertPointPair is depricated, " - << " it does not check parallel insertion." << endl; - vector ppDistn = ppDist*n; - label master = insertPoint + pts.append ( - surfPt - ppDistn, - number_of_vertices() + 1 + Vb(surfPt - ppDistn, Vb::vtInternalSurface) ); - insertPoint(surfPt + ppDistn, master); + pts.append + ( + Vb(surfPt + ppDistn, Vb::vtExternalSurface) + ); } -inline void Foam::conformalVoronoiMesh::createPointPair +inline Foam::point Foam::conformalVoronoiMesh::perturbPoint +( + const Foam::point& pt +) const +{ + Foam::point perturbedPt(pt); + +// vector delta(xR/ni, yR/nj, zR/nk); +// scalar pert = randomPerturbationCoeff*cmptMin(delta); + + scalar pert = 1e-12*defaultCellSize(); + + perturbedPt.x() += pert*(rndGen_.scalar01() - 0.5); + perturbedPt.y() += pert*(rndGen_.scalar01() - 0.5); + perturbedPt.z() += pert*(rndGen_.scalar01() - 0.5); + + return perturbedPt; +} + + +inline void Foam::conformalVoronoiMesh::createBafflePointPair ( const scalar ppDist, const Foam::point& surfPt, const vector& n, - DynamicList<Foam::point>& pts, - DynamicList<label>& indices, - DynamicList<label>& types + DynamicList<Vb>& pts ) { vector ppDistn = ppDist*n; - // Result when the points are eventually inserted. - // Add number_of_vertices() at insertion of first vertex to all numbers: - // pt index type - // surfPt - ppDistn 0 1 - // surfPt + ppDistn 1 0 - - // Master, index = number_of_vertices(), type = number_of_vertices() + 1 - pts.append(surfPt - ppDistn); - indices.append(0); - types.append(1); + pts.append + ( + Vb(surfPt - ppDistn, Vb::vtInternalSurface) + ); - // Slave, index = number_of_vertices()(new) + 1, type = index of master. - // This will be inserted after the master, so number_of_vertices() will - // have increased - pts.append(surfPt + ppDistn); - indices.append(0); - types.append(-1); + pts.append + ( + Vb(surfPt + ppDistn, Vb::vtInternalSurface) + ); } @@ -350,13 +397,30 @@ inline bool Foam::conformalVoronoiMesh::isBoundaryDualFace Vertex_handle vA = c->vertex(eit->second); Vertex_handle vB = c->vertex(eit->third); +// if (vA->internalBoundaryPoint() && vB->externalBoundaryPoint()) +// { +// if (vA->index() == vB->index() - 1) +// { +// return true; +// } +// } +// else if (vA->externalBoundaryPoint() && vB->internalBoundaryPoint()) +// { +// if (vA->index() == vB->index() + 1) +// { +// return true; +// } +// } +// +// return false; + // A dual face on the boundary will result from one Dv inside and // one outside return ( ( - vA->internalOrBoundaryPoint() - || vB->internalOrBoundaryPoint() + (vA->internalOrBoundaryPoint() && !vA->referred()) + || (vB->internalOrBoundaryPoint() && !vB->referred()) ) && ( !vA->internalOrBoundaryPoint() @@ -458,58 +522,35 @@ inline bool Foam::conformalVoronoiMesh::isParallelDualEdge } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -#ifdef CGAL_INEXACT - -inline Foam::conformalVoronoiMesh::pointFromPoint -Foam::conformalVoronoiMesh::topoint +inline bool Foam::conformalVoronoiMesh::isProcBoundaryEdge ( - const Point& P -) const -{ - return reinterpret_cast<pointFromPoint>(P); -} - - -inline Foam::conformalVoronoiMesh::PointFrompoint -Foam::conformalVoronoiMesh::toPoint -( - const Foam::point& p + const Delaunay::Finite_edges_iterator& eit ) const { - return reinterpret_cast<PointFrompoint>(p); -} - -#else + bool isProcBoundaryEdge = false; + Cell_handle c = eit->first; + Vertex_handle vA = c->vertex(eit->second); + Vertex_handle vB = c->vertex(eit->third); -inline Foam::conformalVoronoiMesh::pointFromPoint -Foam::conformalVoronoiMesh::topoint -( - const Point& P -) const -{ - return Foam::point + if ( - CGAL::to_double(P.x()), - CGAL::to_double(P.y()), - CGAL::to_double(P.z()) - ); -} - + ( + (vA->referred() && !vB->referred()) + || (vB->referred() && !vA->referred()) + ) + && vA->internalOrBoundaryPoint() + && vB->internalOrBoundaryPoint() + ) + { + isProcBoundaryEdge = true; + } -inline Foam::conformalVoronoiMesh::PointFrompoint -Foam::conformalVoronoiMesh::toPoint -( - const Foam::point& p -) const -{ - return Point(p.x(), p.y(), p.z()); + return isProcBoundaryEdge; } -#endif +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // inline Foam::conformalVoronoiMesh::CGALVector Foam::conformalVoronoiMesh::toCGALVector(const Foam::vector& v) const @@ -562,10 +603,10 @@ Foam::conformalVoronoiMesh::decomposition() const } -inline const Foam::cellSizeControlSurfaces& -Foam::conformalVoronoiMesh::cellSizeControl() const +inline const Foam::cellShapeControl& +Foam::conformalVoronoiMesh::cellShapeControls() const { - return cellSizeControl_; + return cellShapeControl_; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C index 68f98e8a9d3..f21ef34adc6 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/conformalVoronoiMeshIO.C @@ -28,6 +28,11 @@ License #include "OFstream.H" #include "pointMesh.H" #include "pointFields.H" +#include "ListOps.H" +#include "polyMeshFilter.H" +#include "polyTopoChange.H" +#include "PrintTable.H" +#include "pointMesh.H" // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -57,61 +62,185 @@ void Foam::conformalVoronoiMesh::timeCheck if (m.valid()) { - label mSize = m.size(); - label mPeak = m.peak(); - label mRss = m.rss(); + PrintTable<word, label> memoryTable("Memory Usage (kB)"); + + memoryTable.add("mSize", m.size()); + memoryTable.add("mPeak", m.peak()); + memoryTable.add("mRss", m.rss()); + + Info<< incrIndent; + memoryTable.print(Info); + Info<< decrIndent; + } + } +} - if (Pstream::parRun()) + +void Foam::conformalVoronoiMesh::printVertexInfo() const +{ + label nInternal = 0; + label nInternalRef = 0; + label nUnassigned = 0; + label nUnassignedRef = 0; + label nInternalNearBoundary = 0; + label nInternalNearBoundaryRef = 0; + label nInternalSurface = 0; + label nInternalSurfaceRef = 0; + label nInternalFeatureEdge = 0; + label nInternalFeatureEdgeRef = 0; + label nInternalFeaturePoint = 0; + label nInternalFeaturePointRef = 0; + label nExternalSurface = 0; + label nExternalSurfaceRef = 0; + label nExternalFeatureEdge = 0; + label nExternalFeatureEdgeRef = 0; + label nExternalFeaturePoint = 0; + label nExternalFeaturePointRef = 0; + label nFar = 0; + label nReferred = 0; + + for + ( + Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); + vit != finite_vertices_end(); + ++vit + ) + { + if (vit->type() == Vb::vtInternal) + { + if (vit->referred()) { - labelList allMSize(Pstream::nProcs()); - labelList allMPeak(Pstream::nProcs()); - labelList allMRss(Pstream::nProcs()); - - allMSize[Pstream::myProcNo()] = mSize; - allMPeak[Pstream::myProcNo()] = mPeak; - allMRss[Pstream::myProcNo()] = mRss; - - Pstream::gatherList(allMSize); - Pstream::gatherList(allMPeak); - Pstream::gatherList(allMRss); - - Info<< "--- [ " - << "mem (kB) " << tab - << "size" << tab - << "peak" << tab - << "rss" - << " ] --- " << endl; - - forAll(allMSize, procI) - { - Info<< "--- [ " - << procI << " " << tab - << allMSize[procI] << tab - << allMPeak[procI] << tab - << allMRss[procI] - << " ] --- " << endl; - } + nReferred++; + nInternalRef++; + } + + nInternal++; + } + else if (vit->type() == Vb::vtUnassigned) + { + if (vit->referred()) + { + nReferred++; + nUnassignedRef++; + } + + nUnassigned++; + } + else if (vit->type() == Vb::vtInternalNearBoundary) + { + if (vit->referred()) + { + nReferred++; + nInternalNearBoundaryRef++; + } + + nInternalNearBoundary++; + } + else if (vit->type() == Vb::vtInternalSurface) + { + if (vit->referred()) + { + nReferred++; + nInternalSurfaceRef++; + } + + nInternalSurface++; + } + else if (vit->type() == Vb::vtInternalFeatureEdge) + { + if (vit->referred()) + { + nReferred++; + nInternalFeatureEdgeRef++; + } + + nInternalFeatureEdge++; + } + else if (vit->type() == Vb::vtInternalFeaturePoint) + { + if (vit->referred()) + { + nReferred++; + nInternalFeaturePointRef++; + } - Info<< "--- [ " - << "sum " << tab - << sum(allMSize) << tab - << sum(allMPeak) << tab - << sum(allMRss) - << " ] --- " << endl; + nInternalFeaturePoint++; + } + else if (vit->type() == Vb::vtExternalSurface) + { + if (vit->referred()) + { + nReferred++; + nExternalSurfaceRef++; + } + nExternalSurface++; + } + else if (vit->type() == Vb::vtExternalFeatureEdge) + { + if (vit->referred()) + { + nReferred++; + nExternalFeatureEdgeRef++; } - else + + nExternalFeatureEdge++; + } + else if (vit->type() == Vb::vtExternalFeaturePoint) + { + if (vit->referred()) { - Info<< "--- [ " - << "mem size " << mSize << " kB, " - << "mem peak " << mPeak << " kB, " - << "mem rss " << mRss << " kB" - << " ] --- " << endl; + nReferred++; + nExternalFeaturePointRef++; } + + nExternalFeaturePoint++; + } + else if (vit->type() == Vb::vtFar) + { + nFar++; } } + + label nTotalVertices + = nUnassigned + + nInternal + + nInternalNearBoundary + + nInternalSurface + + nInternalFeatureEdge + + nInternalFeaturePoint + + nExternalSurface + + nExternalFeatureEdge + + nExternalFeaturePoint + + nFar; + + if (nTotalVertices != label(number_of_vertices())) + { + WarningIn("Foam::conformalVoronoiMesh::printVertexInfo()") + << nTotalVertices << " does not equal " << number_of_vertices() + << endl; + } + + PrintTable<word, label> vertexTable("Vertex Type Information"); + + vertexTable.add("Total", nTotalVertices); + vertexTable.add("Unassigned", nUnassigned); + vertexTable.add("nInternal", nInternal); + vertexTable.add("nInternalNearBoundary", nInternalNearBoundary); + vertexTable.add("nInternalSurface", nInternalSurface); + vertexTable.add("nInternalFeatureEdge", nInternalFeatureEdge); + vertexTable.add("nInternalFeaturePoint", nInternalFeaturePoint); + vertexTable.add("nExternalSurface", nExternalSurface); + vertexTable.add("nExternalFeatureEdge", nExternalFeatureEdge); + vertexTable.add("nExternalFeaturePoint", nExternalFeaturePoint); + vertexTable.add("nFar", nFar); + vertexTable.add("nReferred", nReferred); + + Info<< endl; + vertexTable.print(Info); } + void Foam::conformalVoronoiMesh::drawDelaunayCell ( Ostream& os, @@ -120,7 +249,7 @@ void Foam::conformalVoronoiMesh::drawDelaunayCell ) const { // Supply offset as tet number - offset *= 5; + offset *= 4; os << "# cell index: " << label(c->cellIndex()) << endl; @@ -130,9 +259,10 @@ void Foam::conformalVoronoiMesh::drawDelaunayCell for (int i = 0; i < 4; i++) { - os << "# index type: " + os << "# index / type / procIndex: " << label(c->vertex(i)->index()) << " " - << label(c->vertex(i)->type()) << endl; + << label(c->vertex(i)->type()) << " " + << label(c->vertex(i)->procIndex()) << endl; meshTools::writeOBJ(os, topoint(c->vertex(i)->point())); } @@ -142,23 +272,39 @@ void Foam::conformalVoronoiMesh::drawDelaunayCell << "f " << 1 + offset << " " << 4 + offset << " " << 3 + offset << nl << "f " << 1 + offset << " " << 2 + offset << " " << 4 + offset << endl; - os << "# cicumcentre " << endl; +// os << "# cicumcentre " << endl; - meshTools::writeOBJ(os, c->dual()); +// meshTools::writeOBJ(os, c->dual()); - os << "l " << 1 + offset << " " << 5 + offset << endl; +// os << "l " << 1 + offset << " " << 5 + offset << endl; } void Foam::conformalVoronoiMesh::writePoints ( const fileName& fName, - bool internalOnly + const Foam::indexedVertexEnum::vertexType startPointType, + const Foam::indexedVertexEnum::vertexType endPointType ) const { OFstream str(runTime_.path()/fName); - Pout<< nl << "Writing points to " << str.name() << endl; + Pout<< nl << "Writing points of types:" << nl; + + forAllConstIter + ( + HashTable<int>, + Foam::indexedVertexEnum::vertexTypeNames_, + iter + ) + { + if (iter() >= startPointType && iter() <= endPointType) + { + Pout<< " " << iter.key() << nl; + } + } + + Pout<< "to " << str.name() << endl; for ( @@ -167,7 +313,7 @@ void Foam::conformalVoronoiMesh::writePoints ++vit ) { - if (!internalOnly || vit->internalPoint()) + if (vit->type() >= startPointType && vit->type() <= endPointType) { meshTools::writeOBJ(str, topoint(vit->point())); } @@ -175,6 +321,16 @@ void Foam::conformalVoronoiMesh::writePoints } +void Foam::conformalVoronoiMesh::writePoints +( + const fileName& fName, + const Foam::indexedVertexEnum::vertexType pointType +) const +{ + writePoints(fName, pointType, pointType); +} + + void Foam::conformalVoronoiMesh::writeBoundaryPoints ( const fileName& fName @@ -220,6 +376,27 @@ void Foam::conformalVoronoiMesh::writePoints } +void Foam::conformalVoronoiMesh::writePoints +( + const fileName& fName, + const List<Vb>& points +) const +{ + if (points.size()) + { + OFstream str(runTime_.path()/fName); + + Pout<< nl << "Writing " << points.size() << " points from pointList to " + << str.name() << endl; + + forAll(points, p) + { + meshTools::writeOBJ(str, topoint(points[p].point())); + } + } +} + + void Foam::conformalVoronoiMesh::writeProcessorInterface ( const fileName& fName, @@ -228,9 +405,7 @@ void Foam::conformalVoronoiMesh::writeProcessorInterface { OFstream str(runTime_.path()/fName); - Pout<< "Writing processor interface" << endl; - - pointField points(number_of_cells(), point::max); + pointField points(number_of_finite_cells(), point::max); for ( @@ -239,15 +414,13 @@ void Foam::conformalVoronoiMesh::writeProcessorInterface ++cit ) { - if (!cit->farCell()) + if (!cit->hasFarPoint()) { points[cit->cellIndex()] = cit->dual(); } } meshTools::writeOBJ(str, faces, points); - - Pout<< "Written processor interface" << endl; } @@ -297,11 +470,7 @@ void Foam::conformalVoronoiMesh::writeInternalDelaunayVertices } -void Foam::conformalVoronoiMesh::writeMesh -( - const fileName& instance, - bool filterFaces -) +void Foam::conformalVoronoiMesh::writeMesh(const fileName& instance) { writeInternalDelaunayVertices(instance); @@ -314,6 +483,7 @@ void Foam::conformalVoronoiMesh::writeMesh { pointField points; + labelList boundaryPts(number_of_finite_cells(), -1); faceList faces; labelList owner; labelList neighbour; @@ -323,9 +493,12 @@ void Foam::conformalVoronoiMesh::writeMesh labelList procNeighbours; pointField cellCentres; + PackedBoolList boundaryFacesToRemove; + calcDualMesh ( points, + boundaryPts, faces, owner, neighbour, @@ -337,7 +510,7 @@ void Foam::conformalVoronoiMesh::writeMesh cellCentres, cellToDelaunayVertex, patchToDelaunayVertex, - filterFaces + boundaryFacesToRemove ); Info<< nl << "Writing polyMesh to " << instance << endl; @@ -347,6 +520,7 @@ void Foam::conformalVoronoiMesh::writeMesh Foam::polyMesh::defaultRegion, instance, points, + boundaryPts, faces, owner, neighbour, @@ -355,12 +529,11 @@ void Foam::conformalVoronoiMesh::writeMesh patchSizes, dualPatchStarts, procNeighbours, - cellCentres + cellCentres, + boundaryFacesToRemove ); } - - if (cvMeshControls().writeTetDualMesh()) { // Determine map from Delaunay vertex to Dual mesh @@ -389,6 +562,7 @@ void Foam::conformalVoronoiMesh::writeMesh forAll(patchToDelaunayVertex, patchI) { const labelList& patchVertices = patchToDelaunayVertex[patchI]; + forAll(patchVertices, i) { label vertI = patchVertices[i]; @@ -416,6 +590,7 @@ void Foam::conformalVoronoiMesh::writeMesh // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pointField points; + labelList boundaryPts(number_of_finite_cells(), -1); // From tet point back to Delaunay vertex index labelList pointToDelaunayVertex; faceList faces; @@ -541,23 +716,24 @@ void Foam::conformalVoronoiMesh::writeMesh labelList procNeighbours(patchNames.size(), -1); - Info<< nl << "Writing tetDualMesh to " << instance << endl; - - writeMesh - ( - "tetDualMesh", - instance, - points, - faces, - owner, - neighbour, - patchTypes, - patchNames, - patchSizes, - patchStarts, - procNeighbours, - cellCentres - ); +// Info<< nl << "Writing tetDualMesh to " << instance << endl; + +// writeMesh +// ( +// "tetDualMesh", +// instance, +// points, +// boundaryPts, +// faces, +// owner, +// neighbour, +// patchTypes, +// patchNames, +// patchSizes, +// patchStarts, +// procNeighbours, +// cellCentres +// ); } } @@ -598,7 +774,8 @@ Foam::autoPtr<Foam::fvMesh> Foam::conformalVoronoiMesh::createDummyMesh patchI, mesh.boundaryMesh(), Pstream::myProcNo(), - procNeighbours[patchI] + procNeighbours[patchI], + coupledPolyPatch::COINCIDENTFULLMATCH ); } else @@ -620,6 +797,122 @@ Foam::autoPtr<Foam::fvMesh> Foam::conformalVoronoiMesh::createDummyMesh } +void Foam::conformalVoronoiMesh::checkProcessorPatchesMatch +( + const wordList& patchTypes, + const labelList& patchSizes, + const labelList& procNeighbours +) const +{ + // Check patch sizes + labelListList procPatchSizes + ( + Pstream::nProcs(), + labelList(Pstream::nProcs(), -1) + ); + + forAll(patchTypes, patchI) + { + if (patchTypes[patchI] == processorPolyPatch::typeName) + { + procPatchSizes[Pstream::myProcNo()][procNeighbours[patchI]] + = patchSizes[patchI]; + } + } + + Pstream::gatherList(procPatchSizes); + + if (Pstream::master()) + { + bool allMatch = true; + + forAll(procPatchSizes, procI) + { + const labelList& patchSizes = procPatchSizes[procI]; + + forAll(patchSizes, patchI) + { + if (patchSizes[patchI] != procPatchSizes[patchI][procI]) + { + allMatch = false; + + Info<< indent << "Patches " << procI << " and " << patchI + << " have different sizes: " << patchSizes[patchI] + << " and " << procPatchSizes[patchI][procI] << endl; + } + } + } + + if (allMatch) + { + Info<< indent << "All processor patches have matching numbers of " + << "faces" << endl; + } + } +} + + +void Foam::conformalVoronoiMesh::reorderPoints +( + pointField& points, + labelList& boundaryPts, + faceList& faces, + const label nInternalFaces +) const +{ + Info<< incrIndent << indent << "Reordering points into internal/external" + << endl; + + labelList oldToNew(points.size(), 0); + + // Find points that are internal + for (label fI = nInternalFaces; fI < faces.size(); ++fI) + { + const face& f = faces[fI]; + + forAll(f, fpI) + { + oldToNew[f[fpI]] = 1; + } + } + + const label nInternalPoints = points.size() - sum(oldToNew); + + label countInternal = 0; + label countExternal = nInternalPoints; + + forAll(points, pI) + { + if (oldToNew[pI] == 0) + { + oldToNew[pI] = countInternal++; + } + else + { + oldToNew[pI] = countExternal++; + } + } + + Info<< indent + << "Number of internal points: " << countInternal << nl + << indent << "Number of external points: " << countExternal + << decrIndent << endl; + + inplaceReorder(oldToNew, points); + inplaceReorder(oldToNew, boundaryPts); + + forAll(faces, fI) + { + face& f = faces[fI]; + + forAll(f, fpI) + { + f[fpI] = oldToNew[f[fpI]]; + } + } +} + + void Foam::conformalVoronoiMesh::reorderProcessorPatches ( const word& meshName, @@ -633,6 +926,11 @@ void Foam::conformalVoronoiMesh::reorderProcessorPatches const labelList& procNeighbours ) const { + Info<< incrIndent << indent << "Reordering processor patches" << endl; + + Info<< incrIndent; + checkProcessorPatchesMatch(patchTypes, patchSizes, procNeighbours); + // Create dummy mesh with correct proc boundaries to do sorting autoPtr<fvMesh> sortMeshPtr ( @@ -656,8 +954,26 @@ void Foam::conformalVoronoiMesh::reorderProcessorPatches ); const fvMesh& sortMesh = sortMeshPtr(); + // Change the transform type on processors to coincident full match. +// forAll(sortMesh.boundaryMesh(), patchI) +// { +// const polyPatch& patch = sortMesh.boundaryMesh()[patchI]; +// +// if (isA<processorPolyPatch>(patch)) +// { +// const processorPolyPatch& cpPatch +// = refCast<const processorPolyPatch>(patch); +// +// processorPolyPatch& pPatch +// = const_cast<processorPolyPatch&>(cpPatch); +// +// pPatch.transform() = coupledPolyPatch::COINCIDENTFULLMATCH; +// } +// } + // Rotation on new faces. - labelList rotation(faces.size(), 0); + labelList rotation(faces.size(), -1); + labelList faceMap(faces.size(), -1); PstreamBuffers pBufs(Pstream::nonBlocking); @@ -699,23 +1015,22 @@ void Foam::conformalVoronoiMesh::reorderProcessorPatches labelList patchFaceMap(patchSizes[patchI], -1); labelList patchFaceRotation(patchSizes[patchI], 0); - bool changed = - refCast<const processorPolyPatch>(pp).order + bool changed = refCast<const processorPolyPatch>(pp).order + ( + pBufs, + primitivePatch ( - pBufs, - primitivePatch + SubList<face> ( - SubList<face> - ( - faces, - patchSizes[patchI], - patchStarts[patchI] - ), - points + faces, + patchSizes[patchI], + patchStarts[patchI] ), - patchFaceMap, - patchFaceRotation - ); + points + ), + patchFaceMap, + patchFaceRotation + ); if (changed) { @@ -724,8 +1039,17 @@ void Foam::conformalVoronoiMesh::reorderProcessorPatches forAll(patchFaceRotation, patchFaceI) { - rotation[patchFaceI + start] = - patchFaceRotation[patchFaceI]; + rotation[patchFaceI + start] + = patchFaceRotation[patchFaceI]; + } + + forAll(patchFaceMap, patchFaceI) + { + if (patchFaceMap[patchFaceI] != patchFaceI) + { + faceMap[patchFaceI + start] + = patchFaceMap[patchFaceI] + start; + } } anyChanged = true; @@ -738,13 +1062,26 @@ void Foam::conformalVoronoiMesh::reorderProcessorPatches if (anyChanged) { // Rotate faces (rotation is already in new face indices). + label nRotated = 0; + forAll(rotation, faceI) { + if (rotation[faceI] == -1) + { + continue; + } + if (rotation[faceI] != 0) { - faces[faceI] = faces[faceI].rotateFace(rotation[faceI]); + inplaceRotateList<List, label>(faces[faceI], rotation[faceI]); + nRotated++; } } + + inplaceReorder(faceMap, faces); + + Info<< indent << returnReduce(nRotated, sumOp<label>()) + << " faces have been rotated" << decrIndent << decrIndent << endl; } } @@ -754,6 +1091,7 @@ void Foam::conformalVoronoiMesh::writeMesh const word& meshName, const fileName& instance, pointField& points, + labelList& boundaryPts, faceList& faces, labelList& owner, labelList& neighbour, @@ -762,7 +1100,8 @@ void Foam::conformalVoronoiMesh::writeMesh const labelList& patchSizes, const labelList& patchStarts, const labelList& procNeighbours, - const pointField& cellCentres + const pointField& cellCentres, + const PackedBoolList& boundaryFacesToRemove ) const { if (cvMeshControls().objOutput()) @@ -770,6 +1109,8 @@ void Foam::conformalVoronoiMesh::writeMesh writeObjMesh(points, faces, word(meshName + ".obj")); } + reorderPoints(points, boundaryPts, faces, patchStarts[0]); + if (Pstream::parRun()) { reorderProcessorPatches @@ -786,6 +1127,10 @@ void Foam::conformalVoronoiMesh::writeMesh ); } + Info<< " Constructing mesh" << endl; + + timeCheck("Before fvMesh construction"); + fvMesh mesh ( IOobject @@ -802,6 +1147,8 @@ void Foam::conformalVoronoiMesh::writeMesh xferMove(neighbour) ); + Info<< " Adding patches to mesh" << endl; + List<polyPatch*> patches(patchStarts.size()); label nValidPatches = 0; @@ -811,7 +1158,6 @@ void Foam::conformalVoronoiMesh::writeMesh if (patchTypes[p] == processorPolyPatch::typeName) { // Do not create empty processor patches - if (patchSizes[p] > 0) { patches[nValidPatches] = new processorPolyPatch @@ -822,7 +1168,8 @@ void Foam::conformalVoronoiMesh::writeMesh nValidPatches, mesh.boundaryMesh(), Pstream::myProcNo(), - procNeighbours[p] + procNeighbours[p], + coupledPolyPatch::NOORDERING ); nValidPatches++; @@ -848,18 +1195,224 @@ void Foam::conformalVoronoiMesh::writeMesh mesh.addFvPatches(patches); + timeCheck("Before fvMesh filtering"); + + autoPtr<polyMeshFilter> meshFilter; + + label nInitialBadFaces = 0; + + if (cvMeshControls().filterEdges()) + { + Info<< nl << "Filtering edges on polyMesh" << nl << endl; + + meshFilter.reset(new polyMeshFilter(mesh)); + + // Filter small edges only. This reduces the number of faces so that + // the face filtering is sped up. + nInitialBadFaces = meshFilter().filterEdges(0); + { + const autoPtr<fvMesh>& newMesh = meshFilter().filteredMesh(); + + polyTopoChange meshMod(newMesh); + + meshMod.changeMesh(mesh, false); + } + } + + if (cvMeshControls().filterFaces()) + { + Info<< nl << "Filtering faces on polyMesh" << nl << endl; + + meshFilter.reset(new polyMeshFilter(mesh)); + + meshFilter().filter(nInitialBadFaces); + { + const autoPtr<fvMesh>& newMesh = meshFilter().filteredMesh(); + + polyTopoChange meshMod(newMesh); + + meshMod.changeMesh(mesh, false); + } + } + + timeCheck("After fvMesh filtering"); + + mesh.setInstance(instance); + if (!mesh.write()) { FatalErrorIn("Foam::conformalVoronoiMesh::writeMesh(..)") << "Failed writing polyMesh." << exit(FatalError); } + else + { + Info<< nl << "Written filtered mesh to " + << mesh.polyMesh::instance() << nl + << endl; + } - writeCellSizes(mesh); - writeCellCentres(mesh); + volTensorField alignments + ( + IOobject + ( + "alignmentsField", + runTime_.timeName(), + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh, + tensor::zero + ); - findRemainingProtrusionSet(mesh); + forAll(mesh.cellCentres(), pI) + { + Vertex_handle nearV = + nearest_vertex + ( + toPoint<Point>(mesh.cellCentres()[pI]) + ); + alignments[pI] = nearV->alignment(); + } + alignments.write(); + + { + volVectorField alignmentx + ( + IOobject + ( + "alignmentsx", + runTime_.timeName(), + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh, + vector::zero + ); + forAll(alignmentx, aI) + { + alignmentx[aI] = alignments[aI].x(); + } + alignmentx.write(); + } + { + volVectorField alignmenty + ( + IOobject + ( + "alignmentsy", + runTime_.timeName(), + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh, + vector::zero + ); + forAll(alignmenty, aI) + { + alignmenty[aI] = alignments[aI].y(); + } + alignmenty.write(); + } + { + volVectorField alignmentz + ( + IOobject + ( + "alignmentsz", + runTime_.timeName(), + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + mesh, + vector::zero + ); + forAll(alignmentz, aI) + { + alignmentz[aI] = alignments[aI].z(); + } + alignmentz.write(); + } + labelIOList boundaryIOPts + ( + IOobject + ( + "boundaryPoints", + instance, + runTime_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + boundaryPts + ); + + + + + // Dump list of boundary points + forAll(mesh.boundaryMesh(), patchI) + { + const polyPatch& pp = mesh.boundaryMesh()[patchI]; + + if (!isA<coupledPolyPatch>(pp)) + { + forAll(pp, fI) + { + const face& boundaryFace = pp[fI]; + + forAll(boundaryFace, pI) + { + const label boundaryPointI = boundaryFace[pI]; + + boundaryIOPts[boundaryPointI] = boundaryPts[boundaryPointI]; + } + } + } + } + + boundaryIOPts.write(); + +// forAllConstIter(labelHashSet, pointsInPatch, pI) +// { +// const Foam::point& ptMaster = mesh.points()[pI.key()]; +// +// forAllConstIter(labelHashSet, pointsInPatch, ptI) +// { +// if (ptI.key() != pI.key()) +// { +// const Foam::point& ptSlave = mesh.points()[ptI.key()]; +// +// const scalar dist = mag(ptMaster - ptSlave); +// if (ptMaster == ptSlave) +// { +// Pout<< "Point(" << pI.key() << ") " << ptMaster +// << " == " +// << "(" << ptI.key() << ") " << ptSlave +// << endl; +// } +// else if (dist == 0) +// { +// Pout<< "Point(" << pI.key() << ") " << ptMaster +// << " ~= " +// << "(" << ptI.key() << ") " << ptSlave +// << endl; +// } +// } +// } +// } + +// writeCellSizes(mesh); + +// writeCellAlignments(mesh); + +// writeCellCentres(mesh); + +// findRemainingProtrusionSet(mesh); } @@ -926,7 +1479,7 @@ void Foam::conformalVoronoiMesh::writeCellSizes forAll(cellSize, i) { - cellSize[i] = cellSizeControl().cellSize(C[i]); + cellSize[i] = cellShapeControls().cellSize(C[i]); } // Info<< nl << "Create targetCellVolume volScalarField" << endl; @@ -1036,7 +1589,7 @@ void Foam::conformalVoronoiMesh::writeCellSizes // forAll(cellSize, i) // { - // cellSize[i] = cellSizeControl().cellSize(P[i]); + // cellSize[i] = cellShapeControls().cellSize(P[i]); // } // ptTargetCellSize.write(); @@ -1044,6 +1597,61 @@ void Foam::conformalVoronoiMesh::writeCellSizes } +void Foam::conformalVoronoiMesh::writeCellAlignments +( + const fvMesh& mesh +) const +{ +// Info<< nl << "Create cellAlignments volTensorField" << endl; +// +// volTensorField cellAlignments +// ( +// IOobject +// ( +// "cellAlignments", +// mesh.polyMesh::instance(), +// mesh, +// IOobject::NO_READ, +// IOobject::AUTO_WRITE +// ), +// mesh, +// tensor::I, +// zeroGradientFvPatchTensorField::typeName +// ); +// +// tensorField& cellAlignment = cellAlignments.internalField(); +// +// const vectorField& C = mesh.cellCentres(); +// +// vectorField xDir(cellAlignment.size()); +// vectorField yDir(cellAlignment.size()); +// vectorField zDir(cellAlignment.size()); +// +// forAll(cellAlignment, i) +// { +// cellAlignment[i] = cellShapeControls().cellAlignment(C[i]); +// xDir[i] = cellAlignment[i] & vector(1, 0, 0); +// yDir[i] = cellAlignment[i] & vector(0, 1, 0); +// zDir[i] = cellAlignment[i] & vector(0, 0, 1); +// } +// +// OFstream xStr("xDir.obj"); +// OFstream yStr("yDir.obj"); +// OFstream zStr("zDir.obj"); +// +// forAll(xDir, i) +// { +// meshTools::writeOBJ(xStr, C[i], C[i] + xDir[i]); +// meshTools::writeOBJ(yStr, C[i], C[i] + yDir[i]); +// meshTools::writeOBJ(zStr, C[i], C[i] + zDir[i]); +// } +// +// cellAlignments.correctBoundaryConditions(); +// +// cellAlignments.write(); +} + + void Foam::conformalVoronoiMesh::writeCellCentres ( const fvMesh& mesh diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.C similarity index 67% rename from applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.C rename to applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.C index 06b2c4d4008..bd4973b32b9 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.C @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - \*---------------------------------------------------------------------------*/ #include "indexedCell.H" @@ -41,8 +36,47 @@ Foam::Ostream& Foam::operator<< { const CGAL::indexedCell<Gt, Cb>& iv = p.t_; - os << "Cell : index:" << iv.index_ << " filterCount:" << iv.filterCount_ - << nl; + os << "Cell: "; + + if (iv.index_ == CGAL::indexedCell<Gt, Cb>::ctFar) + { + os << "far"; + } + else if (iv.index_ >= 0) + { + os << iv.index_; + } + else if (iv.index_ == CGAL::indexedCell<Gt, Cb>::ctInternal) + { + os << "internal"; + } + else if (iv.index_ == CGAL::indexedCell<Gt, Cb>::ctSurface) + { + os << "surface"; + } + else if (iv.index_ == CGAL::indexedCell<Gt, Cb>::ctFeatureEdge) + { + os << "featureEdge"; + } + else if (iv.index_ == CGAL::indexedCell<Gt, Cb>::ctFeaturePoint) + { + os << "featurePoint"; + } + else + { + os << "unassigned"; + } + + if (iv.parallelDualVertex()) + { + os << " (processor)"; + } + else + { + os << " (local)"; + } + + os << " filterCount: " << iv.filterCount_ << nl; os << " " << iv.vertex(0)->info(); os << " " << iv.vertex(1)->info(); os << " " << iv.vertex(2)->info(); diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H similarity index 84% rename from applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H rename to applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H index eab096819ae..4669110b6e9 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCell.H @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Class indexedCell @@ -52,6 +47,8 @@ SourceFiles #include "InfoProxy.H" #include "tetCell.H" #include "typeInfo.H" +#include "vectorTools.H" +#include "indexedCellEnum.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -85,6 +82,7 @@ template > class indexedCell : + public Foam::indexedCellEnum, public Cb { // Private data @@ -98,6 +96,7 @@ class indexedCell // not on a processor face // < 0 && > ctFar : the (global) index of a dual point on a processor // face + int index_; //- The number of times that this Delaunay cell has been limited @@ -105,14 +104,17 @@ class indexedCell int filterCount_; -public: + // Private member functions - enum cellTypes - { - ctFar = INT_MIN - }; + //- Same as globallyOrderedCellVertices but without sorting + Foam::tetCell unsortedVertexGlobalIndices + ( + const Foam::globalIndex& globalDelaunayVertexIndices + ) const; +public: + typedef typename Cb::Vertex_handle Vertex_handle; typedef typename Cb::Cell_handle Cell_handle; @@ -155,9 +157,13 @@ public: inline int cellIndex() const; +#ifdef CGAL_INEXACT inline const Foam::point& dual(); +#else + inline const Foam::point dual(); +#endif - inline bool farCell() const; + inline bool unassigned() const; inline int& filterCount(); @@ -169,6 +175,12 @@ public: //- Does the Delaunay cell have a far point inline bool hasFarPoint() const; + //- Does the Delaunay cell have a feature point + inline bool hasFeaturePoint() const; + + //- Does the Delaunay cell have a seed point + inline bool hasSeedPoint() const; + inline bool hasInternalPoint() const; //- Does the Dual vertex form part of a processor patch @@ -186,6 +198,13 @@ public: const Foam::globalIndex& globalDelaunayVertexIndices ) const; + //- Using the globalIndex object, return a list of four vertices with + // so that the cell has a consistent orientation in parallel. + inline Foam::FixedList<Foam::label, 4> globallyOrderedCellVertices + ( + const Foam::globalIndex& globalDelaunayVertexIndices + ) const; + //- Is the Delaunay cell part of the final dual mesh, i.e. any vertex // form part of the internal or boundary definition inline bool internalOrBoundaryDualVertex() const; @@ -198,8 +217,13 @@ public: // least one Delaunay vertex outside and at least one inside inline bool boundaryDualVertex() const; + //- A dual vertex on a feature edge will result from this Delaunay cell + inline bool featureEdgeDualVertex() const; + inline bool nearProcBoundary() const; + inline bool potentialCoplanarCell() const; + // Info diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C new file mode 100644 index 00000000000..7213739844d --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.C @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "plane.H" +#include "tetrahedron.H" +#include "pointConversion.H" +#include "CGALTriangulation3DKernel.H" + + +template <typename Cell> +Foam::scalar Foam::cvMeshChecks::coplanarTet +( + Cell& c, + const scalar tol +) +{ + tetPointRef tet + ( + topoint(c->vertex(0)->point()), + topoint(c->vertex(1)->point()), + topoint(c->vertex(2)->point()), + topoint(c->vertex(3)->point()) + ); + + const scalar quality = tet.quality(); + + if (quality < tol) + { + return quality; + } + + return 0; + +// plane triPlane +// ( +// topoint(c->vertex(0)->point()), +// topoint(c->vertex(1)->point()), +// topoint(c->vertex(2)->point()) +// ); +// +// const scalar distance = triPlane.distance(topoint(c->vertex(3)->point())); +// +// // Check if the four points are roughly coplanar. If they are then we +// // cannot calculate the circumcentre. Better test might be the volume +// // of the tet. +// if (distance < tol) +// { +// return 0; +// } +// +// return distance; +} + + +template <typename Cell> +bool Foam::cvMeshChecks::closePoints +( + Cell& c, + const scalar tol +) +{ + for (label v = 0; v < 4; ++v) + { + for (label vA = v + 1; vA < 4; ++vA) + { + if + ( + mag + ( + topoint(c->vertex(v)->point()) + - topoint(c->vertex(vA)->point()) + ) + < tol + ) + { + return true; + } + } + } + + return false; +} + + +template <typename Cell> +bool Foam::cvMeshChecks::smallVolume +( + Cell& c, + const scalar tol +) +{ + CGAL::Tetrahedron_3<baseK> tet + ( + c->vertex(0)->point(), + c->vertex(1)->point(), + c->vertex(2)->point(), + c->vertex(3)->point() + ); + + if (tet.volume() < tol) + { + return true; + } + + return false; +} diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.H new file mode 100644 index 00000000000..c040eafab67 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellChecks.H @@ -0,0 +1,77 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#ifndef indexedCellChecks_H +#define indexedCellChecks_H + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +namespace cvMeshChecks +{ + + template <typename Cell> + scalar coplanarTet + ( + Cell& c, + const scalar tol = 1e-12 + ); + + template <typename Cell> + bool closePoints + ( + Cell& c, + const scalar tol = 1e-12 + ); + + template <typename Cell> + bool smallVolume + ( + Cell& c, + const scalar tol = 0.0 + ); + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace cvMeshChecks + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "indexedCellChecks.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.C new file mode 100644 index 00000000000..5d7d953948b --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.C @@ -0,0 +1,46 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "indexedCellEnum.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +template<> +const char* +Foam::NamedEnum<Foam::indexedCellEnum::cellTypes, 6>::names[] = +{ + "Unassigned", + "Internal", + "Surface", + "FeatureEdge", + "FeaturePoint", + "Far" +}; + +const Foam::NamedEnum<Foam::indexedCellEnum::cellTypes, 6> +cellTypesNames_; + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.H new file mode 100644 index 00000000000..5ccef621e74 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellEnum.H @@ -0,0 +1,80 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + indexedCellEnum + +Description + +SourceFiles + indexedCellEnum.C + +\*---------------------------------------------------------------------------*/ + +#ifndef indexedCellEnum_H +#define indexedCellEnum_H + +#include "NamedEnum.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +class indexedCellEnum +{ +public: + + + enum cellTypes + { + ctUnassigned = INT_MIN, + ctFar = INT_MIN + 1, + ctInternal = INT_MIN + 2, + ctSurface = INT_MIN + 3, + ctFeatureEdge = INT_MIN + 4, + ctFeaturePoint = INT_MIN + 5 + }; + + static const Foam::NamedEnum<cellTypes, 6> cellTypesNames_; +}; + + +template<> +inline bool contiguous<indexedCellEnum>() +{ + return true; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H similarity index 51% rename from applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H rename to applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H index eb5e0b44bd1..83434ba2f12 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCellI.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedCell/indexedCellI.H @@ -21,20 +21,41 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - \*---------------------------------------------------------------------------*/ +//#include "indexedCellChecks.H" + +template<class Gt, class Cb> +Foam::tetCell CGAL::indexedCell<Gt, Cb>::unsortedVertexGlobalIndices +( + const Foam::globalIndex& globalDelaunayVertexIndices +) const +{ + Foam::tetCell tVGI; + + for (int i = 0; i < 4; i++) + { + Vertex_handle v = this->vertex(i); + + // Finding the global index of each Delaunay vertex + tVGI[i] = globalDelaunayVertexIndices.toGlobal + ( + Foam::Pstream::myProcNo(), + v->index() + ); + } + + return tVGI; +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template<class Gt, class Cb> CGAL::indexedCell<Gt, Cb>::indexedCell() : Cb(), - index_(ctFar), + index_(ctUnassigned), filterCount_(0) {} @@ -46,7 +67,7 @@ CGAL::indexedCell<Gt, Cb>::indexedCell ) : Cb(v0, v1, v2, v3), - index_(ctFar), + index_(ctUnassigned), filterCount_(0) {} @@ -65,7 +86,7 @@ CGAL::indexedCell<Gt, Cb>::indexedCell ) : Cb(v0, v1, v2, v3, n0, n1, n2, n3), - index_(ctFar), + index_(ctUnassigned), filterCount_(0) {} @@ -86,28 +107,37 @@ int CGAL::indexedCell<Gt, Cb>::cellIndex() const } -template<class Gt, class Cb> -const Foam::point& CGAL::indexedCell<Gt, Cb>::dual() -{ #ifdef CGAL_INEXACT - return reinterpret_cast<const Foam::point&>(this->circumcenter()); + template<class Gt, class Cb> + const Foam::point& CGAL::indexedCell<Gt, Cb>::dual() + { + // if (Foam::cvMeshChecks::coplanarTet(*this, 1e-20) == 0) + // { + // Do exact calc + // } + + return reinterpret_cast<const Foam::point&>(this->circumcenter()); + } #else - const typename Gt::Point_3& P = this->circumcenter(); + template<class Gt, class Cb> + const Foam::point CGAL::indexedCell<Gt, Cb>::dual() + { + const typename Gt::Point_3& P = this->circumcenter(); - return - ( - CGAL::to_double(P.x()), - CGAL::to_double(P.y()), - CGAL::to_double(P.z()) - ); + return Foam::point + ( + CGAL::to_double(P.x()), + CGAL::to_double(P.y()), + CGAL::to_double(P.z()) + ); + } #endif -} template<class Gt, class Cb> -inline bool CGAL::indexedCell<Gt, Cb>::farCell() const +inline bool CGAL::indexedCell<Gt, Cb>::unassigned() const { - return index_ == ctFar; + return index_ == ctUnassigned; } @@ -160,6 +190,32 @@ inline bool CGAL::indexedCell<Gt, Cb>::hasFarPoint() const } +template<class Gt, class Cb> +inline bool CGAL::indexedCell<Gt, Cb>::hasFeaturePoint() const +{ + return + ( + this->vertex(0)->featurePoint() + || this->vertex(1)->featurePoint() + || this->vertex(2)->featurePoint() + || this->vertex(3)->featurePoint() + ); +} + + +template<class Gt, class Cb> +inline bool CGAL::indexedCell<Gt, Cb>::hasSeedPoint() const +{ + return + ( + this->vertex(0)->seedPoint() + || this->vertex(1)->seedPoint() + || this->vertex(2)->seedPoint() + || this->vertex(3)->seedPoint() + ); +} + + template<class Gt, class Cb> inline bool CGAL::indexedCell<Gt, Cb>::hasInternalPoint() const { @@ -178,10 +234,21 @@ inline bool CGAL::indexedCell<Gt, Cb>::parallelDualVertex() const { return ( - this->vertex(0)->referred() - || this->vertex(1)->referred() - || this->vertex(2)->referred() - || this->vertex(3)->referred() + !this->hasFarPoint() + && + ( + this->vertex(0)->referred() + || this->vertex(1)->referred() + || this->vertex(2)->referred() + || this->vertex(3)->referred() + ) + && + ( + this->vertex(0)->real() + || this->vertex(1)->real() + || this->vertex(2)->real() + || this->vertex(3)->real() + ) ); } @@ -247,34 +314,38 @@ inline Foam::tetCell CGAL::indexedCell<Gt, Cb>::vertexGlobalIndices ) const { // tetVertexGlobalIndices - Foam::tetCell tVGI; + Foam::tetCell tVGI + = unsortedVertexGlobalIndices(globalDelaunayVertexIndices); - for (int i = 0; i < 4; i++) + // bubble sort + for (int i = 0; i < tVGI.size(); i++) { - Vertex_handle v = this->vertex(i); - - // Finding the global index of each Delaunay vertex - - if (v->referred()) - { - // Referred vertices may have negative indices - - tVGI[i] = globalDelaunayVertexIndices.toGlobal - ( - v->procIndex(), - Foam::mag(v->index()) - ); - } - else + for (int j = tVGI.size() - 1 ; j > i; j--) { - tVGI[i] = globalDelaunayVertexIndices.toGlobal - ( - Foam::Pstream::myProcNo(), - v->index() - ); + if (tVGI[j - 1] > tVGI[j]) + { + Foam::Swap(tVGI[j - 1], tVGI[j]); + } } } + return tVGI; +} + + +template<class Gt, class Cb> +inline Foam::FixedList<Foam::label, 4> +CGAL::indexedCell<Gt, Cb>::globallyOrderedCellVertices +( + const Foam::globalIndex& globalDelaunayVertexIndices +) const +{ + // tetVertexGlobalIndices + Foam::tetCell tVGI + = unsortedVertexGlobalIndices(globalDelaunayVertexIndices); + + Foam::FixedList<Foam::label, 4> vertexMap(Foam::identity(4)); + // bubble sort for (int i = 0; i < tVGI.size(); i++) { @@ -283,10 +354,16 @@ inline Foam::tetCell CGAL::indexedCell<Gt, Cb>::vertexGlobalIndices if (tVGI[j - 1] > tVGI[j]) { Foam::Swap(tVGI[j - 1], tVGI[j]); + Foam::Swap(vertexMap[j - 1], vertexMap[j]); } } } + for (int i = 0; i < 4; i++) + { + tVGI[i] = vertexMap[i]; + } + return tVGI; } @@ -309,10 +386,14 @@ inline bool CGAL::indexedCell<Gt, Cb>::anyInternalOrBoundaryDualVertex() const { return ( - this->vertex(0)->anyInternalOrBoundaryPoint() - || this->vertex(1)->anyInternalOrBoundaryPoint() - || this->vertex(2)->anyInternalOrBoundaryPoint() - || this->vertex(3)->anyInternalOrBoundaryPoint() + this->vertex(0)->internalOrBoundaryPoint() + || this->vertex(0)->externalBoundaryPoint() + || this->vertex(1)->internalOrBoundaryPoint() + || this->vertex(1)->externalBoundaryPoint() + || this->vertex(2)->internalOrBoundaryPoint() + || this->vertex(2)->externalBoundaryPoint() + || this->vertex(3)->internalOrBoundaryPoint() + || this->vertex(3)->externalBoundaryPoint() ); } @@ -323,21 +404,34 @@ inline bool CGAL::indexedCell<Gt, Cb>::boundaryDualVertex() const return ( ( - this->vertex(0)->internalOrBoundaryPoint() - || this->vertex(1)->internalOrBoundaryPoint() - || this->vertex(2)->internalOrBoundaryPoint() - || this->vertex(3)->internalOrBoundaryPoint() + this->vertex(0)->internalBoundaryPoint() + || this->vertex(1)->internalBoundaryPoint() + || this->vertex(2)->internalBoundaryPoint() + || this->vertex(3)->internalBoundaryPoint() ) && ( - !this->vertex(0)->internalOrBoundaryPoint() - || !this->vertex(1)->internalOrBoundaryPoint() - || !this->vertex(2)->internalOrBoundaryPoint() - || !this->vertex(3)->internalOrBoundaryPoint() + this->vertex(0)->externalBoundaryPoint() + || this->vertex(1)->externalBoundaryPoint() + || this->vertex(2)->externalBoundaryPoint() + || this->vertex(3)->externalBoundaryPoint() ) ); } +template<class Gt, class Cb> +inline bool CGAL::indexedCell<Gt, Cb>::featureEdgeDualVertex() const +{ + return + ( + this->vertex(0)->featureEdgePoint() + && this->vertex(1)->featureEdgePoint() + && this->vertex(2)->featureEdgePoint() + && this->vertex(3)->featureEdgePoint() + ); +} + + template<class Gt, class Cb> inline bool CGAL::indexedCell<Gt, Cb>::nearProcBoundary() const { @@ -351,4 +445,94 @@ inline bool CGAL::indexedCell<Gt, Cb>::nearProcBoundary() const } +template<class Gt, class Cb> +inline bool CGAL::indexedCell<Gt, Cb>::potentialCoplanarCell() const +{ + Foam::label nMasters = 0; + Foam::label nSlaves = 0; + + Vertex_handle vM[2]; + Vertex_handle vS[2]; + + for (Foam::label i = 0; i < 4; ++i) + { + Vertex_handle v = this->vertex(i); + + if (v->internalBoundaryPoint()) + { + vM[nMasters] = v; + nMasters++; + } + + if (v->externalBoundaryPoint()) + { + vS[nSlaves] = v; + nSlaves++; + } + } + + Foam::label nPairs = 0; + + if (nMasters == 2 && nSlaves == 2) + { + Foam::vector vp0(Foam::vector::zero); + Foam::vector vp1(Foam::vector::zero); + + if + ( + vM[0]->type() == vS[0]->index() + && vM[0]->index() == vS[0]->type() + ) + { + vp0 = reinterpret_cast<const Foam::point&>(vM[0]->point()) + - reinterpret_cast<const Foam::point&>(vS[0]->point()); + nPairs++; + } + else if + ( + vM[0]->type() == vS[1]->index() + && vM[0]->index() == vS[1]->type() + ) + { + vp0 = reinterpret_cast<const Foam::point&>(vM[0]->point()) + - reinterpret_cast<const Foam::point&>(vS[1]->point()); + nPairs++; + } + + if + ( + vM[1]->type() == vS[0]->index() + && vM[1]->index() == vS[0]->type() + ) + { + vp1 = reinterpret_cast<const Foam::point&>(vM[1]->point()) + - reinterpret_cast<const Foam::point&>(vS[0]->point()); + nPairs++; + } + else if + ( + vM[1]->type() == vS[1]->index() + && vM[1]->index() == vS[1]->type() + ) + { + vp1 = reinterpret_cast<const Foam::point&>(vM[1]->point()) + - reinterpret_cast<const Foam::point&>(vS[1]->point()); + nPairs++; + } + + if (nPairs == 2) + { + if (Foam::vectorTools::areParallel(vp0, vp1)) + { + Foam::Pout<< "PARALLEL" << Foam::endl; + + return true; + } + } + } + + return false; +} + + // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C deleted file mode 100644 index 2f1fa3c5bbb..00000000000 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.C +++ /dev/null @@ -1,115 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation - \\/ M anipulation | -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - -\*---------------------------------------------------------------------------*/ - -#include "indexedVertex.H" -#include "point.H" - -// * * * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * // - -template<class Gt, class Vb> -Foam::Ostream& Foam::operator<< -( - Ostream& os, - const InfoProxy<CGAL::indexedVertex<Gt, Vb> >& p -) -{ - const CGAL::indexedVertex<Gt, Vb>& iv = p.t_; - - if (iv.type_ == CGAL::indexedVertex<Gt, Vb>::vtNearBoundary) - { - os << "internal near boundary point" << nl; - } - else if (iv.type_ == CGAL::indexedVertex<Gt, Vb>::vtInternal) - { - os << "internal point" << nl; - } - else if (iv.type_ == CGAL::indexedVertex<Gt, Vb>::vtFar) - { - os << "far point" << nl; - } - else if (iv.type_ > CGAL::indexedVertex<Gt, Vb>::vtFar && iv.type_ < 0) - { - if (iv.index_ >= 0) - { - os << "referred (master) point from processor " << iv.procIndex() - << nl; - } - else - { - os << "referred (slave) point from processor " << iv.procIndex() - << nl; - } - } - else if (iv.type_ >= 0) - { - if (iv.ppMaster()) - { - os << "master of point pair. paired up with point " << iv.index_ - << nl; - } - else if (iv.ppSlave()) - { - os << "slave of point pair. paired up with point " << iv.index_ - << nl; - } - else - { - FatalErrorIn - ( - "operator<<" - "(Ostream&, const InfoProxy<CGAL::indexedVertex<Gt, Vb> >&)" - ) << "unhandled type " << iv.type_ << " index " << iv.index_ - << abort(FatalError); - } - } - else - { - FatalErrorIn - ( - "operator<<" - "(Ostream&, const InfoProxy<CGAL::indexedVertex<Gt, Vb> >&)" - ) << "unhandled type " << iv.type_ << " index " << iv.index_ - << abort(FatalError); - } - const Foam::point pos - ( - CGAL::to_double(iv.point().x()), - CGAL::to_double(iv.point().y()), - CGAL::to_double(iv.point().z()) - ); - - os << " type:" << iv.type_ << " index:" << iv.index_ - << " at:" << pos << nl; - - return os; -} - - -// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.C new file mode 100644 index 00000000000..5aa39368740 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.C @@ -0,0 +1,185 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "indexedVertex.H" +#include "point.H" +#include "Istream.H" +#include "Ostream.H" +#include "OStringStream.H" +#include "IStringStream.H" + +// * * * * * * * * * * * * * * * * IOStream operators * * * * * * * * * * * // + +Foam::Istream& Foam::operator>> +( + Istream& is, + CGAL::Point_3<baseK>& p +) +{ +// string data(is); +// +// std::istringstream stdIs; +// +// CGAL::set_ascii_mode(stdIs); +// +// stdIs.str(data); +// +// CGAL::Gmpz xNumer, xDenom; +// CGAL::Gmpz yNumer, yDenom; +// CGAL::Gmpz zNumer, zDenom; +// +// stdIs >> xNumer >> xDenom >> yNumer >> yDenom >> zNumer >> zDenom; +// +// CGAL::Gmpq x(xNumer, xDenom); +// CGAL::Gmpq y(yNumer, yDenom); +// CGAL::Gmpq z(zNumer, zDenom); +// +// p = CGAL::Point_3<baseK> +// ( +// CGAL::to_double(x), +// CGAL::to_double(y), +// CGAL::to_double(z) +// ); + + Foam::point pt; + + is >> pt.x() >> pt.y() >> pt.z(); + + p = CGAL::Point_3<baseK> + ( + pt.x(), + pt.y(), + pt.z() + ); + + return is; +} + + +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const CGAL::Point_3<baseK>& p +) +{ +// CGAL::Gmpq x(CGAL::to_double(p.x())); +// CGAL::Gmpq y(CGAL::to_double(p.y())); +// CGAL::Gmpq z(CGAL::to_double(p.z())); +// +// std::ostringstream stdOs; +// +// CGAL::set_ascii_mode(stdOs); +// +// stdOs<< x.numerator() << ' ' << x.denominator() << ' ' +// << y.numerator() << ' ' << y.denominator() << ' ' +// << z.numerator() << ' ' << z.denominator(); +// +// os << stdOs.str(); + + os << CGAL::to_double(p.x()) << ' ' + << CGAL::to_double(p.y()) << ' ' + << CGAL::to_double(p.z()); + + return os; +} + + +template<class Gt, class Vb> +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const CGAL::indexedVertex<Gt, Vb>& p +) +{ + os << p.point() + << p.index() + << static_cast<int>(p.type()) + << p.procIndex() + << p.alignment() + << p.targetCellSize(); + + return os; +} + + +template<class Gt, class Vb> +Foam::Istream& Foam::operator>> +( + Istream& is, + CGAL::indexedVertex<Gt, Vb>& p +) +{ + is >> p.point() + >> p.index(); + + int type; + is >> type; + + p.type() = static_cast<Foam::indexedVertexEnum::vertexType>(type); + + is >> p.procIndex() + >> p.alignment() + >> p.targetCellSize(); + + return is; +} + + +template<class Gt, class Vb> +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const InfoProxy<CGAL::indexedVertex<Gt, Vb> >& p +) +{ + const CGAL::indexedVertex<Gt, Vb>& iv = p.t_; + + const Foam::point pt + ( + CGAL::to_double(iv.point().x()), + CGAL::to_double(iv.point().y()), + CGAL::to_double(iv.point().z()) + ); + + string referred + ( + Pstream::myProcNo() == iv.processor_ + ? string(" (local)") + : string(" (from " + name(iv.processor_) + ")") + ); + + os << iv.index_ << " " + << CGAL::indexedVertex<Gt, Vb>::vertexTypeNames_[iv.type_] + << " at:" << pt + << " size:" << iv.targetCellSize_ + << " alignment:" << iv.alignment_ + << referred.c_str() + << endl; + + return os; +} + + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H similarity index 57% rename from applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H rename to applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H index c3d13ab05eb..f39e90761d0 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertex.H @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Class indexedVertex @@ -43,9 +38,11 @@ SourceFiles #define indexedVertex_H #include <CGAL/Triangulation_3.h> +#include "CGALTriangulation3DKernel.H" #include "tensor.H" #include "InfoProxy.H" #include "point.H" +#include "indexedVertexEnum.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -56,13 +53,41 @@ template<class Gt, class Vb> class indexedVertex; namespace Foam { + class Ostream; +class Istream; + template<class Gt, class Vb> Ostream& operator<< ( Ostream&, const Foam::InfoProxy<CGAL::indexedVertex<Gt, Vb> >& ); -} + +template<class Gt, class Vb> Ostream& operator<< +( + Ostream&, + const CGAL::indexedVertex<Gt, Vb>& +); + +template<class Gt, class Vb> Istream& operator>> +( + Istream&, + CGAL::indexedVertex<Gt, Vb>& +); + +inline Istream& operator>> +( + Istream& is, + CGAL::Point_3<baseK>& p +); + +inline Ostream& operator<< +( + Ostream& os, + const CGAL::Point_3<baseK>& p +); + +} // End namespace Foam namespace CGAL @@ -72,26 +97,24 @@ namespace CGAL Class indexedVertex Declaration \*---------------------------------------------------------------------------*/ -template<class Gt, class Vb=CGAL::Triangulation_vertex_base_3<Gt> > +template<class Gt, class Vb = CGAL::Triangulation_vertex_base_3<Gt> > class indexedVertex : + public Foam::indexedVertexEnum, public Vb { // Private data + //- Type of pair-point + vertexType type_; + //- The index for this Delaunay vertex. For referred vertices, the // index is negative for vertices that are the outer (slave) of point // pairs int index_; - //- type of pair-point : - // vtNearBoundary : internal near boundary point. - // vtInternal : internal point. - // vtFar : far-point. - // > vtFar, < 0 : referred point from processor -(type_ + 1) - // >= 0 : part of point-pair. Index of other point. - // Lowest numbered is inside one (master). - int type_; + //- Number of the processor that owns this vertex + int processor_; //- Required alignment of the dual cell of this vertex Foam::tensor alignment_; @@ -100,29 +123,15 @@ class indexedVertex Foam::scalar targetCellSize_; //- Specify whether the vertex is fixed or movable. - bool vertexFixed_; - - bool nearProcBoundary_; +// bool vertexFixed_; public: - enum vertexTypes - { - vtNearBoundary = INT_MIN, - vtInternal = INT_MIN + 1, - vtFar = INT_MIN + 2 - }; - - enum vertexMotion - { - fixed = 0, - movable = 1 - }; - - typedef typename Vb::Vertex_handle Vertex_handle; - typedef typename Vb::Cell_handle Cell_handle; - typedef typename Vb::Point Point; + typedef typename Vb::Triangulation_data_structure Tds; + typedef typename Vb::Point Point; + typedef typename Tds::Vertex_handle Vertex_handle; + typedef typename Tds::Cell_handle Cell_handle; template<typename TDS2> struct Rebind_TDS @@ -131,14 +140,23 @@ public: typedef indexedVertex<Gt,Vb2> Other; }; - // Constructors inline indexedVertex(); inline indexedVertex(const Point& p); - inline indexedVertex(const Point& p, int index, int type); + inline indexedVertex(const Point& p, vertexType type); + + inline indexedVertex(const Foam::point& p, vertexType type); + + inline indexedVertex + ( + const Point& p, + int index, + vertexType type, + int processor + ); inline indexedVertex(const Point& p, Cell_handle f); @@ -151,9 +169,9 @@ public: inline int index() const; - inline int& type(); + inline vertexType& type(); - inline int type() const; + inline vertexType type() const; inline Foam::tensor& alignment(); @@ -171,26 +189,18 @@ public: //- Is point internal, i.e. not on boundary inline bool internalPoint() const; - //- Is point internal, i.e. not on boundary, external query. - inline static bool internalPoint(int type); - - // is this a referred vertex + //- Is this a referred vertex inline bool referred() const; - // is this a referred internal or boundary vertex - inline bool referredInternalOrBoundaryPoint() const; - - // is this a referred external (pair slave) vertex - inline bool referredExternal() const; - - // Is this a "real" point on this processor, i.e. is it internal or part - // of the boundary description, and not a "far" or "referred" point + //- Is this a "real" point on this processor, i.e. is internal or part + // of the boundary description, and not a "far" or "referred" point inline bool real() const; // For referred vertices, what is the original processor index inline int procIndex() const; - inline static int encodeProcIndex(int procI); + // For referred vertices, set the original processor index + inline int& procIndex(); //- Set the point to be internal inline void setInternal(); @@ -208,45 +218,61 @@ public: inline void setNearProcBoundary(); //- Either master or slave of pointPair. - inline bool pairPoint() const; - - //- Master of a pointPair is the lowest numbered one. - inline bool ppMaster() const; - - //- Master of a pointPair is the lowest numbered one, external query. - inline static bool ppMaster(int index, int type); - - //- Slave of a pointPair is the highest numbered one. - inline bool ppSlave() const; + inline bool boundaryPoint() const; //- Either original internal point or master of pointPair. inline bool internalOrBoundaryPoint() const; - //- Either original internal point or master of pointPair. - // External query. - inline static bool internalOrBoundaryPoint(int index, int type); - //- Is point near the boundary or part of the boundary definition inline bool nearOrOnBoundary() const; - //- Either a real or referred internal or boundary point - inline bool anyInternalOrBoundaryPoint() const; + //- Part of a feature point + inline bool featurePoint() const; - //- Is the vertex fixed or movable - inline bool isVertexFixed() const; + //- Part of a feature edge + inline bool featureEdgePoint() const; - //- Fix the vertex so that it can't be moved - inline void setVertexFixed(); + //- Part of a surface point pair + inline bool surfacePoint() const; - // inline void operator=(const Delaunay::Finite_vertices_iterator vit) - // { - // Vb::operator=indexedVertex(vit->point()); + inline bool internalBoundaryPoint() const; - // this->index_ = vit->index(); + inline bool externalBoundaryPoint() const; - // this->type_ = vit->type(); - // } +// //- Is the vertex fixed or movable +// inline bool isVertexFixed() const; +// +// //- Fix the vertex so that it can't be moved +// inline void setVertexFixed(); + inline indexedVertex& operator=(const indexedVertex& rhs) + { + Vb::operator=(rhs); + + this->type_ = rhs.type(); + this->index_ = rhs.index(); + this->processor_ = rhs.procIndex(); + this->alignment_ = rhs.alignment(); + this->targetCellSize_ = rhs.targetCellSize(); + + return *this; + } + + inline bool operator==(const indexedVertex& rhs) const + { + return + ( + //this->point() == rhs.point() + this->type_ == rhs.type() + && this->index_ == rhs.index() + && this->processor_ == rhs.procIndex() + ); + } + + inline bool operator!=(const indexedVertex& rhs) const + { + return !(*this == rhs); + } // Info @@ -264,6 +290,17 @@ public: const Foam::InfoProxy<indexedVertex<Gt, Vb> >& ); + friend Foam::Ostream& Foam::operator<< <Gt, Vb> + ( + Foam::Ostream&, + const indexedVertex<Gt, Vb>& + ); + + friend Foam::Istream& Foam::operator>> <Gt, Vb> + ( + Foam::Istream&, + indexedVertex<Gt, Vb>& + ); }; @@ -271,6 +308,37 @@ public: } // End namespace CGAL +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // + +#ifdef CGAL_INEXACT +namespace Foam +{ + // For inexact representations where the storage type is a double, the data + // is contiguous. This may not be true for exact number types. + template<> + inline bool contiguous + < + CGAL::indexedVertex + < + K, + CGAL::Triangulation_vertex_base_3<K> + > + >() + { + return true; + } + + + template<> + inline bool contiguous<CGAL::Triangulation_vertex_base_3<K>::Point>() + { + return true; + } + +} // End namespace Foam +#endif + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #include "indexedVertexI.H" diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C new file mode 100644 index 00000000000..ee394b16fa6 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.C @@ -0,0 +1,88 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "indexedVertexEnum.H" +#include "Pstream.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +template<> +const char* +Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 10>::names[] = +{ + "Unassigned", + "Internal", + "InternalNearBoundary", + "InternalSurface", + "InternalFeatureEdge", + "InternalFeaturePoint", + "ExternalSurface", + "ExternalFeatureEdge", + "ExternalFeaturePoint", + "Far" +}; + +const Foam::NamedEnum<Foam::indexedVertexEnum::vertexType, 10> +Foam::indexedVertexEnum::vertexTypeNames_; + + +template<> +const char* +Foam::NamedEnum<Foam::indexedVertexEnum::vertexMotion, 2>::names[] = +{ + "fixed", + "movable" +}; + +const Foam::NamedEnum<Foam::indexedVertexEnum::vertexMotion, 2> +vertexMotionNames_; + + +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const Foam::indexedVertexEnum::vertexType& v +) +{ + os << static_cast<int>(v); + + return os; +} + +Foam::Istream& Foam::operator>> +( + Istream& is, + Foam::indexedVertexEnum::vertexType& v +) +{ + int type; + is >> type; + + v = static_cast<Foam::indexedVertexEnum::vertexType>(type); + + return is; +} + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H new file mode 100644 index 00000000000..c597d8a1730 --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexEnum.H @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + indexedVertexEnum + +Description + +SourceFiles + indexedVertexEnum.C + +\*---------------------------------------------------------------------------*/ + +#ifndef indexedVertexEnum_H +#define indexedVertexEnum_H + +#include "NamedEnum.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +class indexedVertexEnum +{ +public: + + enum vertexType + { + vtUnassigned = 0, + vtInternal = 1, + vtInternalNearBoundary = 2, + vtInternalSurface = 3, + vtInternalFeatureEdge = 4, + vtInternalFeaturePoint = 5, + vtExternalSurface = 6, + vtExternalFeatureEdge = 7, + vtExternalFeaturePoint = 8, + vtFar = 9 + }; + + enum vertexMotion + { + fixed = 0, + movable = 1 + }; + + static const Foam::NamedEnum<vertexType, 10> vertexTypeNames_; + + static const Foam::NamedEnum<vertexMotion, 2> vertexMotionNames_; + + friend Ostream& operator<<(Foam::Ostream&, const vertexType&); + + friend Istream& operator>>(Foam::Istream&, vertexType&); +}; + + +template<> +inline bool contiguous<indexedVertexEnum>() +{ + return true; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H similarity index 56% rename from applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H rename to applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H index f427316fc54..02d37c1b05c 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertexI.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/indexedVertex/indexedVertexI.H @@ -21,25 +21,21 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - \*---------------------------------------------------------------------------*/ +#include "Pstream.H" + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template<class Gt, class Vb> inline CGAL::indexedVertex<Gt, Vb>::indexedVertex() : Vb(), - index_(vtInternal), - type_(vtInternal), - alignment_(), - targetCellSize_(0.0), - vertexFixed_(false), - nearProcBoundary_(false) + type_(vtUnassigned), + index_(vtUnassigned), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) {} @@ -47,12 +43,43 @@ template<class Gt, class Vb> inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p) : Vb(p), - index_(vtInternal), - type_(vtInternal), - alignment_(), - targetCellSize_(0.0), - vertexFixed_(false), - nearProcBoundary_(false) + type_(vtUnassigned), + index_(vtUnassigned), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) +{} + + +template<class Gt, class Vb> +inline CGAL::indexedVertex<Gt, Vb>::indexedVertex +( + const Point& p, + vertexType type +) +: + Vb(p), + type_(type), + index_(-1), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) +{} + + +template<class Gt, class Vb> +inline CGAL::indexedVertex<Gt, Vb>::indexedVertex +( + const Foam::point& p, + vertexType type +) +: + Vb(Point(p.x(), p.y(), p.z())), + type_(type), + index_(-1), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) {} @@ -61,16 +88,16 @@ inline CGAL::indexedVertex<Gt, Vb>::indexedVertex ( const Point& p, int index, - int type + vertexType type, + int processor ) : Vb(p), - index_(index), type_(type), - alignment_(), - targetCellSize_(0.0), - vertexFixed_(false), - nearProcBoundary_(false) + index_(index), + processor_(processor), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) {} @@ -78,12 +105,11 @@ template<class Gt, class Vb> inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(const Point& p, Cell_handle f) : Vb(f, p), - index_(vtInternal), - type_(vtInternal), - alignment_(), - targetCellSize_(0.0), - vertexFixed_(false), - nearProcBoundary_(false) + type_(vtUnassigned), + index_(vtUnassigned), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) {} @@ -91,12 +117,11 @@ template<class Gt, class Vb> inline CGAL::indexedVertex<Gt, Vb>::indexedVertex(Cell_handle f) : Vb(f), - index_(vtInternal), - type_(vtInternal), - alignment_(), - targetCellSize_(0.0), - vertexFixed_(false), - nearProcBoundary_(false) + type_(vtUnassigned), + index_(vtUnassigned), + processor_(Foam::Pstream::myProcNo()), + alignment_(Foam::tensor::zero), + targetCellSize_(0.0) {} @@ -117,14 +142,16 @@ inline int CGAL::indexedVertex<Gt, Vb>::index() const template<class Gt, class Vb> -inline int& CGAL::indexedVertex<Gt, Vb>::type() +inline typename CGAL::indexedVertex<Gt, Vb>::vertexType& +CGAL::indexedVertex<Gt, Vb>::type() { return type_; } template<class Gt, class Vb> -inline int CGAL::indexedVertex<Gt, Vb>::type() const +inline typename CGAL::indexedVertex<Gt, Vb>::vertexType +CGAL::indexedVertex<Gt, Vb>::type() const { return type_; } @@ -161,7 +188,7 @@ inline Foam::scalar CGAL::indexedVertex<Gt, Vb>::targetCellSize() const template<class Gt, class Vb> inline bool CGAL::indexedVertex<Gt, Vb>::uninitialised() const { - return type_ == vtInternal && index_ == vtInternal; + return type_ == vtUnassigned; } @@ -175,63 +202,41 @@ inline bool CGAL::indexedVertex<Gt, Vb>::farPoint() const template<class Gt, class Vb> inline bool CGAL::indexedVertex<Gt, Vb>::internalPoint() const { - return internalPoint(type_); -} - - -template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::internalPoint(int type) -{ - return type <= vtInternal; + return type_ == vtInternal || type_ == vtInternalNearBoundary; } template<class Gt, class Vb> inline bool CGAL::indexedVertex<Gt, Vb>::referred() const { - return (type_ < 0 && type_ > vtFar); -} - - -template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::referredInternalOrBoundaryPoint() const -{ - return referred() && index_ >= 0; -} - + // Can't be zero as the first few points are far points which won't be + // referred + //return index_ < 0; -template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::referredExternal() const -{ - return referred() && index_ < 0; + // processor_ will be take the value of the processor that this vertex is + // from, so it cannot be on this processor. + return processor_ != Foam::Pstream::myProcNo(); } template<class Gt, class Vb> inline bool CGAL::indexedVertex<Gt, Vb>::real() const { - return internalPoint() || pairPoint(); + return (internalPoint() || boundaryPoint()) && !referred(); } template<class Gt, class Vb> inline int CGAL::indexedVertex<Gt, Vb>::procIndex() const { - if (referred()) - { - return -(type_ + 1); - } - else - { - return -1; - } + return processor_; } template<class Gt, class Vb> -inline int CGAL::indexedVertex<Gt, Vb>::encodeProcIndex(int procI) +inline int& CGAL::indexedVertex<Gt, Vb>::procIndex() { - return -(procI + 1); + return processor_; } @@ -245,115 +250,85 @@ inline void CGAL::indexedVertex<Gt, Vb>::setInternal() template<class Gt, class Vb> inline bool CGAL::indexedVertex<Gt, Vb>::nearBoundary() const { - return type_ == vtNearBoundary; + return type_ == vtInternalNearBoundary; } template<class Gt, class Vb> inline void CGAL::indexedVertex<Gt, Vb>::setNearBoundary() { - type_ = vtNearBoundary; -} - - -template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::nearProcBoundary() const -{ - return nearProcBoundary_; -} - - -template<class Gt, class Vb> -inline void CGAL::indexedVertex<Gt, Vb>::setNearProcBoundary() -{ - nearProcBoundary_ = true; + type_ = vtInternalNearBoundary; } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::pairPoint() const +inline bool CGAL::indexedVertex<Gt, Vb>::boundaryPoint() const { - return type_ >= 0; + return type_ >= vtInternalSurface && !farPoint(); } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::ppMaster() const -{ - return ppMaster(index_, type_); -} - - -template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::ppMaster(int index, int type) +inline bool CGAL::indexedVertex<Gt, Vb>::internalOrBoundaryPoint() const { - if (index >= 0 && type > index) - { - return true; - } - - return false; + return internalPoint() || internalBoundaryPoint(); } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::ppSlave() const +inline bool CGAL::indexedVertex<Gt, Vb>::nearOrOnBoundary() const { - if (type_ >= 0 && type_ < index_) - { - return true; - } - else - { - return false; - } + return boundaryPoint() || nearBoundary(); } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::internalOrBoundaryPoint() const +inline bool CGAL::indexedVertex<Gt, Vb>::internalBoundaryPoint() const { - return internalOrBoundaryPoint(index_, type_); + return type_ >= vtInternalSurface && type_ <= vtInternalFeaturePoint; } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::internalOrBoundaryPoint -( - int index, - int type -) +inline bool CGAL::indexedVertex<Gt, Vb>::externalBoundaryPoint() const { - return internalPoint(type) || ppMaster(index, type); + return type_ >= vtExternalSurface && type_ <= vtExternalFeaturePoint; } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::nearOrOnBoundary() const +inline bool CGAL::indexedVertex<Gt, Vb>::featurePoint() const { - return pairPoint() || nearBoundary(); + return type_ == vtInternalFeaturePoint || type_ == vtExternalFeaturePoint; } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::anyInternalOrBoundaryPoint() const +inline bool CGAL::indexedVertex<Gt, Vb>::featureEdgePoint() const { - return internalOrBoundaryPoint() || referredInternalOrBoundaryPoint(); + return type_ == vtInternalFeatureEdge || type_ == vtExternalFeatureEdge; } template<class Gt, class Vb> -inline bool CGAL::indexedVertex<Gt, Vb>::isVertexFixed() const +inline bool CGAL::indexedVertex<Gt, Vb>::surfacePoint() const { - return vertexFixed_; + return type_ == vtInternalSurface || type_ == vtExternalSurface; } -template<class Gt, class Vb> -inline void CGAL::indexedVertex<Gt, Vb>::setVertexFixed() -{ - vertexFixed_ = true; -} +//template<class Gt, class Vb> +//inline bool CGAL::indexedVertex<Gt, Vb>::isVertexFixed() const +//{ +// return vertexFixed_; +//} +// +// +//template<class Gt, class Vb> +//inline void CGAL::indexedVertex<Gt, Vb>::setVertexFixed() +//{ +// vertexFixed_ = true; +//} // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointConversion.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointConversion.H new file mode 100644 index 00000000000..6242a3a6fea --- /dev/null +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointConversion.H @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2012 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + pointConversion + +Description + + Conversion functions between point (FOAM::) and Point (CGAL) + +\*---------------------------------------------------------------------------*/ + +#ifndef pointConversion_H +#define pointConversion_H + +#include "point.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef CGAL_INEXACT + + // Define Point to be contiguous for inexact (double storage) kernel + typedef const Foam::point& pointFromPoint; + typedef const CGAL::Triangulation_vertex_base_3<K>::Point& PointFrompoint; + +#else + + typedef Foam::point pointFromPoint; + typedef CGAL::Triangulation_vertex_base_3<K>::Point PointFrompoint; + +#endif + +namespace Foam +{ + +#ifdef CGAL_INEXACT + + template<typename Point> + inline pointFromPoint topoint(const Point& P) + { + return reinterpret_cast<pointFromPoint>(P); + } + + template<typename Point> + inline PointFrompoint toPoint(const Foam::point& p) + { + return reinterpret_cast<PointFrompoint>(p); + } + +#else + + template<typename Point> + inline pointFromPoint topoint(const Point& P) + { + return Foam::point + ( + CGAL::to_double(P.x()), + CGAL::to_double(P.y()), + CGAL::to_double(P.z()) + ); + } + + template<typename Point> + inline Point toPoint(const Foam::point& p) + { + return Point(p.x(), p.y(), p.z()); + } + +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H index 8838487f1e5..5bae06d86f1 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformalVoronoiMesh/pointFeatureEdgesTypes.H @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Class pointFeatureEdgesTypes @@ -48,28 +43,39 @@ namespace Foam \*---------------------------------------------------------------------------*/ //- Hold the types of feature edges attached to the point. -struct pointFeatureEdgesTypes +class pointFeatureEdgesTypes +: + public HashTable<label, extendedFeatureEdgeMesh::edgeStatus> { - label ptI; - label nExternal, nInternal; - label nFlat, nOpen, nMultiple, nNonFeature; + label pointLabel_; + +public: pointFeatureEdgesTypes(const label pointLabel) - { - ptI = pointLabel; - nExternal = nInternal = 0; - nFlat = nOpen = nMultiple = nNonFeature = 0; - } + : + HashTable<label, extendedFeatureEdgeMesh::edgeStatus>(), + pointLabel_(pointLabel) + {} + friend Ostream& operator<<(Ostream& os, const pointFeatureEdgesTypes& p) { - os << "E " << "I " << "F " << "O " << "M " << "N " - << "Pt" << nl - << p.nExternal << " " << p.nInternal << " " - << p.nFlat << " " << p.nOpen << " " - << p.nMultiple << " " << p.nNonFeature << " " - << p.ptI - << endl; + os << "Point = " << p.pointLabel_ << endl; + + for + ( + HashTable<label, extendedFeatureEdgeMesh::edgeStatus> + ::const_iterator iter = p.cbegin(); + iter != p.cend(); + ++iter + ) + { + os << " " + << extendedFeatureEdgeMesh::edgeStatusNames_[iter.key()] + << " = " + << iter() + << endl; + } return os; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C index 50d2384f24c..64f753fb99d 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.C @@ -117,7 +117,6 @@ Foam::conformationSurfaces::conformationSurfaces } } - word featureMethod = surfaceSubDict.lookup("featureMethod"); if (featureMethod == "extendedFeatureEdgeMesh") @@ -230,7 +229,12 @@ Foam::conformationSurfaces::conformationSurfaces // Extend the global bounds to stop the bound box sitting on the surfaces // to be conformed to - globalBounds_ = globalBounds_.extend(rndGen_, 1e-4); + //globalBounds_ = globalBounds_.extend(rndGen_, 1e-4); + + vector newSpan = 1e-4*globalBounds_.span(); + + globalBounds_.min() -= newSpan; + globalBounds_.max() += newSpan; // Look at all surfaces at determine whether the locationInMesh point is // inside or outside each, to establish a signature for the domain to be diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H index c1bdac76ba2..3acb10d53a8 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/conformationSurfaces/conformationSurfaces.H @@ -45,9 +45,6 @@ SourceFiles namespace Foam { -// Forward declaration of classes -class conformalVoronoiMesh; - /*---------------------------------------------------------------------------*\ Class conformationSurfaces Declaration \*---------------------------------------------------------------------------*/ diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C index 15c82e64c5c..e65cbea4e9e 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.C @@ -84,126 +84,42 @@ Foam::cvControls::cvControls // Controls for coarse surface conformation - const dictionary& coarseDict + const dictionary& conformationControlsDict ( - surfDict.subDict("coarseConformationControls") - ); - - const dictionary& coarseInitialDict - ( - coarseDict.subDict("initial") - ); - - const dictionary& coarseIterationDict - ( - coarseDict.subDict("iteration") + surfDict.subDict("conformationControls") ); surfacePtExclusionDistanceCoeff_ = readScalar ( - coarseInitialDict.lookup("surfacePtExclusionDistanceCoeff") - ); - - edgeSearchDistCoeffSqr_coarse_initial_ = sqr - ( - readScalar - ( - coarseInitialDict.lookup("edgeSearchDistCoeff") - ) - ); - - edgeSearchDistCoeffSqr_coarse_iteration_ = sqr - ( - readScalar - ( - coarseIterationDict.lookup("edgeSearchDistCoeff") - ) - ); - - surfacePtReplaceDistCoeffSqr_coarse_initial_ = sqr - ( - readScalar - ( - coarseInitialDict.lookup("surfacePtReplaceDistCoeff") - ) - ); - - surfacePtReplaceDistCoeffSqr_coarse_iteration_ = sqr - ( - readScalar - ( - coarseIterationDict.lookup("surfacePtReplaceDistCoeff") - ) - ); - - maxConformationIterations_coarse_ = readLabel - ( - coarseDict.lookup("maxIterations") - ); - - iterationToInitialHitRatioLimit_coarse_ = readScalar - ( - coarseDict.lookup("iterationToInitialHitRatioLimit") - ); - - // Controls for fine surface conformation - - const dictionary& fineDict - ( - surfDict.subDict("fineConformationControls") - ); - - const dictionary& fineInitialDict - ( - fineDict.subDict("initial") - ); - - const dictionary& fineIterationDict - ( - fineDict.subDict("iteration") + conformationControlsDict.lookup("surfacePtExclusionDistanceCoeff") ); - edgeSearchDistCoeffSqr_fine_initial_ = sqr + edgeSearchDistCoeffSqr_ = sqr ( readScalar ( - fineInitialDict.lookup("edgeSearchDistCoeff") + conformationControlsDict.lookup("edgeSearchDistCoeff") ) ); - edgeSearchDistCoeffSqr_fine_iteration_ = sqr + surfacePtReplaceDistCoeffSqr_ = sqr ( readScalar ( - fineIterationDict.lookup("edgeSearchDistCoeff") + conformationControlsDict.lookup("surfacePtReplaceDistCoeff") ) ); - surfacePtReplaceDistCoeffSqr_fine_initial_ = sqr + maxConformationIterations_ = readLabel ( - readScalar - ( - fineInitialDict.lookup("surfacePtReplaceDistCoeff") - ) - ); - - surfacePtReplaceDistCoeffSqr_fine_iteration_ = sqr - ( - readScalar - ( - fineIterationDict.lookup("surfacePtReplaceDistCoeff") - ) + conformationControlsDict.lookup("maxIterations") ); - maxConformationIterations_fine_ = readLabel + iterationToInitialHitRatioLimit_ = readScalar ( - fineDict.lookup("maxIterations") + conformationControlsDict.lookup("iterationToInitialHitRatioLimit") ); - iterationToInitialHitRatioLimit_fine_ = readScalar - ( - fineDict.lookup("iterationToInitialHitRatioLimit") - ); // Motion control controls @@ -279,248 +195,22 @@ Foam::cvControls::cvControls const dictionary& filteringDict(cvMeshDict_.subDict("polyMeshFiltering")); - writeTetDualMesh_ = Switch(filteringDict.lookup("writeTetDualMesh")); - - filterSizeCoeff_ = readScalar - ( - filteringDict.lookup("filterSizeCoeff") - ); - - mergeClosenessCoeff_ = readScalar - ( - filteringDict.lookup("mergeClosenessCoeff") - ); - - edgeMergeAngle_ = readScalar - ( - filteringDict.lookup("edgeMergeAngle") - ); - - continueFilteringOnBadInitialPolyMesh_ = Switch - ( - filteringDict.lookupOrDefault<Switch> - ( - "continueFilteringOnBadInitialPolyMesh", - false - ) - ); - - filterErrorReductionCoeff_ = readScalar - ( - filteringDict.lookup("filterErrorReductionCoeff") - ); - - filterCountSkipThreshold_ = readLabel - ( - filteringDict.lookup("filterCountSkipThreshold") - ); - - maxCollapseIterations_ = readLabel - ( - filteringDict.lookup("maxCollapseIterations") - ); - - maxConsecutiveEqualFaceSets_ = readLabel - ( - filteringDict.lookup("maxConsecutiveEqualFaceSets") - ); - - surfaceStepFaceAngle_ = readScalar - ( - filteringDict.lookup("surfaceStepFaceAngle") - ); - - edgeCollapseGuardFraction_ = readScalar + filterEdges_ = Switch ( - filteringDict.lookup("edgeCollapseGuardFraction") + filteringDict.lookupOrDefault<Switch>("filterEdges", true) ); - maxCollapseFaceToPointSideLengthCoeff_ = readScalar + filterFaces_ = Switch ( - filteringDict.lookup("maxCollapseFaceToPointSideLengthCoeff") + filteringDict.lookupOrDefault<Switch>("filterFaces", false) ); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -Foam::scalar Foam::cvControls::edgeSearchDistCoeffSqrInitial -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) - { - return edgeSearchDistCoeffSqr_coarse_initial_; - } - - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return edgeSearchDistCoeffSqr_fine_initial_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::edgeSearchDistCoeffSqrInitial" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; -} - - -Foam::scalar Foam::cvControls::edgeSearchDistCoeffSqrIteration -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) - { - return edgeSearchDistCoeffSqr_coarse_iteration_; - } - - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return edgeSearchDistCoeffSqr_fine_iteration_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::edgeSearchDistCoeffSqrIteration" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; -} - - -Foam::scalar Foam::cvControls::surfacePtReplaceDistCoeffSqrInitial -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) - { - return surfacePtReplaceDistCoeffSqr_coarse_initial_; - } - - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return surfacePtReplaceDistCoeffSqr_fine_initial_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::surfacePtReplaceDistCoeffSqrInitial" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; -} - - -Foam::scalar Foam::cvControls::surfacePtReplaceDistCoeffSqrIteration -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) - { - return surfacePtReplaceDistCoeffSqr_coarse_iteration_; - } - - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return surfacePtReplaceDistCoeffSqr_fine_iteration_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::surfacePtReplaceDistCoeffSqrIteration" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; -} - - -Foam::label Foam::cvControls::maxConformationIterations -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) - { - return maxConformationIterations_coarse_; - } - - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return maxConformationIterations_fine_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::maxConformationIterations" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; -} - -Foam::scalar Foam::cvControls::iterationToInitialHitRatioLimit -( - int reconfMode -) const -{ - if (reconfMode == conformalVoronoiMesh::rmCoarse) + if (filterFaces_) { - return iterationToInitialHitRatioLimit_coarse_; + filterEdges_ = Switch::ON; } - else if (reconfMode == conformalVoronoiMesh::rmFine) - { - return iterationToInitialHitRatioLimit_fine_; - } - else - { - FatalErrorIn - ( - "Foam::cvControls::iterationToInitialHitRatioLimit" - "(" - "int reconfMode" - ") const" - ) << "Unknown reconformationMode " << reconfMode - << exit(FatalError); - } - - return 0; + writeTetDualMesh_ = Switch(filteringDict.lookup("writeTetDualMesh")); } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H index 58dd06fc741..e8184753b0b 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControls.H @@ -37,6 +37,7 @@ SourceFiles #include "dictionary.H" #include "Switch.H" +#include "vector.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -106,74 +107,21 @@ class cvControls //- Distance to search for feature edges near to // surface protrusions - fraction of the local target - // cell size. Coarse conformation, initial protrusion - // tests. - scalar edgeSearchDistCoeffSqr_coarse_initial_; - - //- Distance to search for feature edges near to - // surface protrusions - fraction of the local target - // cell size. Coarse conformation, iteration - // protrusion tests. - scalar edgeSearchDistCoeffSqr_coarse_iteration_; - - //- Proximity to a feature edge where a surface hit is - // not created, only the edge conformation is created - // - fraction of the local target cell size. Coarse - // conformation, initial protrusion tests. - scalar surfacePtReplaceDistCoeffSqr_coarse_initial_; + // cell size. + scalar edgeSearchDistCoeffSqr_; //- Proximity to a feature edge where a surface hit is // not created, only the edge conformation is created - // - fraction of the local target cell size. Coarse - // conformation, iteration protrusion tests. - scalar surfacePtReplaceDistCoeffSqr_coarse_iteration_; + // - fraction of the local target cell size. + scalar surfacePtReplaceDistCoeffSqr_; - //- Maximum allowed number coarse surface conformation - // iterations. - label maxConformationIterations_coarse_; + //- Maximum allowed number surface conformation iterations. + label maxConformationIterations_; - //- Termination criterion for coarse surface - // conformation iterations. When the number of - // surface protrusions drops below this ratio of the - // initial number of protrusions. - scalar iterationToInitialHitRatioLimit_coarse_; - - - // Controls for fine surface conformation - - //- Distance to search for feature edges near to - // surface protrusions - fraction of the local target - // cell size. Fine conformation, initial protrusion - // tests. - scalar edgeSearchDistCoeffSqr_fine_initial_; - - //- Distance to search for feature edges near to - // surface protrusions - fraction of the local target - // cell size. Fine conformation, iteration protrusion - // tests. - scalar edgeSearchDistCoeffSqr_fine_iteration_; - - //- Proximity to a feature edge where a surface hit is - // not created, only the edge conformation is created - // - fraction of the local target cell size. Fine - // conformation, initial protrusion tests. - scalar surfacePtReplaceDistCoeffSqr_fine_initial_; - - //- Proximity to a feature edge where a surface hit is - // not created, only the edge conformation is created - // - fraction of the local target cell size. Fine - // conformation, iteration protrusion tests. - scalar surfacePtReplaceDistCoeffSqr_fine_iteration_; - - //- Maximum allowed number fine surface conformation - // iterations. - label maxConformationIterations_fine_; - - //- Termination criterion for fine surface conformation - // iterations. When the number of surface protrusions - // drops below this ratio of the initial number of - // protrusions. - scalar iterationToInitialHitRatioLimit_fine_; + //- Termination criterion for conformation iterations. + // When the number of surface protrusions drops below this + // ratio of the initial number of protrusions. + scalar iterationToInitialHitRatioLimit_; // Motion control controls @@ -198,6 +146,7 @@ class cvControls //- Now often to re-store the size and alignment data label sizeAndAlignmentRebuildFrequency_; + // Point insertion criteria //- Length between Delaunay vertices above which a new Dv should be @@ -223,66 +172,14 @@ class cvControls // polyMesh filtering controls - //- Write tet mesh at output time (it always writes the Voronoi) - Switch writeTetDualMesh_; + //- Activates the mesh edge filtering. On by default. + Switch filterEdges_; - //- Upper limit on the size of faces to be filtered from, - // fraction of the local target cell size - scalar filterSizeCoeff_; - - //- Upper limit on how close two dual vertices can be before - // being merged, fraction of the local target cell size - scalar mergeClosenessCoeff_; - - //- If the angle between two dual edges that are connected by a single - // point is less than this angle, then the edges will be merged into a - // single edge. - scalar edgeMergeAngle_; - - //- If the mesh quality criteria cannot be satisfied, continue - // with filtering anyway? - Switch continueFilteringOnBadInitialPolyMesh_; - - //- When a face is "bad", what fraction should the filterSizeCoeff_ be - // reduced by. Recursive, so for a filterCount value of fC, the - // filterSizeCoeff is reduced by pow(filterErrorReductionCoeff_, fC) - scalar filterErrorReductionCoeff_; - - //- Maximum number of filterCount applications before a face - // is not attempted to be filtered - label filterCountSkipThreshold_; - - //- Maximum number of permissible iterations of the face collapse - // algorithm. The value to choose will be related the maximum number - // of points on a face that is to be collapsed and how many faces - // around it need to be collapsed. - label maxCollapseIterations_; - - //- Maximum number of times an to allow an equal faceSet to be - // returned from the face quality assessment before stopping iterations - // to break an infinitie loop. - label maxConsecutiveEqualFaceSets_; - - //- The maximum allowed angle between a boundary face normal and the - // local surface normal before face will be aggressively collapsed - scalar surfaceStepFaceAngle_; - - //- Defining how close to the midpoint (M) of the projected - // vertices line a projected vertex (X) can be before making - // an edge collapse invalid - // - // X---X-g----------------M----X-----------g----X--X - // - // Only allow a collapse if all projected vertices are - // outwith edgeCollapseGuardFraction (g) of the distance form - // the face centre to the furthest vertex in the considered - // direction - scalar edgeCollapseGuardFraction_; + //- Activates the mesh face filtering. Off by default. + Switch filterFaces_; - //- The maximum allowed length of the longest edge of a face - // to enable a face to be collapsed to a point, fraction of - // the local target cell size - scalar maxCollapseFaceToPointSideLengthCoeff_; + //- Write tet mesh at output time (it always writes the Voronoi) + Switch writeTetDualMesh_; // Private Member Functions @@ -346,30 +243,17 @@ public: //- Return the surfaceConformationRebuildFrequency inline label surfaceConformationRebuildFrequency() const; - //- Return the edgeSearchDistCoeffSqr for initial - // conformation for the given reconformationMode. - scalar edgeSearchDistCoeffSqrInitial(int reconfMode) const; - - //- Return the edgeSearchDistCoeffSqr for conformation - // iterations for the given reconformationMode. - scalar edgeSearchDistCoeffSqrIteration(int reconfMode) const; + //- Return the edgeSearchDistCoeffSqr for conformation. + scalar edgeSearchDistCoeffSqr() const; - //- Return the surfacePtReplaceDistCoeffSqr for initial - // conformation for the given reconformationMode. - scalar surfacePtReplaceDistCoeffSqrInitial(int reconfMode) const; + //- Return the surfacePtReplaceDistCoeffSqr for conformation. + scalar surfacePtReplaceDistCoeffSqr() const; - //- Return the surfacePtReplaceDistCoeffSqr for - // conformation iterations for the given - // reconformationMode. - scalar surfacePtReplaceDistCoeffSqrIteration(int reconfMode) const; + //- Return the maxConformationIterations + label maxConformationIterations() const; - //- Return the maxConformationIterations for the given - // reconformationMode. - label maxConformationIterations(int reconfMode) const; - - //- Return the iterationToInitialHitRatioLimit for the - // given reconformationMode. - scalar iterationToInitialHitRatioLimit(int reconfMode) const; + //- Return the iterationToInitialHitRatioLimit + scalar iterationToInitialHitRatioLimit() const; //- Return the objOutput Switch inline Switch objOutput() const; @@ -389,6 +273,12 @@ public: //- Return the sizeAndAlignmentRebuildFrequency inline label sizeAndAlignmentRebuildFrequency() const; + //- Return the aspectRatio + inline scalar aspectRatio() const; + + //- Return the aspectRatioDirection + inline const vector& aspectRatioDirection() const; + //- Return the insertionDistCoeff inline scalar insertionDistCoeff() const; @@ -401,44 +291,14 @@ public: //- Return removalDistCoeff inline scalar removalDistCoeff() const; - //- Write tetMesh at output time - inline Switch writeTetDualMesh() const; - - //- Return the filterSizeCoeff - inline scalar filterSizeCoeff() const; + //- Filter edges at output time + inline Switch filterEdges() const; - //- Return the mergeClosenessCoeff - inline scalar mergeClosenessCoeff() const; + //- Filter faces at output time + inline Switch filterFaces() const; - //- Return the edgeMergeAngle - inline scalar edgeMergeAngle() const; - - //- Return the continueFilteringOnBadInitialPolyMesh Switch - inline Switch continueFilteringOnBadInitialPolyMesh() const; - - //- Return the filterErrorReductionCoeff - inline scalar filterErrorReductionCoeff() const; - - //- Return the maxCollapseIterations - inline label maxCollapseIterations() const; - - //- Return the maxConsecutiveEqualFaceSets - inline label maxConsecutiveEqualFaceSets() const; - - //- Return the filterCountSkipThreshold - inline label filterCountSkipThreshold() const; - - //- Return the maxCollapseIterations - inline label minCollapseFaces() const; - - //- Return the surfaceStepFaceAngle - inline scalar surfaceStepFaceAngle() const; - - //- Return the edgeCollapseGuardFraction - inline scalar edgeCollapseGuardFraction() const; - - //- Return the maxCollapseFaceToPointSideLengthCoeff - inline scalar maxCollapseFaceToPointSideLengthCoeff() const; + //- Write tetMesh at output time + inline Switch writeTetDualMesh() const; }; diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H index 50df7e8f584..befc7b5666a 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/cvControls/cvControlsI.H @@ -88,6 +88,30 @@ inline Foam::label Foam::cvControls::surfaceConformationRebuildFrequency() const } +inline Foam::scalar Foam::cvControls::edgeSearchDistCoeffSqr() const +{ + return edgeSearchDistCoeffSqr_; +} + + +inline Foam::scalar Foam::cvControls::surfacePtReplaceDistCoeffSqr() const +{ + return surfacePtReplaceDistCoeffSqr_; +} + + +inline Foam::label Foam::cvControls::maxConformationIterations() const +{ + return maxConformationIterations_; +} + + +inline Foam::scalar Foam::cvControls::iterationToInitialHitRatioLimit() const +{ + return iterationToInitialHitRatioLimit_; +} + + inline Foam::Switch Foam::cvControls::objOutput() const { return objOutput_; @@ -148,77 +172,19 @@ inline Foam::scalar Foam::cvControls::removalDistCoeff() const } -inline Foam::Switch Foam::cvControls::writeTetDualMesh() const -{ - return writeTetDualMesh_; -} - - -inline Foam::scalar Foam::cvControls::filterSizeCoeff() const -{ - return filterSizeCoeff_; -} - - -inline Foam::scalar Foam::cvControls::mergeClosenessCoeff() const -{ - return mergeClosenessCoeff_; -} - - -inline Foam::scalar Foam::cvControls::edgeMergeAngle() const -{ - return edgeMergeAngle_; -} - - -inline Foam::Switch -Foam::cvControls::continueFilteringOnBadInitialPolyMesh() const +inline Foam::Switch Foam::cvControls::filterEdges() const { - return continueFilteringOnBadInitialPolyMesh_; + return filterEdges_; } - -inline Foam::scalar Foam::cvControls::filterErrorReductionCoeff() const +inline Foam::Switch Foam::cvControls::filterFaces() const { - return filterErrorReductionCoeff_; + return filterFaces_; } - -inline Foam::label Foam::cvControls::filterCountSkipThreshold() const -{ - return filterCountSkipThreshold_; -} - - -inline Foam::label Foam::cvControls::maxCollapseIterations() const -{ - return maxCollapseIterations_; -} - - -inline Foam::label Foam::cvControls::maxConsecutiveEqualFaceSets() const -{ - return maxConsecutiveEqualFaceSets_; -} - - -inline Foam::scalar Foam::cvControls::surfaceStepFaceAngle() const -{ - return surfaceStepFaceAngle_; -} - - -inline Foam::scalar Foam::cvControls::edgeCollapseGuardFraction() const -{ - return edgeCollapseGuardFraction_; -} - - -inline Foam::scalar -Foam::cvControls::maxCollapseFaceToPointSideLengthCoeff() const +inline Foam::Switch Foam::cvControls::writeTetDualMesh() const { - return maxCollapseFaceToPointSideLengthCoeff_; + return writeTetDualMesh_; } diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C index 2b7d83f2b2a..0aace4f77fc 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/autoDensity/autoDensity.C @@ -339,7 +339,7 @@ bool Foam::autoDensity::fillBox pointField corners(bb.points()); - scalarField cornerSizes = cvMesh_.cellSizeControl().cellSize(corners); + scalarField cornerSizes = cvMesh_.cellShapeControls().cellSize(corners); Field<bool> insideCorners = combinedWellInside(corners, cornerSizes); @@ -448,7 +448,7 @@ bool Foam::autoDensity::fillBox ); } - lineSizes = cvMesh_.cellSizeControl().cellSize(linePoints); + lineSizes = cvMesh_.cellShapeControls().cellSize(linePoints); Field<bool> insideLines = combinedWellInside ( @@ -547,7 +547,7 @@ bool Foam::autoDensity::fillBox // corner when only some these points are required. shuffle(samplePoints); - scalarField sampleSizes = cvMesh_.cellSizeControl().cellSize + scalarField sampleSizes = cvMesh_.cellShapeControls().cellSize ( samplePoints ); @@ -713,7 +713,7 @@ bool Foam::autoDensity::fillBox point p = min + cmptMultiply(span, rnd.vector01()); - scalar localSize = cvMesh_.cellSizeControl().cellSize(p); + scalar localSize = cvMesh_.cellShapeControls().cellSize(p); bool insidePoint = false; diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C index 751a743e6d9..c69e7ac8fb3 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/bodyCentredCubic/bodyCentredCubic.C @@ -167,7 +167,7 @@ List<Vb::Point> bodyCentredCubic::initialPoints() const minimumSurfaceDistanceCoeffSqr_ *sqr ( - cvMesh_.cellSizeControl().cellSize(points) + cvMesh_.cellShapeControls().cellSize(points) ) ); diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C index a1c1f383b06..af2e7dfbf4d 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/faceCentredCubic/faceCentredCubic.C @@ -228,7 +228,7 @@ List<Vb::Point> faceCentredCubic::initialPoints() const minimumSurfaceDistanceCoeffSqr_ *sqr ( - cvMesh_.cellSizeControl().cellSize(points) + cvMesh_.cellShapeControls().cellSize(points) ) ); diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C index eb67cf60e24..19861f3e817 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/pointFile/pointFile.C @@ -132,7 +132,7 @@ List<Vb::Point> pointFile::initialPoints() const minimumSurfaceDistanceCoeffSqr_ *sqr ( - cvMesh_.cellSizeControl().cellSize(points) + cvMesh_.cellShapeControls().cellSize(points) ) ); diff --git a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C index 3bc914ea43b..2538c90702d 100644 --- a/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C +++ b/applications/utilities/mesh/generation/cvMesh/conformalVoronoiMesh/initialPointsMethod/uniformGrid/uniformGrid.C @@ -144,7 +144,7 @@ List<Vb::Point> uniformGrid::initialPoints() const minimumSurfaceDistanceCoeffSqr_ *sqr ( - cvMesh_.cellSizeControl().cellSize(points) + cvMesh_.cellShapeControls().cellSize(points) ) ); diff --git a/applications/utilities/mesh/generation/cvMesh/cvMesh.C b/applications/utilities/mesh/generation/cvMesh/cvMesh.C index f15ebea29ab..cf21964271a 100644 --- a/applications/utilities/mesh/generation/cvMesh/cvMesh.C +++ b/applications/utilities/mesh/generation/cvMesh/cvMesh.C @@ -21,11 +21,6 @@ License You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - As a special exception, you have permission to link this program with the - CGAL library and distribute executables, as long as you follow the - requirements of the GNU GPL in regard to all of the software in the - executable aside from CGAL. - Application cvMesh @@ -44,11 +39,6 @@ using namespace Foam; int main(int argc, char *argv[]) { - argList::addBoolOption - ( - "noFilter", - "Do not filter the mesh" - ); Foam::argList::addBoolOption ( "checkGeometry", @@ -60,11 +50,8 @@ int main(int argc, char *argv[]) runTime.functionObjects().off(); - const bool noFilter = !args.optionFound("noFilter"); const bool checkGeometry = args.optionFound("checkGeometry"); - Info<< "Mesh filtering is " << (noFilter ? "on" : "off") << endl; - IOdictionary cvMeshDict ( IOobject @@ -112,15 +99,9 @@ int main(int argc, char *argv[]) Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" - << nl << endl; + << endl; } - mesh.writeMesh(runTime.constant(), noFilter); - - Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s" - << " ClockTime = " << runTime.elapsedClockTime() << " s" - << nl << endl; - Info<< nl << "End" << nl << endl; return 0; diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options index ed71a800294..0322435c8c9 100644 --- a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options @@ -14,14 +14,14 @@ EXE_INC = \ -I$(LIB_SRC)/triSurface/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \ - -I$(LIB_SRC)/fileFormats/lnInclude \ - -I$(LIB_SRC)/sampling/lnInclude \ - -I$(LIB_SRC)/dynamicMesh/lnInclude + -I$(LIB_SRC)/dynamicMesh/lnInclude \ + -I../vectorTools EXE_LIBS = \ $(CGAL_LIBS) \ -lboost_thread \ -lmpfr \ + -lgmp \ -lconformalVoronoiMesh \ -ldecompositionMethods /* -L$(FOAM_LIBBIN)/dummy -lscotchDecomp */ \ -ledgeMesh \ diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C index 485c5568b48..53766c59a02 100644 --- a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C @@ -36,7 +36,7 @@ Description #include "triSurface.H" #include "searchableSurfaces.H" #include "conformationSurfaces.H" -#include "cellSizeControlSurfaces.H" +#include "cellShapeControl.H" #include "backgroundMeshDecomposition.H" #include "cellShape.H" #include "cellModeller.H" @@ -450,10 +450,15 @@ int main(int argc, char *argv[]) cvMeshDict.subDict("surfaceConformation") ); - cellSizeControlSurfaces cellSizeControl + autoPtr<cellShapeControl> cellShapeControls ( - allGeometry, - cvMeshDict.subDict("motionControl") + cellShapeControl::New + ( + runTime, + cvMeshDict.subDict("motionControl"), + allGeometry, + geometryToConformTo + ) ); @@ -464,7 +469,7 @@ int main(int argc, char *argv[]) // Determine the number of cells in each direction. const vector span = bb.span(); - vector nScalarCells = span/cellSizeControl.defaultCellSize(); + vector nScalarCells = span/cellShapeControls().defaultCellSize(); // Calculate initial cell size to be a little bit smaller than the // defaultCellSize to avoid initial refinement triggering. @@ -580,7 +585,7 @@ int main(int argc, char *argv[]) 20.0, //maxCellWeightCoeff runTime, geometryToConformTo, - cellSizeControl, + cellShapeControls(), rndGen, cvMeshDict ); diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshDict b/applications/utilities/mesh/generation/cvMesh/cvMeshDict index 513d73573ba..28f3b0043bc 100644 --- a/applications/utilities/mesh/generation/cvMesh/cvMeshDict +++ b/applications/utilities/mesh/generation/cvMesh/cvMeshDict @@ -263,7 +263,7 @@ initialPoints // It determines the cell size given a location. It then uses all // the rules // - defaultCellSize -// - cellSizeControlGeometry +// - cellShapeControl // to determine target cell size. Rule with highest priority wins. If same // priority smallest cell size wins. motionControl @@ -271,10 +271,28 @@ motionControl // Absolute cell size of back ground mesh. This is the maximum cell size. defaultCellSize 0.00075; - // Assign a priority to all requests for cell sizes, the highest overrules. - defaultPriority 0; + //cellShapeControl constantControl; + //cellShapeControl fileControl; + cellShapeControl surfaceControl; - cellSizeControlGeometry + // Provide constant values for cell size and alignment + constantControlCoeffs + { + cellSize 0.00075; + cellAlignment (1 0 0 0 1 0 0 0 1); + } + + // Read in the points of the background grid used for cell shape control + // from a file, with corresponding files for alignment and size + fileControlCoeffs + { + pointFile ""; + sizesFile ""; + alignmentsFile ""; + } + + // Calculate the sizes and alignments from surfaces + surfaceControlCoeffs { ref7_outside { @@ -319,6 +337,16 @@ motionControl } } + // Provide an aspect ratio and the direction in which it acts on the mesh. + // Default is 1.0 if this section is not present in the dictionary + cellAspectRatioControl + { + // Aspect ratio. + aspectRatio 2.0; + // Direction of action of the aspect ratio + aspectRatioDirection (1 0 0); + } + // Underrelaxation for point motion. Simulated annealing: starts off at 1 // and lowers to 0 (at simulation endTime) to converge points. // adaptiveLinear is preferred choice. @@ -396,6 +424,12 @@ motionControl // Do not change. See cvControls.H polyMeshFiltering { + // Filter small edges + filterEdges on; + + // Filter small and sliver faces + filterFaces off; + // Write the underlying Delaunay tet mesh at output time writeTetDualMesh false; //true; diff --git a/wmake/rules/General/CGAL b/wmake/rules/General/CGAL index cfb02d716ab..167a420ab6d 100644 --- a/wmake/rules/General/CGAL +++ b/wmake/rules/General/CGAL @@ -7,4 +7,5 @@ CGAL_INC = \ CGAL_LIBS = \ -L$(MPFR_ARCH_PATH)/lib \ + -L$(GMP_ARCH_PATH)/lib \ -L$(BOOST_ARCH_PATH)/lib -- GitLab