diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict index b3be8fe96f68bfd6240a98ef05fb71c0b45b7e15..f0cc40a8e4867cc7d1de6408832d6360006e9985 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMeshDict @@ -245,6 +245,10 @@ snapControls //- Use castellatedMeshControls::features (default = true) explicitFeatureSnap true; + + //- Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap false; } // Settings for the layer addition. diff --git a/applications/utilities/miscellaneous/foamDebugSwitches/Make/options b/applications/utilities/miscellaneous/foamDebugSwitches/Make/options index 6fe40ed9f19464475c06f704c9842935d8fcdfd1..6fa4104188a79deb511308fe1cf34d9e80243768 100644 --- a/applications/utilities/miscellaneous/foamDebugSwitches/Make/options +++ b/applications/utilities/miscellaneous/foamDebugSwitches/Make/options @@ -60,7 +60,6 @@ EXE_LIBS = \ -lsurfaceFilmModels \ -lsurfMesh \ -lsystemCall \ - -lthermalPorousZone \ -lthermophysicalFunctions \ -ltopoChangerFvMesh \ -ltriSurface \ diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C index d06e5d03cb8b12ff53e10e575d6a01fc31a58cdc..b3b390af515122423aaf6a99116a267366cd1da2 100644 --- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C +++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtract.C @@ -25,7 +25,8 @@ Application surfaceFeatureExtract Description - Extracts and writes surface features to file + Extracts and writes surface features to file. All but the basic feature + extraction is WIP. \*---------------------------------------------------------------------------*/ @@ -472,6 +473,176 @@ void unmarkBaffles } +//- Divide into multiple normal bins +// - return REGION if != 2 normals +// - return REGION if 2 normals that make feature angle +// - otherwise return NONE and set normals,bins +surfaceFeatures::edgeStatus checkFlatRegionEdge +( + const triSurface& surf, + const scalar tol, + const scalar includedAngle, + const label edgeI +) +{ + const edge& e = surf.edges()[edgeI]; + const labelList& eFaces = surf.edgeFaces()[edgeI]; + + // Bin according to normal + + DynamicList<Foam::vector> normals(2); + DynamicList<labelList> bins(2); + + forAll(eFaces, eFaceI) + { + const Foam::vector& n = surf.faceNormals()[eFaces[eFaceI]]; + + // Find the normal in normals + label index = -1; + forAll(normals, normalI) + { + if (mag(n&normals[normalI]) > (1-tol)) + { + index = normalI; + break; + } + } + + if (index != -1) + { + bins[index].append(eFaceI); + } + else if (normals.size() >= 2) + { + // Would be third normal. Mark as feature. + //Pout<< "** at edge:" << surf.localPoints()[e[0]] + // << surf.localPoints()[e[1]] + // << " have normals:" << normals + // << " and " << n << endl; + return surfaceFeatures::REGION; + } + else + { + normals.append(n); + bins.append(labelList(1, eFaceI)); + } + } + + + // Check resulting number of bins + if (bins.size() == 1) + { + // Note: should check here whether they are two sets of faces + // that are planar or indeed 4 faces al coming together at an edge. + //Pout<< "** at edge:" + // << surf.localPoints()[e[0]] + // << surf.localPoints()[e[1]] + // << " have single normal:" << normals[0] + // << endl; + return surfaceFeatures::NONE; + } + else + { + // Two bins. Check if normals make an angle + + //Pout<< "** at edge:" + // << surf.localPoints()[e[0]] + // << surf.localPoints()[e[1]] << nl + // << " normals:" << normals << nl + // << " bins :" << bins << nl + // << endl; + + if (includedAngle >= 0) + { + scalar minCos = Foam::cos(degToRad(180.0 - includedAngle)); + + forAll(eFaces, i) + { + const Foam::vector& ni = surf.faceNormals()[eFaces[i]]; + for (label j=i+1; j<eFaces.size(); j++) + { + const Foam::vector& nj = surf.faceNormals()[eFaces[j]]; + if (mag(ni & nj) < minCos) + { + //Pout<< "have sharp feature between normal:" << ni + // << " and " << nj << endl; + + // Is feature. Keep as region or convert to + // feature angle? For now keep as region. + return surfaceFeatures::REGION; + } + } + } + } + + + // So now we have two normals bins but need to make sure both + // bins have the same regions in it. + + // 1. store + or - region number depending + // on orientation of triangle in bins[0] + const labelList& bin0 = bins[0]; + labelList regionAndNormal(bin0.size()); + forAll(bin0, i) + { + const labelledTri& t = surf.localFaces()[eFaces[bin0[i]]]; + int dir = t.edgeDirection(e); + + if (dir > 0) + { + regionAndNormal[i] = t.region()+1; + } + else if (dir == 0) + { + FatalErrorIn("problem.") + << exit(FatalError); + } + else + { + regionAndNormal[i] = -(t.region()+1); + } + } + + // 2. check against bin1 + const labelList& bin1 = bins[1]; + labelList regionAndNormal1(bin1.size()); + forAll(bin1, i) + { + const labelledTri& t = surf.localFaces()[eFaces[bin1[i]]]; + int dir = t.edgeDirection(e); + + label myRegionAndNormal; + if (dir > 0) + { + myRegionAndNormal = t.region()+1; + } + else + { + myRegionAndNormal = -(t.region()+1); + } + + regionAndNormal1[i] = myRegionAndNormal; + + label index = findIndex(regionAndNormal, -myRegionAndNormal); + if (index == -1) + { + // Not found. + //Pout<< "cannot find region " << myRegionAndNormal + // << " in regions " << regionAndNormal << endl; + + return surfaceFeatures::REGION; + } + } + + // Passed all checks, two normal bins with the same contents. + //Pout<< "regionAndNormal:" << regionAndNormal << endl; + //Pout<< "myRegionAndNormal:" << regionAndNormal1 << endl; + + return surfaceFeatures::NONE; + } +} + + void writeStats(const extendedFeatureEdgeMesh& fem, Ostream& os) { os << " points : " << fem.points().size() << nl @@ -610,6 +781,8 @@ int main(int argc, char *argv[]) surfaceFeatures set(surf); + scalar includedAngle = -1; + if (extractionMethod == "extractFromFile") { const fileName featureEdgeFile = @@ -630,14 +803,13 @@ int main(int argc, char *argv[]) } else if (extractionMethod == "extractFromSurface") { - const scalar includedAngle = - readScalar + includedAngle = readScalar + ( + surfaceDict.subDict("extractFromSurfaceCoeffs").lookup ( - surfaceDict.subDict("extractFromSurfaceCoeffs").lookup - ( - "includedAngle" - ) - ); + "includedAngle" + ) + ); Info<< nl << "Constructing feature set from included angle " << includedAngle << endl; @@ -727,13 +899,27 @@ int main(int argc, char *argv[]) if (!nonManifoldEdges) { Info<< "Removing all non-manifold edges" - << " (edges with > 2 connected faces)" << endl; + << " (edges with > 2 connected faces) unless they" + << " cross multiple regions" << endl; forAll(edgeStat, edgeI) { - if (surf.edgeFaces()[edgeI].size() > 2) + const labelList& eFaces = surf.edgeFaces()[edgeI]; + + if + ( + eFaces.size() > 2 + && edgeStat[edgeI] == surfaceFeatures::REGION + && (eFaces.size() % 2) == 0 + ) { - edgeStat[edgeI] = surfaceFeatures::NONE; + edgeStat[edgeI] = checkFlatRegionEdge + ( + surf, + 1e-5, //tol, + includedAngle, + edgeI + ); } } } diff --git a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict index 6c1eab66e9c5cc466540055c8b0382dc633bf109..a52ebdfa555755da0ff951721f0d26823ad6b2b1 100644 --- a/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict +++ b/applications/utilities/surface/surfaceFeatureExtract/surfaceFeatureExtractDict @@ -69,7 +69,8 @@ surface2.nas // Keep edges outside the box: outsideBox (0 0 0)(1 1 1); - // Keep nonManifold edges (edges with >2 connected faces) + // Keep nonManifold edges (edges with >2 connected faces where + // the faces form more than two different normal planes) nonManifoldEdges yes; // Keep open edges (edges with 1 connected face) diff --git a/src/OSspecific/POSIX/regExp.C b/src/OSspecific/POSIX/regExp.C index 3ce0d2c4471b69f487781c4bbc64d5971ac5f4fa..2023f9ce59870df5786c1b58638c9c3f24ee882f 100644 --- a/src/OSspecific/POSIX/regExp.C +++ b/src/OSspecific/POSIX/regExp.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -80,12 +80,18 @@ void Foam::regExp::set(const char* pattern, const bool ignoreCase) const cflags |= REG_ICASE; } - if (regcomp(preg_, pattern, cflags) != 0) + int err = regcomp(preg_, pattern, cflags); + + if (err != 0) { + char errbuf[200]; + regerror(err, preg_, errbuf, sizeof(errbuf)); + FatalErrorIn ( "regExp::set(const char*)" ) << "Failed to compile regular expression '" << pattern << "'" + << nl << errbuf << exit(FatalError); } } diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C index a3161386e69677e283c5b2d7872a6465dfdfde2d..c93aad5a36f956d6075d1b89e4329cd601ba5a93 100644 --- a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C +++ b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C @@ -266,7 +266,7 @@ Foam::Istream& Foam::ISstream::read(token& t) else { t = sPtr; - t.type() = token::STRING; + t.type() = token::VARIABLE; } return *this; } diff --git a/src/OpenFOAM/db/IOstreams/token/token.H b/src/OpenFOAM/db/IOstreams/token/token.H index 75c946d1d407c48fc2da2a73ab9fd783c9a72e1a..a1523fd3ffd5194b3e309457c7a069abb5026998 100644 --- a/src/OpenFOAM/db/IOstreams/token/token.H +++ b/src/OpenFOAM/db/IOstreams/token/token.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -77,6 +77,7 @@ public: PUNCTUATION, WORD, + VARIABLE, STRING, VERBATIMSTRING, LABEL, @@ -331,6 +332,8 @@ public: inline bool isWord() const; inline const word& wordToken() const; + inline bool isVariable() const; + inline bool isString() const; inline const string& stringToken() const; diff --git a/src/OpenFOAM/db/IOstreams/token/tokenI.H b/src/OpenFOAM/db/IOstreams/token/tokenI.H index dfa6cdf93e453162c30fe7cb7546921dab6ee618..e23fc83679463bcaa3acb00a9857129ddbabd4f1 100644 --- a/src/OpenFOAM/db/IOstreams/token/tokenI.H +++ b/src/OpenFOAM/db/IOstreams/token/tokenI.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -39,7 +39,7 @@ inline void token::clear() { delete wordTokenPtr_; } - else if (type_ == STRING || type_ == VERBATIMSTRING) + else if (type_ == STRING || type_ == VARIABLE || type_ == VERBATIMSTRING) { delete stringTokenPtr_; } @@ -88,6 +88,7 @@ inline token::token(const token& t) break; case STRING: + case VARIABLE: case VERBATIMSTRING: stringTokenPtr_ = new string(*t.stringTokenPtr_); break; @@ -235,14 +236,19 @@ inline const word& token::wordToken() const } } +inline bool token::isVariable() const +{ + return (type_ == VARIABLE); +} + inline bool token::isString() const { - return (type_ == STRING || type_ == VERBATIMSTRING); + return (type_ == STRING || type_ == VARIABLE || type_ == VERBATIMSTRING); } inline const string& token::stringToken() const { - if (type_ == STRING || type_ == VERBATIMSTRING) + if (type_ == STRING || type_ == VARIABLE || type_ == VERBATIMSTRING) { return *stringTokenPtr_; } @@ -411,6 +417,7 @@ inline void token::operator=(const token& t) break; case STRING: + case VARIABLE: case VERBATIMSTRING: stringTokenPtr_ = new string(*t.stringTokenPtr_); break; @@ -518,6 +525,7 @@ inline bool token::operator==(const token& t) const return *wordTokenPtr_ == *t.wordTokenPtr_; case STRING: + case VARIABLE: case VERBATIMSTRING: return *stringTokenPtr_ == *t.stringTokenPtr_; @@ -552,7 +560,11 @@ inline bool token::operator==(const word& w) const inline bool token::operator==(const string& s) const { - return ((type_ == STRING || type_ == VERBATIMSTRING) && stringToken() == s); + return + ( + (type_ == STRING || type_ == VARIABLE || type_ == VERBATIMSTRING) + && stringToken() == s + ); } inline bool token::operator==(const label l) const diff --git a/src/OpenFOAM/db/IOstreams/token/tokenIO.C b/src/OpenFOAM/db/IOstreams/token/tokenIO.C index 2aedebe6814f737da7bfd6c8574337e13286402b..b513a4be0eda7d991b10f538ae11499ced859134 100644 --- a/src/OpenFOAM/db/IOstreams/token/tokenIO.C +++ b/src/OpenFOAM/db/IOstreams/token/tokenIO.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -74,6 +74,11 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const token& t) os << *t.stringTokenPtr_; break; + case token::VARIABLE: + // Write variable as word so without "" + os.writeQuoted(*t.stringTokenPtr_, false); + break; + case token::LABEL: os << t.labelToken_; break; @@ -157,6 +162,10 @@ ostream& Foam::operator<<(ostream& os, const InfoProxy<token>& ip) os << " the string " << t.stringToken(); break; + case token::VARIABLE: + os << " the variable " << t.stringToken(); + break; + case token::VERBATIMSTRING: os << " the verbatim string " << t.stringToken(); break; @@ -231,6 +240,10 @@ Ostream& operator<<(Ostream& os, const InfoProxy<token>& ip) os << " the string " << t.stringToken(); break; + case token::VARIABLE: + os << " the variable " << t.stringToken(); + break; + case token::VERBATIMSTRING: os << " the verbatim string " << t.stringToken(); break; diff --git a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C index d5626972cc37fc25f92bb87655613bd1ecf6ccac..04cb8cf1652a357bdfed346982650de532c0d493 100644 --- a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C +++ b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C @@ -55,7 +55,7 @@ void Foam::primitiveEntry::append newElmt(tokenIndex()++) = currToken; } } - else if (currToken.isString()) + else if (currToken.isVariable()) { const string& w = currToken.stringToken(); diff --git a/src/OpenFOAM/primitives/functions/DataEntry/Table/TableBase.H b/src/OpenFOAM/primitives/functions/DataEntry/Table/TableBase.H index 929e151a0c7aca1b197546435cf9d928c4de1dde..da670e2db56a80ec8eecc6e781963219464e79ce 100644 --- a/src/OpenFOAM/primitives/functions/DataEntry/Table/TableBase.H +++ b/src/OpenFOAM/primitives/functions/DataEntry/Table/TableBase.H @@ -125,7 +125,7 @@ public: //- Construct from dictionary - note table is not populated TableBase(const word& name, const dictionary& dict); - //- Copy constructor + //- Copy constructor. Note: steals interpolator, tableSamples TableBase(const TableBase<Type>& tbl); diff --git a/tutorials/mesh/snappyHexMesh/flange/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/flange/system/snappyHexMeshDict index 520d52950fd68de40456313e06c8e895313a99a2..a1c0e1162f43801b6007ec103c38b837ec14209c 100644 --- a/tutorials/mesh/snappyHexMesh/flange/system/snappyHexMeshDict +++ b/tutorials/mesh/snappyHexMesh/flange/system/snappyHexMeshDict @@ -186,6 +186,10 @@ snapControls //- Use castellatedMeshControls::features explicitFeatureSnap true; + + //- Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap true; }