ENH: sample on nearest cell, not cell containing triangle centre.

Much more robust. Also now works on triSurfaces with non-compact point numbering.
This commit is contained in:
mattijs
2010-03-09 18:05:30 +00:00
parent 3aed3c45be
commit 1f88dac94b
3 changed files with 146 additions and 107 deletions

View File

@ -25,11 +25,10 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "sampledTriSurfaceMesh.H" #include "sampledTriSurfaceMesh.H"
#include "dictionary.H" #include "treeDataPoint.H"
#include "polyMesh.H"
#include "polyPatch.H"
#include "volFields.H"
#include "meshSearch.H" #include "meshSearch.H"
#include "Tuple2.H"
#include "globalIndex.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
@ -44,6 +43,25 @@ namespace Foam
sampledTriSurfaceMesh, sampledTriSurfaceMesh,
word word
); );
//- Private class for finding nearest
// - global index
// - sqr(distance)
typedef Tuple2<scalar, label> nearInfo;
class nearestEqOp
{
public:
void operator()(nearInfo& x, const nearInfo& y) const
{
if (y.first() < x.first())
{
x = y;
}
}
};
} }
@ -66,13 +84,13 @@ Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
"triSurface", // local "triSurface", // local
mesh, // registry mesh, // registry
IOobject::MUST_READ, IOobject::MUST_READ,
IOobject::NO_WRITE IOobject::NO_WRITE,
false
) )
), ),
needsUpdate_(true), needsUpdate_(true),
cellLabels_(0), cellLabels_(0),
pointMap_(0), pointToFace_(0)
faceMap_(0)
{} {}
@ -93,13 +111,13 @@ Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
"triSurface", // local "triSurface", // local
mesh, // registry mesh, // registry
IOobject::MUST_READ, IOobject::MUST_READ,
IOobject::NO_WRITE IOobject::NO_WRITE,
false
) )
), ),
needsUpdate_(true), needsUpdate_(true),
cellLabels_(0), cellLabels_(0),
pointMap_(0), pointToFace_(0)
faceMap_(0)
{} {}
@ -128,8 +146,7 @@ bool Foam::sampledTriSurfaceMesh::expire()
sampledSurface::clearGeom(); sampledSurface::clearGeom();
MeshStorage::clear(); MeshStorage::clear();
cellLabels_.clear(); cellLabels_.clear();
pointMap_.clear(); pointToFace_.clear();
faceMap_.clear();
needsUpdate_ = true; needsUpdate_ = true;
return true; return true;
@ -148,93 +165,137 @@ bool Foam::sampledTriSurfaceMesh::update()
// Does approximation by looking at the face centres only // Does approximation by looking at the face centres only
const pointField& fc = surface_.faceCentres(); const pointField& fc = surface_.faceCentres();
cellLabels_.setSize(fc.size());
meshSearch meshSearcher(mesh(), false); meshSearch meshSearcher(mesh(), false);
const indexedOctree<treeDataPoint>& cellCentreTree =
meshSearcher.cellCentreTree();
// Global numbering for cells - only used to uniquely identify local cells.
globalIndex globalCells(mesh().nCells());
List<nearInfo> nearest(fc.size());
forAll(nearest, i)
{
nearest[i].first() = GREAT;
nearest[i].second() = labelMax;
}
// Search triangles using nearest on local mesh
forAll(fc, triI) forAll(fc, triI)
{ {
cellLabels_[triI] = meshSearcher.findCell pointIndexHit nearInfo = cellCentreTree.findNearest
( (
fc[triI], fc[triI],
-1, // seed sqr(GREAT)
true // use tree
); );
} if (nearInfo.hit())
boolList include(surface_.size(), true);
label nNotFound = 0;
forAll(cellLabels_, triI)
{ {
if (cellLabels_[triI] == -1) nearest[triI].first() = magSqr(nearInfo.hitPoint()-fc[triI]);
{ nearest[triI].second() = globalCells.toGlobal(nearInfo.index());
include[triI] = false;
nNotFound++;
} }
} }
label nTotalNotFound = returnReduce(nNotFound, sumOp<label>());
if (debug) // See which processor has the nearest.
Pstream::listCombineGather(nearest, nearestEqOp());
Pstream::listCombineScatter(nearest);
boolList include(surface_.size(), false);
cellLabels_.setSize(fc.size());
cellLabels_ = -1;
label nFound = 0;
forAll(nearest, triI)
{ {
Pout<< "surface:" << surface_.size() if (nearest[triI].second() == labelMax)
<< " included:" << surface_.size()-nNotFound {
<< " total not found" << nTotalNotFound << endl; // Not found on any processor. How to map?
} }
else if (globalCells.isLocal(nearest[triI].second()))
{
cellLabels_[triI] = globalCells.toLocal(nearest[triI].second());
// Add to master all triangles are outside all meshes.
{
boolList onAnyProc(surface_.size(), false);
Pstream::listCombineGather(onAnyProc, orEqOp<bool>());
if (Pstream::master())
{
label nAdded = 0;
forAll(onAnyProc, triI)
{
if (!onAnyProc[triI])
{
include[triI] = true; include[triI] = true;
nAdded++; nFound++;
} }
} }
if (debug) if (debug)
{ {
Pout<< "nAdded to master:" << nAdded << endl; Pout<< "Local out of faces:" << cellLabels_.size()
<< " keeping:" << nFound << endl;
}
// Now subset the surface. Do not use triSurface::subsetMesh since requires
// original surface to be in compact numbering.
const triSurface& s = surface_;
// Compact to original triangle
labelList faceMap(s.size());
// Compact to original points
labelList pointMap(s.points().size());
// From original point to compact points
labelList reversePointMap(s.points().size(), -1);
{
label newPointI = 0;
label newTriI = 0;
forAll(s, triI)
{
if (include[triI])
{
faceMap[newTriI++] = triI;
const labelledTri& f = s[triI];
forAll(f, fp)
{
if (reversePointMap[f[fp]] == -1)
{
pointMap[newPointI] = f[fp];
reversePointMap[f[fp]] = newPointI++;
} }
} }
} }
}
faceMap.setSize(newTriI);
pointMap.setSize(newPointI);
}
// Subset cellLabels
cellLabels_ = UIndirectList<label>(cellLabels_, faceMap)();
// Now subset the surface // Store any face per point
triSurface localSurface pointToFace_.setSize(pointMap.size());
(
surface_.subsetMesh
(
include,
pointMap_,
faceMap_
)
);
// And convert into faces. // Create faces and points for subsetted surface
faceList& faces = this->storedFaces(); faceList& faces = this->storedFaces();
faces.setSize(localSurface.size()); faces.setSize(faceMap.size());
forAll(localSurface, i) forAll(faceMap, i)
{ {
faces[i] = localSurface[i].triFaceFace(); const triFace& f = s[faceMap[i]];
triFace newF
(
reversePointMap[f[0]],
reversePointMap[f[1]],
reversePointMap[f[2]]
);
faces[i] = newF.triFaceFace();
forAll(newF, fp)
{
pointToFace_[newF[fp]] = i;
}
} }
this->storedPoints() = localSurface.points(); this->storedPoints() = pointField(s.points(), pointMap);
if (debug) if (debug)
{ {
print(Pout); print(Pout);
Pout << endl; Pout<< endl;
} }
needsUpdate_ = false; needsUpdate_ = false;

View File

@ -29,15 +29,13 @@ Description
A sampledSurface from a triSurfaceMesh. It samples on the points/triangles A sampledSurface from a triSurfaceMesh. It samples on the points/triangles
of the triSurface. of the triSurface.
It samples using the cell nearest to the triangle centre so does
not check the cell the centre is actually in ...
In parallel every processor just operates on the part of the surface In parallel every processor just operates on the part of the surface
where the face centres are inside the mesh. It is then up to the where the face centres are inside the mesh. It is then up to the
caller to stitch the partial surfaces together. caller to stitch the partial surfaces together.
No check is done for triangle centres being on multiple processors
(should never happen but truncation errors ...)
Any value on a triangle outside the mesh will be set to 0.
SourceFiles SourceFiles
sampledTriSurfaceMesh.C sampledTriSurfaceMesh.C
@ -75,14 +73,11 @@ class sampledTriSurfaceMesh
//- Track if the surface needs an update //- Track if the surface needs an update
mutable bool needsUpdate_; mutable bool needsUpdate_;
//- Local cell labels //- From local surface triangle to mesh cell.
labelList cellLabels_; labelList cellLabels_;
//- From local surface back to surface_ //- From local surface back to surface_
labelList pointMap_; labelList pointToFace_;
//- From local surface back to surface_
labelList faceMap_;
// Private Member Functions // Private Member Functions

View File

@ -36,20 +36,12 @@ Foam::sampledTriSurfaceMesh::sampleField
) const ) const
{ {
// One value per face // One value per face
tmp<Field<Type> > tvalues(new Field<Type>(faceMap_.size())); tmp<Field<Type> > tvalues(new Field<Type>(cellLabels_.size()));
Field<Type>& values = tvalues(); Field<Type>& values = tvalues();
forAll(faceMap_, i) forAll(cellLabels_, triI)
{ {
label cellI = cellLabels_[faceMap_[i]]; values[triI] = vField[cellLabels_[triI]];
if (cellI != -1)
{
values[i] = vField[cellI];
}
else
{
values[i] = pTraits<Type>::zero;
}
} }
return tvalues; return tvalues;
@ -64,24 +56,15 @@ Foam::sampledTriSurfaceMesh::interpolateField
) const ) const
{ {
// One value per vertex // One value per vertex
tmp<Field<Type> > tvalues(new Field<Type>(pointMap_.size())); tmp<Field<Type> > tvalues(new Field<Type>(pointToFace_.size()));
Field<Type>& values = tvalues(); Field<Type>& values = tvalues();
forAll(pointMap_, i) forAll(pointToFace_, pointI)
{ {
label origPointI = pointMap_[i]; label triI = pointToFace_[pointI];
label origTriI = surface_.pointFaces()[origPointI][0]; label cellI = cellLabels_[triI];
label cellI = cellLabels_[origTriI]; values[pointI] = interpolator.interpolate(points()[pointI], cellI);
if (cellI != -1)
{
values[i] = interpolator.interpolate(points()[i], cellI);
}
else
{
values[i] = pTraits<Type>::zero;
}
} }
return tvalues; return tvalues;