Ifpack2 Templated Preconditioning Package  Version 1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Ifpack2_IlukGraph.hpp
Go to the documentation of this file.
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 
48 
49 #ifndef IFPACK2_ILUK_GRAPH_HPP
50 #define IFPACK2_ILUK_GRAPH_HPP
51 
52 #include <algorithm>
53 #include <vector>
54 
55 #include <Ifpack2_ConfigDefs.hpp>
57 #include <Teuchos_CommHelpers.hpp>
58 #include <Tpetra_CrsGraph.hpp>
59 #include <Tpetra_Import.hpp>
60 #include <Ifpack2_CreateOverlapGraph.hpp>
61 #include <Ifpack2_Parameters.hpp>
62 
63 namespace Ifpack2 {
64 
96 template<class GraphType>
98 public:
99  typedef typename GraphType::local_ordinal_type local_ordinal_type;
100  typedef typename GraphType::global_ordinal_type global_ordinal_type;
101  typedef typename GraphType::node_type node_type;
102 
104  typedef Tpetra::RowGraph<local_ordinal_type,
105  global_ordinal_type,
106  node_type> row_graph_type;
108  typedef Tpetra::CrsGraph<local_ordinal_type,
109  global_ordinal_type,
110  node_type> crs_graph_type;
111 
124  const int levelFill,
125  const int levelOverlap,
126  const double overalloc = 2.);
127 
129  virtual ~IlukGraph ();
130 
136  void setParameters (const Teuchos::ParameterList& parameterlist);
137 
149  void initialize ();
150 
152  int getLevelFill () const { return LevelFill_; }
153 
155  int getLevelOverlap () const { return LevelOverlap_; }
156 
159  return L_Graph_;
160  }
161 
164  return U_Graph_;
165  }
166 
169  return OverlapGraph_;
170  }
171 
173  size_t getNumGlobalDiagonals() const { return NumGlobalDiagonals_; }
174 
175 private:
176  typedef typename GraphType::map_type map_type;
177 
187 
196  IlukGraph& operator= (const IlukGraph<GraphType>&);
197 
199  void constructOverlapGraph();
200 
203  int LevelFill_;
204  int LevelOverlap_;
205  const double Overalloc_;
208  size_t NumMyDiagonals_;
209  size_t NumGlobalDiagonals_;
210 };
211 
212 
213 template<class GraphType>
216  const int levelFill,
217  const int levelOverlap,
218  const double overalloc)
219  : Graph_ (G),
220  LevelFill_ (levelFill),
221  LevelOverlap_ (levelOverlap),
222  Overalloc_ (overalloc),
223  NumMyDiagonals_ (0),
224  NumGlobalDiagonals_ (0)
225 {
226  TEUCHOS_TEST_FOR_EXCEPTION(Overalloc_ <= 1., std::runtime_error,
227  "Ifpack2::IlukGraph: FATAL: overalloc must be greater than 1.")
228 }
229 
230 
231 template<class GraphType>
233 {}
234 
235 
236 template<class GraphType>
238 setParameters (const Teuchos::ParameterList& parameterlist)
239 {
240  getParameter (parameterlist, "iluk level-of-fill", LevelFill_);
241  getParameter (parameterlist, "iluk level-of-overlap", LevelOverlap_);
242 }
243 
244 
245 template<class GraphType>
247  // FIXME (mfh 22 Dec 2013) This won't do if we want
248  // RILUK::initialize() to do the right thing (that is,
249  // unconditionally recompute the "symbolic factorization").
250  if (OverlapGraph_ == Teuchos::null) {
251  OverlapGraph_ = createOverlapGraph<GraphType> (Graph_, LevelOverlap_);
252  }
253 }
254 
255 
256 template<class GraphType>
258 {
259  using Teuchos::Array;
260  using Teuchos::ArrayView;
261  using Teuchos::RCP;
262  using Teuchos::rcp;
263  using Teuchos::REDUCE_SUM;
264  using Teuchos::reduceAll;
265 
266  size_t NumIn, NumL, NumU;
267  bool DiagFound;
268 
269  constructOverlapGraph();
270 
271  // Get Maximum Row length
272  const int MaxNumIndices = OverlapGraph_->getNodeMaxNumRowEntries ();
273 
274  // FIXME (mfh 23 Dec 2013) Use size_t or whatever
275  // getNodeNumElements() returns, instead of ptrdiff_t.
276  const int NumMyRows = OverlapGraph_->getRowMap ()->getNodeNumElements ();
277 
278 
279  using device_type = typename node_type::device_type;
280  using execution_space = typename device_type::execution_space;
281  Kokkos::DualView<size_t*, device_type> numEntPerRow("numEntPerRow", NumMyRows);
282  auto numEntPerRow_d = numEntPerRow.template view<device_type>();
283  auto localOverlapGraph = OverlapGraph_->getLocalGraph();
284 
285  const auto overalloc = Overalloc_;
286  const auto levelfill = LevelFill_;
287  numEntPerRow.sync_device();
288  numEntPerRow.modify_device();
289  Kokkos::parallel_for("CountOverlapGraphRowEntries",
290  Kokkos::RangePolicy<execution_space>(0, NumMyRows),
291  KOKKOS_LAMBDA(const int i)
292  {
293  // Heuristic to get the maximum number of entries per row.
294  int RowMaxNumIndices = localOverlapGraph.rowConst(i).length;
295  numEntPerRow_d(i) = (levelfill == 0) ? RowMaxNumIndices // No additional storage needed
296  : ceil(static_cast<double>(RowMaxNumIndices)
297  * pow(overalloc, levelfill));
298  });
299 
300  bool insertError; // No error found yet while inserting entries
301  do {
302  insertError = false;
303  L_Graph_ = rcp (new crs_graph_type (OverlapGraph_->getRowMap (),
304  OverlapGraph_->getRowMap (),
305  numEntPerRow));
306  U_Graph_ = rcp (new crs_graph_type (OverlapGraph_->getRowMap (),
307  OverlapGraph_->getRowMap (),
308  numEntPerRow));
309 
310  Array<local_ordinal_type> L (MaxNumIndices);
311  Array<local_ordinal_type> U (MaxNumIndices);
312 
313  // First we copy the user's graph into L and U, regardless of fill level
314 
315  NumMyDiagonals_ = 0;
316 
317  for (int i = 0; i< NumMyRows; ++i) {
318  ArrayView<const local_ordinal_type> my_indices;
319  OverlapGraph_->getLocalRowView (i, my_indices);
320 
321  // Split into L and U (we don't assume that indices are ordered).
322 
323  NumL = 0;
324  NumU = 0;
325  DiagFound = false;
326  NumIn = my_indices.size();
327 
328  for (size_t j = 0; j < NumIn; ++j) {
329  const local_ordinal_type k = my_indices[j];
330 
331  if (k<NumMyRows) { // Ignore column elements that are not in the square matrix
332 
333  if (k==i) {
334  DiagFound = true;
335  }
336  else if (k < i) {
337  L[NumL] = k;
338  NumL++;
339  }
340  else {
341  U[NumU] = k;
342  NumU++;
343  }
344  }
345  }
346 
347  // Check in things for this row of L and U
348 
349  if (DiagFound) {
350  ++NumMyDiagonals_;
351  }
352  if (NumL) {
353  ArrayView<const local_ordinal_type> L_view = L.view (0, NumL);
354  L_Graph_->insertLocalIndices (i, L_view);
355  }
356  if (NumU) {
357  ArrayView<const local_ordinal_type> U_view = U.view (0, NumU);
358  U_Graph_->insertLocalIndices (i, U_view);
359  }
360  }
361 
362  if (LevelFill_ > 0) {
363  // Complete Fill steps
364  RCP<const map_type> L_DomainMap = OverlapGraph_->getRowMap ();
365  RCP<const map_type> L_RangeMap = Graph_->getRangeMap ();
366  RCP<const map_type> U_DomainMap = Graph_->getDomainMap ();
367  RCP<const map_type> U_RangeMap = OverlapGraph_->getRowMap ();
368  RCP<Teuchos::ParameterList> params = Teuchos::parameterList ();
369  params->set ("Optimize Storage",false);
370  L_Graph_->fillComplete (L_DomainMap, L_RangeMap, params);
371  U_Graph_->fillComplete (U_DomainMap, U_RangeMap, params);
372  L_Graph_->resumeFill ();
373  U_Graph_->resumeFill ();
374 
375  // At this point L_Graph and U_Graph are filled with the pattern of input graph,
376  // sorted and have redundant indices (if any) removed. Indices are zero based.
377  // LevelFill is greater than zero, so continue...
378 
379  int MaxRC = NumMyRows;
380  std::vector<std::vector<int> > Levels(MaxRC);
381  std::vector<int> LinkList(MaxRC);
382  std::vector<int> CurrentLevel(MaxRC);
383  Array<local_ordinal_type> CurrentRow (MaxRC + 1);
384  std::vector<int> LevelsRowU(MaxRC);
385 
386  try {
387  for (int i = 0; i < NumMyRows; ++i) {
388  int First, Next;
389 
390  // copy column indices of row into workspace and sort them
391 
392  size_t LenL = L_Graph_->getNumEntriesInLocalRow(i);
393  size_t LenU = U_Graph_->getNumEntriesInLocalRow(i);
394  size_t Len = LenL + LenU + 1;
395 
396  CurrentRow.resize(Len);
397 
398  L_Graph_->getLocalRowCopy(i, CurrentRow(), LenL); // Get L Indices
399  CurrentRow[LenL] = i; // Put in Diagonal
400  if (LenU > 0) {
401  ArrayView<local_ordinal_type> URowView = CurrentRow.view (LenL+1,
402  LenU);
403  // Get U Indices
404  U_Graph_->getLocalRowCopy (i, URowView, LenU);
405  }
406 
407  // Construct linked list for current row
408 
409  for (size_t j=0; j<Len-1; j++) {
410  LinkList[CurrentRow[j]] = CurrentRow[j+1];
411  CurrentLevel[CurrentRow[j]] = 0;
412  }
413 
414  LinkList[CurrentRow[Len-1]] = NumMyRows;
415  CurrentLevel[CurrentRow[Len-1]] = 0;
416 
417  // Merge List with rows in U
418 
419  First = CurrentRow[0];
420  Next = First;
421  while (Next < i) {
422  int PrevInList = Next;
423  int NextInList = LinkList[Next];
424  int RowU = Next;
425  // Get Indices for this row of U
426  ArrayView<const local_ordinal_type> IndicesU;
427  U_Graph_->getLocalRowView (RowU, IndicesU);
428  // FIXME (mfh 23 Dec 2013) size() returns ptrdiff_t, not int.
429  int LengthRowU = IndicesU.size ();
430 
431  int ii;
432 
433  // Scan RowU
434 
435  for (ii = 0; ii < LengthRowU; /*nop*/) {
436  int CurInList = IndicesU[ii];
437  if (CurInList < NextInList) {
438  // new fill-in
439  int NewLevel = CurrentLevel[RowU] + Levels[RowU][ii+1] + 1;
440  if (NewLevel <= LevelFill_) {
441  LinkList[PrevInList] = CurInList;
442  LinkList[CurInList] = NextInList;
443  PrevInList = CurInList;
444  CurrentLevel[CurInList] = NewLevel;
445  }
446  ii++;
447  }
448  else if (CurInList == NextInList) {
449  PrevInList = NextInList;
450  NextInList = LinkList[PrevInList];
451  int NewLevel = CurrentLevel[RowU] + Levels[RowU][ii+1] + 1;
452  CurrentLevel[CurInList] = std::min (CurrentLevel[CurInList],
453  NewLevel);
454  ii++;
455  }
456  else { // (CurInList > NextInList)
457  PrevInList = NextInList;
458  NextInList = LinkList[PrevInList];
459  }
460  }
461  Next = LinkList[Next];
462  }
463 
464  // Put pattern into L and U
465 
466  CurrentRow.resize (0);
467 
468  Next = First;
469 
470  // Lower
471 
472  while (Next < i) {
473  CurrentRow.push_back (Next);
474  Next = LinkList[Next];
475  }
476 
477  // FIXME (mfh 23 Dec 2013) It's not clear to me that
478  // removeLocalIndices works like people expect it to work. In
479  // particular, it does not actually change the column Map.
480  L_Graph_->removeLocalIndices (i); // Delete current set of Indices
481  if (CurrentRow.size() > 0) {
482  L_Graph_->insertLocalIndices (i, CurrentRow ());
483  }
484 
485  // Diagonal
486 
488  Next != i, std::runtime_error,
489  "Ifpack2::IlukGraph::initialize: FATAL: U has zero diagonal")
490 
491  LevelsRowU[0] = CurrentLevel[Next];
492  Next = LinkList[Next];
493 
494  // Upper
495 
496  CurrentRow.resize (0);
497  LenU = 0;
498 
499  while (Next < NumMyRows) {
500  LevelsRowU[LenU+1] = CurrentLevel[Next];
501  CurrentRow.push_back (Next);
502  ++LenU;
503  Next = LinkList[Next];
504  }
505 
506  // FIXME (mfh 23 Dec 2013) It's not clear to me that
507  // removeLocalIndices works like people expect it to work. In
508  // particular, it does not actually change the column Map.
509 
510  U_Graph_->removeLocalIndices (i); // Delete current set of Indices
511  if (LenU > 0) {
512  U_Graph_->insertLocalIndices (i, CurrentRow ());
513  }
514 
515  // Allocate and fill Level info for this row
516  Levels[i] = std::vector<int> (LenU+1);
517  for (size_t jj=0; jj<LenU+1; jj++) {
518  Levels[i][jj] = LevelsRowU[jj];
519  }
520  }
521  }
522  catch (std::runtime_error &e) {
523  insertError = true;
524  numEntPerRow.sync_device();
525  numEntPerRow.modify_device();
526  Kokkos::parallel_for("CountOverlapGraphRowEntries",
527  Kokkos::RangePolicy<execution_space>(0, NumMyRows),
528  KOKKOS_LAMBDA(const int i)
529  {
530  const auto numRowEnt = numEntPerRow_d(i);
531  numEntPerRow_d(i) = ceil(static_cast<double>((numRowEnt != 0 ? numRowEnt : 1)) * overalloc);
532  });
533  }
534  const int localInsertError = insertError ? 1 : 0;
535  int globalInsertError = 0;
536  reduceAll (* (OverlapGraph_->getRowMap ()->getComm ()), REDUCE_SUM, 1,
537  &localInsertError, &globalInsertError);
538  insertError = globalInsertError > 0;
539  }
540  } while (insertError); // do until all insertions complete successfully
541 
542  // Complete Fill steps
543  RCP<const map_type> L_DomainMap = OverlapGraph_->getRowMap ();
544  RCP<const map_type> L_RangeMap = Graph_->getRangeMap ();
545  RCP<const map_type> U_DomainMap = Graph_->getDomainMap ();
546  RCP<const map_type> U_RangeMap = OverlapGraph_->getRowMap ();
547  L_Graph_->fillComplete (L_DomainMap, L_RangeMap);//DoOptimizeStorage is default here...
548  U_Graph_->fillComplete (U_DomainMap, U_RangeMap);//DoOptimizeStorage is default here...
549 
550  reduceAll<int, size_t> (* (L_DomainMap->getComm ()), REDUCE_SUM, 1,
551  &NumMyDiagonals_, &NumGlobalDiagonals_);
552 }
553 
554 } // namespace Ifpack2
555 
556 #endif /* IFPACK2_ILUK_GRAPH_HPP */
void initialize()
Set up the graph structure of the L and U factors.
Definition: Ifpack2_IlukGraph.hpp:257
void setParameters(const Teuchos::ParameterList &parameterlist)
Set parameters.
Definition: Ifpack2_IlukGraph.hpp:238
Tpetra::CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Tpetra::CrsGraph specialization used by this class.
Definition: Ifpack2_IlukGraph.hpp:110
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void getParameter(const Teuchos::ParameterList &params, const std::string &name, T &value)
Set a value from a ParameterList if a parameter with the specified name exists.
Definition: Ifpack2_Parameters.hpp:59
Tpetra::RowGraph< local_ordinal_type, global_ordinal_type, node_type > row_graph_type
Tpetra::RowGraph specialization used by this class.
Definition: Ifpack2_IlukGraph.hpp:106
virtual ~IlukGraph()
IlukGraph Destructor.
Definition: Ifpack2_IlukGraph.hpp:232
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< crs_graph_type > getL_Graph() const
Returns the graph of lower triangle of the ILU(k) graph as a Tpetra::CrsGraph.
Definition: Ifpack2_IlukGraph.hpp:158
int getLevelFill() const
The level of fill used to construct this graph.
Definition: Ifpack2_IlukGraph.hpp:152
int getLevelOverlap() const
The level of overlap used to construct this graph.
Definition: Ifpack2_IlukGraph.hpp:155
Construct a level filled graph for use in computing an ILU(k) incomplete factorization.
Definition: Ifpack2_IlukGraph.hpp:97
size_t getNumGlobalDiagonals() const
Returns the global number of diagonals in the ILU(k) graph.
Definition: Ifpack2_IlukGraph.hpp:173
Teuchos::RCP< const crs_graph_type > getOverlapGraph() const
Returns the the overlapped graph.
Definition: Ifpack2_IlukGraph.hpp:168
IlukGraph(const Teuchos::RCP< const GraphType > &G, const int levelFill, const int levelOverlap, const double overalloc=2.)
Constructor.
Definition: Ifpack2_IlukGraph.hpp:215
Teuchos::RCP< crs_graph_type > getU_Graph() const
Returns the graph of upper triangle of the ILU(k) graph as a Tpetra::CrsGraph.
Definition: Ifpack2_IlukGraph.hpp:163