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 -------------------------------------------------------------------------------
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 "zoneDistribute.H"
30 #include "processorPolyPatch.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
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);
102  regIOobject::store(ptr);
103  }
105  return *ptr;
106 }
107 
108 
109 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
110 
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 
184 (
185  const label celli,
186  const label globalIdx,
187  const vector globalIdxCellCentre
188 ) const
189 {
190  // Initialise cyclic patch label list
191  List<label> patches(0);
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 
283  if(cpp.transform() == coupledPolyPatch::transformType::ROTATIONAL)
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  }
341  }
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 // ************************************************************************* //
vector getPosition(const VolumeField< vector > &positions, const Map< vector > &valuesFromOtherProc, const label gblIdx, const List< label > cyclicPatchID=List< label >()) const
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:502
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:496
Map< Field< Type > > getFields(const boolList &zone, const VolumeField< Type > &phi)
Returns stencil and provides a Map with globalNumbering.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
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.
static int myProcNo(label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1799
bool store()
Register object with its registry and transfer ownership to the registry.
Definition: regIOobjectI.H:36
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
computes a cell point cell stencil in a narrow band. resizes in case of topological change ...
label k
Boltzmann constant.
const labelHashSet & needsComm() noexcept
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition: fvMesh.H:376
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
static zoneDistribute & New(const fvMesh &)
Selector.
dynamicFvMesh & mesh
bool allowClearRecv() const noexcept
Is clearStorage of individual receive buffer by external hooks allowed? (default: true) ...
const labelUList & faceCells() const
Return face-cell addressing.
Definition: polyPatch.C:401
Base class for mesh zones.
Definition: zone.H:59
const fvMesh & mesh() const noexcept
Reference to the mesh.
Definition: MeshObject.H:257
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:611
Type * getObjectPtr(const word &name, const bool recursive=false) const
Return non-const pointer to the object of the given Type, using a const-cast to have it behave like a...
zoneDistribute(const fvMesh &)
Construct from fvMesh.
Cyclic plane patch.
static zoneCPCStencil & New(const fvMesh &)
Vector< scalar > vector
Definition: vector.H:57
bool test(label pos) const
Test for true value at specified position. A no-op and returns false for out-of-range positions (safe...
Definition: bitSet.H:336
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
void updateStencil(const boolList &zone)
int debug
Static debugging option.
defineTypeNameAndDebug(combustionModel, 0)
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&#39;s.
void setUpCommforZone(const boolList &zone, bool updateStencil=true)
Update stencil with boolList the size has to match mesh nCells.
void append(autoPtr< T > &ptr)
Move append an element to the end of the list.
Definition: PtrList.H:367
static label nProcs(label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1790
decomposeUsingBbs false
Use bounding boxes (default) or unique decomposition of triangles (i.e. do not duplicate triangles) ...
label nCells() const noexcept
Number of mesh cells.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
virtual label neighbPatchID() const
Neighbour patchID.
const polyBoundaryMesh & patches
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
void updateStencil(const boolList &zone)
Updates stencil with boolList the size has to match mesh nCells.
const volVectorField & C() const
Return cell centres as volVectorField.
Class for parallel communication in a narrow band. It either provides a Map with the neighbouring val...
List< label > labelList
A List of labels.
Definition: List.H:61
PrimitivePatch< List< face >, const pointField > bMesh
Holder of faceList and points. (v.s. e.g. primitivePatch which references points) ...
Definition: bMesh.H:39
List< bool > boolList
A List of bools.
Definition: List.H:59
bool found
Inter-processor communications stream.
Definition: UPstream.H:69
Namespace for OpenFOAM.