ParSortableList.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 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "ParSortableList.H"
29 #include "SortableList.H"
30 #include "Pstream.H"
31 #include "ListListOps.H"
32 #include "PstreamReduceOps.H"
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 template<class Type>
38 (
39  const List<Type>& elems,
40  Ostream& os
41 ) const
42 {
43  os << '(';
44 
45  forAll(elems, elemI)
46  {
47  os << ' ' << elems[elemI];
48  }
49  os << ')';
50 }
51 
52 
53 template<class Type>
55 (
56  const List<Type>& values,
57  const labelList& indices,
58  const label fromProcNo,
59  label& destI,
60  List<taggedValue>& dest
61 ) const
62 {
63  forAll(values, elemI)
64  {
65  taggedValue& tagVal = dest[destI];
66 
67  tagVal.value() = values[elemI];
68  tagVal.index() = indices[elemI];
69  tagVal.procID() = fromProcNo;
70 
71  destI++;
72  }
73 }
74 
75 
76 template<class Type>
78 (
79  const List<Type>& elems,
80  List<Type>& pivots
81 ) const
82 {
83  pivots.setSize(Pstream::nProcs());
84 
85  label pivotPos = 0;
86 
87  forAll(pivots, pivotI)
88  {
89  pivots[pivotI] = elems[pivotPos];
90 
91  pivotPos += elems.size()/Pstream::nProcs();
92  }
93 }
94 
95 
96 template<class Type>
98 (
99  List<Type>& values,
100  labelList& indices,
101  const label bufSize,
102  const label destProci
103 ) const
104 {
105  if (destProci != Pstream::myProcNo())
106  {
107  values.setSize(bufSize);
108  indices.setSize(bufSize);
109 
110  if (debug)
111  {
112  Pout<< "Sending to " << destProci << " elements:" << values
113  << endl;
114  }
115 
116  {
117  OPstream toSlave(Pstream::commsTypes::blocking, destProci);
118  toSlave << values << indices;
119  }
120  }
121 }
122 
123 
124 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
125 
126 template<class Type>
128 :
129  List<Type>(values),
130  indices_(0),
131  procs_(0)
132 {
133  sort();
134 }
135 
136 
137 template<class Type>
139 :
140  List<Type>(size),
141  indices_(0),
142  procs_(0)
143 {}
144 
145 
146 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
147 
148 template<class Type>
150 {
151  //
152  // 0. Get total size of dataset.
153  //
154 
155  label n = this->size();
156 
157  reduce(n, sumOp<label>());
158 
159 
160  // 1. Sort list locally
161  SortableList<Type> sorted(*this);
162 
163  // Collect elements at pivot points
164  labelListList sortedGatherList(Pstream::nProcs());
165 
166  labelList& pivots = sortedGatherList[Pstream::myProcNo()];
167 
168  getPivots(sorted, pivots);
169 
170  if (debug)
171  {
172  Pout<< "pivots:";
173  write(pivots, Pout);
174  Pout<< endl;
175  }
176 
177 
178  //
179  // 2. Combine pivotlist per processor onto master, sort, get pivots.
180  //
181 
182  Pstream::gatherList(sortedGatherList);
183 
184  if (Pstream::master())
185  {
186  labelList allPivots =
187  ListListOps::combine<labelList>
188  (
189  sortedGatherList,
191  );
192 
193  SortableList<Type> sortedPivots(allPivots);
194 
195  if (debug)
196  {
197  Pout<< "allPivots:";
198  write(allPivots, Pout);
199  Pout<< endl;
200  }
201 
202  getPivots(sortedPivots, pivots);
203  }
204  Pstream::scatter(pivots);
205 
206  if (debug)
207  {
208  Pout<< "new pivots:";
209  write(pivots, Pout);
210  Pout<< endl;
211  }
212 
213 
214  //
215  // 3. Distribute pivots & distribute.
216  //
217 
218  label pivotI = 1;
219  label destProci = 0;
220 
221  // Buffer for my own data. Keep original index together with value.
222  labelList ownValues(sorted.size());
223  labelList ownIndices(sorted.size());
224  label ownI = 0;
225 
226  // Buffer for sending data
227  labelList sendValues(sorted.size());
228  labelList sendIndices(sorted.size());
229  label sendI = 0;
230 
231  forAll(sorted, sortedI)
232  {
233  if ((pivotI < Pstream::nProcs()) && (sorted[sortedI] > pivots[pivotI]))
234  {
235  checkAndSend(sendValues, sendIndices, sendI, destProci);
236 
237  // Reset buffer.
238  sendValues.setSize(sorted.size());
239  sendIndices.setSize(sorted.size());
240  sendI = 0;
241 
242  pivotI++;
243  destProci++;
244  }
245 
246  if (destProci != Pstream::myProcNo())
247  {
248  sendValues[sendI] = sorted[sortedI];
249  sendIndices[sendI] = sorted.indices()[sortedI];
250  sendI++;
251  }
252  else
253  {
254  ownValues[ownI] = sorted[sortedI];
255  ownIndices[ownI] = sorted.indices()[sortedI];
256  ownI++;
257  }
258  }
259 
260 
261  // Handle trailing send buffer
262  if (sendI != 0)
263  {
264  checkAndSend(sendValues, sendIndices, sendI, destProci);
265  }
266 
267  // Print ownValues
268  ownValues.setSize(ownI);
269  ownIndices.setSize(ownI);
270 
271  if (debug & 2)
272  {
273  Pout<< "Not sending (to myself) elements "
274  << ownValues << endl;
275  }
276 
277  //
278  // 4. Combine pieces from all processors & sort. Use indices() from
279  // SortableList to remember source processor number.
280  //
281 
282  // Allocate receive buffer. Acc. to paper upper bound is 2*n/p
283  // (n=total size, p=nProcs). Resize later on.
284  List<taggedValue> combinedValues(2 * n/Pstream::nProcs());
285 
286  label combinedI = 0;
287 
288  for (label proci = 0; proci < Pstream::nProcs(); proci++)
289  {
290  if (proci == Pstream::myProcNo())
291  {
292  if (debug & 2)
293  {
294  Pout<< "Copying from own:" << ownValues << endl;
295  }
296 
297  // Copy ownValues,ownIndices into combined buffer
298  copyInto(ownValues, ownIndices, proci, combinedI, combinedValues);
299  }
300  else
301  {
302  labelList recValues;
303  labelList recIndices;
304 
305  {
306  if (debug)
307  {
308  Pout<< "Receiving from " << proci << endl;
309  }
310 
311  IPstream fromSlave(Pstream::commsTypes::blocking, proci);
312 
313  fromSlave >> recValues >> recIndices;
314 
315  if (debug & 2)
316  {
317  Pout<< "Received from " << proci
318  << " elements:" << recValues << endl;
319  }
320  }
321 
322  if (debug)
323  {
324  Pout<< "Copying starting at:" << combinedI << endl;
325  }
326  copyInto(recValues, recIndices, proci, combinedI, combinedValues);
327  }
328  }
329  combinedValues.setSize(combinedI);
330 
331  // Sort according to values
332  Foam::sort(combinedValues);
333 
334  // Copy into *this
335  this->setSize(combinedI);
336  indices_.setSize(combinedI);
337  procs_.setSize(combinedI);
338 
339  forAll(combinedValues, elemI)
340  {
341  this->operator[](elemI) = combinedValues[elemI].value();
342  indices_[elemI] = combinedValues[elemI].index();
343  procs_[elemI] = combinedValues[elemI].procID();
344  }
345 }
346 
347 
348 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:74
Foam::UPstream::commsTypes::blocking
setSize
points setSize(newPointi)
Foam::accessOp
Definition: UList.H:607
Foam::HashTableOps::values
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:149
ListListOps.H
Foam::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:426
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:150
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
Foam::sumOp
Definition: ops.H:213
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
n
label n
Definition: TABSMDCalcMethod2.H:31
SortableList.H
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::sort
void sort(UList< T > &a)
Definition: UList.C:241
Foam::ParSortableList::sort
void sort()
(stable) sort the list (if changed after construction time)
Definition: ParSortableList.C:149
Foam::ParSortableList
Implementation of PSRS parallel sorting routine.
Definition: ParSortableList.H:71
Foam::SortableList
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: List.H:66
Pstream.H
PstreamReduceOps.H
Inter-processor communication reduction functions.
Foam::ParSortableList::ParSortableList
ParSortableList(const UList< Type > &)
Construct from List, sorting the elements.
Definition: ParSortableList.C:127
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:444
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:438
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:102
Foam::UList< Type >
Foam::SortableList::indices
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
Definition: SortableList.H:113
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:35
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:52
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
ParSortableList.H