Loading...
Searching...
No Matches
zoneDistribute.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 DLR
9 Copyright (C) 2020-2023 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
30#include "processorPolyPatch.H"
31
32// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33
34namespace Foam
37}
38
39
40// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
41
43:
44 MeshObject_type(mesh),
45 stencil_(zoneCPCStencil::New(mesh)),
46 globalNumbering_(stencil_.globalNumbering()),
47 send_(UPstream::nProcs()),
48 pBufs_(UPstream::commsTypes::nonBlocking),
49 cyclicBoundaryCells_(mesh.nCells(), false)
50{
51 // Don't clear storage on persistent buffer
52 pBufs_.allowClearRecv(false);
53
54 // Loop over boundary patches and store cells with a face on a cyclic patch
55 bool hasCyclicPatches = false;
56 forAll(mesh.boundaryMesh(), patchi)
57 {
58 const cyclicPolyPatch* cpp =
59 isA<cyclicPolyPatch>(mesh.boundaryMesh()[patchi]);
60
61 if (cpp)
62 {
63 cyclicBoundaryCells_.set(cpp->faceCells());
64 hasCyclicPatches = true;
65 }
66 }
67
68 // Populate cyclicCentres_
69 if(hasCyclicPatches)
70 {
71 // Make a boolList from the bitSet
72 boolList isCyclicCell(mesh.nCells(), false);
73
74 forAll(cyclicBoundaryCells_, celli)
75 {
76 if (cyclicBoundaryCells_.test(celli))
77 {
78 isCyclicCell[celli] = true;
79 }
80 }
81
82 // Use getFields to get map of cell centres across processor boundaries
83 setUpCommforZone(isCyclicCell, true);
84
85 cyclicCentres_.reset
86 (
87 new Map<vectorField>(getFields(isCyclicCell, mesh_.C()))
88 );
89 }
90}
91
92
93// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * //
94
96{
97 auto* ptr = mesh.thisDb().getObjectPtr<zoneDistribute>("zoneDistribute");
98
99 if (!ptr)
100 {
101 ptr = new zoneDistribute(mesh);
103 }
105 return *ptr;
106}
107
108
109// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
112{
114}
115
116
118(
119 const boolList& zone,
120 bool updateStencil
121)
122{
123 zoneCPCStencil& stencil = zoneCPCStencil::New(mesh_);
124
125 if (updateStencil)
126 {
127 stencil.updateStencil(zone);
128 }
129
130 if (UPstream::parRun())
131 {
132 List<labelHashSet> needed(UPstream::nProcs());
133
134 // Bin according to originating (sending) processor
135 for (const label celli : stencil.needsComm())
136 {
137 if (zone[celli])
138 {
139 for (const label gblIdx : stencil_[celli])
140 {
141 const label proci = globalNumbering_.whichProcID(gblIdx);
142
143 if (proci != Pstream::myProcNo())
144 {
145 needed[proci].insert(gblIdx);
146 }
147 }
148 }
149 }
150
151 // Stream the send data into PstreamBuffers,
152 // which we also use to track the current topology.
153
154 pBufs_.clear();
155
156 for (const int proci : pBufs_.allProcs())
157 {
158 const auto& indices = needed[proci];
159
160 if (proci != UPstream::myProcNo() && !indices.empty())
161 {
162 // Serialize as List
163 UOPstream toProc(proci, pBufs_);
164 toProc << indices.sortedToc();
165 }
166 }
167
168 pBufs_.finishedSends(sendConnections_, sendProcs_, recvProcs_);
169
170 for (const int proci : pBufs_.allProcs())
171 {
172 send_[proci].clear();
173
174 if (proci != UPstream::myProcNo() && pBufs_.recvDataCount(proci))
175 {
176 UIPstream fromProc(proci, pBufs_);
177 fromProc >> send_[proci];
178 }
179 }
180 }
181}
182
183Foam::List<Foam::label> Foam::zoneDistribute::getCyclicPatches
184(
185 const label celli,
186 const label globalIdx,
187 const vector globalIdxCellCentre
188) const
189{
190 // Initialise cyclic patch label list
192
193 // If celli is not on a cyclic boundary, return the empty list
194 if (!cyclicBoundaryCells_.test(celli))
195 {
196 return patches;
197 }
198
199 const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
200
201 // Making list of cyclic patches to which celli belongs
202 List<label> celliCyclicPatches;
203 forAll(bMesh, patchi)
204 {
205 if (isA<cyclicPolyPatch>(bMesh[patchi]))
206 {
207 // Note: Probably not efficient due to use of found(celli) but
208 // typically only used for very few cells (interface cells and their
209 // point neighbours on cyclic boundaries).
210 if (bMesh[patchi].faceCells().found(celli))
211 {
212 celliCyclicPatches.append(patchi);
213 }
214 }
215 }
216
217 // So celli belongs to at least one cyclic patch.
218 // Let us figure out which.
219 if (globalNumbering_.isLocal(globalIdx)) // celli and globalIdx on same proc
220 {
221 // Get all local point neighbor cells of celli, i.e. all point
222 // neighbours that are not on the other side of a cyclic patch.
223 List<label> localPointNeiCells(0);
224 const labelList& cellPoints = mesh_.cellPoints()[celli];
225
226 for (const label cellPoint : cellPoints)
227 {
228 const labelList& pointKCells = mesh_.pointCells()[cellPoint];
229
230 for (const label pointKCell : pointKCells)
231 {
232 if (!localPointNeiCells.found(pointKCell))
233 {
234 localPointNeiCells.append(pointKCell);
235 }
236 }
237 }
238
239 // Since globalIdx is a global cell index obtained from the point
240 // neighbour list, stencil[celli], all cells in this that are not in
241 // localPointNeiCells must be cyclic neighbour cells.
242 const label localIdx = globalNumbering_.toLocal(globalIdx);
243 if (!localPointNeiCells.found(localIdx))
244 {
245 for (const label patchi : celliCyclicPatches)
246 {
247 // Find the corresponding cyclic neighbor patch ID
248 const cyclicPolyPatch& cpp =
249 static_cast<const cyclicPolyPatch&>(bMesh[patchi]);
250
251 const label neiPatch = cpp.neighbPatchID();
252
253 // Check if the cell globalIdx is on neiPatch.
254 // If it is, append neiPatch to list of patches to return
255 if (bMesh[neiPatch].faceCells().found(localIdx))
256 {
257 patches.append(neiPatch);
258 // Here it may be possible to append patchi and do:
259 //
260 // cpp.transformPosition()
261 //
262 // instead of
263 //
264 // cpp.neighbPatch().transformPosition() in getPosition()
265 }
266 }
267 }
268 }
269 else // celli and globalIdx on differet processors
270 {
271 List<label> cyclicID(3, -1);
272 List<vector> separationVectors(3, vector(0,0,0));
273 scalar distance = GREAT;
274
275 forAll(celliCyclicPatches, cID)
276 {
277 cyclicID[cID] = celliCyclicPatches[cID];
278
279 const label& patchI = celliCyclicPatches[cID];
280 const cyclicPolyPatch& cpp =
281 static_cast<const cyclicPolyPatch&>(bMesh[patchI]);
282
284 {
286 << "Rotational cyclic patches are not supported in parallel.\n"
287 << "Try to decompose the domain so that the rotational cyclic patch "
288 << "is not split in between processors."
289 << exit(FatalError);
290 }
291 cpp.neighbPatch().transformPosition(separationVectors[cID], 0);
292 }
293
294 for(int i = 0; i < 2; i++)
295 {
296 for(int j = 0; j < 2; j++)
297 {
298 for(int k = 0; k < 2; k++)
299 {
300 vector separation = i*separationVectors[0]
301 + j*separationVectors[1]
302 + k*separationVectors[2];
303
304 scalar testDistance = mag
305 (
306 (globalIdxCellCentre - separation)
307 -
308 mesh_.C()[celli]
309 );
310 if(debug) Info << "testDistance " << testDistance << endl;
311
312 if( testDistance < distance )
313 {
314 distance = testDistance;
315 patches = List<label>(0);
316 List<label> applyCyclic({i,j,k});
317
318 if(debug) Info << "distance " << distance << endl;
319 if(debug) Info << "separation " << separation << endl;
320 if(debug) Info << "applyCyclic " << applyCyclic << endl;
321
322 for(int n = 0; n < 3; n++)
323 {
324 if(cyclicID[n] != -1 && applyCyclic[n] == 1)
325 {
326 const cyclicPolyPatch& cpp =
327 static_cast<const cyclicPolyPatch&>
328 (
329 bMesh[cyclicID[n]]
330 );
331 if(debug)
332 {
333 Info << "cpp.name() " << cpp.name() << endl;
334 }
335 patches.append(cpp.neighbPatchID());
336 }
337 }
338 }
339 }
340 }
342 }
343
344 return patches;
345}
346
347
349(
350 const VolumeField<vector>& positions,
351 const Map<vector>& valuesFromOtherProc,
352 const label gblIdx,
353 const List<label> cyclicPatchID
354) const
355{
356 // Position vector, possibly from other processor, to be returned
357 vector position(getValue(positions, valuesFromOtherProc, gblIdx));
358
359 // Dealing with position transformation across cyclic patches.
360 // If no transformation is required (most cases), cyclicPatchID is empty
361 forAll(cyclicPatchID, i)
362 {
363 const label patchi = cyclicPatchID[i];
364
365 const cyclicPolyPatch& cpp =
366 static_cast<const cyclicPolyPatch&>
367 (
368 positions.mesh().boundaryMesh()[patchi]
369 );
370
371 if (cpp.transform() != coupledPolyPatch::transformType::ROTATIONAL)
372 {
373 cpp.neighbPatch().transformPosition(position, 0);
374 }
375 else if (globalNumbering_.isLocal(gblIdx))
376 {
377 const label localIdx = globalNumbering_.toLocal(gblIdx);
378
379 for (const label facei : mesh_.cells()[localIdx])
380 {
381 if (mesh_.boundaryMesh().whichPatch(facei) == cyclicPatchID[i])
382 {
383 cpp.neighbPatch().transformPosition(position, facei);
384 continue;
385 }
386 }
387 }
388 else
389 {
391 << "Rotational cyclic patches are not supported in parallel.\n"
392 << "Try to decompose the domain so that the rotational cyclic"
393 << "patch is not split in between processors."
394 << exit(FatalError);
395 }
396 }
397
398 return position;
399}
400
401
402// ************************************************************************* //
label k
bool found
label n
const Mesh & mesh() const noexcept
Return const reference to mesh.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void append(const T &val)
Append an element at the end of the list.
Definition List.H:497
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
bool allowClearRecv() const noexcept
Is clearStorage of individual receive buffer by external hooks allowed? (default: true).
void append(autoPtr< T > &ptr)
Move append an element to the end of the list.
Definition PtrList.H:364
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UIPstream.H:313
bool found(const T &val, label pos=0) const
Same as contains().
Definition UList.H:983
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UOPstream.H:408
Inter-processor communications stream.
Definition UPstream.H:69
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 parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
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
static bool & parRun() noexcept
Test if this a parallel run.
Definition UPstream.H:1681
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition bitSetI.H:502
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
virtual transformType transform() const
Type of transform.
Cyclic plane patch.
const cyclicPolyPatch & neighbPatch() const
virtual void transformPosition(pointField &l) const
Transform a patch-based position from other side to this side.
virtual label neighbPatchID() const
Neighbour patchID.
Smooth ATC in cells next to a set of patches supplied by type.
Definition faceCells.H:55
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
const word & name() const noexcept
The patch name.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
const labelUList & faceCells() const
Return face-cell addressing.
Definition polyPatch.C:401
bool store()
Register object with its registry and transfer ownership to the registry.
computes a cell point cell stencil in a narrow band. resizes in case of topological change
static zoneCPCStencil & New(const fvMesh &)
const labelHashSet & needsComm() noexcept
void updateStencil(const boolList &zone)
Class for parallel communication in a narrow band. It either provides a Map with the neighbouring val...
const globalIndex & globalNumbering() const noexcept
Addressing reference.
List< label > getCyclicPatches(const label celli, const label globalIdx, const vector globalIdxCellCentre) const
Finds and returns list of all cyclic patch labels to which celli's.
void updateStencil(const boolList &zone)
Updates stencil with boolList the size has to match mesh nCells.
void setUpCommforZone(const boolList &zone, bool updateStencil=true)
Update stencil with boolList the size has to match mesh nCells.
Type getValue(const VolumeField< Type > &phi, const Map< Type > &valuesFromOtherProc, const label gblIdx) const
Gives patchNumber and patchFaceNumber for a given Geometric volume field.
zoneDistribute(const fvMesh &)
Construct from fvMesh.
static zoneDistribute & New(const fvMesh &)
Selector.
Map< Field< Type > > getFields(const boolList &zone, const VolumeField< Type > &phi)
Returns stencil and provides a Map with globalNumbering.
vector getPosition(const VolumeField< vector > &positions, const Map< vector > &valuesFromOtherProc, const label gblIdx, const List< label > cyclicPatchID=List< label >()) const
Base class for mesh zones.
Definition zone.H:63
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
scalar distance(const vector &p1, const vector &p2)
Definition curveTools.C:12
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
GeometricField< Type, fvPatchField, volMesh > VolumeField
A volume field for a given type.
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
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)
List< bool > boolList
A List of bools.
Definition List.H:60
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points).
Definition bMesh.H:39
Vector< scalar > vector
Definition vector.H:57
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299