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-2022 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::listCombineReduce(regionNFaces, plusEqOp<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::listCombineGather(regionWeights, plusEqOp<scalar>());
285  Pstream::listCombineGather(regionCentres, plusEqOp<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  (
393  mesh,
394  dict.get<vector>("point"),
395  dict.get<vector>("normal"),
396  faceActionNames_.getOrDefault("option", dict, faceAction::ALL)
397  )
398 {}
399 
400 
402 (
403  const polyMesh& mesh,
404  Istream& is
405 )
406 :
408  point_(checkIs(is)),
409  normal_(checkIs(is)),
410  option_(faceActionNames_.read(checkIs(is)))
411 {}
412 
413 
414 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
415 
417 (
418  const topoSetSource::setAction action,
419  topoSet& set
420 ) const
421 {
422  if (!isA<faceZoneSet>(set))
423  {
425  << "Operation only allowed on a faceZoneSet." << endl;
426  return;
427  }
428 
429  faceZoneSet& zoneSet = refCast<faceZoneSet>(set);
430 
431  if (action == topoSetSource::NEW || action == topoSetSource::ADD)
432  {
433  if (verbose_)
434  {
435  Info<< " Adding faces that form a plane at "
436  << point_ << " with normal " << normal_ << endl;
437  }
438 
439  combine(zoneSet, true);
440  }
441  else if (action == topoSetSource::SUBTRACT)
442  {
443  if (verbose_)
444  {
445  Info<< " Removing faces that form a plane at "
446  << point_ << " with normal " << normal_ << endl;
447  }
448 
449  combine(zoneSet, false);
450  }
451 }
452 
453 
454 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
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:1122
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:531
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:432
const cellList & cells() const
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
label nFaces() const noexcept
Number of mesh faces.
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
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.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
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:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
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:1065
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
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:137
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
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:1116
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
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
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.
A topoSetSource to select faces based on the adjacent cell centres spanning a given plane...
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:1082
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:74
static void listCombineGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
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:62
virtual void applyToSet(const topoSetSource::setAction action, topoSet &) const
Apply specified action to the topoSet.
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static void listCombineReduce(List< T > &values, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
After completion all processors have the same data.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127