FreeFOAM The Cross-Platform CFD Toolkit
mapDistribute.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 | Copyright (C) 1991-2010 OpenCFD Ltd.
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "mapDistribute.H"
27 #include <OpenFOAM/commSchedule.H>
28 #include <OpenFOAM/HashSet.H>
29 #include <OpenFOAM/ListOps.H>
30 
31 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32 
34 (
35  const labelListList& subMap,
36  const labelListList& constructMap
37 )
38 {
39  // Communications: send and receive processor
40  List<labelPair> allComms;
41 
42  {
43  HashSet<labelPair, labelPair::Hash<> > commsSet(Pstream::nProcs());
44 
45  // Find what communication is required
46  forAll(subMap, procI)
47  {
48  if (procI != Pstream::myProcNo())
49  {
50  if (subMap[procI].size())
51  {
52  // I need to send to procI
53  commsSet.insert(labelPair(Pstream::myProcNo(), procI));
54  }
55  if (constructMap[procI].size())
56  {
57  // I need to receive from procI
58  commsSet.insert(labelPair(procI, Pstream::myProcNo()));
59  }
60  }
61  }
62  allComms = commsSet.toc();
63  }
64 
65 
66  // Reduce
67  if (Pstream::master())
68  {
69  // Receive and merge
70  for
71  (
72  int slave=Pstream::firstSlave();
73  slave<=Pstream::lastSlave();
74  slave++
75  )
76  {
77  IPstream fromSlave(Pstream::blocking, slave);
78  List<labelPair> nbrData(fromSlave);
79 
80  forAll(nbrData, i)
81  {
82  if (findIndex(allComms, nbrData[i]) == -1)
83  {
84  label sz = allComms.size();
85  allComms.setSize(sz+1);
86  allComms[sz] = nbrData[i];
87  }
88  }
89  }
90  // Send back
91  for
92  (
93  int slave=Pstream::firstSlave();
94  slave<=Pstream::lastSlave();
95  slave++
96  )
97  {
98  OPstream toSlave(Pstream::blocking, slave);
99  toSlave << allComms;
100  }
101  }
102  else
103  {
104  {
105  OPstream toMaster(Pstream::blocking, Pstream::masterNo());
106  toMaster << allComms;
107  }
108  {
109  IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
110  fromMaster >> allComms;
111  }
112  }
113 
114 
115  // Determine my schedule.
116  labelList mySchedule
117  (
119  (
120  Pstream::nProcs(),
121  allComms
122  ).procSchedule()[Pstream::myProcNo()]
123  );
124 
125  // Processors involved in my schedule
126  return UIndirectList<labelPair>(allComms, mySchedule);
127 
128 
129  //if (debug)
130  //{
131  // Pout<< "I need to:" << endl;
132  // const List<labelPair>& comms = schedule();
133  // forAll(comms, i)
134  // {
135  // const labelPair& twoProcs = comms[i];
136  // label sendProc = twoProcs[0];
137  // label recvProc = twoProcs[1];
138  //
139  // if (recvProc == Pstream::myProcNo())
140  // {
141  // Pout<< " receive from " << sendProc << endl;
142  // }
143  // else
144  // {
145  // Pout<< " send to " << recvProc << endl;
146  // }
147  // }
148  //}
149 }
150 
151 
153 {
154  if (schedulePtr_.empty())
155  {
156  schedulePtr_.reset
157  (
158  new List<labelPair>
159  (
160  schedule(subMap_, constructMap_)
161  )
162  );
163  }
164  return schedulePtr_();
165 }
166 
167 
168 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
169 
170 //- Construct from components
172 (
173  const label constructSize,
174  const labelListList& subMap,
175  const labelListList& constructMap
176 )
177 :
178  constructSize_(constructSize),
179  subMap_(subMap),
180  constructMap_(constructMap),
181  schedulePtr_()
182 {}
183 
184 
185 //- (optionally destructively) construct from components
187 (
188  const label constructSize,
189  labelListList& subMap,
190  labelListList& constructMap,
191  const bool reUse // clone or reuse
192 )
193 :
194  constructSize_(constructSize),
195  subMap_(subMap, reUse),
196  constructMap_(constructMap, reUse),
197  schedulePtr_()
198 {}
199 
200 
202 (
203  const labelList& sendProcs,
204  const labelList& recvProcs
205 )
206 :
207  constructSize_(0),
208  schedulePtr_()
209 {
210  if (sendProcs.size() != recvProcs.size())
211  {
213  (
214  "mapDistribute::mapDistribute(const labelList&, const labelList&)"
215  ) << "The send and receive data is not the same length. sendProcs:"
216  << sendProcs.size() << " recvProcs:" << recvProcs.size()
217  << abort(FatalError);
218  }
219 
220  // Per processor the number of samples we have to send/receive.
221  labelList nSend(Pstream::nProcs(), 0);
222  labelList nRecv(Pstream::nProcs(), 0);
223 
224  forAll(sendProcs, sampleI)
225  {
226  label sendProc = sendProcs[sampleI];
227  label recvProc = recvProcs[sampleI];
228 
229  // Note that also need to include local communication (both
230  // RecvProc and sendProc on local processor)
231 
232  if (Pstream::myProcNo() == sendProc)
233  {
234  // I am the sender. Count destination processor.
235  nSend[recvProc]++;
236  }
237  if (Pstream::myProcNo() == recvProc)
238  {
239  // I am the receiver.
240  nRecv[sendProc]++;
241  }
242  }
243 
244  subMap_.setSize(Pstream::nProcs());
245  constructMap_.setSize(Pstream::nProcs());
246  forAll(nSend, procI)
247  {
248  subMap_[procI].setSize(nSend[procI]);
249  constructMap_[procI].setSize(nRecv[procI]);
250  }
251  nSend = 0;
252  nRecv = 0;
253 
254  forAll(sendProcs, sampleI)
255  {
256  label sendProc = sendProcs[sampleI];
257  label recvProc = recvProcs[sampleI];
258 
259  if (Pstream::myProcNo() == sendProc)
260  {
261  // I am the sender. Store index I need to send.
262  subMap_[recvProc][nSend[recvProc]++] = sampleI;
263  }
264  if (Pstream::myProcNo() == recvProc)
265  {
266  // I am the receiver.
267  constructMap_[sendProc][nRecv[sendProc]++] = sampleI;
268  // Largest entry inside constructMap
269  constructSize_ = sampleI+1;
270  }
271  }
272 }
273 
274 
276 :
277  constructSize_(map.constructSize_),
278  subMap_(map.subMap_),
279  constructMap_(map.constructMap_),
280  schedulePtr_()
281 {}
282 
283 
284 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
285 
286 void Foam::mapDistribute::compact(const boolList& elemIsUsed)
287 {
288  // 1. send back to sender. Have him delete the corresponding element
289  // from the submap and do the same to the constructMap locally
290  // (and in same order).
291 
292  // Send elemIsUsed field to neighbour. Use nonblocking code from
293  // mapDistribute but in reverse order.
294  {
295  List<boolList> sendFields(Pstream::nProcs());
296 
297  for (label domain = 0; domain < Pstream::nProcs(); domain++)
298  {
299  const labelList& map = constructMap_[domain];
300 
301  if (domain != Pstream::myProcNo() && map.size())
302  {
303  boolList& subField = sendFields[domain];
304  subField.setSize(map.size());
305  forAll(map, i)
306  {
307  subField[i] = elemIsUsed[map[i]];
308  }
309 
311  (
313  domain,
314  reinterpret_cast<const char*>(subField.begin()),
315  subField.size()*sizeof(bool)
316  );
317  }
318  }
319 
320  // Set up receives from neighbours
321 
322  List<boolList> recvFields(Pstream::nProcs());
323 
324  for (label domain = 0; domain < Pstream::nProcs(); domain++)
325  {
326  const labelList& map = subMap_[domain];
327 
328  if (domain != Pstream::myProcNo() && map.size())
329  {
330  recvFields[domain].setSize(map.size());
332  (
334  domain,
335  reinterpret_cast<char*>(recvFields[domain].begin()),
336  recvFields[domain].size()*sizeof(bool)
337  );
338  }
339  }
340 
341 
342  // Set up 'send' to myself - write directly into recvFields
343 
344  {
345  const labelList& map = constructMap_[Pstream::myProcNo()];
346 
347  recvFields[Pstream::myProcNo()].setSize(map.size());
348  forAll(map, i)
349  {
350  recvFields[Pstream::myProcNo()][i] = elemIsUsed[map[i]];
351  }
352  }
353 
354 
355  // Wait for all to finish
356 
359 
360 
361  // Compact out all submap entries that are referring to unused elements
362  for (label domain = 0; domain < Pstream::nProcs(); domain++)
363  {
364  const labelList& map = subMap_[domain];
365 
366  labelList newMap(map.size());
367  label newI = 0;
368 
369  forAll(map, i)
370  {
371  if (recvFields[domain][i])
372  {
373  // So element is used on destination side
374  newMap[newI++] = map[i];
375  }
376  }
377  if (newI < map.size())
378  {
379  newMap.setSize(newI);
380  subMap_[domain].transfer(newMap);
381  }
382  }
383  }
384 
385 
386  // 2. remove from construct map - since end-result (element in elemIsUsed)
387  // not used.
388 
389  label maxConstructIndex = -1;
390 
391  for (label domain = 0; domain < Pstream::nProcs(); domain++)
392  {
393  const labelList& map = constructMap_[domain];
394 
395  labelList newMap(map.size());
396  label newI = 0;
397 
398  forAll(map, i)
399  {
400  label destinationI = map[i];
401 
402  // Is element is used on destination side
403  if (elemIsUsed[destinationI])
404  {
405  maxConstructIndex = max(maxConstructIndex, destinationI);
406 
407  newMap[newI++] = destinationI;
408  }
409  }
410  if (newI < map.size())
411  {
412  newMap.setSize(newI);
413  constructMap_[domain].transfer(newMap);
414  }
415  }
416 
417  constructSize_ = maxConstructIndex+1;
418 
419  // Clear the schedule (note:not necessary if nothing changed)
420  schedulePtr_.clear();
421 }
422 
423 
424 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
425 
427 {
428  // Check for assignment to self
429  if (this == &rhs)
430  {
432  (
433  "Foam::mapDistribute::operator=(const Foam::mapDistribute&)"
434  ) << "Attempted assignment to self"
435  << abort(FatalError);
436  }
437  constructSize_ = rhs.constructSize_;
438  subMap_ = rhs.subMap_;
439  constructMap_ = rhs.constructMap_;
440  schedulePtr_.clear();
441 }
442 
443 
444 // ************************ vim: set sw=4 sts=4 et: ************************ //