/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-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 "sampledCuttingPlane.H"
#include "dictionary.H"
#include "fvMesh.H"
#include "volFields.H"
#include "volPointInterpolation.H"
#include "cartesianCS.H"
#include "addToRunTimeSelectionTable.H"
#include "PtrList.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(sampledCuttingPlane, 0);
addNamedToRunTimeSelectionTable
(
sampledSurface,
sampledCuttingPlane,
word,
cuttingPlane
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::plane Foam::sampledCuttingPlane::definePlane
(
const polyMesh& mesh,
const dictionary& dict
)
{
plane pln(dict);
// Optional (cartesian) coordinate transform.
// - with registry to allow lookup from globally defined systems
auto csysPtr = coordinateSystem::NewIfPresent(mesh, dict);
if (!csysPtr)
{
csysPtr = coordinateSystem::NewIfPresent(dict, "transform");
}
// Make plane relative to the Cartesian coordinate system
if (csysPtr)
{
coordSystem::cartesian cs(csysPtr());
const point orig = cs.globalPosition(pln.origin());
const vector norm = cs.globalVector(pln.normal());
DebugInfo
<< "plane "
<< " origin:" << pln.origin()
<< " normal:" << pln.normal()
<< " =>"
<< " origin:" << orig << " normal:" << norm
<< endl;
// Reassign the plane
pln = plane(orig, norm);
}
return pln;
}
void Foam::sampledCuttingPlane::checkBoundsIntersection
(
const plane& pln,
const boundBox& meshBb
) const
{
// Verify specified bounding box
const boundBox& clipBb = isoParams_.getClipBounds();
if (clipBb.good())
{
// Bounding box does not overlap with (global) mesh!
if (!clipBb.overlaps(meshBb))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Bounds " << clipBb
<< " do not overlap the mesh bounding box " << meshBb
<< nl << endl;
}
// Plane does not intersect the bounding box
if (!clipBb.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the bounds "
<< clipBb
<< nl << endl;
}
}
// Plane does not intersect the (global) mesh!
if (!meshBb.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the mesh bounds "
<< meshBb
<< nl << endl;
}
}
void Foam::sampledCuttingPlane::setDistanceFields(const plane& pln)
{
volScalarField& cellDistance = cellDistancePtr_();
// Get mesh from volField,
// so automatically submesh or baseMesh
const fvMesh& mesh = cellDistance.mesh();
// Distance to cell centres
// ~~~~~~~~~~~~~~~~~~~~~~~~
// Internal field
{
const auto& cc = mesh.cellCentres();
scalarField& fld = cellDistance.primitiveFieldRef();
forAll(cc, i)
{
fld[i] = pln.signedDistance(cc[i]);
}
}
// Patch fields
{
volScalarField::Boundary& cellDistanceBf =
cellDistance.boundaryFieldRef();
forAll(cellDistanceBf, patchi)
{
if
(
isA
(
cellDistanceBf[patchi]
)
)
{
cellDistanceBf.set
(
patchi,
new calculatedFvPatchScalarField
(
mesh.boundary()[patchi],
cellDistance
)
);
const polyPatch& pp = mesh.boundary()[patchi].patch();
pointField::subField cc = pp.patchSlice(mesh.faceCentres());
fvPatchScalarField& fld = cellDistanceBf[patchi];
fld.setSize(pp.size());
forAll(fld, i)
{
fld[i] = pln.signedDistance(cc[i]);
}
}
else
{
// Other side cell centres?
const pointField& cc = mesh.C().boundaryField()[patchi];
fvPatchScalarField& fld = cellDistanceBf[patchi];
forAll(fld, i)
{
fld[i] = pln.signedDistance(cc[i]);
}
}
}
}
// On processor patches the mesh.C() will already be the cell centre
// on the opposite side so no need to swap cellDistance.
// Distance to points
pointDistance_.resize(mesh.nPoints());
{
const pointField& pts = mesh.points();
forAll(pointDistance_, i)
{
pointDistance_[i] = pln.signedDistance(pts[i]);
}
}
}
void Foam::sampledCuttingPlane::combineSurfaces
(
PtrList& isoSurfPtrs
)
{
isoSurfacePtr_.reset(nullptr);
// Already checked previously for ALGO_POINT, but do it again
// - ALGO_POINT still needs fields (for interpolate)
// The others can do straight transfer
if
(
isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT
&& isoSurfPtrs.size() == 1
)
{
// Shift ownership from list to autoPtr
isoSurfacePtr_.reset(isoSurfPtrs.release(0));
}
else if (isoSurfPtrs.size() == 1)
{
autoPtr ptr(isoSurfPtrs.release(0));
auto& surf = *ptr;
surface_.transfer(static_cast(surf));
meshCells_.transfer(surf.meshCells());
}
else
{
// Combine faces with point offsets
//
// Note: use points().size() from surface, not nPoints()
// since there may be uncompacted dangling nodes
label nFaces = 0, nPoints = 0;
for (const auto& surf : isoSurfPtrs)
{
nFaces += surf.size();
nPoints += surf.points().size();
}
faceList newFaces(nFaces);
pointField newPoints(nPoints);
meshCells_.resize(nFaces);
surfZoneList newZones(isoSurfPtrs.size());
nFaces = 0;
nPoints = 0;
forAll(isoSurfPtrs, surfi)
{
autoPtr ptr(isoSurfPtrs.release(surfi));
auto& surf = *ptr;
SubList subFaces(newFaces, surf.size(), nFaces);
SubList subPoints(newPoints, surf.points().size(), nPoints);
SubList