1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "sampledTriSurfaceMesh.H"
27 #include "meshSearch.H"
29 #include "globalIndex.H"
30 #include "treeDataPolyMeshCell.H"
31 #include "treeDataFace.H"
32 #include "meshTools.H"
34 #include "addToRunTimeSelectionTable.H"
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(sampledTriSurfaceMesh, 0);
41 addToRunTimeSelectionTable
44 sampledTriSurfaceMesh,
49 const char* NamedEnum<sampledTriSurfaceMesh::samplingSource, 2>::names[] =
55 const NamedEnum<sampledTriSurfaceMesh::samplingSource, 2>
56 sampledTriSurfaceMesh::samplingSourceNames_;
59 //- Private class for finding nearest
63 typedef Tuple2<scalar, label> nearInfo;
70 void operator()(nearInfo& x, const nearInfo& y) const
72 if (y.first() < x.first())
81 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
83 const Foam::indexedOctree<Foam::treeDataFace>&
84 Foam::sampledTriSurfaceMesh::nonCoupledboundaryTree() const
86 // Variant of meshSearch::boundaryTree() that only does non-coupled
89 if (!boundaryTreePtr_.valid())
91 // all non-coupled boundary faces (not just walls)
92 const polyBoundaryMesh& patches = mesh().boundaryMesh();
94 labelList bndFaces(mesh().nFaces()-mesh().nInternalFaces());
96 forAll(patches, patchI)
98 const polyPatch& pp = patches[patchI];
103 bndFaces[bndI++] = pp.start()+i;
107 bndFaces.setSize(bndI);
110 treeBoundBox overallBb(mesh().points());
111 Random rndGen(123456);
112 overallBb = overallBb.extend(rndGen, 1E-4);
113 overallBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
114 overallBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
116 boundaryTreePtr_.reset
118 new indexedOctree<treeDataFace>
120 treeDataFace // all information needed to search faces
122 false, // do not cache bb
124 bndFaces // boundary faces only
126 overallBb, // overall search domain
134 return boundaryTreePtr_();
138 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
140 Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
143 const polyMesh& mesh,
144 const word& surfaceName,
145 const samplingSource sampleSource
148 sampledSurface(name, mesh),
154 mesh.time().constant(), // instance
155 "triSurface", // local
162 sampleSource_(sampleSource),
169 Foam::sampledTriSurfaceMesh::sampledTriSurfaceMesh
172 const polyMesh& mesh,
173 const dictionary& dict
176 sampledSurface(name, mesh, dict),
181 dict.lookup("surface"),
182 mesh.time().constant(), // instance
183 "triSurface", // local
190 sampleSource_(samplingSourceNames_[dict.lookup("source")]),
197 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
199 Foam::sampledTriSurfaceMesh::~sampledTriSurfaceMesh()
203 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
205 bool Foam::sampledTriSurfaceMesh::needsUpdate() const
211 bool Foam::sampledTriSurfaceMesh::expire()
213 // already marked as expired
219 sampledSurface::clearGeom();
220 MeshStorage::clear();
222 boundaryTreePtr_.clear();
223 sampleElements_.clear();
224 samplePoints_.clear();
231 bool Foam::sampledTriSurfaceMesh::update()
239 // Find the cells the triangles of the surface are in.
240 // Does approximation by looking at the face centres only
241 const pointField& fc = surface_.faceCentres();
243 // Mesh search engine, no triangulation of faces.
244 meshSearch meshSearcher(mesh(), false);
247 List<nearInfo> nearest(fc.size());
249 // Global numbering for cells/faces - only used to uniquely identify local
251 globalIndex globalCells
253 sampleSource_ == cells
260 nearest[i].first() = GREAT;
261 nearest[i].second() = labelMax;
264 if (sampleSource_ == cells)
266 // Search for nearest cell
268 const indexedOctree<treeDataPolyMeshCell>& cellTree =
269 meshSearcher.cellTree();
273 pointIndexHit nearInfo = cellTree.findNearest
280 nearest[triI].first() = magSqr(nearInfo.hitPoint()-fc[triI]);
281 nearest[triI].second() = globalCells.toGlobal(nearInfo.index());
287 // Search for nearest boundaryFace
289 ////- Search on all (including coupled) boundary faces
290 //const indexedOctree<treeDataFace>& bTree = meshSearcher.boundaryTree()
291 //- Search on all non-coupled boundary faces
292 const indexedOctree<treeDataFace>& bTree = nonCoupledboundaryTree();
296 pointIndexHit nearInfo = bTree.findNearest
303 nearest[triI].first() = magSqr(nearInfo.hitPoint()-fc[triI]);
304 nearest[triI].second() = globalCells.toGlobal
306 bTree.shapes().faceLabels()[nearInfo.index()]
313 // See which processor has the nearest. Mark and subset
314 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
316 Pstream::listCombineGather(nearest, nearestEqOp());
317 Pstream::listCombineScatter(nearest);
319 labelList cellOrFaceLabels(fc.size(), -1);
322 forAll(nearest, triI)
324 if (nearest[triI].second() == labelMax)
326 // Not found on any processor. How to map?
328 else if (globalCells.isLocal(nearest[triI].second()))
330 cellOrFaceLabels[triI] = globalCells.toLocal
332 nearest[triI].second()
341 Pout<< "Local out of faces:" << cellOrFaceLabels.size()
342 << " keeping:" << nFound << endl;
345 // Now subset the surface. Do not use triSurface::subsetMesh since requires
346 // original surface to be in compact numbering.
348 const triSurface& s = surface_;
350 // Compact to original triangle
351 labelList faceMap(s.size());
352 // Compact to original points
353 labelList pointMap(s.points().size());
354 // From original point to compact points
355 labelList reversePointMap(s.points().size(), -1);
363 if (cellOrFaceLabels[faceI] != -1)
365 faceMap[newFaceI++] = faceI;
367 const triSurface::FaceType& f = s[faceI];
370 if (reversePointMap[f[fp]] == -1)
372 pointMap[newPointI] = f[fp];
373 reversePointMap[f[fp]] = newPointI++;
378 faceMap.setSize(newFaceI);
379 pointMap.setSize(newPointI);
383 // Subset cellOrFaceLabels
384 cellOrFaceLabels = UIndirectList<label>(cellOrFaceLabels, faceMap)();
386 // Store any face per point (without using pointFaces())
387 labelList pointToFace(pointMap.size());
389 // Create faces and points for subsetted surface
390 faceList& faces = this->storedFaces();
391 faces.setSize(faceMap.size());
394 const triFace& f = s[faceMap[i]];
397 reversePointMap[f[0]],
398 reversePointMap[f[1]],
399 reversePointMap[f[2]]
401 faces[i] = newF.triFaceFace();
405 pointToFace[newF[fp]] = i;
409 this->storedPoints() = pointField(s.points(), pointMap);
419 // Collect the samplePoints and sampleElements
420 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422 if (sampledSurface::interpolate())
424 samplePoints_.setSize(pointMap.size());
425 sampleElements_.setSize(pointMap.size(), -1);
427 if (sampleSource_ == cells)
429 // samplePoints_ : per surface point a location inside the cell
430 // sampleElements_ : per surface point the cell
432 forAll(points(), pointI)
434 const point& pt = points()[pointI];
435 label cellI = cellOrFaceLabels[pointToFace[pointI]];
436 sampleElements_[pointI] = cellI;
438 // Check if point inside cell
439 if (mesh().pointInCell(pt, sampleElements_[pointI]))
441 samplePoints_[pointI] = pt;
445 // Find nearest point on faces of cell
446 const cell& cFaces = mesh().cells()[cellI];
448 scalar minDistSqr = VGREAT;
452 const face& f = mesh().faces()[cFaces[i]];
453 pointHit info = f.nearestPoint(pt, mesh().points());
454 if (info.distance() < minDistSqr)
456 minDistSqr = info.distance();
457 samplePoints_[pointI] = info.rawPoint();
465 // samplePoints_ : per surface point a location on the boundary
466 // sampleElements_ : per surface point the boundary face containing
469 forAll(points(), pointI)
471 const point& pt = points()[pointI];
472 label faceI = cellOrFaceLabels[pointToFace[pointI]];
473 sampleElements_[pointI] = faceI;
474 samplePoints_[pointI] = mesh().faces()[faceI].nearestPoint
484 // if sampleSource_ == cells:
485 // samplePoints_ : n/a
486 // sampleElements_ : per surface triangle the cell
488 // samplePoints_ : n/a
489 // sampleElements_ : per surface triangle the boundary face
490 samplePoints_.clear();
491 sampleElements_.transfer(cellOrFaceLabels);
498 OFstream str(mesh().time().path()/"surfaceToMesh.obj");
499 Info<< "Dumping correspondence from local surface (points or faces)"
500 << " to mesh (cells or faces) to " << str.name() << endl;
503 if (sampledSurface::interpolate())
505 if (sampleSource_ == cells)
507 forAll(samplePoints_, pointI)
509 meshTools::writeOBJ(str, points()[pointI]);
512 meshTools::writeOBJ(str, samplePoints_[pointI]);
515 label cellI = sampleElements_[pointI];
516 meshTools::writeOBJ(str, mesh().cellCentres()[cellI]);
518 str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI
524 forAll(samplePoints_, pointI)
526 meshTools::writeOBJ(str, points()[pointI]);
529 meshTools::writeOBJ(str, samplePoints_[pointI]);
532 label faceI = sampleElements_[pointI];
533 meshTools::writeOBJ(str, mesh().faceCentres()[faceI]);
535 str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI
542 if (sampleSource_ == cells)
544 forAll(sampleElements_, triI)
546 meshTools::writeOBJ(str, faceCentres()[triI]);
549 label cellI = sampleElements_[triI];
550 meshTools::writeOBJ(str, mesh().cellCentres()[cellI]);
552 str << "l " << vertI-1 << ' ' << vertI << nl;
557 forAll(sampleElements_, triI)
559 meshTools::writeOBJ(str, faceCentres()[triI]);
562 label faceI = sampleElements_[triI];
563 meshTools::writeOBJ(str, mesh().faceCentres()[faceI]);
565 str << "l " << vertI-1 << ' ' << vertI << nl;
572 needsUpdate_ = false;
577 Foam::tmp<Foam::scalarField> Foam::sampledTriSurfaceMesh::sample
579 const volScalarField& vField
582 return sampleField(vField);
586 Foam::tmp<Foam::vectorField> Foam::sampledTriSurfaceMesh::sample
588 const volVectorField& vField
591 return sampleField(vField);
594 Foam::tmp<Foam::sphericalTensorField> Foam::sampledTriSurfaceMesh::sample
596 const volSphericalTensorField& vField
599 return sampleField(vField);
603 Foam::tmp<Foam::symmTensorField> Foam::sampledTriSurfaceMesh::sample
605 const volSymmTensorField& vField
608 return sampleField(vField);
612 Foam::tmp<Foam::tensorField> Foam::sampledTriSurfaceMesh::sample
614 const volTensorField& vField
617 return sampleField(vField);
621 Foam::tmp<Foam::scalarField> Foam::sampledTriSurfaceMesh::interpolate
623 const interpolation<scalar>& interpolator
626 return interpolateField(interpolator);
630 Foam::tmp<Foam::vectorField> Foam::sampledTriSurfaceMesh::interpolate
632 const interpolation<vector>& interpolator
635 return interpolateField(interpolator);
638 Foam::tmp<Foam::sphericalTensorField> Foam::sampledTriSurfaceMesh::interpolate
640 const interpolation<sphericalTensor>& interpolator
643 return interpolateField(interpolator);
647 Foam::tmp<Foam::symmTensorField> Foam::sampledTriSurfaceMesh::interpolate
649 const interpolation<symmTensor>& interpolator
652 return interpolateField(interpolator);
656 Foam::tmp<Foam::tensorField> Foam::sampledTriSurfaceMesh::interpolate
658 const interpolation<tensor>& interpolator
661 return interpolateField(interpolator);
665 void Foam::sampledTriSurfaceMesh::print(Ostream& os) const
667 os << "sampledTriSurfaceMesh: " << name() << " :"
668 << " surface:" << surface_.objectRegistry::name()
669 << " faces:" << faces().size()
670 << " points:" << points().size();
674 // ************************************************************************* //