/*---------------------------------------------------------------------------*\
========= |
\\ / 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 .
\*----------------------------------------------------------------------------*/
#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(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(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(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