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 // 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 
15 
16 #ifndef IFPACK2_ILUK_GRAPH_HPP
17 #define IFPACK2_ILUK_GRAPH_HPP
18 
19 #include <algorithm>
20 #include <vector>
21 
22 #include "KokkosSparse_spiluk.hpp"
23 
24 #include <Ifpack2_ConfigDefs.hpp>
26 #include <Teuchos_CommHelpers.hpp>
27 #include <Tpetra_CrsGraph.hpp>
28 #include <Tpetra_Details_WrappedDualView.hpp>
29 #include <Tpetra_Import.hpp>
30 #include <Ifpack2_CreateOverlapGraph.hpp>
31 #include <Ifpack2_Parameters.hpp>
32 
33 namespace Ifpack2 {
34 
66 template <class GraphType, class KKHandleType>
68  public:
69  typedef typename GraphType::local_ordinal_type local_ordinal_type;
70  typedef typename GraphType::global_ordinal_type global_ordinal_type;
71  typedef typename GraphType::node_type node_type;
72 
74  typedef Tpetra::RowGraph<local_ordinal_type,
75  global_ordinal_type,
76  node_type>
79  typedef Tpetra::CrsGraph<local_ordinal_type,
80  global_ordinal_type,
81  node_type>
83 
84  typedef typename crs_graph_type::nonconst_global_inds_host_view_type nonconst_global_inds_host_view_type;
85  typedef typename crs_graph_type::nonconst_local_inds_host_view_type nonconst_local_inds_host_view_type;
86  typedef typename crs_graph_type::global_inds_host_view_type global_inds_host_view_type;
87  typedef typename crs_graph_type::local_inds_host_view_type local_inds_host_view_type;
88 
101  const int levelFill,
102  const int levelOverlap,
103  const double overalloc = 2.);
104 
106  virtual ~IlukGraph();
107 
113  void setParameters(const Teuchos::ParameterList& parameterlist);
114 
126  void initialize();
127  void initialize(const Teuchos::RCP<KKHandleType>& KernelHandle);
128 
130  int getLevelFill() const { return LevelFill_; }
131 
133  int getLevelOverlap() const { return LevelOverlap_; }
134 
137  return Graph_;
138  }
139 
142  return L_Graph_;
143  }
144 
147  return U_Graph_;
148  }
149 
152  return OverlapGraph_;
153  }
154 
156  size_t getNumGlobalDiagonals() const { return NumGlobalDiagonals_; }
157 
158  private:
159  typedef typename GraphType::map_type map_type;
160 
170 
180 
182  void constructOverlapGraph();
183 
186  int LevelFill_;
187  int LevelOverlap_;
188  const double Overalloc_;
191  size_t NumMyDiagonals_;
192  size_t NumGlobalDiagonals_;
193 };
194 
195 template <class GraphType, class KKHandleType>
198  const int levelFill,
199  const int levelOverlap,
200  const double overalloc)
201  : Graph_(G)
202  , LevelFill_(levelFill)
203  , LevelOverlap_(levelOverlap)
204  , Overalloc_(overalloc)
205  , NumMyDiagonals_(0)
206  , NumGlobalDiagonals_(0) {
207  TEUCHOS_TEST_FOR_EXCEPTION(Overalloc_ <= 1., std::runtime_error,
208  "Ifpack2::IlukGraph: FATAL: overalloc must be greater than 1.")
209 }
210 
211 template <class GraphType, class KKHandleType>
213 
214 template <class GraphType, class KKHandleType>
216  setParameters(const Teuchos::ParameterList& parameterlist) {
217  getParameter(parameterlist, "iluk level-of-fill", LevelFill_);
218  getParameter(parameterlist, "iluk level-of-overlap", LevelOverlap_);
219 }
220 
221 template <class GraphType, class KKHandleType>
223  // FIXME (mfh 22 Dec 2013) This won't do if we want
224  // RILUK::initialize() to do the right thing (that is,
225  // unconditionally recompute the "symbolic factorization").
226  if (OverlapGraph_ == Teuchos::null) {
227  OverlapGraph_ = createOverlapGraph<GraphType>(Graph_, LevelOverlap_);
228  }
229 }
230 
231 template <class GraphType, class KKHandleType>
233  using Teuchos::Array;
234  using Teuchos::ArrayView;
235  using Teuchos::RCP;
236  using Teuchos::rcp;
237  using Teuchos::REDUCE_SUM;
238  using Teuchos::reduceAll;
239 
240  size_t NumIn, NumL, NumU;
241  bool DiagFound;
242 
243  constructOverlapGraph();
244 
245  // Get Maximum Row length
246  const int MaxNumIndices = OverlapGraph_->getLocalMaxNumRowEntries();
247 
248  // FIXME (mfh 23 Dec 2013) Use size_t or whatever
249  // getLocalNumElements() returns, instead of ptrdiff_t.
250  const int NumMyRows = OverlapGraph_->getRowMap()->getLocalNumElements();
251 
252  using device_type = typename node_type::device_type;
253  using execution_space = typename device_type::execution_space;
254  using dual_view_type = Kokkos::DualView<size_t*, device_type>;
255  dual_view_type numEntPerRow_dv("numEntPerRow", NumMyRows);
256  Tpetra::Details::WrappedDualView<dual_view_type> numEntPerRow(numEntPerRow_dv);
257 
258  const auto overalloc = Overalloc_;
259  const auto levelfill = LevelFill_;
260  {
261  // Scoping for the localOverlapGraph access
262  auto numEntPerRow_d = numEntPerRow.getDeviceView(Tpetra::Access::OverwriteAll);
263  auto localOverlapGraph = OverlapGraph_->getLocalGraphDevice();
264  Kokkos::parallel_for(
265  "CountOverlapGraphRowEntries",
266  Kokkos::RangePolicy<execution_space>(0, NumMyRows),
267  KOKKOS_LAMBDA(const int i) {
268  // Heuristic to get the maximum number of entries per row.
269  int RowMaxNumIndices = localOverlapGraph.rowConst(i).length;
270  numEntPerRow_d(i) = (levelfill == 0) ? RowMaxNumIndices // No additional storage needed
271  : Kokkos::ceil(static_cast<double>(RowMaxNumIndices) * Kokkos::pow(overalloc, levelfill));
272  });
273  };
274 
275  bool insertError; // No error found yet while inserting entries
276  do {
277  insertError = false;
278  Teuchos::ArrayView<const size_t> a_numEntPerRow(numEntPerRow.getHostView(Tpetra::Access::ReadOnly).data(), NumMyRows);
279  L_Graph_ = rcp(new crs_graph_type(OverlapGraph_->getRowMap(),
280  OverlapGraph_->getRowMap(),
281  a_numEntPerRow));
282  U_Graph_ = rcp(new crs_graph_type(OverlapGraph_->getRowMap(),
283  OverlapGraph_->getRowMap(),
284  a_numEntPerRow));
285 
286  Array<local_ordinal_type> L(MaxNumIndices);
287  Array<local_ordinal_type> U(MaxNumIndices);
288 
289  // First we copy the user's graph into L and U, regardless of fill level
290 
291  NumMyDiagonals_ = 0;
292 
293  for (int i = 0; i < NumMyRows; ++i) {
294  local_inds_host_view_type my_indices;
295  OverlapGraph_->getLocalRowView(i, my_indices);
296 
297  // Split into L and U (we don't assume that indices are ordered).
298 
299  NumL = 0;
300  NumU = 0;
301  DiagFound = false;
302  NumIn = my_indices.size();
303 
304  for (size_t j = 0; j < NumIn; ++j) {
305  const local_ordinal_type k = my_indices[j];
306 
307  if (k < NumMyRows) { // Ignore column elements that are not in the square matrix
308 
309  if (k == i) {
310  DiagFound = true;
311  } else if (k < i) {
312  L[NumL] = k;
313  NumL++;
314  } else {
315  U[NumU] = k;
316  NumU++;
317  }
318  }
319  }
320 
321  // Check in things for this row of L and U
322 
323  if (DiagFound) {
324  ++NumMyDiagonals_;
325  }
326  if (NumL) {
327  L_Graph_->insertLocalIndices(i, NumL, L.data());
328  }
329  if (NumU) {
330  U_Graph_->insertLocalIndices(i, NumU, U.data());
331  }
332  }
333 
334  if (LevelFill_ > 0) {
335  // Complete Fill steps
336  RCP<const map_type> L_DomainMap = OverlapGraph_->getRowMap();
337  RCP<const map_type> L_RangeMap = Graph_->getRangeMap();
338  RCP<const map_type> U_DomainMap = Graph_->getDomainMap();
339  RCP<const map_type> U_RangeMap = OverlapGraph_->getRowMap();
340  RCP<Teuchos::ParameterList> params = Teuchos::parameterList();
341  params->set("Optimize Storage", false);
342  L_Graph_->fillComplete(L_DomainMap, L_RangeMap, params);
343  U_Graph_->fillComplete(U_DomainMap, U_RangeMap, params);
344  L_Graph_->resumeFill();
345  U_Graph_->resumeFill();
346 
347  // At this point L_Graph and U_Graph are filled with the pattern of input graph,
348  // sorted and have redundant indices (if any) removed. Indices are zero based.
349  // LevelFill is greater than zero, so continue...
350 
351  int MaxRC = NumMyRows;
352  std::vector<std::vector<int> > Levels(MaxRC);
353  std::vector<int> LinkList(MaxRC);
354  std::vector<int> CurrentLevel(MaxRC);
355  Array<local_ordinal_type> CurrentRow(MaxRC + 1);
356  std::vector<int> LevelsRowU(MaxRC);
357 
358  try {
359  for (int i = 0; i < NumMyRows; ++i) {
360  int First, Next;
361 
362  // copy column indices of row into workspace and sort them
363 
364  size_t LenL = L_Graph_->getNumEntriesInLocalRow(i);
365  size_t LenU = U_Graph_->getNumEntriesInLocalRow(i);
366  size_t Len = LenL + LenU + 1;
367  CurrentRow.resize(Len);
368  nonconst_local_inds_host_view_type CurrentRow_view(CurrentRow.data(), CurrentRow.size());
369  L_Graph_->getLocalRowCopy(i, CurrentRow_view, LenL); // Get L Indices
370  CurrentRow[LenL] = i; // Put in Diagonal
371  if (LenU > 0) {
372  ArrayView<local_ordinal_type> URowView = CurrentRow.view(LenL + 1, LenU);
373  nonconst_local_inds_host_view_type URowView_v(URowView.data(), URowView.size());
374 
375  // Get U Indices
376  U_Graph_->getLocalRowCopy(i, URowView_v, LenU);
377  }
378 
379  // Construct linked list for current row
380 
381  for (size_t j = 0; j < Len - 1; j++) {
382  LinkList[CurrentRow[j]] = CurrentRow[j + 1];
383  CurrentLevel[CurrentRow[j]] = 0;
384  }
385 
386  LinkList[CurrentRow[Len - 1]] = NumMyRows;
387  CurrentLevel[CurrentRow[Len - 1]] = 0;
388 
389  // Merge List with rows in U
390 
391  First = CurrentRow[0];
392  Next = First;
393  while (Next < i) {
394  int PrevInList = Next;
395  int NextInList = LinkList[Next];
396  int RowU = Next;
397  // Get Indices for this row of U
398  local_inds_host_view_type IndicesU;
399  U_Graph_->getLocalRowView(RowU, IndicesU);
400  // FIXME (mfh 23 Dec 2013) size() returns ptrdiff_t, not int.
401  int LengthRowU = IndicesU.size();
402 
403  int ii;
404 
405  // Scan RowU
406 
407  for (ii = 0; ii < LengthRowU; /*nop*/) {
408  int CurInList = IndicesU[ii];
409  if (CurInList < NextInList) {
410  // new fill-in
411  int NewLevel = CurrentLevel[RowU] + Levels[RowU][ii + 1] + 1;
412  if (NewLevel <= LevelFill_) {
413  LinkList[PrevInList] = CurInList;
414  LinkList[CurInList] = NextInList;
415  PrevInList = CurInList;
416  CurrentLevel[CurInList] = NewLevel;
417  }
418  ii++;
419  } else if (CurInList == NextInList) {
420  PrevInList = NextInList;
421  NextInList = LinkList[PrevInList];
422  int NewLevel = CurrentLevel[RowU] + Levels[RowU][ii + 1] + 1;
423  CurrentLevel[CurInList] = std::min(CurrentLevel[CurInList],
424  NewLevel);
425  ii++;
426  } else { // (CurInList > NextInList)
427  PrevInList = NextInList;
428  NextInList = LinkList[PrevInList];
429  }
430  }
431  Next = LinkList[Next];
432  }
433 
434  // Put pattern into L and U
435  CurrentRow.resize(0);
436 
437  Next = First;
438 
439  // Lower
440  while (Next < i) {
441  CurrentRow.push_back(Next);
442  Next = LinkList[Next];
443  }
444 
445  // FIXME (mfh 23 Dec 2013) It's not clear to me that
446  // removeLocalIndices works like people expect it to work. In
447  // particular, it does not actually change the column Map.
448  L_Graph_->removeLocalIndices(i); // Delete current set of Indices
449  if (CurrentRow.size() > 0) {
450  L_Graph_->insertLocalIndices(i, CurrentRow.size(), CurrentRow.data());
451  }
452 
453  // Diagonal
454 
456  Next != i, std::runtime_error,
457  "Ifpack2::IlukGraph::initialize: FATAL: U has zero diagonal")
458 
459  LevelsRowU[0] = CurrentLevel[Next];
460  Next = LinkList[Next];
461 
462  // Upper
463  CurrentRow.resize(0);
464  LenU = 0;
465 
466  while (Next < NumMyRows) {
467  LevelsRowU[LenU + 1] = CurrentLevel[Next];
468  CurrentRow.push_back(Next);
469  ++LenU;
470  Next = LinkList[Next];
471  }
472 
473  // FIXME (mfh 23 Dec 2013) It's not clear to me that
474  // removeLocalIndices works like people expect it to work. In
475  // particular, it does not actually change the column Map.
476 
477  U_Graph_->removeLocalIndices(i); // Delete current set of Indices
478  if (LenU > 0) {
479  U_Graph_->insertLocalIndices(i, CurrentRow.size(), CurrentRow.data());
480  }
481 
482  // Allocate and fill Level info for this row
483  Levels[i] = std::vector<int>(LenU + 1);
484  for (size_t jj = 0; jj < LenU + 1; jj++) {
485  Levels[i][jj] = LevelsRowU[jj];
486  }
487  }
488  } catch (std::runtime_error& e) {
489  insertError = true;
490  auto numEntPerRow_d = numEntPerRow.getDeviceView(Tpetra::Access::OverwriteAll);
491  Kokkos::parallel_for(
492  "CountOverlapGraphRowEntries",
493  Kokkos::RangePolicy<execution_space>(0, NumMyRows),
494  KOKKOS_LAMBDA(const int i) {
495  const auto numRowEnt = numEntPerRow_d(i);
496  numEntPerRow_d(i) = ceil(static_cast<double>((numRowEnt != 0 ? numRowEnt : 1)) * overalloc);
497  });
498  }
499  const int localInsertError = insertError ? 1 : 0;
500  int globalInsertError = 0;
501  reduceAll(*(OverlapGraph_->getRowMap()->getComm()), REDUCE_SUM, 1,
502  &localInsertError, &globalInsertError);
503  insertError = globalInsertError > 0;
504  }
505  } while (insertError); // do until all insertions complete successfully
506 
507  // Complete Fill steps
508  RCP<const map_type> L_DomainMap = OverlapGraph_->getRowMap();
509  RCP<const map_type> L_RangeMap = Graph_->getRangeMap();
510  RCP<const map_type> U_DomainMap = Graph_->getDomainMap();
511  RCP<const map_type> U_RangeMap = OverlapGraph_->getRowMap();
512  L_Graph_->fillComplete(L_DomainMap, L_RangeMap); // DoOptimizeStorage is default here...
513  U_Graph_->fillComplete(U_DomainMap, U_RangeMap); // DoOptimizeStorage is default here...
514 
515  reduceAll<int, size_t>(*(L_DomainMap->getComm()), REDUCE_SUM, 1,
516  &NumMyDiagonals_, &NumGlobalDiagonals_);
517 }
518 
519 template <class GraphType, class KKHandleType>
521  using Teuchos::Array;
522  using Teuchos::ArrayView;
523  using Teuchos::RCP;
524  using Teuchos::rcp;
525  using Teuchos::REDUCE_SUM;
526  using Teuchos::reduceAll;
527 
528  typedef typename crs_graph_type::local_graph_device_type local_graph_device_type;
529  typedef typename local_graph_device_type::size_type size_type;
530  typedef typename local_graph_device_type::data_type data_type;
531  typedef typename local_graph_device_type::array_layout array_layout;
532  typedef typename local_graph_device_type::device_type device_type;
533 
534  typedef typename Kokkos::View<size_type*, array_layout, device_type> lno_row_view_t;
535  typedef typename Kokkos::View<data_type*, array_layout, device_type> lno_nonzero_view_t;
536 
537  constructOverlapGraph();
538 
539  // FIXME (mfh 23 Dec 2013) Use size_t or whatever
540  // getLocalNumElements() returns, instead of ptrdiff_t.
541  const int NumMyRows = OverlapGraph_->getRowMap()->getLocalNumElements();
542  auto localOverlapGraph = OverlapGraph_->getLocalGraphDevice();
543 
544  if (KernelHandle->get_spiluk_handle()->get_nrows() < static_cast<size_type>(NumMyRows)) {
545  KernelHandle->get_spiluk_handle()->reset_handle(NumMyRows,
546  KernelHandle->get_spiluk_handle()->get_nnzL(),
547  KernelHandle->get_spiluk_handle()->get_nnzU());
548  }
549 
550  lno_row_view_t L_row_map("L_row_map", NumMyRows + 1);
551  lno_nonzero_view_t L_entries("L_entries", KernelHandle->get_spiluk_handle()->get_nnzL());
552  lno_row_view_t U_row_map("U_row_map", NumMyRows + 1);
553  lno_nonzero_view_t U_entries("U_entries", KernelHandle->get_spiluk_handle()->get_nnzU());
554 
555  bool symbolicError;
556  do {
557  symbolicError = false;
558  try {
559  KokkosSparse::spiluk_symbolic(KernelHandle.getRawPtr(), LevelFill_,
560  localOverlapGraph.row_map, localOverlapGraph.entries,
561  L_row_map, L_entries, U_row_map, U_entries);
562  } catch (std::runtime_error& e) {
563  symbolicError = true;
564  data_type nnzL = static_cast<data_type>(Overalloc_) * L_entries.extent(0);
565  data_type nnzU = static_cast<data_type>(Overalloc_) * U_entries.extent(0);
566  KernelHandle->get_spiluk_handle()->reset_handle(NumMyRows, nnzL, nnzU);
567  Kokkos::resize(L_entries, KernelHandle->get_spiluk_handle()->get_nnzL());
568  Kokkos::resize(U_entries, KernelHandle->get_spiluk_handle()->get_nnzU());
569  }
570  const int localSymbolicError = symbolicError ? 1 : 0;
571  int globalSymbolicError = 0;
572  reduceAll(*(OverlapGraph_->getRowMap()->getComm()), REDUCE_SUM, 1,
573  &localSymbolicError, &globalSymbolicError);
574  symbolicError = globalSymbolicError > 0;
575  } while (symbolicError);
576 
577  Kokkos::resize(L_entries, KernelHandle->get_spiluk_handle()->get_nnzL());
578  Kokkos::resize(U_entries, KernelHandle->get_spiluk_handle()->get_nnzU());
579 
580  RCP<Teuchos::ParameterList> params = Teuchos::parameterList();
581  params->set("Optimize Storage", false);
582 
583  L_Graph_ = rcp(new crs_graph_type(OverlapGraph_->getRowMap(),
584  OverlapGraph_->getRowMap(),
585  L_row_map, L_entries));
586  U_Graph_ = rcp(new crs_graph_type(OverlapGraph_->getRowMap(),
587  OverlapGraph_->getRowMap(),
588  U_row_map, U_entries));
589 
590  RCP<const map_type> L_DomainMap = OverlapGraph_->getRowMap();
591  RCP<const map_type> L_RangeMap = Graph_->getRangeMap();
592  RCP<const map_type> U_DomainMap = Graph_->getDomainMap();
593  RCP<const map_type> U_RangeMap = OverlapGraph_->getRowMap();
594  L_Graph_->fillComplete(L_DomainMap, L_RangeMap, params);
595  U_Graph_->fillComplete(U_DomainMap, U_RangeMap, params);
596 }
597 
598 } // namespace Ifpack2
599 
600 #endif /* IFPACK2_ILUK_GRAPH_HPP */
IlukGraph(const Teuchos::RCP< const GraphType > &G, const int levelFill, const int levelOverlap, const double overalloc=2.)
Constructor.
Definition: Ifpack2_IlukGraph.hpp:197
Teuchos::RCP< const GraphType > getA_Graph() const
Returns the original graph given.
Definition: Ifpack2_IlukGraph.hpp:136
#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:26
size_t getNumGlobalDiagonals() const
Returns the global number of diagonals in the ILU(k) graph.
Definition: Ifpack2_IlukGraph.hpp:156
virtual ~IlukGraph()
IlukGraph Destructor.
Definition: Ifpack2_IlukGraph.hpp:212
Tpetra::CrsGraph< local_ordinal_type, global_ordinal_type, node_type > crs_graph_type
Tpetra::CrsGraph specialization used by this class.
Definition: Ifpack2_IlukGraph.hpp:82
T * getRawPtr() const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< const crs_graph_type > getOverlapGraph() const
Returns the the overlapped graph.
Definition: Ifpack2_IlukGraph.hpp:151
Construct a level filled graph for use in computing an ILU(k) incomplete factorization.
Definition: Ifpack2_IlukGraph.hpp:67
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:146
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:141
void initialize()
Set up the graph structure of the L and U factors.
Definition: Ifpack2_IlukGraph.hpp:232
int getLevelFill() const
The level of fill used to construct this graph.
Definition: Ifpack2_IlukGraph.hpp:130
ArrayView< T > view(size_type offset, size_type size) const
int getLevelOverlap() const
The level of overlap used to construct this graph.
Definition: Ifpack2_IlukGraph.hpp:133
Tpetra::RowGraph< local_ordinal_type, global_ordinal_type, node_type > row_graph_type
Tpetra::RowGraph specialization used by this class.
Definition: Ifpack2_IlukGraph.hpp:77
void setParameters(const Teuchos::ParameterList &parameterlist)
Set parameters.
Definition: Ifpack2_IlukGraph.hpp:216