UPstreamCommsStruct.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-2016 OpenFOAM Foundation
9  Copyright (C) 2021-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 "UPstream.H"
30 
31 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
32 
34 (
35  const label above,
36  labelList&& below,
37  labelList&& allBelow,
38  labelList&& allNotBelow
39 )
40 :
41  above_(above),
42  below_(std::move(below)),
43  allBelow_(std::move(allBelow)),
44  allNotBelow_(std::move(allNotBelow))
45 {}
46 
47 
49 (
50  const label numProcs,
51  const label myProcID,
52  const label above,
53  const labelUList& below,
54  const labelUList& allBelow
55 )
56 :
57  above_(above),
58  below_(below),
59  allBelow_(allBelow),
60  allNotBelow_(numProcs - allBelow.size() - 1)
61 {
62  List<bool> isNotBelow(numProcs, true);
63 
64  // Exclude self
65  isNotBelow[myProcID] = false;
66 
67  // Exclude allBelow
68  for (const label proci : allBelow)
69  {
70  isNotBelow[proci] = false;
71  }
72 
73  // Compacting to obtain allNotBelow_
74  label nNotBelow = 0;
75  forAll(isNotBelow, proci)
76  {
77  if (isNotBelow[proci])
78  {
79  allNotBelow_[nNotBelow++] = proci;
80  }
81  }
82 
83  if (nNotBelow != allNotBelow_.size())
84  {
86  << "Problem: " << nNotBelow << " != " << allNotBelow_.size() << nl
88  }
89 }
90 
91 
92 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
93 
94 // This outputs as depth-first, but graphviz sorts that for us
96 (
97  Ostream& os,
98  const UList<UPstream::commsStruct>& comms,
99  const label proci
100 )
101 {
102  // if (proci >= comms.size()) return; // Extreme safety!
103 
104  const auto& below = comms[proci].below();
105 
106  if (proci == 0)
107  {
108  os << nl << "// communication graph:" << nl;
109  os.beginBlock("graph");
110 
111  if (below.empty())
112  {
113  // A graph with a single-node (eg, self-comm)
114  os << indent << proci << nl;
115  }
116  }
117 
118  int pos = 0;
119 
120  for (const label nbrProci : below)
121  {
122  if (pos)
123  {
124  os << " ";
125  }
126  else
127  {
128  os << indent;
129  }
130  os << proci << " -- " << nbrProci;
131 
132  if (++pos >= 4) // Max 4 items per line
133  {
134  pos = 0;
135  os << nl;
136  }
137  }
138 
139  if (pos)
140  {
141  os << nl;
142  }
143 
144  for (const label nbrProci : below)
145  {
146  // if (proci == nbrProci) continue; // Extreme safety!
147  printGraph(os, comms, nbrProci);
148  }
149 
150  if (proci == 0)
151  {
152  os.endBlock();
153 
154  os << "// end graph" << nl;
155  }
156 }
157 
158 
159 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
161 Foam::label Foam::UPstream::commsStruct::nProcs() const
162 {
163  return (1 + allBelow_.size() + allNotBelow_.size());
164 }
165 
166 
168 {
169  above_ = -1;
170  below_.clear();
171  allBelow_.clear();
172  allNotBelow_.clear();
173 }
174 
175 
177 (
178  const label procID,
179  const label numProcs
180 )
181 {
182  reset();
183 
184  label above(-1);
185  DynamicList<label> below;
186  DynamicList<label> allBelow;
187 
188  if (numProcs < UPstream::nProcsSimpleSum)
189  {
190  // Linear schedule
191 
192  if (procID == 0)
193  {
194  below = identity(numProcs-1, 1);
195  allBelow = below;
196  }
197  else
198  {
199  above = 0;
200  }
201  }
202  else
203  {
204  // Use tree like schedule. For 8 procs:
205  // (level 0)
206  // 0 receives from 1
207  // 2 receives from 3
208  // 4 receives from 5
209  // 6 receives from 7
210  // (level 1)
211  // 0 receives from 2
212  // 4 receives from 6
213  // (level 2)
214  // 0 receives from 4
215  //
216  // The sends/receives for all levels are collected per processor
217  // (one send per processor; multiple receives possible) creating
218  // a table:
219  //
220  // So per processor:
221  // proc receives from sends to
222  // ---- ------------- --------
223  // 0 1,2,4 -
224  // 1 - 0
225  // 2 3 0
226  // 3 - 2
227  // 4 5 0
228  // 5 - 4
229  // 6 7 4
230  // 7 - 6
231 
232  label mod = 0;
233 
234  for (label step = 1; step < numProcs; step = mod)
235  {
236  mod = step * 2;
237 
238  if (procID % mod)
239  {
240  above = procID - (procID % mod);
241  break;
242  }
243  else
244  {
245  for
246  (
247  label j = procID + step;
248  j < numProcs && j < procID + mod;
249  j += step
250  )
251  {
252  below.push_back(j);
253  }
254  for
255  (
256  label j = procID + step;
257  j < numProcs && j < procID + mod;
258  j++
259  )
260  {
261  allBelow.push_back(j);
262  }
263  }
264  }
265  }
266 
267  *this = UPstream::commsStruct(numProcs, procID, above, below, allBelow);
268 }
269 
270 
271 // * * * * * * * * * * * * * * * Specializations * * * * * * * * * * * * * * //
272 
273 template<>
276 {
277  auto& val = this->v_[procID]; // or this->data()[procID]
278 
279  if (val.nProcs() != size())
280  {
281  // Create/update
282  val.reset(procID, size());
283  }
285  return val;
286 }
287 
288 
289 template<>
292 {
293  return const_cast<UList<UPstream::commsStruct>&>(*this).operator[](procID);
294 }
295 
296 
297 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
298 
300 {
301  return
302  (
303  (above_ == comm.above())
304  && (below_ == comm.below())
305  // && (allBelow_ == comm.allBelow())
306  // && (allNotBelow_ == comm.allNotBelow())
307  );
308 }
309 
310 
312 {
313  return !operator==(comm);
314 }
315 
316 
317 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
318 
319 Foam::Ostream& Foam::operator<<(Ostream& os, const UPstream::commsStruct& comm)
320 {
321  os << comm.above() << nl << token::SPACE << token::SPACE;
322  comm.below().writeList(os) << nl << token::SPACE << token::SPACE;
323  comm.allBelow().writeList(os) << nl << token::SPACE << token::SPACE;
324  comm.allNotBelow().writeList(os);
325 
326  os.check(FUNCTION_NAME);
327  return os;
328 }
329 
330 
331 // ************************************************************************* //
const labelList & below() const noexcept
The procIDs of the processors directly below.
Definition: UPstream.H:193
commsStruct() noexcept
Default construct with above == -1.
Definition: UPstream.H:139
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:493
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
static int nProcsSimpleSum
Number of processors to change from linear to tree communication.
Definition: UPstream.H:369
static void printGraph(Ostream &os, const UList< UPstream::commsStruct > &comms, const label proci=0)
Print un-directed graph in graphviz dot format.
void reset()
Reset to default constructed state.
label above() const noexcept
The procID of the processor directly above.
Definition: UPstream.H:188
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
T & operator[](const label i)
Return element of UList.
Definition: UListI.H:361
dimensionedScalar pos(const dimensionedScalar &ds)
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
label nProcs() const
The number of processors addressed by the structure.
Space [isspace].
Definition: token.H:131
errorManip< error > abort(error &err)
Definition: errorManip.H:139
Structure for communicating between processors.
Definition: UPstream.H:104
const labelList & allBelow() const noexcept
The procIDs of all processors below (so not just directly below)
Definition: UPstream.H:199
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
bool operator==(const commsStruct &) const
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
bool operator!=(const commsStruct &) const
void push_back(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:555
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
static List< int > & procID(const label communicator)
The list of ranks within a given communicator.
Definition: UPstream.H:1130
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)