Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
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"
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
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::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// ************************************************************************* //
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:57
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
static label markZones(const PrimitivePatch< FaceList, PointField > &, const BoolListType &borderEdge, labelList &faceZone)
Size and fills faceZone with zone of face.
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.
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.
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.
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.
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:1706
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
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:1697
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
Like faceSet but -reads data from faceZone -updates faceZone when writing.
Definition faceZoneSet.H:50
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.
@ ALL
Select all faces that meet the criteria.
Geometric class that creates a 3D plane and can return the intersection point between a line and the ...
Definition plane.H:91
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
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
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...
topoSetFaceZoneSource(const polyMesh &mesh)
Construct from mesh.
Class with constructor to add usage string to table.
Base class of a source for a topoSet.
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.
bool verbose_
Output verbosity (default: true).
const polyMesh & mesh() const noexcept
Reference to the mesh.
const polyMesh & mesh_
Reference to the mesh.
static Istream & checkIs(Istream &is)
Check state of stream.
General set of labels of mesh quantity (points, cells, faces).
Definition topoSet.H:63
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
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.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition int32.H:127
List< label > labelList
A List of labels.
Definition List.H:62
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...
messageStream Info
Information stream (stdout output on master, null elsewhere).
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
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.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void add(DimensionedField< scalar, GeoMesh > &result, const dimensioned< scalar > &dt1, const DimensionedField< scalar, GeoMesh > &f2)
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
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...
vector point
Point is a vector.
Definition point.H:37
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
dict add("bounds", meshBb)
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299