Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
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>
25#include <Teuchos_ParameterList.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
33namespace Ifpack2 {
34
66template <class GraphType, class KKHandleType>
67class IlukGraph : public Teuchos::Describable {
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
100 IlukGraph(const Teuchos::RCP<const GraphType>& G,
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
136 Teuchos::RCP<const GraphType> getA_Graph() const {
137 return Graph_;
138 }
139
141 Teuchos::RCP<crs_graph_type> getL_Graph() const {
142 return L_Graph_;
143 }
144
146 Teuchos::RCP<crs_graph_type> getU_Graph() const {
147 return U_Graph_;
148 }
149
151 Teuchos::RCP<const crs_graph_type> getOverlapGraph() const {
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
184 Teuchos::RCP<const GraphType> Graph_;
185 Teuchos::RCP<const crs_graph_type> OverlapGraph_;
186 int LevelFill_;
187 int LevelOverlap_;
188 const double Overalloc_;
189 Teuchos::RCP<crs_graph_type> L_Graph_;
190 Teuchos::RCP<crs_graph_type> U_Graph_;
191 size_t NumMyDiagonals_;
192 size_t NumGlobalDiagonals_;
193};
194
195template <class GraphType, class KKHandleType>
197 IlukGraph(const Teuchos::RCP<const GraphType>& G,
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
211template <class GraphType, class KKHandleType>
213
214template <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
221template <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
231template <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
455 TEUCHOS_TEST_FOR_EXCEPTION(
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
519template <class GraphType, class KKHandleType>
520void IlukGraph<GraphType, KKHandleType>::initialize(const Teuchos::RCP<KKHandleType>& KernelHandle) {
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 */
Construct a level filled graph for use in computing an ILU(k) incomplete factorization.
Definition Ifpack2_IlukGraph.hpp:67
size_t getNumGlobalDiagonals() const
Returns the global number of diagonals in the ILU(k) graph.
Definition Ifpack2_IlukGraph.hpp:156
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
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
int getLevelFill() const
The level of fill used to construct this graph.
Definition Ifpack2_IlukGraph.hpp:130
int getLevelOverlap() const
The level of overlap used to construct this graph.
Definition Ifpack2_IlukGraph.hpp:133
Teuchos::RCP< const GraphType > getA_Graph() const
Returns the original graph given.
Definition Ifpack2_IlukGraph.hpp:136
void initialize()
Set up the graph structure of the L and U factors.
Definition Ifpack2_IlukGraph.hpp:232
Teuchos::RCP< const crs_graph_type > getOverlapGraph() const
Returns the the overlapped graph.
Definition Ifpack2_IlukGraph.hpp:151
void setParameters(const Teuchos::ParameterList &parameterlist)
Set parameters.
Definition Ifpack2_IlukGraph.hpp:216
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
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
IlukGraph(const Teuchos::RCP< const GraphType > &G, const int levelFill, const int levelOverlap, const double overalloc=2.)
Constructor.
Definition Ifpack2_IlukGraph.hpp:197
virtual ~IlukGraph()
IlukGraph Destructor.
Definition Ifpack2_IlukGraph.hpp:212
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40
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