Loading...
Searching...
No Matches
FaceCellWave.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-2017 OpenFOAM Foundation
9 Copyright (C) 2018-2025 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
29#include "FaceCellWave.H"
30#include "polyMesh.H"
31#include "processorPolyPatch.H"
32#include "cyclicPolyPatch.H"
33#include "cyclicAMIPolyPatch.H"
34#include "UIPstream.H"
35#include "UOPstream.H"
36#include "PstreamReduceOps.H"
37#include "debug.H"
38#include "typeInfo.H"
39#include "SubField.H"
41
42// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43
44namespace Foam
45{
46 template<class Type, class TrackingData>
47 class combine
48 {
49 //- Combine operator for AMIInterpolation
50
53 const cyclicAMIPolyPatch& patch_;
54
55 public:
56
58 (
60 const cyclicAMIPolyPatch& patch
61 )
62 :
63 solver_(solver),
64 patch_(patch)
65 {}
66
67
68 void operator()
69 (
70 Type& x,
71 const label facei,
72 const Type& y,
73 const scalar weight
74 ) const
75 {
76 if (y.valid(solver_.data()))
77 {
78 label meshFacei = -1;
79 if (patch_.owner())
80 {
81 meshFacei = patch_.start() + facei;
82 }
83 else
84 {
85 meshFacei = patch_.neighbPatch().start() + facei;
86 }
87 x.updateFace
88 (
89 solver_.mesh(),
90 meshFacei,
91 y,
92 solver_.propagationTol(),
93 solver_.data()
94 );
95 }
96 }
97 };
98
99 template<class Type, class TrackingData>
100 class interpolate
101 {
102 //- Combine operator for AMIInterpolation
103
104 FaceCellWave<Type, TrackingData>& solver_;
105
106 const cyclicAMIPolyPatch& patch_;
108 public:
109
111 (
113 const cyclicAMIPolyPatch& patch
114 )
115 :
116 solver_(solver),
117 patch_(patch)
118 {}
119
120
121 void operator()
122 (
123 Type& x,
124 const label localFacei,
125 const label f0i,
126 const Type& y0,
127 const label f1i,
128 const Type& y1,
129 const scalar weight
130 ) const
131 {
132 if (y0.valid(solver_.data()))
133 {
134 if (y1.valid(solver_.data()))
135 {
136 x.interpolate
137 (
138 solver_.mesh(),
139 patch_.faceCentres()[localFacei],
140 f0i,
141 y0,
142 f1i,
143 y1,
144 weight,
145 solver_.propagationTol(),
146 solver_.data()
147 );
148 }
149 else
150 {
151 // Convert patch face into mesh face
152 label meshFacei = -1;
153 if (patch_.owner())
154 {
155 meshFacei = patch_.start() + f0i;
156 }
157 else
158 {
159 meshFacei = patch_.neighbPatch().start() + f0i;
160 }
161 x.updateFace
162 (
163 solver_.mesh(),
164 meshFacei,
165 y0,
166 solver_.propagationTol(),
167 solver_.data()
168 );
169 }
170 }
171 else if (y1.valid(solver_.data()))
172 {
173 // Convert patch face into mesh face
174 label meshFacei = -1;
175 if (patch_.owner())
176 {
177 meshFacei = patch_.start() + f1i;
178 }
179 else
180 {
181 meshFacei = patch_.neighbPatch().start() + f1i;
182 }
183 x.updateFace
184 (
185 solver_.mesh(),
186 meshFacei,
187 y1,
188 solver_.propagationTol(),
189 solver_.data()
190 );
191 }
192 }
193 };
194}
195
196
197// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
198
199template<class Type, class TrackingData>
201(
202 const label celli,
203 const label neighbourFacei,
204 const Type& neighbourInfo,
205 const scalar tol,
206 Type& cellInfo
207)
208{
209 // Update info for celli, at position pt, with information from
210 // neighbouring face/cell.
211 // Updates:
212 // - changedCell_, changedCells_
213 // - statistics: nEvals_, nUnvisitedCells_
214
215 ++nEvals_;
216
217 const bool wasValid = cellInfo.valid(td_);
218
219 const bool propagate =
221 (
222 mesh_,
223 celli,
224 neighbourFacei,
225 neighbourInfo,
226 tol,
227 td_
228 );
229
230 if (propagate)
231 {
232 if (changedCell_.set(celli))
233 {
234 changedCells_.push_back(celli);
235 }
236 }
237
238 if (!wasValid && cellInfo.valid(td_))
239 {
241 }
242
243 return propagate;
244}
246
247template<class Type, class TrackingData>
249(
250 const label facei,
251 const label neighbourCelli,
252 const Type& neighbourInfo,
253 const scalar tol,
254 Type& faceInfo
255)
256{
257 // Update info for facei, at position pt, with information from
258 // neighbouring face/cell.
259 // Updates:
260 // - changedFace_, changedFaces_,
261 // - statistics: nEvals_, nUnvisitedFaces_
262
263 ++nEvals_;
264
265 const bool wasValid = faceInfo.valid(td_);
266
267 const bool propagate =
268 faceInfo.updateFace
270 mesh_,
271 facei,
272 neighbourCelli,
273 neighbourInfo,
274 tol,
275 td_
276 );
277
278 if (propagate)
279 {
280 if (changedFace_.set(facei))
281 {
282 changedFaces_.push_back(facei);
284 }
285
286 if (!wasValid && faceInfo.valid(td_))
287 {
288 --nUnvisitedFaces_;
289 }
290
291 return propagate;
292}
294
295template<class Type, class TrackingData>
297(
298 const label facei,
299 const Type& neighbourInfo,
300 const scalar tol,
301 Type& faceInfo
302)
303{
304 // Update info for facei, at position pt, with information from
305 // same face.
306 // Updates:
307 // - changedFace_, changedFaces_,
308 // - statistics: nEvals_, nUnvisitedFaces_
309
310 ++nEvals_;
312 const bool wasValid = faceInfo.valid(td_);
313
314 const bool propagate =
315 faceInfo.updateFace
316 (
318 facei,
319 neighbourInfo,
320 tol,
321 td_
322 );
323
324 if (propagate)
325 {
326 if (changedFace_.set(facei))
327 {
328 changedFaces_.push_back(facei);
329 }
330 }
331
332 if (!wasValid && faceInfo.valid(td_))
335 }
336
337 return propagate;
338}
340
341template<class Type, class TrackingData>
343(
344 const polyPatch& patch
345) const
346{
347 // For debugging: check status on both sides of cyclic
348
349 const cyclicPolyPatch& nbrPatch =
350 refCast<const cyclicPolyPatch>(patch).neighbPatch();
351
352 forAll(patch, patchFacei)
353 {
354 const label i1 = patch.start() + patchFacei;
355 const label i2 = nbrPatch.start() + patchFacei;
357 if
358 (
359 !allFaceInfo_[i1].sameGeometry
360 (
361 mesh_,
362 allFaceInfo_[i2],
363 geomTol_,
364 td_
365 )
366 )
369 << " faceInfo:" << allFaceInfo_[i1]
370 << " otherfaceInfo:" << allFaceInfo_[i2]
371 << abort(FatalError);
372 }
373
374 if (changedFace_.test(i1) != changedFace_.test(i2))
375 {
377 << " faceInfo:" << allFaceInfo_[i1]
378 << " otherfaceInfo:" << allFaceInfo_[i2]
379 << " changedFace:" << changedFace_.test(i1)
380 << " otherchangedFace:" << changedFace_.test(i2)
381 << abort(FatalError);
382 }
383 }
384}
385
387template<class Type, class TrackingData>
388template<class PatchType>
391 for (const polyPatch& p : mesh_.boundaryMesh())
392 {
393 if (isA<PatchType>(p))
394 {
395 return true;
396 }
398 return false;
399}
401
402template<class Type, class TrackingData>
404(
405 const label facei,
406 const Type& faceInfo
407)
408{
409 const bool wasValid = allFaceInfo_[facei].valid(td_);
410
411 // Copy info for facei
412 allFaceInfo_[facei] = faceInfo;
413
414 // Maintain count of unset faces
415 if (!wasValid && allFaceInfo_[facei].valid(td_))
416 {
418 }
419
420 // Mark facei as visited and changed (both on list and on face itself)
421 changedFace_.set(facei);
422 changedFaces_.push_back(facei);
423}
425
426template<class Type, class TrackingData>
428(
429 const labelUList& changedFaces,
430 const UList<Type>& changedFacesInfo
431)
432{
433 forAll(changedFaces, changedFacei)
434 {
435 const label facei = changedFaces[changedFacei];
436
437 const bool wasValid = allFaceInfo_[facei].valid(td_);
438
439 // Copy info for facei
440 allFaceInfo_[facei] = changedFacesInfo[changedFacei];
441
442 // Maintain count of unset faces
443 if (!wasValid && allFaceInfo_[facei].valid(td_))
444 {
446 }
447
448 // Mark facei as changed, both on list and on face itself.
449 changedFace_.set(facei);
450 changedFaces_.push_back(facei);
451 }
452}
454
455template<class Type, class TrackingData>
457(
458 const polyPatch& patch,
459 const label nFaces,
460 const labelUList& changedFaces,
461 const UList<Type>& changedFacesInfo
462)
463{
464 // Merge face information into member data
465
466 for (label changedFacei = 0; changedFacei < nFaces; ++changedFacei)
467 {
468 const Type& newInfo = changedFacesInfo[changedFacei];
469 const label patchFacei = changedFaces[changedFacei];
470
471 const label meshFacei = patch.start() + patchFacei;
472
473 Type& currInfo = allFaceInfo_[meshFacei];
474
475 if (!currInfo.equal(newInfo, td_))
476 {
478 (
479 meshFacei,
480 newInfo,
482 currInfo
483 );
484 }
485 }
486}
488
489template<class Type, class TrackingData>
491(
492 const polyPatch& patch,
493 const label startFacei,
494 const label nFaces,
495 labelUList& changedPatchFaces,
496 UList<Type>& changedPatchFacesInfo
497) const
498{
499 // Construct compact patchFace change arrays for a (slice of a) single
500 // patch. changedPatchFaces in local patch numbering.
501 // Return length of arrays.
502 label nChanged = 0;
503
504 for (label i = 0; i < nFaces; ++i)
505 {
506 const label patchFacei = i + startFacei;
507 const label meshFacei = patch.start() + patchFacei;
508
509 if (changedFace_.test(meshFacei))
510 {
511 changedPatchFaces[nChanged] = patchFacei;
512 changedPatchFacesInfo[nChanged] = allFaceInfo_[meshFacei];
513 ++nChanged;
514 }
515 }
516
517 return nChanged;
518}
520
521template<class Type, class TrackingData>
523(
524 const polyPatch& patch,
525 const label nFaces,
526 const labelUList& faceLabels,
527 UList<Type>& faceInfo
528) const
529{
530 // Handle leaving domain. Implementation referred to Type
531
532 const vectorField& fc = mesh_.faceCentres();
533
534 for (label i = 0; i < nFaces; ++i)
536 const label patchFacei = faceLabels[i];
537 const label meshFacei = patch.start() + patchFacei;
538
539 faceInfo[i].leaveDomain(mesh_, patch, patchFacei, fc[meshFacei], td_);
540 }
541}
544template<class Type, class TrackingData>
546(
547 const polyPatch& patch,
548 const label nFaces,
549 const labelUList& faceLabels,
550 UList<Type>& faceInfo
551) const
552{
553 // Handle entering domain. Implementation referred to Type
554
555 const vectorField& fc = mesh_.faceCentres();
556
557 for (label i = 0; i < nFaces; ++i)
558 {
559 const label patchFacei = faceLabels[i];
560 const label meshFacei = patch.start() + patchFacei;
561
562 faceInfo[i].enterDomain(mesh_, patch, patchFacei, fc[meshFacei], td_);
563 }
564}
566
567template<class Type, class TrackingData>
569(
570 const tensorField& rotTensor,
571 const label nFaces,
572 UList<Type>& faceInfo
573)
574{
575 // Transform. Implementation referred to Type
576
577 if (rotTensor.size() == 1)
578 {
579 const tensor& T = rotTensor[0];
580
581 for (label facei = 0; facei < nFaces; ++facei)
582 {
583 faceInfo[facei].transform(mesh_, T, td_);
584 }
585 }
586 else
587 {
588 for (label facei = 0; facei < nFaces; ++facei)
589 {
590 faceInfo[facei].transform(mesh_, rotTensor[facei], td_);
591 }
592 }
593}
595
596template<class Type, class TrackingData>
598(
599 const polyPatch&,
600 const label cycOffset,
601 const label nFaces,
602 labelUList& faces
603)
604{
605 // Offset mesh face.
606 // Used for transferring from one cyclic half to the other.
607
608 for (label facei = 0; facei < nFaces; ++facei)
609 {
610 faces[facei] += cycOffset;
611 }
612}
614
615template<class Type, class TrackingData>
617{
618 // Transfer all the information to/from neighbouring processors
619
620 const globalMeshData& pData = mesh_.globalData();
621
622 // Which patches are processor patches
623 const labelList& procPatches = pData.processorPatches();
624
625 // Which processors this processor is connected to
626 const labelList& neighbourProcs = pData.topology().procNeighbours();
627
628 // Reduce communication by only sending non-zero data,
629 // but with multiply-connected processor/processor
630 // (eg, processorCyclic) also need to send zero information
631 // to keep things synchronised
632
633 // Reset buffers, initialize for registerSend() bookkeeping
634 pBufs_.clear();
635 pBufs_.initRegisterSend();
636
637
638 // Information to send
639 DynamicList<Type> sendFacesInfo;
640 DynamicList<label> sendFaces;
641
642 for (const label patchi : procPatches)
643 {
644 const auto& procPatch =
645 refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchi]);
646
647 const label nbrProci = procPatch.neighbProcNo();
648
649 // Resize buffers
650 sendFaces.resize_nocopy(procPatch.size());
651 sendFacesInfo.resize_nocopy(procPatch.size());
652
653 // Determine which faces changed on current patch
654 const label nSendFaces = getChangedPatchFaces
655 (
656 procPatch,
657 0,
658 procPatch.size(),
659 sendFaces,
660 sendFacesInfo
661 );
662
663 // Shrink
664 sendFaces.resize(nSendFaces);
665 sendFacesInfo.resize(nSendFaces);
666
667 // Adapt wallInfo for leaving domain
669 (
670 procPatch,
671 nSendFaces,
672 sendFaces,
673 sendFacesInfo
674 );
675
676 // Send to neighbour
677 {
678 UOPstream toNbr(nbrProci, pBufs_);
679 toNbr << sendFaces << sendFacesInfo;
680
681 // Record if send is required (data are non-zero)
682 pBufs_.registerSend(nbrProci, !sendFaces.empty());
683
684 if (debug & 2)
685 {
686 Pout<< " Processor patch " << patchi << ' ' << procPatch.name()
687 << " send:" << sendFaces.size() << " to proc:" << nbrProci
688 << endl;
689 }
690 }
691 }
692
693 // Limit exchange to involved procs
694 // - automatically discards unnecessary (unregistered) sends
695 pBufs_.finishedNeighbourSends(neighbourProcs);
696
697
698 for (const label patchi : procPatches)
699 {
700 const auto& procPatch =
701 refCast<const processorPolyPatch>(mesh_.boundaryMesh()[patchi]);
702
703 const label nbrProci = procPatch.neighbProcNo();
704
705 if (!pBufs_.recvDataCount(nbrProci))
706 {
707 // Nothing to receive
708 continue;
709 }
710
711
712 labelList receiveFaces;
713 List<Type> receiveFacesInfo;
714 {
715 UIPstream is(nbrProci, pBufs_);
716 is >> receiveFaces >> receiveFacesInfo;
717 }
718
719 const label nReceiveFaces = receiveFaces.size();
720
721 if (debug & 2)
722 {
723 Pout<< " Processor patch " << patchi << ' ' << procPatch.name()
724 << " recv:" << receiveFaces.size() << " from proci:"
725 << nbrProci << endl;
726 }
727
728 // Apply transform to received data for non-parallel planes
729 if (!procPatch.parallel())
730 {
732 (
733 procPatch.forwardT(),
734 nReceiveFaces,
735 receiveFacesInfo
736 );
737 }
738
739 // Adapt wallInfo for entering domain
741 (
742 procPatch,
743 nReceiveFaces,
744 receiveFaces,
745 receiveFacesInfo
746 );
747
748 // Merge received info
750 (
751 procPatch,
752 nReceiveFaces,
753 receiveFaces,
754 receiveFacesInfo
755 );
756 }
757}
759
760template<class Type, class TrackingData>
762{
763 // Transfer information across cyclic halves.
764
765 for (const polyPatch& patch : mesh_.boundaryMesh())
766 {
767 const cyclicPolyPatch* cpp = isA<cyclicPolyPatch>(patch);
768
769 if (cpp)
770 {
771 const auto& cycPatch = *cpp;
772 const auto& nbrPatch = cycPatch.neighbPatch();
773
774 // Allocate buffers
775 labelList receiveFaces(patch.size());
776 List<Type> receiveFacesInfo(patch.size());
777
778 // Determine which faces changed
779 const label nReceiveFaces = getChangedPatchFaces
780 (
781 nbrPatch,
782 0,
783 nbrPatch.size(),
784 receiveFaces,
785 receiveFacesInfo
786 );
787
788 // Adapt wallInfo for leaving domain
790 (
791 nbrPatch,
792 nReceiveFaces,
793 receiveFaces,
794 receiveFacesInfo
795 );
796
797 if (!cycPatch.parallel())
798 {
799 // Received data from other half
801 (
802 cycPatch.forwardT(),
803 nReceiveFaces,
804 receiveFacesInfo
805 );
806 }
807
808 if (debug & 2)
809 {
810 Pout<< " Cyclic patch "
811 << cycPatch.index() << ' ' << cycPatch.name()
812 << " Changed : " << nReceiveFaces
813 << endl;
814 }
815
816 // Half2: Adapt wallInfo for entering domain
818 (
819 cycPatch,
820 nReceiveFaces,
821 receiveFaces,
822 receiveFacesInfo
823 );
824
825 // Merge into global storage
827 (
828 cycPatch,
829 nReceiveFaces,
830 receiveFaces,
831 receiveFacesInfo
832 );
833
834 if (debug)
835 {
836 checkCyclic(cycPatch);
837 }
838 }
839 }
840}
842
843template<class Type, class TrackingData>
845{
846 // Transfer information across cyclicAMI halves.
847
848 for (const polyPatch& patch : mesh_.boundaryMesh())
849 {
851
852 // Note:
853 // - can either do owner and neighbour separately or have owner
854 // do both
855 // - separately means that neighbour will receive updated owner
856 // properties which might be beneficial or involve extra work?
857
858 if (cpp)
859 {
860 const auto& cycPatch = *cpp;
861 const auto& nbrPatch = cycPatch.neighbPatch();
862
863 List<Type> receiveInfo(cycPatch.size());
864
865 {
866 // Get nbrPatch data (so not just changed faces). Do not use
867 // a slice here since the leaveDomain might change the values
868 List<Type> sendInfo(nbrPatch.patchSlice(allFaceInfo_));
869
870 if (!nbrPatch.parallel() || nbrPatch.separated())
871 {
872 // Adapt sendInfo for leaving domain
873 const vectorField::subField fc = nbrPatch.faceCentres();
874 forAll(sendInfo, i)
875 {
876 sendInfo[i].leaveDomain(mesh_, nbrPatch, i, fc[i], td_);
877 }
878 }
879
880 // Transfer sendInfo to cycPatch
881 combine<Type, TrackingData> cmb(*this, cycPatch);
882
883 // Linear interpolation
884 interpolate<Type, TrackingData> interp(*this, cycPatch);
885
886 const auto& AMI =
887 (
888 cycPatch.owner()
889 ? cycPatch.AMI()
890 : cycPatch.neighbPatch().AMI()
891 );
892
893 if (cycPatch.applyLowWeightCorrection())
894 {
895 const List<Type> defVals
896 (
897 cycPatch.patchInternalList(allCellInfo_)
898 );
899
900 AMI.interpolate
901 (
902 cycPatch.owner(),
903 sendInfo,
904 cmb,
905 interp,
906 receiveInfo,
907 defVals
908 );
909 }
910 else
911 {
912 AMI.interpolate
913 (
914 cycPatch.owner(),
915 sendInfo,
916 cmb,
917 interp,
918 receiveInfo,
919 UList<Type>::null() // no default values needed
920 );
921 }
922 }
923
924 // Apply transform to received data for non-parallel planes
925 if (!cycPatch.parallel())
926 {
928 (
929 cycPatch.forwardT(),
930 receiveInfo.size(),
931 receiveInfo
932 );
933 }
934
935 if (!cycPatch.parallel() || cycPatch.separated())
936 {
937 // Adapt receiveInfo for entering domain
938 const vectorField::subField fc = cycPatch.faceCentres();
939 forAll(receiveInfo, i)
940 {
941 receiveInfo[i].enterDomain(mesh_, cycPatch, i, fc[i], td_);
942 }
943 }
944
945 // Merge into global storage
946
947 const auto areaFraction(patch.areaFraction());
948
949 forAll(receiveInfo, i)
950 {
951 if (areaFraction && areaFraction()[i] <= 0.5)
952 {
953 // not coupled
954 continue;
955 }
956
957 const label meshFacei = cycPatch.start()+i;
958
959 const Type& newInfo = receiveInfo[i];
960
961 Type& currInfo = allFaceInfo_[meshFacei];
962
963 if (newInfo.valid(td_) && !currInfo.equal(newInfo, td_))
964 {
966 (
967 meshFacei,
968 newInfo,
970 currInfo
971 );
972 }
973 }
974 }
975 }
976}
978
979template<class Type, class TrackingData>
981{
982 changedBaffles_.clear();
983
984 // Collect all/any changed information touching a baffle
985 for (const labelPair& baffle : explicitConnections_)
986 {
987 const label f0 = baffle.first();
988 const label f1 = baffle.second();
989
990 if (changedFace_.test(f0))
991 {
992 // f0 changed. Update information on f1.
993 changedBaffles_.push_back(taggedInfoType(f1, allFaceInfo_[f0]));
994 }
995
996 if (changedFace_.test(f1))
997 {
998 // f1 changed. Update information on f0.
999 changedBaffles_.push_back(taggedInfoType(f0, allFaceInfo_[f1]));
1000 }
1001 }
1002
1003
1004 // Update other side with changed information
1005
1006 for (const taggedInfoType& updated : changedBaffles_)
1007 {
1008 const label tgtFace = updated.first;
1009 const Type& newInfo = updated.second;
1010
1011 Type& currInfo = allFaceInfo_[tgtFace];
1012
1013 if (!currInfo.equal(newInfo, td_))
1014 {
1016 (
1017 tgtFace,
1018 newInfo,
1020 currInfo
1021 );
1022 }
1023 }
1024
1025 changedBaffles_.clear();
1026}
1027
1028
1029// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1030
1031template<class Type, class TrackingData>
1033(
1034 const polyMesh& mesh,
1037 TrackingData& td
1038)
1039:
1041
1045 td_(td),
1049 (
1051 ),
1052 nEvals_(0)
1053{
1054 if
1055 (
1056 allFaceInfo.size() != mesh_.nFaces()
1057 || allCellInfo.size() != mesh_.nCells()
1058 )
1059 {
1060 FatalErrorInFunction
1061 << "face and cell storage not the size of mesh faces, cells:" << nl
1062 << " allFaceInfo :" << allFaceInfo.size() << nl
1063 << " mesh_.nFaces():" << mesh_.nFaces() << nl
1064 << " allCellInfo :" << allCellInfo.size() << nl
1065 << " mesh_.nCells():" << mesh_.nCells() << endl
1066 << exit(FatalError);
1067 }
1068}
1070
1071template<class Type, class TrackingData>
1073(
1074 const polyMesh& mesh,
1075 const labelUList& changedFaces,
1076 const UList<Type>& changedFacesInfo,
1079 const label maxIter,
1080 TrackingData& td
1081)
1082:
1084
1088 td_(td),
1092 (
1094 ),
1095 nEvals_(0)
1096{
1097 if
1098 (
1099 allFaceInfo.size() != mesh_.nFaces()
1100 || allCellInfo.size() != mesh_.nCells()
1101 )
1102 {
1103 FatalErrorInFunction
1104 << "face and cell storage not the size of mesh faces, cells:" << nl
1105 << " allFaceInfo :" << allFaceInfo.size() << nl
1106 << " mesh_.nFaces():" << mesh_.nFaces() << nl
1107 << " allCellInfo :" << allCellInfo.size() << nl
1108 << " mesh_.nCells():" << mesh_.nCells() << endl
1109 << exit(FatalError);
1110 }
1111
1112 // Copy initial changed faces data
1113 setFaceInfo(changedFaces, changedFacesInfo);
1114
1115 // Iterate until nothing changes
1116 const label iter = iterate(maxIter);
1117
1118 if ((maxIter > 0) && (iter >= maxIter))
1119 {
1121 << "Maximum number of iterations reached. Increase maxIter." << nl
1122 << " maxIter:" << maxIter << nl
1123 << " nChangedCells:" << nChangedCells() << nl
1124 << " nChangedFaces:" << nChangedFaces() << endl
1125 << exit(FatalError);
1126 }
1127}
1129
1130template<class Type, class TrackingData>
1132(
1133 const polyMesh& mesh,
1134 const UList<labelPair>& explicitConnections,
1135 const bool handleCyclicAMI,
1136 const labelUList& changedFaces,
1137 const UList<Type>& changedFacesInfo,
1140 const label maxIter,
1141 TrackingData& td
1142)
1143:
1145
1146 explicitConnections_(explicitConnections),
1149 td_(td),
1153 (
1154 handleCyclicAMI
1156 ),
1157 nEvals_(0)
1158{
1159 if
1160 (
1161 allFaceInfo.size() != mesh_.nFaces()
1162 || allCellInfo.size() != mesh_.nCells()
1163 )
1164 {
1165 FatalErrorInFunction
1166 << "face and cell storage not the size of mesh faces, cells:" << nl
1167 << " allFaceInfo :" << allFaceInfo.size() << nl
1168 << " mesh_.nFaces():" << mesh_.nFaces() << nl
1169 << " allCellInfo :" << allCellInfo.size() << nl
1170 << " mesh_.nCells():" << mesh_.nCells() << endl
1171 << exit(FatalError);
1172 }
1173
1174 // Copy initial changed faces data
1175 setFaceInfo(changedFaces, changedFacesInfo);
1176
1177 // Iterate until nothing changes
1178 const label iter = iterate(maxIter);
1179
1180 if ((maxIter > 0) && (iter >= maxIter))
1181 {
1183 << "Maximum number of iterations reached. Increase maxIter." << nl
1184 << " maxIter:" << maxIter << nl
1185 << " nChangedCells:" << nChangedCells() << nl
1186 << " nChangedFaces:" << nChangedFaces() << endl
1187 << exit(FatalError);
1188 }
1189}
1190
1191
1192// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1193
1194template<class Type, class TrackingData>
1196{
1197 // Propagate face to cell
1198
1199 const labelList& owner = mesh_.faceOwner();
1200 const labelList& neighbour = mesh_.faceNeighbour();
1201 const label nInternalFaces = mesh_.nInternalFaces();
1202
1203 for (const label facei : changedFaces_)
1204 {
1205 if (!changedFace_.test(facei))
1206 {
1208 << "Face " << facei
1209 << " not marked as having been changed"
1210 << abort(FatalError);
1211 }
1212
1213 const Type& newInfo = allFaceInfo_[facei];
1214
1215 // Evaluate all connected cells
1216
1217 // Owner
1218 {
1219 const label celli = owner[facei];
1220 Type& currInfo = allCellInfo_[celli];
1221
1222 if (!currInfo.equal(newInfo, td_))
1223 {
1225 (
1226 celli,
1227 facei,
1228 newInfo,
1230 currInfo
1231 );
1232 }
1233 }
1234
1235 // Neighbour.
1236 if (facei < nInternalFaces)
1237 {
1238 const label celli = neighbour[facei];
1239 Type& currInfo = allCellInfo_[celli];
1240
1241 if (!currInfo.equal(newInfo, td_))
1242 {
1244 (
1245 celli,
1246 facei,
1247 newInfo,
1249 currInfo
1250 );
1251 }
1252 }
1253
1254 // Reset status of face
1255 changedFace_.unset(facei);
1256 }
1257
1258 // Handled all changed faces by now
1259 changedFaces_.clear();
1260
1261 if (debug & 2)
1262 {
1263 Pout<< " Changed cells : " << nChangedCells() << endl;
1264 }
1265
1266 // Number of changedCells over all procs
1268}
1270
1271template<class Type, class TrackingData>
1273{
1274 // Propagate cell to face
1275
1276 const cellList& cells = mesh_.cells();
1277
1278 for (const label celli : changedCells_)
1279 {
1280 if (!changedCell_.test(celli))
1281 {
1283 << "Cell " << celli << " not marked as having been changed"
1284 << abort(FatalError);
1285 }
1286
1287 const Type& newInfo = allCellInfo_[celli];
1288
1289 // Evaluate all connected faces
1290
1291 const labelList& faceLabels = cells[celli];
1292 for (const label facei : faceLabels)
1293 {
1294 Type& currInfo = allFaceInfo_[facei];
1295
1296 if (!currInfo.equal(newInfo, td_))
1297 {
1299 (
1300 facei,
1301 celli,
1302 newInfo,
1304 currInfo
1305 );
1306 }
1307 }
1308
1309 // Reset status of cell
1310 changedCell_.unset(celli);
1311 }
1312
1313 // Handled all changed cells by now
1314 changedCells_.clear();
1315
1316
1317 // Transfer across any explicitly provided internal connections
1319
1321 {
1323 }
1324
1326 {
1328 }
1329
1330 if (Pstream::parRun())
1331 {
1333 }
1334
1335 if (debug & 2)
1336 {
1337 Pout<< " Changed faces : " << nChangedFaces() << endl;
1338 }
1339
1340
1341 // Number of changedFaces over all procs
1343}
1344
1346// Iterate
1347template<class Type, class TrackingData>
1348Foam::label Foam::FaceCellWave<Type, TrackingData>::iterate(const label maxIter)
1349{
1350 if (maxIter < 0)
1351 {
1352 return 0;
1353 }
1354
1356 {
1358 }
1359
1361 {
1363 }
1364
1365 if (Pstream::parRun())
1366 {
1368 }
1369
1370 label iter = 0;
1371
1372 for (/*nil*/; iter < maxIter; ++iter)
1373 {
1374 if (debug)
1375 {
1376 Info<< " Iteration " << iter << endl;
1377 }
1378
1379 nEvals_ = 0;
1380 const label nCells = faceToCell();
1381 const label nFaces = nCells ? cellToFace() : 0;
1382
1383 if (debug)
1384 {
1385 Info<< " Total evaluations : "
1386 << nEvals_ << nl
1387 << " Changed cells / faces : "
1388 << nCells << " / " << nFaces << nl
1389 << " Pending cells / faces : "
1390 << nUnvisitedCells_ << " / " << nUnvisitedFaces_ << nl;
1391 }
1392
1393 if (!nCells || !nFaces)
1394 {
1395 break;
1396 }
1397 }
1398
1399 return iter;
1400}
1401
1402
1403// ************************************************************************* //
scalar y
Inter-processor communication reduction functions.
labelList faceLabels(nFaceLabels)
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void resize_nocopy(const label len)
Alter addressable list size, allocating new space if required without necessarily recovering old cont...
void resize(const label len)
Alter addressable list size, allocating new space if required while recovering old content.
label nChangedFaces() const noexcept
Current number of changed faces.
DynamicList< label > changedCells_
List of changed cells.
DynamicList< label > changedFaces_
List of changed faces.
bitSet changedFace_
Track if face has changed.
PstreamBuffers pBufs_
Buffers when updating processor patches.
static scalar propagationTol_
FaceCellWaveBase(const polyMesh &mesh)
Construct with mesh reference and set initial sizes.
static const scalar geomTol_
label nUnvisitedFaces_
Current count of unvisited faces.
label nChangedCells() const noexcept
Current number of changed cells.
label nUnvisitedCells_
Current count of unvisited cells.
bitSet changedCell_
Track if cell has changed.
const polyMesh & mesh() const noexcept
Return access to the mesh.
const polyMesh & mesh_
Reference to mesh.
Wave propagation of information through grid. Every iteration information goes through one layer of c...
void handleExplicitConnections()
Merge data across explicitly provided local connections.
UList< Type > & allCellInfo_
Information for all cells.
void mergeFaceInfo(const polyPatch &patch, const label nFaces, const labelUList &changedFaces, const UList< Type > &changedFacesInfo)
Merge received patch data into global data.
void handleProcPatches()
Merge data from across processor boundaries.
label nEvals_
Number of evaluations.
DynamicList< taggedInfoType > changedBaffles_
FaceCellWave(const FaceCellWave &)=delete
No copy construct.
bool hasPatch() const
Has cyclic patch?
void leaveDomain(const polyPatch &patch, const label nFaces, const labelUList &faceLabels, UList< Type > &faceInfo) const
Handle leaving domain. Implementation referred to Type.
TrackingData & td_
Additional data to be passed into container.
const TrackingData & data() const noexcept
Additional data to be passed into container.
static void offset(const polyPatch &patch, const label off, const label nFaces, labelUList &faces)
Offset face labels by constant value.
void handleAMICyclicPatches()
Merge data from across AMI cyclics.
void checkCyclic(const polyPatch &pPatch) const
Debugging: check info on both sides of cyclic.
virtual label iterate(const label maxIter)
Iterate until no changes or maxIter reached.
void handleCyclicPatches()
Merge data from across cyclics.
void setFaceInfo(const label facei, const Type &faceInfo)
Set single initial changed face.
label getChangedPatchFaces(const polyPatch &patch, const label startFacei, const label nFaces, labelUList &changedPatchFaces, UList< Type > &changedPatchFacesInfo) const
Extract info for single patch only.
void enterDomain(const polyPatch &patch, const label nFaces, const labelUList &faceLabels, UList< Type > &faceInfo) const
Handle leaving domain. Implementation referred to Type.
bool updateCell(const label celli, const label neighbourFacei, const Type &neighbourInfo, const scalar tol, Type &cellInfo)
Updates cellInfo with information from neighbour.
const labelPairList explicitConnections_
Optional boundary faces that information should travel through.
void transform(const tensorField &rotTensor, const label nFaces, UList< Type > &faceInfo)
Apply transformation to Type.
const bool hasCyclicAMIPatches_
Contains cyclicAMI.
virtual label faceToCell()
Propagate from face to cell.
UList< Type > & allFaceInfo() noexcept
Access allFaceInfo.
bool updateFace(const label facei, const label neighbourCelli, const Type &neighbourInfo, const scalar tol, Type &faceInfo)
Updates faceInfo with information from neighbour.
std::pair< label, Type > taggedInfoType
Information tagged with a source or destination id.
virtual label cellToFace()
Propagate from cell to face.
UList< Type > & allCellInfo() noexcept
Access allCellInfo.
const bool hasCyclicPatches_
Contains cyclics.
SubField< vector > subField
Definition Field.H:183
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
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UIPstream.H:313
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition UList.H:89
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
static const UList< T > & null() noexcept
Return a null UList (reference to a nullObject). Behaves like an empty UList.
Definition UList.H:225
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UOPstream.H:408
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
Holds information regarding type of cell. Used in inside/outside determination in cellClassification.
Definition cellInfo.H:61
bool updateCell(const polyMesh &, const label thisCelli, const label neighbourFacei, const cellInfo &neighbourInfo, const scalar tol, TrackingData &td)
Influence of neighbouring face.
Definition cellInfoI.H:166
bool valid(TrackingData &td) const
Changed or contains original (invalid) value.
Definition cellInfoI.H:106
combine(FaceCellWave< Type, TrackingData > &solver, const cyclicAMIPolyPatch &patch)
virtual bool separated() const
Are the planes separated.
virtual bool parallel() const
Are the cyclic planes parallel.
Cyclic patch for Arbitrary Mesh Interface (AMI).
virtual bool owner() const
Does this side own the patch?
virtual const cyclicAMIPolyPatch & neighbPatch() const
Return a reference to the neighbour patch.
Cyclic plane patch.
const cyclicPolyPatch & neighbPatch() const
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const labelList & processorPatches() const noexcept
Return list of processor patch labels.
const processorTopology & topology() const noexcept
The processor to processor topology.
interpolate(FaceCellWave< Type, TrackingData > &solver, const cyclicAMIPolyPatch &patch)
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
const vectorField::subField faceCentres() const
Return face centres.
Definition polyPatch.C:320
label start() const noexcept
Return start label of this patch in the polyMesh face list.
Definition polyPatch.H:446
const List< T >::subList patchSlice(const UList< T > &values) const
This patch slice from the complete list, which has size mesh::nFaces(), using the number of patch fac...
Definition polyPatch.H:502
const labelList & procNeighbours() const
The neighbour processor connections (ascending order) associated with the local rank.
Base solver class.
Definition solver.H:48
volScalarField & p
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const cellShapeList & cells
wallPoints::trackData td(isBlockedFace, regionToBlockSize)
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
List< label > labelList
A List of labels.
Definition List.H:62
dimensionedScalar y0(const dimensionedScalar &ds)
messageStream Info
Information stream (stdout output on master, null elsewhere).
Tensor< scalar > tensor
Definition symmTensor.H:57
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar y1(const dimensionedScalar &ds)
List< cell > cellList
List of cell.
Definition cellListFwd.H:41
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
errorManip< error > abort(error &err)
Definition errorManip.H:139
Field< vector > vectorField
Specialisation of Field<T> for vector.
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Basic run-time type information using word as the type's name. Used to enhance the standard RTTI to c...