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 //
4 // Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
5 // Copyright (2009) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 //@HEADER
41 */
42 
43 #ifndef IFPACK2_OVERLAPPINGPARTITIONER_DEF_HPP
44 #define IFPACK2_OVERLAPPINGPARTITIONER_DEF_HPP
45 #include <vector>
46 #include <string>
47 #include <algorithm>
48 #include "Ifpack2_ConfigDefs.hpp"
49 #include "Ifpack2_OverlappingPartitioner_decl.hpp"
50 #include "Teuchos_Array.hpp"
51 #include "Teuchos_ArrayRCP.hpp"
52 
53 namespace Ifpack2 {
54 
55 template<class GraphType>
58  NumLocalParts_ (1),
59  Graph_ (graph),
60  OverlappingLevel_ (0),
61  IsComputed_ (false),
62  verbose_ (false),
63  maintainSparsity_(false)
64 {}
65 
66 
67 template<class GraphType>
69 
70 
71 template<class GraphType>
72 int
74 {
75  return NumLocalParts_;
76 }
77 
78 
79 template<class GraphType>
81 {
82  return OverlappingLevel_;
83 }
84 
85 
86 template<class GraphType>
87 typename GraphType::local_ordinal_type
89 operator () (const local_ordinal_type MyRow) const
90 {
92  MyRow < 0 || Teuchos::as<size_t> (MyRow) > Graph_->getNodeNumRows (),
93  std::runtime_error,
94  "Ifpack2::OverlappingPartitioner::operator(): "
95  "Invalid local row index " << MyRow << ".");
96 
97  return Partition_[MyRow];
98 }
99 
100 
101 //==============================================================================
102 template<class GraphType>
103 typename GraphType::local_ordinal_type
105 operator() (const local_ordinal_type i, const local_ordinal_type j) const
106 {
108  i < 0 || i > Teuchos::as<local_ordinal_type> (NumLocalParts_),
109  std::runtime_error,
110  "Ifpack2::OverlappingPartitioner::operator(): "
111  "Invalid local row index i=" << i << ".");
113  j < 0 || j > Teuchos::as<local_ordinal_type> (Parts_[i].size ()),
114  std::runtime_error,
115  "Ifpack2::OverlappingPartitioner::operator(): "
116  "Invalid node index j=" << j << ".");
117  return Parts_[i][j];
118 }
119 
120 //==============================================================================
121 template<class GraphType>
122 size_t
124 numRowsInPart (const local_ordinal_type Part) const
125 {
127  Part < 0 || Part > Teuchos::as<local_ordinal_type> (NumLocalParts_),
128  std::runtime_error,
129  "Ifpack2::OverlappingPartitioner::numRowsInPart: "
130  "Invalid partition index Part=" << Part << ".");
131  return Parts_[Part].size ();
132 }
133 
134 //==============================================================================
135 template<class GraphType>
136 void
138 rowsInPart (const local_ordinal_type Part,
140 {
141  // Let numRowsInPart do the sanity checking...
142  const size_t numRows = numRowsInPart (Part);
143  for (size_t i = 0; i < numRows; ++i) {
144  List[i] = Parts_[Part][i];
145  }
146 }
147 
148 //==============================================================================
149 template<class GraphType>
152 {
153  return Partition_.view (0, Graph_->getNodeNumRows ());
154 }
155 
156 //==============================================================================
157 template<class GraphType>
158 void
161 {
162  NumLocalParts_ = List.get("partitioner: local parts", NumLocalParts_);
163  OverlappingLevel_ = List.get("partitioner: overlap", OverlappingLevel_);
164  verbose_ = List.get("partitioner: print level", verbose_);
165  maintainSparsity_ = List.get("partitioner: maintain sparsity", false);
166 
167  if (NumLocalParts_ < 0) {
168  NumLocalParts_ = Graph_->getNodeNumRows() / (-NumLocalParts_);
169  }
170  if (NumLocalParts_ == 0) {
171  NumLocalParts_ = 1;
172  }
173 
174  // Sanity checking
176  NumLocalParts_ < 0 ||
177  Teuchos::as<size_t> (NumLocalParts_) > Graph_->getNodeNumRows(),
178  std::runtime_error,
179  "Ifpack2::OverlappingPartitioner::setParameters: "
180  "Invalid NumLocalParts_ = " << NumLocalParts_ << ".");
182  OverlappingLevel_ < 0, std::runtime_error,
183  "Ifpack2::OverlappingPartitioner::setParameters: "
184  "Invalid OverlappingLevel_ = " << OverlappingLevel_ << ".");
185 
186  setPartitionParameters(List);
187 }
188 
189 //==============================================================================
190 template<class GraphType>
192 {
193  using std::cout;
194  using std::endl;
195 
197  NumLocalParts_ < 1 || OverlappingLevel_ < 0,
198  std::runtime_error,
199  "Ifpack2::OverlappingPartitioner::compute: "
200  "Invalid NumLocalParts_ or OverlappingLevel_.");
201 
202  // std::string's constructor has some overhead, so it's better to
203  // use const char[] for local constant strings.
204  const char printMsg[] = "OverlappingPartitioner: ";
205 
206  if (verbose_ && (Graph_->getComm()->getRank() == 0)) {
207  cout << printMsg << "Number of local parts = "
208  << NumLocalParts_ << endl;
209  cout << printMsg << "Approx. Number of global parts = "
210  << NumLocalParts_ * Graph_->getComm ()->getSize () << endl;
211  cout << printMsg << "Amount of overlap = "
212  << OverlappingLevel_ << endl;
213  }
214 
215  // 1.- allocate memory
216  Partition_.resize (Graph_->getNodeNumRows ());
217  //Parts_ is allocated in computeOverlappingPartitions_, where it is used
218 
219  // 2.- sanity checks on input graph
221  ! Graph_->isFillComplete (), std::runtime_error,
222  "Ifpack2::OverlappingPartitioner::compute: "
223  "The input graph must be fill complete.");
224 
226  Graph_->getGlobalNumRows () != Graph_->getGlobalNumCols (),
227  std::runtime_error,
228  "Ifpack2::OverlappingPartitioner::compute: "
229  "The input graph must be (globally) square.");
230 
231  // 3.- perform non-overlapping partition
232  computePartitions ();
233 
234  // 4.- compute the partitions with overlapping
235  computeOverlappingPartitions ();
236 
237  // 5.- mark as computed
238  IsComputed_ = true;
239 }
240 
241 //==============================================================================
242 template<class GraphType>
244 {
245  //If user has explicitly specified parts, then Partition_ size has been set to 0.
246  //In this case, there is no need to compute Parts_.
247  if (Partition_.size() == 0)
248  return;
249 
250  const local_ordinal_type invalid =
252 
253  // Old FIXME from Ifpack: the first part of this function should be elsewhere
254 
255  // start defining the subgraphs for no overlap
256 
257  std::vector<size_t> sizes;
258  sizes.resize (NumLocalParts_);
259 
260  // 1.- compute how many rows are in each subgraph
261  for (int i = 0; i < NumLocalParts_; ++i) {
262  sizes[i] = 0;
263  }
264 
265  for (size_t i = 0; i < Graph_->getNodeNumRows (); ++i) {
267  Partition_[i] >= NumLocalParts_, std::runtime_error,
268  "Ifpack2::OverlappingPartitioner::computeOverlappingPartitions: "
269  "Partition_[i] > NumLocalParts_.");
270  // invalid indicates that this unknown is not in a nonoverlapping
271  // partition
272  if (Partition_[i] != invalid) {
273  sizes[Partition_[i]]++;
274  }
275  }
276 
277  // 2.- allocate space for each subgraph
278  Parts_.resize (NumLocalParts_);
279  for (int i = 0; i < NumLocalParts_; ++i) {
280  Parts_[i].resize (sizes[i]);
281  }
282 
283  // 3.- cycle over all rows and populate the vectors
284  for (int i = 0; i < NumLocalParts_; ++i) {
285  sizes[i] = 0;
286  }
287 
288  for (size_t i = 0; i < Graph_->getNodeNumRows (); ++i) {
289  const local_ordinal_type part = Partition_[i];
290  if (part != invalid) {
291  const size_t count = sizes[part];
292  Parts_[part][count] = i;
293  sizes[part]++;
294  }
295  }
296 
297  // If there is no overlap, we're done, so return
298  if (OverlappingLevel_ == 0) {
299  return;
300  }
301 
302  // wider overlap requires further computations
303  for (int level = 1; level <= OverlappingLevel_; ++level) {
304  std::vector<std::vector<size_t> > tmp;
305  tmp.resize (NumLocalParts_);
306 
307  // cycle over all rows in the local graph (that is the overlapping
308  // graph). For each row, all columns will belong to the subgraph
309  // of row `i'.
310 
311  int MaxNumEntries_tmp = Graph_->getNodeMaxNumRowEntries();
313  Indices.resize (MaxNumEntries_tmp);
315  newIndices.resize(MaxNumEntries_tmp);
316 
317  if (!maintainSparsity_) {
318 
319  local_ordinal_type numLocalRows = Graph_->getNodeNumRows();
320  for (int part = 0; part < NumLocalParts_ ; ++part) {
321  for (size_t i = 0; i < Teuchos::as<size_t> (Parts_[part].size ()); ++i) {
322  const local_ordinal_type LRID = Parts_[part][i];
323 
324  size_t numIndices;
325  Graph_->getLocalRowCopy (LRID, Indices (), numIndices);
326 
327  for (size_t j = 0; j < numIndices; ++j) {
328  // use *local* indices only
329  const local_ordinal_type col = Indices[j];
330  if (col >= numLocalRows) {
331  continue;
332  }
333 
334  // has this column already been inserted?
335  std::vector<size_t>::iterator where =
336  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (col));
337 
338 
339  if (where == tmp[part].end()) {
340  tmp[part].push_back (col);
341  }
342  }
343 
344  //10-Jan-2017 JHU : A possible optimization is to avoid the std::find's in the loop above,
345  //but instead sort and make unique afterwards. One would have to be careful to only sort/
346  //make unique the insertions associated with the current row LRID, as for each row, LRID
347  //may occur after all other col indices for row LRID (see comment about zero pivot below).
348 
349  // has this column already been inserted?
350  std::vector<size_t>::iterator where =
351  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (LRID));
352 
353  // This happens here b/c Vanka on Stokes with Stabilized elements will have
354  // a zero pivot entry if this gets pushed back first. So... Last.
355  if (where == tmp[part].end ()) {
356  tmp[part].push_back (LRID);
357  }
358  }
359  } //for (int part = 0; ...
360 
361  } else {
362  //maintainSparsity_ == true
363 
364  for (int part = 0; part < NumLocalParts_ ; ++part) {
365  for (size_t i = 0; i < Teuchos::as<size_t> (Parts_[part].size ()); ++i) {
366  const local_ordinal_type LRID = Parts_[part][i];
367 
368  size_t numIndices;
369  Graph_->getLocalRowCopy (LRID, Indices (), numIndices);
370  //JJH: the entries in Indices are already sorted. However, the Tpetra documentation states
371  // that we can't count on this always being true, hence we sort. Also note that there are
372  // unused entries at the end of Indices (it's sized to hold any row). This means we can't
373  // just use Indices.end() in sorting and in std::includes
374  std::sort(Indices.begin(),Indices.begin()+numIndices);
375 
376  for (size_t j = 0; j < numIndices; ++j) {
377  // use *local* indices only
378  const local_ordinal_type col = Indices[j];
379  if (Teuchos::as<size_t> (col) >= Graph_->getNodeNumRows ()) {
380  continue;
381  }
382 
383  // has this column already been inserted?
384  std::vector<size_t>::iterator where =
385  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (col));
386 
387 
388  if (where == tmp[part].end()) {
389  // Check if row associated with "col" increases connectivity already defined by row LRID's stencil.
390  // If it does and maintainSparsity_ is true, do not add "col" to the current partition (block).
391  size_t numNewIndices;
392  Graph_->getLocalRowCopy(col, newIndices(), numNewIndices);
393  std::sort(newIndices.begin(),newIndices.begin()+numNewIndices);
394  bool isSubset = std::includes(Indices.begin(),Indices.begin()+numIndices,
395  newIndices.begin(),newIndices.begin()+numNewIndices);
396  if (isSubset) {
397  tmp[part].push_back (col);
398  }
399  }
400  }
401 
402  // has this column already been inserted?
403  std::vector<size_t>::iterator where =
404  std::find (tmp[part].begin (), tmp[part].end (), Teuchos::as<size_t> (LRID));
405 
406  // This happens here b/c Vanka on Stokes with Stabilized elements will have
407  // a zero pivot entry if this gets pushed back first. So... Last.
408  if (where == tmp[part].end ()) {
409  tmp[part].push_back (LRID);
410  }
411  }
412  } //for (int part = 0;
413 
414  } //if (maintainSparsity_) ... else
415 
416  // now I convert the STL vectors into Teuchos Array RCP's
417  //
418  // FIXME (mfh 12 July 2013) You could have started with ArrayRCP
419  // in the first place (which implements push_back and iterators)
420  // and avoided the copy.
421  for (int i = 0; i < NumLocalParts_; ++i) {
422  Parts_[i].resize (tmp[i].size ());
423  for (size_t j = 0; j < tmp[i].size (); ++j) {
424  Parts_[i][j] = tmp[i][j];
425  }
426  }
427  }
428 }
429 
430 //==============================================================================
431 template<class GraphType>
433 {
434  return IsComputed_;
435 }
436 
437 //==============================================================================
438 template<class GraphType>
439 std::ostream&
441 {
442  Teuchos::FancyOStream fos (Teuchos::rcpFromRef (os));
443  fos.setOutputToRootOnly (0);
444  describe (fos);
445  return os;
446 }
447 
448 //==============================================================================
449 template<class GraphType>
451 {
452  std::ostringstream oss;
454  if (isComputed()) {
455  oss << "{status = computed";
456  }
457  else {
458  oss << "{status = is not computed";
459  }
460  oss <<"}";
461  return oss.str();
462 }
463 
464 //==============================================================================
465 template<class GraphType>
467 {
468  using std::endl;
469  if (verbLevel == Teuchos::VERB_NONE) {
470  return;
471  }
472 
473  os << "================================================================================" << endl;
474  os << "Ifpack2::OverlappingPartitioner" << endl;
475  os << "Number of local rows = " << Graph_->getNodeNumRows() << endl;
476  os << "Number of global rows = " << Graph_->getGlobalNumRows() << endl;
477  os << "Number of local parts = " << NumLocalParts_ << endl;
478  os << "Overlapping level = " << OverlappingLevel_ << endl;
479  os << "Is computed = " << IsComputed_ << endl;
480  os << "================================================================================" << endl;
481 }
482 
483 }// namespace Ifpack2
484 
485 #define IFPACK2_OVERLAPPINGPARTITIONER_INSTANT(LO,GO,N) \
486  template class Ifpack2::OverlappingPartitioner<Tpetra::CrsGraph< LO, GO, N > >; \
487  template class Ifpack2::OverlappingPartitioner<Tpetra::RowGraph< LO, GO, N > >;
488 
489 #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:138
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:151
T & get(const std::string &name, T def_value)
OverlappingPartitioner(const Teuchos::RCP< const row_graph_type > &graph)
Constructor.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:57
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
int overlappingLevel() const
The number of levels of overlap.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:80
int numLocalParts() const
Number of computed local partitions.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:73
virtual void computeOverlappingPartitions()
Computes the partitions. Returns 0 if successful.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:243
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:466
virtual ~OverlappingPartitioner()
Destructor.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:68
virtual bool isComputed() const
Returns true if partitions have been computed successfully.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:432
virtual std::string description() const
std::string description() const
Return a simple one-line description of this object.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:450
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
void resize(size_type new_size, const value_type &x=value_type())
virtual void compute()
Computes the partitions. Returns 0 if successful.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:191
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:440
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:89
virtual void setParameters(Teuchos::ParameterList &List)
Set all the parameters for the partitioner.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:160
size_t numRowsInPart(const local_ordinal_type Part) const
the number of rows contained in the given partition.
Definition: Ifpack2_OverlappingPartitioner_def.hpp:124
iterator begin()