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:
@ -1,7 +1,9 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/conversion/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-lmeshTools \
|
||||
-ldynamicMesh
|
||||
-ldynamicMesh \
|
||||
-lconversion
|
||||
|
||||
@ -38,10 +38,11 @@ License
|
||||
#include "polyMeshZipUpCells.H"
|
||||
#include "wallPolyPatch.H"
|
||||
#include "symmetryPolyPatch.H"
|
||||
#include "oldCyclicPolyPatch.H"
|
||||
#include "mergedCyclicPolyPatch.H"
|
||||
#include "Swap.H"
|
||||
#include "IFstream.H"
|
||||
#include "readHexLabel.H"
|
||||
#include "polyMeshUnMergeCyclics.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -769,6 +770,12 @@ int main(int argc, char *argv[])
|
||||
"geometry scaling factor - default is 1"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"includedAngle",
|
||||
"angle",
|
||||
"feature angle with which to split cyclics"
|
||||
);
|
||||
argList::addOption
|
||||
(
|
||||
"ignoreCellGroups",
|
||||
"names",
|
||||
@ -901,16 +908,13 @@ int main(int argc, char *argv[])
|
||||
fluentToFoamType.insert("interface", polyPatch::typeName);
|
||||
fluentToFoamType.insert("internal", 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
|
||||
// initial matching since we require knowledge of the transformation.
|
||||
// It is ok if the periodics are already ordered. We should read the
|
||||
// periodic shadow faces section (section 18) to give use the ordering
|
||||
// For now just disable.
|
||||
// fluentToFoamType.insert("periodic", cyclicPolyPatch::typeName);
|
||||
fluentToFoamType.insert("fan", mergedCyclicPolyPatch::typeName);
|
||||
fluentToFoamType.insert("radiator", mergedCyclicPolyPatch::typeName);
|
||||
fluentToFoamType.insert("porous-jump", mergedCyclicPolyPatch::typeName);
|
||||
|
||||
fluentToFoamType.insert("periodic", cyclicPolyPatch::typeName);
|
||||
fluentToFoamType.insert("shadow", cyclicPolyPatch::typeName);
|
||||
|
||||
|
||||
// Foam patch type for Fluent zone type
|
||||
@ -919,6 +923,8 @@ int main(int argc, char *argv[])
|
||||
HashSet<word> fluentGroupToFoamPatch;
|
||||
fluentGroupToFoamPatch.insert("wall");
|
||||
fluentGroupToFoamPatch.insert("fan");
|
||||
fluentGroupToFoamPatch.insert("radiator");
|
||||
fluentGroupToFoamPatch.insert("porous-jump");
|
||||
|
||||
|
||||
// Create initial empty polyMesh
|
||||
@ -1023,6 +1029,76 @@ int main(int argc, char *argv[])
|
||||
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
|
||||
// ~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1031,7 +1107,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
forAll(patchIDs, patchi)
|
||||
{
|
||||
label zoneID = faceGroupZoneID[patchIDs[patchi] ];
|
||||
const label zoneID = faceGroupZoneID[patchIDs[patchi]];
|
||||
word name = groupName[zoneID];
|
||||
const word& type = groupType[zoneID];
|
||||
|
||||
@ -1047,32 +1123,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (iter != fluentToFoamType.end())
|
||||
{
|
||||
// See if we have a periodic and can derive the other side.
|
||||
word nbrPatchName;
|
||||
if (iter() == cyclicPolyPatch::typeName)
|
||||
{
|
||||
// Periodic
|
||||
size_t n = name.rfind("-SIDE-1");
|
||||
|
||||
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;
|
||||
const label nbrPatchi = nbrPatchis[patchi];
|
||||
const label nbrZoneID = faceGroupZoneID[patchIDs[nbrPatchi]];
|
||||
const word nbrName = groupName[nbrZoneID];
|
||||
|
||||
newPatches[patchi] = new cyclicPolyPatch
|
||||
(
|
||||
@ -1082,8 +1137,7 @@ int main(int argc, char *argv[])
|
||||
patchi,
|
||||
mesh.boundaryMesh(),
|
||||
cyclicPolyPatch::typeName,
|
||||
nbrPatchName,
|
||||
cyclicPolyPatch::NOORDERING
|
||||
nbrName
|
||||
);
|
||||
}
|
||||
else
|
||||
@ -1101,9 +1155,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
Info<< "Adding polyPatch for unknown Fluent type " << type
|
||||
<< endl;
|
||||
|
||||
newPatches[patchi] = new polyPatch
|
||||
(
|
||||
name,
|
||||
@ -1342,6 +1393,7 @@ int main(int argc, char *argv[])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark face as being done
|
||||
owner[facei] = -1;
|
||||
}
|
||||
@ -1411,6 +1463,16 @@ int main(int argc, char *argv[])
|
||||
polyMeshZipUpCells(mesh);
|
||||
}
|
||||
|
||||
// Un-merge any merged cyclics
|
||||
if (args.optionFound("includedAngle"))
|
||||
{
|
||||
polyMeshUnMergeCyclics(mesh, args.optionRead<scalar>("includedAngle"));
|
||||
}
|
||||
else
|
||||
{
|
||||
polyMeshUnMergeCyclics(mesh);
|
||||
}
|
||||
|
||||
mesh.setInstance(runTime.constant());
|
||||
|
||||
// Set the precision of the points data to 10
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/conversion/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lconversion
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -41,7 +41,8 @@ Description
|
||||
#include "wallPolyPatch.H"
|
||||
#include "symmetryPolyPatch.H"
|
||||
#include "wedgePolyPatch.H"
|
||||
#include "oldCyclicPolyPatch.H"
|
||||
#include "mergedCyclicPolyPatch.H"
|
||||
#include "polyMeshUnMergeCyclics.H"
|
||||
#include "unitConversion.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
@ -196,7 +196,7 @@ const word* kivaPatchTypes[nBCs] =
|
||||
&polyPatch::typeName,
|
||||
&polyPatch::typeName,
|
||||
&symmetryPolyPatch::typeName,
|
||||
&oldCyclicPolyPatch::typeName
|
||||
&mergedCyclicPolyPatch::typeName
|
||||
};
|
||||
|
||||
enum patchTypeNames
|
||||
@ -574,6 +574,9 @@ polyMesh pShapeMesh
|
||||
defaultFacesType
|
||||
);
|
||||
|
||||
// Un-merge any merged cyclics
|
||||
polyMeshUnMergeCyclics(pShapeMesh);
|
||||
|
||||
Info << "Writing polyMesh" << endl;
|
||||
pShapeMesh.write();
|
||||
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/conversion/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lconversion
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -29,7 +29,7 @@ Description
|
||||
#include "sammMesh.H"
|
||||
#include "Time.H"
|
||||
#include "wallPolyPatch.H"
|
||||
#include "oldCyclicPolyPatch.H"
|
||||
#include "mergedCyclicPolyPatch.H"
|
||||
#include "symmetryPolyPatch.H"
|
||||
#include "preservePatchTypes.H"
|
||||
#include "IFstream.H"
|
||||
@ -206,9 +206,7 @@ void Foam::sammMesh::readBoundary()
|
||||
}
|
||||
else if (patchType == "CYCL")
|
||||
{
|
||||
// incorrect. should be cyclicPatch but this
|
||||
// requires info on connected faces.
|
||||
patchTypes_[patchLabel] = oldCyclicPolyPatch::typeName;
|
||||
patchTypes_[patchLabel] = mergedCyclicPolyPatch::typeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -29,6 +29,7 @@ Description
|
||||
#include "sammMesh.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "polyMeshUnMergeCyclics.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -56,6 +57,8 @@ void Foam::sammMesh::writeMesh()
|
||||
patchPhysicalTypes_
|
||||
);
|
||||
|
||||
polyMeshUnMergeCyclics(pShapeMesh);
|
||||
|
||||
Info<< "Writing polyMesh" << endl;
|
||||
pShapeMesh.write();
|
||||
}
|
||||
@ -82,6 +85,8 @@ void Foam::sammMesh::writeMesh()
|
||||
|
||||
pMesh.addPatches(polyBoundaryPatches(pMesh));
|
||||
|
||||
polyMeshUnMergeCyclics(pMesh);
|
||||
|
||||
Info<< "Writing polyMesh" << endl;
|
||||
pMesh.write();
|
||||
}
|
||||
|
||||
@ -4,4 +4,10 @@ EXE_INC = \
|
||||
/* -DDEBUG_COUPLE_INTERSECTION */ \
|
||||
/* -DDEBUG_RIGHT_HAND_WALK */ \
|
||||
/* -DDEBUG_FACE_ORDERING */ \
|
||||
/* -DDEBUG_COUPLE_PROJECTION */
|
||||
/* -DDEBUG_COUPLE_PROJECTION */ \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/conversion/lnInclude
|
||||
|
||||
EXE_LIBS = \
|
||||
-ldynamicMesh \
|
||||
-lconversion
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -29,7 +29,7 @@ Description
|
||||
#include "starMesh.H"
|
||||
#include "Time.H"
|
||||
#include "wallPolyPatch.H"
|
||||
#include "oldCyclicPolyPatch.H"
|
||||
#include "mergedCyclicPolyPatch.H"
|
||||
#include "symmetryPolyPatch.H"
|
||||
#include "preservePatchTypes.H"
|
||||
#include "IFstream.H"
|
||||
@ -204,9 +204,7 @@ void Foam::starMesh::readBoundary()
|
||||
}
|
||||
else if (patchType == "CYCL")
|
||||
{
|
||||
// incorrect. should be cyclicPatch but this
|
||||
// requires info on connected faces.
|
||||
patchTypes_[patchLabel] = oldCyclicPolyPatch::typeName;
|
||||
patchTypes_[patchLabel] = mergedCyclicPolyPatch::typeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -29,6 +29,7 @@ Description
|
||||
#include "starMesh.H"
|
||||
#include "Time.H"
|
||||
#include "polyMesh.H"
|
||||
#include "polyMeshUnMergeCyclics.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -60,6 +61,8 @@ void Foam::starMesh::writeMesh()
|
||||
patchPhysicalTypes_
|
||||
);
|
||||
|
||||
polyMeshUnMergeCyclics(pShapeMesh);
|
||||
|
||||
Info<< "Writing polyMesh" << endl;
|
||||
pShapeMesh.write();
|
||||
}
|
||||
@ -89,6 +92,8 @@ void Foam::starMesh::writeMesh()
|
||||
// adding patches also checks the mesh
|
||||
pMesh.addPatches(polyBoundaryPatches(pMesh));
|
||||
|
||||
polyMeshUnMergeCyclics(pMesh);
|
||||
|
||||
Info<< "Writing polyMesh" << endl;
|
||||
pMesh.write();
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2012-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2012-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -437,8 +437,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::conformalVoronoiMesh::createDummyMesh
|
||||
patchi,
|
||||
mesh.boundaryMesh(),
|
||||
patchDicts[patchi].lookup<label>("myProcNo"),
|
||||
patchDicts[patchi].lookup<label>("neighbProcNo"),
|
||||
coupledPolyPatch::COINCIDENTFULLMATCH
|
||||
patchDicts[patchi].lookup<label>("neighbProcNo")
|
||||
);
|
||||
}
|
||||
else
|
||||
|
||||
@ -360,7 +360,11 @@ void syncPoints
|
||||
if (procPatch.transform().transformsPosition())
|
||||
{
|
||||
hasTransformation = true;
|
||||
procPatch.transform().transformPosition(nbrPatchInfo);
|
||||
procPatch.transform().transformPosition
|
||||
(
|
||||
nbrPatchInfo,
|
||||
nbrPatchInfo
|
||||
);
|
||||
}
|
||||
|
||||
const labelList& meshPts = procPatch.meshPoints();
|
||||
@ -405,7 +409,11 @@ void syncPoints
|
||||
if (cycPatch.transform().transformsPosition())
|
||||
{
|
||||
hasTransformation = true;
|
||||
cycPatch.transform().invTransformPosition(patchPoints);
|
||||
cycPatch.transform().invTransformPosition
|
||||
(
|
||||
patchPoints,
|
||||
patchPoints
|
||||
);
|
||||
}
|
||||
|
||||
forAll(coupledPoints, i)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -495,8 +495,7 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
|
||||
procMesh.boundaryMesh(),
|
||||
proci,
|
||||
curNeighbourProcessors[procPatchi],
|
||||
pcPatch.name(),
|
||||
pcPatch.ordering()
|
||||
pcPatch.name()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -40,12 +40,12 @@ wmake $targetType lagrangian/basic
|
||||
wmake $targetType lagrangian/distributionModels
|
||||
wmake $targetType genericPatchFields
|
||||
|
||||
wmake $targetType conversion
|
||||
wmake $targetType mesh/extrudeModel
|
||||
wmake $targetType dynamicMesh
|
||||
wmake $targetType sampling
|
||||
wmake $targetType dynamicFvMesh
|
||||
wmake $targetType topoChangerFvMesh
|
||||
wmake $targetType conversion
|
||||
wmake $targetType sampling
|
||||
|
||||
# Compile scotchDecomp, metisDecomp etc.
|
||||
parallel/Allwmake $targetType $*
|
||||
|
||||
@ -472,7 +472,6 @@ constraintPolyPatches = $(polyPatches)/constraint
|
||||
$(constraintPolyPatches)/cyclic/cyclicTransform.C
|
||||
$(constraintPolyPatches)/cyclic/cyclicPolyPatch.C
|
||||
$(constraintPolyPatches)/cyclicSlip/cyclicSlipPolyPatch.C
|
||||
$(constraintPolyPatches)/oldCyclic/oldCyclicPolyPatch.C
|
||||
$(constraintPolyPatches)/empty/emptyPolyPatch.C
|
||||
$(constraintPolyPatches)/processorCyclic/processorCyclicPolyPatch.C
|
||||
$(constraintPolyPatches)/processor/processorPolyPatch.C
|
||||
|
||||
@ -35,163 +35,561 @@ namespace Foam
|
||||
defineTypeNameAndDebug(coupledPolyPatch, 0);
|
||||
|
||||
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
|
||||
{
|
||||
"unknown",
|
||||
"coincidentFullMatch",
|
||||
"noOrdering"
|
||||
};
|
||||
// Initialisation
|
||||
label facei = seedFacei, facePointi = seedFacePointi;
|
||||
faceMap[facei] = mapFacei;
|
||||
facePointMap[facei] = facePointi;
|
||||
bool changed = facei != mapFacei || facePointi != 0;
|
||||
++ mapFacei;
|
||||
if (walks.valid())
|
||||
{
|
||||
walks->append(labelList(1, facei));
|
||||
}
|
||||
|
||||
const NamedEnum<coupledPolyPatch::orderingType, 3>
|
||||
coupledPolyPatch::orderingTypeNames;
|
||||
// Walk the patch until we get back to the seed face and point
|
||||
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 * * * * * * * * * * * //
|
||||
|
||||
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
|
||||
(
|
||||
Ostream& os,
|
||||
const fileName& name,
|
||||
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,
|
||||
const point& p0,
|
||||
const point& p1,
|
||||
label& vertI
|
||||
)
|
||||
ownToNbrOrderData& ownToNbr,
|
||||
autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
|
||||
const primitivePatch& pp
|
||||
) const
|
||||
{
|
||||
writeOBJ(os, p0);
|
||||
vertI++;
|
||||
if (owner())
|
||||
{
|
||||
// Generate the connected regions
|
||||
label nRegions = 0;
|
||||
labelList faceRegionis(pp.size(), -1);
|
||||
|
||||
writeOBJ(os, p1);
|
||||
vertI++;
|
||||
label seedFacei = 0;
|
||||
|
||||
os << "l " << vertI-1 << ' ' << vertI << nl;
|
||||
}
|
||||
labelList faceMap(pp.size(), -1);
|
||||
labelList facePointMap(pp.size(), -1);
|
||||
label mapFacei = 0;
|
||||
autoPtr<labelListList> walks(nullptr);
|
||||
|
||||
|
||||
void Foam::coupledPolyPatch::writeOBJ
|
||||
while (mapFacei < pp.size())
|
||||
{
|
||||
walk
|
||||
(
|
||||
const fileName& fName,
|
||||
const UList<face>& faces,
|
||||
const pointField& points
|
||||
)
|
||||
{
|
||||
OFstream os(fName);
|
||||
pp,
|
||||
owner(),
|
||||
seedFacei,
|
||||
0,
|
||||
faceMap,
|
||||
facePointMap,
|
||||
mapFacei,
|
||||
walks
|
||||
);
|
||||
|
||||
Map<label> foamToObj(4*faces.size());
|
||||
|
||||
label vertI = 0;
|
||||
|
||||
forAll(faces, i)
|
||||
forAll(pp, facei)
|
||||
{
|
||||
const face& f = faces[i];
|
||||
|
||||
forAll(f, fp)
|
||||
if (faceRegionis[facei] == -1 && faceMap[facei] != -1)
|
||||
{
|
||||
if (foamToObj.insert(f[fp], vertI))
|
||||
{
|
||||
writeOBJ(os, points[f[fp]]);
|
||||
vertI++;
|
||||
faceRegionis[facei] = nRegions;
|
||||
}
|
||||
}
|
||||
|
||||
os << 'l';
|
||||
forAll(f, fp)
|
||||
++ nRegions;
|
||||
|
||||
forAll(pp, facei)
|
||||
{
|
||||
os << ' ' << foamToObj[f[fp]]+1;
|
||||
if (faceMap[facei] == -1)
|
||||
{
|
||||
seedFacei = facei;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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])
|
||||
{
|
||||
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();
|
||||
}
|
||||
os << ' ' << foamToObj[f[0]]+1 << nl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::pointField Foam::coupledPolyPatch::getAnchorPoints
|
||||
bool Foam::coupledPolyPatch::order
|
||||
(
|
||||
const UList<face>& faces,
|
||||
const pointField& points,
|
||||
const orderingType ordering
|
||||
)
|
||||
const ownToNbrOrderData& ownToNbr,
|
||||
const autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
|
||||
const primitivePatch& pp,
|
||||
labelList& faceMap,
|
||||
labelList& rotation
|
||||
) const
|
||||
{
|
||||
pointField anchors(faces.size());
|
||||
// Determine the seed faces and face points
|
||||
labelList seedFaceis, seedFacePointis;
|
||||
if (owner())
|
||||
{
|
||||
seedFaceis = ownToOwnOrderDataPtr_->seedFaceis;
|
||||
ownToOwnOrderDataPtr_.clear();
|
||||
|
||||
if (ordering != COINCIDENTFULLMATCH)
|
||||
{
|
||||
// Return the first point
|
||||
forAll(faces, facei)
|
||||
{
|
||||
anchors[facei] = points[faces[facei][0]];
|
||||
}
|
||||
seedFacePointis.resize(seedFaceis.size(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make anchor point unique
|
||||
forAll(faces, facei)
|
||||
const List<pointField> ownerSeedFacePoints(ownToNbr.seedFacePoints);
|
||||
|
||||
seedFaceis.resize(ownerSeedFacePoints.size());
|
||||
seedFacePointis.resize(ownerSeedFacePoints.size());
|
||||
|
||||
// Check the element counts
|
||||
if (ownToNbrDebugPtr.valid())
|
||||
{
|
||||
const face& f = faces[facei];
|
||||
|
||||
bool unique = true;
|
||||
|
||||
forAll(f, fp1)
|
||||
const label ownerNFaces = ownToNbrDebugPtr->nFaces;
|
||||
const label ownerNPoints = ownToNbrDebugPtr->nPoints;
|
||||
const label ownerNEdges = ownToNbrDebugPtr->nEdges;
|
||||
const label ownerNInternalEdges = ownToNbrDebugPtr->nInternalEdges;
|
||||
if (pp.size() != ownerNFaces)
|
||||
{
|
||||
const point& p1 = points[f[fp1]];
|
||||
|
||||
unique = true;
|
||||
|
||||
for (label fp2 = 0; fp2 < f.size(); ++fp2)
|
||||
SeriousErrorInFunction<< "The patch " << name() << " has "
|
||||
<< pp.size() << " faces whilst it's neighbour has "
|
||||
<< ownerNFaces << endl;
|
||||
}
|
||||
if (pp.nPoints() != ownerNPoints)
|
||||
{
|
||||
if (f[fp1] == f[fp2])
|
||||
SeriousErrorInFunction<< "The patch " << name() << " has "
|
||||
<< pp.nPoints() << " points whilst it's neighbour has "
|
||||
<< ownerNPoints << endl;
|
||||
}
|
||||
if (pp.nEdges() != ownerNEdges)
|
||||
{
|
||||
continue;
|
||||
SeriousErrorInFunction<< "The patch " << name() << " has "
|
||||
<< pp.nEdges() << " edges whilst it's neighbour has "
|
||||
<< ownerNEdges << endl;
|
||||
}
|
||||
|
||||
const point& p2 = points[f[fp2]];
|
||||
|
||||
// TODO: Change to a tolerance and possibly select closest
|
||||
// point to the origin
|
||||
if (p1 == p2)
|
||||
if (pp.nInternalEdges() != ownerNInternalEdges)
|
||||
{
|
||||
unique = false;
|
||||
break;
|
||||
SeriousErrorInFunction<< "The patch " << name() << " has "
|
||||
<< pp.nInternalEdges() << " internal edges whilst it's "
|
||||
<< "neighbour has " << ownerNInternalEdges << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (unique)
|
||||
// Do geometric testing to determine the faces that match those sent
|
||||
// over from the opposite patch
|
||||
forAll(ownerSeedFacePoints, regioni)
|
||||
{
|
||||
anchors[facei] = p1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const pointField& ownerFacePts = ownerSeedFacePoints[regioni];
|
||||
|
||||
if (!unique)
|
||||
// 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)
|
||||
{
|
||||
anchors[facei] = points[faces[facei][0]];
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return anchors;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
(
|
||||
@ -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
|
||||
{
|
||||
polyPatch::write(os);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -54,21 +54,58 @@ class coupledPolyPatch
|
||||
:
|
||||
public polyPatch
|
||||
{
|
||||
public:
|
||||
private:
|
||||
|
||||
enum orderingType
|
||||
{
|
||||
UNKNOWN, // Unspecified -> automatic ordering
|
||||
COINCIDENTFULLMATCH,// Assume no transforms
|
||||
// and check the points in faces match
|
||||
NOORDERING // Unspecified -> no automatic ordering
|
||||
};
|
||||
// Private Member Functions
|
||||
|
||||
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 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
|
||||
|
||||
//- Default matching tolerance
|
||||
@ -77,12 +114,10 @@ protected:
|
||||
//- Local matching tolerance
|
||||
const scalar matchTolerance_;
|
||||
|
||||
//- Type of ordering
|
||||
orderingType ordering_;
|
||||
//- Data to pass from owner.initOrder to owner.order
|
||||
mutable autoPtr<ownToOwnOrderData> ownToOwnOrderDataPtr_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Initialise the calculation of the patch geometry
|
||||
@ -103,46 +138,52 @@ protected:
|
||||
//- Update of the patch topology
|
||||
virtual void updateMesh(PstreamBuffers&) = 0;
|
||||
|
||||
//- Write point 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
|
||||
//- Write a patch in OBJ format
|
||||
static void writeOBJ
|
||||
(
|
||||
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&
|
||||
);
|
||||
|
||||
//- Write edge in OBJ format
|
||||
//- Write a set of paths in OBJ format
|
||||
static void writeOBJ
|
||||
(
|
||||
Ostream& os,
|
||||
const point& p0,
|
||||
const point& p1,
|
||||
label& vertI
|
||||
);
|
||||
|
||||
//- Get a unique anchor point for all faces
|
||||
static pointField getAnchorPoints
|
||||
(
|
||||
const UList<face>&,
|
||||
const fileName&,
|
||||
const pointField&,
|
||||
const orderingType
|
||||
const labelListList&
|
||||
);
|
||||
|
||||
//- Get the number of vertices face f needs to be rotated such that
|
||||
// its f[0] point aligns with given anchor (within tol).
|
||||
static label getRotation
|
||||
//- Initialise ordering for the given primitivePatch. Fills the
|
||||
// referenced data structures, but leaves transferring them to the
|
||||
// opposite patch to the caller.
|
||||
virtual void initOrder
|
||||
(
|
||||
const pointField& points,
|
||||
const face& f,
|
||||
const point& anchor,
|
||||
const scalar tol
|
||||
);
|
||||
ownToNbrOrderData& ownToNbr,
|
||||
autoPtr<ownToNbrDebugOrderData>& ownToNbrDebugPtr,
|
||||
const primitivePatch&
|
||||
) 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:
|
||||
@ -161,8 +202,7 @@ public:
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct from dictionary
|
||||
@ -172,8 +212,7 @@ public:
|
||||
const dictionary& dict,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct as copy, resetting the boundary mesh
|
||||
@ -224,15 +263,10 @@ public:
|
||||
return !owner();
|
||||
}
|
||||
|
||||
//- Type of ordering
|
||||
virtual orderingType ordering() const
|
||||
{
|
||||
return ordering_;
|
||||
}
|
||||
|
||||
//- Return transformation between the coupled patches
|
||||
virtual const transformer& transform() const = 0;
|
||||
|
||||
//- Return the matching tolerance
|
||||
scalar matchTolerance() const
|
||||
{
|
||||
return matchTolerance_;
|
||||
@ -283,9 +317,23 @@ public:
|
||||
|
||||
//- Write the polyPatch data as a dictionary
|
||||
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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -78,21 +78,6 @@ class cyclicPolyPatch
|
||||
//- Index of cyclic neighbour patch
|
||||
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
|
||||
// this patch, e[1] the corresponding point on the cyclic neighbour.
|
||||
mutable edgeList* coupledPointsPtr_;
|
||||
@ -101,66 +86,17 @@ class cyclicPolyPatch
|
||||
// e[1] the corresponding edge on the cyclic neigbour
|
||||
mutable edgeList* coupledEdgesPtr_;
|
||||
|
||||
//- Temporary storage of owner side patch during ordering.
|
||||
mutable autoPtr<primitivePatch> ownerPatchPtr_;
|
||||
//- Data to pass from owner.initOrder to nbr.order
|
||||
mutable autoPtr<ownToNbrOrderData> ownToNbrOrderDataPtr_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- 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;
|
||||
//- Data to pass from owner.initOrder to nbr.order if debugging
|
||||
mutable autoPtr<ownToNbrDebugOrderData> ownToNbrDebugOrderDataPtr_;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member functions
|
||||
|
||||
//- Recalculate the transformation tensors
|
||||
virtual void calcTransforms();
|
||||
|
||||
//- Initialise the calculation of the patch geometry
|
||||
virtual void initGeometry(PstreamBuffers&);
|
||||
|
||||
@ -220,8 +156,7 @@ public:
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType defaultOrdering = UNKNOWN
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct from components
|
||||
@ -233,8 +168,7 @@ public:
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const word& nbrPatchName,
|
||||
const orderingType ordering
|
||||
const word& nbrPatchName
|
||||
);
|
||||
|
||||
//- Construct from dictionary
|
||||
@ -244,8 +178,7 @@ public:
|
||||
const dictionary& dict,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct as copy, resetting the boundary mesh
|
||||
@ -364,9 +297,8 @@ public:
|
||||
return cyclicTransform::transform();
|
||||
}
|
||||
|
||||
|
||||
// Transformation
|
||||
|
||||
//- For a given patch face index, return the corresponding index of the
|
||||
// face on the neighbour
|
||||
label transformGlobalFace(const label facei) const
|
||||
{
|
||||
label offset = facei - start();
|
||||
@ -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
|
||||
// refer to *this (except for name() and type() etc.)
|
||||
virtual void initOrder(PstreamBuffers&, const primitivePatch&) const;
|
||||
@ -415,7 +334,6 @@ public:
|
||||
labelList& rotation
|
||||
) const;
|
||||
|
||||
|
||||
//- Write the polyPatch data as a dictionary
|
||||
virtual void write(Ostream&) const;
|
||||
};
|
||||
|
||||
@ -24,6 +24,8 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "cyclicTransform.H"
|
||||
#include "unitConversion.H"
|
||||
#include "IOmanip.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -40,34 +42,489 @@ namespace Foam
|
||||
|
||||
const NamedEnum<cyclicTransform::transformTypes, 4>
|
||||
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_
|
||||
(
|
||||
dict.found("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()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::cyclicTransform::write(Ostream& os) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -65,25 +65,95 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Type of transformation
|
||||
transformTypes transformType_;
|
||||
|
||||
//- Axis of rotation
|
||||
vector rotationAxis_;
|
||||
|
||||
protected:
|
||||
//- Centre of rotation
|
||||
point rotationCentre_;
|
||||
|
||||
//- Transformation between the coupled patches
|
||||
mutable transformer transform_;
|
||||
//- Rotation angle
|
||||
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:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("cyclicTransform");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
// Unspecified tranformation
|
||||
cyclicTransform();
|
||||
// Transformation set as UNSPECIFIED or NONE
|
||||
cyclicTransform(const bool defaultIsNone);
|
||||
|
||||
// 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
|
||||
@ -96,18 +166,46 @@ public:
|
||||
return transformType_;
|
||||
}
|
||||
|
||||
//- Is the transform fully specified?
|
||||
bool transformComplete() const
|
||||
{
|
||||
return transformComplete_;
|
||||
}
|
||||
|
||||
//- Return transformation between the coupled patches
|
||||
const transformer& transform() const
|
||||
{
|
||||
if (!transformComplete_)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "The transformation has not been fully specified or "
|
||||
<< "calculated" << exit(FatalError);
|
||||
}
|
||||
return transform_;
|
||||
}
|
||||
|
||||
|
||||
//- Write the polyPatch data as a dictionary
|
||||
//- Write the data to a dictionary
|
||||
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
|
||||
|
||||
@ -68,11 +68,10 @@ public:
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
cyclicPolyPatch(name, size, start, index, bm, patchType, ordering)
|
||||
cyclicPolyPatch(name, size, start, index, bm, patchType)
|
||||
{}
|
||||
|
||||
//- Construct from dictionary
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -55,11 +55,10 @@ Foam::processorPolyPatch::processorPolyPatch
|
||||
const polyBoundaryMesh& bm,
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const orderingType ordering,
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
coupledPolyPatch(name, size, start, index, bm, patchType, ordering),
|
||||
coupledPolyPatch(name, size, start, index, bm, patchType),
|
||||
myProcNo_(myProcNo),
|
||||
neighbProcNo_(neighbProcNo),
|
||||
neighbFaceCentres_(),
|
||||
@ -76,7 +75,6 @@ Foam::processorPolyPatch::processorPolyPatch
|
||||
const polyBoundaryMesh& bm,
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const orderingType ordering,
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
@ -87,8 +85,7 @@ Foam::processorPolyPatch::processorPolyPatch
|
||||
start,
|
||||
index,
|
||||
bm,
|
||||
patchType,
|
||||
ordering
|
||||
patchType
|
||||
),
|
||||
myProcNo_(myProcNo),
|
||||
neighbProcNo_(neighbProcNo),
|
||||
@ -247,38 +244,27 @@ void Foam::processorPolyPatch::calcGeometry(PstreamBuffers& pBufs)
|
||||
}
|
||||
else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei]))
|
||||
{
|
||||
fileName nm
|
||||
const fileName patchOBJName
|
||||
(
|
||||
boundaryMesh().mesh().time().path()
|
||||
/name()+"_faces.obj"
|
||||
boundaryMesh().mesh().time().path()/name() + "_faces.obj"
|
||||
);
|
||||
|
||||
Pout<< "processorPolyPatch::calcGeometry : Writing my "
|
||||
<< size()
|
||||
<< " faces to OBJ file " << nm << endl;
|
||||
<< size() << " faces to " << patchOBJName << endl;
|
||||
|
||||
writeOBJ(nm, *this, points());
|
||||
writeOBJ(patchOBJName, *this);
|
||||
|
||||
OFstream ccStr
|
||||
const fileName centresOBJName
|
||||
(
|
||||
boundaryMesh().mesh().time().path()
|
||||
/name() + "_faceCentresConnections.obj"
|
||||
boundaryMesh().mesh().time().path()/name()
|
||||
+ "_faceCentresConnections.obj"
|
||||
);
|
||||
|
||||
Pout<< "processorPolyPatch::calcGeometry :"
|
||||
<< " Dumping cell centre lines between"
|
||||
<< " corresponding face centres to OBJ file" << ccStr.name()
|
||||
<< endl;
|
||||
<< " Dumping lines between corresponding face centres to "
|
||||
<< centresOBJName.name() << endl;
|
||||
|
||||
label vertI = 0;
|
||||
|
||||
forAll(faceCentres(), facej)
|
||||
{
|
||||
const point& c0 = neighbFaceCentres_[facej];
|
||||
const point& c1 = faceCentres()[facej];
|
||||
|
||||
writeOBJ(ccStr, c0, c1, vertI);
|
||||
}
|
||||
writeOBJ(centresOBJName, neighbFaceCentres_, faceCentres());
|
||||
|
||||
FatalErrorInFunction
|
||||
<< "face " << facei << " area does not match neighbour by "
|
||||
@ -521,189 +507,37 @@ void Foam::processorPolyPatch::initOrder
|
||||
const primitivePatch& pp
|
||||
) const
|
||||
{
|
||||
if
|
||||
(
|
||||
!Pstream::parRun()
|
||||
|| ordering() == NOORDERING
|
||||
)
|
||||
if (!Pstream::parRun())
|
||||
{
|
||||
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 (ordering() == COINCIDENTFULLMATCH)
|
||||
{
|
||||
// Pass the patch points and faces across
|
||||
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
|
||||
ownToNbrOrderData ownToNbr;
|
||||
autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
|
||||
(
|
||||
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)
|
||||
coupledPolyPatch::debug
|
||||
? new ownToNbrDebugOrderData()
|
||||
: nullptr
|
||||
);
|
||||
|
||||
if (!aCirc.circulate())
|
||||
coupledPolyPatch::initOrder
|
||||
(
|
||||
ownToNbr,
|
||||
ownToNbrDebugPtr,
|
||||
pp
|
||||
);
|
||||
|
||||
UOPstream toNeighbour(neighbProcNo(), pBufs);
|
||||
toNeighbour << ownToNbr;
|
||||
if (coupledPolyPatch::debug)
|
||||
{
|
||||
if (matchDistSqr < closestMatchDistSqr)
|
||||
{
|
||||
closestMatchDistSqr = matchDistSqr;
|
||||
|
||||
if (!sameOrientation)
|
||||
{
|
||||
matchFp = a.size() - bCirc.nRotations();
|
||||
}
|
||||
else
|
||||
{
|
||||
matchFp = bCirc.nRotations();
|
||||
}
|
||||
|
||||
if (closestMatchDistSqr == 0)
|
||||
{
|
||||
break;
|
||||
toNeighbour << ownToNbrDebugPtr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset aCirc
|
||||
aCirc.setIteratorToFulcrum();
|
||||
}
|
||||
|
||||
} while (bCirc.circulate(circulateDirection));
|
||||
|
||||
matchDistSqr = closestMatchDistSqr;
|
||||
|
||||
return matchFp;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::processorPolyPatch::order
|
||||
(
|
||||
@ -713,387 +547,38 @@ bool Foam::processorPolyPatch::order
|
||||
labelList& rotation
|
||||
) const
|
||||
{
|
||||
// Note: we only get the faces that originate from internal faces.
|
||||
|
||||
if
|
||||
(
|
||||
!Pstream::parRun()
|
||||
|| ordering() == NOORDERING
|
||||
)
|
||||
if (!Pstream::parRun())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
faceMap.setSize(pp.size());
|
||||
faceMap = -1;
|
||||
|
||||
rotation.setSize(pp.size());
|
||||
rotation = 0;
|
||||
|
||||
bool change = false;
|
||||
|
||||
if (owner())
|
||||
{
|
||||
// Do nothing (i.e. identical mapping, zero rotation).
|
||||
// See comment at top.
|
||||
forAll(faceMap, patchFacei)
|
||||
{
|
||||
faceMap[patchFacei] = patchFacei;
|
||||
}
|
||||
|
||||
if (ordering() != COINCIDENTFULLMATCH)
|
||||
{
|
||||
const pointField& ppPoints = pp.points();
|
||||
|
||||
pointField anchors(getAnchorPoints(pp, ppPoints, ordering()));
|
||||
|
||||
// Calculate typical distance from face centre
|
||||
scalarField tols
|
||||
ownToNbrOrderData ownToNbr;
|
||||
autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
|
||||
(
|
||||
matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres())
|
||||
coupledPolyPatch::debug
|
||||
? new ownToNbrDebugOrderData()
|
||||
: nullptr
|
||||
);
|
||||
|
||||
forAll(faceMap, patchFacei)
|
||||
if (!owner())
|
||||
{
|
||||
const point& wantedAnchor = anchors[patchFacei];
|
||||
UIPstream fromOwner(neighbProcNo(), pBufs);
|
||||
fromOwner >> ownToNbr;
|
||||
if (coupledPolyPatch::debug)
|
||||
{
|
||||
fromOwner >> ownToNbrDebugPtr();
|
||||
}
|
||||
}
|
||||
|
||||
rotation[patchFacei] = getRotation
|
||||
return
|
||||
coupledPolyPatch::order
|
||||
(
|
||||
ppPoints,
|
||||
pp[patchFacei],
|
||||
wantedAnchor,
|
||||
tols[patchFacei]
|
||||
ownToNbr,
|
||||
ownToNbrDebugPtr,
|
||||
pp,
|
||||
faceMap,
|
||||
rotation
|
||||
);
|
||||
|
||||
if (rotation[patchFacei] > 0)
|
||||
{
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate the absolute matching tolerance
|
||||
scalarField tols
|
||||
(
|
||||
matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres())
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -93,7 +93,6 @@ protected:
|
||||
const polyBoundaryMesh& bm,
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const orderingType defaultOrdering = UNKNOWN,
|
||||
const word& patchType = typeName
|
||||
);
|
||||
|
||||
@ -152,7 +151,6 @@ public:
|
||||
const polyBoundaryMesh& bm,
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const orderingType ordering = UNKNOWN,
|
||||
const word& patchType = typeName
|
||||
);
|
||||
|
||||
@ -340,21 +338,6 @@ public:
|
||||
// refer to *this (except for name() and type() etc.)
|
||||
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.
|
||||
// Ordering is -faceMap: for every face
|
||||
// index of the new face -rotation:for every new face the clockwise
|
||||
|
||||
@ -48,7 +48,6 @@ Foam::processorCyclicPolyPatch::processorCyclicPolyPatch
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const word& referPatchName,
|
||||
const orderingType ordering,
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
@ -61,7 +60,6 @@ Foam::processorCyclicPolyPatch::processorCyclicPolyPatch
|
||||
bm,
|
||||
myProcNo,
|
||||
neighbProcNo,
|
||||
ordering,
|
||||
patchType
|
||||
),
|
||||
referPatchName_(referPatchName),
|
||||
@ -237,29 +235,11 @@ void Foam::processorCyclicPolyPatch::calcGeometry(PstreamBuffers& pBufs)
|
||||
|
||||
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
|
||||
// half might be present as a processorCyclic.
|
||||
|
||||
cyclicPolyPatch& pp = const_cast<cyclicPolyPatch&>(referPatch());
|
||||
|
||||
pp.calcGeometry
|
||||
(
|
||||
*this,
|
||||
@ -325,7 +305,6 @@ void Foam::processorCyclicPolyPatch::initOrder
|
||||
const primitivePatch& pp
|
||||
) const
|
||||
{
|
||||
// For now use the same algorithm as processorPolyPatch
|
||||
processorPolyPatch::initOrder(pBufs, pp);
|
||||
}
|
||||
|
||||
@ -338,7 +317,6 @@ bool Foam::processorCyclicPolyPatch::order
|
||||
labelList& rotation
|
||||
) const
|
||||
{
|
||||
// For now use the same algorithm as processorPolyPatch
|
||||
return processorPolyPatch::order(pBufs, pp, faceMap, rotation);
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +122,6 @@ public:
|
||||
const int myProcNo,
|
||||
const int neighbProcNo,
|
||||
const word& referPatchName,
|
||||
const orderingType ordering = UNKNOWN,
|
||||
const word& patchType = typeName
|
||||
);
|
||||
|
||||
@ -329,7 +328,7 @@ public:
|
||||
//- Return transformation between the coupled patches
|
||||
virtual const transformer& transform() const
|
||||
{
|
||||
return referPatch().transform_;
|
||||
return referPatch().transform();
|
||||
}
|
||||
|
||||
//- Initialize ordering for primitivePatch. Does not
|
||||
|
||||
@ -6,6 +6,9 @@ ensight/part/ensightPartCells.C
|
||||
ensight/part/ensightPartFaces.C
|
||||
ensight/part/ensightParts.C
|
||||
|
||||
mergedCyclic/mergedCyclicPolyPatch.C
|
||||
mergedCyclic/polyMeshUnMergeCyclics.C
|
||||
|
||||
meshTables/boundaryRegion.C
|
||||
meshTables/cellTable.C
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
EXE_INC = \
|
||||
-I$(LIB_SRC)/fileFormats/lnInclude \
|
||||
-I$(LIB_SRC)/finiteVolume/lnInclude \
|
||||
-I$(LIB_SRC)/dynamicMesh/lnInclude \
|
||||
-I$(LIB_SRC)/meshTools/lnInclude
|
||||
|
||||
LIB_LIBS = \
|
||||
-lfileFormats \
|
||||
-lfiniteVolume \
|
||||
-ldynamicMesh \
|
||||
-lmeshTools
|
||||
|
||||
104
src/conversion/mergedCyclic/mergedCyclicPolyPatch.C
Normal file
104
src/conversion/mergedCyclic/mergedCyclicPolyPatch.C
Normal 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)
|
||||
{}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
170
src/conversion/mergedCyclic/mergedCyclicPolyPatch.H
Normal file
170
src/conversion/mergedCyclic/mergedCyclicPolyPatch.H
Normal 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
|
||||
|
||||
// ************************************************************************* //
|
||||
311
src/conversion/mergedCyclic/polyMeshUnMergeCyclics.C
Normal file
311
src/conversion/mergedCyclic/polyMeshUnMergeCyclics.C
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
51
src/conversion/mergedCyclic/polyMeshUnMergeCyclics.H
Normal file
51
src/conversion/mergedCyclic/polyMeshUnMergeCyclics.H
Normal 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
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -30,6 +30,7 @@ License
|
||||
#include "emptyPolyPatch.H"
|
||||
#include "cellModeller.H"
|
||||
#include "demandDrivenData.H"
|
||||
#include "polyMeshUnMergeCyclics.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -150,6 +151,9 @@ Foam::autoPtr<Foam::polyMesh> Foam::meshReader::mesh
|
||||
// adding patches also checks the mesh
|
||||
mesh().addPatches(polyBoundaryPatches(mesh));
|
||||
|
||||
// Un-merge any merged cyclics
|
||||
polyMeshUnMergeCyclics(mesh());
|
||||
|
||||
warnDuplicates("boundaries", mesh().boundaryMesh().names());
|
||||
|
||||
addCellZones(mesh());
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -24,7 +24,7 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "STARCDMeshReader.H"
|
||||
#include "oldCyclicPolyPatch.H"
|
||||
#include "mergedCyclicPolyPatch.H"
|
||||
#include "emptyPolyPatch.H"
|
||||
#include "wallPolyPatch.H"
|
||||
#include "symmetryPolyPatch.H"
|
||||
@ -945,16 +945,12 @@ void Foam::meshReaders::STARCD::readBoundary(const fileName& inputName)
|
||||
}
|
||||
else if (origType == "cyclic")
|
||||
{
|
||||
// incorrect. should be cyclicPatch but this
|
||||
// requires info on connected faces.
|
||||
patchTypes_[patchi] = oldCyclicPolyPatch::typeName;
|
||||
patchTypes_[patchi] = mergedCyclicPolyPatch::typeName;
|
||||
patchPhysicalTypes_[patchi] = patchTypes_[patchi];
|
||||
}
|
||||
else if (origType == "baffle")
|
||||
{
|
||||
// incorrect. tag the patch until we get proper support.
|
||||
// set physical type to a canonical "baffle"
|
||||
patchTypes_[patchi] = emptyPolyPatch::typeName;
|
||||
patchTypes_[patchi] = mergedCyclicPolyPatch::typeName;
|
||||
patchPhysicalTypes_[patchi] = "baffle";
|
||||
}
|
||||
else
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -1244,8 +1244,7 @@ void Foam::fvMeshDistribute::addProcPatches
|
||||
mesh_.boundaryMesh(),
|
||||
Pstream::myProcNo(),
|
||||
proci,
|
||||
pcPatch.name(),
|
||||
pcPatch.ordering()
|
||||
pcPatch.name()
|
||||
);
|
||||
|
||||
procPatchID[proci].insert
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration | Website: https://openfoam.org
|
||||
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
|
||||
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
@ -25,6 +25,7 @@ License
|
||||
|
||||
#include "blockMesh.H"
|
||||
#include "Time.H"
|
||||
#include "cyclicTransform.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -127,11 +128,22 @@ Foam::PtrList<Foam::dictionary> Foam::blockMesh::patchDicts() const
|
||||
|
||||
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;
|
||||
patchTopologies[patchi].write(os);
|
||||
ppPtr->write(os);
|
||||
IStringStream is(os.str());
|
||||
patchDicts.set(patchi, new dictionary(is));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
label num = 0;
|
||||
|
||||
@ -204,8 +204,7 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
cyclicAMIPolyPatch
|
||||
@ -216,7 +215,6 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch
|
||||
index,
|
||||
bm,
|
||||
patchType,
|
||||
ordering,
|
||||
false,
|
||||
AMIInterpolation::imPartialFaceAreaWeight
|
||||
),
|
||||
@ -433,15 +431,15 @@ void Foam::cyclicACMIPolyPatch::calcGeometry
|
||||
const pointField& nbrCc
|
||||
)
|
||||
{
|
||||
cyclicAMIPolyPatch::calcGeometry
|
||||
static_cast<cyclicTransform&>(*this) =
|
||||
cyclicTransform
|
||||
(
|
||||
referPatch,
|
||||
thisCtrs,
|
||||
name(),
|
||||
thisAreas,
|
||||
thisCc,
|
||||
nbrCtrs,
|
||||
nbrAreas,
|
||||
nbrCc
|
||||
*this,
|
||||
nbrPatchName(),
|
||||
nbrPatch(),
|
||||
matchTolerance()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -109,8 +109,7 @@ public:
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct from dictionary
|
||||
|
||||
@ -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 * * * * * * * * * * * * //
|
||||
|
||||
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)
|
||||
{
|
||||
// Clear the invalid AMIs and transforms
|
||||
@ -439,8 +165,6 @@ void Foam::cyclicAMIPolyPatch::movePoints
|
||||
)
|
||||
{
|
||||
polyPatch::movePoints(pBufs, p);
|
||||
|
||||
calcTransforms();
|
||||
}
|
||||
|
||||
|
||||
@ -480,18 +204,14 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering,
|
||||
const bool AMIRequireMatch,
|
||||
const AMIInterpolation::interpolationMethod AMIMethod
|
||||
)
|
||||
:
|
||||
coupledPolyPatch(name, size, start, index, bm, patchType, ordering),
|
||||
coupledPolyPatch(name, size, start, index, bm, patchType),
|
||||
cyclicTransform(true),
|
||||
nbrPatchName_(word::null),
|
||||
nbrPatchID_(-1),
|
||||
rotationAxis_(Zero),
|
||||
rotationCentre_(point::zero),
|
||||
rotationAngleDefined_(false),
|
||||
rotationAngle_(0.0),
|
||||
AMIs_(),
|
||||
AMITransforms_(),
|
||||
AMIReverse_(false),
|
||||
@ -518,14 +238,10 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
)
|
||||
:
|
||||
coupledPolyPatch(name, dict, index, bm, patchType),
|
||||
cyclicTransform(dict),
|
||||
cyclicTransform(dict, true),
|
||||
nbrPatchName_(dict.lookupOrDefault<word>("neighbourPatch", "")),
|
||||
coupleGroup_(dict),
|
||||
nbrPatchID_(-1),
|
||||
rotationAxis_(Zero),
|
||||
rotationCentre_(point::zero),
|
||||
rotationAngleDefined_(false),
|
||||
rotationAngle_(0.0),
|
||||
AMIs_(),
|
||||
AMITransforms_(),
|
||||
AMIReverse_(dict.lookupOrDefault<bool>("flipNormals", false)),
|
||||
@ -562,49 +278,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
<< 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
|
||||
// calculation possible
|
||||
}
|
||||
@ -617,13 +290,10 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
)
|
||||
:
|
||||
coupledPolyPatch(pp, bm),
|
||||
cyclicTransform(pp),
|
||||
nbrPatchName_(pp.nbrPatchName_),
|
||||
coupleGroup_(pp.coupleGroup_),
|
||||
nbrPatchID_(-1),
|
||||
rotationAxis_(pp.rotationAxis_),
|
||||
rotationCentre_(pp.rotationCentre_),
|
||||
rotationAngleDefined_(pp.rotationAngleDefined_),
|
||||
rotationAngle_(pp.rotationAngle_),
|
||||
AMIs_(),
|
||||
AMITransforms_(),
|
||||
AMIReverse_(pp.AMIReverse_),
|
||||
@ -653,10 +323,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
nbrPatchName_(nbrPatchName),
|
||||
coupleGroup_(pp.coupleGroup_),
|
||||
nbrPatchID_(-1),
|
||||
rotationAxis_(pp.rotationAxis_),
|
||||
rotationCentre_(pp.rotationCentre_),
|
||||
rotationAngleDefined_(pp.rotationAngleDefined_),
|
||||
rotationAngle_(pp.rotationAngle_),
|
||||
AMIs_(),
|
||||
AMITransforms_(),
|
||||
AMIReverse_(pp.AMIReverse_),
|
||||
@ -693,10 +359,6 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
|
||||
nbrPatchName_(pp.nbrPatchName_),
|
||||
coupleGroup_(pp.coupleGroup_),
|
||||
nbrPatchID_(-1),
|
||||
rotationAxis_(pp.rotationAxis_),
|
||||
rotationCentre_(pp.rotationCentre_),
|
||||
rotationAngleDefined_(pp.rotationAngleDefined_),
|
||||
rotationAngle_(pp.rotationAngle_),
|
||||
AMIs_(),
|
||||
AMITransforms_(),
|
||||
AMIReverse_(pp.AMIReverse_),
|
||||
@ -924,15 +586,40 @@ void Foam::cyclicAMIPolyPatch::calcGeometry
|
||||
const pointField& nbrCc
|
||||
)
|
||||
{
|
||||
calcTransforms
|
||||
if
|
||||
(
|
||||
referPatch,
|
||||
!Pstream::parRun()
|
||||
&& !this->boundaryMesh().mesh().time().processorCase()
|
||||
)
|
||||
{
|
||||
static_cast<cyclicTransform&>(*this) =
|
||||
cyclicTransform
|
||||
(
|
||||
name(),
|
||||
thisCtrs,
|
||||
thisAreas,
|
||||
*this,
|
||||
nbrPatchName(),
|
||||
nbrCtrs,
|
||||
nbrAreas
|
||||
nbrAreas,
|
||||
nbrPatch(),
|
||||
matchTolerance()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cast<cyclicTransform&>(*this) =
|
||||
cyclicTransform
|
||||
(
|
||||
name(),
|
||||
thisAreas,
|
||||
*this,
|
||||
nbrPatchName(),
|
||||
nbrPatch(),
|
||||
matchTolerance()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::cyclicAMIPolyPatch::initOrder
|
||||
@ -1048,31 +735,6 @@ void Foam::cyclicAMIPolyPatch::write(Ostream& os) const
|
||||
|
||||
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_)
|
||||
{
|
||||
writeEntry(os, "flipNormals", AMIReverse_);
|
||||
|
||||
@ -55,21 +55,6 @@ class cyclicAMIPolyPatch
|
||||
public coupledPolyPatch,
|
||||
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 data
|
||||
@ -83,27 +68,6 @@ protected:
|
||||
//- Index of cyclic neighbour patch
|
||||
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
|
||||
mutable PtrList<AMIInterpolation> AMIs_;
|
||||
|
||||
@ -134,9 +98,6 @@ protected:
|
||||
//- Reset the AMI interpolator
|
||||
virtual void resetAMI() const;
|
||||
|
||||
//- Recalculate the transformation tensors
|
||||
virtual void calcTransforms();
|
||||
|
||||
//- Initialise the calculation of the patch geometry
|
||||
virtual void initGeometry(PstreamBuffers&);
|
||||
|
||||
@ -176,7 +137,6 @@ public:
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN,
|
||||
const bool AMIRequireMatch = true,
|
||||
const AMIInterpolation::interpolationMethod AMIMethod =
|
||||
AMIInterpolation::imFaceAreaWeight
|
||||
@ -329,12 +289,6 @@ public:
|
||||
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
|
||||
|
||||
|
||||
@ -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_;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -294,8 +294,7 @@ Foam::cyclicRepeatAMIPolyPatch::cyclicRepeatAMIPolyPatch
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering
|
||||
const word& patchType
|
||||
)
|
||||
:
|
||||
cyclicAMIPolyPatch
|
||||
@ -306,7 +305,6 @@ Foam::cyclicRepeatAMIPolyPatch::cyclicRepeatAMIPolyPatch
|
||||
index,
|
||||
bm,
|
||||
patchType,
|
||||
ordering,
|
||||
false,
|
||||
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
|
||||
{
|
||||
cyclicAMIPolyPatch::write(os);
|
||||
|
||||
@ -85,8 +85,7 @@ public:
|
||||
const label start,
|
||||
const label index,
|
||||
const polyBoundaryMesh& bm,
|
||||
const word& patchType,
|
||||
const orderingType ordering = UNKNOWN
|
||||
const word& patchType
|
||||
);
|
||||
|
||||
//- Construct from dictionary
|
||||
@ -210,6 +209,18 @@ public:
|
||||
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
|
||||
virtual void write(Ostream&) const;
|
||||
};
|
||||
|
||||
@ -256,6 +256,7 @@ boundary
|
||||
type cyclic;
|
||||
neighbourPatch baffleCyclic_half1;
|
||||
faces ();
|
||||
transformType none;
|
||||
}
|
||||
|
||||
baffleCyclic_half1
|
||||
@ -263,6 +264,7 @@ boundary
|
||||
type cyclic;
|
||||
neighbourPatch baffleCyclic_half0;
|
||||
faces ();
|
||||
transformType none;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user