Loading...
Searching...
No Matches
mapDistributeBaseTemplates.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) 2015-2017 OpenFOAM Foundation
9 Copyright (C) 2015-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 "Pstream.H"
30#include "PstreamBuffers.H"
31#include "flipOp.H"
32
33// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34
35template<class T, class CombineOp, class NegateOp>
37(
38 UList<T>& lhs,
39 const UList<T>& rhs,
40
41 const labelUList& map,
42 const bool hasFlip,
43 const CombineOp& cop,
44 const NegateOp& negOp
45)
46{
47 const label len = map.size();
48
49 // FULLDEBUG: if (lhs.size() < max(map)) FatalError ...;
50 // FULLDEBUG: if (rhs.size() < len) FatalError ...;
51
52 if (hasFlip)
53 {
54 for (label i = 0; i < len; ++i)
55 {
56 const label index = map[i];
57
58 if (index > 0)
59 {
60 cop(lhs[index-1], rhs[i]);
61 }
62 else if (index < 0)
63 {
64 cop(lhs[-index-1], negOp(rhs[i]));
65 }
66 else
67 {
69 << "Illegal flip index '0' at " << i << '/' << map.size()
70 << " for list:" << rhs.size() << nl
71 << exit(FatalError);
72 }
73 }
74 }
75 else
76 {
77 for (label i = 0; i < len; ++i)
78 {
79 cop(lhs[map[i]], rhs[i]);
80 }
81 }
82}
83
84
85template<class T, class NegateOp>
87(
88 UList<T>& output,
89 const UList<T>& values,
90 const labelUList& map,
91 const bool hasFlip,
92 const NegateOp& negOp
93)
94{
95 const label len = map.size();
96
97 // FULLDEBUG: if (values.size() < max(map)) FatalError ...;
98 // FULLDEBUG: if (output.size() < len) FatalError ...;
99
100 if (hasFlip)
101 {
102 for (label i = 0; i < len; ++i)
103 {
104 const label index = map[i];
105
106 if (index > 0)
107 {
108 output[i] = values[index-1];
109 }
110 else if (index < 0)
111 {
112 output[i] = negOp(values[-index-1]);
113 }
114 else
115 {
117 << "Illegal flip index '0' at " << i << '/' << map.size()
118 << " for list:" << values.size() << nl
119 << exit(FatalError);
120 }
121 }
122 }
123 else
124 {
125 // Like indirect list
126 for (label i = 0; i < len; ++i)
127 {
128 output[i] = values[map[i]];
129 }
130 }
131}
132
133
134template<class T, class NegateOp>
136(
137 const UList<T>& values,
138 const labelUList& map,
139 const bool hasFlip,
140 const NegateOp& negOp
141)
142{
143 List<T> output(map.size());
144 accessAndFlip(output, values, map, hasFlip, negOp);
145 return output;
146}
147
148
149template<class T, class negateOp>
151(
152 const labelListList& subMap,
153 const bool subHasFlip,
154 const labelListList& constructMap,
155 const bool constructHasFlip,
156 const UList<T>& field,
157
158 labelRange& sendRequests,
159 PtrList<List<T>>& sendFields,
160
161 labelRange& recvRequests,
162 PtrList<List<T>>& recvFields,
163
164 const negateOp& negOp,
165 const int tag,
166 const label comm
167)
168{
169 if constexpr (!is_contiguous_v<T>)
170 {
172 << "Only contiguous is currently supported"
174 }
175
176 const auto myRank = UPstream::myProcNo(comm);
177 const auto nProcs = UPstream::nProcs(comm);
178
179
180 // Set up receives from neighbours
181 recvRequests.start() = UPstream::nRequests();
182 recvRequests.size() = 0;
183
184 recvFields.resize(nProcs);
185
186 for (const int proci : UPstream::allProcs(comm))
187 {
188 const labelList& map = constructMap[proci];
189
190 if (proci == myRank)
191 {
192 // No communication for myself - but recvFields may be used
193 }
194 else if (map.empty())
195 {
196 // No receive necessary
197 (void) recvFields.release(proci);
198 }
199 else
200 {
201 List<T>& subField = recvFields.try_emplace(proci);
202 subField.resize_nocopy(map.size());
203
205 (
207 proci,
208 subField,
209 tag,
210 comm
211 );
212 }
213 }
214
215 // Finished setting up the receives
216 recvRequests.size() = (UPstream::nRequests() - recvRequests.start());
217
218
219 // Set up sends to neighbours
220 sendRequests.start() = UPstream::nRequests();
221 sendRequests.size() = 0;
222
223 sendFields.resize(nProcs);
224
225 for (const int proci : UPstream::allProcs(comm))
226 {
227 const labelList& map = subMap[proci];
228
229 if (proci == myRank)
230 {
231 // No communication - sendFields not needed
232 (void) sendFields.release(proci);
233 }
234 else if (map.empty())
235 {
236 // No send necessary
237 (void) sendFields.release(proci);
238 }
239 else
240 {
241 List<T>& subField = sendFields.try_emplace(proci);
242 subField.resize_nocopy(map.size());
243
244 accessAndFlip(subField, field, map, subHasFlip, negOp);
245
247 (
249 proci,
250 subField,
251 tag,
252 comm
253 );
254 }
255 }
256
257 // Finished setting up the sends
258 sendRequests.size() = (UPstream::nRequests() - sendRequests.start());
259
260
261 // Set up 'send' to myself - copy directly into recvFields
262 {
263 const labelList& map = subMap[myRank];
264
265 if (map.empty())
266 {
267 // Nothing to send/recv
268 (void) recvFields.release(myRank);
269 }
270 else
271 {
272 List<T>& subField = recvFields.try_emplace(myRank);
273 subField.resize_nocopy(map.size());
274
275 accessAndFlip(subField, field, map, subHasFlip, negOp);
276 }
277 }
278}
279
280
281template<class T>
283(
284 const UList<T>& field,
285 labelRange& sendRequests,
286 PtrList<List<T>>& sendFields,
287 labelRange& recvRequests,
288 PtrList<List<T>>& recvFields,
289 const int tag
290) const
291{
292 send
293 (
294 subMap_,
295 subHasFlip_,
296 constructMap_,
297 constructHasFlip_,
298 field,
299 sendRequests, sendFields,
300 recvRequests, recvFields,
301 flipOp(),
302 tag,
303 comm_
304 );
305}
306
307
308template<class T, class CombineOp, class negateOp>
310(
311 const label constructSize,
312 const labelListList& constructMap,
313 const bool constructHasFlip,
314 const labelRange& requests,
315 const UPtrList<List<T>>& recvFields,
316 List<T>& field,
317 const CombineOp& cop,
318 const negateOp& negOp,
319 const int tag,
320 const label comm
321)
322{
323 if constexpr (!is_contiguous_v<T>)
324 {
326 << "Only contiguous is currently supported"
328 }
329
330 const auto myRank = UPstream::myProcNo(comm);
331 [[maybe_unused]]
332 const auto nProcs = UPstream::nProcs(comm);
333
334
335 // Receiving from which procs - according to map information
336
337 DynamicList<int> recvProcs(nProcs);
338 for (const int proci : UPstream::allProcs(comm))
339 {
340 const labelList& map = constructMap[proci];
341
342 if (proci != myRank && map.size())
343 {
344 recvProcs.push_back(proci);
345
346 const auto* subFieldPtr = recvFields.get(proci);
347 if (subFieldPtr)
348 {
349 checkReceivedSize(proci, map.size(), subFieldPtr->size());
350 }
351 else
352 {
354 << "From processor " << proci
355 << " : unallocated receive field."
356 << " Expected size " << map.size()
357 << " on comm " << comm
358 << " with procs " << UPstream::nProcs(comm) << nl
359 << exit(FatalError);
360 }
361 }
362 }
363
364
365 // Combining bits - can reuse field storage
366 field.resize_nocopy(constructSize);
367
368
369 // Received sub field from myself : recvFields[myRank]
370 if (recvFields.test(myRank))
371 {
372 const labelList& map = constructMap[myRank];
373 const List<T>& subField = recvFields[myRank];
374
375 // Unlikely to need a size check
376 // checkReceivedSize(myRank, map.size(), subField.size());
377
378 flipAndCombine
379 (
380 field,
381 subField,
382 map,
383 constructHasFlip,
384 cop,
385 negOp
386 );
387 }
388
389
390 // NB: do NOT use polling and dispatch here.
391 // There is no certainty if the listed requests are still pending or
392 // have already been waited on before calling this method.
393
394 // Wait for (receive) requests, but the range may also include
395 // other requests depending on what the caller provided
396
397 UPstream::waitRequests(requests.start(), requests.size());
398
399
400 // Process received fields
401
402 {
403 for (const int proci : recvProcs)
404 {
405 const labelList& map = constructMap[proci];
406 const List<T>& subField = recvFields[proci];
407
408 // Already checked the sizes previously
409 // checkReceivedSize(proci, map.size(), subField.size());
410
411 flipAndCombine
412 (
413 field,
414 subField,
415 map,
416 constructHasFlip,
417 cop,
418 negOp
419 );
420 }
421 }
422}
423
424
425template<class T>
427(
428 const labelRange& requests,
429 const UPtrList<List<T>>& recvFields,
430 List<T>& field,
431 const int tag
432) const
433{
434 receive
435 (
436 constructSize_,
437 constructMap_,
438 constructHasFlip_,
439 requests,
440 recvFields,
441 field,
442 eqOp<T>(),
443 flipOp(),
444 tag,
445 comm_
446 );
447}
448
449
450template<class T, class CombineOp, class NegateOp>
452(
453 const UPstream::commsTypes commsType,
454 const UList<labelPair>& schedule,
455 const label constructSize,
456 const labelListList& subMap,
457 const bool subHasFlip,
458 const labelListList& constructMap,
459 const bool constructHasFlip,
460 List<T>& field,
461 const T& nullValue,
462 const CombineOp& cop,
463 const NegateOp& negOp,
464 const int tag,
465 const label comm
466)
467{
468 const auto myRank = UPstream::myProcNo(comm);
469 [[maybe_unused]]
470 const auto nProcs = UPstream::nProcs(comm);
471
472 if (!UPstream::parRun())
473 {
474 // Do only me to me.
475
476 List<T> subField
477 (
478 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
479 );
480
481 // Receive sub field from myself (subField)
482 const labelList& map = constructMap[myRank];
483
484 // Combining bits - can now reuse field storage
485 field.resize_nocopy(constructSize);
486 field = nullValue;
487
488 flipAndCombine
489 (
490 field,
491 subField,
492 map,
493 constructHasFlip,
494 cop,
495 negOp
496 );
497
498 return;
499 }
500
501 if (commsType == UPstream::commsTypes::buffered)
502 {
503 // Since buffered sending can reuse the field to collect the
504 // received data.
505
506 // Send sub field to neighbour
507 for (const int proci : UPstream::allProcs(comm))
508 {
509 const labelList& map = subMap[proci];
510
511 if (proci != myRank && map.size())
512 {
513 List<T> subField
514 (
515 accessAndFlip(field, map, subHasFlip, negOp)
516 );
517
518 // buffered send
519 OPstream os(commsType, proci, 0, tag, comm);
520 os << subField;
521 }
522 }
523
524 {
525 // Subset myself
526 List<T> subField
527 (
528 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
529 );
530
531 // Receive sub field from myself (subField)
532 const labelList& map = constructMap[myRank];
533
534 // Combining bits - can now reuse field storage
535 field.resize_nocopy(constructSize);
536 field = nullValue;
537
538 flipAndCombine
539 (
540 field,
541 subField,
542 map,
543 constructHasFlip,
544 cop,
545 negOp
546 );
547 }
548
549 // Receive and process sub-field from neighbours
550 for (const int proci : UPstream::allProcs(comm))
551 {
552 const labelList& map = constructMap[proci];
553
554 if (proci != myRank && map.size())
555 {
556 List<T> subField;
557 IPstream::recv(subField, proci, tag, comm);
558
559 checkReceivedSize(proci, map.size(), subField.size());
560
561 flipAndCombine
562 (
563 field,
564 subField,
565 map,
566 constructHasFlip,
567 cop,
568 negOp
569 );
570 }
571 }
572 }
573 else if (commsType == UPstream::commsTypes::scheduled)
574 {
575 // Need to make sure I don't overwrite field with received data
576 // since the data might need to be sent to another processor. So
577 // allocate a new field for the results.
578 List<T> newField;
579 newField.resize_nocopy(constructSize);
580 newField = nullValue;
581
582 // First handle self
583 {
584 // Subset myself
585 List<T> subField
586 (
587 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
588 );
589
590 // Receive sub field from myself (subField)
591 const labelList& map = constructMap[myRank];
592
593 flipAndCombine
594 (
595 newField,
596 subField,
597 map,
598 constructHasFlip,
599 cop,
600 negOp
601 );
602 }
603
604
605 // Schedule will already have pruned 0-sized comms
606 for (const labelPair& twoProcs : schedule)
607 {
608 // twoProcs is a swap pair of processors. The first one is the
609 // one that needs to send first and then receive.
610
611 if (twoProcs.first() == myRank)
612 {
613 // I am send first, receive next
614 const label nbrProc = twoProcs.second();
615
616 {
617 const labelList& map = subMap[nbrProc];
618
619 List<T> subField
620 (
621 accessAndFlip(field, map, subHasFlip, negOp)
622 );
623
624 OPstream::send(subField, nbrProc, tag, comm);
625 }
626 {
627 List<T> subField;
628 IPstream::recv(subField, nbrProc, tag, comm);
629
630 const labelList& map = constructMap[nbrProc];
631
632 checkReceivedSize(nbrProc, map.size(), subField.size());
633
634 flipAndCombine
635 (
636 newField,
637 subField,
638 map,
639 constructHasFlip,
640 cop,
641 negOp
642 );
643 }
644 }
645 else
646 {
647 // I am receive first, send next
648 const label nbrProc = twoProcs.first();
649
650 {
651 List<T> subField;
652 IPstream::recv(subField, nbrProc, tag, comm);
653
654 const labelList& map = constructMap[nbrProc];
655
656 checkReceivedSize(nbrProc, map.size(), subField.size());
657
658 flipAndCombine
659 (
660 newField,
661 subField,
662 map,
663 constructHasFlip,
664 cop,
665 negOp
666 );
667 }
668 {
669 const labelList& map = subMap[nbrProc];
670
671 List<T> subField
672 (
673 accessAndFlip(field, map, subHasFlip, negOp)
674 );
675
676 OPstream::send(subField, nbrProc, tag, comm);
677 }
678 }
679 }
680 field.transfer(newField);
681 }
682 else if (commsType == UPstream::commsTypes::nonBlocking)
683 {
684 const label startOfRequests = UPstream::nRequests();
685
686 if constexpr (!is_contiguous_v<T>)
687 {
688 PstreamBuffers pBufs(comm, tag);
689
690 // Stream data into buffer
691 for (const int proci : UPstream::allProcs(comm))
692 {
693 const labelList& map = subMap[proci];
694
695 if (proci != myRank && map.size())
696 {
697 List<T> subField
698 (
699 accessAndFlip(field, map, subHasFlip, negOp)
700 );
701
702 UOPstream os(proci, pBufs);
703 os << subField;
704 }
705 }
706
707 // Initiate receiving - do yet not block
708 pBufs.finishedSends(false);
709
710 {
711 // Set up 'send' to myself
712 List<T> subField
713 (
714 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
715 );
716
717 // Combining bits - can now reuse field storage
718 field.resize_nocopy(constructSize);
719 field = nullValue;
720
721 // Receive sub field from myself
722 const labelList& map = constructMap[myRank];
723
724 flipAndCombine
725 (
726 field,
727 subField,
728 map,
729 constructHasFlip,
730 cop,
731 negOp
732 );
733 }
734
735 // Wait for receive requests (and the send requests too)
736 UPstream::waitRequests(startOfRequests);
737
738 // Receive and process neighbour fields
739 for (const int proci : UPstream::allProcs(comm))
740 {
741 const labelList& map = constructMap[proci];
742
743 if (proci != myRank && map.size())
744 {
745 UIPstream is(proci, pBufs);
746 List<T> subField(is);
747
748 checkReceivedSize(proci, map.size(), subField.size());
749
750 flipAndCombine
751 (
752 field,
753 subField,
754 map,
755 constructHasFlip,
756 cop,
757 negOp
758 );
759 }
760 }
761 }
762 else
763 {
764 // Set up receives from neighbours
765
766 List<List<T>> recvFields(nProcs);
767 DynamicList<int> recvProcs(nProcs);
768
769 for (const int proci : UPstream::allProcs(comm))
770 {
771 const labelList& map = constructMap[proci];
772
773 if (proci != myRank && map.size())
774 {
775 recvProcs.push_back(proci);
776 List<T>& subField = recvFields[proci];
777 subField.resize_nocopy(map.size());
778
780 (
782 proci,
783 subField,
784 tag,
785 comm
786 );
787 }
788 }
789
790
791 // Set up sends to neighbours
792
793 List<List<T>> sendFields(nProcs);
794
795 for (const int proci : UPstream::allProcs(comm))
796 {
797 const labelList& map = subMap[proci];
798
799 if (proci != myRank && map.size())
800 {
801 List<T>& subField = sendFields[proci];
802 subField.resize_nocopy(map.size());
803
804 accessAndFlip(subField, field, map, subHasFlip, negOp);
805
807 (
809 proci,
810 subField,
811 tag,
812 comm
813 );
814 }
815 }
816
817 // Set up 'send' to myself - copy directly into recvFields
818 {
819 const labelList& map = subMap[myRank];
820 List<T>& subField = recvFields[myRank];
821 subField.resize_nocopy(map.size());
822
823 accessAndFlip(subField, field, map, subHasFlip, negOp);
824 }
825
826
827 // Combining bits - can now reuse field storage
828 field.resize_nocopy(constructSize);
829 field = nullValue;
830
831 // Receive sub field from myself : recvFields[myRank]
832 {
833 const labelList& map = constructMap[myRank];
834 const List<T>& subField = recvFields[myRank];
835
836 // Probably don't need a size check
837 // checkReceivedSize(myRank, map.size(), subField.size());
838
839 flipAndCombine
840 (
841 field,
842 subField,
843 map,
844 constructHasFlip,
845 cop,
846 negOp
847 );
848 }
849
850
851 // Poll for completed receive requests and dispatch
852 DynamicList<int> indices(recvProcs.size());
853 while
854 (
856 (
857 startOfRequests,
858 recvProcs.size(),
859 &indices
860 )
861 )
862 {
863 for (const int idx : indices)
864 {
865 const int proci = recvProcs[idx];
866 const labelList& map = constructMap[proci];
867 const List<T>& subField = recvFields[proci];
868
869 // No size check - was dimensioned above
870 // checkReceivedSize(proci, map.size(), subField.size());
871
872 flipAndCombine
873 (
874 field,
875 subField,
876 map,
877 constructHasFlip,
878 cop,
879 negOp
880 );
881 }
882 }
883
884 // Wait for any remaining requests
885 UPstream::waitRequests(startOfRequests);
886 }
887 }
888 else
889 {
891 << "Unknown communication schedule " << int(commsType)
892 << abort(FatalError);
893 }
894}
895
896
897template<class T, class CombineOp, class NegateOp>
899(
900 const UPstream::commsTypes commsType,
901 const UList<labelPair>& schedule,
902
903 const UList<T>& inField, // input field
904 const labelListList& subMap,
905 const bool subHasFlip,
906
907 List<T>& field,
908 const label constructSize,
909 const labelListList& constructMap,
910 const bool constructHasFlip,
911 const T& nullValue,
912 const CombineOp& cop,
913 const NegateOp& negOp,
914
915 const int tag,
916 const label comm
917)
918{
919 const auto myRank = UPstream::myProcNo(comm);
920 const auto nProcs = UPstream::nProcs(comm);
921
922 if (!UPstream::parRun())
923 {
924 // Do only me to me.
925
926 List<T> subField
927 (
928 accessAndFlip(inField, subMap[myRank], subHasFlip, negOp)
929 );
930
931 // Receive sub field from myself (subField)
932 const labelList& map = constructMap[myRank];
933
934 // Combining bits - can now reuse field storage
935 field.resize_nocopy(constructSize);
936 field = nullValue;
937
938 flipAndCombine
939 (
940 field,
941 subField,
942 map,
943 constructHasFlip,
944 cop,
945 negOp
946 );
947
948 return;
949 }
950
951 if (commsType != UPstream::commsTypes::nonBlocking)
952 {
954 << "Unsupport communication type " << int(commsType)
955 << abort(FatalError);
956 }
957
958 const label startOfRequests = UPstream::nRequests();
959
960 if constexpr (!is_contiguous_v<T>)
961 {
962 PstreamBuffers pBufs(comm, tag);
963
964 // Stream data into buffer
965 for (const int proci : UPstream::allProcs(comm))
966 {
967 const labelList& map = subMap[proci];
968
969 if (proci != myRank && map.size())
970 {
971 List<T> subField
972 (
973 accessAndFlip(inField, map, subHasFlip, negOp)
974 );
975
976 UOPstream os(proci, pBufs);
977 os << subField;
978 }
979 }
980
981 // Initiate receiving - do yet not block
982 pBufs.finishedSends(false);
983
984 {
985 // Set up 'send' to myself
986 List<T> subField
987 (
988 accessAndFlip(inField, subMap[myRank], subHasFlip, negOp)
989 );
990
991 // Combining bits - can now reuse field storage
992 field.resize_nocopy(constructSize);
993 field = nullValue;
994
995 // Receive sub field from myself
996 const labelList& map = constructMap[myRank];
997
998 flipAndCombine
999 (
1000 field,
1001 subField,
1002 map,
1003 constructHasFlip,
1004 cop,
1005 negOp
1006 );
1007 }
1008
1009 // Wait for receive requests (and the send requests too)
1010 UPstream::waitRequests(startOfRequests);
1011
1012 // Receive and process neighbour fields
1013 for (const int proci : UPstream::allProcs(comm))
1014 {
1015 const labelList& map = constructMap[proci];
1016
1017 if (proci != myRank && map.size())
1018 {
1019 UIPstream is(proci, pBufs);
1020 List<T> subField(is);
1021
1022 checkReceivedSize(proci, map.size(), subField.size());
1023
1024 flipAndCombine
1025 (
1026 field,
1027 subField,
1028 map,
1029 constructHasFlip,
1030 cop,
1031 negOp
1032 );
1033 }
1034 }
1035 }
1036 else
1037 {
1038 // Set up receives from neighbours
1039
1040 List<List<T>> recvFields(nProcs);
1041 DynamicList<int> recvProcs(nProcs);
1042
1043 for (const int proci : UPstream::allProcs(comm))
1044 {
1045 const labelList& map = constructMap[proci];
1046
1047 if (proci != myRank && map.size())
1048 {
1049 recvProcs.push_back(proci);
1050 List<T>& subField = recvFields[proci];
1051 subField.resize_nocopy(map.size());
1052
1054 (
1056 proci,
1057 subField.data_bytes(),
1058 subField.size_bytes(),
1059 tag,
1060 comm
1061 );
1062 }
1063 }
1064
1065
1066 // Set up sends to neighbours
1067
1068 List<List<T>> sendFields(nProcs);
1069
1070 for (const int proci : UPstream::allProcs(comm))
1071 {
1072 const labelList& map = subMap[proci];
1073
1074 if (proci != myRank && map.size())
1075 {
1076 List<T>& subField = sendFields[proci];
1077 subField.resize_nocopy(map.size());
1078
1079 accessAndFlip(subField, inField, map, subHasFlip, negOp);
1080
1082 (
1084 proci,
1085 subField.cdata_bytes(),
1086 subField.size_bytes(),
1087 tag,
1088 comm
1089 );
1090 }
1091 }
1092
1093 // Set up 'send' to myself - copy directly into recvFields
1094 {
1095 const labelList& map = subMap[myRank];
1096 List<T>& subField = recvFields[myRank];
1097 subField.resize_nocopy(map.size());
1098
1099 accessAndFlip(subField, inField, map, subHasFlip, negOp);
1100 }
1101
1102
1103 // Combining bits - can now reuse field storage
1104 field.resize_nocopy(constructSize);
1105 field = nullValue;
1106
1107 // Receive sub field from myself : recvFields[myRank]
1108 {
1109 const labelList& map = constructMap[myRank];
1110 const List<T>& subField = recvFields[myRank];
1111
1112 // Probably don't need a size check
1113 // checkReceivedSize(myRank, map.size(), subField.size());
1114
1115 flipAndCombine
1116 (
1117 field,
1118 subField,
1119 map,
1120 constructHasFlip,
1121 cop,
1122 negOp
1123 );
1124 }
1125
1126
1127 // Poll for completed receive requests and dispatch
1128 DynamicList<int> indices(recvProcs.size());
1129 while
1130 (
1132 (
1133 startOfRequests,
1134 recvProcs.size(),
1135 &indices
1136 )
1137 )
1138 {
1139 for (const int idx : indices)
1140 {
1141 const int proci = recvProcs[idx];
1142 const labelList& map = constructMap[proci];
1143 const List<T>& subField = recvFields[proci];
1144
1145 // No size check - was dimensioned above
1146 // checkReceivedSize(proci, map.size(), subField.size());
1147
1148 flipAndCombine
1149 (
1150 field,
1151 subField,
1152 map,
1153 constructHasFlip,
1154 cop,
1155 negOp
1156 );
1157 }
1158 }
1159
1160 // Wait for any remaining requests
1161 UPstream::waitRequests(startOfRequests);
1162 }
1163}
1164
1165
1166template<class T, class NegateOp>
1168(
1169 const UPstream::commsTypes commsType,
1170 const UList<labelPair>& schedule,
1171 const label constructSize,
1172 const labelListList& subMap,
1173 const bool subHasFlip,
1174 const labelListList& constructMap,
1175 const bool constructHasFlip,
1176 List<T>& field,
1177 const NegateOp& negOp,
1178 const int tag,
1179 const label comm
1180)
1181{
1182 const auto myRank = UPstream::myProcNo(comm);
1183 [[maybe_unused]]
1184 const auto nProcs = UPstream::nProcs(comm);
1185
1186 if (!UPstream::parRun())
1187 {
1188 // Do only me to me.
1189
1190 List<T> subField
1191 (
1192 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1193 );
1194
1195 // Receive sub field from myself (subField)
1196 const labelList& map = constructMap[myRank];
1197
1198 // Combining bits - can now reuse field storage
1199 field.resize_nocopy(constructSize);
1200
1201 flipAndCombine
1202 (
1203 field,
1204 subField,
1205 map,
1206 constructHasFlip,
1207 eqOp<T>(),
1208 negOp
1209 );
1210
1211 return;
1212 }
1213
1214 if (commsType == UPstream::commsTypes::buffered)
1215 {
1216 // Since buffered sending can reuse the field to collect the
1217 // received data.
1218
1219 // Send sub field to neighbour
1220 for (const int proci : UPstream::allProcs(comm))
1221 {
1222 const labelList& map = subMap[proci];
1223
1224 if (proci != myRank && map.size())
1225 {
1226 List<T> subField
1227 (
1228 accessAndFlip(field, map, subHasFlip, negOp)
1229 );
1230
1231 // buffered send
1232 OPstream os(commsType, proci, 0, tag, comm);
1233 os << subField;
1234 }
1235 }
1236
1237 {
1238 // Subset myself
1239 List<T> subField
1240 (
1241 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1242 );
1243
1244 // Receive sub field from myself (subField)
1245 const labelList& map = constructMap[myRank];
1246
1247 // Combining bits - can now reuse field storage
1248 field.resize_nocopy(constructSize);
1249
1250 flipAndCombine
1251 (
1252 field,
1253 subField,
1254 map,
1255 constructHasFlip,
1256 eqOp<T>(),
1257 negOp
1258 );
1259 }
1260
1261 // Receive and process sub-field from neighbours
1262 for (const int proci : UPstream::allProcs(comm))
1263 {
1264 const labelList& map = constructMap[proci];
1265
1266 if (proci != myRank && map.size())
1267 {
1268 List<T> subField;
1269 IPstream::recv(subField, proci, tag, comm);
1270
1271 checkReceivedSize(proci, map.size(), subField.size());
1272
1273 flipAndCombine
1274 (
1275 field,
1276 subField,
1277 map,
1278 constructHasFlip,
1279 eqOp<T>(),
1280 negOp
1281 );
1282 }
1283 }
1284 }
1285 else if (commsType == UPstream::commsTypes::scheduled)
1286 {
1287 // Need to make sure I don't overwrite field with received data
1288 // since the data might need to be sent to another processor. So
1289 // allocate a new field for the results.
1290 List<T> newField;
1291 newField.resize_nocopy(constructSize);
1292
1293 // First handle self
1294 {
1295 // Subset myself
1296 List<T> subField
1297 (
1298 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1299 );
1300
1301 // Receive sub field from myself (subField)
1302 const labelList& map = constructMap[myRank];
1303
1304 flipAndCombine
1305 (
1306 newField,
1307 subField,
1308 map,
1309 constructHasFlip,
1310 eqOp<T>(),
1311 negOp
1312 );
1313 }
1314
1315 // Schedule will already have pruned 0-sized comms
1316 for (const labelPair& twoProcs : schedule)
1317 {
1318 // twoProcs is a swap pair of processors. The first one is the
1319 // one that needs to send first and then receive.
1320
1321 if (twoProcs.first() == myRank)
1322 {
1323 // I am send first, receive next
1324 const label nbrProc = twoProcs.second();
1325
1326 {
1327 const labelList& map = subMap[nbrProc];
1328 List<T> subField
1329 (
1330 accessAndFlip(field, map, subHasFlip, negOp)
1331 );
1332
1333 OPstream::send(subField, nbrProc, tag, comm);
1334 }
1335 {
1336 List<T> subField;
1337 IPstream::recv(subField, nbrProc, tag, comm);
1338
1339 const labelList& map = constructMap[nbrProc];
1340
1341 checkReceivedSize(nbrProc, map.size(), subField.size());
1342
1343 flipAndCombine
1344 (
1345 newField,
1346 subField,
1347 map,
1348 constructHasFlip,
1349 eqOp<T>(),
1350 negOp
1351 );
1352 }
1353 }
1354 else
1355 {
1356 // I am receive first, send next
1357 const label nbrProc = twoProcs.first();
1358
1359 {
1360 List<T> subField;
1361 IPstream::recv(subField, nbrProc, tag, comm);
1362
1363 const labelList& map = constructMap[nbrProc];
1364
1365 checkReceivedSize(nbrProc, map.size(), subField.size());
1366
1367 flipAndCombine
1368 (
1369 newField,
1370 subField,
1371 map,
1372 constructHasFlip,
1373 eqOp<T>(),
1374 negOp
1375 );
1376 }
1377 {
1378 const labelList& map = subMap[nbrProc];
1379 List<T> subField
1380 (
1381 accessAndFlip(field, map, subHasFlip, negOp)
1382 );
1383
1384 OPstream::send(subField, nbrProc, tag, comm);
1385 }
1386 }
1387 }
1388 field.transfer(newField);
1389 }
1390 else if (commsType == UPstream::commsTypes::nonBlocking)
1391 {
1392 const label startOfRequests = UPstream::nRequests();
1393
1394 if constexpr (!is_contiguous_v<T>)
1395 {
1396 PstreamBuffers pBufs(comm, tag);
1397
1398 // Stream data into buffer
1399 for (const int proci : UPstream::allProcs(comm))
1400 {
1401 const labelList& map = subMap[proci];
1402
1403 if (proci != myRank && map.size())
1404 {
1405 List<T> subField
1406 (
1407 accessAndFlip(field, map, subHasFlip, negOp)
1408 );
1409
1410 UOPstream os(proci, pBufs);
1411 os << subField;
1412 }
1413 }
1414
1415 // Initiate receiving - do yet not block
1416 pBufs.finishedSends(false);
1417
1418 {
1419 // Set up 'send' to myself
1420 List<T> subField
1421 (
1422 accessAndFlip(field, subMap[myRank], subHasFlip, negOp)
1423 );
1424
1425 // Combining bits - can now reuse field storage
1426 field.resize_nocopy(constructSize);
1427
1428 // Receive sub field from myself
1429 const labelList& map = constructMap[myRank];
1430
1431 flipAndCombine
1432 (
1433 field,
1434 subField,
1435 map,
1436 constructHasFlip,
1437 eqOp<T>(),
1438 negOp
1439 );
1440 }
1441
1442 // Wait for receive requests (and the send requests too)
1443 UPstream::waitRequests(startOfRequests);
1444
1445 // Receive and process neighbour fields
1446 for (const int proci : UPstream::allProcs(comm))
1447 {
1448 const labelList& map = constructMap[proci];
1449
1450 if (proci != myRank && map.size())
1451 {
1452 UIPstream is(proci, pBufs);
1453 List<T> subField(is);
1454
1455 checkReceivedSize(proci, map.size(), subField.size());
1456
1457 flipAndCombine
1458 (
1459 field,
1460 subField,
1461 map,
1462 constructHasFlip,
1463 eqOp<T>(),
1464 negOp
1465 );
1466 }
1467 }
1468 }
1469 else
1470 {
1471 // Set up receives from neighbours
1472
1473 List<List<T>> recvFields(nProcs);
1474 DynamicList<int> recvProcs(nProcs);
1475
1476 for (const int proci : UPstream::allProcs(comm))
1477 {
1478 const labelList& map = constructMap[proci];
1479
1480 if (proci != myRank && map.size())
1481 {
1482 recvProcs.push_back(proci);
1483 List<T>& subField = recvFields[proci];
1484 subField.resize_nocopy(map.size());
1485
1487 (
1489 proci,
1490 subField,
1491 tag,
1492 comm
1493 );
1494 }
1495 }
1496
1497
1498 // Set up sends to neighbours
1499
1500 List<List<T>> sendFields(nProcs);
1501
1502 for (const int proci : UPstream::allProcs(comm))
1503 {
1504 const labelList& map = subMap[proci];
1505
1506 if (proci != myRank && map.size())
1507 {
1508 List<T>& subField = sendFields[proci];
1509 subField.resize_nocopy(map.size());
1510
1511 accessAndFlip(subField, field, map, subHasFlip, negOp);
1512
1514 (
1516 proci,
1517 subField,
1518 tag,
1519 comm
1520 );
1521 }
1522 }
1523
1524 // Set up 'send' to myself - copy directly into recvFields
1525 {
1526 const labelList& map = subMap[myRank];
1527 List<T>& subField = recvFields[myRank];
1528 subField.resize_nocopy(map.size());
1529
1530 accessAndFlip(subField, field, map, subHasFlip, negOp);
1531 }
1532
1533
1534 // Combining bits - can now reuse field storage
1535 field.resize_nocopy(constructSize);
1536
1537
1538 // Receive sub field from myself : recvFields[myRank]
1539 {
1540 const labelList& map = constructMap[myRank];
1541 const List<T>& subField = recvFields[myRank];
1542
1543 // Probably don't need a size check
1544 // checkReceivedSize(myRank, map.size(), subField.size());
1545
1546 flipAndCombine
1547 (
1548 field,
1549 subField,
1550 map,
1551 constructHasFlip,
1552 eqOp<T>(),
1553 negOp
1554 );
1555 }
1556
1557
1558 // Poll for completed receive requests and dispatch
1559 DynamicList<int> indices(recvProcs.size());
1560 while
1561 (
1563 (
1564 startOfRequests,
1565 recvProcs.size(),
1566 &indices
1567 )
1568 )
1569 {
1570 for (const int idx : indices)
1571 {
1572 const int proci = recvProcs[idx];
1573 const labelList& map = constructMap[proci];
1574 const List<T>& subField = recvFields[proci];
1575
1576 // No size check - was dimensioned above
1577 // checkReceivedSize(proci, map.size(), subField.size());
1578
1579 flipAndCombine
1580 (
1581 field,
1582 subField,
1583 map,
1584 constructHasFlip,
1585 eqOp<T>(),
1586 negOp
1587 );
1588 }
1589 }
1590
1591 // Wait for any remaining requests
1592 UPstream::waitRequests(startOfRequests);
1593 }
1594 }
1595 else
1596 {
1598 << "Unknown communication schedule " << int(commsType)
1599 << abort(FatalError);
1600 }
1601}
1602
1603
1604template<class T>
1606(
1607 PstreamBuffers& pBufs,
1608 const UList<T>& field
1609) const
1610{
1611 // Stream data into buffer
1612 for (const int proci : UPstream::allProcs(comm_))
1613 {
1614 const labelList& map = subMap_[proci];
1615
1616 if (map.size())
1617 {
1618 List<T> subField
1619 (
1620 accessAndFlip(field, map, subHasFlip_, flipOp())
1621 );
1622
1623 UOPstream os(proci, pBufs);
1624 os << subField;
1625 }
1626 }
1628 // Start sending and receiving but do not block.
1629 pBufs.finishedSends(false);
1630}
1631
1632
1633template<class T>
1635(
1636 PstreamBuffers& pBufs,
1637 List<T>& field
1638) const
1639{
1640 // Consume
1641 field.resize_nocopy(constructSize_);
1642
1643 for (const int proci : UPstream::allProcs(comm_))
1644 {
1645 const labelList& map = constructMap_[proci];
1646
1647 if (map.size())
1648 {
1649 UIPstream is(proci, pBufs);
1650 List<T> subField(is);
1651
1652 checkReceivedSize(proci, map.size(), subField.size());
1653
1654 flipAndCombine
1655 (
1656 field,
1657 subField,
1658 map,
1659 constructHasFlip_,
1660 eqOp<T>(),
1661 flipOp()
1663 }
1664 }
1665}
1666
1667
1668template<class T, class NegateOp>
1670(
1671 const UPstream::commsTypes commsType,
1672 List<T>& values,
1673 const NegateOp& negOp,
1674 const int tag
1675) const
1676{
1677 distribute
1678 (
1679 commsType,
1680 whichSchedule(commsType),
1681 constructSize_,
1682 subMap_,
1683 subHasFlip_,
1684 constructMap_,
1685 constructHasFlip_,
1686 values,
1687 negOp,
1688 tag,
1689 comm_
1690 );
1691}
1692
1693
1694template<class T, class NegateOp>
1696(
1697 const UPstream::commsTypes commsType,
1698 const T& nullValue,
1699 List<T>& values,
1700 const NegateOp& negOp,
1701 const int tag
1702) const
1703{
1704 distribute
1705 (
1706 commsType,
1707 whichSchedule(commsType),
1708 constructSize_,
1709 subMap_,
1710 subHasFlip_,
1711 constructMap_,
1712 constructHasFlip_,
1713 values,
1714 nullValue,
1715 eqOp<T>(),
1716 negOp,
1717 tag,
1718 comm_
1719 );
1720}
1721
1722
1723template<class T, class NegateOp>
1725(
1726 List<T>& values,
1727 const NegateOp& negOp,
1728 const int tag
1729) const
1730{
1731 distribute
1733 UPstream::defaultCommsType, values, negOp, tag
1734 );
1735}
1736
1737
1738template<class T>
1740(
1741 const UPstream::commsTypes commsType,
1742 List<T>& values,
1743 const int tag
1744) const
1745{
1746 distribute(commsType, values, flipOp(), tag);
1747}
1748
1749
1750template<class T>
1752(
1753 const UPstream::commsTypes commsType,
1754 DynamicList<T>& values,
1755 const int tag
1756) const
1757{
1758 List<T> work(std::move(values));
1759
1760 distribute(commsType, work, tag);
1761
1762 values = std::move(work);
1763}
1764
1765
1766template<class T>
1768(
1769 List<T>& values,
1770 const int tag
1771) const
1772{
1774}
1775
1776
1777template<class T>
1779(
1780 DynamicList<T>& values,
1781 const int tag
1782) const
1783{
1785}
1786
1787
1788template<class T>
1790(
1791 const UPstream::commsTypes commsType,
1792 const label constructSize,
1793 List<T>& values,
1794 const int tag
1795) const
1796{
1797 reverseDistribute<T, flipOp>
1798 (
1799 commsType,
1800 constructSize,
1801 values,
1803 tag
1804 );
1805}
1806
1807
1808template<class T, class NegateOp>
1810(
1811 const UPstream::commsTypes commsType,
1812 const label constructSize,
1813 List<T>& values,
1814 const NegateOp& negOp,
1815 const int tag
1816) const
1817{
1818 distribute
1819 (
1820 commsType,
1821 whichSchedule(commsType),
1822 constructSize,
1823 constructMap_,
1824 constructHasFlip_,
1825 subMap_,
1826 subHasFlip_,
1827 values,
1828 negOp,
1829 tag,
1830 comm_
1831 );
1832}
1833
1834
1835template<class T>
1837(
1838 const UPstream::commsTypes commsType,
1839 const label constructSize,
1840 const T& nullValue,
1841 List<T>& values,
1842 const int tag
1843) const
1844{
1845 distribute
1846 (
1847 commsType,
1848 whichSchedule(commsType),
1849 constructSize,
1850 constructMap_,
1851 constructHasFlip_,
1852 subMap_,
1853 subHasFlip_,
1854 values,
1855
1856 nullValue,
1857 eqOp<T>(),
1858 flipOp(),
1859
1860 tag,
1861 comm_
1862 );
1863}
1864
1865
1866template<class T>
1868(
1869 const label constructSize,
1870 List<T>& values,
1871 const int tag
1872) const
1873{
1874 reverseDistribute
1875 (
1877 constructSize,
1878 values,
1879 tag
1880 );
1881}
1882
1883
1884template<class T>
1886(
1887 const label constructSize,
1888 const T& nullValue,
1889 List<T>& values,
1890 const int tag
1891) const
1892{
1893 reverseDistribute
1894 (
1896 constructSize,
1897 nullValue,
1898 values,
1899 tag
1900 );
1901}
1902
1903
1904// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void push_back(const T &val)
Copy append an element to the end of this list.
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition IPstream.H:80
IntType start() const noexcept
The (inclusive) lower value of the range.
Definition IntRange.H:218
IntType size() const noexcept
The size of the range.
Definition IntRange.H:208
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
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
Output inter-processor communications stream.
Definition OPstream.H:53
Buffers for inter-processor communications streams (UOPstream, UIPstream).
void finishedSends(const bool wait=true)
Mark the send phase as being finished.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UIPstream.H:313
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr)
Receive buffer contents (contiguous types) from given processor.
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
char * data_bytes() noexcept
Return pointer to the underlying array serving as data storage,.
Definition UListI.H:288
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
const char * cdata_bytes() const noexcept
Return pointer to the underlying array serving as data storage,.
Definition UListI.H:281
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
std::streamsize size_bytes() const noexcept
Number of contiguous bytes for the List data.
Definition UListI.H:295
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UOPstream.H:408
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents (contiguous types only) to given processor.
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition OPstreams.C:84
static bool waitSomeRequests(label pos, label len=-1, DynamicList< int > *indices=nullptr)
Wait until some requests (from position onwards) have finished. Corresponds to MPI_Waitsome().
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:1706
static label nRequests() noexcept
Number of outstanding requests (on the internal list of requests).
commsTypes
Communications types.
Definition UPstream.H:81
@ scheduled
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
Definition UPstream.H:83
@ nonBlocking
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
Definition UPstream.H:84
@ buffered
"buffered" : (MPI_Bsend, MPI_Recv)
Definition UPstream.H:82
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
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:1697
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition UPstream.H:1857
static void waitRequests()
Wait for all requests to finish.
Definition UPstream.H:2497
static commsTypes defaultCommsType
Default commsType.
Definition UPstream.H:1045
static bool & parRun() noexcept
Test if this a parallel run.
Definition UPstream.H:1681
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition UPtrList.H:101
A range or interval of labels defined by a start and a size.
Definition labelRange.H:66
static void accessAndFlip(UList< T > &output, const UList< T > &values, const labelUList &map, const bool hasFlip, const NegateOp &negOp)
Lookup field values at specified map indices and save after any flip negation operations.
const List< labelPair > & whichSchedule(const UPstream::commsTypes commsType) const
Return real or dummy schedule depending on the communication type.
void send(PstreamBuffers &pBufs, const UList< T > &field) const
Do all sends using PstreamBuffers.
const labelListList & constructMap() const noexcept
From subsetted data to new reconstructed data.
void reverseDistribute(const label constructSize, List< T > &values, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType and the default flip/negate operator.
static List< labelPair > schedule(const labelListList &subMap, const labelListList &constructMap, const int tag, const label comm=UPstream::worldComm)
Calculate a communication schedule. See above.
bool constructHasFlip() const noexcept
Does constructMap include a sign.
const labelListList & subMap() const noexcept
From subsetted data back to original data.
static void checkReceivedSize(const label proci, const label expectedSize, const label receivedSize)
Fatal if expected != received size.
bool subHasFlip() const noexcept
Does subMap include a sign.
void receive(PstreamBuffers &pBufs, List< T > &field) const
Do all receives using PstreamBuffers.
static void distribute(const UPstream::commsTypes commsType, const UList< labelPair > &schedule, const label constructSize, const labelListList &subMap, const bool subHasFlip, const labelListList &constructMap, const bool constructHasFlip, List< T > &field, const T &nullValue, const CombineOp &cop, const NegateOp &negOp, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Distribute combine data with specified combine operation and negate operator (for flips).
label comm() const noexcept
The communicator used.
static void flipAndCombine(UList< T > &lhs, const UList< T > &rhs, const labelUList &map, const bool hasFlip, const CombineOp &cop, const NegateOp &negOp)
Combine field values (after any flip negation operation) into the specified mapped target locations.
label constructSize() const noexcept
Constructed data size.
const volScalarField & T
rDeltaTY field()
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition HashOps.H:164
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
errorManip< error > abort(error &err)
Definition errorManip.H:139
void rhs(fvMatrix< typename Expr::value_type > &m, const Expr &expression)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
constexpr bool is_contiguous_v
The is_contiguous value of Type (after stripping of qualifiers).
Definition contiguous.H:77
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
Functor to negate primitives. Dummy for most other types.
Definition flipOp.H:67