distanceSurfaceFilter.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2020 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "distanceSurface.H"
29 #include "regionSplit.H"
30 #include "syncTools.H"
31 #include "vtkSurfaceWriter.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
36 (
37  bitSet& ignoreCells,
38  const isoSurfaceBase& isoCutter
39 ) const
40 {
41  // With the cell/point distance fields we can take a second pass at
42  // pre-filtering.
43  // This duplicates how cut detection is determined in the cell/topo
44  // algorithms but is fairly inexpensive (creates no geometry)
45 
46  bool changed = false;
47 
48  for (label celli = 0; celli < mesh_.nCells(); ++celli)
49  {
50  if (ignoreCells.test(celli))
51  {
52  continue;
53  }
54 
55  auto cut = isoCutter.getCellCutType(celli);
56  if (!(cut & isoSurfaceBase::ANYCUT))
57  {
58  ignoreCells.set(celli);
59  changed = true;
60  }
61  }
62 
63  return changed;
64 }
65 
66 
68 (
69  const bitSet& ignoreCells
70 ) const
71 {
72  // Prepare for region split
73 
74  bitSet blockedFaces(mesh_.nFaces());
75 
76  const labelList& faceOwn = mesh_.faceOwner();
77  const labelList& faceNei = mesh_.faceNeighbour();
78 
79  // Could be more efficient
80  for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
81  {
82  // If only one cell is blocked, the face corresponds
83  // to an exposed subMesh face
84 
85  if
86  (
87  ignoreCells.test(faceOwn[facei])
88  != ignoreCells.test(faceNei[facei])
89  )
90  {
91  blockedFaces.set(facei);
92  }
93  }
94 
95  for (const polyPatch& patch : mesh_.boundaryMesh())
96  {
97  if (!patch.coupled())
98  {
99  continue;
100  }
101 
102  forAll(patch, patchFacei)
103  {
104  const label facei = patch.start() + patchFacei;
105  if (ignoreCells.test(faceOwn[facei]))
106  {
107  blockedFaces.set(facei);
108  }
109  }
110  }
111 
112  syncTools::syncFaceList(mesh_, blockedFaces, xorEqOp<unsigned int>());
113 
114  return blockedFaces;
115 }
116 
117 
119 (
120  bitSet& ignoreCells
121 ) const
122 {
123  // For region split
124  bitSet blockedFaces(filterPrepareRegionSplit(ignoreCells));
125 
126  // Split region
127  regionSplit rs(mesh_, blockedFaces);
128  blockedFaces.clearStorage();
129 
130  const labelList& regionColour = rs;
131 
132  // Identical number of regions on all processors
133  labelList nCutsPerRegion(rs.nRegions(), Zero);
134 
135  // Count cut cells (ie, unblocked)
136  forAll(regionColour, celli)
137  {
138  if (!ignoreCells.test(celli))
139  {
140  ++nCutsPerRegion[regionColour[celli]];
141  }
142  }
143 
144  // Sum totals from all processors
145  Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>());
146 
147 
148  // Define which regions to keep
149  boolList keepRegion(rs.nRegions(), false);
150 
151  if (Pstream::master())
152  {
153  const label largest = findMax(nCutsPerRegion);
154 
155  if (largest == -1)
156  {
157  // Should not happen
158  keepRegion = true;
159  }
160  else
161  {
162  keepRegion[largest] = true;
163  }
164 
165  if (debug)
166  {
167  Info<< "Had " << sum(nCutsPerRegion) << " cuts, in "
168  << nCutsPerRegion.size() << " regions, largest is "
169  << largest << ": " << flatOutput(nCutsPerRegion) << nl;
170  }
171  }
172 
173  Pstream::scatter(keepRegion);
174 
175  forAll(regionColour, celli)
176  {
177  if (!keepRegion.test(regionColour[celli]))
178  {
179  ignoreCells.set(celli);
180  }
181  }
182 }
183 
184 
186 (
187  bitSet& ignoreCells
188 ) const
189 {
190  if (nearestPoints_.empty())
191  {
193  << "Ignoring nearestPoints - no points provided" << nl
194  << endl;
195  return;
196  }
197 
198  // For region split
199  bitSet blockedFaces(filterPrepareRegionSplit(ignoreCells));
200 
201  // Split region
202  regionSplit rs(mesh_, blockedFaces);
203  blockedFaces.clearStorage();
204 
205  const labelList& regionColour = rs;
206 
207  const pointField& cc = mesh_.cellCentres();
208  const pointField& nearPts = nearestPoints_;
209 
210  // The magSqr distance and region
211  typedef Tuple2<scalar, label> nearInfo;
212  List<nearInfo> nearest(nearPts.size(), nearInfo(GREAT, -1));
213 
214  // Also collect cuts per region, may be useful for rejecting
215  // small regions. Code as per filterKeepLargestRegion
216  labelList nCutsPerRegion(rs.nRegions(), Zero);
217 
218  forAll(cc, celli)
219  {
220  if (ignoreCells.test(celli))
221  {
222  continue;
223  }
224 
225  const point& pt = cc[celli];
226  const label regioni = regionColour[celli];
227 
228  ++nCutsPerRegion[regioni];
229 
230  label pointi = 0;
231  for (nearInfo& near : nearest)
232  {
233  const scalar distSqr = magSqr(nearPts[pointi] - pt);
234  ++pointi;
235 
236  if (distSqr < near.first())
237  {
238  near.first() = distSqr;
239  near.second() = regioni;
240  }
241  }
242  }
243 
244  // Sum totals from all processors
245  Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>());
246 
247  // Get nearest
248  Pstream::listCombineGather(nearest, minFirstEqOp<scalar>());
249 
250 
251  // Define which regions to keep
252 
253  boolList keepRegion(rs.nRegions(), false);
254 
255  if (Pstream::master())
256  {
257  const label largest = findMax(nCutsPerRegion);
258 
259  for (const nearInfo& near : nearest)
260  {
261  const scalar distSqr = near.first();
262  const label regioni = near.second();
263 
264  if (regioni != -1 && distSqr < maxDistanceSqr_)
265  {
266  keepRegion[regioni] = true;
267  }
268  }
269 
270  if (debug)
271  {
272  Info<< "Had " << sum(nCutsPerRegion) << " cuts, in "
273  << nCutsPerRegion.size() << " regions, largest is "
274  << largest << ": " << flatOutput(nCutsPerRegion) << nl;
275 
276  Info<< "nearestPoints (max distance = "
277  << sqrt(maxDistanceSqr_) << ")" << nl;
278 
279  forAll(nearPts, pointi)
280  {
281  const scalar dist = sqrt(nearest[pointi].first());
282  const label regioni = nearest[pointi].second();
283 
284  Info<< " " << nearPts[pointi] << " region "
285  << regioni << " distance "
286  << dist;
287 
288  if (!keepRegion.test(regioni))
289  {
290  Info<< " too far";
291  }
292  Info<< nl;
293  }
294  }
295  }
296 
297  Pstream::scatter(keepRegion);
298 
299  forAll(regionColour, celli)
300  {
301  if (!keepRegion.test(regionColour[celli]))
302  {
303  ignoreCells.set(celli);
304  }
305  }
306 }
307 
308 
310 {
311  const searchableSurface& geom = geometryPtr_();
312 
313  // Filtering for faces
314  const pointField& fc = surface_.faceCentres();
315 
316  bitSet faceSelection(fc.size());
317  label nTrimmed = 0;
318 
319 
320  // For each face
321  scalarField faceDistance(fc.size(), GREAT);
322  scalarField faceNormalDistance; // Debugging only
323  {
324  List<pointIndexHit> nearest;
325  geom.findNearest
326  (
327  fc,
328  // Use initialized field (GREAT) to limit search too
329  faceDistance,
330  nearest
331  );
332  calcAbsoluteDistance(faceDistance, fc, nearest);
333 
334  // Heavier debugging
335  if (debug & 4)
336  {
337  vectorField norms;
338  geom.getNormal(nearest, norms);
339 
340  faceNormalDistance.resize(fc.size());
341 
342  forAll(nearest, i)
343  {
344  const vector diff(fc[i] - nearest[i].point());
345 
346  faceNormalDistance[i] = Foam::mag((diff & norms[i]));
347  }
348  }
349  }
350 
351  // Note
352  // Proximity checks using the face points (nearest hit) to establish
353  // a length scale are too fragile. Can easily have stretched faces
354  // where the centre is less than say 0.3-0.5 of the centre-point distance
355  // but they are still outside.
356 
357  // Using the absolute proximity of the face centres is more robust.
358 
359 
360  // Consider the absolute proximity of the face centres
361  forAll(faceDistance, facei)
362  {
363  if (faceDistance[facei] <= absProximity_)
364  {
365  faceSelection.set(facei);
366  }
367  else
368  {
369  ++nTrimmed;
370 
371  if (debug & 2)
372  {
373  Pout<< "trim reject: "
374  << faceDistance[facei] << nl;
375  }
376  }
377  }
378 
379 
380  // Heavier debugging
381  if (debug & 4)
382  {
383  labelField faceFilterStatus(faceSelection.size(), Zero);
384 
385  for (const label facei : faceSelection)
386  {
387  faceFilterStatus[facei] = 1;
388  }
389 
390  const fileName outputName(surfaceName() + "-proximity-filter");
391 
392  Info<< "Writing debug surface: " << outputName << nl;
393 
395  (
396  surface_.points(),
397  surface_, // faces
398  outputName
399  );
400 
401  writer.write("absolute-distance", faceDistance);
402  writer.write("normal-distance", faceNormalDistance);
403  writer.write("filter-state", faceFilterStatus);
404  }
405 
406 
407  if (returnReduce(nTrimmed, sumOp<label>()) != 0)
408  {
409  labelList pointMap, faceMap;
410  meshedSurface filtered
411  (
412  surface_.subsetMesh(faceSelection, pointMap, faceMap)
413  );
414  surface_.transfer(filtered);
415 
416  meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
417  }
418 }
419 
420 
421 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeTopological.C:94
Foam::isoSurfaceBase
Low-level components common to various iso-surface algorithms.
Definition: isoSurfaceBase.H:66
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::searchableSurface::getNormal
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const =0
From a set of points and indices get the normal.
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::xorEqOp
Definition: ops.H:87
Foam::isoSurfaceBase::getCellCutType
cutType getCellCutType(const label celli) const
Definition: isoSurfaceBase.C:248
Foam::writer::write
virtual void write(const coordSet &, const wordList &, const List< const Field< Type > * > &, Ostream &) const =0
General entry point for writing.
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::distanceSurface::filterKeepNearestRegions
void filterKeepNearestRegions(bitSet &ignoreCells) const
Keep region(s) closest to the nearest points.
Definition: distanceSurfaceFilter.C:186
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::bitSet::test
bool test(const label pos) const
Test value at specified position, never auto-vivify entries.
Definition: bitSetI.H:520
syncTools.H
Foam::sumOp
Definition: ops.H:213
Foam::faceSelection
Face selection method for createBaffles.
Definition: faceSelection.H:58
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::distanceSurface::refineBlockedCells
bool refineBlockedCells(bitSet &ignoreCells, const isoSurfaceBase &isoContext) const
Re-filter the blocked cells based on the anticipated cuts.
Definition: distanceSurfaceFilter.C:36
Foam::diff
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:378
Foam::surfaceWriters::vtkWriter
A surfaceWriter for VTK legacy (.vtk) or XML (.vtp) format.
Definition: vtkSurfaceWriter.H:124
Foam::MeshedSurface::transfer
void transfer(pointField &pointLst, List< Face > &faceLst)
Transfer the components.
Definition: MeshedSurface.C:1281
Foam::Field< vector >
writer
vtk::internalMeshWriter writer(topoMesh, topoCells, writeOpts, runTime.path()/"blockTopology")
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::searchableSurface
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
Definition: searchableSurface.H:69
regionSplit.H
Foam::minFirstEqOp
Assign tuple-like container to use the one with the smaller value of first.
Definition: Tuple2.H:226
Foam::regionSplit
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:140
Foam::regionSplit::nRegions
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:294
Foam::distanceSurface::surfaceName
const word & surfaceName() const
The name of the underlying searchableSurface.
Definition: distanceSurface.H:383
cut
Patchify triangles based on orientation w.r.t other (triangulated or triangulatable) surfaces.
Foam::writer
Base class for graphics format writing. Entry points are.
Definition: writer.H:80
Foam::searchableSurface::findNearest
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const =0
distanceSurface.H
Foam::flatOutput
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:217
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::Vector< scalar >
Foam::findMax
label findMax(const ListType &input, label start=0)
vtkSurfaceWriter.H
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:325
Foam::PackedList::clearStorage
void clearStorage()
Clear the list and delete storage.
Definition: PackedListI.H:510
Foam::distanceSurface::filterKeepLargestRegion
void filterKeepLargestRegion(bitSet &ignoreCells) const
Keep region with the most cuts (after region split)
Definition: distanceSurfaceFilter.C:119
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::plusEqOp
Definition: ops.H:72
Foam::distanceSurface::filterPrepareRegionSplit
bitSet filterPrepareRegionSplit(const bitSet &ignoreCells) const
Prepare blockedFaces for region split.
Definition: distanceSurfaceFilter.C:68
Foam::Tuple2
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition: Tuple2.H:57
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::distanceSurface::filterByProximity
void filterByProximity()
Adjust extracted iso-surface to remove far faces.
Definition: distanceSurfaceFilter.C:309
Foam::MeshedSurface< face >
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303
Foam::MeshedSurface::subsetMesh
MeshedSurface subsetMesh(const UList< bool > &include, labelList &pointMap, labelList &faceMap) const
Return a new surface subsetted on the selected faces.
Definition: MeshedSurface.C:1182