/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2019-2020 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 "isoSurfaceBase.H" #include "polyMesh.H" #include "tetMatcher.H" #include "cyclicACMIPolyPatch.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #include "isoSurfaceBaseMethods.H" defineIsoSurfaceInterpolateMethods(Foam::isoSurfaceBase); // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // namespace Foam { // Test face for edge cuts inline static bool isFaceCut ( const scalar isoval, const scalarField& pointValues, const labelUList& indices ) { auto iter = indices.cbegin(); const auto last = indices.cend(); // if (iter == last) return false; // ie, indices.empty() const bool aLower = (pointValues[*iter] < isoval); ++iter; while (iter != last) { if (aLower != (pointValues[*iter] < isoval)) { return true; } ++iter; } return false; } } // End namespace Foam // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::isoSurfaceBase::isoSurfaceBase ( const polyMesh& mesh, const scalarField& cellValues, const scalarField& pointValues, const scalar iso, const isoSurfaceParams& params ) : meshedSurface(), isoSurfaceParams(params), mesh_(mesh), cVals_(cellValues), pVals_(pointValues), iso_(iso), ignoreBoundaryFaces_(), meshCells_() {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::isoSurfaceBase::ignoreCyclics() { // Determine boundary pyramids to ignore (originating from ACMI faces) // Maybe needs to be optional argument or more general detect colocated // faces. for (const polyPatch& pp : mesh_.boundaryMesh()) { if (isA(pp)) { ignoreBoundaryFaces_.set(labelRange(pp.offset(), pp.size())); } } } Foam::label Foam::isoSurfaceBase::countCutType ( const UList& cuts, const uint8_t maskValue ) { label count = 0; for (const cutType cut : cuts) { if (maskValue ? (cut & maskValue) != 0 : !cut) { ++count; } } return count; } void Foam::isoSurfaceBase::resetCuts(UList& cuts) { for (cutType& cut : cuts) { if (cut != cutType::BLOCKED) { cut = cutType::UNVISITED; } } } Foam::label Foam::isoSurfaceBase::blockCells ( UList& cuts, const bitSet& ignoreCells ) const { label count = 0; for (const label celli : ignoreCells) { if (celli >= cuts.size()) { break; } cuts[celli] = cutType::BLOCKED; ++count; } return count; } Foam::label Foam::isoSurfaceBase::blockCells ( UList& cuts, const boundBox& bb, const volumeType::type volType ) const { label count = 0; // Mark cells inside/outside bounding box as blocked const bool keepInside = (volType == volumeType::INSIDE); if (!keepInside && volType != volumeType::OUTSIDE) { // Could warn about invalid... } else if (bb.good()) { const pointField& cc = mesh_.cellCentres(); forAll(cuts, celli) { if ( cuts[celli] == cutType::UNVISITED && (bb.contains(cc[celli]) ? keepInside : !keepInside) ) { cuts[celli] = cutType::BLOCKED; ++count; } } } return count; } Foam::label Foam::isoSurfaceBase::calcCellCuts(List& cuts) const { // Don't consider SPHERE cuts in the total number of cells cut constexpr uint8_t realCut(cutType::CUT | cutType::TETCUT); cuts.resize(mesh_.nCells(), cutType::UNVISITED); label nCuts = 0; forAll(cuts, celli) { if (cuts[celli] == cutType::UNVISITED) { cuts[celli] = getCellCutType(celli); if ((cuts[celli] & realCut) != 0) { ++nCuts; } } } return nCuts; } Foam::isoSurfaceBase::cutType Foam::isoSurfaceBase::getFaceCutType(const label facei) const { return ( ( mesh_.isInternalFace(facei) || !ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces()) ) && isFaceCut(iso_, pVals_, mesh_.faces()[facei]) ) ? cutType::CUT : cutType::NOTCUT; } Foam::isoSurfaceBase::cutType Foam::isoSurfaceBase::getCellCutType(const label celli) const { // Tet version if (tetMatcher::test(mesh_, celli)) { for (const label facei : mesh_.cells()[celli]) { if ( !mesh_.isInternalFace(facei) && ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces()) ) { continue; } if (isFaceCut(iso_, pVals_, mesh_.faces()[facei])) { return cutType::TETCUT; } } return cutType::NOTCUT; } // Regular cell label nPyrEdges = 0; label nPyrCuts = 0; const bool cellLower = (cVals_[celli] < iso_); for (const label facei : mesh_.cells()[celli]) { if ( !mesh_.isInternalFace(facei) && ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces()) ) { continue; } const face& f = mesh_.faces()[facei]; // Count pyramid edges cut for (const label pointi : f) { ++nPyrEdges; if (cellLower != (pVals_[pointi] < iso_)) { ++nPyrCuts; } } } if (nPyrCuts == 0) { return cutType::NOTCUT; } // If all pyramid edges are cut (no outside faces), // it is a sphere cut return (nPyrCuts == nPyrEdges) ? cutType::SPHERE : cutType::CUT; } // ************************************************************************* //