From 92a66ebc61dcb3fb3fca95909f84260a0111703c Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Mon, 2 Apr 2012 10:56:59 +0100
Subject: [PATCH] ENH: cvMeshbackgroundMesh: cleaned up building

---
 .../cvMesh/cvMeshBackgroundMesh/Make/files    |   3 +
 .../cvMesh/cvMeshBackgroundMesh/Make/options  |  31 +
 .../cvMeshBackgroundMesh.C                    | 920 ++++++++++++++++++
 3 files changed, 954 insertions(+)
 create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/files
 create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options
 create mode 100644 applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C

diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/files b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/files
new file mode 100644
index 00000000000..58406b931af
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/files
@@ -0,0 +1,3 @@
+cvMeshBackgroundMesh.C
+
+EXE = $(FOAM_APPBIN)/cvMeshBackgroundMesh
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options
new file mode 100644
index 00000000000..0e2d0c9f0ac
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/Make/options
@@ -0,0 +1,31 @@
+/*
+EXE_DEBUG = -DFULLDEBUG -g -O0
+EXE_FROUNDING_MATH = -frounding-math
+EXE_NDEBUG = -DNDEBUG
+*/
+
+include $(GENERAL_RULES)/CGAL
+
+EXE_INC = \
+    ${EXE_FROUNDING_MATH} \
+    ${EXE_NDEBUG} \
+    ${CGAL_INC} \
+    -I../conformalVoronoiMesh/lnInclude \
+    -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
+    -I$(LIB_SRC)/edgeMesh/lnInclude \
+    -I$(LIB_SRC)/sampling/lnInclude \
+    -I$(LIB_SRC)/triSurface/lnInclude \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/dynamicMesh/lnInclude
+
+EXE_LIBS = \
+    $(CGAL_LIBS) \
+    -lconformalVoronoiMesh \
+    -ldecompositionMethods /* -L$(FOAM_LIBBIN)/dummy -lscotchDecomp */ \
+    -ledgeMesh \
+    -ltriSurface \
+    -lmeshTools \
+    -ldynamicMesh \
+    -lsampling \
+    -lfiniteVolume
diff --git a/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.C
new file mode 100644
index 00000000000..c2642366a92
--- /dev/null
+++ b/applications/utilities/mesh/generation/cvMesh/cvMeshBackgroundMesh/cvMeshBackgroundMesh.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/>.
+
+Application
+    cvMeshBackGroundMesh
+
+Description
+    Writes out background mesh as constructed by cvMesh and constructs
+    distanceSurface.
+
+\*---------------------------------------------------------------------------*/
+
+#include "PatchTools.H"
+#include "argList.H"
+#include "Time.H"
+#include "triSurface.H"
+#include "searchableSurfaces.H"
+#include "conformationSurfaces.H"
+#include "cellSizeControlSurfaces.H"
+#include "backgroundMeshDecomposition.H"
+#include "cellShape.H"
+#include "cellModeller.H"
+#include "DynamicField.H"
+#include "isoSurfaceCell.H"
+#include "vtkSurfaceWriter.H"
+#include "syncTools.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Tolerance (as fraction of the bounding box). Needs to be fairly lax since
+// usually meshes get written with limited precision (6 digits)
+static const scalar defaultMergeTol = 1E-6;
+
+// Get merging distance when matching face centres
+scalar getMergeDistance
+(
+    const argList& args,
+    const Time& runTime,
+    const boundBox& bb
+)
+{
+    scalar mergeTol = defaultMergeTol;
+    args.optionReadIfPresent("mergeTol", mergeTol);
+
+    scalar writeTol =
+        Foam::pow(scalar(10.0), -scalar(IOstream::defaultPrecision()));
+
+    Info<< "Merge tolerance : " << mergeTol << nl
+        << "Write tolerance : " << writeTol << endl;
+
+    if (runTime.writeFormat() == IOstream::ASCII && mergeTol < writeTol)
+    {
+        FatalErrorIn("getMergeDistance")
+            << "Your current settings specify ASCII writing with "
+            << IOstream::defaultPrecision() << " digits precision." << endl
+            << "Your merging tolerance (" << mergeTol << ") is finer than this."
+            << endl
+            << "Please change your writeFormat to binary"
+            << " or increase the writePrecision" << endl
+            << "or adjust the merge tolerance (-mergeTol)."
+            << exit(FatalError);
+    }
+
+    scalar mergeDist = mergeTol * bb.mag();
+
+    Info<< "Overall meshes bounding box : " << bb << nl
+        << "Relative tolerance          : " << mergeTol << nl
+        << "Absolute matching distance  : " << mergeDist << nl
+        << endl;
+
+    return mergeDist;
+}
+
+
+void printMeshData(const polyMesh& mesh)
+{
+    // Collect all data on master
+
+    globalIndex globalCells(mesh.nCells());
+    labelListList patchNeiProcNo(Pstream::nProcs());
+    labelListList patchSize(Pstream::nProcs());
+    const labelList& pPatches = mesh.globalData().processorPatches();
+    patchNeiProcNo[Pstream::myProcNo()].setSize(pPatches.size());
+    patchSize[Pstream::myProcNo()].setSize(pPatches.size());
+    forAll(pPatches, i)
+    {
+        const processorPolyPatch& ppp = refCast<const processorPolyPatch>
+        (
+            mesh.boundaryMesh()[pPatches[i]]
+        );
+        patchNeiProcNo[Pstream::myProcNo()][i] = ppp.neighbProcNo();
+        patchSize[Pstream::myProcNo()][i] = ppp.size();
+    }
+    Pstream::gatherList(patchNeiProcNo);
+    Pstream::gatherList(patchSize);
+
+
+    // Print stats
+
+    globalIndex globalBoundaryFaces(mesh.nFaces()-mesh.nInternalFaces());
+
+    label maxProcCells = 0;
+    label totProcFaces = 0;
+    label maxProcPatches = 0;
+    label totProcPatches = 0;
+    label maxProcFaces = 0;
+
+    for (label procI = 0; procI < Pstream::nProcs(); procI++)
+    {
+        Info<< endl
+            << "Processor " << procI << nl
+            << "    Number of cells = " << globalCells.localSize(procI)
+            << endl;
+
+        label nProcFaces = 0;
+
+        const labelList& nei = patchNeiProcNo[procI];
+
+        forAll(patchNeiProcNo[procI], i)
+        {
+            Info<< "    Number of faces shared with processor "
+                << patchNeiProcNo[procI][i] << " = " << patchSize[procI][i]
+                << endl;
+
+            nProcFaces += patchSize[procI][i];
+        }
+
+        Info<< "    Number of processor patches = " << nei.size() << nl
+            << "    Number of processor faces = " << nProcFaces << nl
+            << "    Number of boundary faces = "
+            << globalBoundaryFaces.localSize(procI) << endl;
+
+        maxProcCells = max(maxProcCells, globalCells.localSize(procI));
+        totProcFaces += nProcFaces;
+        totProcPatches += nei.size();
+        maxProcPatches = max(maxProcPatches, nei.size());
+        maxProcFaces = max(maxProcFaces, nProcFaces);
+    }
+
+    // Stats
+
+    scalar avgProcCells = scalar(globalCells.size())/Pstream::nProcs();
+    scalar avgProcPatches = scalar(totProcPatches)/Pstream::nProcs();
+    scalar avgProcFaces = scalar(totProcFaces)/Pstream::nProcs();
+
+    // In case of all faces on one processor. Just to avoid division by 0.
+    if (totProcPatches == 0)
+    {
+        avgProcPatches = 1;
+    }
+    if (totProcFaces == 0)
+    {
+        avgProcFaces = 1;
+    }
+
+    Info<< nl
+        << "Number of processor faces = " << totProcFaces/2 << nl
+        << "Max number of cells = " << maxProcCells
+        << " (" << 100.0*(maxProcCells-avgProcCells)/avgProcCells
+        << "% above average " << avgProcCells << ")" << nl
+        << "Max number of processor patches = " << maxProcPatches
+        << " (" << 100.0*(maxProcPatches-avgProcPatches)/avgProcPatches
+        << "% above average " << avgProcPatches << ")" << nl
+        << "Max number of faces between processors = " << maxProcFaces
+        << " (" << 100.0*(maxProcFaces-avgProcFaces)/avgProcFaces
+        << "% above average " << avgProcFaces << ")" << nl
+        << endl;
+}
+
+
+// Return cellID
+label cellLabel
+(
+    const Vector<label>& nCells,
+    const label i,
+    const label j,
+    const label k
+)
+{
+    return i*nCells[1]*nCells[2]+j*nCells[2]+k;
+}
+
+label vtxLabel
+(
+    const Vector<label>& nCells,
+    const label i,
+    const label j,
+    const label k
+)
+{
+    Vector<label> nPoints
+    (
+        nCells[0]+1,
+        nCells[1]+1,
+        nCells[2]+1
+    );
+    return i*nPoints[1]*nPoints[2]+j*nPoints[2]+k;
+}
+
+
+//// Generate hex mesh around surface.
+//void setRefinement
+//(
+//    const vector& cellSize,
+//    const Vector<label>& nCells
+//    polyTopoChange& meshMod
+//)
+//{
+//    const treeBoundBox& bb = geometryToConformTo.globalBounds();
+//
+//    // Determine the number of cells in each direction.
+//    vector nScalarCells = bb.span()/cellSizeControl.defaultCellSize();
+//    Vector<label> nCells
+//    (
+//        label(nScalarCells[0]),
+//        label(nScalarCells[1]),
+//        label(nScalarCells[2])
+//    );
+//    vector cellSize(bb.span()/nCells);
+//
+//    const label nPatches = 1;
+//    polyTopoChange meshMod(nPatches);
+//
+//    // Generate points
+//    for (label i = 0; i <= nCells[0]; i++)
+//    {
+//        for (label j = 0; j <= nCells[1]; j++)
+//        {
+//            for (label k = 0; k <= nCells[2]; k++)
+//            {
+//                meshMod.addPoint
+//                (
+//                    bb.min()+i*cellSize[0]+j*cellSize[1]+k*cellSize[2],
+//                    -1, // masterPointID,
+//                    -1, // zoneID,
+//                    true
+//                );
+//            }
+//        }
+//    }
+//
+//    // Generate cells such that cell
+//    for (label i = 0; i < nCells[0]; i++)
+//    {
+//        for (label j = 0; j < nCells[1]; j++)
+//        {
+//            for (label k = 0; k < nCells[2]; k++)
+//            {
+//                meshMod.addCell
+//                (
+//                    -1, // masterPointID,
+//                    -1, // masterEdgeID,
+//                    -1, // masterFaceID,
+//                    -1, // masterCellID,
+//                    -1  //zoneID
+//                );
+//            }
+//        }
+//    }
+//
+//    // Generate internal faces
+//    face f(4);
+//
+//    // Internal faces between i and i+1
+//    for (label i = 0; i < nCells[0]-1; i++)
+//    {
+//        for (label j = 0; j < nCells[1]-1; j++)
+//        {
+//            for (label k = 0; k < nCells[2]-1; k++)
+//            {
+//                face[0] = vertexID(nCells, i, j, k);
+//                face[1] = vertexID(nCells, i, j+1, k);
+//                face[2] = vertexID(nCells, i, j+1, k+1);
+//                face[3] = vertexID(nCells, i, j, k+1);
+//
+//                meshMod.addFace
+//                (
+//                    f,
+//                    cellID(nCells, i,j, k),     //own
+//                    cellID(nCells, i+1,j, k+1), //nei
+//                    -1,     //masterPointID,
+//                    -1,     //masterEdgeID,
+//                    -1,     //masterFaceID,
+//                    false,  //flipFaceFlux,
+//                    -1,     //patchID,
+//                    -1,       //zoneID,
+//                    false   //zoneFlip
+//                );
+//            }
+//        }
+//    }
+//    // Internal faces between j and j+1
+//    for (label i = 0; i < nCells[0]-1; i++)
+//    {
+//        for (label j = 0; j < nCells[1]-1; j++)
+//        {
+//            for (label k = 0; k < nCells[2]-1; k++)
+//            {
+//                face[0] = vertexID(nCells, i, j, k);
+//                face[1] = vertexID(nCells, i, j, k+1);
+//                face[2] = vertexID(nCells, i+1, j, k+1);
+//                face[3] = vertexID(nCells, i+1, j, k);
+//
+//                meshMod.addFace
+//                (
+//                    f,
+//                    cellID(nCells, i,j, k),     //own
+//                    cellID(nCells, i,j+1, k+1), //nei
+//                    -1,     //masterPointID,
+//                    -1,     //masterEdgeID,
+//                    -1,     //masterFaceID,
+//                    false,  //flipFaceFlux,
+//                    -1,     //patchID,
+//                    -1,       //zoneID,
+//                    false   //zoneFlip
+//                );
+//            }
+//        }
+//    }
+//    // Internal faces between k and k+1
+//    for (label i = 0; i < nCells[0]-1; i++)
+//    {
+//        for (label j = 0; j < nCells[1]-1; j++)
+//        {
+//            for (label k = 0; k < nCells[2]-1; k++)
+//            {
+//                face[0] = vertexID(nCells, i, j, k);
+//                face[1] = vertexID(nCells, i+1, j, k);
+//                face[2] = vertexID(nCells, i+1, j+1, k);
+//                face[3] = vertexID(nCells, i, j+1, k);
+//
+//                meshMod.addFace
+//                (
+//                    f,
+//                    cellID(nCells, i,j, k),     //own
+//                    cellID(nCells, i,j, k+1),   //nei
+//                    -1,     //masterPointID,
+//                    -1,     //masterEdgeID,
+//                    -1,     //masterFaceID,
+//                    false,  //flipFaceFlux,
+//                    -1,     //patchID,
+//                    -1,       //zoneID,
+//                    false   //zoneFlip
+//                );
+//            }
+//        }
+//    }
+//}
+
+
+autoPtr<polyMesh> generateHexMesh
+(
+    const IOobject& io,
+    const point& origin,
+    const vector& cellSize,
+    const Vector<label>& nCells
+)
+{
+    pointField points;
+    if (nCells[0]+nCells[1]+nCells[2] > 0)
+    {
+        points.setSize((nCells[0]+1)*(nCells[1]+1)*(nCells[2]+1));
+
+        // Generate points
+        for (label i = 0; i <= nCells[0]; i++)
+        {
+            for (label j = 0; j <= nCells[1]; j++)
+            {
+                for (label k = 0; k <= nCells[2]; k++)
+                {
+                    point pt = origin;
+                    pt.x() += i*cellSize[0];
+                    pt.y() += j*cellSize[1];
+                    pt.z() += k*cellSize[2];
+                    points[vtxLabel(nCells, i, j, k)] = pt;
+                }
+            }
+        }
+    }
+
+
+    const cellModel& hex = *(cellModeller::lookup("hex"));
+    cellShapeList cellShapes(nCells[0]*nCells[1]*nCells[2]);
+
+    labelList hexPoints(8);
+    label cellI = 0;
+    for (label i = 0; i < nCells[0]; i++)
+    {
+        for (label j = 0; j < nCells[1]; j++)
+        {
+            for (label k = 0; k < nCells[2]; k++)
+            {
+                hexPoints[0] = vtxLabel(nCells, i,   j,   k);
+                hexPoints[1] = vtxLabel(nCells, i+1, j,   k);
+                hexPoints[2] = vtxLabel(nCells, i+1, j+1, k);
+                hexPoints[3] = vtxLabel(nCells, i,   j+1, k);
+                hexPoints[4] = vtxLabel(nCells, i,   j,   k+1);
+                hexPoints[5] = vtxLabel(nCells, i+1, j,   k+1);
+                hexPoints[6] = vtxLabel(nCells, i+1, j+1, k+1);
+                hexPoints[7] = vtxLabel(nCells, i,   j+1, k+1);
+                cellShapes[cellI++] = cellShape(hex, hexPoints);
+            }
+        }
+    }
+
+    faceListList boundary(0);
+    wordList patchNames(0);
+    wordList patchTypes(0);
+    word defaultFacesName = "defaultFaces";
+    word defaultFacesType = polyPatch::typeName;
+    wordList patchPhysicalTypes(0);
+
+    return autoPtr<polyMesh>
+    (
+        new polyMesh
+        (
+            io,
+            xferMoveTo<pointField>(points),
+            cellShapes,
+            boundary,
+            patchNames,
+            patchTypes,
+            defaultFacesName,
+            defaultFacesType,
+            patchPhysicalTypes
+        )
+    );
+}
+
+
+// Determine for every point a signed distance to the nearest surface
+// (outside is positive)
+tmp<scalarField> signedDistance
+(
+    const scalarField& distSqr,
+    const pointField& points,
+    const searchableSurfaces& geometry,
+    const labelList& surfaces
+)
+{
+    tmp<scalarField> tfld(new scalarField(points.size(), Foam::sqr(GREAT)));
+    scalarField& fld = tfld();
+
+    // Find nearest
+    List<pointIndexHit> nearest;
+    labelList nearestSurfaces;
+    searchableSurfacesQueries::findNearest
+    (
+        geometry,
+        surfaces,
+        points,
+        scalarField(points.size(), Foam::sqr(GREAT)),//distSqr
+        nearestSurfaces,
+        nearest
+    );
+
+    // Determine sign of nearest. Sort by surface to do this.
+    DynamicField<point> surfPoints(points.size());
+    DynamicList<label> surfIndices(points.size());
+
+    forAll(surfaces, surfI)
+    {
+        // Extract points on this surface
+        surfPoints.clear();
+        surfIndices.clear();
+        forAll(nearestSurfaces, i)
+        {
+            if (nearestSurfaces[i] == surfI)
+            {
+                surfPoints.append(points[i]);
+                surfIndices.append(i);
+            }
+        }
+
+        // Calculate sideness of these surface points
+        label geomI = surfaces[surfI];
+        List<searchableSurface::volumeType> volType;
+        geometry[geomI].getVolumeType(surfPoints, volType);
+
+        // Push back to original
+        forAll(volType, i)
+        {
+            label pointI = surfIndices[i];
+            scalar dist = mag(points[pointI] - nearest[pointI].hitPoint());
+
+            searchableSurface::volumeType vT = volType[i];
+
+            if (vT == searchableSurface::OUTSIDE)
+            {
+                fld[pointI] = dist;
+            }
+            else if (vT == searchableSurface::INSIDE)
+            {
+                fld[i] = -dist;
+            }
+            else
+            {
+                FatalErrorIn("signedDistance()")
+                    << "getVolumeType failure, neither INSIDE or OUTSIDE"
+                    << exit(FatalError);
+            }
+        }
+    }
+
+    return tfld;
+}
+
+
+
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::addNote
+    (
+        "Generate cvMesh-consistent representation of surfaces"
+    );
+    argList::addBoolOption
+    (
+        "writeMesh",
+        "write the resulting mesh and distance fields"
+    );
+    argList::addOption
+    (
+        "mergeTol",
+        "scalar",
+        "specify the merge distance relative to the bounding box size "
+        "(default 1E-6)"
+    );
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+    runTime.functionObjects().off();
+
+    const bool writeMesh = args.optionFound("writeMesh");
+
+    if (writeMesh)
+    {
+        Info<< "Writing resulting mesh and cellDistance, pointDistance fields."
+            << nl << endl;
+    }
+
+
+    IOdictionary cvMeshDict
+    (
+        IOobject
+        (
+            "cvMeshDict",
+            runTime.system(),
+            runTime,
+            IOobject::MUST_READ_IF_MODIFIED,
+            IOobject::NO_WRITE
+        )
+    );
+
+    // Define/load all geometry
+    searchableSurfaces allGeometry
+    (
+        IOobject
+        (
+            "cvSearchableSurfaces",
+            runTime.constant(),
+            "triSurface",
+            runTime,
+            IOobject::MUST_READ,
+            IOobject::NO_WRITE
+        ),
+        cvMeshDict.subDict("geometry")
+    );
+
+    Random rndGen(64293*Pstream::myProcNo());
+
+    conformationSurfaces geometryToConformTo
+    (
+        runTime,
+        rndGen,
+        allGeometry,
+        cvMeshDict.subDict("surfaceConformation")
+    );
+
+    cellSizeControlSurfaces cellSizeControl
+    (
+        allGeometry,
+        cvMeshDict.subDict("motionControl")
+    );
+
+
+    // Generate starting block mesh
+    vector cellSize;
+    {
+        const treeBoundBox& bb = geometryToConformTo.globalBounds();
+
+        // Determine the number of cells in each direction.
+        const vector span = bb.span();
+        vector nScalarCells = span/cellSizeControl.defaultCellSize();
+
+        // Calculate initial cell size to be a little bit smaller than the
+        // defaultCellSize to avoid initial refinement triggering.
+        Vector<label> nCells = Vector<label>
+        (
+            label(nScalarCells.x())+2,
+            label(nScalarCells.y())+2,
+            label(nScalarCells.z())+2
+        );
+        cellSize = vector
+        (
+            span[0]/nCells[0],
+            span[1]/nCells[1],
+            span[2]/nCells[2]
+        );
+
+        Info<< "Generating initial hex mesh with" << nl
+            << "    bounding box : " << bb << nl
+            << "    nCells       : " << nCells << nl
+            << "    cellSize     : " << cellSize << nl
+            << endl;
+
+        autoPtr<polyMesh> meshPtr
+        (
+            generateHexMesh
+            (
+                IOobject
+                (
+                    polyMesh::defaultRegion,
+                    runTime.constant(),
+                    runTime
+                ),
+                bb.min(),
+                cellSize,
+                (
+                    Pstream::master()
+                  ? nCells
+                  : Vector<label>(0, 0, 0)
+                )
+            )
+        );
+        Info<< "Writing initial hex mesh to " << meshPtr().instance() << nl
+            << endl;
+        meshPtr().write();
+    }
+
+    // Distribute the initial mesh
+    if (Pstream::parRun())
+    {
+#       include "createMesh.H"
+        Info<< "Loaded mesh:" << endl;
+        printMeshData(mesh);
+
+        // Allocate a decomposer
+        IOdictionary decompositionDict
+        (
+            IOobject
+            (
+                "decomposeParDict",
+                runTime.system(),
+                mesh,
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE
+            )
+        );
+
+        autoPtr<decompositionMethod> decomposer
+        (
+            decompositionMethod::New
+            (
+                decompositionDict
+            )
+        );
+
+        labelList decomp = decomposer().decompose(mesh, mesh.cellCentres());
+
+        // Global matching tolerance
+        const scalar tolDim = getMergeDistance
+        (
+            args,
+            runTime,
+            mesh.bounds()
+        );
+
+        // Mesh distribution engine
+        fvMeshDistribute distributor(mesh, tolDim);
+
+        Info<< "Wanted distribution:"
+            << distributor.countCells(decomp) << nl << endl;
+
+        // Do actual sending/receiving of mesh
+        autoPtr<mapDistributePolyMesh> map = distributor.distribute(decomp);
+
+        // Print some statistics
+        //Info<< "After distribution:" << endl;
+        //printMeshData(mesh);
+
+        mesh.setInstance(runTime.constant());
+        Info<< "Writing redistributed mesh" << nl << endl;
+        mesh.write();
+    }
+
+
+    Info<< "Refining backgroud mesh according to cell size specification" << nl
+        << endl;
+
+    backgroundMeshDecomposition backgroundMesh
+    (
+        1.0,    //spanScale,ratio of poly cell size v.s. hex cell size
+        0.0,    //minCellSizeLimit
+        0,      //minLevels
+        4,      //volRes, check multiple points per cell
+        20.0,   //maxCellWeightCoeff
+        runTime,
+        geometryToConformTo,
+        cellSizeControl,
+        rndGen,
+        cvMeshDict
+    );
+
+    if (writeMesh)
+    {
+        runTime++;
+        Info<< "Writing mesh to " << runTime.timeName() << endl;
+        backgroundMesh.mesh().write();
+    }
+
+    const scalar tolDim = getMergeDistance
+    (
+        args,
+        runTime,
+        backgroundMesh.mesh().bounds()
+    );
+
+
+    faceList isoFaces;
+    pointField isoPoints;
+
+    {
+        // Apply a distanceSurface to it.
+        const fvMesh& fvm = backgroundMesh.mesh();
+
+        volScalarField cellDistance
+        (
+            IOobject
+            (
+                "cellDistance",
+                fvm.time().timeName(),
+                fvm.time(),
+                IOobject::NO_READ,
+                IOobject::NO_WRITE,
+                false
+            ),
+            fvm,
+            dimensionedScalar("zero", dimLength, 0)
+        );
+
+        const searchableSurfaces& geometry = geometryToConformTo.geometry();
+        const labelList& surfaces = geometryToConformTo.surfaces();
+
+
+        // Get maximum search size per cell
+        scalarField distSqr(cellDistance.size());
+
+        const labelList& cellLevel = backgroundMesh.cellLevel();
+        forAll(cellLevel, cellI)
+        {
+            // The largest edge of the cell will always be less than the
+            // span of the bounding box of the cell.
+            distSqr[cellI] = magSqr(cellSize)/pow(2, cellLevel[cellI]);
+        }
+
+        {
+            // Internal field
+            cellDistance.internalField() = signedDistance
+            (
+                distSqr,
+                fvm.C(),
+                geometry,
+                surfaces
+            );
+            // Patch fields
+            forAll(fvm.C().boundaryField(), patchI)
+            {
+                const pointField& cc = fvm.C().boundaryField()[patchI];
+                fvPatchScalarField& fld = cellDistance.boundaryField()[patchI];
+                scalarField patchDistSqr
+                (
+                    fld.patch().patchInternalField(distSqr)
+                );
+                fld = signedDistance(patchDistSqr, cc, geometry, surfaces);
+            }
+
+            // On processor patches the fvm.C() will already be the cell centre
+            // on the opposite side so no need to swap cellDistance.
+
+            if (writeMesh)
+            {
+                cellDistance.write();
+            }
+        }
+
+
+        // Distance to points
+        pointScalarField pointDistance
+        (
+            IOobject
+            (
+                "pointDistance",
+                fvm.time().timeName(),
+                fvm.time(),
+                IOobject::NO_READ,
+                IOobject::NO_WRITE,
+                false
+            ),
+            pointMesh::New(fvm),
+            dimensionedScalar("zero", dimLength, 0)
+        );
+        {
+            scalarField pointDistSqr(fvm.nPoints(), -sqr(GREAT));
+            for (label faceI = 0; faceI < fvm.nInternalFaces(); faceI++)
+            {
+                label own = fvm.faceOwner()[faceI];
+                label ownDistSqr = distSqr[own];
+
+                const face& f = fvm.faces()[faceI];
+                forAll(f, fp)
+                {
+                    pointDistSqr[f[fp]] = max(pointDistSqr[f[fp]], ownDistSqr);
+                }
+            }
+            syncTools::syncPointList
+            (
+                fvm,
+                pointDistSqr,
+                maxEqOp<scalar>(),
+                -sqr(GREAT)             // null value
+            );
+
+            pointDistance.internalField() = signedDistance
+            (
+                pointDistSqr,
+                fvm.points(),
+                geometry,
+                surfaces
+            );
+
+            if (writeMesh)
+            {
+                pointDistance.write();
+            }
+        }
+
+        isoSurfaceCell iso
+        (
+            fvm,
+            cellDistance,
+            pointDistance,
+            0,      //distance,
+            false   //regularise
+        );
+
+        isoFaces.setSize(iso.size());
+        forAll(isoFaces, i)
+        {
+            isoFaces[i] = iso[i].triFaceFace();
+        }
+        isoPoints = iso.points();
+    }
+
+
+    pointField mergedPoints;
+    faceList mergedFaces;
+    labelList pointMergeMap;
+    PatchTools::gatherAndMerge
+    (
+        tolDim,
+        primitivePatch
+        (
+            SubList<face>(isoFaces, isoFaces.size()),
+            isoPoints
+        ),
+        mergedPoints,
+        mergedFaces,
+        pointMergeMap
+    );
+
+    vtkSurfaceWriter writer;
+    writer.write
+    (
+        runTime.path(),
+        "iso",
+        mergedPoints,
+        mergedFaces
+    );
+
+    Info<< "End\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
-- 
GitLab