UPstream.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) 2011-2016 OpenFOAM Foundation
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 "UPstream.H"
27 #include "debug.H"
28 #include "registerSwitch.H"
29 #include "dictionary.H"
30 #include "IOstreams.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36  defineTypeNameAndDebug(UPstream, 0);
37 
38  template<>
39  const char* Foam::NamedEnum
40  <
42  3
43  >::names[] =
44  {
45  "blocking",
46  "scheduled",
47  "nonBlocking"
48  };
49 }
50 
51 
54 
55 
56 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 
58 void Foam::UPstream::setParRun(const label nProcs)
59 {
60  if (nProcs == 0)
61  {
62  parRun_ = false;
63  freeCommunicator(UPstream::worldComm);
64  label comm = allocateCommunicator(-1, labelList(1, label(0)), false);
65  if (comm != UPstream::worldComm)
66  {
67  FatalErrorIn("UPstream::setParRun(const label)")
68  << "problem : comm:" << comm
69  << " UPstream::worldComm:" << UPstream::worldComm
71  }
72 
73  Pout.prefix() = "";
74  Perr.prefix() = "";
75  }
76  else
77  {
78  parRun_ = true;
79 
80  // Redo worldComm communicator (this has been created at static
81  // initialisation time)
82  freeCommunicator(UPstream::worldComm);
83  label comm = allocateCommunicator(-1, identity(nProcs), true);
84  if (comm != UPstream::worldComm)
85  {
87  << "problem : comm:" << comm
88  << " UPstream::worldComm:" << UPstream::worldComm
90  }
91 
92  Pout.prefix() = '[' + name(myProcNo(Pstream::worldComm)) + "] ";
93  Perr.prefix() = '[' + name(myProcNo(Pstream::worldComm)) + "] ";
94  }
95 }
96 
97 
98 Foam::List<Foam::UPstream::commsStruct> Foam::UPstream::calcLinearComm
99 (
100  const label nProcs
101 )
102 {
103  List<commsStruct> linearCommunication(nProcs);
104 
105  // Master
106  labelList belowIDs(nProcs - 1);
107  forAll(belowIDs, i)
108  {
109  belowIDs[i] = i + 1;
110  }
111 
112  linearCommunication[0] = commsStruct
113  (
114  nProcs,
115  0,
116  -1,
117  belowIDs,
118  labelList(0)
119  );
120 
121  // Slaves. Have no below processors, only communicate up to master
122  for (label procID = 1; procID < nProcs; procID++)
123  {
124  linearCommunication[procID] = commsStruct
125  (
126  nProcs,
127  procID,
128  0,
129  labelList(0),
130  labelList(0)
131  );
132  }
133  return linearCommunication;
134 }
135 
136 
137 void Foam::UPstream::collectReceives
138 (
139  const label procID,
140  const List<DynamicList<label>>& receives,
141  DynamicList<label>& allReceives
142 )
143 {
144  // Append my children (and my children children etc.) to allReceives.
145 
146  const DynamicList<label>& myChildren = receives[procID];
147 
148  forAll(myChildren, childI)
149  {
150  allReceives.append(myChildren[childI]);
151  collectReceives(myChildren[childI], receives, allReceives);
152  }
153 }
154 
155 
156 Foam::List<Foam::UPstream::commsStruct> Foam::UPstream::calcTreeComm
157 (
158  label nProcs
159 )
160 {
161  // Tree like schedule. For 8 procs:
162  // (level 0)
163  // 0 receives from 1
164  // 2 receives from 3
165  // 4 receives from 5
166  // 6 receives from 7
167  // (level 1)
168  // 0 receives from 2
169  // 4 receives from 6
170  // (level 2)
171  // 0 receives from 4
172  //
173  // The sends/receives for all levels are collected per processor
174  // (one send per processor; multiple receives possible) creating a table:
175  //
176  // So per processor:
177  // proc receives from sends to
178  // ---- ------------- --------
179  // 0 1,2,4 -
180  // 1 - 0
181  // 2 3 0
182  // 3 - 2
183  // 4 5 0
184  // 5 - 4
185  // 6 7 4
186  // 7 - 6
187 
188  label nLevels = 1;
189  while ((1 << nLevels) < nProcs)
190  {
191  nLevels++;
192  }
193 
194  List<DynamicList<label>> receives(nProcs);
195  labelList sends(nProcs, -1);
196 
197  // Info<< "Using " << nLevels << " communication levels" << endl;
198 
199  label offset = 2;
200  label childOffset = offset/2;
201 
202  for (label level = 0; level < nLevels; level++)
203  {
204  label receiveID = 0;
205  while (receiveID < nProcs)
206  {
207  // Determine processor that sends and we receive from
208  label sendID = receiveID + childOffset;
209 
210  if (sendID < nProcs)
211  {
212  receives[receiveID].append(sendID);
213  sends[sendID] = receiveID;
214  }
215 
216  receiveID += offset;
217  }
218 
219  offset <<= 1;
220  childOffset <<= 1;
221  }
222 
223  // For all processors find the processors it receives data from
224  // (and the processors they receive data from etc.)
225  List<DynamicList<label>> allReceives(nProcs);
226  for (label procID = 0; procID < nProcs; procID++)
227  {
228  collectReceives(procID, receives, allReceives[procID]);
229  }
230 
231 
232  List<commsStruct> treeCommunication(nProcs);
233 
234  for (label procID = 0; procID < nProcs; procID++)
235  {
236  treeCommunication[procID] = commsStruct
237  (
238  nProcs,
239  procID,
240  sends[procID],
241  receives[procID].shrink(),
242  allReceives[procID].shrink()
243  );
244  }
245  return treeCommunication;
246 }
247 
248 
250 (
251  const label parentIndex,
252  const labelList& subRanks,
253  const bool doPstream
254 )
255 {
256  label index;
257  if (!freeComms_.empty())
258  {
259  index = freeComms_.pop();
260  }
261  else
262  {
263  // Extend storage
264  index = parentCommunicator_.size();
265 
266  myProcNo_.append(-1);
267  procIDs_.append(List<int>(0));
268  parentCommunicator_.append(-1);
269  linearCommunication_.append(List<commsStruct>(0));
270  treeCommunication_.append(List<commsStruct>(0));
271  }
272 
273  if (debug)
274  {
275  Pout<< "Communicators : Allocating communicator " << index << endl
276  << " parent : " << parentIndex << endl
277  << " procs : " << subRanks << endl
278  << endl;
279  }
280 
281  // Initialise; overwritten by allocatePstreamCommunicator
282  myProcNo_[index] = 0;
283 
284  // Convert from label to int
285  procIDs_[index].setSize(subRanks.size());
286  forAll(procIDs_[index], i)
287  {
288  procIDs_[index][i] = subRanks[i];
289 
290  // Enforce incremental order (so index is rank in next communicator)
291  if (i >= 1 && subRanks[i] <= subRanks[i-1])
292  {
294  << "subranks not sorted : " << subRanks
295  << " when allocating subcommunicator from parent "
296  << parentIndex
298  }
299  }
300  parentCommunicator_[index] = parentIndex;
301 
302  linearCommunication_[index] = calcLinearComm(procIDs_[index].size());
303  treeCommunication_[index] = calcTreeComm(procIDs_[index].size());
304 
305 
306  if (doPstream && parRun())
307  {
308  allocatePstreamCommunicator(parentIndex, index);
309  }
310 
311  return index;
312 }
313 
314 
316 (
317  const label communicator,
318  const bool doPstream
319 )
320 {
321  if (debug)
322  {
323  Pout<< "Communicators : Freeing communicator " << communicator << endl
324  << " parent : " << parentCommunicator_[communicator] << endl
325  << " myProcNo : " << myProcNo_[communicator] << endl
326  << endl;
327  }
328 
329  if (doPstream && parRun())
330  {
331  freePstreamCommunicator(communicator);
332  }
333  myProcNo_[communicator] = -1;
334  //procIDs_[communicator].clear();
335  parentCommunicator_[communicator] = -1;
336  linearCommunication_[communicator].clear();
337  treeCommunication_[communicator].clear();
338 
339  freeComms_.push(communicator);
340 }
341 
342 
343 void Foam::UPstream::freeCommunicators(const bool doPstream)
344 {
345  forAll(myProcNo_, communicator)
346  {
347  if (myProcNo_[communicator] != -1)
348  {
349  freeCommunicator(communicator, doPstream);
350  }
351  }
352 }
353 
354 
355 int Foam::UPstream::baseProcNo(const label myComm, const int myProcID)
356 {
357  int procID = myProcID;
358  label comm = myComm;
359 
360  while (parent(comm) != -1)
361  {
362  const List<int>& parentRanks = UPstream::procID(comm);
363  procID = parentRanks[procID];
364  comm = UPstream::parent(comm);
365  }
366 
367  return procID;
368 }
369 
370 
371 Foam::label Foam::UPstream::procNo(const label myComm, const int baseProcID)
372 {
373  const List<int>& parentRanks = procID(myComm);
374  label parentComm = parent(myComm);
375 
376  if (parentComm == -1)
377  {
378  return findIndex(parentRanks, baseProcID);
379  }
380  else
381  {
382  label parentRank = procNo(parentComm, baseProcID);
383  return findIndex(parentRanks, parentRank);
384  }
385 }
386 
387 
389 (
390  const label myComm,
391  const label currentComm,
392  const int currentProcID
393 )
394 {
395  label physProcID = UPstream::baseProcNo(currentComm, currentProcID);
396  return procNo(myComm, physProcID);
397 }
398 
399 
400 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
401 
402 bool Foam::UPstream::parRun_(false);
403 
404 Foam::LIFOStack<Foam::label> Foam::UPstream::freeComms_;
405 
406 Foam::DynamicList<int> Foam::UPstream::myProcNo_(10);
407 
408 Foam::DynamicList<Foam::List<int>> Foam::UPstream::procIDs_(10);
409 
410 Foam::DynamicList<Foam::label> Foam::UPstream::parentCommunicator_(10);
411 
412 int Foam::UPstream::msgType_(1);
413 
414 
416 Foam::UPstream::linearCommunication_(10);
417 
419 Foam::UPstream::treeCommunication_(10);
420 
421 
422 // Allocate a serial communicator. This gets overwritten in parallel mode
423 // (by UPstream::setParRun())
425 (
426  -1,
428  false
429 );
430 
431 
433 (
434  Foam::debug::optimisationSwitch("floatTransfer", 0)
435 );
437 (
438  "floatTransfer",
439  bool,
440  Foam::UPstream::floatTransfer
441 );
442 
444 (
445  Foam::debug::optimisationSwitch("nProcsSimpleSum", 16)
446 );
448 (
449  "nProcsSimpleSum",
450  int,
451  Foam::UPstream::nProcsSimpleSum
452 );
453 
455 (
456  commsTypeNames.read(Foam::debug::optimisationSwitches().lookup("commsType"))
457 );
458 
459 namespace Foam
460 {
461  // Register re-reader
463  :
465  {
466  public:
467 
468  addcommsTypeToOpt(const char* name)
469  :
471  {}
472 
474  {}
475 
476  virtual void readData(Foam::Istream& is)
477  {
479  (
480  is
481  );
482  }
483 
484  virtual void writeData(Foam::Ostream& os) const
485  {
487  }
488  };
489 
491 }
492 
494 
496 
498 (
499  Foam::debug::optimisationSwitch("nPollProcInterfaces", 0)
500 );
502 (
503  "nPollProcInterfaces",
504  int,
505  Foam::UPstream::nPollProcInterfaces
506 );
507 
508 
509 // ************************************************************************* //
A LIFO stack based on a singly-linked list.
Definition: LIFOStack.H:51
static bool floatTransfer
Should compact transfer be used in which floats replace doubles.
Definition: UPstream.H:261
Abstract base class for registered object with I/O. Used in debug symbol registration.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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:59
addcommsTypeToOpt addcommsTypeToOpt_("commsType")
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Foam::UPstream::communicator serialComm(-1, Foam::labelList(1, Foam::label(0)), false)
commsTypes
Types of communications.
Definition: UPstream.H:64
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:265
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
int optimisationSwitch(const char *name, const int defaultValue=0)
Lookup optimisation switch or add default value.
Definition: debug.C:184
static label procNo(const label comm, const int baseProcID)
Return processor number in communicator (given physical processor.
Definition: UPstream.C:371
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
virtual void writeData(Foam::Ostream &os) const
Write.
Definition: UPstream.C:484
static label worldComm
Default communicator (all processors)
Definition: UPstream.H:274
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:52
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
static void freeCommunicators(const bool doPstream)
Free all communicators.
Definition: UPstream.C:343
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:271
static label parent(const label communicator)
Definition: UPstream.H:422
virtual void readData(Foam::Istream &is)
Read.
Definition: UPstream.C:476
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:97
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
List< label > labelList
A List of labels.
Definition: labelList.H:56
registerOptSwitch("floatTransfer", bool, Foam::UPstream::floatTransfer)
static label warnComm
Debugging: warn for use of any communicator differing from warnComm.
Definition: UPstream.H:277
errorManip< error > abort(error &err)
Definition: errorManip.H:131
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
static int baseProcNo(const label myComm, const int procID)
Return physical processor number (i.e. processor number in.
Definition: UPstream.C:355
defineTypeNameAndDebug(combustionModel, 0)
static const NamedEnum< commsTypes, 3 > commsTypeNames
Definition: UPstream.H:71
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
prefixOSstream Perr(cerr,"Perr")
Definition: IOstreams.H:54
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Helper class for allocating/freeing communicators.
Definition: UPstream.H:310
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:268
dictionary & optimisationSwitches()
The OptimisationSwitches sub-dictionary in the central controlDict.
Definition: debug.C:160
static label allocateCommunicator(const label parent, const labelList &subRanks, const bool doPstream=true)
Allocate a new communicator.
Definition: UPstream.C:250
void addOptimisationObject(const char *name, simpleRegIOobject *obj)
Register optimisation switch read/write object.
Definition: debug.C:236
addcommsTypeToOpt(const char *name)
Definition: UPstream.C:468
virtual ~addcommsTypeToOpt()
Definition: UPstream.C:473
const string & prefix() const
Return the prefix of the stream.
Enum read(Istream &) const
Read a word from Istream and return the corresponding.
Definition: NamedEnum.C:61
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
static List< int > & procID(label communicator)
Process ID of given process index.
Definition: UPstream.H:428
static void freeCommunicator(const label communicator, const bool doPstream=true)
Free a previously allocated communicator.
Definition: UPstream.C:316
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:451