/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2024-2025 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 "pointSmoother.H" #include "pointConstraints.H" #include "polyMeshTools.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(pointSmoother, 0); defineRunTimeSelectionTable(pointSmoother, dictionary); } // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // bool Foam::pointSmoother::isInternalOrProcessorFace(const label faceI) const { if (mesh().isInternalFace(faceI)) { return true; } if ( processorPatchIDs_ [ mesh().boundaryMesh().patchID() [ faceI - mesh().nInternalFaces() ] ] ) { return true; } return false; } Foam::bitSet Foam::pointSmoother::pointsToMove ( const labelList& facesToMove, const bool moveInternalFaces ) const { bitSet marker(mesh().nPoints()); for (const label facei : facesToMove) { if (moveInternalFaces || !isInternalOrProcessorFace(facei)) { marker.set(mesh().faces()[facei]); } } syncTools::syncPointList ( mesh(), marker, orEqOp(), 0U ); return marker; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::pointSmoother::pointSmoother ( const polyMesh& mesh, const dictionary& dict ) : mesh_(mesh) { for (const auto& pp : mesh.boundaryMesh()) { if (isA(pp)) { processorPatchIDs_.insert(pp.index()); } } } // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * // Foam::autoPtr Foam::pointSmoother::New ( const word& pointSmootherType, const polyMesh& mesh, const dictionary& dict ) { Info<< "Selecting pointSmoother type " << pointSmootherType << endl; auto* ctorPtr = dictionaryConstructorTable(pointSmootherType); if (!ctorPtr) { FatalIOErrorInLookup ( dict, typeName, pointSmootherType, *dictionaryConstructorTablePtr_ ) << exit(FatalIOError); } return autoPtr(ctorPtr(mesh, dict)); } Foam::autoPtr Foam::pointSmoother::New ( const polyMesh& mesh, const dictionary& dict ) { word pointSmootherType(dict.get(typeName)); return New(pointSmootherType, mesh, dict); } // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // void Foam::pointSmoother::update ( const labelList& facesToMove, const pointField& oldPoints, const pointField& currentPoints, const pointField& faceCentres, const vectorField& faceAreas, const pointField& cellCentres, const scalarField& cellVolumes, pointVectorField& pointDisplacement, const bool correctBCs ) const { // Apply point smoothing (without boundary conditions!) calculate ( facesToMove, oldPoints, currentPoints, faceCentres, faceAreas, cellCentres, cellVolumes, pointDisplacement.ref() ); // Note: do not want to apply boundary conditions whilst smoothing so // disable for now //// Take over boundary values //for (auto& ppf : pointDisplacement.boundaryFieldRef()) //{ // ppf.operator==(ppf.patchInternalField()); //} if (correctBCs) { // Apply (multi-)patch constraints pointConstraints::New ( pointDisplacement().mesh() ).constrainDisplacement(pointDisplacement); } } Foam::tmp Foam::pointSmoother::faceQuality ( const pointField& points, const pointField& faceCentres, const vectorField& faceAreas, const pointField& cellCentres, const scalarField& cellVolumes ) const { // See e.g. // - src/functionObjects/field/stabilityBlendingFactor/ // stabilityBlendingFactor.H // - maybe add function to motionSmootherCheck to return value instead // of yes/no for invalid? // - for now just look at non-ortho tmp tortho ( polyMeshTools::faceOrthogonality ( mesh(), faceAreas, cellCentres ) ); // tortho.ref().clamp_min(0); return tortho; } Foam::tmp Foam::pointSmoother::cellQuality ( const pointField& points, const pointField& faceCentres, const vectorField& faceAreas, const pointField& cellCentres, const scalarField& cellVolumes ) const { // Get face-based non-ortho tmp tfaceOrtho ( faceQuality ( points, faceCentres, faceAreas, cellCentres, cellVolumes ) ); const auto& faceOrtho = tfaceOrtho(); // Min over cells auto tortho = tmp::New(mesh().nCells(), GREAT); auto& ortho = tortho.ref(); const auto& own = mesh().faceOwner(); const auto& nei = mesh().faceNeighbour(); forAll(own, facei) { auto& o = ortho[own[facei]]; o = min(o, faceOrtho[facei]); } for (label facei = 0; facei < mesh().nInternalFaces(); facei++) { auto& o = ortho[nei[facei]]; o = min(o, faceOrtho[facei]); } return tortho; } // ************************************************************************* //