PatchEdgeFaceWave.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "PatchEdgeFaceWave.H"
27 #include "polyMesh.H"
28 #include "globalMeshData.H"
29 #include "PatchTools.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 template
34 <
35  class PrimitivePatchType,
36  class Type,
37  class TrackingData
38 >
40 propagationTol_ = 0.01;
41 
42 template
43 <
44  class PrimitivePatchType,
45  class Type,
46  class TrackingData
47 >
49 defaultTrackingData_ = -1;
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
54 // Update info for edgeI, at position pt, with information from
55 // neighbouring face.
56 // Updates:
57 // - changedEdge_, changedEdges_,
58 // - statistics: nEvals_, nUnvisitedEdges_
59 template
60 <
61  class PrimitivePatchType,
62  class Type,
63  class TrackingData
64 >
67 (
68  const label edgeI,
69  const label neighbourFacei,
70  const Type& neighbourInfo,
71  Type& edgeInfo
72 )
73 {
74  nEvals_++;
75 
76  bool wasValid = edgeInfo.valid(td_);
77 
78  bool propagate =
79  edgeInfo.updateEdge
80  (
81  mesh_,
82  patch_,
83  edgeI,
84  neighbourFacei,
85  neighbourInfo,
86  propagationTol_,
87  td_
88  );
89 
90  if (propagate)
91  {
92  if (!changedEdge_[edgeI])
93  {
94  changedEdge_[edgeI] = true;
95  changedEdges_.append(edgeI);
96  }
97  }
98 
99  if (!wasValid && edgeInfo.valid(td_))
100  {
101  --nUnvisitedEdges_;
102  }
103 
104  return propagate;
105 }
106 
107 
108 // Update info for facei, at position pt, with information from
109 // neighbouring edge.
110 // Updates:
111 // - changedFace_, changedFaces_,
112 // - statistics: nEvals_, nUnvisitedFace_
113 template
114 <
115  class PrimitivePatchType,
116  class Type,
117  class TrackingData
118 >
121 (
122  const label facei,
123  const label neighbourEdgeI,
124  const Type& neighbourInfo,
125  Type& faceInfo
126 )
127 {
128  nEvals_++;
129 
130  bool wasValid = faceInfo.valid(td_);
131 
132  bool propagate =
133  faceInfo.updateFace
134  (
135  mesh_,
136  patch_,
137  facei,
138  neighbourEdgeI,
139  neighbourInfo,
140  propagationTol_,
141  td_
142  );
143 
144  if (propagate)
145  {
146  if (!changedFace_[facei])
147  {
148  changedFace_[facei] = true;
149  changedFaces_.append(facei);
150  }
151  }
152 
153  if (!wasValid && faceInfo.valid(td_))
154  {
155  --nUnvisitedFaces_;
156  }
157 
158  return propagate;
159 }
160 
161 
162 template
163 <
164  class PrimitivePatchType,
165  class Type,
166  class TrackingData
167 >
169 syncEdges()
170 {
171  const globalMeshData& globalData = mesh_.globalData();
172  const distributionMap& map = globalData.globalEdgeSlavesMap();
173  const PackedBoolList& cppOrientation = globalData.globalEdgeOrientation();
174 
175  // Convert patch-edge data into cpp-edge data
176  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
177 
178  //- Construct with all data in consistent orientation
179  List<Type> cppEdgeData(map.constructSize());
180 
181  forAll(patchEdges_, i)
182  {
183  label patchEdgeI = patchEdges_[i];
184  label coupledEdgeI = coupledEdges_[i];
185 
186  if (changedEdge_[patchEdgeI])
187  {
188  const Type& data = allEdgeInfo_[patchEdgeI];
189 
190  // Patch-edge data needs to be converted into coupled-edge data
191  // (optionally flipped) and consistent in orientation with
192  // master of coupled edge (optionally flipped)
193  bool sameOrientation =
194  (
195  sameEdgeOrientation_[i]
196  == cppOrientation[coupledEdgeI]
197  );
198 
199  cppEdgeData[coupledEdgeI].updateEdge
200  (
201  mesh_,
202  patch_,
203  data,
204  sameOrientation,
205  propagationTol_,
206  td_
207  );
208  }
209  }
210 
211 
212  // Synchronise
213  // ~~~~~~~~~~~
214 
215  globalData.syncData
216  (
217  cppEdgeData,
218  globalData.globalEdgeSlaves(),
219  globalData.globalEdgeTransformedSlaves(),
220  map,
221  globalData.globalTransforms(),
222  updateOp<PrimitivePatchType, Type, TrackingData>
223  (
224  mesh_,
225  patch_,
226  propagationTol_,
227  td_
228  ),
229  transformOp<PrimitivePatchType, Type, TrackingData>
230  (
231  mesh_,
232  patch_,
233  propagationTol_,
234  td_
235  )
236  );
237 
238 
239  // Back from cpp-edge to patch-edge data
240  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241 
242  forAll(patchEdges_, i)
243  {
244  label patchEdgeI = patchEdges_[i];
245  label coupledEdgeI = coupledEdges_[i];
246 
247  const Type& data = cppEdgeData[coupledEdgeI];
248 
249  if (data.valid(td_))
250  {
251  bool sameOrientation =
252  (
253  sameEdgeOrientation_[i]
254  == cppOrientation[coupledEdgeI]
255  );
256 
257  allEdgeInfo_[patchEdgeI].updateEdge
258  (
259  mesh_,
260  patch_,
261  data,
262  sameOrientation,
263  propagationTol_,
264  td_
265  );
266 
267  if (!changedEdge_[patchEdgeI])
268  {
269  changedEdges_.append(patchEdgeI);
270  changedEdge_[patchEdgeI] = true;
271  }
272  }
273  }
274 }
275 
276 
277 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
278 
279 // Iterate, propagating changedEdgesInfo across patch, until no change (or
280 // maxIter reached). Initial edge values specified.
281 template
282 <
283  class PrimitivePatchType,
284  class Type,
285  class TrackingData
286 >
289 (
290  const polyMesh& mesh,
291  const PrimitivePatchType& patch,
292  const labelList& changedEdges,
293  const List<Type>& changedEdgesInfo,
294 
295  UList<Type>& allEdgeInfo,
296  UList<Type>& allFaceInfo,
297 
298  const label maxIter,
299  TrackingData& td
300 )
301 :
302  mesh_(mesh),
303  patch_(patch),
304  allEdgeInfo_(allEdgeInfo),
305  allFaceInfo_(allFaceInfo),
306  td_(td),
307  changedEdge_(patch_.nEdges()),
308  changedEdges_(patch_.size()),
309  changedFace_(patch_.size()),
310  changedFaces_(patch_.size()),
311  nEvals_(0),
312  nUnvisitedEdges_(patch_.nEdges()),
313  nUnvisitedFaces_(patch_.size())
314 {
315  // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
316  // for ease of synchronisation
317  PatchTools::matchEdges
318  (
319  patch_,
320  mesh_.globalData().coupledPatch(),
321 
322  patchEdges_,
323  coupledEdges_,
324  sameEdgeOrientation_
325  );
326 
327 
328  if (allEdgeInfo_.size() != patch_.nEdges())
329  {
331  << "size of edgeInfo work array is not equal to the number"
332  << " of edges in the patch" << endl
333  << " edgeInfo :" << allEdgeInfo_.size() << endl
334  << " patch.nEdges:" << patch_.nEdges()
335  << exit(FatalError);
336  }
337  if (allFaceInfo_.size() != patch_.size())
338  {
340  << "size of edgeInfo work array is not equal to the number"
341  << " of faces in the patch" << endl
342  << " faceInfo :" << allFaceInfo_.size() << endl
343  << " patch.size:" << patch_.size()
344  << exit(FatalError);
345  }
346 
347 
348  // Set from initial changed edges data
349  setEdgeInfo(changedEdges, changedEdgesInfo);
350 
351  if (debug)
352  {
353  Pout<< "Seed edges : " << changedEdges_.size() << endl;
354  }
355 
356  // Iterate until nothing changes
357  label iter = iterate(maxIter);
358 
359  if ((maxIter > 0) && (iter >= maxIter))
360  {
362  << "Maximum number of iterations reached. Increase maxIter." << endl
363  << " maxIter:" << maxIter << endl
364  << " changedEdges:" << changedEdges_.size() << endl
365  << " changedFaces:" << changedFaces_.size() << endl
366  << exit(FatalError);
367  }
368 }
369 
370 
371 template
372 <
373  class PrimitivePatchType,
374  class Type,
375  class TrackingData
376 >
379 (
380  const polyMesh& mesh,
381  const PrimitivePatchType& patch,
382  UList<Type>& allEdgeInfo,
383  UList<Type>& allFaceInfo,
384  TrackingData& td
385 )
386 :
387  mesh_(mesh),
388  patch_(patch),
389  allEdgeInfo_(allEdgeInfo),
390  allFaceInfo_(allFaceInfo),
391  td_(td),
392  changedEdge_(patch_.nEdges()),
393  changedEdges_(patch_.nEdges()),
394  changedFace_(patch_.size()),
395  changedFaces_(patch_.size()),
396  nEvals_(0),
397  nUnvisitedEdges_(patch_.nEdges()),
398  nUnvisitedFaces_(patch_.size())
399 {
400  // Calculate addressing between patch_ and mesh.globalData().coupledPatch()
401  // for ease of synchronisation
402  PatchTools::matchEdges
403  (
404  patch_,
405  mesh_.globalData().coupledPatch(),
406 
407  patchEdges_,
408  coupledEdges_,
409  sameEdgeOrientation_
410  );
411 }
412 
413 
414 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
415 
416 template
417 <
418  class PrimitivePatchType,
419  class Type,
420  class TrackingData
421 >
424 {
425  return nUnvisitedEdges_;
426 }
427 
428 
429 template
430 <
431  class PrimitivePatchType,
432  class Type,
433  class TrackingData
434 >
437 {
438  return nUnvisitedFaces_;
439 }
440 
441 
442 // Copy edge information into member data
443 template
444 <
445  class PrimitivePatchType,
446  class Type,
447  class TrackingData
448 >
451 (
452  const labelList& changedEdges,
453  const List<Type>& changedEdgesInfo
454 )
455 {
456  forAll(changedEdges, changedEdgeI)
457  {
458  label edgeI = changedEdges[changedEdgeI];
459 
460  bool wasValid = allEdgeInfo_[edgeI].valid(td_);
461 
462  // Copy info for edgeI
463  allEdgeInfo_[edgeI] = changedEdgesInfo[changedEdgeI];
464 
465  // Maintain count of unset edges
466  if (!wasValid && allEdgeInfo_[edgeI].valid(td_))
467  {
468  --nUnvisitedEdges_;
469  }
470 
471  // Mark edgeI as changed, both on list and on edge itself.
472 
473  if (!changedEdge_[edgeI])
474  {
475  changedEdge_[edgeI] = true;
476  changedEdges_.append(edgeI);
477  }
478  }
479 }
480 
481 
482 // Propagate information from face to edge. Return number of edges changed.
483 template
484 <
485  class PrimitivePatchType,
486  class Type,
487  class TrackingData
488 >
491 {
492  changedEdges_.clear();
493  changedEdge_ = false;
494 
495  forAll(changedFaces_, changedFacei)
496  {
497  label facei = changedFaces_[changedFacei];
498 
499  if (!changedFace_[facei])
500  {
502  << "face " << facei
503  << " not marked as having been changed" << nl
504  << "This might be caused by multiple occurrences of the same"
505  << " seed edge." << abort(FatalError);
506  }
507 
508  const Type& neighbourWallInfo = allFaceInfo_[facei];
509 
510  // Evaluate all connected edges
511  const labelList& fEdges = patch_.faceEdges()[facei];
512 
513  forAll(fEdges, fEdgeI)
514  {
515  label edgeI = fEdges[fEdgeI];
516 
517  Type& currentWallInfo = allEdgeInfo_[edgeI];
518 
519  if (!currentWallInfo.equal(neighbourWallInfo, td_))
520  {
521  updateEdge
522  (
523  edgeI,
524  facei,
525  neighbourWallInfo,
526  currentWallInfo
527  );
528  }
529  }
530  }
531 
532 
533  syncEdges();
534 
535 
536  if (debug)
537  {
538  Pout<< "Changed edges : " << changedEdges_.size() << endl;
539  }
540 
541  return returnReduce(changedEdges_.size(), sumOp<label>());
542 }
543 
544 
545 // Propagate information from edge to face. Return number of faces changed.
546 template
547 <
548  class PrimitivePatchType,
549  class Type,
550  class TrackingData
551 >
554 {
555  changedFaces_.clear();
556  changedFace_ = false;
557 
558  const labelListList& edgeFaces = patch_.edgeFaces();
559 
560  forAll(changedEdges_, changedEdgeI)
561  {
562  label edgeI = changedEdges_[changedEdgeI];
563 
564  if (!changedEdge_[edgeI])
565  {
567  << "edge " << edgeI
568  << " not marked as having been changed" << nl
569  << "This might be caused by multiple occurrences of the same"
570  << " seed edge." << abort(FatalError);
571  }
572 
573  const Type& neighbourWallInfo = allEdgeInfo_[edgeI];
574 
575  // Evaluate all connected faces
576 
577  const labelList& eFaces = edgeFaces[edgeI];
578  forAll(eFaces, eFacei)
579  {
580  label facei = eFaces[eFacei];
581 
582  Type& currentWallInfo = allFaceInfo_[facei];
583 
584  if (!currentWallInfo.equal(neighbourWallInfo, td_))
585  {
586  updateFace
587  (
588  facei,
589  edgeI,
590  neighbourWallInfo,
591  currentWallInfo
592  );
593  }
594  }
595  }
596 
597  if (debug)
598  {
599  Pout<< "Changed faces : " << changedFaces_.size() << endl;
600  }
601 
602  return returnReduce(changedFaces_.size(), sumOp<label>());
603 }
604 
605 
606 // Iterate
607 template
608 <
609  class PrimitivePatchType,
610  class Type,
611  class TrackingData
612 >
614 iterate
615 (
616  const label maxIter
617 )
618 {
619  // Make sure coupled edges contain same info
620  syncEdges();
621 
622  nEvals_ = 0;
623 
624  label iter = 0;
625 
626  while (iter < maxIter)
627  {
628  if (debug)
629  {
630  Pout<< "Iteration " << iter << endl;
631  }
632 
633  label nFaces = edgeToFace();
634 
635  if (debug)
636  {
637  Pout<< "Total changed faces : " << nFaces << endl;
638  }
639 
640  if (nFaces == 0)
641  {
642  break;
643  }
644 
645  label nEdges = faceToEdge();
646 
647  if (debug)
648  {
649  Pout<< "Total changed edges : " << nEdges << nl
650  << "Total evaluations : " << nEvals_ << nl
651  << "Remaining unvisited edges : " << nUnvisitedEdges_ << nl
652  << "Remaining unvisited faces : " << nUnvisitedFaces_ << nl
653  << endl;
654  }
655 
656  if (nEdges == 0)
657  {
658  break;
659  }
660 
661  iter++;
662  }
663 
664  return iter;
665 }
666 
667 
668 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
label getUnsetFaces() const
Get number of unvisited faces, i.e. faces that were not (yet)
PatchEdgeFaceWave(const polyMesh &mesh, const PrimitivePatchType &patch, const labelList &initialEdges, const List< Type > &initialEdgesInfo, UList< Type > &allEdgeInfo, UList< Type > &allFaceInfo, const label maxIter, TrackingData &td=defaultTrackingData_)
Construct from patch, list of changed edges with the Type.
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
Wave propagation of information along patch. Every iteration information goes through one layer of fa...
label faceToEdge()
Propagate from face to edge. Returns total number of edges.
label edgeToFace()
Propagate from edge to face. Returns total number of faces.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
errorManip< error > abort(error &err)
Definition: errorManip.H:131
label iterate(const label maxIter)
Iterate until no changes or maxIter reached. Returns actual.
static const char nl
Definition: Ostream.H:260
void setEdgeInfo(const labelList &changedEdges, const List< Type > &changedEdgesInfo)
Copy initial data into allEdgeInfo_.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76