mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
465 lines
12 KiB
C
465 lines
12 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / 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 2 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, write to the Free Software Foundation,
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#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<Foam::directions::directionType, 3>::names[] =
|
|
{
|
|
"tan1",
|
|
"tan2",
|
|
"normal"
|
|
};
|
|
|
|
const Foam::NamedEnum<Foam::directions::directionType, 3>
|
|
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<directionInfo> 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<directionInfo> directionCalc
|
|
(
|
|
mesh,
|
|
changedFaces,
|
|
changedFacesInfo,
|
|
mesh.nCells()
|
|
);
|
|
|
|
const List<directionInfo>& 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<vectorField>(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;
|
|
|
|
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");
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
|
|
|
|
|
|
// ************************************************************************* //
|