Files
openfoam/src/dynamicMesh/polyMeshAdder/faceCoupleInfo.C

2156 lines
61 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2004-2010 OpenCFD Ltd.
\\/ 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 "faceCoupleInfo.H"
#include "polyMesh.H"
#include "matchPoints.H"
#include "indirectPrimitivePatch.H"
#include "meshTools.H"
#include "treeDataFace.H"
#include "indexedOctree.H"
#include "OFstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(Foam::faceCoupleInfo, 0);
const Foam::scalar Foam::faceCoupleInfo::angleTol_ = 1E-3;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
//- Write edges
void Foam::faceCoupleInfo::writeOBJ
(
const fileName& fName,
const edgeList& edges,
const pointField& points,
const bool compact
)
{
OFstream str(fName);
labelList pointMap(points.size(), -1);
if (compact)
{
label newPointI = 0;
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
forAll(e, eI)
{
label pointI = e[eI];
if (pointMap[pointI] == -1)
{
pointMap[pointI] = newPointI++;
meshTools::writeOBJ(str, points[pointI]);
}
}
}
}
else
{
forAll(points, pointI)
{
meshTools::writeOBJ(str, points[pointI]);
}
pointMap = identity(points.size());
}
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
str<< "l " << pointMap[e[0]]+1 << ' ' << pointMap[e[1]]+1 << nl;
}
}
//- Writes edges.
void Foam::faceCoupleInfo::writeOBJ
(
const fileName& fName,
const pointField& points0,
const pointField& points1
)
{
Pout<< "Writing connections as edges to " << fName << endl;
OFstream str(fName);
label vertI = 0;
forAll(points0, i)
{
meshTools::writeOBJ(str, points0[i]);
vertI++;
meshTools::writeOBJ(str, points1[i]);
vertI++;
str << "l " << vertI-1 << ' ' << vertI << nl;
}
}
//- Writes face and point connectivity as .obj files.
void Foam::faceCoupleInfo::writePointsFaces() const
{
const indirectPrimitivePatch& m = masterPatch();
const indirectPrimitivePatch& s = slavePatch();
const primitiveFacePatch& c = cutFaces();
// Patches
{
OFstream str("masterPatch.obj");
Pout<< "Writing masterPatch to " << str.name() << endl;
meshTools::writeOBJ(str, m.localFaces(), m.localPoints());
}
{
OFstream str("slavePatch.obj");
Pout<< "Writing slavePatch to " << str.name() << endl;
meshTools::writeOBJ(str, s.localFaces(), s.localPoints());
}
{
OFstream str("cutFaces.obj");
Pout<< "Writing cutFaces to " << str.name() << endl;
meshTools::writeOBJ(str, c.localFaces(), c.localPoints());
}
// Point connectivity
{
Pout<< "Writing cutToMasterPoints to cutToMasterPoints.obj" << endl;
writeOBJ
(
"cutToMasterPoints.obj",
m.localPoints(),
pointField(c.localPoints(), masterToCutPoints_));
}
{
Pout<< "Writing cutToSlavePoints to cutToSlavePoints.obj" << endl;
writeOBJ
(
"cutToSlavePoints.obj",
s.localPoints(),
pointField(c.localPoints(), slaveToCutPoints_)
);
}
// Face connectivity
{
Pout<< "Writing cutToMasterFaces to cutToMasterFaces.obj" << endl;
pointField equivMasterFaces(c.size());
forAll(cutToMasterFaces(), cutFaceI)
{
label masterFaceI = cutToMasterFaces()[cutFaceI];
if (masterFaceI != -1)
{
equivMasterFaces[cutFaceI] = m[masterFaceI].centre(m.points());
}
else
{
WarningIn("writePointsFaces()")
<< "No master face for cut face " << cutFaceI
<< " at position " << c[cutFaceI].centre(c.points())
<< endl;
equivMasterFaces[cutFaceI] = vector::zero;
}
}
writeOBJ
(
"cutToMasterFaces.obj",
calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
equivMasterFaces
);
}
{
Pout<< "Writing cutToSlaveFaces to cutToSlaveFaces.obj" << endl;
pointField equivSlaveFaces(c.size());
forAll(cutToSlaveFaces(), cutFaceI)
{
label slaveFaceI = cutToSlaveFaces()[cutFaceI];
equivSlaveFaces[cutFaceI] = s[slaveFaceI].centre(s.points());
}
writeOBJ
(
"cutToSlaveFaces.obj",
calcFaceCentres<List>(c, cutPoints(), 0, c.size()),
equivSlaveFaces
);
}
Pout<< endl;
}
void Foam::faceCoupleInfo::writeEdges
(
const labelList& cutToMasterEdges,
const labelList& cutToSlaveEdges
) const
{
const indirectPrimitivePatch& m = masterPatch();
const indirectPrimitivePatch& s = slavePatch();
const primitiveFacePatch& c = cutFaces();
// Edge connectivity
{
OFstream str("cutToMasterEdges.obj");
Pout<< "Writing cutToMasterEdges to " << str.name() << endl;
label vertI = 0;
forAll(cutToMasterEdges, cutEdgeI)
{
if (cutToMasterEdges[cutEdgeI] != -1)
{
const edge& masterEdge =
m.edges()[cutToMasterEdges[cutEdgeI]];
const edge& cutEdge = c.edges()[cutEdgeI];
meshTools::writeOBJ(str, m.localPoints()[masterEdge[0]]);
vertI++;
meshTools::writeOBJ(str, m.localPoints()[masterEdge[1]]);
vertI++;
meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
vertI++;
meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
vertI++;
str << "l " << vertI-3 << ' ' << vertI-2 << nl;
str << "l " << vertI-3 << ' ' << vertI-1 << nl;
str << "l " << vertI-3 << ' ' << vertI << nl;
str << "l " << vertI-2 << ' ' << vertI-1 << nl;
str << "l " << vertI-2 << ' ' << vertI << nl;
str << "l " << vertI-1 << ' ' << vertI << nl;
}
}
}
{
OFstream str("cutToSlaveEdges.obj");
Pout<< "Writing cutToSlaveEdges to " << str.name() << endl;
label vertI = 0;
labelList slaveToCut(invert(s.nEdges(), cutToSlaveEdges));
forAll(slaveToCut, edgeI)
{
if (slaveToCut[edgeI] != -1)
{
const edge& slaveEdge = s.edges()[edgeI];
const edge& cutEdge = c.edges()[slaveToCut[edgeI]];
meshTools::writeOBJ(str, s.localPoints()[slaveEdge[0]]);
vertI++;
meshTools::writeOBJ(str, s.localPoints()[slaveEdge[1]]);
vertI++;
meshTools::writeOBJ(str, c.localPoints()[cutEdge[0]]);
vertI++;
meshTools::writeOBJ(str, c.localPoints()[cutEdge[1]]);
vertI++;
str << "l " << vertI-3 << ' ' << vertI-2 << nl;
str << "l " << vertI-3 << ' ' << vertI-1 << nl;
str << "l " << vertI-3 << ' ' << vertI << nl;
str << "l " << vertI-2 << ' ' << vertI-1 << nl;
str << "l " << vertI-2 << ' ' << vertI << nl;
str << "l " << vertI-1 << ' ' << vertI << nl;
}
}
}
Pout<< endl;
}
// Given an edgelist and a map for the points on the edges it tries to find
// the corresponding patch edges.
Foam::labelList Foam::faceCoupleInfo::findMappedEdges
(
const edgeList& edges,
const labelList& pointMap,
const indirectPrimitivePatch& patch
)
{
labelList toPatchEdges(edges.size());
forAll(toPatchEdges, edgeI)
{
const edge& e = edges[edgeI];
label v0 = pointMap[e[0]];
label v1 = pointMap[e[1]];
toPatchEdges[edgeI] =
meshTools::findEdge
(
patch.edges(),
patch.pointEdges()[v0],
v0,
v1
);
}
return toPatchEdges;
}
// Detect a cut edge which originates from two boundary faces having different
// polyPatches.
bool Foam::faceCoupleInfo::regionEdge
(
const polyMesh& slaveMesh,
const label slaveEdgeI
) const
{
const labelList& eFaces = slavePatch().edgeFaces()[slaveEdgeI];
if (eFaces.size() == 1)
{
return true;
}
else
{
// Count how many different patches connected to this edge.
label patch0 = -1;
forAll(eFaces, i)
{
label faceI = eFaces[i];
label meshFaceI = slavePatch().addressing()[faceI];
label patchI = slaveMesh.boundaryMesh().whichPatch(meshFaceI);
if (patch0 == -1)
{
patch0 = patchI;
}
else if (patchI != patch0)
{
// Found two different patches connected to this edge.
return true;
}
}
return false;
}
}
// Find edge using pointI that is most aligned with vector between
// master points. Patchdivision tells us whether or not to use
// patch information to match edges.
Foam::label Foam::faceCoupleInfo::mostAlignedCutEdge
(
const bool report,
const polyMesh& slaveMesh,
const bool patchDivision,
const labelList& cutToMasterEdges,
const labelList& cutToSlaveEdges,
const label pointI,
const label edgeStart,
const label edgeEnd
) const
{
const pointField& localPoints = cutFaces().localPoints();
const labelList& pEdges = cutFaces().pointEdges()[pointI];
if (report)
{
Pout<< "mostAlignedEdge : finding nearest edge among "
<< UIndirectList<edge>(cutFaces().edges(), pEdges)()
<< " connected to point " << pointI
<< " coord:" << localPoints[pointI]
<< " running between " << edgeStart << " coord:"
<< localPoints[edgeStart]
<< " and " << edgeEnd << " coord:"
<< localPoints[edgeEnd]
<< endl;
}
// Find the edge that gets us nearest end.
label maxEdgeI = -1;
scalar maxCos = -GREAT;
forAll(pEdges, i)
{
label edgeI = pEdges[i];
if
(
!(
patchDivision
&& cutToMasterEdges[edgeI] == -1
)
|| (
patchDivision
&& regionEdge(slaveMesh, cutToSlaveEdges[edgeI])
)
)
{
const edge& e = cutFaces().edges()[edgeI];
label otherPointI = e.otherVertex(pointI);
if (otherPointI == edgeEnd)
{
// Shortcut: found edge end point.
if (report)
{
Pout<< " mostAlignedEdge : found end point " << edgeEnd
<< endl;
}
return edgeI;
}
// Get angle between edge and edge to masterEnd
vector eVec(localPoints[otherPointI] - localPoints[pointI]);
scalar magEVec = mag(eVec);
if (magEVec < VSMALL)
{
WarningIn("faceCoupleInfo::mostAlignedEdge")
<< "Crossing zero sized edge " << edgeI
<< " coords:" << localPoints[otherPointI]
<< localPoints[pointI]
<< " when walking from " << localPoints[edgeStart]
<< " to " << localPoints[edgeEnd]
<< endl;
return edgeI;
}
eVec /= magEVec;
vector eToEndPoint(localPoints[edgeEnd] - localPoints[otherPointI]);
eToEndPoint /= mag(eToEndPoint);
scalar cosAngle = eVec & eToEndPoint;
if (report)
{
Pout<< " edge:" << e << " points:" << localPoints[pointI]
<< localPoints[otherPointI]
<< " vec:" << eVec
<< " vecToEnd:" << eToEndPoint
<< " cosAngle:" << cosAngle
<< endl;
}
if (cosAngle > maxCos)
{
maxCos = cosAngle;
maxEdgeI = edgeI;
}
}
}
if (maxCos > 1 - angleTol_)
{
return maxEdgeI;
}
else
{
return -1;
}
}
// Construct points to split points map (in cut addressing)
void Foam::faceCoupleInfo::setCutEdgeToPoints(const labelList& cutToMasterEdges)
{
labelListList masterToCutEdges
(
invertOneToMany
(
masterPatch().nEdges(),
cutToMasterEdges
)
);
const edgeList& cutEdges = cutFaces().edges();
// Size extra big so searching is faster
cutEdgeToPoints_.resize
(
masterPatch().nEdges()
+ slavePatch().nEdges()
+ cutEdges.size()
);
forAll(masterToCutEdges, masterEdgeI)
{
const edge& masterE = masterPatch().edges()[masterEdgeI];
//Pout<< "Master:" << masterPatch().localPoints()[masterE[0]] << ' '
// << masterPatch().localPoints()[masterE[1]] << endl;
const labelList& stringedEdges = masterToCutEdges[masterEdgeI];
if (stringedEdges.empty())
{
FatalErrorIn
(
"faceCoupleInfo::setCutEdgeToPoints"
"(const labelList&)"
) << "Did not match all of master edges to cutFace edges"
<< nl
<< "First unmatched edge:" << masterEdgeI << " endPoints:"
<< masterPatch().localPoints()[masterE[0]]
<< masterPatch().localPoints()[masterE[1]]
<< endl
<< "This usually means that the slave patch is not a"
<< " subdivision of the master patch"
<< abort(FatalError);
}
else if (stringedEdges.size() > 1)
{
// String up the edges between e[0] and e[1]. Store the points
// inbetween e[0] and e[1] (all in cutFaces() labels)
DynamicList<label> splitPoints(stringedEdges.size()-1);
// Unsplit edge endpoints
const edge unsplitEdge
(
masterToCutPoints_[masterE[0]],
masterToCutPoints_[masterE[1]]
);
label startVertI = unsplitEdge[0];
label startEdgeI = -1;
while (startVertI != unsplitEdge[1])
{
// Loop over all string of edges. Update
// - startVertI : previous vertex
// - startEdgeI : previous edge
// and insert any points into splitPoints
// For checking
label oldStart = startVertI;
forAll(stringedEdges, i)
{
label edgeI = stringedEdges[i];
if (edgeI != startEdgeI)
{
const edge& e = cutEdges[edgeI];
//Pout<< " cut:" << e << " at:"
// << cutFaces().localPoints()[e[0]]
// << ' ' << cutFaces().localPoints()[e[1]] << endl;
if (e[0] == startVertI)
{
startEdgeI = edgeI;
startVertI = e[1];
if (e[1] != unsplitEdge[1])
{
splitPoints.append(e[1]);
}
break;
}
else if (e[1] == startVertI)
{
startEdgeI = edgeI;
startVertI = e[0];
if (e[0] != unsplitEdge[1])
{
splitPoints.append(e[0]);
}
break;
}
}
}
// Check
if (oldStart == startVertI)
{
FatalErrorIn
(
"faceCoupleInfo::setCutEdgeToPoints"
"(const labelList&)"
) << " unsplitEdge:" << unsplitEdge
<< " does not correspond to split edges "
<< UIndirectList<edge>(cutEdges, stringedEdges)()
<< abort(FatalError);
}
}
//Pout<< "For master edge:"
// << unsplitEdge
// << " Found stringed points "
// << UIndirectList<point>
// (
// cutFaces().localPoints(),
// splitPoints.shrink()
// )()
// << endl;
cutEdgeToPoints_.insert(unsplitEdge, splitPoints.shrink());
}
}
}
// Determines rotation for f1 to match up with f0, i.e. the index in f0 of
// the first point of f1.
Foam::label Foam::faceCoupleInfo::matchFaces
(
const scalar absTol,
const pointField& points0,
const face& f0,
const pointField& points1,
const face& f1,
const bool sameOrientation
)
{
if (f0.size() != f1.size())
{
FatalErrorIn
(
"faceCoupleInfo::matchFaces"
"(const scalar, const face&, const pointField&"
", const face&, const pointField&)"
) << "Different sizes for supposedly matching faces." << nl
<< "f0:" << f0 << " coords:" << UIndirectList<point>(points0, f0)()
<< nl
<< "f1:" << f1 << " coords:" << UIndirectList<point>(points1, f1)()
<< abort(FatalError);
}
const scalar absTolSqr = sqr(absTol);
label matchFp = -1;
forAll(f0, startFp)
{
// See -if starting from startFp on f0- the two faces match.
bool fullMatch = true;
label fp0 = startFp;
label fp1 = 0;
forAll(f1, i)
{
scalar distSqr = Foam::magSqr(points0[f0[fp0]] - points1[f1[fp1]]);
if (distSqr > absTolSqr)
{
fullMatch = false;
break;
}
fp0 = f0.fcIndex(fp0); // walk forward
if (sameOrientation)
{
fp1 = f1.fcIndex(fp1);
}
else
{
fp1 = f1.rcIndex(fp1);
}
}
if (fullMatch)
{
matchFp = startFp;
break;
}
}
if (matchFp == -1)
{
FatalErrorIn
(
"faceCoupleInfo::matchFaces"
"(const scalar, const face&, const pointField&"
", const face&, const pointField&)"
) << "No unique match between two faces" << nl
<< "Face " << f0 << " coords "
<< UIndirectList<point>(points0, f0)() << nl
<< "Face " << f1 << " coords "
<< UIndirectList<point>(points1, f1)()
<< "when using tolerance " << absTol
<< " and forwardMatching:" << sameOrientation
<< abort(FatalError);
}
return matchFp;
}
// Find correspondence from patch points to cut points. This might
// detect shared points so the output is a patch-to-cut point list
// and a compaction list for the cut points (which will always be equal or more
// connected than the patch).
// Returns true if there are any duplicates.
bool Foam::faceCoupleInfo::matchPointsThroughFaces
(
const scalar absTol,
const pointField& cutPoints,
const faceList& cutFaces,
const pointField& patchPoints,
const faceList& patchFaces,
const bool sameOrientation,
labelList& patchToCutPoints, // patch to (uncompacted) cut points
labelList& cutToCompact, // compaction list for cut points
labelList& compactToCut // inverse ,,
)
{
// From slave to cut point
patchToCutPoints.setSize(patchPoints.size());
patchToCutPoints = -1;
// Compaction list for cut points: either -1 or index into master which
// gives the point to compact to.
labelList cutPointRegion(cutPoints.size(), -1);
DynamicList<label> cutPointRegionMaster;
forAll(patchFaces, patchFaceI)
{
const face& patchF = patchFaces[patchFaceI];
//const face& cutF = cutFaces[patchToCutFaces[patchFaceI]];
const face& cutF = cutFaces[patchFaceI];
// Do geometric matching to get position of cutF[0] in patchF
label patchFp = matchFaces
(
absTol,
patchPoints,
patchF,
cutPoints,
cutF,
sameOrientation // orientation
);
forAll(cutF, cutFp)
{
label cutPointI = cutF[cutFp];
label patchPointI = patchF[patchFp];
//const point& cutPt = cutPoints[cutPointI];
//const point& patchPt = patchPoints[patchPointI];
//if (mag(cutPt - patchPt) > SMALL)
//{
// FatalErrorIn("matchPointsThroughFaces")
// << "cutP:" << cutPt
// << " patchP:" << patchPt
// << abort(FatalError);
//}
if (patchToCutPoints[patchPointI] == -1)
{
patchToCutPoints[patchPointI] = cutPointI;
}
else if (patchToCutPoints[patchPointI] != cutPointI)
{
// Multiple cut points connecting to same patch.
// Check if already have region & region master for this set
label otherCutPointI = patchToCutPoints[patchPointI];
//Pout<< "PatchPoint:" << patchPt
// << " matches to:" << cutPointI
// << " coord:" << cutPoints[cutPointI]
// << " and to:" << otherCutPointI
// << " coord:" << cutPoints[otherCutPointI]
// << endl;
if (cutPointRegion[otherCutPointI] != -1)
{
// Have region for this set. Copy.
label region = cutPointRegion[otherCutPointI];
cutPointRegion[cutPointI] = region;
// Update region master with min point label
cutPointRegionMaster[region] = min
(
cutPointRegionMaster[region],
cutPointI
);
}
else
{
// Create new region.
label region = cutPointRegionMaster.size();
cutPointRegionMaster.append
(
min(cutPointI, otherCutPointI)
);
cutPointRegion[cutPointI] = region;
cutPointRegion[otherCutPointI] = region;
}
}
if (sameOrientation)
{
patchFp = patchF.fcIndex(patchFp);
}
else
{
patchFp = patchF.rcIndex(patchFp);
}
}
}
// Rework region&master into compaction array
compactToCut.setSize(cutPointRegion.size());
cutToCompact.setSize(cutPointRegion.size());
cutToCompact = -1;
label compactPointI = 0;
forAll(cutPointRegion, i)
{
if (cutPointRegion[i] == -1)
{
// Unduplicated point. Allocate new compacted point.
cutToCompact[i] = compactPointI;
compactToCut[compactPointI] = i;
compactPointI++;
}
else
{
// Duplicate point. Get master.
label masterPointI = cutPointRegionMaster[cutPointRegion[i]];
if (cutToCompact[masterPointI] == -1)
{
cutToCompact[masterPointI] = compactPointI;
compactToCut[compactPointI] = masterPointI;
compactPointI++;
}
cutToCompact[i] = cutToCompact[masterPointI];
}
}
compactToCut.setSize(compactPointI);
return compactToCut.size() != cutToCompact.size();
}
// Return max distance from any point on cutF to masterF
Foam::scalar Foam::faceCoupleInfo::maxDistance
(
const face& cutF,
const pointField& cutPoints,
const face& masterF,
const pointField& masterPoints
)
{
scalar maxDist = -GREAT;
forAll(cutF, fp)
{
const point& cutPt = cutPoints[cutF[fp]];
pointHit pHit = masterF.nearestPoint(cutPt, masterPoints);
maxDist = max(maxDist, pHit.distance());
}
return maxDist;
}
void Foam::faceCoupleInfo::findPerfectMatchingFaces
(
const primitiveMesh& mesh0,
const primitiveMesh& mesh1,
const scalar absTol,
labelList& mesh0Faces,
labelList& mesh1Faces
)
{
// Face centres of external faces (without invoking
// mesh.faceCentres since mesh might have been clearedOut)
pointField fc0
(
calcFaceCentres<List>
(
mesh0.faces(),
mesh0.points(),
mesh0.nInternalFaces(),
mesh0.nFaces() - mesh0.nInternalFaces()
)
);
pointField fc1
(
calcFaceCentres<List>
(
mesh1.faces(),
mesh1.points(),
mesh1.nInternalFaces(),
mesh1.nFaces() - mesh1.nInternalFaces()
)
);
if (debug)
{
Pout<< "Face matching tolerance : " << absTol << endl;
}
// Match geometrically
labelList from1To0;
bool matchedAllFaces = matchPoints
(
fc1,
fc0,
scalarField(fc1.size(), absTol),
false,
from1To0
);
if (matchedAllFaces)
{
Warning
<< "faceCoupleInfo::faceCoupleInfo : "
<< "Matched ALL " << fc1.size()
<< " boundary faces of mesh0 to boundary faces of mesh1." << endl
<< "This is only valid if the mesh to add is fully"
<< " enclosed by the mesh it is added to." << endl;
}
// Collect matches.
label nMatched = 0;
mesh0Faces.setSize(fc0.size());
mesh1Faces.setSize(fc1.size());
forAll(from1To0, i)
{
if (from1To0[i] != -1)
{
mesh1Faces[nMatched] = i + mesh1.nInternalFaces();
mesh0Faces[nMatched] = from1To0[i] + mesh0.nInternalFaces();
nMatched++;
}
}
mesh0Faces.setSize(nMatched);
mesh1Faces.setSize(nMatched);
}
void Foam::faceCoupleInfo::findSlavesCoveringMaster
(
const primitiveMesh& mesh0,
const primitiveMesh& mesh1,
const scalar absTol,
labelList& mesh0Faces,
labelList& mesh1Faces
)
{
// Construct octree from all mesh0 boundary faces
labelList bndFaces(mesh0.nFaces()-mesh0.nInternalFaces());
forAll(bndFaces, i)
{
bndFaces[i] = mesh0.nInternalFaces() + i;
}
treeBoundBox overallBb(mesh0.points());
Random rndGen(123456);
indexedOctree<treeDataFace> tree
(
treeDataFace // all information needed to search faces
(
false, // do not cache bb
mesh0,
bndFaces // boundary faces only
),
overallBb.extend(rndGen, 1E-4), // overall search domain
8, // maxLevel
10, // leafsize
3.0 // duplicity
);
if (debug)
{
Pout<< "findSlavesCoveringMaster :"
<< " constructed octree for mesh0 boundary faces" << endl;
}
// Search nearest face for every mesh1 boundary face.
labelHashSet mesh0Set(mesh0.nFaces() - mesh0.nInternalFaces());
labelHashSet mesh1Set(mesh1.nFaces() - mesh1.nInternalFaces());
for
(
label mesh1FaceI = mesh1.nInternalFaces();
mesh1FaceI < mesh1.nFaces();
mesh1FaceI++
)
{
const face& f1 = mesh1.faces()[mesh1FaceI];
// Generate face centre (prevent cellCentres() reconstruction)
point fc(f1.centre(mesh1.points()));
pointIndexHit nearInfo = tree.findNearest(fc, Foam::sqr(absTol));
if (nearInfo.hit())
{
label mesh0FaceI = tree.shapes().faceLabels()[nearInfo.index()];
// Check if points of f1 actually lie on top of mesh0 face
// This is the bit that might fail since if f0 is severely warped
// and f1's points are not present on f0 (since subdivision)
// then the distance of the points to f0 might be quite large
// and the test will fail. This all should in fact be some kind
// of walk from known corresponding points/edges/faces.
scalar dist =
maxDistance
(
f1,
mesh1.points(),
mesh0.faces()[mesh0FaceI],
mesh0.points()
);
if (dist < absTol)
{
mesh0Set.insert(mesh0FaceI);
mesh1Set.insert(mesh1FaceI);
}
}
}
if (debug)
{
Pout<< "findSlavesCoveringMaster :"
<< " matched " << mesh1Set.size() << " mesh1 faces to "
<< mesh0Set.size() << " mesh0 faces" << endl;
}
mesh0Faces = mesh0Set.toc();
mesh1Faces = mesh1Set.toc();
}
// Grow cutToMasterFace across 'internal' edges.
Foam::label Foam::faceCoupleInfo::growCutFaces
(
const labelList& cutToMasterEdges,
Map<labelList>& candidates
)
{
if (debug)
{
Pout<< "growCutFaces :"
<< " growing cut faces to masterPatch" << endl;
}
label nTotChanged = 0;
while (true)
{
const labelListList& cutFaceEdges = cutFaces().faceEdges();
const labelListList& cutEdgeFaces = cutFaces().edgeFaces();
label nChanged = 0;
forAll(cutToMasterFaces_, cutFaceI)
{
const label masterFaceI = cutToMasterFaces_[cutFaceI];
if (masterFaceI != -1)
{
// We now have a cutFace for which we have already found a
// master face. Grow this masterface across any internal edge
// (internal: no corresponding master edge)
const labelList& fEdges = cutFaceEdges[cutFaceI];
forAll(fEdges, i)
{
const label cutEdgeI = fEdges[i];
if (cutToMasterEdges[cutEdgeI] == -1)
{
// So this edge:
// - internal to the cutPatch (since all region edges
// marked before)
// - on cutFaceI which corresponds to masterFace.
// Mark all connected faces with this masterFace.
const labelList& eFaces = cutEdgeFaces[cutEdgeI];
forAll(eFaces, j)
{
const label faceI = eFaces[j];
if (cutToMasterFaces_[faceI] == -1)
{
cutToMasterFaces_[faceI] = masterFaceI;
candidates.erase(faceI);
nChanged++;
}
else if (cutToMasterFaces_[faceI] != masterFaceI)
{
const pointField& cutPoints =
cutFaces().points();
const pointField& masterPoints =
masterPatch().points();
const edge& e = cutFaces().edges()[cutEdgeI];
label myMaster = cutToMasterFaces_[faceI];
const face& myF = masterPatch()[myMaster];
const face& nbrF = masterPatch()[masterFaceI];
FatalErrorIn
(
"faceCoupleInfo::growCutFaces"
"(const labelList&, Map<labelList>&)"
) << "Cut face "
<< cutFaces()[faceI].points(cutPoints)
<< " has master "
<< myMaster
<< " but also connects to nbr face "
<< cutFaces()[cutFaceI].points(cutPoints)
<< " with master " << masterFaceI
<< nl
<< "myMasterFace:"
<< myF.points(masterPoints)
<< " nbrMasterFace:"
<< nbrF.points(masterPoints) << nl
<< "Across cut edge " << cutEdgeI
<< " coord:"
<< cutFaces().localPoints()[e[0]]
<< cutFaces().localPoints()[e[1]]
<< abort(FatalError);
}
}
}
}
}
}
if (debug)
{
Pout<< "growCutFaces : Grown an additional " << nChanged
<< " cut to master face" << " correspondence" << endl;
}
nTotChanged += nChanged;
if (nChanged == 0)
{
break;
}
}
return nTotChanged;
}
void Foam::faceCoupleInfo::checkMatch(const labelList& cutToMasterEdges) const
{
const pointField& cutLocalPoints = cutFaces().localPoints();
const pointField& masterLocalPoints = masterPatch().localPoints();
const faceList& masterLocalFaces = masterPatch().localFaces();
forAll(cutToMasterEdges, cutEdgeI)
{
const edge& e = cutFaces().edges()[cutEdgeI];
if (cutToMasterEdges[cutEdgeI] == -1)
{
// Internal edge. Check that master face is same on both sides.
const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
label masterFaceI = -1;
forAll(cutEFaces, i)
{
label cutFaceI = cutEFaces[i];
if (cutToMasterFaces_[cutFaceI] != -1)
{
if (masterFaceI == -1)
{
masterFaceI = cutToMasterFaces_[cutFaceI];
}
else if (masterFaceI != cutToMasterFaces_[cutFaceI])
{
label myMaster = cutToMasterFaces_[cutFaceI];
const face& myF = masterLocalFaces[myMaster];
const face& nbrF = masterLocalFaces[masterFaceI];
FatalErrorIn
(
"faceCoupleInfo::checkMatch(const labelList&) const"
)
<< "Internal CutEdge " << e
<< " coord:"
<< cutLocalPoints[e[0]]
<< cutLocalPoints[e[1]]
<< " connects to master " << myMaster
<< " and to master " << masterFaceI << nl
<< "myMasterFace:"
<< myF.points(masterLocalPoints)
<< " nbrMasterFace:"
<< nbrF.points(masterLocalPoints)
<< abort(FatalError);
}
}
}
}
}
}
// Extends matching information by elimination across cutFaces using more
// than one region edge. Updates cutToMasterFaces_ and sets candidates
// which is for every cutface on a region edge the possible master faces.
Foam::label Foam::faceCoupleInfo::matchEdgeFaces
(
const labelList& cutToMasterEdges,
Map<labelList>& candidates
)
{
// For every unassigned cutFaceI the possible list of master faces.
candidates.clear();
candidates.resize(cutFaces().size());
label nChanged = 0;
forAll(cutToMasterEdges, cutEdgeI)
{
label masterEdgeI = cutToMasterEdges[cutEdgeI];
if (masterEdgeI != -1)
{
// So cutEdgeI is matched to masterEdgeI. For all cut faces using
// the cut edge store the master face as a candidate match.
const labelList& cutEFaces = cutFaces().edgeFaces()[cutEdgeI];
const labelList& masterEFaces =
masterPatch().edgeFaces()[masterEdgeI];
forAll(cutEFaces, i)
{
label cutFaceI = cutEFaces[i];
if (cutToMasterFaces_[cutFaceI] == -1)
{
// So this face (cutFaceI) is on an edge (cutEdgeI) that
// is used by some master faces (masterEFaces). Check if
// the cutFaceI and some of these masterEFaces share more
// than one edge (which uniquely defines face)
// Combine master faces with current set of candidate
// master faces.
Map<labelList>::iterator fnd = candidates.find(cutFaceI);
if (fnd == candidates.end())
{
// No info yet for cutFaceI. Add all master faces as
// candidates
candidates.insert(cutFaceI, masterEFaces);
}
else
{
// From some other cutEdgeI there are already some
// candidate master faces. Check the overlap with
// the current set of master faces.
const labelList& masterFaces = fnd();
DynamicList<label> newCandidates(masterFaces.size());
forAll(masterEFaces, j)
{
if (findIndex(masterFaces, masterEFaces[j]) != -1)
{
newCandidates.append(masterEFaces[j]);
}
}
if (newCandidates.size() == 1)
{
// We found a perfect match. Delete entry from
// candidates map.
cutToMasterFaces_[cutFaceI] = newCandidates[0];
candidates.erase(cutFaceI);
nChanged++;
}
else
{
// Should not happen?
//Pout<< "On edge:" << cutEdgeI
// << " have connected masterFaces:"
// << masterEFaces
// << " and from previous edge we have"
// << " connected masterFaces" << masterFaces
// << " . Overlap:" << newCandidates << endl;
fnd() = newCandidates.shrink();
}
}
}
}
}
}
if (debug)
{
Pout<< "matchEdgeFaces : Found " << nChanged
<< " faces where there was"
<< " only one remaining choice for cut-master correspondence"
<< endl;
}
return nChanged;
}
// Gets a list of cutFaces (that use a master edge) and the candidate
// master faces.
// Finds most aligned master face.
Foam::label Foam::faceCoupleInfo::geometricMatchEdgeFaces
(
Map<labelList>& candidates
)
{
const pointField& cutPoints = cutFaces().points();
label nChanged = 0;
// Mark all master faces that have been matched so far.
labelListList masterToCutFaces
(
invertOneToMany
(
masterPatch().size(),
cutToMasterFaces_
)
);
forAllConstIter(Map<labelList>, candidates, iter)
{
label cutFaceI = iter.key();
const face& cutF = cutFaces()[cutFaceI];
if (cutToMasterFaces_[cutFaceI] == -1)
{
const labelList& masterFaces = iter();
// Find the best matching master face.
scalar minDist = GREAT;
label minMasterFaceI = -1;
forAll(masterFaces, i)
{
label masterFaceI = masterFaces[i];
if (masterToCutFaces[masterFaces[i]].empty())
{
scalar dist = maxDistance
(
cutF,
cutPoints,
masterPatch()[masterFaceI],
masterPatch().points()
);
if (dist < minDist)
{
minDist = dist;
minMasterFaceI = masterFaceI;
}
}
}
if (minMasterFaceI != -1)
{
cutToMasterFaces_[cutFaceI] = minMasterFaceI;
masterToCutFaces[minMasterFaceI] = cutFaceI;
nChanged++;
}
}
}
// (inefficiently) force candidates to be uptodate.
forAll(cutToMasterFaces_, cutFaceI)
{
if (cutToMasterFaces_[cutFaceI] != -1)
{
candidates.erase(cutFaceI);
}
}
if (debug)
{
Pout<< "geometricMatchEdgeFaces : Found " << nChanged
<< " faces where there was"
<< " only one remaining choice for cut-master correspondence"
<< endl;
}
return nChanged;
}
// Calculate the set of cut faces inbetween master and slave patch
// assuming perfect match (and optional face ordering on slave)
void Foam::faceCoupleInfo::perfectPointMatch
(
const scalar absTol,
const bool slaveFacesOrdered
)
{
if (debug)
{
Pout<< "perfectPointMatch :"
<< " Matching master and slave to cut."
<< " Master and slave faces are identical" << nl;
if (slaveFacesOrdered)
{
Pout<< "and master and slave faces are ordered"
<< " (on coupled patches)" << endl;
}
else
{
Pout<< "and master and slave faces are not ordered"
<< " (on coupled patches)" << endl;
}
}
cutToMasterFaces_ = identity(masterPatch().size());
cutPoints_ = masterPatch().localPoints();
cutFacesPtr_.reset
(
new primitiveFacePatch
(
masterPatch().localFaces(),
cutPoints_
)
);
masterToCutPoints_ = identity(cutPoints_.size());
// Cut faces to slave patch.
bool matchedAllFaces = false;
if (slaveFacesOrdered)
{
cutToSlaveFaces_ = identity(cutFaces().size());
matchedAllFaces = (cutFaces().size() == slavePatch().size());
}
else
{
// Faces do not have to be ordered (but all have
// to match). Note: Faces will be already ordered if we enter here from
// construct from meshes.
matchedAllFaces = matchPoints
(
calcFaceCentres<List>
(
cutFaces(),
cutPoints_,
0,
cutFaces().size()
),
calcFaceCentres<IndirectList>
(
slavePatch(),
slavePatch().points(),
0,
slavePatch().size()
),
scalarField(slavePatch().size(), absTol),
true,
cutToSlaveFaces_
);
}
if (!matchedAllFaces)
{
FatalErrorIn
(
"faceCoupleInfo::perfectPointMatch"
"(const scalar, const bool)"
) << "Did not match all of the master faces to the slave faces"
<< endl
<< "This usually means that the slave patch and master patch"
<< " do not align to within " << absTol << " meter."
<< abort(FatalError);
}
// Find correspondence from slave points to cut points. This might
// detect shared points so the output is a slave-to-cut point list
// and a compaction list.
labelList cutToCompact, compactToCut;
matchPointsThroughFaces
(
absTol,
cutFaces().localPoints(),
reorder(cutToSlaveFaces_, cutFaces().localFaces()),
slavePatch().localPoints(),
slavePatch().localFaces(),
false, // slave and cut have opposite orientation
slaveToCutPoints_, // slave to (uncompacted) cut points
cutToCompact, // compaction map: from cut to compacted
compactToCut // compaction map: from compacted to cut
);
// Use compaction lists to renumber cutPoints.
cutPoints_ = UIndirectList<point>(cutPoints_, compactToCut)();
{
const faceList& cutLocalFaces = cutFaces().localFaces();
faceList compactFaces(cutLocalFaces.size());
forAll(cutLocalFaces, i)
{
compactFaces[i] = renumber(cutToCompact, cutLocalFaces[i]);
}
cutFacesPtr_.reset
(
new primitiveFacePatch
(
compactFaces,
cutPoints_
)
);
}
inplaceRenumber(cutToCompact, slaveToCutPoints_);
inplaceRenumber(cutToCompact, masterToCutPoints_);
}
// Calculate the set of cut faces inbetween master and slave patch
// assuming that slave patch is subdivision of masterPatch.
void Foam::faceCoupleInfo::subDivisionMatch
(
const polyMesh& slaveMesh,
const bool patchDivision,
const scalar absTol
)
{
if (debug)
{
Pout<< "subDivisionMatch :"
<< " Matching master and slave to cut."
<< " Slave can be subdivision of master but all master edges"
<< " have to be covered by slave edges." << endl;
}
// Assume slave patch is subdivision of the master patch so cutFaces is a
// copy of the slave (but reversed since orientation has to be like master).
cutPoints_ = slavePatch().localPoints();
{
faceList cutFaces(slavePatch().size());
forAll(cutFaces, i)
{
cutFaces[i] = slavePatch().localFaces()[i].reverseFace();
}
cutFacesPtr_.reset(new primitiveFacePatch(cutFaces, cutPoints_));
}
// Cut is copy of slave so addressing to slave is trivial.
cutToSlaveFaces_ = identity(cutFaces().size());
slaveToCutPoints_ = identity(slavePatch().nPoints());
// Cut edges to slave patch
labelList cutToSlaveEdges
(
findMappedEdges
(
cutFaces().edges(),
slaveToCutPoints_, //note:should be cutToSlavePoints but since iden
slavePatch()
)
);
if (debug)
{
OFstream str("regionEdges.obj");
Pout<< "subDivisionMatch :"
<< " addressing for slave patch fully done."
<< " Dumping region edges to " << str.name() << endl;
label vertI = 0;
forAll(slavePatch().edges(), slaveEdgeI)
{
if (regionEdge(slaveMesh, slaveEdgeI))
{
const edge& e = slavePatch().edges()[slaveEdgeI];
meshTools::writeOBJ(str, slavePatch().localPoints()[e[0]]);
vertI++;
meshTools::writeOBJ(str, slavePatch().localPoints()[e[1]]);
vertI++;
str<< "l " << vertI-1 << ' ' << vertI << nl;
}
}
}
// Addressing from cut to master.
// Cut points to master patch
// - determine master points to cut points. Has to be full!
// - invert to get cut to master
if (debug)
{
Pout<< "subDivisionMatch :"
<< " matching master points to cut points" << endl;
}
bool matchedAllPoints = matchPoints
(
masterPatch().localPoints(),
cutPoints_,
scalarField(masterPatch().nPoints(), absTol),
true,
masterToCutPoints_
);
if (!matchedAllPoints)
{
FatalErrorIn
(
"faceCoupleInfo::subDivisionMatch"
"(const polyMesh&, const bool, const scalar)"
) << "Did not match all of the master points to the slave points"
<< endl
<< "This usually means that the slave patch is not a"
<< " subdivision of the master patch"
<< abort(FatalError);
}
// Do masterEdges to cutEdges :
// - mark all edges between two masterEdge endpoints. (geometric test since
// this is the only distinction)
// - this gives the borders inbetween which all cutfaces come from
// a single master face.
if (debug)
{
Pout<< "subDivisionMatch :"
<< " matching cut edges to master edges" << endl;
}
const edgeList& masterEdges = masterPatch().edges();
const pointField& masterPoints = masterPatch().localPoints();
const edgeList& cutEdges = cutFaces().edges();
labelList cutToMasterEdges(cutFaces().nEdges(), -1);
forAll(masterEdges, masterEdgeI)
{
const edge& masterEdge = masterEdges[masterEdgeI];
label cutPoint0 = masterToCutPoints_[masterEdge[0]];
label cutPoint1 = masterToCutPoints_[masterEdge[1]];
// Find edges between cutPoint0 and cutPoint1.
label cutPointI = cutPoint0;
do
{
// Find edge (starting at pointI on cut), aligned with master
// edge.
label cutEdgeI =
mostAlignedCutEdge
(
false,
slaveMesh,
patchDivision,
cutToMasterEdges,
cutToSlaveEdges,
cutPointI,
cutPoint0,
cutPoint1
);
if (cutEdgeI == -1)
{
// Problem. Report while matching to produce nice error message
mostAlignedCutEdge
(
true,
slaveMesh,
patchDivision,
cutToMasterEdges,
cutToSlaveEdges,
cutPointI,
cutPoint0,
cutPoint1
);
Pout<< "Dumping unmatched pointEdges to errorEdges.obj"
<< endl;
writeOBJ
(
"errorEdges.obj",
edgeList
(
UIndirectList<edge>
(
cutFaces().edges(),
cutFaces().pointEdges()[cutPointI]
)
),
cutFaces().localPoints(),
false
);
FatalErrorIn
(
"faceCoupleInfo::subDivisionMatch"
"(const polyMesh&, const bool, const scalar)"
) << "Problem in finding cut edges corresponding to"
<< " master edge " << masterEdge
<< " points:" << masterPoints[masterEdge[0]]
<< ' ' << masterPoints[masterEdge[1]]
<< " corresponding cut edge: (" << cutPoint0
<< ' ' << cutPoint1
<< abort(FatalError);
}
cutToMasterEdges[cutEdgeI] = masterEdgeI;
cutPointI = cutEdges[cutEdgeI].otherVertex(cutPointI);
} while (cutPointI != cutPoint1);
}
if (debug)
{
// Write all matched edges.
writeEdges(cutToMasterEdges, cutToSlaveEdges);
}
// Rework cutToMasterEdges into list of points inbetween two endpoints
// (cutEdgeToPoints_)
setCutEdgeToPoints(cutToMasterEdges);
// Now that we have marked the cut edges that lie on top of master edges
// we can find cut faces that have two (or more) of these edges.
// Note that there can be multiple faces having two or more matched edges
// since the cut faces can form a non-manifold surface(?)
// So the matching is done as an elimination process where for every
// cutFace on a matched edge we store the possible master faces and
// eliminate more and more until we only have one possible master face
// left.
if (debug)
{
Pout<< "subDivisionMatch :"
<< " matching (topological) cut faces to masterPatch" << endl;
}
// For every unassigned cutFaceI the possible list of master faces.
Map<labelList> candidates(cutFaces().size());
cutToMasterFaces_.setSize(cutFaces().size());
cutToMasterFaces_ = -1;
while (true)
{
// See if there are any edges left where there is only one remaining
// candidate.
label nChanged = matchEdgeFaces(cutToMasterEdges, candidates);
checkMatch(cutToMasterEdges);
// Now we should have found a face correspondence for every cutFace
// that uses two or more cutEdges. Floodfill from these across
// 'internal' cutedges (i.e. edges that do not have a master
// equivalent) to determine some more cutToMasterFaces
nChanged += growCutFaces(cutToMasterEdges, candidates);
checkMatch(cutToMasterEdges);
if (nChanged == 0)
{
break;
}
}
if (debug)
{
Pout<< "subDivisionMatch :"
<< " matching (geometric) cut faces to masterPatch" << endl;
}
// Above should have matched all cases fully. Cannot prove this yet so
// do any remaining unmatched edges by a geometric test.
while (true)
{
// See if there are any edges left where there is only one remaining
// candidate.
label nChanged = geometricMatchEdgeFaces(candidates);
checkMatch(cutToMasterEdges);
nChanged += growCutFaces(cutToMasterEdges, candidates);
checkMatch(cutToMasterEdges);
if (nChanged == 0)
{
break;
}
}
// All cut faces matched?
forAll(cutToMasterFaces_, cutFaceI)
{
if (cutToMasterFaces_[cutFaceI] == -1)
{
const face& cutF = cutFaces()[cutFaceI];
FatalErrorIn
(
"faceCoupleInfo::subDivisionMatch"
"(const polyMesh&, const bool, const scalar)"
) << "Did not match all of cutFaces to a master face" << nl
<< "First unmatched cut face:" << cutFaceI << " with points:"
<< UIndirectList<point>(cutFaces().points(), cutF)()
<< nl
<< "This usually means that the slave patch is not a"
<< " subdivision of the master patch"
<< abort(FatalError);
}
}
if (debug)
{
Pout<< "subDivisionMatch :"
<< " finished matching master and slave to cut" << endl;
}
if (debug)
{
writePointsFaces();
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from mesh data
Foam::faceCoupleInfo::faceCoupleInfo
(
const polyMesh& masterMesh,
const polyMesh& slaveMesh,
const scalar absTol,
const bool perfectMatch
)
:
masterPatchPtr_(NULL),
slavePatchPtr_(NULL),
cutPoints_(0),
cutFacesPtr_(NULL),
cutToMasterFaces_(0),
masterToCutPoints_(0),
cutToSlaveFaces_(0),
slaveToCutPoints_(0),
cutEdgeToPoints_(0)
{
// Get faces on both meshes that are aligned.
// (not ordered i.e. masterToMesh[0] does
// not couple to slaveToMesh[0]. This ordering is done later on)
labelList masterToMesh;
labelList slaveToMesh;
if (perfectMatch)
{
// Identical faces so use tight face-centre comparison.
findPerfectMatchingFaces
(
masterMesh,
slaveMesh,
absTol,
masterToMesh,
slaveToMesh
);
}
else
{
// Slave subdivision of master so use 'nearest'. Bit dodgy, especially
// with using absTol (which is quite small)
findSlavesCoveringMaster
(
masterMesh,
slaveMesh,
absTol,
masterToMesh,
slaveToMesh
);
}
// Construct addressing engines for both sides
masterPatchPtr_.reset
(
new indirectPrimitivePatch
(
IndirectList<face>(masterMesh.faces(), masterToMesh),
masterMesh.points()
)
);
slavePatchPtr_.reset
(
new indirectPrimitivePatch
(
IndirectList<face>(slaveMesh.faces(), slaveToMesh),
slaveMesh.points()
)
);
if (perfectMatch)
{
// Faces are perfectly aligned but probably not ordered.
perfectPointMatch(absTol, false);
}
else
{
// Slave faces are subdivision of master face. Faces not ordered.
subDivisionMatch(slaveMesh, false, absTol);
}
if (debug)
{
writePointsFaces();
}
}
// Slave is subdivision of master patch.
// (so -both cover the same area -all of master points are present in slave)
Foam::faceCoupleInfo::faceCoupleInfo
(
const polyMesh& masterMesh,
const labelList& masterAddressing,
const polyMesh& slaveMesh,
const labelList& slaveAddressing,
const scalar absTol,
const bool perfectMatch,
const bool orderedFaces,
const bool patchDivision
)
:
masterPatchPtr_
(
new indirectPrimitivePatch
(
IndirectList<face>(masterMesh.faces(), masterAddressing),
masterMesh.points()
)
),
slavePatchPtr_
(
new indirectPrimitivePatch
(
IndirectList<face>(slaveMesh.faces(), slaveAddressing),
slaveMesh.points()
)
),
cutPoints_(0),
cutFacesPtr_(NULL),
cutToMasterFaces_(0),
masterToCutPoints_(0),
cutToSlaveFaces_(0),
slaveToCutPoints_(0),
cutEdgeToPoints_(0)
{
if (perfectMatch && (masterAddressing.size() != slaveAddressing.size()))
{
FatalErrorIn
(
"faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
", const primitiveMesh&, const scalar, const bool"
) << "Perfect match specified but number of master and slave faces"
<< " differ." << endl
<< "master:" << masterAddressing.size()
<< " slave:" << slaveAddressing.size()
<< abort(FatalError);
}
if
(
masterAddressing.size()
&& min(masterAddressing) < masterMesh.nInternalFaces()
)
{
FatalErrorIn
(
"faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
", const primitiveMesh&, const scalar, const bool"
) << "Supplied internal face on master mesh to couple." << nl
<< "Faces to be coupled have to be boundary faces."
<< abort(FatalError);
}
if
(
slaveAddressing.size()
&& min(slaveAddressing) < slaveMesh.nInternalFaces()
)
{
FatalErrorIn
(
"faceCoupleInfo::faceCoupleInfo(const primitiveMesh&"
", const primitiveMesh&, const scalar, const bool"
) << "Supplied internal face on slave mesh to couple." << nl
<< "Faces to be coupled have to be boundary faces."
<< abort(FatalError);
}
if (perfectMatch)
{
perfectPointMatch(absTol, orderedFaces);
}
else
{
// Slave faces are subdivision of master face. Faces not ordered.
subDivisionMatch(slaveMesh, patchDivision, absTol);
}
if (debug)
{
writePointsFaces();
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::faceCoupleInfo::~faceCoupleInfo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::labelList Foam::faceCoupleInfo::faceLabels(const polyPatch& pp)
{
labelList faces(pp.size());
label faceI = pp.start();
forAll(pp, i)
{
faces[i] = faceI++;
}
return faces;
}
Foam::Map<Foam::label> Foam::faceCoupleInfo::makeMap(const labelList& lst)
{
Map<label> map(lst.size());
forAll(lst, i)
{
if (lst[i] != -1)
{
map.insert(i, lst[i]);
}
}
return map;
}
Foam::Map<Foam::labelList> Foam::faceCoupleInfo::makeMap
(
const labelListList& lst
)
{
Map<labelList> map(lst.size());
forAll(lst, i)
{
if (lst[i].size())
{
map.insert(i, lst[i]);
}
}
return map;
}
// ************************************************************************* //