coupledPolyPatch: Rewrite transformations and ordering

The calculation and input/output of transformations has been rewritten
for all coupled patches. This replaces multiple duplicated, inconsistent
and incomplete implementations of transformation handling which were
spread across the different coupled patch types.

Transformations are now calculated or specified once, typically during
mesh construction or manipulation, and are written out with the boundary
data. They are never re-calculated. Mesh changes should not change the
transformation across a coupled interface; to do so would violate the
transformation.

Transformations are now calculated using integral properties of the
patches. This is more numerically stable that the previous methods which
functioned in terms of individual faces. The new routines are also able
to automatically calculate non-zero centres of rotation.

The user input of transformations is backwards compatible, and permits
the user to manually specify varying amounts of the transformation
geometry. Anything left unspecified gets automatically computed from the
patch geometry. Supported specifications are:

    1) No specification. Transformations on cyclics are automatically
    generated, and cyclicAMI-type patches assume no transformation. For
    example (in system/blockMeshDict):

        cyclicLeft
        {
            type                cyclic;
            neighbourPatch      cyclicRight;
            faces               ((0 1 2 3));
        }

        cyclicRight
        {
            type                cyclic;
            neighbourPatch      cyclicLeft;
            faces               ((4 5 6 7));
        }

    2) Partial specification. The type of transformation is specified
    by the user, as well as the coordinate system if the transform is
    rotational. The rotation angle or separation vector is still
    automatically generated. This form is useful as the signs of the
    angle and separation are opposite on different sides of an interface
    and can be difficult to specify correctly. For example:

        cyclicLeft
        {
            type                cyclic;
            neighbourPatch      cyclicRight;
            transformType       translational;
            faces               ((0 1 2 3));
        }

        cyclicRight
        {
            type                cyclic;
            neighbourPatch      cyclicLeft;
            transformType       translational;
            faces               ((4 5 6 7));
        }

        cyclicAMILeft
        {
            type                cyclicAMI;
            neighbourPatch      cyclicAMIRight;
            transformType       rotational;
            rotationAxis        (0 0 1);
            rotationCentre      (0.05 -0.01 0);
            faces               ((8 9 10 11));
        }

        cyclicAMIRight
        {
            type                cyclicAMI;
            neighbourPatch      cyclicAMILeft;
            transformType       rotational;
            rotationAxis        (0 0 1);
            rotationCentre      (0.05 -0.01 0);
            faces               ((12 13 14 15));
        }

    3) Full specification. All parameters of the transformation are
    given. For example:

        cyclicLeft
        {
            type                cyclic;
            neighbourPatch      cyclicRight;
            transformType       translational;
            separaion           (-0.01 0 0);
            faces               ((0 1 2 3));
        }

        cyclicRight
        {
            type                cyclic;
            neighbourPatch      cyclicLeft;
            transformType       translational;
            separaion           (0.01 0 0);
            faces               ((4 5 6 7));
        }

        cyclicAMILeft
        {
            type                cyclicAMI;
            neighbourPatch      cyclicAMIRight;
            transformType       rotational;
            rotationAxis        (0 0 1);
            rotationCentre      (0.05 -0.01 0);
            rotationAngle       60;
            faces               ((8 9 10 11));
        }

        cyclicAMIRight
        {
            type                cyclicAMI;
            neighbourPatch      cyclicAMILeft;
            transformType       rotational;
            rotationAxis        (0 0 1);
            rotationCentre      (0.05 -0.01 0);
            rotationAngle       60;
            faces               ((12 13 14 15));
        }

Automatic ordering of faces and points across coupled patches has also
been rewritten, again replacing multiple unsatisfactory implementations.

The new ordering method is more robust on poor meshes as it
geometrically matches only a single face (per contiguous region of the
patch) in order to perform the ordering, and this face is chosen to be
the one with the highest quality. A failure in ordering now only occurs
if the best face in the patch cannot be geometrically matched, whether
as previously the worst face could cause the algorithm to fail.

The oldCyclicPolyPatch has been removed, and the mesh converters which
previously used it now all generate ordered cyclic and baffle patches
directly. This removes the need to run foamUpgradeCyclics after
conversion. In addition the fluent3DMeshToFoam converter now supports
conversion of periodic/shadow pairs to OpenFOAM cyclic patches.
This commit is contained in:
Will Bainbridge
2020-01-10 09:45:18 +00:00
parent d38a680dae
commit 87bce82854
47 changed files with 2351 additions and 4129 deletions

View File

@ -1,7 +1,9 @@
EXE_INC = \ EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude -I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude
EXE_LIBS = \ EXE_LIBS = \
-lmeshTools \ -lmeshTools \
-ldynamicMesh -ldynamicMesh \
-lconversion

View File

@ -38,10 +38,11 @@ License
#include "polyMeshZipUpCells.H" #include "polyMeshZipUpCells.H"
#include "wallPolyPatch.H" #include "wallPolyPatch.H"
#include "symmetryPolyPatch.H" #include "symmetryPolyPatch.H"
#include "oldCyclicPolyPatch.H" #include "mergedCyclicPolyPatch.H"
#include "Swap.H" #include "Swap.H"
#include "IFstream.H" #include "IFstream.H"
#include "readHexLabel.H" #include "readHexLabel.H"
#include "polyMeshUnMergeCyclics.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -769,6 +770,12 @@ int main(int argc, char *argv[])
"geometry scaling factor - default is 1" "geometry scaling factor - default is 1"
); );
argList::addOption argList::addOption
(
"includedAngle",
"angle",
"feature angle with which to split cyclics"
);
argList::addOption
( (
"ignoreCellGroups", "ignoreCellGroups",
"names", "names",
@ -901,16 +908,13 @@ int main(int argc, char *argv[])
fluentToFoamType.insert("interface", polyPatch::typeName); fluentToFoamType.insert("interface", polyPatch::typeName);
fluentToFoamType.insert("internal", polyPatch::typeName); fluentToFoamType.insert("internal", polyPatch::typeName);
fluentToFoamType.insert("solid", polyPatch::typeName); fluentToFoamType.insert("solid", polyPatch::typeName);
fluentToFoamType.insert("fan", oldCyclicPolyPatch::typeName);
fluentToFoamType.insert("radiator", polyPatch::typeName);
fluentToFoamType.insert("porous-jump", polyPatch::typeName);
//- Periodic halves map directly into split cyclics. The problem is the fluentToFoamType.insert("fan", mergedCyclicPolyPatch::typeName);
// initial matching since we require knowledge of the transformation. fluentToFoamType.insert("radiator", mergedCyclicPolyPatch::typeName);
// It is ok if the periodics are already ordered. We should read the fluentToFoamType.insert("porous-jump", mergedCyclicPolyPatch::typeName);
// periodic shadow faces section (section 18) to give use the ordering
// For now just disable. fluentToFoamType.insert("periodic", cyclicPolyPatch::typeName);
// fluentToFoamType.insert("periodic", cyclicPolyPatch::typeName); fluentToFoamType.insert("shadow", cyclicPolyPatch::typeName);
// Foam patch type for Fluent zone type // Foam patch type for Fluent zone type
@ -919,6 +923,8 @@ int main(int argc, char *argv[])
HashSet<word> fluentGroupToFoamPatch; HashSet<word> fluentGroupToFoamPatch;
fluentGroupToFoamPatch.insert("wall"); fluentGroupToFoamPatch.insert("wall");
fluentGroupToFoamPatch.insert("fan"); fluentGroupToFoamPatch.insert("fan");
fluentGroupToFoamPatch.insert("radiator");
fluentGroupToFoamPatch.insert("porous-jump");
// Create initial empty polyMesh // Create initial empty polyMesh
@ -1023,6 +1029,76 @@ int main(int argc, char *argv[])
faceZoneIDs.shrink(); faceZoneIDs.shrink();
// Pair up cyclics
// ~~~~~~~~~~~~~~~
labelList nbrPatchis(patchIDs.size(), -1);
forAll(patchIDs, patchi)
{
const label zonei = faceGroupZoneID[patchIDs[patchi]];
const word& name = groupName[zonei];
const word& type = groupType[zonei];
HashTable<word>::const_iterator iter = fluentToFoamType.find(type);
if (iter != fluentToFoamType.end())
{
if
(
iter() == cyclicPolyPatch::typeName
&& nbrPatchis[patchi] == -1
)
{
// This is one half of a pair of patches defining a cyclic
// interface. Find the neighbouring patch.
forAll(patchIDs, nbrPatchi)
{
const label nbrZonei = faceGroupZoneID[patchIDs[nbrPatchi]];
const word& nbrName = groupName[nbrZonei];
const word& nbrType = groupType[nbrZonei];
HashTable<word>::const_iterator nbrIter =
fluentToFoamType.find(nbrType);
if (nbrIter != fluentToFoamType.end())
{
if
(
nbrIter() == cyclicPolyPatch::typeName
&& nbrPatchis[nbrPatchi] == -1
)
{
// The neighbour must have a different type
// (periodic =/= shadow) and its name must share a
// prefix with the patch.
if
(
nbrType != type
&& nbrName(min(name.size(), nbrName.size()))
== name(min(name.size(), nbrName.size()))
)
{
nbrPatchis[nbrPatchi] = patchi;
nbrPatchis[patchi] = nbrPatchi;
break;
}
}
}
}
if (nbrPatchis[patchi] == -1)
{
FatalErrorInFunction
<< "Could not find neighbour patch for " << type
<< " patch " << name << exit(FatalError);
}
}
}
}
// Add empty patches // Add empty patches
// ~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~
@ -1031,7 +1107,7 @@ int main(int argc, char *argv[])
forAll(patchIDs, patchi) forAll(patchIDs, patchi)
{ {
label zoneID = faceGroupZoneID[patchIDs[patchi] ]; const label zoneID = faceGroupZoneID[patchIDs[patchi]];
word name = groupName[zoneID]; word name = groupName[zoneID];
const word& type = groupType[zoneID]; const word& type = groupType[zoneID];
@ -1047,32 +1123,11 @@ int main(int argc, char *argv[])
if (iter != fluentToFoamType.end()) if (iter != fluentToFoamType.end())
{ {
// See if we have a periodic and can derive the other side.
word nbrPatchName;
if (iter() == cyclicPolyPatch::typeName) if (iter() == cyclicPolyPatch::typeName)
{ {
// Periodic const label nbrPatchi = nbrPatchis[patchi];
size_t n = name.rfind("-SIDE-1"); const label nbrZoneID = faceGroupZoneID[patchIDs[nbrPatchi]];
const word nbrName = groupName[nbrZoneID];
if (n != string::npos)
{
nbrPatchName = name.substr(0, n) + "-SIDE-2";
}
else
{
n = name.rfind("-SIDE-2");
if (n != string::npos)
{
nbrPatchName = name.substr(0, n) + "-SIDE-1";
}
}
}
if (nbrPatchName.size())
{
Info<< "Adding cyclicPolyPatch for Fluent zone " << name
<< " with neighbour patch " << nbrPatchName
<< endl;
newPatches[patchi] = new cyclicPolyPatch newPatches[patchi] = new cyclicPolyPatch
( (
@ -1082,8 +1137,7 @@ int main(int argc, char *argv[])
patchi, patchi,
mesh.boundaryMesh(), mesh.boundaryMesh(),
cyclicPolyPatch::typeName, cyclicPolyPatch::typeName,
nbrPatchName, nbrName
cyclicPolyPatch::NOORDERING
); );
} }
else else
@ -1101,9 +1155,6 @@ int main(int argc, char *argv[])
} }
else else
{ {
Info<< "Adding polyPatch for unknown Fluent type " << type
<< endl;
newPatches[patchi] = new polyPatch newPatches[patchi] = new polyPatch
( (
name, name,
@ -1342,6 +1393,7 @@ int main(int argc, char *argv[])
); );
} }
} }
// Mark face as being done // Mark face as being done
owner[facei] = -1; owner[facei] = -1;
} }
@ -1411,6 +1463,16 @@ int main(int argc, char *argv[])
polyMeshZipUpCells(mesh); polyMeshZipUpCells(mesh);
} }
// Un-merge any merged cyclics
if (args.optionFound("includedAngle"))
{
polyMeshUnMergeCyclics(mesh, args.optionRead<scalar>("includedAngle"));
}
else
{
polyMeshUnMergeCyclics(mesh);
}
mesh.setInstance(runTime.constant()); mesh.setInstance(runTime.constant());
// Set the precision of the points data to 10 // Set the precision of the points data to 10

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lconversion

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -41,7 +41,8 @@ Description
#include "wallPolyPatch.H" #include "wallPolyPatch.H"
#include "symmetryPolyPatch.H" #include "symmetryPolyPatch.H"
#include "wedgePolyPatch.H" #include "wedgePolyPatch.H"
#include "oldCyclicPolyPatch.H" #include "mergedCyclicPolyPatch.H"
#include "polyMeshUnMergeCyclics.H"
#include "unitConversion.H" #include "unitConversion.H"
using namespace Foam; using namespace Foam;

View File

@ -196,7 +196,7 @@ const word* kivaPatchTypes[nBCs] =
&polyPatch::typeName, &polyPatch::typeName,
&polyPatch::typeName, &polyPatch::typeName,
&symmetryPolyPatch::typeName, &symmetryPolyPatch::typeName,
&oldCyclicPolyPatch::typeName &mergedCyclicPolyPatch::typeName
}; };
enum patchTypeNames enum patchTypeNames
@ -574,6 +574,9 @@ polyMesh pShapeMesh
defaultFacesType defaultFacesType
); );
// Un-merge any merged cyclics
polyMeshUnMergeCyclics(pShapeMesh);
Info << "Writing polyMesh" << endl; Info << "Writing polyMesh" << endl;
pShapeMesh.write(); pShapeMesh.write();

View File

@ -0,0 +1,7 @@
EXE_INC = \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lconversion

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -29,7 +29,7 @@ Description
#include "sammMesh.H" #include "sammMesh.H"
#include "Time.H" #include "Time.H"
#include "wallPolyPatch.H" #include "wallPolyPatch.H"
#include "oldCyclicPolyPatch.H" #include "mergedCyclicPolyPatch.H"
#include "symmetryPolyPatch.H" #include "symmetryPolyPatch.H"
#include "preservePatchTypes.H" #include "preservePatchTypes.H"
#include "IFstream.H" #include "IFstream.H"
@ -206,9 +206,7 @@ void Foam::sammMesh::readBoundary()
} }
else if (patchType == "CYCL") else if (patchType == "CYCL")
{ {
// incorrect. should be cyclicPatch but this patchTypes_[patchLabel] = mergedCyclicPolyPatch::typeName;
// requires info on connected faces.
patchTypes_[patchLabel] = oldCyclicPolyPatch::typeName;
} }
else else
{ {

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -29,6 +29,7 @@ Description
#include "sammMesh.H" #include "sammMesh.H"
#include "Time.H" #include "Time.H"
#include "polyMesh.H" #include "polyMesh.H"
#include "polyMeshUnMergeCyclics.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -56,6 +57,8 @@ void Foam::sammMesh::writeMesh()
patchPhysicalTypes_ patchPhysicalTypes_
); );
polyMeshUnMergeCyclics(pShapeMesh);
Info<< "Writing polyMesh" << endl; Info<< "Writing polyMesh" << endl;
pShapeMesh.write(); pShapeMesh.write();
} }
@ -82,6 +85,8 @@ void Foam::sammMesh::writeMesh()
pMesh.addPatches(polyBoundaryPatches(pMesh)); pMesh.addPatches(polyBoundaryPatches(pMesh));
polyMeshUnMergeCyclics(pMesh);
Info<< "Writing polyMesh" << endl; Info<< "Writing polyMesh" << endl;
pMesh.write(); pMesh.write();
} }

View File

@ -4,4 +4,10 @@ EXE_INC = \
/* -DDEBUG_COUPLE_INTERSECTION */ \ /* -DDEBUG_COUPLE_INTERSECTION */ \
/* -DDEBUG_RIGHT_HAND_WALK */ \ /* -DDEBUG_RIGHT_HAND_WALK */ \
/* -DDEBUG_FACE_ORDERING */ \ /* -DDEBUG_FACE_ORDERING */ \
/* -DDEBUG_COUPLE_PROJECTION */ /* -DDEBUG_COUPLE_PROJECTION */ \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/conversion/lnInclude
EXE_LIBS = \
-ldynamicMesh \
-lconversion

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -29,7 +29,7 @@ Description
#include "starMesh.H" #include "starMesh.H"
#include "Time.H" #include "Time.H"
#include "wallPolyPatch.H" #include "wallPolyPatch.H"
#include "oldCyclicPolyPatch.H" #include "mergedCyclicPolyPatch.H"
#include "symmetryPolyPatch.H" #include "symmetryPolyPatch.H"
#include "preservePatchTypes.H" #include "preservePatchTypes.H"
#include "IFstream.H" #include "IFstream.H"
@ -204,9 +204,7 @@ void Foam::starMesh::readBoundary()
} }
else if (patchType == "CYCL") else if (patchType == "CYCL")
{ {
// incorrect. should be cyclicPatch but this patchTypes_[patchLabel] = mergedCyclicPolyPatch::typeName;
// requires info on connected faces.
patchTypes_[patchLabel] = oldCyclicPolyPatch::typeName;
} }
else else
{ {

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -29,6 +29,7 @@ Description
#include "starMesh.H" #include "starMesh.H"
#include "Time.H" #include "Time.H"
#include "polyMesh.H" #include "polyMesh.H"
#include "polyMeshUnMergeCyclics.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -60,6 +61,8 @@ void Foam::starMesh::writeMesh()
patchPhysicalTypes_ patchPhysicalTypes_
); );
polyMeshUnMergeCyclics(pShapeMesh);
Info<< "Writing polyMesh" << endl; Info<< "Writing polyMesh" << endl;
pShapeMesh.write(); pShapeMesh.write();
} }
@ -89,6 +92,8 @@ void Foam::starMesh::writeMesh()
// adding patches also checks the mesh // adding patches also checks the mesh
pMesh.addPatches(polyBoundaryPatches(pMesh)); pMesh.addPatches(polyBoundaryPatches(pMesh));
polyMeshUnMergeCyclics(pMesh);
Info<< "Writing polyMesh" << endl; Info<< "Writing polyMesh" << endl;
pMesh.write(); pMesh.write();
} }

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2012-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2012-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -437,8 +437,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::conformalVoronoiMesh::createDummyMesh
patchi, patchi,
mesh.boundaryMesh(), mesh.boundaryMesh(),
patchDicts[patchi].lookup<label>("myProcNo"), patchDicts[patchi].lookup<label>("myProcNo"),
patchDicts[patchi].lookup<label>("neighbProcNo"), patchDicts[patchi].lookup<label>("neighbProcNo")
coupledPolyPatch::COINCIDENTFULLMATCH
); );
} }
else else

View File

@ -360,7 +360,11 @@ void syncPoints
if (procPatch.transform().transformsPosition()) if (procPatch.transform().transformsPosition())
{ {
hasTransformation = true; hasTransformation = true;
procPatch.transform().transformPosition(nbrPatchInfo); procPatch.transform().transformPosition
(
nbrPatchInfo,
nbrPatchInfo
);
} }
const labelList& meshPts = procPatch.meshPoints(); const labelList& meshPts = procPatch.meshPoints();
@ -405,7 +409,11 @@ void syncPoints
if (cycPatch.transform().transformsPosition()) if (cycPatch.transform().transformsPosition())
{ {
hasTransformation = true; hasTransformation = true;
cycPatch.transform().invTransformPosition(patchPoints); cycPatch.transform().invTransformPosition
(
patchPoints,
patchPoints
);
} }
forAll(coupledPoints, i) forAll(coupledPoints, i)

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -495,8 +495,7 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
procMesh.boundaryMesh(), procMesh.boundaryMesh(),
proci, proci,
curNeighbourProcessors[procPatchi], curNeighbourProcessors[procPatchi],
pcPatch.name(), pcPatch.name()
pcPatch.ordering()
); );
} }

View File

@ -40,12 +40,12 @@ wmake $targetType lagrangian/basic
wmake $targetType lagrangian/distributionModels wmake $targetType lagrangian/distributionModels
wmake $targetType genericPatchFields wmake $targetType genericPatchFields
wmake $targetType conversion
wmake $targetType mesh/extrudeModel wmake $targetType mesh/extrudeModel
wmake $targetType dynamicMesh wmake $targetType dynamicMesh
wmake $targetType sampling
wmake $targetType dynamicFvMesh wmake $targetType dynamicFvMesh
wmake $targetType topoChangerFvMesh wmake $targetType topoChangerFvMesh
wmake $targetType conversion
wmake $targetType sampling
# Compile scotchDecomp, metisDecomp etc. # Compile scotchDecomp, metisDecomp etc.
parallel/Allwmake $targetType $* parallel/Allwmake $targetType $*

View File

@ -472,7 +472,6 @@ constraintPolyPatches = $(polyPatches)/constraint
$(constraintPolyPatches)/cyclic/cyclicTransform.C $(constraintPolyPatches)/cyclic/cyclicTransform.C
$(constraintPolyPatches)/cyclic/cyclicPolyPatch.C $(constraintPolyPatches)/cyclic/cyclicPolyPatch.C
$(constraintPolyPatches)/cyclicSlip/cyclicSlipPolyPatch.C $(constraintPolyPatches)/cyclicSlip/cyclicSlipPolyPatch.C
$(constraintPolyPatches)/oldCyclic/oldCyclicPolyPatch.C
$(constraintPolyPatches)/empty/emptyPolyPatch.C $(constraintPolyPatches)/empty/emptyPolyPatch.C
$(constraintPolyPatches)/processorCyclic/processorCyclicPolyPatch.C $(constraintPolyPatches)/processorCyclic/processorCyclicPolyPatch.C
$(constraintPolyPatches)/processor/processorPolyPatch.C $(constraintPolyPatches)/processor/processorPolyPatch.C

View File

@ -35,164 +35,562 @@ namespace Foam
defineTypeNameAndDebug(coupledPolyPatch, 0); defineTypeNameAndDebug(coupledPolyPatch, 0);
const scalar coupledPolyPatch::defaultMatchTol_ = 1e-4; const scalar coupledPolyPatch::defaultMatchTol_ = 1e-4;
}
template<>
const char* NamedEnum<coupledPolyPatch::orderingType, 3>::names[] = // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
bool Foam::coupledPolyPatch::walk
(
const primitivePatch& pp,
const bool direction,
const label seedFacei,
const label seedFacePointi,
labelList& faceMap,
labelList& facePointMap,
label& mapFacei,
autoPtr<labelListList>& walks
) const
{
// Initialisation
label facei = seedFacei, facePointi = seedFacePointi;
faceMap[facei] = mapFacei;
facePointMap[facei] = facePointi;
bool changed = facei != mapFacei || facePointi != 0;
++ mapFacei;
if (walks.valid())
{ {
"unknown", walks->append(labelList(1, facei));
"coincidentFullMatch", }
"noOrdering"
};
const NamedEnum<coupledPolyPatch::orderingType, 3> // Walk the patch until we get back to the seed face and point
coupledPolyPatch::orderingTypeNames; do
{
// Get the next point and edge around the current face
const label facePointi1 =
direction
? pp[facei].fcIndex(facePointi)
: pp[facei].rcIndex(facePointi);
const label faceEdgei = direction ? facePointi : facePointi1;
// Get the edge and the faces connected to the edge
const label edgei = pp.faceEdges()[facei][faceEdgei];
const labelList edgeFaces = pp.edgeFaces()[edgei];
// Test if this is an edge the walk *can* cross
if (edgeFaces.size() == 2)
{
// This edge is manifold (i.e., the number of connected faces is
// 2), so it is permitted for the walk to cross it. Get the face
// connected to the other side of the edge that we may want to walk
// into.
const label facej = edgeFaces[edgeFaces[0] == facei];
const label facePointj = pp[facej].which(pp[facei][facePointi]);
// Test if this is an edge the walk *should* cross
if (faceMap[facej] == -1)
{
// The connected face has not been visited, so walk into it and
// set its ordering in the map, its point and visited status
facei = facej;
facePointi = facePointj;
faceMap[facei] = mapFacei;
facePointMap[facei] = facePointi;
changed = changed || facei != mapFacei || facePointi != 0;
++ mapFacei;
}
else if (facePointMap[facei] != facePointi1 || facei == seedFacei)
{
// The connected face has been visited, but there are more
// edges to consider on the current face, so move to the next
// face point
facePointi = facePointi1;
}
else
{
// The connected face has been visited, and there are no more
// edges to consider on the current face, so backtrack to the
// previous face in the walk
facei = facej;
facePointi = facePointj;
}
// Add to the walk, if that information is being stored
if (walks.valid() && walks->last().last() != facei)
{
walks->last().append(facei);
}
}
else
{
// This edge is non-manifold (i.e., the number of connected faces
// does not equal 2), so it is considered a boundary to the walk.
// Move on to the next point around the current face.
facePointi = facePointi1;
}
}
while (facei != seedFacei || facePointi != seedFacePointi);
return changed;
} }
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::coupledPolyPatch::writeOBJ(Ostream& os, const point& pt) void Foam::coupledPolyPatch::writeOBJ
(
const fileName& name,
const primitivePatch& pp
)
{ {
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl; OFstream os(name);
forAll(pp.localPoints(), pointi)
{
const point& p = pp.localPoints()[pointi];
os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << endl;
}
forAll(pp.localFaces(), facei)
{
const face& f = pp.localFaces()[facei];
os << 'f';
forAll(f, fi)
{
os << ' ' << f[fi] + 1;
}
os << endl;
}
}
void Foam::coupledPolyPatch::writeOBJ
(
const fileName& name,
const pointField& points0,
const pointField& points1
)
{
OFstream os(name);
forAll(points0, pointi)
{
const point& p0 = points0[pointi];
const point& p1 = points1[pointi];
os << "v " << p0.x() << ' ' << p0.y() << ' ' << p0.z() << endl
<< "v " << p1.x() << ' ' << p1.y() << ' ' << p1.z() << endl
<< "l " << 2*pointi << ' ' << 2*pointi + 1 << endl;
}
} }
void Foam::coupledPolyPatch::writeOBJ void Foam::coupledPolyPatch::writeOBJ
( (
Ostream& os, const fileName& name,
const pointField& points, const pointField& points,
const labelList& pointLabels const labelListList& paths
) )
{ {
forAll(pointLabels, i) OFstream os(name);
forAll(points, pointi)
{ {
writeOBJ(os, points[pointLabels[i]]); const point& c = points[pointi];
os << "v " << c.x() << ' '<< c.y() << ' ' << c.z() << endl;
}
forAll(paths, pathi)
{
for (label pathj = 0; pathj < paths[pathi].size() - 1; ++ pathj)
{
os << "l " << paths[pathi][pathj] + 1 << ' '
<< paths[pathi][pathj + 1] + 1 << endl;
}
} }
} }
void Foam::coupledPolyPatch::writeOBJ void Foam::coupledPolyPatch::initOrder
( (
Ostream& os, ownToNbrOrderData& ownToNbr,
const point& p0, autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
const point& p1, const primitivePatch& pp
label& vertI ) const
)
{ {
writeOBJ(os, p0); if (owner())
vertI++;
writeOBJ(os, p1);
vertI++;
os << "l " << vertI-1 << ' ' << vertI << nl;
}
void Foam::coupledPolyPatch::writeOBJ
(
const fileName& fName,
const UList<face>& faces,
const pointField& points
)
{
OFstream os(fName);
Map<label> foamToObj(4*faces.size());
label vertI = 0;
forAll(faces, i)
{ {
const face& f = faces[i]; // Generate the connected regions
label nRegions = 0;
labelList faceRegionis(pp.size(), -1);
forAll(f, fp) label seedFacei = 0;
labelList faceMap(pp.size(), -1);
labelList facePointMap(pp.size(), -1);
label mapFacei = 0;
autoPtr<labelListList> walks(nullptr);
while (mapFacei < pp.size())
{ {
if (foamToObj.insert(f[fp], vertI)) walk
(
pp,
owner(),
seedFacei,
0,
faceMap,
facePointMap,
mapFacei,
walks
);
forAll(pp, facei)
{ {
writeOBJ(os, points[f[fp]]); if (faceRegionis[facei] == -1 && faceMap[facei] != -1)
vertI++;
}
}
os << 'l';
forAll(f, fp)
{
os << ' ' << foamToObj[f[fp]]+1;
}
os << ' ' << foamToObj[f[0]]+1 << nl;
}
}
Foam::pointField Foam::coupledPolyPatch::getAnchorPoints
(
const UList<face>& faces,
const pointField& points,
const orderingType ordering
)
{
pointField anchors(faces.size());
if (ordering != COINCIDENTFULLMATCH)
{
// Return the first point
forAll(faces, facei)
{
anchors[facei] = points[faces[facei][0]];
}
}
else
{
// Make anchor point unique
forAll(faces, facei)
{
const face& f = faces[facei];
bool unique = true;
forAll(f, fp1)
{
const point& p1 = points[f[fp1]];
unique = true;
for (label fp2 = 0; fp2 < f.size(); ++fp2)
{ {
if (f[fp1] == f[fp2]) faceRegionis[facei] = nRegions;
{
continue;
}
const point& p2 = points[f[fp2]];
// TODO: Change to a tolerance and possibly select closest
// point to the origin
if (p1 == p2)
{
unique = false;
break;
}
} }
}
if (unique) ++ nRegions;
forAll(pp, facei)
{
if (faceMap[facei] == -1)
{ {
anchors[facei] = p1; seedFacei = facei;
break; break;
} }
} }
}
if (!unique) // Generate the face tolerances
//
// !!! It is possble that a different metric would be more appropriate
// for this method than the tolerance that was developed when all faces
// were being geometrically compared
//
const scalarField tols(calcFaceTol(pp, pp.points(), pp.faceCentres()));
// Get the face with the largest tolerance in each region as the seed
// and store its index in the (self) ordering data
ownToOwnOrderDataPtr_ = new ownToOwnOrderData();
ownToOwnOrderDataPtr_->seedFaceis = labelList(nRegions, -1);
scalarList maxTols(nRegions, -vGreat);
forAll(pp, facei)
{
const label regioni = faceRegionis[facei];
if (tols[facei] > maxTols[regioni])
{ {
anchors[facei] = points[faces[facei][0]]; ownToOwnOrderDataPtr_->seedFaceis[regioni] = facei;
maxTols[regioni] = tols[facei];
}
}
// Get the points of each seed face and store them in the neighbour
// ordering data
ownToNbr.seedFacePoints = List<pointField>(nRegions, pointField());
forAll(ownToOwnOrderDataPtr_->seedFaceis, regioni)
{
const face& f = pp[ownToOwnOrderDataPtr_->seedFaceis[regioni]];
ownToNbr.seedFacePoints[regioni] =
transform().invTransformPosition(f.points(pp.points()));
}
// Get debug data
if (ownToNbrDebugPtr.valid())
{
ownToNbrDebugPtr = new ownToNbrDebugOrderData();
ownToNbrDebugPtr->nFaces = pp.size();
ownToNbrDebugPtr->nPoints = pp.nPoints();
ownToNbrDebugPtr->nEdges = pp.nEdges();
ownToNbrDebugPtr->nInternalEdges = pp.nInternalEdges();
}
}
}
bool Foam::coupledPolyPatch::order
(
const ownToNbrOrderData& ownToNbr,
const autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
const primitivePatch& pp,
labelList& faceMap,
labelList& rotation
) const
{
// Determine the seed faces and face points
labelList seedFaceis, seedFacePointis;
if (owner())
{
seedFaceis = ownToOwnOrderDataPtr_->seedFaceis;
ownToOwnOrderDataPtr_.clear();
seedFacePointis.resize(seedFaceis.size(), 0);
}
else
{
const List<pointField> ownerSeedFacePoints(ownToNbr.seedFacePoints);
seedFaceis.resize(ownerSeedFacePoints.size());
seedFacePointis.resize(ownerSeedFacePoints.size());
// Check the element counts
if (ownToNbrDebugPtr.valid())
{
const label ownerNFaces = ownToNbrDebugPtr->nFaces;
const label ownerNPoints = ownToNbrDebugPtr->nPoints;
const label ownerNEdges = ownToNbrDebugPtr->nEdges;
const label ownerNInternalEdges = ownToNbrDebugPtr->nInternalEdges;
if (pp.size() != ownerNFaces)
{
SeriousErrorInFunction<< "The patch " << name() << " has "
<< pp.size() << " faces whilst it's neighbour has "
<< ownerNFaces << endl;
}
if (pp.nPoints() != ownerNPoints)
{
SeriousErrorInFunction<< "The patch " << name() << " has "
<< pp.nPoints() << " points whilst it's neighbour has "
<< ownerNPoints << endl;
}
if (pp.nEdges() != ownerNEdges)
{
SeriousErrorInFunction<< "The patch " << name() << " has "
<< pp.nEdges() << " edges whilst it's neighbour has "
<< ownerNEdges << endl;
}
if (pp.nInternalEdges() != ownerNInternalEdges)
{
SeriousErrorInFunction<< "The patch " << name() << " has "
<< pp.nInternalEdges() << " internal edges whilst it's "
<< "neighbour has " << ownerNInternalEdges << endl;
}
}
// Do geometric testing to determine the faces that match those sent
// over from the opposite patch
forAll(ownerSeedFacePoints, regioni)
{
const pointField& ownerFacePts = ownerSeedFacePoints[regioni];
// The seed face and face-point are the ones which give the smallest
// total displacement between all corresponding points. Note that
// owner and neighbour point order is reversed.
scalar minSumSqrDisplacement = vGreat;
forAll(pp, facei)
{
const pointField facePts = pp[facei].points(pp.points());
if (facePts.size() != ownerFacePts.size()) continue;
forAll(facePts, facePointi)
{
const scalar sumSqrDisplacement =
sum
(
magSqr
(
rotateList(reverseList(facePts), facePointi + 1)
- ownerFacePts
)
);
if (sumSqrDisplacement < minSumSqrDisplacement)
{
seedFaceis[regioni] = facei;
seedFacePointis[regioni] = facePointi;
minSumSqrDisplacement = sumSqrDisplacement;
}
}
}
// Check and report if the min displacement is large
const scalar seedFaceTol =
calcFaceTol
(
faceList(1, pp[seedFaceis[regioni]]),
pp.points(),
pointField(1, pp.faceCentres()[seedFaceis[regioni]])
).first();
if (minSumSqrDisplacement > seedFaceTol)
{
FatalErrorInFunction
<< "The root-sum-square displacement between the points of "
<< "the seed face and the best matching face (#"
<< seedFaceis[regioni] << ") on patch " << name()
<< " is " << sqrt(minSumSqrDisplacement) << "."
<< nl
<< "This is greater than the match tolerance of "
<< seedFaceTol << " for this face."
<< nl
<< "Check that the patches are conformal and that any "
<< "transformations defined between them are correct"
<< nl
<< "It might be possible to fix this problem by increasing "
<< "the \"matchTolerance\" setting for this patch in the "
<< "boundary file."
<< nl
<< "Re-run with the \"coupled\" debug flag set for more "
<< "information."
<< exit(FatalError);
} }
} }
} }
return anchors; // Walk the patch from the seeds
bool changed = false;
faceMap = -1;
labelList facePointMap(pp.size(), -1);
label mapFacei = 0;
autoPtr<labelListList> walks(debug ? new labelListList() : nullptr);
forAll(seedFaceis, regioni)
{
changed =
walk
(
pp,
owner(),
seedFaceis[regioni],
seedFacePointis[regioni],
faceMap,
facePointMap,
mapFacei,
walks
)
|| changed;
}
// Write out the patch
if (debug)
{
Pout<< "Writing patch " << name() << " to " << name() + ".obj" << endl;
writeOBJ(name() + ".obj", pp);
}
// Write out the walk
if (debug)
{
Pout<< "Writing patch " << name() << " walks to "
<< name() + "Walk.obj" << endl;
writeOBJ(name() + "Walk.obj", pp.faceCentres(), walks());
}
// Check that all faces have been visited exactly once
bool badWalk = mapFacei != pp.size();
forAll(pp, facei)
{
badWalk = badWalk || facePointMap[facei] == -1;
}
if (badWalk)
{
FatalErrorInFunction
<< "The ordering walk did not hit every face exactly once"
<< exit(FatalError);
}
// Construct the rotations from the face point map
forAll(pp, facei)
{
rotation[facei] =
(pp[facei].size() - facePointMap[facei]) % pp[facei].size();
}
// Map the rotations
//
// !!! The rotation list appears to be indexed by the new face label,
// rather than the old one. For sanity's sake the ordering code above
// indexes everything consistently with the old face label. This means the
// rotations need mapping to the new indices.
//
UIndirectList<label>(rotation, faceMap) = labelList(rotation);
return changed;
} }
// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
Foam::coupledPolyPatch::coupledPolyPatch
(
const word& name,
const label size,
const label start,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
)
:
polyPatch(name, size, start, index, bm, patchType),
matchTolerance_(defaultMatchTol_),
ownToOwnOrderDataPtr_(nullptr)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const word& name,
const dictionary& dict,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
)
:
polyPatch(name, dict, index, bm, patchType),
matchTolerance_(dict.lookupOrDefault("matchTolerance", defaultMatchTol_)),
ownToOwnOrderDataPtr_(nullptr)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm
)
:
polyPatch(pp, bm),
matchTolerance_(pp.matchTolerance_),
ownToOwnOrderDataPtr_(nullptr)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
)
:
polyPatch(pp, bm, index, newSize, newStart),
matchTolerance_(pp.matchTolerance_),
ownToOwnOrderDataPtr_(nullptr)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const label newStart
)
:
polyPatch(pp, bm, index, mapAddressing, newStart),
matchTolerance_(pp.matchTolerance_),
ownToOwnOrderDataPtr_(nullptr)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coupledPolyPatch::~coupledPolyPatch()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::scalarField Foam::coupledPolyPatch::calcFaceTol Foam::scalarField Foam::coupledPolyPatch::calcFaceTol
( (
const UList<face>& faces, const UList<face>& faces,
@ -233,155 +631,62 @@ Foam::scalarField Foam::coupledPolyPatch::calcFaceTol
} }
Foam::label Foam::coupledPolyPatch::getRotation
(
const pointField& points,
const face& f,
const point& anchor,
const scalar tol
)
{
label anchorFp = -1;
scalar minDistSqr = great;
forAll(f, fp)
{
scalar distSqr = magSqr(anchor - points[f[fp]]);
if (distSqr < minDistSqr)
{
minDistSqr = distSqr;
anchorFp = fp;
}
}
if (anchorFp == -1 || Foam::sqrt(minDistSqr) > tol)
{
return -1;
}
else
{
// Check that anchor is unique.
forAll(f, fp)
{
scalar distSqr = magSqr(anchor - points[f[fp]]);
if (distSqr == minDistSqr && fp != anchorFp)
{
WarningInFunction
<< "Cannot determine unique anchor point on face "
<< UIndirectList<point>(points, f)
<< endl
<< "Both at index " << anchorFp << " and " << fp
<< " the vertices have the same distance "
<< Foam::sqrt(minDistSqr)
<< " to the anchor " << anchor
<< ". Continuing but results might be wrong."
<< nl << endl;
}
}
// Positive rotation
return (f.size() - anchorFp) % f.size();
}
}
// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
Foam::coupledPolyPatch::coupledPolyPatch
(
const word& name,
const label size,
const label start,
const label index,
const polyBoundaryMesh& bm,
const word& patchType,
const orderingType ordering
)
:
polyPatch(name, size, start, index, bm, patchType),
matchTolerance_(defaultMatchTol_),
ordering_(ordering)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const word& name,
const dictionary& dict,
const label index,
const polyBoundaryMesh& bm,
const word& patchType,
const orderingType ordering
)
:
polyPatch(name, dict, index, bm, patchType),
matchTolerance_(dict.lookupOrDefault("matchTolerance", defaultMatchTol_)),
ordering_
(
dict.found("ordering")
? orderingTypeNames.read(dict.lookup("ordering"))
: ordering
)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm
)
:
polyPatch(pp, bm),
matchTolerance_(pp.matchTolerance_),
ordering_(UNKNOWN)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
)
:
polyPatch(pp, bm, index, newSize, newStart),
matchTolerance_(pp.matchTolerance_),
ordering_(UNKNOWN)
{}
Foam::coupledPolyPatch::coupledPolyPatch
(
const coupledPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const label newStart
)
:
polyPatch(pp, bm, index, mapAddressing, newStart),
matchTolerance_(pp.matchTolerance_),
ordering_(UNKNOWN)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::coupledPolyPatch::~coupledPolyPatch()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::coupledPolyPatch::write(Ostream& os) const void Foam::coupledPolyPatch::write(Ostream& os) const
{ {
polyPatch::write(os); polyPatch::write(os);
writeEntry(os, "matchTolerance", matchTolerance_); writeEntry(os, "matchTolerance", matchTolerance_);
writeEntry(os, "ordering", orderingTypeNames[ordering_]); }
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Foam::Istream& Foam::operator>>
(
Istream& is,
coupledPolyPatch::ownToNbrOrderData& ownToNbr
)
{
is >> ownToNbr.seedFacePoints;
return is;
}
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const coupledPolyPatch::ownToNbrOrderData& ownToNbr
)
{
os << ownToNbr.seedFacePoints;
return os;
}
Foam::Istream& Foam::operator>>
(
Istream& is,
coupledPolyPatch::ownToNbrDebugOrderData& ownToNbrDebug
)
{
is >> ownToNbrDebug.nFaces
>> ownToNbrDebug.nPoints
>> ownToNbrDebug.nEdges
>> ownToNbrDebug.nInternalEdges;
return is;
}
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const coupledPolyPatch::ownToNbrDebugOrderData& ownToNbrDebug
)
{
os << ownToNbrDebug.nFaces
<< ownToNbrDebug.nPoints
<< ownToNbrDebug.nEdges
<< ownToNbrDebug.nInternalEdges;
return os;
} }

View File

@ -54,21 +54,58 @@ class coupledPolyPatch
: :
public polyPatch public polyPatch
{ {
public: private:
enum orderingType // Private Member Functions
{
UNKNOWN, // Unspecified -> automatic ordering
COINCIDENTFULLMATCH,// Assume no transforms
// and check the points in faces match
NOORDERING // Unspecified -> no automatic ordering
};
static const NamedEnum<orderingType, 3> orderingTypeNames; //- Walk the given primitive patch. Starts at the given seed face and
// point within that face. Traverses through the next available
// manifold edge to an as yet unvisited face. Stores the order in
// which faces are visited and the point/edge through which they are
// first walked into. Direction reverses the order in which face-edges
// are considered. For two conformal patches, with the same seed face
// and point, the maps are guaranteed to match. They can therefore be
// used for ordering purposes. This can also be used to identify
// contiguous regions of the patch.
bool walk
(
const primitivePatch& pp,
const bool direction,
const label seedFacei,
const label seedFacePointi,
labelList& faceMap,
labelList& facePointMap,
label& mapFacei,
autoPtr<labelListList>& walks
) const;
protected: protected:
// Protected Classes
//- Data to pass from owner.initOrder to owner.order
struct ownToOwnOrderData
{
labelList seedFaceis;
};
//- Data to pass from owner.initOrder to nbr.order
struct ownToNbrOrderData
{
List<pointField> seedFacePoints;
};
//- Data to pass from owner.initOrder to nbr.order if debugging
struct ownToNbrDebugOrderData
{
label nFaces;
label nPoints;
label nEdges;
label nInternalEdges;
};
// Protected Data // Protected Data
//- Default matching tolerance //- Default matching tolerance
@ -77,12 +114,10 @@ protected:
//- Local matching tolerance //- Local matching tolerance
const scalar matchTolerance_; const scalar matchTolerance_;
//- Type of ordering //- Data to pass from owner.initOrder to owner.order
orderingType ordering_; mutable autoPtr<ownToOwnOrderData> ownToOwnOrderDataPtr_;
protected:
// Protected Member Functions // Protected Member Functions
//- Initialise the calculation of the patch geometry //- Initialise the calculation of the patch geometry
@ -103,46 +138,52 @@ protected:
//- Update of the patch topology //- Update of the patch topology
virtual void updateMesh(PstreamBuffers&) = 0; virtual void updateMesh(PstreamBuffers&) = 0;
//- Write point in OBJ format //- Write a patch in OBJ format
static void writeOBJ(Ostream& os, const point& pt);
//- Write selected points in OBJ format
static void writeOBJ(Ostream&, const pointField&, const labelList&);
//- Write patch
static void writeOBJ static void writeOBJ
( (
const fileName&, const fileName&,
const UList<face>&, const primitivePatch&
);
//- Write lines between two lists of points in OBJ format
static void writeOBJ
(
const fileName&,
const pointField&,
const pointField& const pointField&
); );
//- Write edge in OBJ format //- Write a set of paths in OBJ format
static void writeOBJ static void writeOBJ
( (
Ostream& os, const fileName&,
const point& p0,
const point& p1,
label& vertI
);
//- Get a unique anchor point for all faces
static pointField getAnchorPoints
(
const UList<face>&,
const pointField&, const pointField&,
const orderingType const labelListList&
); );
//- Get the number of vertices face f needs to be rotated such that //- Initialise ordering for the given primitivePatch. Fills the
// its f[0] point aligns with given anchor (within tol). // referenced data structures, but leaves transferring them to the
static label getRotation // opposite patch to the caller.
virtual void initOrder
( (
const pointField& points, ownToNbrOrderData& ownToNbr,
const face& f, autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
const point& anchor, const primitivePatch&
const scalar tol ) const;
);
//- Return new ordering for the given primitivePatch.
// Ordering is -faceMap: for every face
// index of the new face -rotation:for every new face the clockwise
// shift of the original face. Return false if nothing changes
// (faceMap is identity, rotation is 0), true otherwise.
virtual bool order
(
const ownToNbrOrderData& ownToNbr,
const autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
const primitivePatch&,
labelList& faceMap,
labelList& rotation
) const;
public: public:
@ -161,8 +202,7 @@ public:
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering
); );
//- Construct from dictionary //- Construct from dictionary
@ -172,8 +212,7 @@ public:
const dictionary& dict, const dictionary& dict,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering = UNKNOWN
); );
//- Construct as copy, resetting the boundary mesh //- Construct as copy, resetting the boundary mesh
@ -224,15 +263,10 @@ public:
return !owner(); return !owner();
} }
//- Type of ordering
virtual orderingType ordering() const
{
return ordering_;
}
//- Return transformation between the coupled patches //- Return transformation between the coupled patches
virtual const transformer& transform() const = 0; virtual const transformer& transform() const = 0;
//- Return the matching tolerance
scalar matchTolerance() const scalar matchTolerance() const
{ {
return matchTolerance_; return matchTolerance_;
@ -283,9 +317,23 @@ public:
//- Write the polyPatch data as a dictionary //- Write the polyPatch data as a dictionary
virtual void write(Ostream&) const; virtual void write(Ostream&) const;
// IOstream Operators
friend Istream& operator>>(Istream&, ownToNbrOrderData&);
friend Ostream& operator<<(Ostream&, const ownToNbrOrderData&);
friend Istream& operator>>(Istream&, ownToNbrDebugOrderData&);
friend Ostream& operator<<(Ostream&, const ownToNbrDebugOrderData&);
}; };
Istream& operator>>(Istream&, coupledPolyPatch::ownToNbrOrderData&);
Ostream& operator<<(Ostream&, const coupledPolyPatch::ownToNbrOrderData&);
Istream& operator>>(Istream&, coupledPolyPatch::ownToNbrDebugOrderData&);
Ostream& operator<<(Ostream&, const coupledPolyPatch::ownToNbrDebugOrderData&);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam } // End namespace Foam

View File

@ -78,21 +78,6 @@ class cyclicPolyPatch
//- Index of cyclic neighbour patch //- Index of cyclic neighbour patch
mutable label nbrPatchID_; mutable label nbrPatchID_;
// Specified transformation
// For translation
//- Offset vector from one side of the cyclic to the other
vector separation_;
// For rotation
//- Axis of rotation for rotational cyclics
vector rotationAxis_;
//- Point on axis of rotation for rotational cyclics
point rotationCentre_;
//- List of edges formed from connected points. e[0] is the point on //- List of edges formed from connected points. e[0] is the point on
// this patch, e[1] the corresponding point on the cyclic neighbour. // this patch, e[1] the corresponding point on the cyclic neighbour.
mutable edgeList* coupledPointsPtr_; mutable edgeList* coupledPointsPtr_;
@ -101,66 +86,17 @@ class cyclicPolyPatch
// e[1] the corresponding edge on the cyclic neigbour // e[1] the corresponding edge on the cyclic neigbour
mutable edgeList* coupledEdgesPtr_; mutable edgeList* coupledEdgesPtr_;
//- Temporary storage of owner side patch during ordering. //- Data to pass from owner.initOrder to nbr.order
mutable autoPtr<primitivePatch> ownerPatchPtr_; mutable autoPtr<ownToNbrOrderData> ownToNbrOrderDataPtr_;
//- Data to pass from owner.initOrder to nbr.order if debugging
// Private Member Functions mutable autoPtr<ownToNbrDebugOrderData> ownToNbrDebugOrderDataPtr_;
//- Calculate the transformation tensors
// smallDist : matching distance per face
// absTol : absolute error in normal
// if orderingType = unknown it first tries rotational, then
// translational transform
void calcTransformTensors
(
const vectorField& thisPatchCtrs,
const vectorField& nbrPatchCtrs,
const vectorField& thisPatchNormals,
const vectorField& nbrPatchNormals,
const scalarField& smallDist,
const scalar absTol,
const orderingType = UNKNOWN,
const transformTypes = UNSPECIFIED
) const;
//- Find amongst selected faces the one with the largest area
static label findMaxArea(const pointField&, const faceList&);
void calcTransforms
(
const primitivePatch& thisPatch,
const pointField& thisPatchCtrs,
const vectorField& thisPatchAreas,
const pointField& nbrPatchCtrs,
const vectorField& nbrPatchAreas
);
// Face ordering
// Transform the points of this patch so they align with those of
// the cyclic neighbour
void getCentresAndAnchors
(
const primitivePatch& thisPatch,
const primitivePatch& nbrPatch,
pointField& thisPatchCtrs,
pointField& nbrPatchCtrs,
pointField& anchors,
scalarField& tols
) const;
//- Return normal of face at max distance from rotation axis
vector findFaceMaxRadius(const pointField& faceCentres) const;
protected: protected:
// Protected Member functions // Protected Member functions
//- Recalculate the transformation tensors
virtual void calcTransforms();
//- Initialise the calculation of the patch geometry //- Initialise the calculation of the patch geometry
virtual void initGeometry(PstreamBuffers&); virtual void initGeometry(PstreamBuffers&);
@ -220,8 +156,7 @@ public:
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType defaultOrdering = UNKNOWN
); );
//- Construct from components //- Construct from components
@ -233,8 +168,7 @@ public:
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType,
const word& nbrPatchName, const word& nbrPatchName
const orderingType ordering
); );
//- Construct from dictionary //- Construct from dictionary
@ -244,8 +178,7 @@ public:
const dictionary& dict, const dictionary& dict,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering = UNKNOWN
); );
//- Construct as copy, resetting the boundary mesh //- Construct as copy, resetting the boundary mesh
@ -364,17 +297,16 @@ public:
return cyclicTransform::transform(); return cyclicTransform::transform();
} }
//- For a given patch face index, return the corresponding index of the
// Transformation // face on the neighbour
label transformGlobalFace(const label facei) const label transformGlobalFace(const label facei) const
{ {
label offset = facei-start(); label offset = facei - start();
label neiStart = nbrPatch().start(); label neiStart = nbrPatch().start();
if (offset >= 0 && offset < size()) if (offset >= 0 && offset < size())
{ {
return neiStart+offset; return neiStart + offset;
} }
else else
{ {
@ -385,19 +317,6 @@ public:
} }
} }
//- Axis of rotation for rotational cyclics
const vector& rotationAxis() const
{
return rotationAxis_;
}
//- Point on axis of rotation for rotational cyclics
const point& rotationCentre() const
{
return rotationCentre_;
}
//- Initialize ordering for primitivePatch. Does not //- Initialize ordering for primitivePatch. Does not
// refer to *this (except for name() and type() etc.) // refer to *this (except for name() and type() etc.)
virtual void initOrder(PstreamBuffers&, const primitivePatch&) const; virtual void initOrder(PstreamBuffers&, const primitivePatch&) const;
@ -415,7 +334,6 @@ public:
labelList& rotation labelList& rotation
) const; ) const;
//- Write the polyPatch data as a dictionary //- Write the polyPatch data as a dictionary
virtual void write(Ostream&) const; virtual void write(Ostream&) const;
}; };

View File

@ -24,6 +24,8 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "cyclicTransform.H" #include "cyclicTransform.H"
#include "unitConversion.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -40,25 +42,390 @@ namespace Foam
const NamedEnum<cyclicTransform::transformTypes, 4> const NamedEnum<cyclicTransform::transformTypes, 4>
cyclicTransform::transformTypeNames; cyclicTransform::transformTypeNames;
defineTypeNameAndDebug(cyclicTransform, 0);
} }
// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::cyclicTransform::cyclicTransform() void Foam::cyclicTransform::update()
{
if (!transformComplete_)
{
return;
}
switch (transformType_)
{
case UNSPECIFIED:
break;
case NONE:
transform_ = transformer();
break;
case ROTATIONAL:
if (rotationAngle_ == 0)
{
transform_ = transformer();
}
else
{
const tensor R =
quaternion(rotationAxis_, degToRad(rotationAngle_)).R();
if (mag(rotationCentre_) == 0)
{
transform_ = transformer(R);
}
else
{
const vector t = rotationCentre_ - (R & rotationCentre_);
transform_ = transformer(t, R);
}
}
break;
case TRANSLATIONAL:
if (mag(separation_) == 0)
{
transform_ = transformer();
}
else
{
transform_ = transformer(separation_);
}
break;
}
}
bool Foam::cyclicTransform::set
(
const cyclicTransform& t,
const scalar lengthScale,
const scalar matchTolerance
)
{
// If the supplied transform is unspecified then there is nothing to do
if (t.transformType_ == UNSPECIFIED)
{
return true;
}
// If this transform is specified then we need to check that it is
// compatible with the supplied transform
if (transformType_ != UNSPECIFIED)
{
// If the transforms are of different types then they are incompatible
if (transformType_ != t.transformType_)
{
return false;
}
// Length-tolerance
const scalar lengthTolerance = lengthScale*matchTolerance;
// If the transforms are both rotational then the axes must be in the
// same direction, the centre points must lie on the same line, and the
// angles (if available) must be opposing.
if (transformType_ == ROTATIONAL)
{
const scalar dot = rotationAxis_ & t.rotationAxis_;
if (mag(dot) < 1 - matchTolerance)
{
return false;
}
if
(
(rotationAxis_ & (rotationCentre_ - t.rotationCentre_))
> lengthTolerance
)
{
return false;
}
if (transformComplete_ && t.transformComplete_)
{
if
(
mag(degToRad(rotationAngle_ - sign(dot)*t.rotationAngle_))
> matchTolerance
)
{
return false;
}
}
}
// If the transforms are both translational then the separations must
// be opposing
if (transformType_ == TRANSLATIONAL)
{
if (transformComplete_ && t.transformComplete_)
{
if (mag(separation_ - t.separation_) > lengthTolerance)
{
return false;
}
}
}
}
// If the supplied transform is more complete then overwrite this with it
if (!transformComplete_ && t.transformComplete_)
{
*this = t;
}
return true;
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
Foam::cyclicTransform::cyclicTransform
(
const bool defaultIsNone
)
: :
transformType_(UNSPECIFIED) transformType_(defaultIsNone ? NONE : UNSPECIFIED),
rotationAxis_(vector::uniform(NaN)),
rotationCentre_(vector::uniform(NaN)),
rotationAngle_(NaN),
separation_(vector::uniform(NaN)),
transformComplete_(transformType_ == NONE),
transform_()
{} {}
Foam::cyclicTransform::cyclicTransform(const dictionary& dict) Foam::cyclicTransform::cyclicTransform
(
const dictionary& dict,
const bool defaultIsNone
)
: :
transformType_ transformType_
( (
dict.found("transformType") dict.found("transformType")
? transformTypeNames.read(dict.lookup("transformType")) ? transformTypeNames.read(dict.lookup("transformType"))
: UNSPECIFIED : (defaultIsNone ? NONE : UNSPECIFIED)
),
rotationAxis_
(
transformType_ == ROTATIONAL
? normalised(dict.lookup<vector>("rotationAxis"))
: vector::uniform(NaN)
),
rotationCentre_
(
transformType_ == ROTATIONAL
? dict.lookup<point>("rotationCentre")
: point::uniform(NaN)
),
rotationAngle_(dict.lookupOrDefault<scalar>("rotationAngle", NaN)),
separation_
(
transformType_ == TRANSLATIONAL
? dict.lookup<vector>("separation")
: vector::uniform(NaN)
),
transformComplete_
(
transformType_ == NONE
|| (transformType_ == ROTATIONAL && dict.found("rotationAngle"))
|| (transformType_ == TRANSLATIONAL && dict.found("separation"))
),
transform_(vector::uniform(NaN), tensor::uniform(NaN))
{
if (transformComplete_)
{
update();
}
}
Foam::cyclicTransform::cyclicTransform
(
const word& name,
const vectorField& areas,
const cyclicTransform& transform,
const word& nbrName,
const cyclicTransform& nbrTransform,
const scalar matchTolerance
)
:
cyclicTransform(transform)
{
// Calculate the total (vector) areas for the supplied patch data
const vector area = sum(areas);
// Calculate patch length scales
const scalar lengthScale = sqrt(mag(area));
// Copy as much data from the neighbour as possible
if (!transformComplete_ && nbrTransform.transformType_ != UNSPECIFIED)
{
if (!set(inv(nbrTransform), lengthScale, matchTolerance))
{
FatalErrorInFunction
<< "Patch " << name
<< " and neighbour patch " << nbrName
<< " have incompatible transforms:" << nl << nl << incrIndent;
FatalErrorInFunction
<< indent << name << nl << indent << token::BEGIN_BLOCK << nl
<< incrIndent;
cyclicTransform::write(FatalError);
FatalErrorInFunction
<< decrIndent << indent << token::END_BLOCK << nl << nl;
FatalErrorInFunction
<< indent << nbrName << nl << indent << token::BEGIN_BLOCK << nl
<< incrIndent;
nbrTransform.write(FatalError);
FatalErrorInFunction
<< decrIndent << indent << token::END_BLOCK << nl << nl;
FatalErrorInFunction
<< decrIndent << exit(FatalError);
}
}
}
Foam::cyclicTransform::cyclicTransform
(
const word& name,
const pointField& ctrs,
const vectorField& areas,
const cyclicTransform& transform,
const word& nbrName,
const pointField& nbrCtrs,
const vectorField& nbrAreas,
const cyclicTransform& nbrTransform,
const scalar matchTolerance
)
:
cyclicTransform
(
name,
areas,
transform,
nbrName,
nbrTransform,
matchTolerance
) )
{
// If there is no geometry from which to calculate the transform then
// nothing can be calculated
if (areas.size() == 0 || nbrAreas.size() == 0) return;
// Calculate the total (vector) areas for the supplied patch data
const vector area = sum(areas);
const vector nbrArea = sum(nbrAreas);
// Calculate patch length scales
const scalar lengthScale = sqrt(mag(area));
// Calculate the centroids for the supplied patch data
const scalarField magAreas(mag(areas));
const scalarField magNbrAreas(mag(nbrAreas));
const point ctr = sum(ctrs*magAreas)/sum(magAreas);
const point nbrCtr = sum(nbrCtrs*magNbrAreas)/sum(magNbrAreas);
// Calculate the transformation from the patch geometry
if (!transformComplete_)
{
// Calculate the average patch normals
const vector normal = normalised(area);
const vector nbrNormal = normalised(nbrArea);
const vector cross = normal ^ nbrNormal;
// Calculate the angle and distance separations
const scalar theta = acos(- min(max(normal & nbrNormal, -1), 1));
const vector delta = ctr - nbrCtr;
// If the transformation is not known then we need to detect the type
// and calculate all the properties that define it.
if (transformType_ == UNSPECIFIED)
{
transformType_ =
mag(theta) > rootSmall
? ROTATIONAL
: mag(delta) > lengthScale*rootSmall
? TRANSLATIONAL
: NONE;
if (transformType_ == ROTATIONAL)
{
rotationAxis_ = normalised(cross);
const tensor T(normal, nbrNormal, rotationAxis_);
rotationCentre_ =
inv(T) & vector(normal & ctr, nbrNormal & nbrCtr, 0);
}
// Fall through to angle and separation calculations below
}
// If the transformation is known to be rotational, then the axis and
// centre are already defined. Just set the angle.
if (transformType_ == ROTATIONAL)
{
rotationAngle_ = sign(cross & rotationAxis_)*radToDeg(theta);
}
// If the transformation is known to be translational then just
// calculate the separation.
if (transformType_ == TRANSLATIONAL)
{
separation_ = delta;
}
// Update the transform object
transformComplete_ = true;
update();
}
// Check the transformation is correct to within the matching tolerance
const point nbrCtrT =
transform_.transformPosition(nbrCtr);
const scalar ctrNbrCtrTDistance = mag(ctr - nbrCtrT);
if (ctrNbrCtrTDistance > lengthScale*matchTolerance)
{
FatalErrorInFunction
<< "The distance between the centre of patch " << name
<< " and the transformed centre of patch " << nbrName << " is "
<< ctrNbrCtrTDistance << "."
<< nl
<< "This is greater than the match tolerance of "
<< lengthScale*matchTolerance << " for the patch."
<< nl
<< "Check that the patches are geometrically similar and that any "
<< "transformations defined between them are correct"
<< nl
<< "It might be possible to fix this problem by increasing the "
<< "\"matchTolerance\" setting for this patch in the boundary "
<< exit(FatalError);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::cyclicTransform::~cyclicTransform()
{} {}
@ -66,7 +433,97 @@ Foam::cyclicTransform::cyclicTransform(const dictionary& dict)
void Foam::cyclicTransform::write(Ostream& os) const void Foam::cyclicTransform::write(Ostream& os) const
{ {
writeEntry(os, "transformType", transformTypeNames[transformType_]); const label oldPrecision = os.precision();
os.precision(16);
if (transformType_ != UNSPECIFIED)
{
writeEntry(os, "transformType", transformTypeNames[transformType_]);
}
if (transformType_ == ROTATIONAL)
{
writeEntry(os, "rotationAxis", rotationAxis_);
writeEntry(os, "rotationCentre", rotationCentre_);
if (transformComplete_)
{
writeEntry(os, "rotationAngle", rotationAngle_);
}
}
if (transformType_ == TRANSLATIONAL)
{
if (transformComplete_)
{
writeEntry(os, "separation", separation_);
}
}
os.precision(oldPrecision);
}
// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
Foam::cyclicTransform Foam::operator&
(
const transformer& t,
const cyclicTransform& c0
)
{
cyclicTransform c1(c0);
if (c1.transformType_ == cyclicTransform::ROTATIONAL)
{
c1.rotationAxis_ = normalised(t.transform(c1.rotationAxis_));
c1.rotationCentre_ = t.transformPosition(c1.rotationCentre_);
}
if (c1.transformType_ == cyclicTransform::TRANSLATIONAL)
{
if (c1.transformComplete_)
{
c1.separation_ = t.transform(c1.separation_);
}
}
if (c1.transformComplete_)
{
c1.update();
}
return c1;
}
Foam::cyclicTransform Foam::inv(const cyclicTransform& c0)
{
cyclicTransform c1(c0);
if (c1.transformType_ == cyclicTransform::ROTATIONAL)
{
if (c1.transformComplete_)
{
c1.rotationAngle_ = - c1.rotationAngle_;
}
}
if (c1.transformType_ == cyclicTransform::TRANSLATIONAL)
{
if (c1.transformComplete_)
{
c1.separation_ = - c1.separation_;
}
}
if (c1.transformComplete_)
{
c1.update();
}
return c1;
} }

View File

@ -65,25 +65,95 @@ public:
private: private:
// Private Data
//- Type of transformation //- Type of transformation
transformTypes transformType_; transformTypes transformType_;
//- Axis of rotation
vector rotationAxis_;
protected: //- Centre of rotation
point rotationCentre_;
//- Transformation between the coupled patches //- Rotation angle
mutable transformer transform_; scalar rotationAngle_;
//- Separation vector
vector separation_;
//- Is the transformation specification complete, or do some parts of
// the above data still need to be computed from the patch geometry?
bool transformComplete_;
//- Generic transformer object
transformer transform_;
// Private Member Functions
//- Re-calculate the transformer object from the other data if possible
void update();
//- Set the transform to that supplied. Return true if the
// transformations are compatible. Used for copying transformation
// data from the neighbour patch.
bool set
(
const cyclicTransform& t,
const scalar lengthScale,
const scalar matchTolerance
);
public: public:
//- Runtime type information
TypeName("cyclicTransform");
// Constructors // Constructors
// Unspecified tranformation // Transformation set as UNSPECIFIED or NONE
cyclicTransform(); cyclicTransform(const bool defaultIsNone);
// Transformation read from dictionary // Transformation read from dictionary
cyclicTransform(const dictionary& dict); cyclicTransform(const dictionary& dict, const bool defaultIsNone);
//- Construct from coupled patch data. Copies from the supplied
// transform and neighbour transform. Suitable for
// geometrically dissimilar patches.
cyclicTransform
(
const word& name,
const vectorField& areas,
const cyclicTransform& transform,
const word& nbrName,
const cyclicTransform& nbrTransform,
const scalar matchTolerance
);
//- Construct from coupled patch data. Copies from the supplied
// transform and neighbour transform, then tries to determine missing
// parts of the transformation automatically from the patch geometry.
// Suitable for geometrically similar patches only.
cyclicTransform
(
const word& name,
const pointField& ctrs,
const vectorField& areas,
const cyclicTransform& transform,
const word& nbrName,
const pointField& nbrCtrs,
const vectorField& nbrAreas,
const cyclicTransform& nbrTransform,
const scalar matchTolerance
);
// Destructor
virtual ~cyclicTransform();
// Member Functions // Member Functions
@ -96,18 +166,46 @@ public:
return transformType_; return transformType_;
} }
//- Is the transform fully specified?
bool transformComplete() const
{
return transformComplete_;
}
//- Return transformation between the coupled patches //- Return transformation between the coupled patches
const transformer& transform() const const transformer& transform() const
{ {
if (!transformComplete_)
{
FatalErrorInFunction
<< "The transformation has not been fully specified or "
<< "calculated" << exit(FatalError);
}
return transform_; return transform_;
} }
//- Write the polyPatch data as a dictionary //- Write the data to a dictionary
void write(Ostream& os) const; void write(Ostream& os) const;
// Global Operators
friend cyclicTransform operator&
(
const transformer& t,
const cyclicTransform& c
);
friend cyclicTransform inv(const cyclicTransform& c);
}; };
cyclicTransform operator&(const transformer& t, const cyclicTransform& c);
cyclicTransform inv(const cyclicTransform& c);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam } // End namespace Foam

View File

@ -68,11 +68,10 @@ public:
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering = UNKNOWN
) )
: :
cyclicPolyPatch(name, size, start, index, bm, patchType, ordering) cyclicPolyPatch(name, size, start, index, bm, patchType)
{} {}
//- Construct from dictionary //- Construct from dictionary

View File

@ -1,305 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 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::oldCyclicPolyPatch
Description
'old' style cyclic polyPatch with all faces in single patch. Does ordering
but cannot be used to run. Writes 'type cyclic' so foamUpgradeCyclics
can be run afterwards.
Used to get cyclics from mesh converters that assume cyclics in single
patch (e.g. fluent3DMeshToFoam)
SourceFiles
oldCyclicPolyPatch.C
\*---------------------------------------------------------------------------*/
#ifndef oldCyclicPolyPatch_H
#define oldCyclicPolyPatch_H
#include "coupledPolyPatch.H"
#include "cyclicTransform.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class oldCyclicPolyPatch Declaration
\*---------------------------------------------------------------------------*/
class oldCyclicPolyPatch
:
public coupledPolyPatch,
public cyclicTransform
{
// Private Data
//- Morph:angle between normals of neighbouring faces.
// Used to split cyclic into halves.
scalar featureCos_;
// For translation
//- Offset vector from one side of the cyclic to the other
vector separation_;
// For rotation
//- Axis of rotation for rotational cyclics
vector rotationAxis_;
//- Point on axis of rotation for rotational cyclics
point rotationCentre_;
// Private Member Functions
//- Find amongst selected faces the one with the largest area
static label findMaxArea(const pointField&, const faceList&);
void calcTransforms();
//- Calculate face centres
static pointField calcFaceCentres
(
const UList<face>&,
const pointField&
);
//- Get f[0] for all faces
static pointField getAnchorPoints
(
const UList<face>&,
const pointField&
);
// Face ordering
//- Find the two parts of the faces of pp using feature edges.
// Returns true if successful.
bool getGeometricHalves
(
const primitivePatch&,
labelList&,
labelList&
) const;
//- Calculate geometric factors of the two halves.
void getCentresAndAnchors
(
const primitivePatch&,
const faceList& half0Faces,
const faceList& half1Faces,
pointField& ppPoints,
pointField& half0Ctrs,
pointField& half1Ctrs,
pointField& anchors0,
scalarField& tols
) const;
//- Given matched faces matches the anchor point. Sets faceMap,
// rotation. Returns true if all matched.
bool matchAnchors
(
const bool report,
const primitivePatch&,
const labelList&,
const pointField&,
const labelList&,
const faceList&,
const labelList&,
const scalarField&,
labelList& faceMap,
labelList& rotation
) const;
//- For rotational cases, try to find a unique face on each side
// of the cyclic.
label getConsistentRotationFace
(
const pointField& faceCentres
) const;
protected:
// Protected Member functions
//- Initialise the calculation of the patch geometry
virtual void initGeometry(PstreamBuffers&);
//- Calculate the patch geometry
virtual void calcGeometry(PstreamBuffers&);
//- Initialise the patches for moving points
virtual void initMovePoints(PstreamBuffers&, const pointField&);
//- Correct patches after moving points
virtual void movePoints(PstreamBuffers&, const pointField&);
//- Initialise the update of the patch topology
virtual void initUpdateMesh(PstreamBuffers&);
//- Update of the patch topology
virtual void updateMesh(PstreamBuffers&);
public:
//- Runtime type information
TypeName("oldCyclic");
// Constructors
//- Construct from components
oldCyclicPolyPatch
(
const word& name,
const label size,
const label start,
const label index,
const polyBoundaryMesh& bm,
const word& patchType,
const orderingType ordering = UNKNOWN
);
//- Construct from dictionary
oldCyclicPolyPatch
(
const word& name,
const dictionary& dict,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
);
//- Construct as copy, resetting the boundary mesh
oldCyclicPolyPatch(const oldCyclicPolyPatch&, const polyBoundaryMesh&);
//- Construct given the original patch and resetting the
// face list and boundary mesh information
oldCyclicPolyPatch
(
const oldCyclicPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
);
//- Construct and return a clone, resetting the boundary mesh
virtual autoPtr<polyPatch> clone(const polyBoundaryMesh& bm) const
{
return autoPtr<polyPatch>(new oldCyclicPolyPatch(*this, bm));
}
//- Construct and return a clone, resetting the face list
// and boundary mesh
virtual autoPtr<polyPatch> clone
(
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
) const
{
return autoPtr<polyPatch>
(
new oldCyclicPolyPatch(*this, bm, index, newSize, newStart)
);
}
// Destructor
virtual ~oldCyclicPolyPatch();
// Member Functions
//- Does this side own the patch ?
virtual bool owner() const
{
NotImplemented;
return true;
}
//- Return transformation between the coupled patches
virtual const transformer& transform() const
{
return cyclicTransform::transform();
}
//- Calculate the patch geometry
virtual void calcGeometry
(
const primitivePatch& referPatch,
const pointField& thisCtrs,
const vectorField& thisAreas,
const pointField& thisCc,
const pointField& nbrCtrs,
const vectorField& nbrAreas,
const pointField& nbrCc
);
//- Initialize ordering for primitivePatch. Does not
// refer to *this (except for name() and type() etc.)
virtual void initOrder
(
PstreamBuffers&,
const primitivePatch&
) const;
//- Return new ordering for primitivePatch.
// Ordering is -faceMap: for every face
// index of the new face -rotation:for every new face the clockwise
// shift of the original face. Return false if nothing changes
// (faceMap is identity, rotation is 0), true otherwise.
virtual bool order
(
PstreamBuffers&,
const primitivePatch&,
labelList& faceMap,
labelList& rotation
) const;
//- Write the polyPatch data as a dictionary
virtual void write(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -55,11 +55,10 @@ Foam::processorPolyPatch::processorPolyPatch
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const orderingType ordering,
const word& patchType const word& patchType
) )
: :
coupledPolyPatch(name, size, start, index, bm, patchType, ordering), coupledPolyPatch(name, size, start, index, bm, patchType),
myProcNo_(myProcNo), myProcNo_(myProcNo),
neighbProcNo_(neighbProcNo), neighbProcNo_(neighbProcNo),
neighbFaceCentres_(), neighbFaceCentres_(),
@ -76,7 +75,6 @@ Foam::processorPolyPatch::processorPolyPatch
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const orderingType ordering,
const word& patchType const word& patchType
) )
: :
@ -87,8 +85,7 @@ Foam::processorPolyPatch::processorPolyPatch
start, start,
index, index,
bm, bm,
patchType, patchType
ordering
), ),
myProcNo_(myProcNo), myProcNo_(myProcNo),
neighbProcNo_(neighbProcNo), neighbProcNo_(neighbProcNo),
@ -247,38 +244,27 @@ void Foam::processorPolyPatch::calcGeometry(PstreamBuffers& pBufs)
} }
else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei])) else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei]))
{ {
fileName nm const fileName patchOBJName
( (
boundaryMesh().mesh().time().path() boundaryMesh().mesh().time().path()/name() + "_faces.obj"
/name()+"_faces.obj"
); );
Pout<< "processorPolyPatch::calcGeometry : Writing my " Pout<< "processorPolyPatch::calcGeometry : Writing my "
<< size() << size() << " faces to " << patchOBJName << endl;
<< " faces to OBJ file " << nm << endl;
writeOBJ(nm, *this, points()); writeOBJ(patchOBJName, *this);
OFstream ccStr const fileName centresOBJName
( (
boundaryMesh().mesh().time().path() boundaryMesh().mesh().time().path()/name()
/name() + "_faceCentresConnections.obj" + "_faceCentresConnections.obj"
); );
Pout<< "processorPolyPatch::calcGeometry :" Pout<< "processorPolyPatch::calcGeometry :"
<< " Dumping cell centre lines between" << " Dumping lines between corresponding face centres to "
<< " corresponding face centres to OBJ file" << ccStr.name() << centresOBJName.name() << endl;
<< endl;
label vertI = 0; writeOBJ(centresOBJName, neighbFaceCentres_, faceCentres());
forAll(faceCentres(), facej)
{
const point& c0 = neighbFaceCentres_[facej];
const point& c1 = faceCentres()[facej];
writeOBJ(ccStr, c0, c1, vertI);
}
FatalErrorInFunction FatalErrorInFunction
<< "face " << facei << " area does not match neighbour by " << "face " << facei << " area does not match neighbour by "
@ -521,190 +507,38 @@ void Foam::processorPolyPatch::initOrder
const primitivePatch& pp const primitivePatch& pp
) const ) const
{ {
if if (!Pstream::parRun())
(
!Pstream::parRun()
|| ordering() == NOORDERING
)
{ {
return; return;
} }
if (debug)
{
fileName nm
(
boundaryMesh().mesh().time().path()
/name()+"_faces.obj"
);
Pout<< "processorPolyPatch::order : Writing my " << pp.size()
<< " faces to OBJ file " << nm << endl;
writeOBJ(nm, pp, pp.points());
// Calculate my face centres
const pointField& fc = pp.faceCentres();
OFstream localStr
(
boundaryMesh().mesh().time().path()
/name() + "_localFaceCentres.obj"
);
Pout<< "processorPolyPatch::order : "
<< "Dumping " << fc.size()
<< " local faceCentres to " << localStr.name() << endl;
forAll(fc, facei)
{
writeOBJ(localStr, fc[facei]);
}
}
if (owner()) if (owner())
{ {
if (ordering() == COINCIDENTFULLMATCH) ownToNbrOrderData ownToNbr;
autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
(
coupledPolyPatch::debug
? new ownToNbrDebugOrderData()
: nullptr
);
coupledPolyPatch::initOrder
(
ownToNbr,
ownToNbrDebugPtr,
pp
);
UOPstream toNeighbour(neighbProcNo(), pBufs);
toNeighbour << ownToNbr;
if (coupledPolyPatch::debug)
{ {
// Pass the patch points and faces across toNeighbour << ownToNbrDebugPtr();
UOPstream toNeighbour(neighbProcNo(), pBufs);
toNeighbour << pp.localPoints()
<< pp.localFaces();
}
else
{
const pointField& ppPoints = pp.points();
pointField anchors(getAnchorPoints(pp, ppPoints, ordering()));
// Get the average of the points of each face. This is needed in
// case the face centroid calculation is incorrect due to the face
// having a very high aspect ratio.
pointField facePointAverages(pp.size(), Zero);
forAll(pp, fI)
{
const labelList& facePoints = pp[fI];
forAll(facePoints, pI)
{
facePointAverages[fI] += ppPoints[facePoints[pI]];
}
facePointAverages[fI] /= facePoints.size();
}
// Now send all info over to the neighbour
UOPstream toNeighbour(neighbProcNo(), pBufs);
toNeighbour << pp.faceCentres() << pp.faceNormals()
<< anchors << facePointAverages;
} }
} }
} }
Foam::label Foam::processorPolyPatch::matchFace
(
const face& a,
const pointField& aPts,
const face& b,
const pointField& bPts,
const bool sameOrientation,
const scalar absTolSqr,
scalar& matchDistSqr
)
{
if (a.size() != b.size())
{
return -1;
}
CirculatorBase::direction circulateDirection =
CirculatorBase::direction::clockwise;
if (!sameOrientation)
{
circulateDirection = CirculatorBase::direction::anticlockwise;
}
label matchFp = -1;
scalar closestMatchDistSqr = sqr(great);
ConstCirculator<face> aCirc(a);
ConstCirculator<face> bCirc(b);
do
{
const scalar diffSqr = magSqr(aPts[aCirc()] - bPts[bCirc()]);
if (diffSqr < absTolSqr)
{
// Found a matching point. Set the fulcrum of b to the iterator
ConstCirculator<face> bCirc2 = bCirc;
++aCirc;
bCirc2.setFulcrumToIterator();
if (!sameOrientation)
{
--bCirc2;
}
else
{
++bCirc2;
}
matchDistSqr = diffSqr;
do
{
const scalar diffSqr2 = magSqr(aPts[aCirc()] - bPts[bCirc2()]);
if (diffSqr2 > absTolSqr)
{
// No match.
break;
}
matchDistSqr += diffSqr2;
}
while
(
aCirc.circulate(CirculatorBase::direction::clockwise),
bCirc2.circulate(circulateDirection)
);
if (!aCirc.circulate())
{
if (matchDistSqr < closestMatchDistSqr)
{
closestMatchDistSqr = matchDistSqr;
if (!sameOrientation)
{
matchFp = a.size() - bCirc.nRotations();
}
else
{
matchFp = bCirc.nRotations();
}
if (closestMatchDistSqr == 0)
{
break;
}
}
}
// Reset aCirc
aCirc.setIteratorToFulcrum();
}
} while (bCirc.circulate(circulateDirection));
matchDistSqr = closestMatchDistSqr;
return matchFp;
}
bool Foam::processorPolyPatch::order bool Foam::processorPolyPatch::order
( (
PstreamBuffers& pBufs, PstreamBuffers& pBufs,
@ -713,387 +547,38 @@ bool Foam::processorPolyPatch::order
labelList& rotation labelList& rotation
) const ) const
{ {
// Note: we only get the faces that originate from internal faces. if (!Pstream::parRun())
if
(
!Pstream::parRun()
|| ordering() == NOORDERING
)
{ {
return false; return false;
} }
faceMap.setSize(pp.size()); ownToNbrOrderData ownToNbr;
faceMap = -1; autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
(
coupledPolyPatch::debug
? new ownToNbrDebugOrderData()
: nullptr
);
rotation.setSize(pp.size()); if (!owner())
rotation = 0;
bool change = false;
if (owner())
{ {
// Do nothing (i.e. identical mapping, zero rotation). UIPstream fromOwner(neighbProcNo(), pBufs);
// See comment at top. fromOwner >> ownToNbr;
forAll(faceMap, patchFacei) if (coupledPolyPatch::debug)
{ {
faceMap[patchFacei] = patchFacei; fromOwner >> ownToNbrDebugPtr();
} }
if (ordering() != COINCIDENTFULLMATCH)
{
const pointField& ppPoints = pp.points();
pointField anchors(getAnchorPoints(pp, ppPoints, ordering()));
// Calculate typical distance from face centre
scalarField tols
(
matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres())
);
forAll(faceMap, patchFacei)
{
const point& wantedAnchor = anchors[patchFacei];
rotation[patchFacei] = getRotation
(
ppPoints,
pp[patchFacei],
wantedAnchor,
tols[patchFacei]
);
if (rotation[patchFacei] > 0)
{
change = true;
}
}
}
return change;
} }
else
{ return
// Calculate the absolute matching tolerance coupledPolyPatch::order
scalarField tols
( (
matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres()) ownToNbr,
ownToNbrDebugPtr,
pp,
faceMap,
rotation
); );
if (ordering() == COINCIDENTFULLMATCH)
{
vectorField masterPts;
faceList masterFaces;
{
UIPstream fromNeighbour(neighbProcNo(), pBufs);
fromNeighbour >> masterPts >> masterFaces;
}
const pointField& localPts = pp.localPoints();
const faceList& localFaces = pp.localFaces();
label nMatches = 0;
forAll(pp, lFacei)
{
const face& localFace = localFaces[lFacei];
label faceRotation = -1;
const scalar absTolSqr = sqr(tols[lFacei]);
scalar closestMatchDistSqr = sqr(great);
scalar matchDistSqr = sqr(great);
label closestFaceMatch = -1;
label closestFaceRotation = -1;
forAll(masterFaces, mFacei)
{
const face& masterFace = masterFaces[mFacei];
faceRotation = matchFace
(
localFace,
localPts,
masterFace,
masterPts,
false,
absTolSqr,
matchDistSqr
);
if
(
faceRotation != -1
&& matchDistSqr < closestMatchDistSqr
)
{
closestMatchDistSqr = matchDistSqr;
closestFaceMatch = mFacei;
closestFaceRotation = faceRotation;
}
if (closestMatchDistSqr == 0)
{
break;
}
}
if
(
closestFaceRotation != -1
&& closestMatchDistSqr < absTolSqr
)
{
faceMap[lFacei] = closestFaceMatch;
rotation[lFacei] = closestFaceRotation;
if (lFacei != closestFaceMatch || closestFaceRotation > 0)
{
change = true;
}
nMatches++;
}
else
{
Pout<< "Number of matches = " << nMatches << " / "
<< pp.size() << endl;
pointField pts(localFace.size());
forAll(localFace, pI)
{
const label localPtI = localFace[pI];
pts[pI] = localPts[localPtI];
}
FatalErrorInFunction
<< "No match for face " << localFace << nl << pts
<< abort(FatalError);
}
}
return change;
}
else
{
vectorField masterCtrs;
vectorField masterNormals;
vectorField masterAnchors;
vectorField masterFacePointAverages;
// Receive data from neighbour
{
UIPstream fromNeighbour(neighbProcNo(), pBufs);
fromNeighbour >> masterCtrs >> masterNormals
>> masterAnchors >> masterFacePointAverages;
}
if (debug || masterCtrs.size() != pp.size())
{
{
OFstream nbrStr
(
boundaryMesh().mesh().time().path()
/name() + "_nbrFaceCentres.obj"
);
Pout<< "processorPolyPatch::order : "
<< "Dumping neighbour faceCentres to " << nbrStr.name()
<< endl;
forAll(masterCtrs, facei)
{
writeOBJ(nbrStr, masterCtrs[facei]);
}
}
if (masterCtrs.size() != pp.size())
{
FatalErrorInFunction
<< "in patch:" << name() << " : "
<< "Local size of patch is " << pp.size() << " (faces)."
<< endl
<< "Received from neighbour " << masterCtrs.size()
<< " faceCentres!"
<< abort(FatalError);
}
}
// Geometric match of face centre vectors
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 1. Try existing ordering and transformation
bool matchedAll = matchPoints
(
pp.faceCentres(),
masterCtrs,
pp.faceNormals(),
masterNormals,
tols,
false,
faceMap
);
// Try using face point average for matching
if (!matchedAll)
{
const pointField& ppPoints = pp.points();
pointField facePointAverages(pp.size(), Zero);
forAll(pp, fI)
{
const labelList& facePoints = pp[fI];
forAll(facePoints, pI)
{
facePointAverages[fI] += ppPoints[facePoints[pI]];
}
facePointAverages[fI] /= facePoints.size();
}
scalarField tols2
(
calcFaceTol(pp, pp.points(), facePointAverages)
);
labelList faceMap2(faceMap.size(), -1);
matchedAll = matchPoints
(
facePointAverages,
masterFacePointAverages,
pp.faceNormals(),
masterNormals,
tols2,
true,
faceMap2
);
forAll(faceMap, oldFacei)
{
if (faceMap[oldFacei] == -1)
{
faceMap[oldFacei] = faceMap2[oldFacei];
}
}
matchedAll = true;
forAll(faceMap, oldFacei)
{
if (faceMap[oldFacei] == -1)
{
matchedAll = false;
}
}
}
if (!matchedAll || debug)
{
// Dump faces
fileName str
(
boundaryMesh().mesh().time().path()
/name() + "_faces.obj"
);
Pout<< "processorPolyPatch::order :"
<< " Writing faces to OBJ file " << str.name() << endl;
writeOBJ(str, pp, pp.points());
OFstream ccStr
(
boundaryMesh().mesh().time().path()
/name() + "_faceCentresConnections.obj"
);
Pout<< "processorPolyPatch::order :"
<< " Dumping newly found match as lines between"
<< " corresponding face centres to OBJ file "
<< ccStr.name()
<< endl;
label vertI = 0;
forAll(pp.faceCentres(), facei)
{
label masterFacei = faceMap[facei];
if (masterFacei != -1)
{
const point& c0 = masterCtrs[masterFacei];
const point& c1 = pp.faceCentres()[facei];
writeOBJ(ccStr, c0, c1, vertI);
}
}
}
if (!matchedAll)
{
SeriousErrorInFunction
<< "in patch:" << name() << " : "
<< "Cannot match vectors to faces on both sides of patch"
<< endl
<< " masterCtrs[0]:" << masterCtrs[0] << endl
<< " ctrs[0]:" << pp.faceCentres()[0] << endl
<< " Check your topology changes or maybe you have"
<< " multiple separated (from cyclics) processor patches"
<< endl
<< " Continuing with incorrect face ordering from now on"
<< endl;
return false;
}
// Set rotation.
forAll(faceMap, oldFacei)
{
// The face f will be at newFacei (after morphing) and we want
// its anchorPoint (= f[0]) to align with the anchorpoint for
// the corresponding face on the other side.
label newFacei = faceMap[oldFacei];
const point& wantedAnchor = masterAnchors[newFacei];
rotation[newFacei] = getRotation
(
pp.points(),
pp[oldFacei],
wantedAnchor,
tols[oldFacei]
);
if (rotation[newFacei] == -1)
{
SeriousErrorInFunction
<< "in patch " << name()
<< " : "
<< "Cannot find point on face " << pp[oldFacei]
<< " with vertices "
<< UIndirectList<point>(pp.points(), pp[oldFacei])()
<< " that matches point " << wantedAnchor
<< " when matching the halves of processor patch "
<< name()
<< "Continuing with incorrect face ordering from now on"
<< endl;
return false;
}
}
forAll(faceMap, facei)
{
if (faceMap[facei] != facei || rotation[facei] != 0)
{
return true;
}
}
return false;
}
}
} }

View File

@ -93,7 +93,6 @@ protected:
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const orderingType defaultOrdering = UNKNOWN,
const word& patchType = typeName const word& patchType = typeName
); );
@ -152,7 +151,6 @@ public:
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const orderingType ordering = UNKNOWN,
const word& patchType = typeName const word& patchType = typeName
); );
@ -340,21 +338,6 @@ public:
// refer to *this (except for name() and type() etc.) // refer to *this (except for name() and type() etc.)
virtual void initOrder(PstreamBuffers&, const primitivePatch&) const; virtual void initOrder(PstreamBuffers&, const primitivePatch&) const;
//- Returns rotation.
// -1 : no match
// 0 : match
// >0 : match if rotated clockwise by this amount
static label matchFace
(
const face& localFace,
const pointField& localPts,
const face& masterFace,
const pointField& masterPts,
const bool sameOrientation,
const scalar absTolSqr,
scalar& matchDistSqr
);
//- Return new ordering for primitivePatch. //- Return new ordering for primitivePatch.
// Ordering is -faceMap: for every face // Ordering is -faceMap: for every face
// index of the new face -rotation:for every new face the clockwise // index of the new face -rotation:for every new face the clockwise

View File

@ -48,7 +48,6 @@ Foam::processorCyclicPolyPatch::processorCyclicPolyPatch
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const word& referPatchName, const word& referPatchName,
const orderingType ordering,
const word& patchType const word& patchType
) )
: :
@ -61,7 +60,6 @@ Foam::processorCyclicPolyPatch::processorCyclicPolyPatch
bm, bm,
myProcNo, myProcNo,
neighbProcNo, neighbProcNo,
ordering,
patchType patchType
), ),
referPatchName_(referPatchName), referPatchName_(referPatchName),
@ -237,29 +235,11 @@ void Foam::processorCyclicPolyPatch::calcGeometry(PstreamBuffers& pBufs)
if (Pstream::parRun()) if (Pstream::parRun())
{ {
cyclicPolyPatch& pp = const_cast<cyclicPolyPatch&>(referPatch());
pp.calcTransformTensors
(
faceCentres(),
neighbFaceCentres(),
faceAreas()/mag(faceAreas()),
neighbFaceAreas()/mag(neighbFaceAreas()),
matchTolerance()*calcFaceTol(*this, points(), faceCentres()),
matchTolerance(),
ordering(),
transformType()
);
// Where do we store the calculated transformation?
// - on the processor patch?
// - on the underlying cyclic patch?
// - or do we not auto-calculate the transformation but
// have option of reading it.
// Update underlying cyclic halves. Need to do both since only one // Update underlying cyclic halves. Need to do both since only one
// half might be present as a processorCyclic. // half might be present as a processorCyclic.
cyclicPolyPatch& pp = const_cast<cyclicPolyPatch&>(referPatch());
pp.calcGeometry pp.calcGeometry
( (
*this, *this,
@ -325,7 +305,6 @@ void Foam::processorCyclicPolyPatch::initOrder
const primitivePatch& pp const primitivePatch& pp
) const ) const
{ {
// For now use the same algorithm as processorPolyPatch
processorPolyPatch::initOrder(pBufs, pp); processorPolyPatch::initOrder(pBufs, pp);
} }
@ -338,7 +317,6 @@ bool Foam::processorCyclicPolyPatch::order
labelList& rotation labelList& rotation
) const ) const
{ {
// For now use the same algorithm as processorPolyPatch
return processorPolyPatch::order(pBufs, pp, faceMap, rotation); return processorPolyPatch::order(pBufs, pp, faceMap, rotation);
} }

View File

@ -122,7 +122,6 @@ public:
const int myProcNo, const int myProcNo,
const int neighbProcNo, const int neighbProcNo,
const word& referPatchName, const word& referPatchName,
const orderingType ordering = UNKNOWN,
const word& patchType = typeName const word& patchType = typeName
); );
@ -329,7 +328,7 @@ public:
//- Return transformation between the coupled patches //- Return transformation between the coupled patches
virtual const transformer& transform() const virtual const transformer& transform() const
{ {
return referPatch().transform_; return referPatch().transform();
} }
//- Initialize ordering for primitivePatch. Does not //- Initialize ordering for primitivePatch. Does not

View File

@ -6,6 +6,9 @@ ensight/part/ensightPartCells.C
ensight/part/ensightPartFaces.C ensight/part/ensightPartFaces.C
ensight/part/ensightParts.C ensight/part/ensightParts.C
mergedCyclic/mergedCyclicPolyPatch.C
mergedCyclic/polyMeshUnMergeCyclics.C
meshTables/boundaryRegion.C meshTables/boundaryRegion.C
meshTables/cellTable.C meshTables/cellTable.C

View File

@ -1,9 +1,11 @@
EXE_INC = \ EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude -I$(LIB_SRC)/meshTools/lnInclude
LIB_LIBS = \ LIB_LIBS = \
-lfileFormats \ -lfileFormats \
-lfiniteVolume \ -lfiniteVolume \
-ldynamicMesh \
-lmeshTools -lmeshTools

View File

@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2020 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 "mergedCyclicPolyPatch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(mergedCyclicPolyPatch, 0);
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word);
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, dictionary);
}
// * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
Foam::mergedCyclicPolyPatch::mergedCyclicPolyPatch
(
const word& name,
const label size,
const label start,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
)
:
polyPatch(name, size, start, index, bm, patchType)
{}
Foam::mergedCyclicPolyPatch::mergedCyclicPolyPatch
(
const word& name,
const dictionary& dict,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
)
:
polyPatch(name, dict, index, bm, patchType)
{}
Foam::mergedCyclicPolyPatch::mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch& pp,
const polyBoundaryMesh& bm
)
:
polyPatch(pp, bm)
{}
Foam::mergedCyclicPolyPatch::mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
)
:
polyPatch(pp, bm, index, newSize, newStart)
{}
Foam::mergedCyclicPolyPatch::mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const label newStart
)
:
polyPatch(pp, bm, index, mapAddressing, newStart)
{}
// ************************************************************************* //

View File

@ -0,0 +1,170 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2020 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::mergedCyclicPolyPatch
Description
Placeholder for two patches describing a cyclic interface. Used in mesh
conversion processes involving formats in which both halves of a cyclic
interface are stored on the same patch.
See also
Foam::polyMeshUnMergeCyclics
SourceFiles
mergedCyclicPolyPatch.C
\*---------------------------------------------------------------------------*/
#ifndef mergedCyclicPolyPatch_H
#define mergedCyclicPolyPatch_H
#include "polyPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class mergedCyclicPolyPatch Declaration
\*---------------------------------------------------------------------------*/
class mergedCyclicPolyPatch
:
public polyPatch
{
public:
//- Runtime type information
TypeName("mergedCyclic");
// Constructors
//- Construct from components
mergedCyclicPolyPatch
(
const word& name,
const label size,
const label start,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
);
//- Construct from dictionary
mergedCyclicPolyPatch
(
const word& name,
const dictionary& dict,
const label index,
const polyBoundaryMesh& bm,
const word& patchType
);
//- Construct as copy, resetting the boundary mesh
mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch&,
const polyBoundaryMesh&
);
//- Construct given the original patch and resetting the
// face list and boundary mesh information
mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
);
//- Construct given the original patch and a map
mergedCyclicPolyPatch
(
const mergedCyclicPolyPatch& pp,
const polyBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const label newStart
);
//- Construct and return a clone, resetting the boundary mesh
virtual autoPtr<polyPatch> clone(const polyBoundaryMesh& bm) const
{
return autoPtr<polyPatch>(new mergedCyclicPolyPatch(*this, bm));
}
//- Construct and return a clone, resetting the face list
// and boundary mesh
virtual autoPtr<polyPatch> clone
(
const polyBoundaryMesh& bm,
const label index,
const label newSize,
const label newStart
) const
{
return autoPtr<polyPatch>
(
new mergedCyclicPolyPatch(*this, bm, index, newSize, newStart)
);
}
//- Construct and return a clone, resetting the face list
// and boundary mesh
virtual autoPtr<polyPatch> clone
(
const polyBoundaryMesh& bm,
const label index,
const labelUList& mapAddressing,
const label newStart
) const
{
return autoPtr<polyPatch>
(
new mergedCyclicPolyPatch
(
*this,
bm,
index,
mapAddressing,
newStart
)
);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,311 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2020 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 "polyMeshUnMergeCyclics.H"
#include "cyclicPolyPatch.H"
#include "mergedCyclicPolyPatch.H"
#include "polyTopoChange.H"
#include "unitConversion.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
labelList primitivePatchGetZones
(
const primitivePatch& pp,
const scalar includedAngle
)
{
const scalar minCos = Foam::cos(degToRad(180.0 - includedAngle));
const labelListList& edgeFaces = pp.edgeFaces();
const labelListList& faceEdges = pp.faceEdges();
const vectorField& faceNormals = pp.faceNormals();
// Working arrays
labelList facePrev(pp.size(), -1);
labelList faceEdge0(pp.size(), -1);
labelList faceEdgeFace0(pp.size(), -1);
// The resulting set of zones
labelList faceZones(pp.size(), -1);
// The current zone being populated
label zonei = 0;
// The starting face of the current zone
label facei0 = 0;
// While there are faces to consider
while (facei0 < faceZones.size())
{
label facei = facei0;
label faceEdgei = 0;
label faceEdgeFacei = 0;
faceZones[facei] = zonei;
do
{
// Find the connected edge and face
const label edgei = faceEdges[facei][faceEdgei];
const label facej = edgeFaces[edgei][faceEdgeFacei];
// Find the corresponding position within the other face
const label faceEdgej = findIndex(faceEdges[facej], edgei);
const label faceEdgeFacej = findIndex(edgeFaces[edgei], facej);
if
(
faceZones[facej] == zonei
|| (faceNormals[facei] & faceNormals[facej]) < minCos
|| face::compare(pp[facei], pp[facej]) == -1
|| edge::compare
(
pp[facei].faceEdge(faceEdgei),
pp[facej].faceEdge(faceEdgej)
) != -1
)
{
// Move to the next face for this edge
faceEdgeFacei = edgeFaces[edgei].fcIndex(faceEdgeFacei);
// If wrapped around, move to the next edge on the face
if (faceEdgeFacei == 0)
{
faceEdgei = faceEdges[facei].fcIndex(faceEdgei);
}
// If back at the start then backtrack to the previous face
if
(
faceEdgei == faceEdge0[facei]
&& faceEdgeFacei == faceEdgeFace0[facei]
)
{
facei = facePrev[facei];
faceEdgei = faceEdge0[facei];
faceEdgeFacei = faceEdgeFace0[facei];
}
}
else
{
// Move into the next face
faceZones[facej] = zonei;
facePrev[facej] = facei;
facei = facej;
// Set the starting position within this face
faceEdgei = faceEdge0[facej] = faceEdgej;
faceEdgeFacei = faceEdgeFace0[facej] = faceEdgeFacej;
}
}
while (facei != facei0 || faceEdgei != 0 || faceEdgeFacei != 0);
// Get the next zone and starting face
++ zonei;
while (facei0 < faceZones.size() && faceZones[facei0] != -1)
{
++ facei0;
}
}
return faceZones;
}
boolList primitivePatchGetHalves
(
const primitivePatch& pp,
const scalar includedAngle
)
{
const labelList faceZones(primitivePatchGetZones(pp, includedAngle));
// If the number of zones is not two, then the split has failed
// !!! To improve the robustness of this in the presence of non-planar
// cyclics we would have to find pairs of zones that all share the same
// transformation. We would still fail if the number of zones were odd.
if (findMin(faceZones) != 0 && findMax(faceZones) != 1)
{
FatalErrorInFunction
<< "Patch did not divide into halves based on topology and an "
<< "included angle of " << includedAngle << " degrees"
<< exit(FatalError);
}
// Convert the zone labels into bools describing which half each face is in
boolList faceHalves(pp.size());
forAll(faceHalves, facei)
{
faceHalves[facei] = faceZones[facei] == 1;
}
return faceHalves;
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void Foam::polyMeshUnMergeCyclics(polyMesh& mesh, const scalar includedAngle)
{
// Add cyclic patches. Clone all the existing patches into a new list, and
// add two additional empty cyclic patches for each merged-cyclic. Then
// re-patch the mesh
DynamicList<polyPatch*> patches;
forAll(mesh.boundaryMesh(), patchi)
{
const polyPatch& pp = mesh.boundaryMesh()[patchi];
patches.append
(
pp.clone
(
mesh.boundaryMesh(),
patches.size(),
pp.size(),
pp.start()
).ptr()
);
}
bool hasMergedCyclics = false;
labelList patchHalf0(mesh.boundaryMesh().size(), -1);
labelList patchHalf1(mesh.boundaryMesh().size(), -1);
forAll(mesh.boundaryMesh(), patchi)
{
const polyPatch& pp = mesh.boundaryMesh()[patchi];
if (isA<mergedCyclicPolyPatch>(pp))
{
hasMergedCyclics = true;
patchHalf0[patchi] = patches.size();
patches.append
(
new cyclicPolyPatch
(
pp.name() + "-half-0",
0,
mesh.nFaces(),
patches.size(),
mesh.boundaryMesh(),
cyclicPolyPatch::typeName,
pp.name() + "-half-1"
)
);
patchHalf1[patchi] = patches.size();
patches.append
(
new cyclicPolyPatch
(
pp.name() + "-half-1",
0,
mesh.nFaces(),
patches.size(),
mesh.boundaryMesh(),
cyclicPolyPatch::typeName,
pp.name() + "-half-0"
)
);
}
}
if (!hasMergedCyclics)
{
return;
}
mesh.removeBoundary();
mesh.addPatches(patches);
// Move faces from the merged cyclics to the pairs of cyclic patches
polyTopoChange meshMod(mesh, false);
forAll(mesh.boundaryMesh(), patchi)
{
const polyPatch& pp = mesh.boundaryMesh()[patchi];
if (isA<mergedCyclicPolyPatch>(pp))
{
const boolList patchFaceHalves
(
primitivePatchGetHalves(pp, includedAngle)
);
forAll(pp, patchFacei)
{
const label facei = pp.start() + patchFacei;
meshMod.modifyFace
(
mesh.faces()[facei],
facei,
mesh.faceOwner()[facei],
-1,
false,
patchFaceHalves[patchFacei]
? patchHalf0[patchi]
: patchHalf1[patchi],
-1,
false
);
}
}
}
autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
// Remove the (now) empty merged cyclic patches. Copy everything except the
// merged cyclics into a patch list and use this then re-patch the mesh.
patches.clear();
forAll(mesh.boundaryMesh(), patchi)
{
const polyPatch& pp = mesh.boundaryMesh()[patchi];
if (!isA<mergedCyclicPolyPatch>(pp))
{
patches.append
(
pp.clone
(
mesh.boundaryMesh(),
patches.size(),
pp.size(),
pp.start()
).ptr()
);
}
}
mesh.removeBoundary();
mesh.addPatches(patches);
}
// ************************************************************************* //

View File

@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2020 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 polyMeshUnMergeCyclics_H
#define polyMeshUnMergeCyclics_H
#include "polyMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Find all patches of type "mergedCyclic" in the given mesh and split them
// into two "standard" cyclics, using the given included angle to
// geometrically separate the halves if they meet at an angle at the axis
void polyMeshUnMergeCyclics(polyMesh& mesh, const scalar includedAngle=165);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -30,6 +30,7 @@ License
#include "emptyPolyPatch.H" #include "emptyPolyPatch.H"
#include "cellModeller.H" #include "cellModeller.H"
#include "demandDrivenData.H" #include "demandDrivenData.H"
#include "polyMeshUnMergeCyclics.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -150,6 +151,9 @@ Foam::autoPtr<Foam::polyMesh> Foam::meshReader::mesh
// adding patches also checks the mesh // adding patches also checks the mesh
mesh().addPatches(polyBoundaryPatches(mesh)); mesh().addPatches(polyBoundaryPatches(mesh));
// Un-merge any merged cyclics
polyMeshUnMergeCyclics(mesh());
warnDuplicates("boundaries", mesh().boundaryMesh().names()); warnDuplicates("boundaries", mesh().boundaryMesh().names());
addCellZones(mesh()); addCellZones(mesh());

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -24,7 +24,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "STARCDMeshReader.H" #include "STARCDMeshReader.H"
#include "oldCyclicPolyPatch.H" #include "mergedCyclicPolyPatch.H"
#include "emptyPolyPatch.H" #include "emptyPolyPatch.H"
#include "wallPolyPatch.H" #include "wallPolyPatch.H"
#include "symmetryPolyPatch.H" #include "symmetryPolyPatch.H"
@ -945,16 +945,12 @@ void Foam::meshReaders::STARCD::readBoundary(const fileName& inputName)
} }
else if (origType == "cyclic") else if (origType == "cyclic")
{ {
// incorrect. should be cyclicPatch but this patchTypes_[patchi] = mergedCyclicPolyPatch::typeName;
// requires info on connected faces.
patchTypes_[patchi] = oldCyclicPolyPatch::typeName;
patchPhysicalTypes_[patchi] = patchTypes_[patchi]; patchPhysicalTypes_[patchi] = patchTypes_[patchi];
} }
else if (origType == "baffle") else if (origType == "baffle")
{ {
// incorrect. tag the patch until we get proper support. patchTypes_[patchi] = mergedCyclicPolyPatch::typeName;
// set physical type to a canonical "baffle"
patchTypes_[patchi] = emptyPolyPatch::typeName;
patchPhysicalTypes_[patchi] = "baffle"; patchPhysicalTypes_[patchi] = "baffle";
} }
else else

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -1244,8 +1244,7 @@ void Foam::fvMeshDistribute::addProcPatches
mesh_.boundaryMesh(), mesh_.boundaryMesh(),
Pstream::myProcNo(), Pstream::myProcNo(),
proci, proci,
pcPatch.name(), pcPatch.name()
pcPatch.ordering()
); );
procPatchID[proci].insert procPatchID[proci].insert

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -25,6 +25,7 @@ License
#include "blockMesh.H" #include "blockMesh.H"
#include "Time.H" #include "Time.H"
#include "cyclicTransform.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -127,11 +128,22 @@ Foam::PtrList<Foam::dictionary> Foam::blockMesh::patchDicts() const
forAll(patchTopologies, patchi) forAll(patchTopologies, patchi)
{ {
autoPtr<polyPatch> ppPtr =
patchTopologies[patchi].clone(topology().boundaryMesh());
if (isA<cyclicTransform>(ppPtr()))
{
refCast<cyclicTransform>(ppPtr()) =
transformer(scaleFactor_*tensor::I)
& refCast<cyclicTransform>(ppPtr());
}
OStringStream os; OStringStream os;
patchTopologies[patchi].write(os); ppPtr->write(os);
IStringStream is(os.str()); IStringStream is(os.str());
patchDicts.set(patchi, new dictionary(is)); patchDicts.set(patchi, new dictionary(is));
} }
return patchDicts; return patchDicts;
} }
@ -181,18 +193,6 @@ Foam::wordList Foam::blockMesh::patchNames() const
} }
//Foam::wordList Foam::blockMesh::patchTypes() const
//{
// return topology().boundaryMesh().types();
//}
//
//
//Foam::wordList Foam::blockMesh::patchPhysicalTypes() const
//{
// return topology().boundaryMesh().physicalTypes();
//}
Foam::label Foam::blockMesh::numZonedBlocks() const Foam::label Foam::blockMesh::numZonedBlocks() const
{ {
label num = 0; label num = 0;

View File

@ -204,8 +204,7 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering
) )
: :
cyclicAMIPolyPatch cyclicAMIPolyPatch
@ -216,7 +215,6 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
index, index,
bm, bm,
patchType, patchType,
ordering,
false, false,
AMIInterpolation::imPartialFaceAreaWeight AMIInterpolation::imPartialFaceAreaWeight
), ),
@ -433,16 +431,16 @@ void Foam::cyclicACMIPolyPatch::calcGeometry
const pointField& nbrCc const pointField& nbrCc
) )
{ {
cyclicAMIPolyPatch::calcGeometry static_cast<cyclicTransform&>(*this) =
( cyclicTransform
referPatch, (
thisCtrs, name(),
thisAreas, thisAreas,
thisCc, *this,
nbrCtrs, nbrPatchName(),
nbrAreas, nbrPatch(),
nbrCc matchTolerance()
); );
} }

View File

@ -109,8 +109,7 @@ public:
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering = UNKNOWN
); );
//- Construct from dictionary //- Construct from dictionary

View File

@ -40,247 +40,6 @@ namespace Foam
} }
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
Foam::vector Foam::cyclicAMIPolyPatch::findFaceNormalMaxRadius
(
const pointField& faceCentres
) const
{
// Determine a face furthest away from the axis
const vectorField n((faceCentres - rotationCentre_) ^ rotationAxis_);
const scalarField magRadSqr(magSqr(n));
label facei = findMax(magRadSqr);
if (debug)
{
Info<< "findFaceMaxRadius(const pointField&) : patch: " << name() << nl
<< " rotFace = " << facei << nl
<< " point = " << faceCentres[facei] << nl
<< " distance = " << Foam::sqrt(magRadSqr[facei])
<< endl;
}
return n[facei];
}
void Foam::cyclicAMIPolyPatch::calcTransforms
(
const primitivePatch& thisPatch,
const pointField& thisPatchCtrs,
const vectorField& thisPatchAreas,
const pointField& nbrPatchCtrs,
const vectorField& nbrPatchAreas
)
{
if (transformType() != nbrPatch().transformType())
{
FatalErrorInFunction
<< "Patch " << name()
<< " has transform type " << transformTypeNames[transformType()]
<< ", neighbour patch " << nbrPatchName()
<< " has transform type "
<< nbrPatch().transformTypeNames[nbrPatch().transformType()]
<< exit(FatalError);
}
// Calculate transformation tensors
switch (transformType())
{
case ROTATIONAL:
{
tensor revT = Zero;
if (rotationAngleDefined_)
{
const tensor T(rotationAxis_*rotationAxis_);
const tensor S
(
0, -rotationAxis_.z(), rotationAxis_.y(),
rotationAxis_.z(), 0, -rotationAxis_.x(),
-rotationAxis_.y(), rotationAxis_.x(), 0
);
const tensor revTPos
(
T
+ cos(rotationAngle_)*(tensor::I - T)
+ sin(rotationAngle_)*S
);
const tensor revTNeg
(
T
+ cos(-rotationAngle_)*(tensor::I - T)
+ sin(-rotationAngle_)*S
);
// Check - assume correct angle when difference in face areas
// is the smallest
const vector transformedAreaPos = gSum(nbrPatchAreas & revTPos);
const vector transformedAreaNeg = gSum(nbrPatchAreas & revTNeg);
const vector area0 = gSum(thisPatchAreas);
const scalar magArea0 = mag(area0) + rootVSmall;
// Areas have opposite sign, so sum should be zero when correct
// rotation applied
const scalar errorPos = mag(transformedAreaPos + area0);
const scalar errorNeg = mag(transformedAreaNeg + area0);
const scalar normErrorPos = errorPos/magArea0;
const scalar normErrorNeg = errorNeg/magArea0;
if (errorPos > errorNeg && normErrorNeg < matchTolerance())
{
revT = revTNeg;
rotationAngle_ *= -1;
}
else
{
revT = revTPos;
}
const scalar areaError = min(normErrorPos, normErrorNeg);
if (areaError > matchTolerance())
{
WarningInFunction
<< "Patch areas are not consistent within "
<< 100*matchTolerance()
<< " % indicating a possible error in the specified "
<< "angle of rotation" << nl
<< " owner patch : " << name() << nl
<< " neighbour patch : " << nbrPatch().name()
<< nl
<< " angle : "
<< radToDeg(rotationAngle_) << " deg" << nl
<< " area error : " << 100*areaError << " %"
<< " match tolerance : " << matchTolerance()
<< endl;
}
if (debug)
{
scalar theta = radToDeg(rotationAngle_);
Pout<< "cyclicAMIPolyPatch::calcTransforms: patch:"
<< name()
<< " Specified rotation:"
<< " swept angle: " << theta << " [deg]"
<< " reverse transform: " << revT
<< endl;
}
}
else
{
point n0 = Zero;
point n1 = Zero;
if (thisPatchCtrs.size())
{
n0 = findFaceNormalMaxRadius(thisPatchCtrs);
}
if (nbrPatchCtrs.size())
{
n1 = -findFaceNormalMaxRadius(nbrPatchCtrs);
}
reduce(n0, maxMagSqrOp<point>());
reduce(n1, maxMagSqrOp<point>());
n0 /= mag(n0) + vSmall;
n1 /= mag(n1) + vSmall;
// Extended tensor from two local coordinate systems calculated
// using normal and rotation axis
const tensor E0
(
rotationAxis_,
(n0 ^ rotationAxis_),
n0
);
const tensor E1
(
rotationAxis_,
(-n1 ^ rotationAxis_),
-n1
);
revT = E1.T() & E0;
if (debug)
{
scalar theta = radToDeg(acos(-(n0 & n1)));
Pout<< "cyclicAMIPolyPatch::calcTransforms: patch:"
<< name()
<< " Specified rotation:"
<< " n0:" << n0 << " n1:" << n1
<< " swept angle: " << theta << " [deg]"
<< " reverse transform: " << revT
<< endl;
}
}
separation_ = Zero;
if (mag(rotationCentre_) > small)
{
transform_ = transformer
(
(I - revT.T()) & rotationCentre_,
revT.T()
);
}
else
{
transform_ = transformer(revT.T());
}
break;
}
case TRANSLATIONAL:
{
if (debug)
{
Pout<< "cyclicAMIPolyPatch::calcTransforms : patch:" << name()
<< " Specified translation : " << separation_
<< endl;
}
transform_ = transformer(separation_);
break;
}
default:
{
if (debug)
{
Pout<< "patch:" << name()
<< " Assuming cyclic AMI pairs are colocated" << endl;
}
separation_ = Zero;
transform_ = transformer();
break;
}
}
if (debug)
{
Pout<< "patch: " << name() << nl
<< " transform = " << transform() << nl << endl;
}
}
// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
void Foam::cyclicAMIPolyPatch::resetAMI() const void Foam::cyclicAMIPolyPatch::resetAMI() const
@ -357,39 +116,6 @@ void Foam::cyclicAMIPolyPatch::resetAMI() const
} }
void Foam::cyclicAMIPolyPatch::calcTransforms()
{
const cyclicAMIPolyPatch& thisPatch = *this;
vectorField thisPatchAreas(thisPatch.size());
forAll(thisPatch, facei)
{
thisPatchAreas[facei] = thisPatch[facei].area(thisPatch.points());
}
const cyclicAMIPolyPatch& nbrPatch = this->nbrPatch();
vectorField nbrPatchAreas(nbrPatch.size());
forAll(nbrPatch, facei)
{
nbrPatchAreas[facei] = nbrPatch[facei].area(nbrPatch.points());
}
calcTransforms
(
thisPatch,
thisPatch.faceCentres(),
thisPatchAreas,
nbrPatch.faceCentres(),
nbrPatchAreas
);
if (debug)
{
Pout<< "calcTransforms() : patch: " << name() << nl
<< " transform = " << transform() << nl << endl;
}
}
void Foam::cyclicAMIPolyPatch::initGeometry(PstreamBuffers& pBufs) void Foam::cyclicAMIPolyPatch::initGeometry(PstreamBuffers& pBufs)
{ {
// Clear the invalid AMIs and transforms // Clear the invalid AMIs and transforms
@ -439,8 +165,6 @@ void Foam::cyclicAMIPolyPatch::movePoints
) )
{ {
polyPatch::movePoints(pBufs, p); polyPatch::movePoints(pBufs, p);
calcTransforms();
} }
@ -480,18 +204,14 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType,
const orderingType ordering,
const bool AMIRequireMatch, const bool AMIRequireMatch,
const AMIInterpolation::interpolationMethod AMIMethod const AMIInterpolation::interpolationMethod AMIMethod
) )
: :
coupledPolyPatch(name, size, start, index, bm, patchType, ordering), coupledPolyPatch(name, size, start, index, bm, patchType),
cyclicTransform(true),
nbrPatchName_(word::null), nbrPatchName_(word::null),
nbrPatchID_(-1), nbrPatchID_(-1),
rotationAxis_(Zero),
rotationCentre_(point::zero),
rotationAngleDefined_(false),
rotationAngle_(0.0),
AMIs_(), AMIs_(),
AMITransforms_(), AMITransforms_(),
AMIReverse_(false), AMIReverse_(false),
@ -518,14 +238,10 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
) )
: :
coupledPolyPatch(name, dict, index, bm, patchType), coupledPolyPatch(name, dict, index, bm, patchType),
cyclicTransform(dict), cyclicTransform(dict, true),
nbrPatchName_(dict.lookupOrDefault<word>("neighbourPatch", "")), nbrPatchName_(dict.lookupOrDefault<word>("neighbourPatch", "")),
coupleGroup_(dict), coupleGroup_(dict),
nbrPatchID_(-1), nbrPatchID_(-1),
rotationAxis_(Zero),
rotationCentre_(point::zero),
rotationAngleDefined_(false),
rotationAngle_(0.0),
AMIs_(), AMIs_(),
AMITransforms_(), AMITransforms_(),
AMIReverse_(dict.lookupOrDefault<bool>("flipNormals", false)), AMIReverse_(dict.lookupOrDefault<bool>("flipNormals", false)),
@ -562,49 +278,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
<< exit(FatalIOError); << exit(FatalIOError);
} }
switch (transformType())
{
case ROTATIONAL:
{
dict.lookup("rotationAxis") >> rotationAxis_;
dict.lookup("rotationCentre") >> rotationCentre_;
if (dict.readIfPresent("rotationAngle", rotationAngle_))
{
rotationAngleDefined_ = true;
rotationAngle_ = degToRad(rotationAngle_);
if (debug)
{
Info<< "rotationAngle: " << rotationAngle_ << " [rad]"
<< endl;
}
}
scalar magRot = mag(rotationAxis_);
if (magRot < small)
{
FatalIOErrorInFunction
(
dict
) << "Illegal rotationAxis " << rotationAxis_ << endl
<< "Please supply a non-zero vector."
<< exit(FatalIOError);
}
rotationAxis_ /= magRot;
break;
}
case TRANSLATIONAL:
{
dict.lookup("separation") >> separation_;
break;
}
default:
{
// No additional info required
}
}
// Neighbour patch might not be valid yet so no transformation // Neighbour patch might not be valid yet so no transformation
// calculation possible // calculation possible
} }
@ -617,13 +290,10 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
) )
: :
coupledPolyPatch(pp, bm), coupledPolyPatch(pp, bm),
cyclicTransform(pp),
nbrPatchName_(pp.nbrPatchName_), nbrPatchName_(pp.nbrPatchName_),
coupleGroup_(pp.coupleGroup_), coupleGroup_(pp.coupleGroup_),
nbrPatchID_(-1), nbrPatchID_(-1),
rotationAxis_(pp.rotationAxis_),
rotationCentre_(pp.rotationCentre_),
rotationAngleDefined_(pp.rotationAngleDefined_),
rotationAngle_(pp.rotationAngle_),
AMIs_(), AMIs_(),
AMITransforms_(), AMITransforms_(),
AMIReverse_(pp.AMIReverse_), AMIReverse_(pp.AMIReverse_),
@ -653,10 +323,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
nbrPatchName_(nbrPatchName), nbrPatchName_(nbrPatchName),
coupleGroup_(pp.coupleGroup_), coupleGroup_(pp.coupleGroup_),
nbrPatchID_(-1), nbrPatchID_(-1),
rotationAxis_(pp.rotationAxis_),
rotationCentre_(pp.rotationCentre_),
rotationAngleDefined_(pp.rotationAngleDefined_),
rotationAngle_(pp.rotationAngle_),
AMIs_(), AMIs_(),
AMITransforms_(), AMITransforms_(),
AMIReverse_(pp.AMIReverse_), AMIReverse_(pp.AMIReverse_),
@ -693,10 +359,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
nbrPatchName_(pp.nbrPatchName_), nbrPatchName_(pp.nbrPatchName_),
coupleGroup_(pp.coupleGroup_), coupleGroup_(pp.coupleGroup_),
nbrPatchID_(-1), nbrPatchID_(-1),
rotationAxis_(pp.rotationAxis_),
rotationCentre_(pp.rotationCentre_),
rotationAngleDefined_(pp.rotationAngleDefined_),
rotationAngle_(pp.rotationAngle_),
AMIs_(), AMIs_(),
AMITransforms_(), AMITransforms_(),
AMIReverse_(pp.AMIReverse_), AMIReverse_(pp.AMIReverse_),
@ -924,14 +586,39 @@ void Foam::cyclicAMIPolyPatch::calcGeometry
const pointField& nbrCc const pointField& nbrCc
) )
{ {
calcTransforms if
( (
referPatch, !Pstream::parRun()
thisCtrs, && !this->boundaryMesh().mesh().time().processorCase()
thisAreas, )
nbrCtrs, {
nbrAreas static_cast<cyclicTransform&>(*this) =
); cyclicTransform
(
name(),
thisCtrs,
thisAreas,
*this,
nbrPatchName(),
nbrCtrs,
nbrAreas,
nbrPatch(),
matchTolerance()
);
}
else
{
static_cast<cyclicTransform&>(*this) =
cyclicTransform
(
name(),
thisAreas,
*this,
nbrPatchName(),
nbrPatch(),
matchTolerance()
);
}
} }
@ -1048,31 +735,6 @@ void Foam::cyclicAMIPolyPatch::write(Ostream& os) const
cyclicTransform::write(os); cyclicTransform::write(os);
switch (transformType())
{
case ROTATIONAL:
{
writeEntry(os, "rotationAxis", rotationAxis_);
writeEntry(os, "rotationCentre", rotationCentre_);
if (rotationAngleDefined_)
{
writeEntry(os, "rotationAngle", radToDeg(rotationAngle_));
}
break;
}
case TRANSLATIONAL:
{
writeEntry(os, "separation", separation_);
break;
}
default:
{
// No additional info to write
}
}
if (AMIReverse_) if (AMIReverse_)
{ {
writeEntry(os, "flipNormals", AMIReverse_); writeEntry(os, "flipNormals", AMIReverse_);

View File

@ -55,21 +55,6 @@ class cyclicAMIPolyPatch
public coupledPolyPatch, public coupledPolyPatch,
public cyclicTransform public cyclicTransform
{ {
// Private Member Functions
//- Return normal of face at max distance from rotation axis
vector findFaceNormalMaxRadius(const pointField& faceCentres) const;
void calcTransforms
(
const primitivePatch& thisPatch,
const pointField& thisPatchCtrs,
const vectorField& thisPatchAreas,
const pointField& neiPatchCtrs,
const vectorField& neiPatchAreas
);
protected: protected:
// Protected data // Protected data
@ -83,27 +68,6 @@ protected:
//- Index of cyclic neighbour patch //- Index of cyclic neighbour patch
mutable label nbrPatchID_; mutable label nbrPatchID_;
// Specified transformation
// For translation
//- Offset vector from one side of the cyclic to the other
vector separation_;
// For rotation
//- Axis of rotation for rotational cyclics
vector rotationAxis_;
//- Point on axis of rotation for rotational cyclics
point rotationCentre_;
//- Flag to show whether the rotation angle is defined
bool rotationAngleDefined_;
//- Rotation angle
scalar rotationAngle_;
//- AMI interpolation classes //- AMI interpolation classes
mutable PtrList<AMIInterpolation> AMIs_; mutable PtrList<AMIInterpolation> AMIs_;
@ -134,9 +98,6 @@ protected:
//- Reset the AMI interpolator //- Reset the AMI interpolator
virtual void resetAMI() const; virtual void resetAMI() const;
//- Recalculate the transformation tensors
virtual void calcTransforms();
//- Initialise the calculation of the patch geometry //- Initialise the calculation of the patch geometry
virtual void initGeometry(PstreamBuffers&); virtual void initGeometry(PstreamBuffers&);
@ -176,7 +137,6 @@ public:
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType,
const orderingType ordering = UNKNOWN,
const bool AMIRequireMatch = true, const bool AMIRequireMatch = true,
const AMIInterpolation::interpolationMethod AMIMethod = const AMIInterpolation::interpolationMethod AMIMethod =
AMIInterpolation::imFaceAreaWeight AMIInterpolation::imFaceAreaWeight
@ -329,12 +289,6 @@ public:
return cyclicTransform::transform(); return cyclicTransform::transform();
} }
//- Axis of rotation for rotational cyclic AMI
inline const vector& rotationAxis() const;
//- Point on axis of rotation for rotational cyclic AMI
inline const point& rotationCentre() const;
// Interpolations // Interpolations

View File

@ -38,16 +38,4 @@ inline const Foam::word& Foam::cyclicAMIPolyPatch::nbrPatchName() const
} }
inline const Foam::vector& Foam::cyclicAMIPolyPatch::rotationAxis() const
{
return rotationAxis_;
}
inline const Foam::point& Foam::cyclicAMIPolyPatch::rotationCentre() const
{
return rotationCentre_;
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -294,8 +294,7 @@ Foam::cyclicRepeatAMIPolyPatch::cyclicRepeatAMIPolyPatch
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering
) )
: :
cyclicAMIPolyPatch cyclicAMIPolyPatch
@ -306,7 +305,6 @@ Foam::cyclicRepeatAMIPolyPatch::cyclicRepeatAMIPolyPatch
index, index,
bm, bm,
patchType, patchType,
ordering,
false, false,
AMIInterpolation::imFaceAreaWeight AMIInterpolation::imFaceAreaWeight
), ),
@ -463,6 +461,30 @@ Foam::cyclicRepeatAMIPolyPatch::nbrWeightsSum() const
} }
void Foam::cyclicRepeatAMIPolyPatch::calcGeometry
(
const primitivePatch& referPatch,
const pointField& thisCtrs,
const vectorField& thisAreas,
const pointField& thisCc,
const pointField& nbrCtrs,
const vectorField& nbrAreas,
const pointField& nbrCc
)
{
static_cast<cyclicTransform&>(*this) =
cyclicTransform
(
name(),
thisAreas,
*this,
nbrPatchName(),
nbrPatch(),
matchTolerance()
);
}
void Foam::cyclicRepeatAMIPolyPatch::write(Ostream& os) const void Foam::cyclicRepeatAMIPolyPatch::write(Ostream& os) const
{ {
cyclicAMIPolyPatch::write(os); cyclicAMIPolyPatch::write(os);

View File

@ -85,8 +85,7 @@ public:
const label start, const label start,
const label index, const label index,
const polyBoundaryMesh& bm, const polyBoundaryMesh& bm,
const word& patchType, const word& patchType
const orderingType ordering = UNKNOWN
); );
//- Construct from dictionary //- Construct from dictionary
@ -210,6 +209,18 @@ public:
virtual const scalarField& nbrWeightsSum() const; virtual const scalarField& nbrWeightsSum() const;
//- Calculate the patch geometry
virtual void calcGeometry
(
const primitivePatch& referPatch,
const pointField& thisCtrs,
const vectorField& thisAreas,
const pointField& thisCc,
const pointField& nbrCtrs,
const vectorField& nbrAreas,
const pointField& nbrCc
);
//- Write the polyPatch data as a dictionary //- Write the polyPatch data as a dictionary
virtual void write(Ostream&) const; virtual void write(Ostream&) const;
}; };

View File

@ -256,6 +256,7 @@ boundary
type cyclic; type cyclic;
neighbourPatch baffleCyclic_half1; neighbourPatch baffleCyclic_half1;
faces (); faces ();
transformType none;
} }
baffleCyclic_half1 baffleCyclic_half1
@ -263,6 +264,7 @@ boundary
type cyclic; type cyclic;
neighbourPatch baffleCyclic_half0; neighbourPatch baffleCyclic_half0;
faces (); faces ();
transformType none;
} }
); );