1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
27 #include "PstreamBuffers.H"
28 #include "PstreamCombineReduceOps.H"
29 #include "globalIndexAndTransform.H"
30 #include "transformField.H"
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 void Foam::mapDistribute::distribute
38 const Pstream::commsTypes commsType,
39 const List<labelPair>& schedule,
40 const label constructSize,
41 const labelListList& subMap,
42 const labelListList& constructMap,
46 if (!Pstream::parRun())
50 const labelList& mySubMap = subMap[Pstream::myProcNo()];
52 List<T> subField(mySubMap.size());
55 subField[i] = field[mySubMap[i]];
58 // Receive sub field from myself (subField)
59 const labelList& map = constructMap[Pstream::myProcNo()];
61 field.setSize(constructSize);
65 field[map[i]] = subField[i];
70 if (commsType == Pstream::blocking)
72 // Since buffered sending can reuse the field to collect the
75 // Send sub field to neighbour
76 for (label domain = 0; domain < Pstream::nProcs(); domain++)
78 const labelList& map = subMap[domain];
80 if (domain != Pstream::myProcNo() && map.size())
82 OPstream toNbr(Pstream::blocking, domain);
83 toNbr << UIndirectList<T>(field, map);
88 const labelList& mySubMap = subMap[Pstream::myProcNo()];
90 List<T> subField(mySubMap.size());
93 subField[i] = field[mySubMap[i]];
96 // Receive sub field from myself (subField)
97 const labelList& map = constructMap[Pstream::myProcNo()];
99 field.setSize(constructSize);
103 field[map[i]] = subField[i];
106 // Receive sub field from neighbour
107 for (label domain = 0; domain < Pstream::nProcs(); domain++)
109 const labelList& map = constructMap[domain];
111 if (domain != Pstream::myProcNo() && map.size())
113 IPstream fromNbr(Pstream::blocking, domain);
114 List<T> subField(fromNbr);
116 checkReceivedSize(domain, map.size(), subField.size());
120 field[map[i]] = subField[i];
125 else if (commsType == Pstream::scheduled)
127 // Need to make sure I don't overwrite field with received data
128 // since the data might need to be sent to another processor. So
129 // allocate a new field for the results.
130 List<T> newField(constructSize);
133 UIndirectList<T> subField(field, subMap[Pstream::myProcNo()]);
135 // Receive sub field from myself (subField)
136 const labelList& map = constructMap[Pstream::myProcNo()];
140 newField[map[i]] = subField[i];
143 // Schedule will already have pruned 0-sized comms
146 const labelPair& twoProcs = schedule[i];
147 // twoProcs is a swap pair of processors. The first one is the
148 // one that needs to send first and then receive.
150 label sendProc = twoProcs[0];
151 label recvProc = twoProcs[1];
153 if (Pstream::myProcNo() == sendProc)
155 // I am send first, receive next
157 OPstream toNbr(Pstream::scheduled, recvProc);
158 toNbr << UIndirectList<T>(field, subMap[recvProc]);
161 IPstream fromNbr(Pstream::scheduled, recvProc);
162 List<T> subField(fromNbr);
164 const labelList& map = constructMap[recvProc];
166 checkReceivedSize(recvProc, map.size(), subField.size());
170 newField[map[i]] = subField[i];
176 // I am receive first, send next
178 IPstream fromNbr(Pstream::scheduled, sendProc);
179 List<T> subField(fromNbr);
181 const labelList& map = constructMap[sendProc];
183 checkReceivedSize(sendProc, map.size(), subField.size());
187 newField[map[i]] = subField[i];
191 OPstream toNbr(Pstream::scheduled, sendProc);
192 toNbr << UIndirectList<T>(field, subMap[sendProc]);
196 field.transfer(newField);
198 else if (commsType == Pstream::nonBlocking)
200 if (!contiguous<T>())
202 PstreamBuffers pBufs(Pstream::nonBlocking);
204 // Stream data into buffer
205 for (label domain = 0; domain < Pstream::nProcs(); domain++)
207 const labelList& map = subMap[domain];
209 if (domain != Pstream::myProcNo() && map.size())
211 // Put data into send buffer
212 UOPstream toDomain(domain, pBufs);
213 toDomain << UIndirectList<T>(field, map);
218 pBufs.finishedSends();
221 // Set up 'send' to myself
222 const labelList& mySubMap = subMap[Pstream::myProcNo()];
223 List<T> mySubField(mySubMap.size());
226 mySubField[i] = field[mySubMap[i]];
228 // Combine bits. Note that can reuse field storage
229 field.setSize(constructSize);
230 // Receive sub field from myself
232 const labelList& map = constructMap[Pstream::myProcNo()];
236 field[map[i]] = mySubField[i];
242 for (label domain = 0; domain < Pstream::nProcs(); domain++)
244 const labelList& map = constructMap[domain];
246 if (domain != Pstream::myProcNo() && map.size())
248 UIPstream str(domain, pBufs);
249 List<T> recvField(str);
251 checkReceivedSize(domain, map.size(), recvField.size());
255 field[map[i]] = recvField[i];
262 // Set up sends to neighbours
264 List<List<T > > sendFields(Pstream::nProcs());
266 for (label domain = 0; domain < Pstream::nProcs(); domain++)
268 const labelList& map = subMap[domain];
270 if (domain != Pstream::myProcNo() && map.size())
272 List<T>& subField = sendFields[domain];
273 subField.setSize(map.size());
276 subField[i] = field[map[i]];
281 Pstream::nonBlocking,
283 reinterpret_cast<const char*>(subField.begin()),
289 // Set up receives from neighbours
291 List<List<T > > recvFields(Pstream::nProcs());
293 for (label domain = 0; domain < Pstream::nProcs(); domain++)
295 const labelList& map = constructMap[domain];
297 if (domain != Pstream::myProcNo() && map.size())
299 recvFields[domain].setSize(map.size());
302 Pstream::nonBlocking,
304 reinterpret_cast<char*>(recvFields[domain].begin()),
305 recvFields[domain].byteSize()
311 // Set up 'send' to myself
314 const labelList& map = subMap[Pstream::myProcNo()];
316 List<T>& subField = sendFields[Pstream::myProcNo()];
317 subField.setSize(map.size());
320 subField[i] = field[map[i]];
325 // Combine bits. Note that can reuse field storage
327 field.setSize(constructSize);
330 // Receive sub field from myself (sendFields[Pstream::myProcNo()])
332 const labelList& map = constructMap[Pstream::myProcNo()];
333 const List<T>& subField = sendFields[Pstream::myProcNo()];
337 field[map[i]] = subField[i];
342 // Wait for all to finish
344 Pstream::waitRequests();
346 // Collect neighbour fields
348 for (label domain = 0; domain < Pstream::nProcs(); domain++)
350 const labelList& map = constructMap[domain];
352 if (domain != Pstream::myProcNo() && map.size())
354 const List<T>& subField = recvFields[domain];
356 checkReceivedSize(domain, map.size(), subField.size());
360 field[map[i]] = subField[i];
368 FatalErrorIn("mapDistribute::distribute(..)")
369 << "Unknown communication schedule " << commsType
370 << abort(FatalError);
376 template<class T, class CombineOp>
377 void Foam::mapDistribute::distribute
379 const Pstream::commsTypes commsType,
380 const List<labelPair>& schedule,
381 const label constructSize,
382 const labelListList& subMap,
383 const labelListList& constructMap,
385 const CombineOp& cop,
389 if (!Pstream::parRun())
393 const labelList& mySubMap = subMap[Pstream::myProcNo()];
395 List<T> subField(mySubMap.size());
398 subField[i] = field[mySubMap[i]];
401 // Receive sub field from myself (subField)
402 const labelList& map = constructMap[Pstream::myProcNo()];
404 field.setSize(constructSize);
409 cop(field[map[i]], subField[i]);
414 if (commsType == Pstream::blocking)
416 // Since buffered sending can reuse the field to collect the
419 // Send sub field to neighbour
420 for (label domain = 0; domain < Pstream::nProcs(); domain++)
422 const labelList& map = subMap[domain];
424 if (domain != Pstream::myProcNo() && map.size())
426 OPstream toNbr(Pstream::blocking, domain);
427 toNbr << UIndirectList<T>(field, map);
432 const labelList& mySubMap = subMap[Pstream::myProcNo()];
434 List<T> subField(mySubMap.size());
437 subField[i] = field[mySubMap[i]];
440 // Receive sub field from myself (subField)
441 const labelList& map = constructMap[Pstream::myProcNo()];
443 field.setSize(constructSize);
448 cop(field[map[i]], subField[i]);
451 // Receive sub field from neighbour
452 for (label domain = 0; domain < Pstream::nProcs(); domain++)
454 const labelList& map = constructMap[domain];
456 if (domain != Pstream::myProcNo() && map.size())
458 IPstream fromNbr(Pstream::blocking, domain);
459 List<T> subField(fromNbr);
461 checkReceivedSize(domain, map.size(), subField.size());
465 cop(field[map[i]], subField[i]);
470 else if (commsType == Pstream::scheduled)
472 // Need to make sure I don't overwrite field with received data
473 // since the data might need to be sent to another processor. So
474 // allocate a new field for the results.
475 List<T> newField(constructSize, nullValue);
478 UIndirectList<T> subField(field, subMap[Pstream::myProcNo()]);
480 // Receive sub field from myself (subField)
481 const labelList& map = constructMap[Pstream::myProcNo()];
485 cop(newField[map[i]], subField[i]);
488 // Schedule will already have pruned 0-sized comms
491 const labelPair& twoProcs = schedule[i];
492 // twoProcs is a swap pair of processors. The first one is the
493 // one that needs to send first and then receive.
495 label sendProc = twoProcs[0];
496 label recvProc = twoProcs[1];
498 if (Pstream::myProcNo() == sendProc)
500 // I am send first, receive next
502 OPstream toNbr(Pstream::scheduled, recvProc);
503 toNbr << UIndirectList<T>(field, subMap[recvProc]);
506 IPstream fromNbr(Pstream::scheduled, recvProc);
507 List<T> subField(fromNbr);
508 const labelList& map = constructMap[recvProc];
510 checkReceivedSize(recvProc, map.size(), subField.size());
514 cop(newField[map[i]], subField[i]);
520 // I am receive first, send next
522 IPstream fromNbr(Pstream::scheduled, sendProc);
523 List<T> subField(fromNbr);
524 const labelList& map = constructMap[sendProc];
526 checkReceivedSize(sendProc, map.size(), subField.size());
530 cop(newField[map[i]], subField[i]);
534 OPstream toNbr(Pstream::scheduled, sendProc);
535 toNbr << UIndirectList<T>(field, subMap[sendProc]);
539 field.transfer(newField);
541 else if (commsType == Pstream::nonBlocking)
543 if (!contiguous<T>())
545 PstreamBuffers pBufs(Pstream::nonBlocking);
547 // Stream data into buffer
548 for (label domain = 0; domain < Pstream::nProcs(); domain++)
550 const labelList& map = subMap[domain];
552 if (domain != Pstream::myProcNo() && map.size())
554 // Put data into send buffer
555 UOPstream toDomain(domain, pBufs);
556 toDomain << UIndirectList<T>(field, map);
561 pBufs.finishedSends();
564 // Set up 'send' to myself
565 List<T> mySubField(field, subMap[Pstream::myProcNo()]);
566 // Combine bits. Note that can reuse field storage
567 field.setSize(constructSize);
569 // Receive sub field from myself
571 const labelList& map = constructMap[Pstream::myProcNo()];
575 cop(field[map[i]], mySubField[i]);
581 // Wait till all finished
582 UPstream::waitRequests();
585 for (label domain = 0; domain < Pstream::nProcs(); domain++)
587 const labelList& map = constructMap[domain];
589 if (domain != Pstream::myProcNo() && map.size())
591 UIPstream str(domain, pBufs);
592 List<T> recvField(str);
594 checkReceivedSize(domain, map.size(), recvField.size());
598 cop(field[map[i]], recvField[i]);
605 // Set up sends to neighbours
607 List<List<T > > sendFields(Pstream::nProcs());
609 for (label domain = 0; domain < Pstream::nProcs(); domain++)
611 const labelList& map = subMap[domain];
613 if (domain != Pstream::myProcNo() && map.size())
615 List<T>& subField = sendFields[domain];
616 subField.setSize(map.size());
619 subField[i] = field[map[i]];
624 Pstream::nonBlocking,
626 reinterpret_cast<const char*>(subField.begin()),
627 subField.size()*sizeof(T)
632 // Set up receives from neighbours
634 List<List<T > > recvFields(Pstream::nProcs());
636 for (label domain = 0; domain < Pstream::nProcs(); domain++)
638 const labelList& map = constructMap[domain];
640 if (domain != Pstream::myProcNo() && map.size())
642 recvFields[domain].setSize(map.size());
645 Pstream::nonBlocking,
647 reinterpret_cast<char*>(recvFields[domain].begin()),
648 recvFields[domain].size()*sizeof(T)
653 // Set up 'send' to myself
656 const labelList& map = subMap[Pstream::myProcNo()];
658 List<T>& subField = sendFields[Pstream::myProcNo()];
659 subField.setSize(map.size());
662 subField[i] = field[map[i]];
667 // Combine bits. Note that can reuse field storage
669 field.setSize(constructSize);
672 // Receive sub field from myself (subField)
674 const labelList& map = constructMap[Pstream::myProcNo()];
675 const List<T>& subField = sendFields[Pstream::myProcNo()];
679 cop(field[map[i]], subField[i]);
684 // Wait for all to finish
686 Pstream::waitRequests();
688 // Collect neighbour fields
690 for (label domain = 0; domain < Pstream::nProcs(); domain++)
692 const labelList& map = constructMap[domain];
694 if (domain != Pstream::myProcNo() && map.size())
696 const List<T>& subField = recvFields[domain];
698 checkReceivedSize(domain, map.size(), subField.size());
702 cop(field[map[i]], subField[i]);
710 FatalErrorIn("mapDistribute::distribute(..)")
711 << "Unknown communication schedule " << commsType
712 << abort(FatalError);
718 void Foam::mapDistribute::send(PstreamBuffers& pBufs, const List<T>& field)
721 // Stream data into buffer
722 for (label domain = 0; domain < Pstream::nProcs(); domain++)
724 const labelList& map = subMap_[domain];
728 // Put data into send buffer
729 UOPstream toDomain(domain, pBufs);
730 toDomain << UIndirectList<T>(field, map);
734 // Start sending and receiving but do not block.
735 pBufs.finishedSends(false);
740 void Foam::mapDistribute::receive(PstreamBuffers& pBufs, List<T>& field) const
743 field.setSize(constructSize_);
745 for (label domain = 0; domain < Pstream::nProcs(); domain++)
747 const labelList& map = constructMap_[domain];
751 UIPstream str(domain, pBufs);
752 List<T> recvField(str);
754 if (recvField.size() != map.size())
758 "template<class T>\n"
759 "void mapDistribute::receive\n"
761 " PstreamBuffers&,\n"
764 ) << "Expected from processor " << domain
765 << " " << map.size() << " but received "
766 << recvField.size() << " elements."
767 << abort(FatalError);
772 field[map[i]] = recvField[i];
779 // In case of no transform: copy elements
781 void Foam::mapDistribute::applyDummyTransforms(List<T>& field) const
783 forAll(transformElements_, trafoI)
785 const labelList& elems = transformElements_[trafoI];
787 label n = transformStart_[trafoI];
791 field[n++] = field[elems[i]];
797 // In case of no transform: copy elements
799 void Foam::mapDistribute::applyDummyInverseTransforms(List<T>& field) const
801 forAll(transformElements_, trafoI)
803 const labelList& elems = transformElements_[trafoI];
804 label n = transformStart_[trafoI];
808 field[elems[i]] = field[n++];
814 // Calculate transformed elements.
815 template<class T, class TransformOp> //, class CombineOp>
816 void Foam::mapDistribute::applyTransforms
818 const globalIndexAndTransform& globalTransforms,
820 const TransformOp& top
823 const List<vectorTensorTransform>& totalTransform =
824 globalTransforms.transformPermutations();
826 forAll(totalTransform, trafoI)
828 const vectorTensorTransform& vt = totalTransform[trafoI];
829 const labelList& elems = transformElements_[trafoI];
830 label n = transformStart_[trafoI];
832 // Could be optimised to avoid memory allocations
833 List<T> transformFld(UIndirectList<T>(field, elems));
834 top(vt, true, transformFld);
836 forAll(transformFld, i)
838 //cop(field[n++], transformFld[i]);
839 field[n++] = transformFld[i];
845 // Calculate transformed elements.
846 template<class T, class TransformOp> //, class CombineOp>
847 void Foam::mapDistribute::applyInverseTransforms
849 const globalIndexAndTransform& globalTransforms,
851 const TransformOp& top
854 const List<vectorTensorTransform>& totalTransform =
855 globalTransforms.transformPermutations();
857 forAll(totalTransform, trafoI)
859 const vectorTensorTransform& vt = totalTransform[trafoI];
860 const labelList& elems = transformElements_[trafoI];
861 label n = transformStart_[trafoI];
863 // Could be optimised to avoid memory allocations
864 List<T> transformFld(SubList<T>(field, elems.size(), n));
865 top(vt, false, transformFld);
867 forAll(transformFld, i)
869 //cop(field[elems[i]], transformFld[i]);
870 field[elems[i]] = transformFld[i];
876 //- Distribute data using default commsType.
878 void Foam::mapDistribute::distribute
881 const bool dummyTransform
884 if (Pstream::defaultCommsType == Pstream::nonBlocking)
888 Pstream::nonBlocking,
896 else if (Pstream::defaultCommsType == Pstream::scheduled)
921 //- Fill in transformed slots with copies
924 applyDummyTransforms(fld);
929 //- Reverse distribute data using default commsType.
931 void Foam::mapDistribute::reverseDistribute
933 const label constructSize,
935 const bool dummyTransform
940 applyDummyInverseTransforms(fld);
943 if (Pstream::defaultCommsType == Pstream::nonBlocking)
947 Pstream::nonBlocking,
955 else if (Pstream::defaultCommsType == Pstream::scheduled)
982 //- Reverse distribute data using default commsType.
983 // Since constructSize might be larger than supplied size supply
986 void Foam::mapDistribute::reverseDistribute
988 const label constructSize,
991 const bool dummyTransform
996 applyDummyInverseTransforms(fld);
999 if (Pstream::defaultCommsType == Pstream::nonBlocking)
1003 Pstream::nonBlocking,
1013 else if (Pstream::defaultCommsType == Pstream::scheduled)
1044 //- Distribute data using default commsType.
1045 template<class T, class TransformOp>
1046 void Foam::mapDistribute::distribute
1048 const globalIndexAndTransform& git,
1050 const TransformOp& top
1053 // Distribute. Leave out dummy transforms since we're doing them ourselves
1054 distribute(fld, false);
1056 applyTransforms(git, fld, top);
1060 template<class T, class TransformOp>
1061 void Foam::mapDistribute::reverseDistribute
1063 const globalIndexAndTransform& git,
1064 const label constructSize,
1066 const TransformOp& top
1069 // Fill slots with reverse-transformed data. Note that it also copies
1070 // back into the non-remote part of fld even though these values are not
1072 applyInverseTransforms(git, fld, top);
1074 // And send back (the remote slots). Disable dummy transformations.
1075 reverseDistribute(constructSize, fld, false);
1079 template<class T, class TransformOp>
1080 void Foam::mapDistribute::reverseDistribute
1082 const globalIndexAndTransform& git,
1083 const label constructSize,
1086 const TransformOp& top
1089 // Fill slots with reverse-transformed data Note that it also copies
1090 // back into the non-remote part of fld even though these values are not
1092 applyInverseTransforms(git, fld, top); //, eqOp<T>());
1094 // And send back (the remote slots) Disable dummy transformations.
1095 reverseDistribute(constructSize, nullValue, fld, false);
1099 // ************************************************************************* //