/*---------------------------------------------------------------------------*\ ========= | \\ / 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); } } // ************************************************************************* //