PatchEdgeFaceWave.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) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2022 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 "PatchEdgeFaceWave.H"
30 #include "polyMesh.H"
31 #include "globalMeshData.H"
32 #include "PatchTools.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 // Update info for edgeI, at position pt, with information from
37 // neighbouring face.
38 // Updates:
39 // - changedEdge_, changedEdges_,
40 // - statistics: nEvals_, nUnvisitedEdges_
41 template
42 <
43  class PrimitivePatchType,
44  class Type,
45  class TrackingData
46 >
49 (
50  const label edgei,
51  const label neighbourFacei,
52  const Type& neighbourInfo,
53  Type& edgeInfo
54 )
55 {
56  nEvals_++;
57 
58  bool wasValid = edgeInfo.valid(td_);
59 
60  bool propagate =
61  edgeInfo.updateEdge
62  (
63  mesh_,
64  patch_,
65  edgei,
66  neighbourFacei,
67  neighbourInfo,
68  propagationTol_,
69  td_
70  );
71 
72  if (propagate)
73  {
74  if (changedEdge_.set(edgei))
75  {
76  changedEdges_.push_back(edgei);
77  }
78  }
79 
80  if (!wasValid && edgeInfo.valid(td_))
81  {
82  --nUnvisitedEdges_;
83  }
84 
85  return propagate;
86 }
87 
88 
89 // Update info for facei, at position pt, with information from
90 // neighbouring edge.
91 // Updates:
92 // - changedFace_, changedFaces_,
93 // - statistics: nEvals_, nUnvisitedFace_
94 template
95 <
96  class PrimitivePatchType,
97  class Type,
98  class TrackingData
99 >
102 (
103  const label facei,
104  const label neighbourEdgeI,
105  const Type& neighbourInfo,
106  Type& faceInfo
107 )
108 {
109  nEvals_++;
110 
111  bool wasValid = faceInfo.valid(td_);
112 
113  bool propagate =
114  faceInfo.updateFace
115  (
116  mesh_,
117  patch_,
118  facei,
119  neighbourEdgeI,
120  neighbourInfo,
121  propagationTol_,
122  td_
123  );
124 
125  if (propagate)
126  {
127  if (changedFace_.set(facei))
128  {
129  changedFaces_.push_back(facei);
130  }
131  }
132 
133  if (!wasValid && faceInfo.valid(td_))
134  {
135  --nUnvisitedFaces_;
136  }
137 
138  return propagate;
139 }
140 
141 
142 template
143 <
144  class PrimitivePatchType,
145  class Type,
146  class TrackingData
147 >
149 syncEdges()
150 {
151  const globalMeshData& globalData = mesh_.globalData();
152  const mapDistribute& map = globalData.globalEdgeSlavesMap();
153  const bitSet& cppOrientation = globalData.globalEdgeOrientation();
154 
155  // Convert patch-edge data into cpp-edge data
156  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157 
158  //- Construct with all data in consistent orientation
159  List<Type> cppEdgeData(map.constructSize());
160 
161  forAll(patchEdges_, i)
162  {
163  label patchEdgeI = patchEdges_[i];
164  label coupledEdgeI = coupledEdges_[i];
165 
166  if (changedEdge_.test(patchEdgeI))
167  {
168  const Type& data = allEdgeInfo_[patchEdgeI];
169 
170  // Patch-edge data needs to be converted into coupled-edge data
171  // (optionally flipped) and consistent in orientation with
172  // master of coupled edge (optionally flipped)
173  bool sameOrientation =
174  (
175  sameEdgeOrientation_[i]
176  == cppOrientation[coupledEdgeI]
177  );
178 
179  cppEdgeData[coupledEdgeI].updateEdge
180  (
181  mesh_,
182  patch_,
183  data,
184  sameOrientation,
185  propagationTol_,
186  td_
187  );
188  }
189  }
190 
191 
192  // Synchronise
193  // ~~~~~~~~~~~
194 
195  globalData.syncData
196  (
197  cppEdgeData,
198  globalData.globalEdgeSlaves(),
199  globalData.globalEdgeTransformedSlaves(),
200  map,
201  globalData.globalTransforms(),
202  updateOp<PrimitivePatchType, Type, TrackingData>
203  (
204  mesh_,
205  patch_,
206  propagationTol_,
207  td_
208  ),
209  transformOp<PrimitivePatchType, Type, TrackingData>
210  (
211  mesh_,
212  patch_,
213  propagationTol_,
214  td_
215  )
216  );
217 
218 
219  // Back from cpp-edge to patch-edge data
220  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
221 
222  forAll(patchEdges_, i)
223  {
224  label patchEdgeI = patchEdges_[i];
225  label coupledEdgeI = coupledEdges_[i];
226 
227  const Type& data = cppEdgeData[coupledEdgeI];
228 
229  if (data.valid(td_))
230  {
231  bool sameOrientation =
232  (
233  sameEdgeOrientation_[i]
234  == cppOrientation[coupledEdgeI]
235  );
236 
237  allEdgeInfo_[patchEdgeI].updateEdge
238  (
239  mesh_,
240  patch_,
241  data,
242  sameOrientation,
243  propagationTol_,
244  td_
245  );
246 
247  if (changedEdge_.set(patchEdgeI))
248  {
249  changedEdges_.push_back(patchEdgeI);
250  }
251  }
252  }
253 }
254 
255 
256 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
257 
258 // Iterate, propagating changedEdgesInfo across patch, until no change (or
259 // maxIter reached). Initial edge values specified.
260 template
261 <
262  class PrimitivePatchType,
263  class Type,
264  class TrackingData
265 >
268 (
269  const polyMesh& mesh,
270  const PrimitivePatchType& patch,
271  const labelList& changedEdges,
272  const List<Type>& changedEdgesInfo,
273 
274  UList<Type>& allEdgeInfo,
275  UList<Type>& allFaceInfo,
276 
277  const label maxIter,
278  TrackingData& td
279 )
280 :
281  PatchEdgeFaceWaveBase(mesh, patch.nEdges(), patch.size()),
282  patch_(patch),
283  allEdgeInfo_(allEdgeInfo),
284  allFaceInfo_(allFaceInfo),
285  td_(td),
286  nEvals_(0)
287 {
288  // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
289  // for ease of synchronisation
291  (
292  patch_,
294 
295  patchEdges_,
296  coupledEdges_,
297  sameEdgeOrientation_
298  );
299 
300 
301  if (allEdgeInfo_.size() != patch_.nEdges())
302  {
304  << "size of edgeInfo work array is not equal to the number"
305  << " of edges in the patch" << nl
306  << " edgeInfo :" << allEdgeInfo_.size() << nl
307  << " patch.nEdges:" << patch_.nEdges() << endl
308  << exit(FatalError);
309  }
310  if (allFaceInfo_.size() != patch_.size())
311  {
313  << "size of edgeInfo work array is not equal to the number"
314  << " of faces in the patch" << nl
315  << " faceInfo :" << allFaceInfo_.size() << nl
316  << " patch.size:" << patch_.size() << endl
317  << exit(FatalError);
318  }
319 
320 
321  // Set from initial changed edges data
322  setEdgeInfo(changedEdges, changedEdgesInfo);
323 
324  if (debug)
325  {
326  Pout<< "Seed edges : " << nChangedEdges() << endl;
327  }
328 
329  // Iterate until nothing changes
330  label iter = iterate(maxIter);
331 
332  if ((maxIter > 0) && (iter >= maxIter))
333  {
335  << "Maximum number of iterations reached. Increase maxIter." << nl
336  << " maxIter:" << maxIter << nl
337  << " changedEdges:" << nChangedEdges() << nl
338  << " changedFaces:" << nChangedFaces() << endl
339  << exit(FatalError);
340  }
341 }
342 
343 
344 template
345 <
346  class PrimitivePatchType,
347  class Type,
348  class TrackingData
349 >
352 (
353  const polyMesh& mesh,
354  const PrimitivePatchType& patch,
355  UList<Type>& allEdgeInfo,
356  UList<Type>& allFaceInfo,
357  TrackingData& td
358 )
359 :
360  PatchEdgeFaceWaveBase(mesh, patch.nEdges(), patch.size()),
361  patch_(patch),
362  allEdgeInfo_(allEdgeInfo),
363  allFaceInfo_(allFaceInfo),
364  td_(td),
365  nEvals_(0)
366 {
367  // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
368  // for ease of synchronisation
370  (
371  patch_,
373 
374  patchEdges_,
375  coupledEdges_,
376  sameEdgeOrientation_
377  );
378 }
379 
380 
381 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
382 
383 // Copy edge information into member data
384 template
385 <
386  class PrimitivePatchType,
387  class Type,
388  class TrackingData
389 >
392 (
393  const labelList& changedEdges,
394  const List<Type>& changedEdgesInfo
395 )
396 {
397  forAll(changedEdges, changedEdgeI)
398  {
399  label edgeI = changedEdges[changedEdgeI];
400 
401  bool wasValid = allEdgeInfo_[edgeI].valid(td_);
402 
403  // Copy info for edgeI
404  allEdgeInfo_[edgeI] = changedEdgesInfo[changedEdgeI];
405 
406  // Maintain count of unset edges
407  if (!wasValid && allEdgeInfo_[edgeI].valid(td_))
408  {
409  --nUnvisitedEdges_;
410  }
411 
412  // Mark edgeI as changed, both on list and on edge itself.
413 
414  if (changedEdge_.set(edgeI))
415  {
416  changedEdges_.push_back(edgeI);
417  }
418  }
419 }
420 
421 
422 // Propagate information from face to edge. Return number of edges changed.
423 template
424 <
425  class PrimitivePatchType,
426  class Type,
427  class TrackingData
428 >
430 faceToEdge()
431 {
432  changedEdges_.clear();
433  changedEdge_ = false;
434 
435  for (const label facei : changedFaces_)
436  {
437  if (!changedFace_.test(facei))
438  {
440  << "face " << facei
441  << " not marked as having been changed" << nl
442  << "This might be caused by multiple occurrences of the same"
443  << " seed edge." << abort(FatalError);
444  }
445 
446  const Type& neighbourWallInfo = allFaceInfo_[facei];
447 
448  // Evaluate all connected edges
449  const labelList& fEdges = patch_.faceEdges()[facei];
450 
451  forAll(fEdges, fEdgeI)
452  {
453  label edgeI = fEdges[fEdgeI];
454 
455  Type& currentWallInfo = allEdgeInfo_[edgeI];
456 
457  if (!currentWallInfo.equal(neighbourWallInfo, td_))
458  {
459  updateEdge
460  (
461  edgeI,
462  facei,
463  neighbourWallInfo,
464  currentWallInfo
465  );
466  }
467  }
468  }
469 
470 
471  syncEdges();
472 
473 
474  if (debug)
475  {
476  Pout<< "Changed edges : " << nChangedEdges() << endl;
477  }
478 
479  return returnReduce(nChangedEdges(), sumOp<label>());
480 }
481 
482 
483 // Propagate information from edge to face. Return number of faces changed.
484 template
485 <
486  class PrimitivePatchType,
487  class Type,
488  class TrackingData
489 >
491 edgeToFace()
492 {
493  changedFaces_.clear();
494  changedFace_ = false;
495 
496  const labelListList& edgeFaces = patch_.edgeFaces();
497 
498  for (const label edgei : changedEdges_)
499  {
500  if (!changedEdge_.test(edgei))
501  {
503  << "edge " << edgei
504  << " not marked as having been changed" << nl
505  << "This might be caused by multiple occurrences of the same"
506  << " seed edge." << abort(FatalError);
507  }
508 
509  const Type& neighbourWallInfo = allEdgeInfo_[edgei];
510 
511  // Evaluate all connected faces
512 
513  for (const label facei : edgeFaces[edgei])
514  {
515  Type& currentWallInfo = allFaceInfo_[facei];
516 
517  if (!currentWallInfo.equal(neighbourWallInfo, td_))
518  {
519  updateFace
520  (
521  facei,
522  edgei,
523  neighbourWallInfo,
524  currentWallInfo
525  );
526  }
527  }
528  }
529 
530  if (debug)
531  {
532  Pout<< "Changed faces : " << nChangedFaces() << endl;
533  }
534 
535  return returnReduce(nChangedFaces(), sumOp<label>());
536 }
537 
538 
539 // Iterate
540 template
541 <
542  class PrimitivePatchType,
543  class Type,
544  class TrackingData
545 >
547 iterate
548 (
549  const label maxIter
550 )
551 {
552  // Make sure coupled edges contain same info
553  syncEdges();
554 
555  nEvals_ = 0;
556 
557  label iter = 0;
558 
559  while (iter < maxIter)
560  {
561  if (debug)
562  {
563  Pout<< "Iteration " << iter << endl;
564  }
565 
566  label nFaces = edgeToFace();
567 
568  if (debug)
569  {
570  Pout<< "Total changed faces : " << nFaces << endl;
571  }
572 
573  if (nFaces == 0)
574  {
575  break;
576  }
577 
578  label nEdges = faceToEdge();
579 
580  if (debug)
581  {
582  Pout<< "Total changed edges : " << nEdges << nl
583  << "Total evaluations : " << nEvals_ << nl
584  << "Remaining unvisited edges : " << nUnvisitedEdges_ << nl
585  << "Remaining unvisited faces : " << nUnvisitedFaces_ << nl
586  << endl;
587  }
588 
589  if (nEdges == 0)
590  {
591  break;
592  }
593 
594  iter++;
595  }
596 
597  return iter;
598 }
599 
600 
601 // ************************************************************************* //
const polyMesh & mesh_
Reference to mesh.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
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:598
Wave propagation of information along patch. Every iteration information goes through one layer of fa...
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label faceToEdge()
Propagate from face to edge.
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
label edgeToFace()
Propagate from edge to face.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:227
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
dynamicFvMesh & mesh
label nChangedFaces() const noexcept
Current number of changed faces.
const globalMeshData & globalData() const
Return parallel info (demand-driven)
Definition: polyMesh.C:1311
errorManip< error > abort(error &err)
Definition: errorManip.H:139
label iterate(const label maxIter)
Iterate until no changes or maxIter reached.
int debug
Static debugging option.
void setEdgeInfo(const labelList &changedEdges, const List< Type > &changedEdgesInfo)
Copy initial data into allEdgeInfo_.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
const std::string patch
OpenFOAM patch number as a std::string.
label nChangedEdges() const noexcept
Current number of changed edges.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.