/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 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 "directions.H"
#include "polyMesh.H"
#include "twoDPointCorrector.H"
#include "directionInfo.H"
#include "MeshWave.H"
#include "OFstream.H"
#include "meshTools.H"
#include "hexMatcher.H"
#include "Switch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template<>
const char* Foam::NamedEnum::names[] =
{
"tan1",
"tan2",
"normal"
};
const Foam::NamedEnum
Foam::directions::directionTypeNames_;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// For debugging
void Foam::directions::writeOBJ(Ostream& os, const point& pt)
{
os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
}
// For debugging
void Foam::directions::writeOBJ
(
Ostream& os,
const point& pt0,
const point& pt1,
label& vertI
)
{
writeOBJ(os, pt0);
writeOBJ(os, pt1);
os << "l " << vertI + 1 << ' ' << vertI + 2 << endl;
vertI += 2;
}
// Dump to file.
void Foam::directions::writeOBJ
(
const fileName& fName,
const primitiveMesh& mesh,
const vectorField& dirs
)
{
Pout<< "Writing cell info to " << fName << " as vectors at the cellCentres"
<< endl << endl;
OFstream xDirStream(fName);
label vertI = 0;
forAll(dirs, cellI)
{
const point& ctr = mesh.cellCentres()[cellI];
// Calculate local length scale
scalar minDist = GREAT;
const labelList& nbrs = mesh.cellCells()[cellI];
forAll(nbrs, nbrI)
{
minDist = min(minDist, mag(mesh.cellCentres()[nbrs[nbrI]] - ctr));
}
scalar scale = 0.5*minDist;
writeOBJ(xDirStream, ctr, ctr + scale*dirs[cellI], vertI);
}
}
void Foam::directions::check2D
(
const twoDPointCorrector* correct2DPtr,
const vector& vec
)
{
if (correct2DPtr)
{
if (mag(correct2DPtr->planeNormal() & vec) > 1E-6)
{
FatalErrorIn("check2D") << "Specified vector " << vec
<< "is not normal to plane defined in dynamicMeshDict."
<< endl
<< "Either make case 3D or adjust vector."
<< exit(FatalError);
}
}
}
// Get direction on all cells
Foam::vectorField Foam::directions::propagateDirection
(
const polyMesh& mesh,
const bool useTopo,
const polyPatch& pp,
const vectorField& ppField,
const vector& defaultDir
)
{
// Seed all faces on patch
labelList changedFaces(pp.size());
List changedFacesInfo(pp.size());
if (useTopo)
{
forAll(pp, patchFaceI)
{
label meshFaceI = pp.start() + patchFaceI;
label cellI = mesh.faceOwner()[meshFaceI];
if (!hexMatcher().isA(mesh, cellI))
{
FatalErrorIn("propagateDirection")
<< "useHexTopology specified but cell " << cellI
<< " on face " << patchFaceI << " of patch " << pp.name()
<< " is not a hex" << exit(FatalError);
}
const vector& cutDir = ppField[patchFaceI];
// Get edge(bundle) on cell most in direction of cutdir
label edgeI = meshTools::cutDirToEdge(mesh, cellI, cutDir);
// Convert edge into index on face
label faceIndex =
directionInfo::edgeToFaceIndex
(
mesh,
cellI,
meshFaceI,
edgeI
);
// Set initial face and direction
changedFaces[patchFaceI] = meshFaceI;
changedFacesInfo[patchFaceI] =
directionInfo
(
faceIndex,
cutDir
);
}
}
else
{
forAll(pp, patchFaceI)
{
changedFaces[patchFaceI] = pp.start() + patchFaceI;
changedFacesInfo[patchFaceI] =
directionInfo
(
-2, // Geometric information only
ppField[patchFaceI]
);
}
}
MeshWave directionCalc
(
mesh,
changedFaces,
changedFacesInfo,
mesh.nCells()
);
const List& cellInfo = directionCalc.allCellInfo();
vectorField dirField(cellInfo.size());
label nUnset = 0;
label nGeom = 0;
label nTopo = 0;
forAll(cellInfo, cellI)
{
label index = cellInfo[cellI].index();
if (index == -3)
{
// Never visited
WarningIn("propagateDirection")
<< "Cell " << cellI << " never visited to determine "
<< "local coordinate system" << endl
<< "Using direction " << defaultDir << " instead" << endl;
dirField[cellI] = defaultDir;
nUnset++;
}
else if (index == -2)
{
// Geometric direction
dirField[cellI] = cellInfo[cellI].n();
nGeom++;
}
else if (index == -1)
{
FatalErrorIn("propagateDirection")
<< "Illegal index " << index << endl
<< "Value is only allowed on faces" << abort(FatalError);
}
else
{
// Topological edge cut. Convert into average cut direction.
dirField[cellI] = meshTools::edgeToCutDir(mesh, cellI, index);
nTopo++;
}
}
Pout<< "Calculated local coords for " << defaultDir
<< endl
<< " Geometric cut cells : " << nGeom << endl
<< " Topological cut cells : " << nTopo << endl
<< " Unset cells : " << nUnset << endl
<< endl;
return dirField;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from dictionary
Foam::directions::directions
(
const polyMesh& mesh,
const dictionary& dict,
const twoDPointCorrector* correct2DPtr
)
:
List(wordList(dict.lookup("directions")).size())
{
const wordList wantedDirs(dict.lookup("directions"));
bool wantNormal = false;
bool wantTan1 = false;
bool wantTan2 = false;
forAll(wantedDirs, i)
{
directionType wantedDir = directionTypeNames_[wantedDirs[i]];
if (wantedDir == NORMAL)
{
wantNormal = true;
}
else if (wantedDir == TAN1)
{
wantTan1 = true;
}
else if (wantedDir == TAN2)
{
wantTan2 = true;
}
}
label nDirs = 0;
const word coordSystem(dict.lookup("coordinateSystem"));
if (coordSystem == "global")
{
const dictionary& globalDict = dict.subDict("globalCoeffs");
vector tan1(globalDict.lookup("tan1"));
check2D(correct2DPtr, tan1);
vector tan2(globalDict.lookup("tan2"));
check2D(correct2DPtr, tan2);
vector normal = tan1 ^ tan2;
normal /= mag(normal);
Pout<< "Global Coordinate system:" << endl
<< " normal : " << normal << endl
<< " tan1 : " << tan1 << endl
<< " tan2 : " << tan2
<< endl << endl;
if (wantNormal)
{
operator[](nDirs++) = vectorField(1, normal);
}
if (wantTan1)
{
operator[](nDirs++) = vectorField(1, tan1);
}
if (wantTan2)
{
operator[](nDirs++) = vectorField(1, tan2);
}
}
else if (coordSystem == "patchLocal")
{
const dictionary& patchDict = dict.subDict("patchLocalCoeffs");
const word patchName(patchDict.lookup("patch"));
label patchI = mesh.boundaryMesh().findPatchID(patchName);
if (patchI == -1)
{
FatalErrorIn
(
"directions::directions(const polyMesh&, const dictionary&,"
"const twoDPointCorrector*"
) << "Cannot find patch "
<< patchName
<< exit(FatalError);
}
// Take zeroth face on patch
const polyPatch& pp = mesh.boundaryMesh()[patchI];
vector tan1(patchDict.lookup("tan1"));
const vector& n0 = pp.faceNormals()[0];
if (correct2DPtr)
{
tan1 = correct2DPtr->planeNormal() ^ n0;
WarningIn
(
"directions::directions(const polyMesh&, const dictionary&,"
"const twoDPointCorrector*"
) << "Discarding user specified tan1 since 2D case." << endl
<< "Recalculated tan1 from face normal and planeNormal as "
<< tan1 << endl << endl;
}
Switch useTopo(dict.lookup("useHexTopology"));
vectorField normalDirs;
vectorField tan1Dirs;
if (wantNormal || wantTan2)
{
normalDirs =
propagateDirection
(
mesh,
useTopo,
pp,
pp.faceNormals(),
n0
);
if (wantNormal)
{
operator[](nDirs++) = normalDirs;
//// Dump to file.
//writeOBJ("normal.obj", mesh, normalDirs);
}
}
if (wantTan1 || wantTan2)
{
tan1Dirs =
propagateDirection
(
mesh,
useTopo,
pp,
vectorField(pp.size(), tan1),
tan1
);
if (wantTan1)
{
operator[](nDirs++) = tan1Dirs;
//// Dump to file.
//writeOBJ("tan1.obj", mesh, tan1Dirs);
}
}
if (wantTan2)
{
vectorField tan2Dirs = normalDirs ^ tan1Dirs;
operator[](nDirs++) = tan2Dirs;
//// Dump to file.
//writeOBJ("tan2.obj", mesh, tan2Dirs);
}
}
else
{
FatalErrorIn
(
"directions::directions(const polyMesh&, const dictionary&,"
"const twoDPointCorrector*"
) << "Unknown coordinate system "
<< coordSystem << endl
<< "Known types are global and patchLocal"
<< exit(FatalError);
}
}
// ************************************************************************* //