/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2020-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- 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 "refinementFeatures.H" #include "Time.H" #include "Tuple2.H" #include "DynamicField.H" #include "featureEdgeMesh.H" #include "meshRefinement.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::refinementFeatures::read ( const objectRegistry& io, const PtrList& featDicts ) { forAll(featDicts, featI) { const dictionary& dict = featDicts[featI]; fileName featFileName ( meshRefinement::get ( dict, "file", dryRun_, keyType::REGEX, fileName::null ) ); // Try reading extendedEdgeMesh first IOobject extFeatObj ( featFileName, // name io.time().constant(), // instance "extendedFeatureEdgeMesh", // local io.time(), // registry IOobject::MUST_READ, IOobject::NO_WRITE, IOobject::NO_REGISTER ); const fileName fName ( extFeatObj.typeFilePath() ); if (!fName.empty() && extendedEdgeMesh::canRead(fName)) { autoPtr eMeshPtr = extendedEdgeMesh::New ( fName ); if (!dryRun_) { Info<< "Read extendedFeatureEdgeMesh " << extFeatObj.name() << nl << incrIndent; eMeshPtr().writeStats(Info); Info<< decrIndent << endl; } set(featI, new extendedFeatureEdgeMesh(extFeatObj, eMeshPtr())); } else { // Try reading edgeMesh IOobject featObj ( featFileName, // name io.time().constant(), // instance "triSurface", // local io.time(), // registry IOobject::MUST_READ, IOobject::NO_WRITE, IOobject::NO_REGISTER ); const fileName fName ( featObj.typeFilePath() ); if (fName.empty()) { FatalIOErrorInFunction(dict) << "Could not open " << featObj.objectPath() << exit(FatalIOError); } // Read as edgeMesh autoPtr eMeshPtr = edgeMesh::New(fName); const edgeMesh& eMesh = eMeshPtr(); if (!dryRun_) { Info<< "Read edgeMesh " << featObj.name() << nl << incrIndent; eMesh.writeStats(Info); Info<< decrIndent << endl; } // Analyse for feature points. These are all classified as mixed // points for lack of anything better const labelListList& pointEdges = eMesh.pointEdges(); labelList oldToNew(eMesh.points().size(), -1); DynamicField newPoints(eMesh.points().size()); forAll(pointEdges, pointi) { if (pointEdges[pointi].size() > 2) { oldToNew[pointi] = newPoints.size(); newPoints.append(eMesh.points()[pointi]); } //else if (pointEdges[pointi].size() == 2) //MEJ: do something based on a feature angle? } label nFeatures = newPoints.size(); forAll(oldToNew, pointi) { if (oldToNew[pointi] == -1) { oldToNew[pointi] = newPoints.size(); newPoints.append(eMesh.points()[pointi]); } } const edgeList& edges = eMesh.edges(); edgeList newEdges(edges.size()); forAll(edges, edgeI) { const edge& e = edges[edgeI]; newEdges[edgeI] = edge ( oldToNew[e[0]], oldToNew[e[1]] ); } // Construct an extendedEdgeMesh with // - all points on more than 2 edges : mixed feature points // - all edges : external edges extendedEdgeMesh eeMesh ( newPoints, // pts newEdges, // eds 0, // (point) concaveStart 0, // (point) mixedStart nFeatures, // (point) nonFeatureStart edges.size(), // (edge) internalStart edges.size(), // (edge) flatStart edges.size(), // (edge) openStart edges.size(), // (edge) multipleStart vectorField(0), // normals List(0),// normalVolumeTypes vectorField(0), // edgeDirections labelListList(0), // normalDirections labelListList(0), // edgeNormals labelListList(0), // featurePointNormals labelListList(0), // featurePointEdges identity(newEdges.size()) // regionEdges ); //Info<< "Constructed extendedFeatureEdgeMesh " << featObj.name() // << nl << incrIndent; //eeMesh.writeStats(Info); //Info<< decrIndent << endl; set(featI, new extendedFeatureEdgeMesh(featObj, eeMesh)); } const extendedEdgeMesh& eMesh = operator[](featI); if (dict.found("levels")) { List> distLevels(dict.lookup("levels")); if (dict.size() < 1) { FatalErrorInFunction << " : levels should be at least size 1" << endl << "levels : " << dict.lookup("levels") << exit(FatalError); } distances_[featI].setSize(distLevels.size()); levels_[featI].setSize(distLevels.size()); forAll(distLevels, j) { distances_[featI][j] = distLevels[j].first(); levels_[featI][j] = distLevels[j].second(); if (levels_[featI][j] < 0) { FatalErrorInFunction << "Feature " << featFileName << " has illegal refinement level " << levels_[featI][j] << exit(FatalError); } // Check in incremental order if (j > 0) { if ( (distances_[featI][j] <= distances_[featI][j-1]) || (levels_[featI][j] > levels_[featI][j-1]) ) { FatalErrorInFunction << " : Refinement should be specified in order" << " of increasing distance" << " (and decreasing refinement level)." << endl << "Distance:" << distances_[featI][j] << " refinementLevel:" << levels_[featI][j] << exit(FatalError); } } } } else { // Look up 'level' for single level levels_[featI] = labelList ( 1, meshRefinement::get