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-------------------------------------------------------------------------------
11License
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"
33#include "PatchTools.H"
34#include "syncTools.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39namespace Foam
40{
44
47
49 (
52 word,
53 plane
54 );
56 (
59 istream,
60 plane
61 );
62}
63
64
65Foam::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
74const Foam::Enum
75<
77>
78Foam::planeToFaceZone::faceActionNames_
79({
80 { faceAction::ALL, "all" },
81 { faceAction::CLOSEST, "closest" },
82});
83
84
85// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
86
87void 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::listCombineAllGather(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::listCombineAllGather(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// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addNamedToRunTimeSelectionTable(baseType, thisType, argNames, lookupName)
Add to construction table with 'lookupName' as the key.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: Enum.H:61
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
static label markZones(const PrimitivePatch< FaceList, PointField > &, const BoolListType &borderEdge, labelList &faceZone)
Size and fills faceZone with zone of face.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
static void allGatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
static void listCombineAllGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
After completion all processors have the same data.
static void broadcast(Type &value, const label comm=UPstream::worldComm)
static void listCombineGather(const List< commsStruct > &comms, List< T > &values, const CombineOp &cop, const int tag, const label comm)
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Like faceSet but -reads data from faceZone -updates faceZone when writing.
Definition: faceZoneSet.H:54
A topoSetSource to select faces based on the adjacent cell centres spanning a given plane....
planeToFaceZone()=delete
No default construct.
virtual void applyToSet(const topoSetSource::setAction action, topoSet &) const
Apply specified action to the topoSet.
faceAction
Enumeration defining the valid options.
@ CLOSEST
Select faces belong to the closest contiguous plane.
Geometric class that creates a 3D plane and can return the intersection point between a line and the ...
Definition: plane.H:95
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
const vectorField & faceCentres() const
const vectorField & cellCentres() const
label nCells() const noexcept
Number of mesh cells.
label nFaces() const noexcept
Number of mesh faces.
const labelListList & faceEdges() const
const vectorField & faceAreas() const
const cellList & cells() const
label nEdges() const
Number of mesh edges.
int myProcNo() const noexcept
Return processor number.
splitCell * master() const
Definition: splitCell.H:113
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:396
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.
The topoSetFaceZoneSource is a intermediate class for handling topoSet sources for selecting face zon...
Class with constructor to add usage string to table.
Base class of a source for a topoSet.
Definition: topoSetSource.H:68
setAction
Enumeration defining various actions.
@ SUBTRACT
Subtract elements from current set.
@ ADD
Add elements to current set.
@ NEW
Create a new set and ADD elements to it.
const polyMesh & mesh_
Reference to the mesh.
General set of labels of mesh quantity (points, cells, faces).
Definition: topoSet.H:67
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
dynamicFvMesh & mesh
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
const std::string patch
OpenFOAM patch number as a std::string.
Namespace for OpenFOAM.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:108
List< label > labelList
A List of labels.
Definition: List.H:66
label findMin(const ListType &input, label start=0)
messageStream Info
Information stream (stdout output on master, null elsewhere)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
dict add("bounds", meshBb)
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333