/*---------------------------------------------------------------------------*\
========= |
\\ / 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 "patchProbes.H"
#include "volFields.H"
#include "IOmanip.H"
#include "mappedPatchBase.H"
#include "treeBoundBox.H"
#include "treeDataFace.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(patchProbes, 0);
addToRunTimeSelectionTable
(
functionObject,
patchProbes,
dictionary
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::patchProbes::findElements(const fvMesh& mesh)
{
(void)mesh.tetBasePtIs();
const polyBoundaryMesh& bm = mesh.boundaryMesh();
// All the info for nearest. Construct to miss
List nearest(this->size());
const labelList patchIDs(bm.patchSet(patchNames_).sortedToc());
label nFaces = 0;
forAll(patchIDs, i)
{
nFaces += bm[patchIDs[i]].size();
}
if (nFaces > 0)
{
// Collect mesh faces and bounding box
labelList bndFaces(nFaces);
treeBoundBox overallBb;
nFaces = 0;
forAll(patchIDs, i)
{
const polyPatch& pp = bm[patchIDs[i]];
forAll(pp, i)
{
bndFaces[nFaces++] = pp.start()+i;
const face& f = pp[i];
// Without reduction.
overallBb.add(pp.points(), f);
}
}
Random rndGen(123456);
overallBb.inflate(rndGen, 1e-4, ROOTVSMALL);
const indexedOctree boundaryTree
(
treeDataFace(mesh, bndFaces), // patch faces only
overallBb, // overall search domain
8, // maxLevel
10, // leafsize
3.0 // duplicity
);
forAll(probeLocations(), probei)
{
const auto& treeData = boundaryTree.shapes();
const point sample = probeLocations()[probei];
pointIndexHit info = boundaryTree.findNearest
(
sample,
Foam::sqr(boundaryTree.bb().mag())
);
if (!info.hit())
{
info = boundaryTree.findNearest(sample, Foam::sqr(GREAT));
}
const label facei = treeData.objectIndex(info.index());
const label patchi = bm.whichPatch(facei);
if (isA(bm[patchi]))
{
WarningInFunction
<< " The sample point: " << sample
<< " belongs to " << patchi
<< " which is an empty patch. This is not permitted. "
<< " This sample will not be included "
<< endl;
}
else if (info.hit())
{
// Note: do we store the face centre or the actual nearest?
// We interpolate using the faceI only though (no
// interpolation) so it does not actually matter much, just for
// the location written to the header.
//const point& facePt = mesh.faceCentres()[faceI];
const point& facePt = info.point();
mappedPatchBase::nearInfo sampleInfo;
sampleInfo.first() = pointIndexHit(true, facePt, facei);
sampleInfo.second().first() = facePt.distSqr(sample);
sampleInfo.second().second() = Pstream::myProcNo();
nearest[probei] = sampleInfo;
}
}
}
// Find nearest - globally consistent
Pstream::listCombineReduce(nearest, mappedPatchBase::nearestEqOp());
oldPoints_.resize(this->size());
// Update actual probe locations and store old ones
forAll(nearest, samplei)
{
oldPoints_[samplei] = operator[](samplei);
operator[](samplei) = nearest[samplei].first().point();
}
if (debug)
{
InfoInFunction << nl;
forAll(nearest, samplei)
{
label proci = nearest[samplei].second().second();
label locali = nearest[samplei].first().index();
Info<< " " << samplei << " coord:"<< operator[](samplei)
<< " found on processor:" << proci
<< " in local face:" << locali
<< " with location:" << nearest[samplei].first().point()
<< endl;
}
}
// Extract any local faces to sample:
// - operator[] : actual point to sample (=nearest point on patch)
// - oldPoints_ : original provided point (might be anywhere in the mesh)
// - elementList_ : cells, not used
// - faceList_ : faces (now patch faces)
// - patchIDList_ : patch corresponding to faceList
// - processor_ : processor
elementList_.resize_nocopy(nearest.size());
elementList_ = -1;
faceList_.resize_nocopy(nearest.size());
faceList_ = -1;
processor_.resize_nocopy(nearest.size());
processor_ = -1;
patchIDList_.resize_nocopy(nearest.size());
patchIDList_ = -1;
forAll(nearest, sampleI)
{
processor_[sampleI] = nearest[sampleI].second().second();
if (nearest[sampleI].second().second() == Pstream::myProcNo())
{
// Store the face to sample
faceList_[sampleI] = nearest[sampleI].first().index();
const label facei = faceList_[sampleI];
if (facei != -1)
{
processor_[sampleI] = Pstream::myProcNo();
patchIDList_[sampleI] = bm.whichPatch(facei);
}
}
reduce(processor_[sampleI], maxOp