Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Ifpack2_OverlappingPartitioner_def.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4 //
5 // Copyright 2009 NTESS and the Ifpack2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef IFPACK2_OVERLAPPINGPARTITIONER_DEF_HPP
11 #define IFPACK2_OVERLAPPINGPARTITIONER_DEF_HPP
12 #include <vector>
13 #include <string>
14 #include <algorithm>
15 #include "Ifpack2_ConfigDefs.hpp"
16 #include "Ifpack2_OverlappingPartitioner_decl.hpp"
17 #include "Teuchos_Array.hpp"
18 #include "Teuchos_ArrayRCP.hpp"
19 
20 namespace Ifpack2 {
21 
22 template<class GraphType>
25  NumLocalParts_ (1),
26  Graph_ (graph),
27  OverlappingLevel_ (0),
28  IsComputed_ (false),
29  verbose_ (false),
30  maintainSparsity_(false)
31 {}
32 
33 
34 template<class GraphType>
36 
37 
38 template<class GraphType>
39 int
41 {
42  return NumLocalParts_;
43 }
44 
45 
46 template<class GraphType>
48 {
49  return OverlappingLevel_;
50 }
51 
52 
53 template<class GraphType>
54 typename GraphType::local_ordinal_type
56 operator () (const local_ordinal_type MyRow) const
57 {
59  MyRow < 0 || Teuchos::as<size_t> (MyRow) > Graph_->getLocalNumRows (),
60  std::runtime_error,
61  "Ifpack2::OverlappingPartitioner::operator(): "
62  "Invalid local row index " << MyRow << ".");
63 
64  return Partition_[MyRow];
65 }
66 
67 
68 //==============================================================================
69 template<class GraphType>
70 typename GraphType::local_ordinal_type
72 operator() (const local_ordinal_type i, const local_ordinal_type j) const
73 {
75  i < 0 || i > Teuchos::as<local_ordinal_type> (NumLocalParts_),
76  std::runtime_error,
77  "Ifpack2::OverlappingPartitioner::operator(): "
78  "Invalid local row index i=" << i << ".");
80  j < 0 || j > Teuchos::as<local_ordinal_type> (Parts_[i].size ()),
81  std::runtime_error,
82  "Ifpack2::OverlappingPartitioner::operator(): "
83  "Invalid node index j=" << j << ".");
84  return Parts_[i][j];
85 }
86 
87 //==============================================================================
88 template<class GraphType>
89 size_t
91 numRowsInPart (const local_ordinal_type Part) const
92 {
94  Part < 0 || Part > Teuchos::as<local_ordinal_type> (NumLocalParts_),
95  std::runtime_error,
96  "Ifpack2::OverlappingPartitioner::numRowsInPart: "
97  "Invalid partition index Part=" << Part << ".");
98  return Parts_[Part].size ();
99 }
100 
101 //==============================================================================
102 template<class GraphType>
103 void
105 rowsInPart (const local_ordinal_type Part,
107 {
108  // Let numRowsInPart do the sanity checking...
109  const size_t numRows = numRowsInPart (Part);
110  for (size_t i = 0; i < numRows; ++i) {
111  List[i] = Parts_[Part][i];
112  }
113 }
114 
115 //==============================================================================
116 template<class GraphType>
119 {
120  return Partition_.view (0, Graph_->getLocalNumRows ());
121 }
122 
123 //==============================================================================
124 template<class GraphType>
125 void
128 {
129  NumLocalParts_ = List.get("partitioner: local parts", NumLocalParts_);
130  OverlappingLevel_ = List.get("partitioner: overlap", OverlappingLevel_);
131  verbose_ = List.get("partitioner: print level", verbose_);
132  maintainSparsity_ = List.get("partitioner: maintain sparsity", false);
135 
136  // when using overlapping schwarz wth combineMode ADD, we need import and
137  // overlap row map to adjust weights for ith dof. Specifically, we sum
138  // all blocks (including off processor ones) that contain i.
139  import_type theImport = Graph_->getImporter();
140  if (theImport != Teuchos::null) List.set< import_type >("theImport",theImport);
141  List.set< map_type >("OverlapRowMap",Graph_->getRowMap());
142 
143  if (NumLocalParts_ < 0) {
144  NumLocalParts_ = Graph_->getLocalNumRows() / (-NumLocalParts_);
145  }
146  if (NumLocalParts_ == 0) {
147  NumLocalParts_ = 1;
148  }
149 
150  // Sanity checking
152  NumLocalParts_ < 0 ||
153  Teuchos::as<size_t> (NumLocalParts_) > Graph_->getLocalNumRows(),
154  std::runtime_error,
155  "Ifpack2::OverlappingPartitioner::setParameters: "
156  "Invalid NumLocalParts_ = " << NumLocalParts_ << ".");
158  OverlappingLevel_ < 0, std::runtime_error,
159  "Ifpack2::OverlappingPartitioner::setParameters: "
160  "Invalid OverlappingLevel_ = " << OverlappingLevel_ << ".");
161 
162  setPartitionParameters(List);
163 }
164 
165 //==============================================================================
166 template<class GraphType>
168 {
169  using std::cout;
170  using std::endl;
171 
173  NumLocalParts_ < 1 || OverlappingLevel_ < 0,
174  std::runtime_error,
175  "Ifpack2::OverlappingPartitioner::compute: "
176  "Invalid NumLocalParts_ or OverlappingLevel_.");
177 
178  // std::string's constructor has some overhead, so it's better to
179  // use const char[] for local constant strings.
180  const char printMsg[] = "OverlappingPartitioner: ";
181 
182  if (verbose_ && (Graph_->getComm()->getRank() == 0)) {
183  cout << printMsg << "Number of local parts = "
184  << NumLocalParts_ << endl;
185  cout << printMsg << "Approx. Number of global parts = "
186  << NumLocalParts_ * Graph_->getComm ()->getSize () << endl;
187  cout << printMsg << "Amount of overlap = "
188  << OverlappingLevel_ << endl;
189  }
190 
191  // 1.- allocate memory
192  Partition_.resize (Graph_->getLocalNumRows ());
193  //Parts_ is allocated in computeOverlappingPartitions_, where it is used
194 
195  // 2.- sanity checks on input graph
197  ! Graph_->isFillComplete (), std::runtime_error,
198  "Ifpack2::OverlappingPartitioner::compute: "
199  "The input graph must be fill complete.");
200 
202  Graph_->getGlobalNumRows () != Graph_->getGlobalNumCols (),
203  std::runtime_error,
204  "Ifpack2::OverlappingPartitioner::compute: "
205  "The input graph must be (globally) square.");
206 
207  // 3.- perform non-overlapping partition
208  computePartitions ();
209 
210  // 4.- compute the partitions with overlapping
211  computeOverlappingPartitions ();
212 
213  // 5.- mark as computed
214  IsComputed_ = true;
215 }
216 
217 //==============================================================================
218 template<class GraphType>
220 {
221  //If user has explicitly specified parts, then Partition_ size has been set to 0.
222  //In this case, there is no need to compute Parts_.
223  if (Partition_.size() == 0)
224  return;
225 
226  const local_ordinal_type invalid =
228 
229  // Old FIXME from Ifpack: the first part of this function should be elsewhere
230 
231  // start defining the subgraphs for no overlap
232 
233  std::vector<size_t> sizes;
234  sizes.resize (NumLocalParts_);
235 
236  // 1.- compute how many rows are in each subgraph
237  for (int i = 0; i < NumLocalParts_; ++i) {
238  sizes[i] = 0;
239  }
240 
241  for (size_t i = 0; i < Graph_->getLocalNumRows (); ++i) {
243  Partition_[i] >= NumLocalParts_, std::runtime_error,
244  "Ifpack2::OverlappingPartitioner::computeOverlappingPartitions: "
245  "Partition_[i] > NumLocalParts_.");
246  // invalid indicates that this unknown is not in a nonoverlapping
247  // partition
248  if (Partition_[i] != invalid) {
249  sizes[Partition_[i]]++;
250  }
251  }
252 
253  // 2.- allocate space for each subgraph
254  Parts_.resize (NumLocalParts_);
255  for (int i = 0; i < NumLocalParts_; ++i) {
256  Parts_[i].resize (sizes[i]);
257  }
258 
259  // 3.- cycle over all rows and populate the vectors
260  for (int i = 0; i < NumLocalParts_; ++i) {
261  sizes[i] = 0;
262  }
263 
264  for (size_t i = 0; i < Graph_->getLocalNumRows (); ++i) {
265  const local_ordinal_type part = Partition_[i];
266  if (part != invalid) {
267  const size_t count = sizes[part];
268  Parts_[part][count] = i;
269  sizes[part]++;
270  }
271  }
272 
273  // If there is no overlap, we're done, so return
274  if (OverlappingLevel_ == 0) {
275  return;
276  }
277 
278  // wider overlap requires further computations
279  for (int level = 1; level <= OverlappingLevel_; ++level) {
280  std::vector<std::vector<size_t> > tmp;
281  tmp.resize (NumLocalParts_);
282 
283  // cycle over all rows in the local graph (that is the overlapping
284  // graph). For each row, all columns will belong to the subgraph
285  // of row `i'.
286 
287  int MaxNumEntries_tmp = Graph_->getLocalMaxNumRowEntries();
288  nonconst_local_inds_host_view_type Indices("Indices",MaxNumEntries_tmp);
289  nonconst_local_inds_host_view_type newIndices("newIndices",MaxNumEntries_tmp);
290 
291  if (!maintainSparsity_) {
292 
293  local_ordinal_type numLocalRows = Graph_->getLocalNumRows();
294  for (int part = 0; part < NumLocalParts_ ; ++part) {
295  for (size_t i = 0; i < Teuchos::as<size_t> (Parts_[part].size ()); ++i) {
296  const local_ordinal_type LRID = Parts_[part][i];
297 
298  size_t numIndices;
299  Graph_->getLocalRowCopy (LRID, Indices, numIndices);
300 
301  for (size_t j = 0; j < numIndices; ++j) {
302  // use *local* indices only
303  const local_ordinal_type col = Indices[j];
304  if (col >= numLocalRows) {
305  continue;
306  }
307 
308  // has this column already been inserted?
309  std::vector<size_t>::iterator where =
310  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (col));
311 
312 
313  if (where == tmp[part].end()) {
314  tmp[part].push_back (col);
315  }
316  }
317 
318  //10-Jan-2017 JHU : A possible optimization is to avoid the std::find's in the loop above,
319  //but instead sort and make unique afterwards. One would have to be careful to only sort/
320  //make unique the insertions associated with the current row LRID, as for each row, LRID
321  //may occur after all other col indices for row LRID (see comment about zero pivot below).
322 
323  // has this column already been inserted?
324  std::vector<size_t>::iterator where =
325  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (LRID));
326 
327  // This happens here b/c Vanka on Stokes with Stabilized elements will have
328  // a zero pivot entry if this gets pushed back first. So... Last.
329  if (where == tmp[part].end ()) {
330  tmp[part].push_back (LRID);
331  }
332  }
333  } //for (int part = 0; ...
334 
335  } else {
336  //maintainSparsity_ == true
337 
338  for (int part = 0; part < NumLocalParts_ ; ++part) {
339  for (size_t i = 0; i < Teuchos::as<size_t> (Parts_[part].size ()); ++i) {
340  const local_ordinal_type LRID = Parts_[part][i];
341 
342  size_t numIndices;
343  Graph_->getLocalRowCopy (LRID, Indices, numIndices);
344  //JJH: the entries in Indices are already sorted. However, the Tpetra documentation states
345  // that we can't count on this always being true, hence we sort. Also note that there are
346  // unused entries at the end of Indices (it's sized to hold any row). This means we can't
347  // just use Indices.end() in sorting and in std::includes
348  Tpetra::sort(Indices,numIndices);
349 
350  for (size_t j = 0; j < numIndices; ++j) {
351  // use *local* indices only
352  const local_ordinal_type col = Indices[j];
353  if (Teuchos::as<size_t> (col) >= Graph_->getLocalNumRows ()) {
354  continue;
355  }
356 
357  // has this column already been inserted?
358  std::vector<size_t>::iterator where =
359  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (col));
360 
361 
362  if (where == tmp[part].end()) {
363  // Check if row associated with "col" increases connectivity already defined by row LRID's stencil.
364  // If it does and maintainSparsity_ is true, do not add "col" to the current partition (block).
365  size_t numNewIndices;
366  Graph_->getLocalRowCopy(col, newIndices, numNewIndices);
367  Tpetra::sort(newIndices,numNewIndices);
368  auto Indices_rcp = Kokkos::Compat::persistingView<nonconst_local_inds_host_view_type>(Indices, 0, numIndices);
369  auto newIndices_rcp = Kokkos::Compat::persistingView<nonconst_local_inds_host_view_type>(newIndices, 0, numNewIndices);
370  bool isSubset = std::includes(Indices_rcp.begin(),Indices_rcp.begin()+numIndices,
371  newIndices_rcp.begin(),newIndices_rcp.begin()+numNewIndices);
372  if (isSubset) {
373  tmp[part].push_back (col);
374  }
375  }
376  }
377 
378  // has this column already been inserted?
379  std::vector<size_t>::iterator where =
380  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (LRID));
381 
382  // This happens here b/c Vanka on Stokes with Stabilized elements will have
383  // a zero pivot entry if this gets pushed back first. So... Last.
384  if (where == tmp[part].end ()) {
385  tmp[part].push_back (LRID);
386  }
387  }
388  } //for (int part = 0;
389 
390  } //if (maintainSparsity_) ... else
391 
392  // now I convert the STL vectors into Teuchos Array RCP's
393  //
394  // FIXME (mfh 12 July 2013) You could have started with ArrayRCP
395  // in the first place (which implements push_back and iterators)
396  // and avoided the copy.
397  for (int i = 0; i < NumLocalParts_; ++i) {
398  Parts_[i].resize (tmp[i].size ());
399  for (size_t j = 0; j < tmp[i].size (); ++j) {
400  Parts_[i][j] = tmp[i][j];
401  }
402  }
403  }
404 }
405 
406 //==============================================================================
407 template<class GraphType>
409 {
410  return IsComputed_;
411 }
412 
413 //==============================================================================
414 template<class GraphType>
415 std::ostream&
417 {
418  Teuchos::FancyOStream fos (Teuchos::rcpFromRef (os));
419  fos.setOutputToRootOnly (0);
420  describe (fos);
421  return os;
422 }
423 
424 //==============================================================================
425 template<class GraphType>
427 {
428  std::ostringstream oss;
430  if (isComputed()) {
431  oss << "{status = computed";
432  }
433  else {
434  oss << "{status = is not computed";
435  }
436  oss <<"}";
437  return oss.str();
438 }
439 
440 //==============================================================================
441 template<class GraphType>
443 {
444  using std::endl;
445  if (verbLevel == Teuchos::VERB_NONE) {
446  return;
447  }
448 
449  os << "================================================================================" << endl;
450  os << "Ifpack2::OverlappingPartitioner" << endl;
451  os << "Number of local rows = " << Graph_->getLocalNumRows() << endl;
452  os << "Number of global rows = " << Graph_->getGlobalNumRows() << endl;
453  os << "Number of local parts = " << NumLocalParts_ << endl;
454  os << "Overlapping level = " << OverlappingLevel_ << endl;
455  os << "Is computed = " << IsComputed_ << endl;
456  os << "================================================================================" << endl;
457 }
458 
459 }// namespace Ifpack2
460 
461 #define IFPACK2_OVERLAPPINGPARTITIONER_INSTANT(LO,GO,N) \
462  template class Ifpack2::OverlappingPartitioner<Tpetra::CrsGraph< LO, GO, N > >; \
463  template class Ifpack2::OverlappingPartitioner<Tpetra::RowGraph< LO, GO, N > >;
464 
465 #endif // IFPACK2_OVERLAPPINGPARTITIONER_DEF_HPP
void rowsInPart(const local_ordinal_type Part, Teuchos::ArrayRCP< local_ordinal_type > &List) const
Fill List with the local indices of the rows in the (overlapping) partition Part. ...
Definition: Ifpack2_OverlappingPartitioner_def.hpp:105
virtual Teuchos::ArrayView< const local_ordinal_type > nonOverlappingPartition() const
A view of the local indices of the nonoverlapping partitions of each local row.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:118
T & get(const std::string &name, T def_value)
OverlappingPartitioner(const Teuchos::RCP< const row_graph_type > &graph)
Constructor.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:24
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
int overlappingLevel() const
The number of levels of overlap.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:47
int numLocalParts() const
Number of computed local partitions.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:40
virtual void computeOverlappingPartitions()
Computes the partitions. Returns 0 if successful.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:219
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print the object with some verbosity level to an FancyOStream object.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:442
virtual ~OverlappingPartitioner()
Destructor.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:35
virtual bool isComputed() const
Returns true if partitions have been computed successfully.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:408
virtual std::string description() const
std::string description() const
Return a simple one-line description of this object.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:426
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
virtual void compute()
Computes the partitions. Returns 0 if successful.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:167
virtual std::ostream & print(std::ostream &os) const
Prints basic information on iostream. This function is used by operator&lt;&lt;.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:416
local_ordinal_type operator()(const local_ordinal_type MyRow) const
Local index of the nonoverlapping partition of the given row.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:56
virtual void setParameters(Teuchos::ParameterList &List)
Set all the parameters for the partitioner.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:127
size_t numRowsInPart(const local_ordinal_type Part) const
the number of rows contained in the given partition.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:91