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:498
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:600
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:526
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:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
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.
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.
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:1611
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:286
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:1602
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:609
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(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition: bitSet.H:329
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:344
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:65
Namespace for OpenFOAM.