planeToFaceZone.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 OpenFOAM Foundation
9  Copyright (C) 2020-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "planeToFaceZone.H"
30 #include "polyMesh.H"
31 #include "faceZoneSet.H"
32 #include "indirectPrimitivePatch.H"
33 #include "PatchTools.H"
34 #include "syncTools.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(planeToFaceZone, 0);
42  addToRunTimeSelectionTable(topoSetSource, planeToFaceZone, word);
43  addToRunTimeSelectionTable(topoSetSource, planeToFaceZone, istream);
44 
45  addToRunTimeSelectionTable(topoSetFaceZoneSource, planeToFaceZone, word);
46  addToRunTimeSelectionTable(topoSetFaceZoneSource, planeToFaceZone, istream);
47 
49  (
50  topoSetFaceZoneSource,
51  planeToFaceZone,
52  word,
53  plane
54  );
56  (
57  topoSetFaceZoneSource,
58  planeToFaceZone,
59  istream,
60  plane
61  );
62 }
63 
64 
65 Foam::topoSetSource::addToUsageTable Foam::planeToFaceZone::usage_
66 (
67  planeToFaceZone::typeName,
68  "\n Usage: planeToFaceZone (px py pz) (nx ny nz) include\n\n"
69  " Select faces for which the adjacent cell centres lie on opposite "
70  " of a plane\n\n"
71 );
72 
73 
74 const Foam::Enum
75 <
77 >
78 Foam::planeToFaceZone::faceActionNames_
79 ({
80  { faceAction::ALL, "all" },
81  { faceAction::CLOSEST, "closest" },
82 });
83 
84 
85 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
86 
87 void Foam::planeToFaceZone::combine(faceZoneSet& fzSet, const bool add) const
88 {
89  // Mark all cells with centres above the plane
90  bitSet cellIsAbovePlane(mesh_.nCells());
91  forAll(mesh_.cells(), celli)
92  {
93  if (((mesh_.cellCentres()[celli] - point_) & normal_) > 0)
94  {
95  cellIsAbovePlane.set(celli);
96  }
97  }
98 
99  // Mark all faces that sit between cells above and below the plane
100  bitSet faceIsOnPlane(mesh_.nFaces());
101  forAll(mesh_.faceNeighbour(), facei)
102  {
103  if
104  (
105  cellIsAbovePlane[mesh_.faceOwner()[facei]]
106  != cellIsAbovePlane[mesh_.faceNeighbour()[facei]]
107  )
108  {
109  faceIsOnPlane.set(facei);
110  }
111  }
112  forAll(mesh_.boundaryMesh(), patchi)
113  {
114  const polyPatch& patch = mesh_.boundaryMesh()[patchi];
115  forAll(patch, patchFacei)
116  {
117  const label facei = patch.start() + patchFacei;
118  if (patch.coupled() && cellIsAbovePlane[mesh_.faceOwner()[facei]])
119  {
120  faceIsOnPlane.set(facei);
121  }
122  }
123  }
124  syncTools::syncFaceList(mesh_, faceIsOnPlane, xorEqOp<unsigned int>());
125 
126  // Convert marked faces to a list of indices
127  labelList newSetFaces(faceIsOnPlane.sortedToc());
128  faceIsOnPlane.clear();
129 
130  // If constructing a single contiguous set, remove all faces except those
131  // connected to the contiguous region closest to the specified point
132  if (option_ == faceAction::CLOSEST)
133  {
134  // Step 1: Get locally contiguous regions for the new face set and the
135  // total number of regions across all processors.
136  labelList newSetFaceRegions(newSetFaces.size(), -1);
137  label nRegions = -1;
138  {
139  // Create a patch of the set faces
140  const uindirectPrimitivePatch newSetPatch
141  (
142  UIndirectList<face>(mesh_.faces(), newSetFaces),
143  mesh_.points()
144  );
145 
146  // Get the region ID-s and store the total number of regions on
147  // each processor
148  labelList procNRegions(Pstream::nProcs(), -1);
149  procNRegions[Pstream::myProcNo()] =
151  (
152  newSetPatch,
153  bitSet(), // No border edges
154  newSetFaceRegions
155  );
156  Pstream::allGatherList(procNRegions);
157 
158  // Cumulative sum the number of regions on each processor to get an
159  // offset which makes the local region ID-s globally unique
160  labelList procRegionOffset(Pstream::nProcs(), Zero);
161  for (label proci = 1; proci < Pstream::nProcs(); ++proci)
162  {
163  procRegionOffset[proci] =
164  procRegionOffset[proci - 1]
165  + procNRegions[proci - 1];
166  }
167 
168  // Apply the offset
169  for (label& regioni : newSetFaceRegions)
170  {
171  regioni += procRegionOffset[Pstream::myProcNo()];
172  }
173 
174  // Store the total number of regions across all processors
175  nRegions = procRegionOffset.last() + procNRegions.last();
176  }
177 
178  // Step 2: Create a region map which combines regions which are
179  // connected across coupled interfaces
180  labelList regionMap(identity(nRegions));
181  {
182  // Put region labels on connected boundary edges and synchronise to
183  // create a list of all regions connected to a given edge
184  labelListList meshEdgeRegions(mesh_.nEdges(), labelList());
185  forAll(newSetFaces, newSetFacei)
186  {
187  const label facei = newSetFaces[newSetFacei];
188  const label regioni = newSetFaceRegions[newSetFacei];
189  for (const label edgei : mesh_.faceEdges()[facei])
190  {
191  meshEdgeRegions[edgei] = labelList(one{}, regioni);
192  }
193  }
195  (
196  mesh_,
197  meshEdgeRegions,
198  ListOps::appendEqOp<label>(),
199  labelList()
200  );
201 
202  // Combine edge regions to create a list of what regions a given
203  // region is connected to
204  List<bitSet> regionRegions(nRegions);
205  forAll(newSetFaces, newSetFacei)
206  {
207  const label facei = newSetFaces[newSetFacei];
208  const label regioni = newSetFaceRegions[newSetFacei];
209  for (const label edgei : mesh_.faceEdges()[facei])
210  {
211  // Includes self region (removed below)
212  regionRegions[regioni].set(meshEdgeRegions[edgei]);
213  }
214  forAll(regionRegions, regioni)
215  {
216  // Remove self region
217  regionRegions[regioni].unset(regioni);
218  }
219  }
220  Pstream::listCombineReduce(regionRegions, bitOrEqOp<bitSet>());
221 
222  // Collapse the region connections into a map between each region
223  // and the lowest numbered region that it connects to
224  forAll(regionRegions, regioni)
225  {
226  for (const label regi : regionRegions[regioni])
227  {
228  // minEqOp<label>()
229  regionMap[regi] = min(regionMap[regi], regionMap[regioni]);
230  }
231  }
232  }
233 
234  // Step 3: Combine connected regions
235  labelList regionNFaces;
236  {
237  // Remove duplicates from the region map
238  label regioni0 = 0;
239  forAll(regionMap, regioni)
240  {
241  if (regionMap[regioni] > regioni0)
242  {
243  ++ regioni0;
244  regionMap[regioni] = regioni0;
245  }
246  }
247 
248  // Recompute the number of regions
249  nRegions = regioni0 + 1;
250 
251  // Renumber the face region ID-s
252  newSetFaceRegions =
253  IndirectList<label>(regionMap, newSetFaceRegions);
254 
255  // Report the final number and size of the regions
256  regionNFaces = labelList(nRegions, Zero);
257  for (const label regioni : newSetFaceRegions)
258  {
259  ++ regionNFaces[regioni];
260  }
261  Pstream::listReduce(regionNFaces, sumOp<label>());
262 
263  Info<< " Found " << nRegions << " contiguous regions with "
264  << regionNFaces << " faces" << endl;
265  }
266 
267  // Step 4: Choose the closest region to output
268  label selectedRegioni = -1;
269  {
270  // Compute the region centres
271  scalarField regionWeights(nRegions, Zero);
272  pointField regionCentres(nRegions, Zero);
273  forAll(newSetFaces, newSetFacei)
274  {
275  const label facei = newSetFaces[newSetFacei];
276  const label regioni = newSetFaceRegions[newSetFacei];
277 
278  const scalar w = mag(mesh_.faceAreas()[facei]);
279  const point& c = mesh_.faceCentres()[facei];
280 
281  regionWeights[regioni] += w;
282  regionCentres[regioni] += w*c;
283  }
284  Pstream::listGather(regionWeights, sumOp<scalar>());
285  Pstream::listGather(regionCentres, sumOp<point>());
286 
287  if (Pstream::master())
288  {
289  regionCentres /= regionWeights;
290  }
291  //Pstream::broadcast(regionWeights);
292  Pstream::broadcast(regionCentres);
293 
294  // Find the region centroid closest to the reference point
295  selectedRegioni =
297  (
298  findMin(mag(regionCentres - point_)()),
299  minOp<label>()
300  );
301 
302  // Report the selection
303  Info<< " Selecting region " << selectedRegioni << " with "
304  << regionNFaces[selectedRegioni]
305  << " faces as the closest to point " << point_ << endl;
306  }
307 
308  // Step 5: Remove any faces from the set list not in the selected region
309  {
310  // Remove faces from the list by shuffling up and resizing
311  label newSetFacei0 = 0;
312  forAll(newSetFaces, newSetFacei)
313  {
314  newSetFaces[newSetFacei0] = newSetFaces[newSetFacei];
315 
316  if (newSetFaceRegions[newSetFacei] == selectedRegioni)
317  {
318  ++ newSetFacei0;
319  }
320  }
321  newSetFaces.resize(newSetFacei0);
322  }
323  }
324 
325  // Modify the face zone set
326  DynamicList<label> newAddressing;
327  DynamicList<bool> newFlipMap;
328  if (add)
329  {
330  // Start from copy
331  newAddressing = fzSet.addressing();
332  newFlipMap = fzSet.flipMap();
333 
334  // Add anything from the new set that is not already in the zone set
335  const auto& exclude = fzSet;
336  for (const label facei : newSetFaces)
337  {
338  if (!exclude.found(facei))
339  {
340  newAddressing.append(facei);
341  newFlipMap.append(cellIsAbovePlane[mesh_.faceOwner()[facei]]);
342  }
343  }
344  }
345  else
346  {
347  // Start from empty
348  newAddressing.reserve(fzSet.addressing().size());
349  newFlipMap.reserve(newAddressing.capacity());
350 
351  // Add everything from the zone set that is not also in the new set
352  bitSet exclude(newSetFaces);
353  for (const label facei : fzSet.addressing())
354  {
355  if (!exclude.found(facei))
356  {
357  newAddressing.append(facei);
358  newFlipMap.append(cellIsAbovePlane[mesh_.faceOwner()[facei]]);
359  }
360  }
361  }
362  fzSet.addressing().transfer(newAddressing);
363  fzSet.flipMap().transfer(newFlipMap);
364  fzSet.updateSet();
365 }
366 
367 
368 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
369 
371 (
372  const polyMesh& mesh,
373  const point& basePoint,
374  const vector& normal,
375  const faceAction action
376 )
377 :
379  point_(basePoint),
380  normal_(normal),
381  option_(action)
382 {}
383 
384 
386 (
387  const polyMesh& mesh,
388  const dictionary& dict
389 )
390 :
392  point_(dict.get<vector>("point")),
393  normal_(dict.get<vector>("normal")),
394  option_(faceActionNames_.getOrDefault("option", dict, faceAction::ALL))
395 {}
396 
397 
399 (
400  const polyMesh& mesh,
401  Istream& is
402 )
403 :
405  point_(checkIs(is)),
406  normal_(checkIs(is)),
407  option_(faceActionNames_.read(checkIs(is)))
408 {}
409 
410 
411 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
412 
414 (
415  const topoSetSource::setAction action,
416  topoSet& set
417 ) const
418 {
419  if (!isA<faceZoneSet>(set))
420  {
422  << "Operation only allowed on a faceZoneSet." << endl;
423  return;
424  }
425 
426  faceZoneSet& zoneSet = refCast<faceZoneSet>(set);
427 
428  if (action == topoSetSource::NEW || action == topoSetSource::ADD)
429  {
430  if (verbose_)
431  {
432  Info<< " Adding faces that form a plane at "
433  << point_ << " with normal " << normal_ << endl;
434  }
435 
436  combine(zoneSet, true);
437  }
438  else if (action == topoSetSource::SUBTRACT)
439  {
440  if (verbose_)
441  {
442  Info<< " Removing faces that form a plane at "
443  << point_ << " with normal " << normal_ << endl;
444  }
445 
446  combine(zoneSet, false);
447  }
448 }
449 
450 
451 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition: syncTools.H:465
dictionary dict
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
const labelListList & faceEdges() const
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1107
planeToFaceZone()=delete
No default construct.
Create a new set and ADD elements to it.
Add elements to current set.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
const cellList & cells() const
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1611
label nFaces() const noexcept
Number of mesh faces.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Macros for easy insertion into run-time selection tables.
static label markZones(const PrimitivePatch< FaceList, PointField > &, const BoolListType &borderEdge, labelList &faceZone)
Size and fills faceZone with zone of face.
addNamedToRunTimeSelectionTable(topoSetCellSource, badQualityToCell, word, badQuality)
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1063
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
label findMin(const ListType &input, label start=0)
Linear search for the index of the min element, similar to std::min_element but for lists and returns...
AccessType combine(const UList< T > &lists, AccessOp aop=accessOp< T >())
Combines sub-lists into a single list.
Definition: ListListOps.C:62
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1602
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
static void listGather(UList< T > &values, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather (reduce) list elements, applying bop to each list element.
dynamicFvMesh & mesh
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
setAction
Enumeration defining various actions.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1101
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1088
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
const vectorField & cellCentres() const
label nEdges() const
Number of mesh edges.
const polyMesh & mesh_
Reference to the mesh.
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
defineTypeNameAndDebug(combustionModel, 0)
General set of labels of mesh quantity (points, cells, faces).
Definition: topoSet.H:59
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
const vectorField & faceCentres() const
Subtract elements from current set.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
vector point
Point is a vector.
Definition: point.H:37
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
Class with constructor to add usage string to table.
label nCells() const noexcept
Number of mesh cells.
static void listCombineReduce(UList< T > &values, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Forwards to Pstream::listReduce with an in-place cop.
const vectorField & faceAreas() const
const dimensionedScalar c
Speed of light in a vacuum.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
faceAction
Enumeration defining the valid options.
const std::string patch
OpenFOAM patch number as a std::string.
messageStream Info
Information stream (stdout output on master, null elsewhere)
The topoSetFaceZoneSource is a intermediate class for handling topoSet sources for selecting face zon...
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
List< label > labelList
A List of labels.
Definition: List.H:61
virtual void applyToSet(const topoSetSource::setAction action, topoSet &) const
Apply specified action to the topoSet.
static void listReduce(UList< T > &values, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce list elements (list must be equal size on all ranks), applying bop to each list element...
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127