From 134f7abd57ae1c2f6327ba27b2b3d26daaa8162d Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Mon, 8 May 2017 10:50:59 +0100
Subject: [PATCH] ENH: checkMesh: output vol fields of mesh quality. Fixes
 #466.

---
 .../mesh/manipulation/checkMesh/Make/files    |   1 +
 .../mesh/manipulation/checkMesh/checkMesh.C   |  55 ++-
 .../mesh/manipulation/checkMesh/writeFields.C | 360 ++++++++++++++++++
 .../mesh/manipulation/checkMesh/writeFields.H |  10 +
 4 files changed, 423 insertions(+), 3 deletions(-)
 create mode 100644 applications/utilities/mesh/manipulation/checkMesh/writeFields.C
 create mode 100644 applications/utilities/mesh/manipulation/checkMesh/writeFields.H

diff --git a/applications/utilities/mesh/manipulation/checkMesh/Make/files b/applications/utilities/mesh/manipulation/checkMesh/Make/files
index 21febe27891..08cbcaf0885 100644
--- a/applications/utilities/mesh/manipulation/checkMesh/Make/files
+++ b/applications/utilities/mesh/manipulation/checkMesh/Make/files
@@ -1,3 +1,4 @@
+writeFields.C
 checkTools.C
 checkTopology.C
 checkGeometry.C
diff --git a/applications/utilities/mesh/manipulation/checkMesh/checkMesh.C b/applications/utilities/mesh/manipulation/checkMesh/checkMesh.C
index 246d559c547..89aa271bfec 100644
--- a/applications/utilities/mesh/manipulation/checkMesh/checkMesh.C
+++ b/applications/utilities/mesh/manipulation/checkMesh/checkMesh.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -57,12 +57,18 @@ Usage
     Reconstruct all cellSets and faceSets geometry and write to postProcessing/
     directory according to surfaceFormat (e.g. vtk or ensight)
 
+    \param -writeAllFields \n
+    Writes all mesh quality measures as fields.
+
+    \param -writeFields '(\<fieldName\>)' \n
+    Writes selected mesh quality measures as fields.
+
 \*---------------------------------------------------------------------------*/
 
 #include "argList.H"
 #include "timeSelector.H"
 #include "Time.H"
-#include "polyMesh.H"
+#include "fvMesh.H"
 #include "globalMeshData.H"
 #include "surfaceWriter.H"
 #include "vtkSetWriter.H"
@@ -71,6 +77,7 @@ Usage
 #include "checkTopology.H"
 #include "checkGeometry.H"
 #include "checkMeshQuality.H"
+#include "writeFields.H"
 
 using namespace Foam;
 
@@ -96,6 +103,17 @@ int main(int argc, char *argv[])
         "include extra topology checks"
     );
     argList::addBoolOption
+    (
+        "writeAllFields",
+        "write volFields with mesh quality parameters"
+    );
+    argList::addOption
+    (
+        "writeFields",
+        "wordList"
+        "write volFields with selected mesh quality parameters"
+    );
+    argList::addBoolOption
     (
         "meshQuality",
         "read user-defined mesh quality criterions from system/meshQualityDict"
@@ -110,7 +128,7 @@ int main(int argc, char *argv[])
     #include "setRootCase.H"
     #include "createTime.H"
     instantList timeDirs = timeSelector::select0(runTime, args);
-    #include "createNamedPolyMesh.H"
+    #include "createNamedMesh.H"
 
     const bool noTopology  = args.optionFound("noTopology");
     const bool allGeometry = args.optionFound("allGeometry");
@@ -119,6 +137,24 @@ int main(int argc, char *argv[])
 
     word surfaceFormat;
     const bool writeSets = args.optionReadIfPresent("writeSets", surfaceFormat);
+    HashSet<word> selectedFields;
+    bool writeFields = args.optionReadIfPresent
+    (
+        "writeFields",
+        selectedFields
+    );
+    if (!writeFields && args.optionFound("writeAllFields"))
+    {
+        selectedFields.insert("nonOrthoAngle");
+        selectedFields.insert("faceWeight");
+        selectedFields.insert("skewness");
+        selectedFields.insert("cellDeterminant");
+        selectedFields.insert("aspectRatio");
+        selectedFields.insert("cellShapes");
+        selectedFields.insert("cellVolume");
+        selectedFields.insert("cellVolumeRatio");
+    }
+
 
     if (noTopology)
     {
@@ -143,6 +179,11 @@ int main(int argc, char *argv[])
             << " representation"
             << " of all faceSets and cellSets." << nl << endl;
     }
+    if (selectedFields.size())
+    {
+        Info<< "Writing mesh quality as fields " << selectedFields << nl
+            << endl;
+    }
 
 
     autoPtr<IOdictionary> qualDict;
@@ -234,6 +275,10 @@ int main(int argc, char *argv[])
                 Info<< "\nFailed " << nFailedChecks << " mesh checks.\n"
                     << endl;
             }
+
+
+            // Write selected fields
+            Foam::writeFields(mesh, selectedFields);
         }
         else if (state == polyMesh::POINTS_MOVED)
         {
@@ -262,6 +307,10 @@ int main(int argc, char *argv[])
             {
                 Info<< "\nMesh OK.\n" << endl;
             }
+
+
+            // Write selected fields
+            Foam::writeFields(mesh, selectedFields);
         }
     }
 
diff --git a/applications/utilities/mesh/manipulation/checkMesh/writeFields.C b/applications/utilities/mesh/manipulation/checkMesh/writeFields.C
new file mode 100644
index 00000000000..1cdc3dbe61a
--- /dev/null
+++ b/applications/utilities/mesh/manipulation/checkMesh/writeFields.C
@@ -0,0 +1,360 @@
+#include "writeFields.H"
+#include "volFields.H"
+#include "polyMeshTools.H"
+#include "zeroGradientFvPatchFields.H"
+#include "syncTools.H"
+
+using namespace Foam;
+
+void maxFaceToCell
+(
+    const scalarField& faceData,
+    volScalarField& cellData
+)
+{
+    const cellList& cells = cellData.mesh().cells();
+
+    scalarField& cellFld = cellData.ref();
+
+    cellFld = -GREAT;
+    forAll(cells, cellI)
+    {
+        const cell& cFaces = cells[cellI];
+        forAll(cFaces, i)
+        {
+            cellFld[cellI] = max(cellFld[cellI], faceData[cFaces[i]]);
+        }
+    }
+
+    forAll(cellData.boundaryField(), patchI)
+    {
+        fvPatchScalarField& fvp = cellData.boundaryFieldRef()[patchI];
+
+        fvp = fvp.patch().patchSlice(faceData);
+    }
+    cellData.correctBoundaryConditions();
+}
+
+
+void minFaceToCell
+(
+    const scalarField& faceData,
+    volScalarField& cellData
+)
+{
+    const cellList& cells = cellData.mesh().cells();
+
+    scalarField& cellFld = cellData.ref();
+
+    cellFld = GREAT;
+    forAll(cells, cellI)
+    {
+        const cell& cFaces = cells[cellI];
+        forAll(cFaces, i)
+        {
+            cellFld[cellI] = min(cellFld[cellI], faceData[cFaces[i]]);
+        }
+    }
+
+    forAll(cellData.boundaryField(), patchI)
+    {
+        fvPatchScalarField& fvp = cellData.boundaryFieldRef()[patchI];
+
+        fvp = fvp.patch().patchSlice(faceData);
+    }
+    cellData.correctBoundaryConditions();
+}
+
+
+void Foam::writeFields
+(
+    const fvMesh& mesh,
+    const HashSet<word>& selectedFields
+)
+{
+    if (selectedFields.empty())
+    {
+        return;
+    }
+
+    Info<< "Writing fields with mesh quality parameters" << endl;
+
+    if (selectedFields.found("nonOrthoAngle"))
+    {
+        //- Face based orthogonality
+        const scalarField faceOrthogonality
+        (
+            polyMeshTools::faceOrthogonality
+            (
+                mesh,
+                mesh.faceAreas(),
+                mesh.cellCentres()
+            )
+        );
+
+        //- Face based angle
+        const scalarField nonOrthoAngle
+        (
+            radToDeg
+            (
+                Foam::acos(min(1.0, faceOrthogonality))
+            )
+        );
+
+        //- Cell field - max of either face
+        volScalarField cellNonOrthoAngle
+        (
+            IOobject
+            (
+                "nonOrthoAngle",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh,
+            dimensionedScalar("angle", dimless, 0),
+            calculatedFvPatchScalarField::typeName
+        );
+        //- Take max
+        maxFaceToCell(nonOrthoAngle, cellNonOrthoAngle);
+        Info<< "    Writing non-orthogonality (angle) to "
+            << cellNonOrthoAngle.name() << endl;
+        cellNonOrthoAngle.write();
+    }
+
+    if (selectedFields.found("faceWeight"))
+    {
+        const scalarField faceWeights
+        (
+            polyMeshTools::faceWeights
+            (
+                mesh,
+                mesh.faceCentres(),
+                mesh.faceAreas(),
+                mesh.cellCentres()
+            )
+        );
+
+        volScalarField cellWeights
+        (
+            IOobject
+            (
+                "faceWeight",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh,
+            dimensionedScalar("weight", dimless, 0),
+            calculatedFvPatchScalarField::typeName
+        );
+        //- Take min
+        minFaceToCell(faceWeights, cellWeights);
+        Info<< "    Writing face interpolation weights (0..0.5) to "
+            << cellWeights.name() << endl;
+        cellWeights.write();
+    }
+
+
+    // Skewness
+    // ~~~~~~~~
+
+    if (selectedFields.found("skewness"))
+    {
+        //- Face based skewness
+        const scalarField faceSkewness
+        (
+            polyMeshTools::faceSkewness
+            (
+                mesh,
+                mesh.points(),
+                mesh.faceCentres(),
+                mesh.faceAreas(),
+                mesh.cellCentres()
+            )
+        );
+
+        //- Cell field - max of either face
+        volScalarField cellSkewness
+        (
+            IOobject
+            (
+                "skewness",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh,
+            dimensionedScalar("skewness", dimless, 0),
+            calculatedFvPatchScalarField::typeName
+        );
+        //- Take max
+        maxFaceToCell(faceSkewness, cellSkewness);
+        Info<< "    Writing face skewness to " << cellSkewness.name() << endl;
+        cellSkewness.write();
+    }
+
+
+    // cellDeterminant
+    // ~~~~~~~~~~~~~~~
+
+    if (selectedFields.found("cellDeterminant"))
+    {
+        volScalarField cellDeterminant
+        (
+            IOobject
+            (
+                "cellDeterminant",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            mesh,
+            dimensionedScalar("cellDeterminant", dimless, 0),
+            zeroGradientFvPatchScalarField::typeName
+        );
+        cellDeterminant.primitiveFieldRef() =
+            primitiveMeshTools::cellDeterminant
+            (
+                mesh,
+                mesh.geometricD(),
+                mesh.faceAreas(),
+                syncTools::getInternalOrCoupledFaces(mesh)
+            );
+        cellDeterminant.correctBoundaryConditions();
+        Info<< "    Writing cell determinant to "
+            << cellDeterminant.name() << endl;
+        cellDeterminant.write();
+    }
+
+
+    // Aspect ratio
+    // ~~~~~~~~~~~~
+    if (selectedFields.found("aspectRatio"))
+    {
+        volScalarField aspectRatio
+        (
+            IOobject
+            (
+                "aspectRatio",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            mesh,
+            dimensionedScalar("aspectRatio", dimless, 0),
+            zeroGradientFvPatchScalarField::typeName
+        );
+
+
+        scalarField cellOpenness;
+        polyMeshTools::cellClosedness
+        (
+            mesh,
+            mesh.geometricD(),
+            mesh.faceAreas(),
+            mesh.cellVolumes(),
+            cellOpenness,
+            aspectRatio.ref()
+        );
+
+        aspectRatio.correctBoundaryConditions();
+        Info<< "    Writing aspect ratio to " << aspectRatio.name() << endl;
+        aspectRatio.write();
+    }
+
+
+    // cell type
+    // ~~~~~~~~~
+    if (selectedFields.found("cellShapes"))
+    {
+        volScalarField shape
+        (
+            IOobject
+            (
+                "cellShapes",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            mesh,
+            dimensionedScalar("cellShapes", dimless, 0),
+            zeroGradientFvPatchScalarField::typeName
+        );
+        const cellShapeList& cellShapes = mesh.cellShapes();
+        forAll(cellShapes, cellI)
+        {
+            const cellModel& model = cellShapes[cellI].model();
+            shape[cellI] = model.index();
+        }
+        shape.correctBoundaryConditions();
+        Info<< "    Writing cell shape (hex, tet etc.) to " << shape.name()
+            << endl;
+        shape.write();
+    }
+
+    if (selectedFields.found("cellVolume"))
+    {
+        volScalarField V
+        (
+            IOobject
+            (
+                "cellVolume",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE,
+                false
+            ),
+            mesh,
+            dimensionedScalar("cellVolume", dimVolume, 0),
+            calculatedFvPatchScalarField::typeName
+        );
+        V.ref() = mesh.V();
+        Info<< "    Writing cell volume to " << V.name() << endl;
+        V.write();
+    }
+
+    if (selectedFields.found("cellVolumeRatio"))
+    {
+        const scalarField faceVolumeRatio
+        (
+            polyMeshTools::volRatio
+            (
+                mesh,
+                mesh.V()
+            )
+        );
+
+        volScalarField cellVolumeRatio
+        (
+            IOobject
+            (
+                "cellVolumeRatio",
+                mesh.time().timeName(),
+                mesh,
+                IOobject::NO_READ,
+                IOobject::AUTO_WRITE
+            ),
+            mesh,
+            dimensionedScalar("cellVolumeRatio", dimless, 0),
+            calculatedFvPatchScalarField::typeName
+        );
+        //- Take min
+        minFaceToCell(faceVolumeRatio, cellVolumeRatio);
+        Info<< "    Writing cell volume ratio to "
+            << cellVolumeRatio.name() << endl;
+        cellVolumeRatio.write();
+    }
+
+    Info<< endl;
+}
diff --git a/applications/utilities/mesh/manipulation/checkMesh/writeFields.H b/applications/utilities/mesh/manipulation/checkMesh/writeFields.H
new file mode 100644
index 00000000000..09c31b0e62b
--- /dev/null
+++ b/applications/utilities/mesh/manipulation/checkMesh/writeFields.H
@@ -0,0 +1,10 @@
+#include "fvMesh.H"
+
+namespace Foam
+{
+    void writeFields
+    (
+        const fvMesh&,
+        const HashSet<word>& selectedFields
+    );
+}
-- 
GitLab