globalIndex.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) 2018-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 "globalIndex.H"
30 #include "Pair.H"
31 
32 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
33 
34 void Foam::globalIndex::reportOverflowAndExit
35 (
36  const label idx,
37  const label prevOffset,
38  const label count
39 )
40 {
41  if (idx < 0)
42  {
43  // No overflow tagged
44  return;
45  }
46 
48  << "Overflow : sum of sizes exceeds labelMax ("
49  << labelMax << ") after index " << idx;
50 
51  if (prevOffset >= 0 && count >= 0)
52  {
54  << " while trying to add (" << count
55  << ") to offset (" << prevOffset << ")";
56  }
57 
59  << nl
60  << "Please recompile with larger datatype for label." << nl
61  << exit(FatalError);
62 }
63 
64 
67 (
68  const label localSize,
69  const label comm,
70  const bool checkOverflow
71 )
72 {
73  // Range with 0-offset initially
74  labelRange myRange(0, localSize);
75 
76  if (!UPstream::is_parallel(comm))
77  {
78  return myRange;
79  }
80 
81  const label myProci = UPstream::myProcNo(comm);
82  const labelList counts = UPstream::allGatherValues(localSize, comm);
83 
84  if (checkOverflow)
85  {
86  const label len = counts.size();
87 
88  label start = 0;
89 
90  for (label i = 0; i < len; ++i)
91  {
92  const label count = counts[i];
93 
94  if (i == myProci)
95  {
96  myRange.start() = start;
97  }
98 
99  const label prev = start;
100  start += count;
101 
102  if (start < prev)
103  {
104  reportOverflowAndExit(i, prev, count);
105  }
106  }
107  }
108  else
109  {
110  // std::accumulate
111  // (
112  // counts.cbegin(),
113  // counts.cbegin(myProci),
114  // label(0)
115  // );
116 
117  label start = 0;
118 
119  for (label i = 0; i < myProci; ++i)
120  {
121  start += counts[i];
122  }
123  myRange.start() = start;
124  }
126  return myRange;
127 }
128 
129 
130 Foam::label
132 (
133  const label localSize,
134  const label comm,
135  const bool checkOverflow
136 )
137 {
138  // Placeholder value
139  label myOffset = 0;
140 
141  if (!UPstream::is_parallel(comm))
142  {
143  return myOffset;
144  }
145 
146  const label myProci = UPstream::myProcNo(comm);
147  const labelList counts = UPstream::allGatherValues(localSize, comm);
148 
149  if (checkOverflow)
150  {
151  const label len = counts.size();
152 
153  label start = 0;
154 
155  for (label i = 0; i < len; ++i)
156  {
157  const label count = counts[i];
158  if (i == myProci)
159  {
160  myOffset = start;
161  }
162 
163  const label prev = start;
164  start += count;
165 
166  if (start < prev)
167  {
168  reportOverflowAndExit(i, prev, count);
169  }
170  }
171  }
172  else
173  {
174  // std::accumulate
175  // (
176  // counts.cbegin(),
177  // counts.cbegin(myProci),
178  // label(0)
179  // );
180 
181  label start = 0;
182 
183  for (label i = 0; i < myProci; ++i)
184  {
185  start += counts[i];
186  }
187  myOffset = start;
188  }
190  return myOffset;
191 }
192 
193 
196 (
197  const labelUList& counts,
198  const bool checkOverflow
199 )
200 {
202 
203  const label len = counts.size();
204 
205  if (len)
206  {
207  values.resize(len+1);
208 
209  label start = 0;
210  for (label i = 0; i < len; ++i)
211  {
212  const label count = counts[i];
213  values[i] = start;
214  start += count;
215 
216  if (checkOverflow && start < values[i])
217  {
218  reportOverflowAndExit(i, values[i], count);
219  }
220  }
221  values[len] = start;
222  }
224  return values;
225 }
226 
227 
230 (
231  const labelUList& counts,
232  const bool checkOverflow
233 )
234 {
236 
237  const label len = counts.size();
238 
239  if (len)
240  {
241  values.resize(len);
242 
243  label start = 0;
244  for (label i = 0; i < len; ++i)
245  {
246  const label count = counts[i];
247  values[i].reset(start, count);
248  start += count;
249 
250  if
251  (
252  checkOverflow
253  && (start < values[i].start())
254  && (i < len-1) // Do not check the one beyond the end range
255  )
256  {
257  reportOverflowAndExit(i, values[i].start(), count);
258  }
259  }
260  }
262  return values;
263 }
264 
265 
266 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
267 
269 {
270  is >> offsets_;
271 }
272 
273 
274 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
275 
277 Foam::globalIndex::bin
278 (
279  const labelUList& offsets,
280  const labelUList& globalIds,
281  labelList& order,
282  DynamicList<label>& validBins
283 )
284 {
285  Foam::sortedOrder(globalIds, order);
286  validBins.clear();
287 
288  CompactListList<label> bins;
289 
290  if (!globalIds.empty())
291  {
292  labelList& binOffsets = bins.offsets();
293  binOffsets.resize(offsets.size(), Zero);
294 
295  labelList& binValues = bins.values();
296  binValues = UIndirectList<label>(globalIds, order);
297 
298  const label id = binValues[0];
299  label proci = findLower(offsets, id+1);
300 
301  validBins.push_back(proci);
302  label binSize = 1;
303 
304  for (label i = 1; i < order.size(); i++)
305  {
306  const label id = binValues[i];
307 
308  if (id < offsets[proci+1])
309  {
310  ++binSize;
311  }
312  else
313  {
314  // Not local. Reset proci
315  const label oldProci = proci;
316  proci = findLower(offsets, id+1);
317 
318  // Set offsets
319  for (label j = oldProci+1; j < proci; ++j)
320  {
321  binOffsets[j] = binOffsets[oldProci]+binSize;
322  }
323  binOffsets[proci] = i;
324  validBins.push_back(proci);
325  binSize = 1;
326  }
327  }
328 
329  for (label j = proci+1; j < binOffsets.size(); ++j)
330  {
331  binOffsets[j] = binOffsets[proci]+binSize;
332  }
333  }
334 
335  return bins;
336 }
337 
338 
339 void Foam::globalIndex::resize(const label n)
340 {
341  if (n < 1)
342  {
343  offsets_.clear();
344  }
345  else
346  {
347  offsets_.resize(n+1, end_value());
348  }
349 }
350 
351 
353 (
354  const label localSize,
355  const label comm,
356  const bool parallel
357 )
358 {
359  const label len = UPstream::nProcs(comm);
360 
361  if (len)
362  {
363  labelList counts;
364 
365  if (parallel && UPstream::parRun()) // or UPstream::is_parallel(comm)
366  {
367  counts = UPstream::allGatherValues(localSize, comm);
368  }
369  else
370  {
371  // Non-parallel branch: use localSize on-proc, zero elsewhere
372  // TBD: check for (proci >= 0) ?
373  const auto proci = UPstream::myProcNo(comm);
374 
375  counts.resize(len, Zero);
376  counts[proci] = localSize;
377  }
378 
379  reset(counts, true); // checkOverflow = true
380  }
381  else
382  {
383  // Nothing to do
384  offsets_.clear();
385  }
386 }
387 
388 
390 (
391  const labelUList& counts,
392  const bool checkOverflow
393 )
394 {
395  const label len = counts.size();
396 
397  if (len)
398  {
399  offsets_.resize_nocopy(len+1);
400 
401  label start = 0;
402  for (label i = 0; i < len; ++i)
403  {
404  const label count = counts[i];
405  offsets_[i] = start;
406  start += count;
407 
408  if (checkOverflow && start < offsets_[i])
409  {
410  reportOverflowAndExit(i, offsets_[i], count);
411  }
412  }
413  offsets_[len] = start;
414  }
415  else
416  {
417  offsets_.clear();
418  }
419 }
420 
421 
422 void Foam::globalIndex::setLocalSize(const label proci, const label len)
423 {
424  if (proci >= 0 && proci+1 < offsets_.size() && len >= 0)
425  {
426  const label delta = (len - (offsets_[proci+1] - offsets_[proci]));
427 
428  // TBD: additional overflow check
429  if (delta)
430  {
431  for (label i = proci+1; i < offsets_.size(); ++i)
432  {
433  offsets_[i] += delta;
434  }
435  }
436  }
437 }
438 
439 
441 {
443 
444  const label len = (offsets_.size() - 1);
445 
446  if (len < 1)
447  {
448  return values;
449  }
450 
451  values.resize(len);
452 
453  for (label proci=0; proci < len; ++proci)
454  {
455  values[proci] = offsets_[proci+1] - offsets_[proci];
456  }
457 
458  return values;
459 }
460 
461 
464 {
465  List<labelRange> values;
466 
467  const label len = (offsets_.size() - 1);
468 
469  if (len < 1)
470  {
471  return values;
472  }
473 
474  values.resize(len);
475 
476  for (label proci=0; proci < len; ++proci)
477  {
478  values[proci].reset
479  (
480  offsets_[proci],
481  (offsets_[proci+1] - offsets_[proci])
482  );
483  }
484 
485  return values;
486 }
487 
488 
489 Foam::label Foam::globalIndex::maxNonLocalSize(const label proci) const
490 {
491  const label len = (offsets_.size() - 1);
492 
493  if (len < 1)
494  {
495  return 0;
496  }
497 
498  label maxLen = 0;
499 
500  for (label i=0; i < len; ++i)
501  {
502  if (i != proci)
503  {
504  const label count = (offsets_[i+1] - offsets_[i]);
505  maxLen = max(maxLen, count);
506  }
507  }
508 
509  return maxLen;
510 }
511 
512 
514 {
515  return
516  (
517  (offsets_.size() < 2)
518  ? labelRange()
519  : labelRange(Pair<label>(offsets_[0], offsets_[1]))
520  );
521 }
522 
523 
525 {
526  return
527  (
528  (offsets_.size() < 2)
529  ? labelRange()
530  : labelRange
531  (
533  (
534  offsets_[offsets_.size()-2],
535  offsets_[offsets_.size()-1]
536  )
537  )
538  );
539 }
540 
541 
542 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
545 {
546  return is >> gi.offsets();
547 }
548 
549 
550 Foam::Ostream& Foam::operator<<(Ostream& os, const globalIndex& gi)
551 {
552  return os << gi.offsets();
553 }
554 
555 
556 // ************************************************************************* //
scalar delta
static labelList calcOffsets(const labelUList &counts, const bool checkOverflow=false)
Calculate offsets from a list of local sizes, with optional check for label overflow.
Definition: globalIndex.C:189
void reset(const label localSize, const label comm=UPstream::worldComm, const bool parallel=UPstream::parRun())
Reset from local size, using gather/broadcast with default/specified communicator if parallel...
Definition: globalIndex.C:346
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Binary search to find the index of the last element in a sorted list that is less than value...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
List< labelRange > ranges() const
Return start/size ranges for all data.
Definition: globalIndex.C:456
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static List< labelRange > calcRanges(const labelUList &counts, const bool checkOverflow=false)
Calculate ranges (offset/size) from a list of local sizes, with optional check for label overflow...
Definition: globalIndex.C:223
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
static List< T > allGatherValues(const T &localValue, const label communicator=worldComm)
Allgather individual values into list locations.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
labelList localSizes() const
The local sizes.
Definition: globalIndex.C:433
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
globalIndex() noexcept=default
Default construct (empty)
const labelList & offsets() const noexcept
Const-access to the offsets.
Definition: globalIndexI.H:205
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1065
Istream & operator>>(Istream &, directionInfo &)
void setLocalSize(const label proci, const label len)
Alter local size for given processor.
Definition: globalIndex.C:415
static bool is_parallel(const label communicator=worldComm)
True if parallel algorithm or exchange is required.
Definition: UPstream.H:1111
A packed storage of objects of type <T> using an offset table for access.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
OBJstream os(runTime.globalPath()/outputName)
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
constexpr label labelMax
Definition: label.H:55
static labelRange calcRange(const label localSize, const label comm=UPstream::worldComm, const bool checkOverflow=false)
Calculate globally-consistent local range (offset/size) based on the local input size(s).
Definition: globalIndex.C:60
label n
List< label > labelList
A List of labels.
Definition: List.H:62
labelRange back() const
The last offset range. It is (0,0) if globalIndex is empty.
Definition: globalIndex.C:517
static label calcOffset(const label localSize, const label comm=UPstream::worldComm, const bool checkOverflow=false)
Calculate globally-consistent local start offset based on the local input size(s).
Definition: globalIndex.C:125
label maxNonLocalSize() const
The max of localSizes, excluding current (myProcNo) rank.
Definition: globalIndexI.H:276
void resize(const label n)
Change the number of entries (nProcs) in the offsets table. Extending will fill with empty local size...
Definition: globalIndex.C:332
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
labelRange front() const
The first offset range. It is (0,0) if globalIndex is empty.
Definition: globalIndex.C:506