Reference documentation for deal.II version 8.4.2
index_set.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2005 - 2015 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/memory_consumption.h>
17 #include <deal.II/base/index_set.h>
18 #include <list>
19 
20 #ifdef DEAL_II_WITH_TRILINOS
21 # ifdef DEAL_II_WITH_MPI
22 # include <Epetra_MpiComm.h>
23 # endif
24 # include <Epetra_SerialComm.h>
25 # include <Epetra_Map.h>
26 #endif
27 
28 DEAL_II_NAMESPACE_OPEN
29 
30 
31 
32 #ifdef DEAL_II_WITH_TRILINOS
33 
34 // the 64-bit path uses a few different names, so put that into a separate
35 // implementation
36 
37 #ifdef DEAL_II_WITH_64BIT_INDICES
38 
39 IndexSet::IndexSet (const Epetra_Map &map)
40  :
41  is_compressed (true),
42  index_space_size (map.NumGlobalElements64()),
43  largest_range (numbers::invalid_unsigned_int)
44 {
45  // For a contiguous map, we do not need to go through the whole data...
46  if (map.LinearMap())
47  add_range(size_type(map.MinMyGID64()), size_type(map.MaxMyGID64()+1));
48  else
49  {
50  const size_type n_indices = map.NumMyElements();
51  size_type *indices = (size_type *)map.MyGlobalElements64();
52  add_indices(indices, indices+n_indices);
53  }
54  compress();
55 }
56 
57 #else
58 
59 // this is the standard 32-bit implementation
60 
61 IndexSet::IndexSet (const Epetra_Map &map)
62  :
63  is_compressed (true),
64  index_space_size (map.NumGlobalElements()),
65  largest_range (numbers::invalid_unsigned_int)
66 {
67  // For a contiguous map, we do not need to go through the whole data...
68  if (map.LinearMap())
69  add_range(size_type(map.MinMyGID()), size_type(map.MaxMyGID()+1));
70  else
71  {
72  const size_type n_indices = map.NumMyElements();
73  unsigned int *indices = (unsigned int *)map.MyGlobalElements();
74  add_indices(indices, indices+n_indices);
75  }
76  compress();
77 }
78 
79 #endif
80 
81 #endif // ifdef DEAL_II_WITH_TRILINOS
82 
83 
84 
85 void
87  const size_type end)
88 {
89  Assert ((begin < index_space_size)
90  ||
91  ((begin == index_space_size) && (end == index_space_size)),
92  ExcIndexRangeType<size_type> (begin, 0, index_space_size));
93  Assert (end <= index_space_size,
94  ExcIndexRangeType<size_type> (end, 0, index_space_size+1));
95  Assert (begin <= end,
96  ExcIndexRangeType<size_type> (begin, 0, end));
97 
98  if (begin != end)
99  {
100  const Range new_range(begin,end);
101 
102  // the new index might be larger than the last index present in the
103  // ranges. Then we can skip the binary search
104  if (ranges.size() == 0 || begin > ranges.back().end)
105  ranges.push_back(new_range);
106  else
107  ranges.insert (Utilities::lower_bound (ranges.begin(),
108  ranges.end(),
109  new_range),
110  new_range);
111  is_compressed = false;
112  }
113 }
114 
115 
116 
117 void
119 {
120  // see if any of the contiguous ranges can be merged. do not use
121  // std::vector::erase in-place as it is quadratic in the number of
122  // ranges. since the ranges are sorted by their first index, determining
123  // overlap isn't all that hard
124  std::vector<Range>::iterator store = ranges.begin();
125  for (std::vector<Range>::iterator i = ranges.begin();
126  i != ranges.end(); )
127  {
128  std::vector<Range>::iterator
129  next = i;
130  ++next;
131 
132  size_type first_index = i->begin;
133  size_type last_index = i->end;
134 
135  // see if we can merge any of the following ranges
136  while (next != ranges.end() &&
137  (next->begin <= last_index))
138  {
139  last_index = std::max (last_index, next->end);
140  ++next;
141  }
142  i = next;
143 
144  // store the new range in the slot we last occupied
145  *store = Range(first_index, last_index);
146  ++store;
147  }
148  // use a compact array with exactly the right amount of storage
149  if (store != ranges.end())
150  {
151  std::vector<Range> new_ranges(ranges.begin(), store);
152  ranges.swap(new_ranges);
153  }
154 
155  // now compute indices within set and the range with most elements
156  size_type next_index = 0, largest_range_size = 0;
157  for (std::vector<Range>::iterator i = ranges.begin(); i != ranges.end();
158  ++i)
159  {
160  Assert(i->begin < i->end, ExcInternalError());
161 
162  i->nth_index_in_set = next_index;
163  next_index += (i->end - i->begin);
164  if (i->end - i->begin > largest_range_size)
165  {
166  largest_range_size = i->end - i->begin;
167  largest_range = i - ranges.begin();
168  }
169  }
170  is_compressed = true;
171 
172  // check that next_index is correct. needs to be after the previous
173  // statement because we otherwise will get into an endless loop
174  Assert (next_index == n_elements(), ExcInternalError());
175 }
176 
177 
178 
179 IndexSet
180 IndexSet::operator & (const IndexSet &is) const
181 {
182  Assert (size() == is.size(),
183  ExcDimensionMismatch (size(), is.size()));
184 
185  compress ();
186  is.compress ();
187 
188  std::vector<Range>::const_iterator r1 = ranges.begin(),
189  r2 = is.ranges.begin();
190  IndexSet result (size());
191 
192  while ((r1 != ranges.end())
193  &&
194  (r2 != is.ranges.end()))
195  {
196  // if r1 and r2 do not overlap at all, then move the pointer that sits
197  // to the left of the other up by one
198  if (r1->end <= r2->begin)
199  ++r1;
200  else if (r2->end <= r1->begin)
201  ++r2;
202  else
203  {
204  // the ranges must overlap somehow
205  Assert (((r1->begin <= r2->begin) &&
206  (r1->end > r2->begin))
207  ||
208  ((r2->begin <= r1->begin) &&
209  (r2->end > r1->begin)),
210  ExcInternalError());
211 
212  // add the overlapping range to the result
213  result.add_range (std::max (r1->begin,
214  r2->begin),
215  std::min (r1->end,
216  r2->end));
217 
218  // now move that iterator that ends earlier one up. note that it has
219  // to be this one because a subsequent range may still have a chance
220  // of overlapping with the range that ends later
221  if (r1->end <= r2->end)
222  ++r1;
223  else
224  ++r2;
225  }
226  }
227 
228  result.compress ();
229  return result;
230 }
231 
232 
233 
234 IndexSet
236  const size_type end) const
237 {
238  Assert (begin <= end,
239  ExcMessage ("End index needs to be larger or equal to begin index!"));
240  Assert (end <= size(),
241  ExcMessage ("Given range exceeds index set dimension"));
242 
243  IndexSet result (end-begin);
244  std::vector<Range>::const_iterator r1 = ranges.begin();
245 
246  while (r1 != ranges.end())
247  {
248  if ((r1->end > begin)
249  &&
250  (r1->begin < end))
251  {
252  result.add_range (std::max(r1->begin, begin)-begin,
253  std::min(r1->end, end)-begin);
254 
255  }
256  else if (r1->begin >= end)
257  break;
258 
259  ++r1;
260  }
261 
262  result.compress();
263  return result;
264 }
265 
266 
267 
268 void
270 {
271  compress();
272  other.compress();
273  is_compressed = false;
274 
275 
276  // we save new ranges to be added to our IndexSet in an temporary list and
277  // add all of them in one go at the end. This is necessary because a growing
278  // ranges vector invalidates iterators.
279  std::list<Range> temp_list;
280 
281  std::vector<Range>::iterator own_it = ranges.begin();
282  std::vector<Range>::iterator other_it = other.ranges.begin();
283 
284  while (own_it != ranges.end() && other_it != other.ranges.end())
285  {
286  //advance own iterator until we get an overlap
287  if (own_it->end <= other_it->begin)
288  {
289  ++own_it;
290  continue;
291  }
292  //we are done with other_it, so advance
293  if (own_it->begin >= other_it->end)
294  {
295  ++other_it;
296  continue;
297  }
298 
299  //Now own_it and other_it overlap. First save the part of own_it that
300  //is before other_it (if not empty).
301  if (own_it->begin < other_it->begin)
302  {
303  Range r(own_it->begin, other_it->begin);
304  r.nth_index_in_set = 0; //fix warning of unused variable
305  temp_list.push_back(r);
306  }
307  // change own_it to the sub range behind other_it. Do not delete own_it
308  // in any case. As removal would invalidate iterators, we just shrink
309  // the range to an empty one.
310  own_it->begin = other_it->end;
311  if (own_it->begin > own_it->end)
312  {
313  own_it->begin = own_it->end;
314  ++own_it;
315  }
316 
317  // continue without advancing iterators, the right one will be advanced
318  // next.
319  }
320 
321  // Now delete all empty ranges we might
322  // have created.
323  for (std::vector<Range>::iterator it = ranges.begin();
324  it != ranges.end(); )
325  {
326  if (it->begin >= it->end)
327  it = ranges.erase(it);
328  else
329  ++it;
330  }
331 
332  // done, now add the temporary ranges
333  for (std::list<Range>::iterator it = temp_list.begin();
334  it != temp_list.end();
335  ++it)
336  add_range(it->begin, it->end);
337 
338  compress();
339 }
340 
341 
342 
343 void
345  const unsigned int offset)
346 {
347  if ((this == &other) && (offset == 0))
348  return;
349 
350  compress();
351  other.compress();
352 
353  std::vector<Range>::const_iterator r1 = ranges.begin(),
354  r2 = other.ranges.begin();
355 
356  std::vector<Range> new_ranges;
357  // just get the start and end of the ranges right in this method, everything
358  // else will be done in compress()
359  while (r1 != ranges.end() || r2 != other.ranges.end())
360  {
361  // the two ranges do not overlap or we are at the end of one of the
362  // ranges
363  if (r2 == other.ranges.end() ||
364  (r1 != ranges.end() && r1->end < (r2->begin+offset)))
365  {
366  new_ranges.push_back(*r1);
367  ++r1;
368  }
369  else if (r1 == ranges.end() || (r2->end+offset) < r1->begin)
370  {
371  new_ranges.push_back(Range(r2->begin+offset,r2->end+offset));
372  ++r2;
373  }
374  else
375  {
376  // ok, we do overlap, so just take the combination of the current
377  // range (do not bother to merge with subsequent ranges)
378  Range next(std::min(r1->begin, r2->begin+offset),
379  std::max(r1->end, r2->end+offset));
380  new_ranges.push_back(next);
381  ++r1;
382  ++r2;
383  }
384  }
385  ranges.swap(new_ranges);
386 
387  is_compressed = false;
388  compress();
389 }
390 
391 
392 
393 void
394 IndexSet::write(std::ostream &out) const
395 {
396  compress();
397  out << size() << " ";
398  out << ranges.size() << std::endl;
399  std::vector<Range>::const_iterator r = ranges.begin();
400  for ( ; r!=ranges.end(); ++r)
401  {
402  out << r->begin << " " << r->end << std::endl;
403  }
404 }
405 
406 
407 
408 void
409 IndexSet::read(std::istream &in)
410 {
411  size_type s;
412  unsigned int numranges;
413 
414  in >> s >> numranges;
415  ranges.clear();
416  set_size(s);
417  for (unsigned int i=0; i<numranges; ++i)
418  {
419  size_type b, e;
420  in >> b >> e;
421  add_range(b,e);
422  }
423 }
424 
425 
426 void
427 IndexSet::block_write(std::ostream &out) const
428 {
429  AssertThrow (out, ExcIO());
430  out.write(reinterpret_cast<const char *>(&index_space_size),
431  sizeof(index_space_size));
432  size_t n_ranges = ranges.size();
433  out.write(reinterpret_cast<const char *>(&n_ranges),
434  sizeof(n_ranges));
435  if (ranges.empty() == false)
436  out.write (reinterpret_cast<const char *>(&*ranges.begin()),
437  ranges.size() * sizeof(Range));
438  AssertThrow (out, ExcIO());
439 }
440 
441 void
442 IndexSet::block_read(std::istream &in)
443 {
444  size_type size;
445  size_t n_ranges;
446  in.read(reinterpret_cast<char *>(&size), sizeof(size));
447  in.read(reinterpret_cast<char *>(&n_ranges), sizeof(n_ranges));
448  // we have to clear ranges first
449  ranges.clear();
450  set_size(size);
451  ranges.resize(n_ranges, Range(0,0));
452  if (n_ranges)
453  in.read(reinterpret_cast<char *>(&*ranges.begin()),
454  ranges.size() * sizeof(Range));
455 
456  do_compress(); // needed so that largest_range can be recomputed
457 }
458 
459 
460 
461 void IndexSet::fill_index_vector(std::vector<size_type> &indices) const
462 {
463  compress();
464 
465  indices.clear();
466  indices.reserve(n_elements());
467 
468  for (std::vector<Range>::iterator it = ranges.begin();
469  it != ranges.end();
470  ++it)
471  for (size_type i=it->begin; i<it->end; ++i)
472  indices.push_back (i);
473 
474  Assert (indices.size() == n_elements(), ExcInternalError());
475 }
476 
477 
478 
479 
480 
481 #ifdef DEAL_II_WITH_TRILINOS
482 
483 Epetra_Map
484 IndexSet::make_trilinos_map (const MPI_Comm &communicator,
485  const bool overlapping) const
486 {
487  compress ();
488 
489 #ifdef DEBUG
490  if (!overlapping)
491  {
492  const size_type n_global_elements
493  = Utilities::MPI::sum (n_elements(), communicator);
494  Assert (n_global_elements == size(),
495  ExcMessage ("You are trying to create an Epetra_Map object "
496  "that partitions elements of an index set "
497  "between processors. However, the union of the "
498  "index sets on different processors does not "
499  "contain all indices exactly once: the sum of "
500  "the number of entries the various processors "
501  "want to store locally is "
502  + Utilities::to_string (n_global_elements) +
503  " whereas the total size of the object to be "
504  "allocated is "
505  + Utilities::to_string (size()) +
506  ". In other words, there are "
507  "either indices that are not spoken for "
508  "by any processor, or there are indices that are "
509  "claimed by multiple processors."));
510  }
511 #endif
512 
513  if ((is_contiguous() == true) && (!overlapping))
514  return Epetra_Map (TrilinosWrappers::types::int_type(size()),
515  TrilinosWrappers::types::int_type(n_elements()),
516  0,
517 #ifdef DEAL_II_WITH_MPI
518  Epetra_MpiComm(communicator));
519 #else
520  Epetra_SerialComm());
521 #endif
522  else
523  {
524  std::vector<size_type> indices;
525  fill_index_vector(indices);
526 
527  return Epetra_Map (TrilinosWrappers::types::int_type(-1),
528  TrilinosWrappers::types::int_type(n_elements()),
529  (n_elements() > 0
530  ?
531  reinterpret_cast<TrilinosWrappers::types::int_type *>(&indices[0])
532  :
533  0),
534  0,
535 #ifdef DEAL_II_WITH_MPI
536  Epetra_MpiComm(communicator));
537 #else
538  Epetra_SerialComm());
539  (void)communicator;
540 #endif
541  }
542 }
543 
544 
545 #endif
546 
547 
548 std::size_t
550 {
554 }
555 
556 
557 
558 DEAL_II_NAMESPACE_CLOSE
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:604
ElementIterator end() const
Definition: index_set.h:1175
IndexSet operator&(const IndexSet &is) const
void block_read(std::istream &in)
Definition: index_set.cc:442
::ExceptionBase & ExcMessage(std::string arg1)
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition: index_set.h:1291
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:89
std::size_t memory_consumption() const
Definition: index_set.cc:549
size_type index_space_size
Definition: index_set.h:771
Epetra_Map make_trilinos_map(const MPI_Comm &communicator=MPI_COMM_WORLD, const bool overlapping=false) const
Definition: index_set.cc:484
size_type size() const
Definition: index_set.h:1247
void block_write(std::ostream &out) const
Definition: index_set.cc:427
std::vector< Range > ranges
Definition: index_set.h:755
T sum(const T &t, const MPI_Comm &mpi_communicator)
Definition: mpi.h:611
void subtract_set(const IndexSet &other)
Definition: index_set.cc:269
#define Assert(cond, exc)
Definition: exceptions.h:294
void do_compress() const
Definition: index_set.cc:118
void fill_index_vector(std::vector< size_type > &indices) const
Definition: index_set.cc:461
void add_range(const size_type begin, const size_type end)
Definition: index_set.cc:86
void set_size(const size_type size)
Definition: index_set.h:1234
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
IndexSet get_view(const size_type begin, const size_type end) const
Definition: index_set.cc:235
void compress() const
Definition: index_set.h:1256
bool is_contiguous() const
Definition: index_set.h:1370
bool is_compressed
Definition: index_set.h:765
void write(std::ostream &out) const
Definition: index_set.cc:394
types::global_dof_index size_type
Definition: index_set.h:70
ElementIterator begin() const
Definition: index_set.h:1165
void read(std::istream &in)
Definition: index_set.cc:409
size_type n_elements() const
Definition: index_set.h:1380
size_type largest_range
Definition: index_set.h:782