Ifpack2 Templated Preconditioning Package  Version 1.0
Ifpack2_RILUK_def.hpp
1 /*@HEADER
2 // ***********************************************************************
3 //
4 // Ifpack2: Tempated 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_CRSRILUK_DEF_HPP
44 #define IFPACK2_CRSRILUK_DEF_HPP
45 
46 #include "Ifpack2_LocalFilter.hpp"
47 #include "Tpetra_CrsMatrix.hpp"
48 #include "Ifpack2_LocalSparseTriangularSolver.hpp"
49 
50 #ifdef IFPACK2_ILUK_EXPERIMENTAL
51 #include <shylubasker_def.hpp>
52 #include <Kokkos_CrsMatrix.hpp>
53 # ifdef IFPACK2_HTS_EXPERIMENTAL
54 # include <shylu_hts.hpp>
55 # endif
56 #endif
57 
58 namespace Ifpack2 {
59 
60 template<class MatrixType>
61 RILUK<MatrixType>::RILUK (const Teuchos::RCP<const row_matrix_type>& Matrix_in)
62  : A_ (Matrix_in),
63  LevelOfFill_ (0),
64  isAllocated_ (false),
65  isInitialized_ (false),
66  isComputed_ (false),
67  isExperimental_ (false),
68  numInitialize_ (0),
69  numCompute_ (0),
70  numApply_ (0),
71  initializeTime_ (0.0),
72  computeTime_ (0.0),
73  applyTime_ (0.0),
74  RelaxValue_ (Teuchos::ScalarTraits<magnitude_type>::zero ()),
75  Athresh_ (Teuchos::ScalarTraits<magnitude_type>::zero ()),
76  Rthresh_ (Teuchos::ScalarTraits<magnitude_type>::one ())
77 {
78  allocateSolvers();
79 }
80 
81 
82 template<class MatrixType>
83 RILUK<MatrixType>::RILUK (const Teuchos::RCP<const crs_matrix_type>& Matrix_in)
84  : A_ (Matrix_in),
85  LevelOfFill_ (0),
86  isAllocated_ (false),
87  isInitialized_ (false),
88  isComputed_ (false),
89  isExperimental_ (false),
90  numInitialize_ (0),
91  numCompute_ (0),
92  numApply_ (0),
93  initializeTime_ (0.0),
94  computeTime_ (0.0),
95  applyTime_ (0.0),
96  RelaxValue_ (Teuchos::ScalarTraits<magnitude_type>::zero ()),
97  Athresh_ (Teuchos::ScalarTraits<magnitude_type>::zero ()),
98  Rthresh_ (Teuchos::ScalarTraits<magnitude_type>::one ())
99 {
100  allocateSolvers();
101 }
102 
103 
104 template<class MatrixType>
106 
107 template<class MatrixType>
109 {
110  L_solver_ = Teuchos::rcp (new LocalSparseTriangularSolver<row_matrix_type> ());
111  U_solver_ = Teuchos::rcp (new LocalSparseTriangularSolver<row_matrix_type> ());
112 }
113 
114 template<class MatrixType>
115 void
116 RILUK<MatrixType>::setMatrix (const Teuchos::RCP<const row_matrix_type>& A)
117 {
118  // It's legal for A to be null; in that case, you may not call
119  // initialize() until calling setMatrix() with a nonnull input.
120  // Regardless, setting the matrix invalidates any previous
121  // factorization.
122  if (A.getRawPtr () != A_.getRawPtr ()) {
123  isAllocated_ = false;
124  isInitialized_ = false;
125  isComputed_ = false;
126  A_local_ = Teuchos::null;
127  Graph_ = Teuchos::null;
128 
129  // The sparse triangular solvers get a triangular factor as their
130  // input matrix. The triangular factors L_ and U_ are getting
131  // reset, so we reset the solvers' matrices to null. Do that
132  // before setting L_ and U_ to null, so that latter step actually
133  // frees the factors.
134  if (! L_solver_.is_null ()) {
135  L_solver_->setMatrix (Teuchos::null);
136  }
137  if (! U_solver_.is_null ()) {
138  U_solver_->setMatrix (Teuchos::null);
139  }
140 
141  L_ = Teuchos::null;
142  U_ = Teuchos::null;
143  D_ = Teuchos::null;
144  A_ = A;
145  }
146 }
147 
148 
149 
150 template<class MatrixType>
153 {
154  TEUCHOS_TEST_FOR_EXCEPTION(
155  L_.is_null (), std::runtime_error, "Ifpack2::RILUK::getL: The L factor "
156  "is null. Please call initialize() (and preferably also compute()) "
157  "before calling this method. If the input matrix has not yet been set, "
158  "you must first call setMatrix() with a nonnull input matrix before you "
159  "may call initialize() or compute().");
160  return *L_;
161 }
162 
163 
164 template<class MatrixType>
165 const Tpetra::Vector<typename RILUK<MatrixType>::scalar_type,
170 {
171  TEUCHOS_TEST_FOR_EXCEPTION(
172  D_.is_null (), std::runtime_error, "Ifpack2::RILUK::getD: The D factor "
173  "(of diagonal entries) is null. Please call initialize() (and "
174  "preferably also compute()) before calling this method. If the input "
175  "matrix has not yet been set, you must first call setMatrix() with a "
176  "nonnull input matrix before you may call initialize() or compute().");
177  return *D_;
178 }
179 
180 
181 template<class MatrixType>
184 {
185  TEUCHOS_TEST_FOR_EXCEPTION(
186  U_.is_null (), std::runtime_error, "Ifpack2::RILUK::getU: The U factor "
187  "is null. Please call initialize() (and preferably also compute()) "
188  "before calling this method. If the input matrix has not yet been set, "
189  "you must first call setMatrix() with a nonnull input matrix before you "
190  "may call initialize() or compute().");
191  return *U_;
192 }
193 
194 
195 template<class MatrixType>
196 Teuchos::RCP<const Tpetra::Map<typename RILUK<MatrixType>::local_ordinal_type,
197  typename RILUK<MatrixType>::global_ordinal_type,
198  typename RILUK<MatrixType>::node_type> >
200  TEUCHOS_TEST_FOR_EXCEPTION(
201  A_.is_null (), std::runtime_error, "Ifpack2::RILUK::getDomainMap: "
202  "The matrix is null. Please call setMatrix() with a nonnull input "
203  "before calling this method.");
204 
205  // FIXME (mfh 25 Jan 2014) Shouldn't this just come from A_?
206  TEUCHOS_TEST_FOR_EXCEPTION(
207  Graph_.is_null (), std::runtime_error, "Ifpack2::RILUK::getDomainMap: "
208  "The computed graph is null. Please call initialize() before calling "
209  "this method.");
210  return Graph_->getL_Graph ()->getDomainMap ();
211 }
212 
213 
214 template<class MatrixType>
215 Teuchos::RCP<const Tpetra::Map<typename RILUK<MatrixType>::local_ordinal_type,
216  typename RILUK<MatrixType>::global_ordinal_type,
217  typename RILUK<MatrixType>::node_type> >
219  TEUCHOS_TEST_FOR_EXCEPTION(
220  A_.is_null (), std::runtime_error, "Ifpack2::RILUK::getRangeMap: "
221  "The matrix is null. Please call setMatrix() with a nonnull input "
222  "before calling this method.");
223 
224  // FIXME (mfh 25 Jan 2014) Shouldn't this just come from A_?
225  TEUCHOS_TEST_FOR_EXCEPTION(
226  Graph_.is_null (), std::runtime_error, "Ifpack2::RILUK::getRangeMap: "
227  "The computed graph is null. Please call initialize() before calling "
228  "this method.");
229  return Graph_->getL_Graph ()->getRangeMap ();
230 }
231 
232 
233 template<class MatrixType>
235 {
236  using Teuchos::null;
237  using Teuchos::rcp;
238 
239  if (! isAllocated_) {
240  // Deallocate any existing storage. This avoids storing 2x
241  // memory, since RCP op= does not deallocate until after the
242  // assignment.
243  L_ = null;
244  U_ = null;
245  D_ = null;
246 
247  // Allocate Matrix using ILUK graphs
248  L_ = rcp (new crs_matrix_type (Graph_->getL_Graph ()));
249  U_ = rcp (new crs_matrix_type (Graph_->getU_Graph ()));
250  L_->setAllToScalar (STS::zero ()); // Zero out L and U matrices
251  U_->setAllToScalar (STS::zero ());
252 
253  // FIXME (mfh 24 Jan 2014) This assumes domain == range Map for L and U.
254  L_->fillComplete ();
255  U_->fillComplete ();
256  D_ = rcp (new vec_type (Graph_->getL_Graph ()->getRowMap ()));
257  }
258  isAllocated_ = true;
259 }
260 
261 
262 template<class MatrixType>
263 void
265 setParameters (const Teuchos::ParameterList& params)
266 {
267  using Teuchos::as;
268  using Teuchos::Exceptions::InvalidParameterName;
269  using Teuchos::Exceptions::InvalidParameterType;
270 
271  // Default values of the various parameters.
272  int fillLevel = 0;
273  magnitude_type absThresh = STM::zero ();
274  magnitude_type relThresh = STM::one ();
275  magnitude_type relaxValue = STM::zero ();
276 
277  //
278  // "fact: iluk level-of-fill" parsing is more complicated, because
279  // we want to allow as many types as make sense. int is the native
280  // type, but we also want to accept magnitude_type (for
281  // compatibility with ILUT) and double (for backwards compatibilty
282  // with ILUT).
283  //
284 
285  bool gotFillLevel = false;
286  try {
287  fillLevel = params.get<int> ("fact: iluk level-of-fill");
288  gotFillLevel = true;
289  }
290  catch (InvalidParameterType&) {
291  // Throwing again in the catch block would just unwind the stack.
292  // Instead, we do nothing here, and check the Boolean outside to
293  // see if we got the value.
294  }
295  catch (InvalidParameterName&) {
296  gotFillLevel = true; // Accept the default value.
297  }
298 
299  if (! gotFillLevel) {
300  try {
301  // Try global_ordinal_type. The cast to int must succeed.
302  fillLevel = as<int> (params.get<global_ordinal_type> ("fact: iluk level-of-fill"));
303  gotFillLevel = true;
304  }
305  catch (InvalidParameterType&) {
306  // Try the next type.
307  }
308  // Don't catch InvalidParameterName here; we've already done that above.
309  }
310 
311  if (! gotFillLevel) {
312  try {
313  // Try magnitude_type, for compatibility with ILUT.
314  // The cast from magnitude_type to int must succeed.
315  fillLevel = as<int> (params.get<magnitude_type> ("fact: iluk level-of-fill"));
316  gotFillLevel = true;
317  }
318  catch (InvalidParameterType&) {
319  // Try the next type.
320  }
321  // Don't catch InvalidParameterName here; we've already done that above.
322  }
323 
324  if (! gotFillLevel) {
325  try {
326  // Try double, for compatibility with ILUT.
327  // The cast from double to int must succeed.
328  fillLevel = as<int> (params.get<double> ("fact: iluk level-of-fill"));
329  gotFillLevel = true;
330  }
331  catch (InvalidParameterType& e) {
332  // We're out of options. The user gave us the parameter, but it
333  // doesn't have the right type. The best thing for us to do in
334  // that case is to throw, telling the user to use the right
335  // type.
336  throw e;
337  }
338  // Don't catch InvalidParameterName here; we've already done that above.
339  }
340 
341  TEUCHOS_TEST_FOR_EXCEPTION(
342  ! gotFillLevel,
343  std::logic_error,
344  "Ifpack2::RILUK::setParameters: We should never get here! "
345  "The method should either have read the \"fact: iluk level-of-fill\" "
346  "parameter by this point, or have thrown an exception. "
347  "Please let the Ifpack2 developers know about this bug.");
348 
349  //
350  // For the other parameters, we prefer magnitude_type, but allow
351  // double for backwards compatibility.
352  //
353 
354  try {
355  absThresh = params.get<magnitude_type> ("fact: absolute threshold");
356  }
357  catch (InvalidParameterType&) {
358  // Try double, for backwards compatibility.
359  // The cast from double to magnitude_type must succeed.
360  absThresh = as<magnitude_type> (params.get<double> ("fact: absolute threshold"));
361  }
362  catch (InvalidParameterName&) {
363  // Accept the default value.
364  }
365 
366  try {
367  relThresh = params.get<magnitude_type> ("fact: relative threshold");
368  }
369  catch (InvalidParameterType&) {
370  // Try double, for backwards compatibility.
371  // The cast from double to magnitude_type must succeed.
372  relThresh = as<magnitude_type> (params.get<double> ("fact: relative threshold"));
373  }
374  catch (InvalidParameterName&) {
375  // Accept the default value.
376  }
377 
378  try {
379  relaxValue = params.get<magnitude_type> ("fact: relax value");
380  }
381  catch (InvalidParameterType&) {
382  // Try double, for backwards compatibility.
383  // The cast from double to magnitude_type must succeed.
384  relaxValue = as<magnitude_type> (params.get<double> ("fact: relax value"));
385  }
386  catch (InvalidParameterName&) {
387  // Accept the default value.
388  }
389 
390  // Forward to trisolvers.
391  L_solver_->setParameters(params);
392  U_solver_->setParameters(params);
393 
394  //Experimental
395  //Note: just following RILUK original style.
396  //Do not think catch is the method for this. JDB
397 #ifdef IFPACK2_ILUK_EXPERIMENTAL
398  try {
399  isExperimental_ = params.get<bool> ("fact: iluk experimental basker");
400  }
401  catch (InvalidParameterType&) {
402  //Use default
403  }
404  catch (InvalidParameterName&) {
405  //Use default
406  }
407 
408  try {
409  basker_threads = params.get<int> ("fact: iluk experimental basker threads");
410  }
411  catch (InvalidParameterType&) {
412  basker_threads = 1;
413  }
414  catch (InvalidParameterName&) {
415  basker_threads = 1;
416  }
417 
418  try {
419  basker_user_fill = (scalar_type) params.get<double>("fact: iluk experimental basker user_fill");
420  }
421  catch (InvalidParameterType&) {
422  basker_user_fill = (scalar_type) 0;
423  }
424  catch (InvalidParameterName&) {
425  basker_user_fill = (scalar_type) 0;
426  }
427 
428 # ifdef IFPACK2_HTS_EXPERIMENTAL
429  use_hts_ = false;
430  hts_nthreads_ = basker_threads;
431  {
432  const std::string name("fact: iluk experimental HTS");
433  if (params.isType<bool> (name))
434  use_hts_ = params.get<bool> (name);
435  }
436  {
437  const std::string name("fact: iluk experimental HTS threads");
438  if (params.isType<int> (name))
439  hts_nthreads_ = params.get<int> (name);
440  }
441 # endif
442 #endif
443 
444  // "Commit" the values only after validating all of them. This
445  // ensures that there are no side effects if this routine throws an
446  // exception.
447 
448  LevelOfFill_ = fillLevel;
449 
450  // mfh 28 Nov 2012: The previous code would not assign Athresh_,
451  // Rthresh_, or RelaxValue_, if the read-in value was -1. I don't
452  // know if keeping this behavior is correct, but I'll keep it just
453  // so as not to change previous behavior.
454 
455  if (absThresh != -STM::one ()) {
456  Athresh_ = absThresh;
457  }
458  if (relThresh != -STM::one ()) {
459  Rthresh_ = relThresh;
460  }
461  if (relaxValue != -STM::one ()) {
462  RelaxValue_ = relaxValue;
463  }
464 }
465 
466 
467 template<class MatrixType>
468 Teuchos::RCP<const typename RILUK<MatrixType>::row_matrix_type>
470  return Teuchos::rcp_implicit_cast<const row_matrix_type> (A_);
471 }
472 
473 
474 template<class MatrixType>
475 Teuchos::RCP<const typename RILUK<MatrixType>::crs_matrix_type>
477  return Teuchos::rcp_dynamic_cast<const crs_matrix_type> (A_, true);
478 }
479 
480 
481 template<class MatrixType>
482 Teuchos::RCP<const typename RILUK<MatrixType>::row_matrix_type>
483 RILUK<MatrixType>::makeLocalFilter (const Teuchos::RCP<const row_matrix_type>& A)
484 {
485  using Teuchos::RCP;
486  using Teuchos::rcp;
487  using Teuchos::rcp_dynamic_cast;
488  using Teuchos::rcp_implicit_cast;
489 
490  // If A_'s communicator only has one process, or if its column and
491  // row Maps are the same, then it is already local, so use it
492  // directly.
493  if (A->getRowMap ()->getComm ()->getSize () == 1 ||
494  A->getRowMap ()->isSameAs (* (A->getColMap ()))) {
495  return A;
496  }
497 
498  // If A_ is already a LocalFilter, then use it directly. This
499  // should be the case if RILUK is being used through
500  // AdditiveSchwarz, for example.
501  RCP<const LocalFilter<row_matrix_type> > A_lf_r =
502  rcp_dynamic_cast<const LocalFilter<row_matrix_type> > (A);
503  if (! A_lf_r.is_null ()) {
504  return rcp_implicit_cast<const row_matrix_type> (A_lf_r);
505  }
506  else {
507  // A_'s communicator has more than one process, its row Map and
508  // its column Map differ, and A_ is not a LocalFilter. Thus, we
509  // have to wrap it in a LocalFilter.
510  return rcp (new LocalFilter<row_matrix_type> (A));
511  }
512 }
513 
514 
515 template<class MatrixType>
517 {
518  using Teuchos::RCP;
519  using Teuchos::rcp;
520  using Teuchos::rcp_const_cast;
521  using Teuchos::rcp_dynamic_cast;
522  using Teuchos::rcp_implicit_cast;
523  typedef Tpetra::CrsGraph<local_ordinal_type,
525  node_type> crs_graph_type;
526  const char prefix[] = "Ifpack2::RILUK::initialize: ";
527 
528  TEUCHOS_TEST_FOR_EXCEPTION
529  (A_.is_null (), std::runtime_error, prefix << "The matrix is null. Please "
530  "call setMatrix() with a nonnull input before calling this method.");
531  TEUCHOS_TEST_FOR_EXCEPTION
532  (! A_->isFillComplete (), std::runtime_error, prefix << "The matrix is not "
533  "fill complete. You may not invoke initialize() or compute() with this "
534  "matrix until the matrix is fill complete. If your matrix is a "
535  "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
536  "range Maps, if appropriate) before calling this method.");
537 
538  Teuchos::Time timer ("RILUK::initialize");
539  { // Start timing
540  Teuchos::TimeMonitor timeMon (timer);
541 
542  // Calling initialize() means that the user asserts that the graph
543  // of the sparse matrix may have changed. We must not just reuse
544  // the previous graph in that case.
545  //
546  // Regarding setting isAllocated_ to false: Eventually, we may want
547  // some kind of clever memory reuse strategy, but it's always
548  // correct just to blow everything away and start over.
549  isInitialized_ = false;
550  isAllocated_ = false;
551  isComputed_ = false;
552  Graph_ = Teuchos::null;
553 
554  A_local_ = makeLocalFilter (A_);
555  TEUCHOS_TEST_FOR_EXCEPTION(
556  A_local_.is_null (), std::logic_error, "Ifpack2::RILUK::initialize: "
557  "makeLocalFilter returned null; it failed to compute A_local. "
558  "Please report this bug to the Ifpack2 developers.");
559 
560  // FIXME (mfh 24 Jan 2014, 26 Mar 2014) It would be more efficient
561  // to rewrite RILUK so that it works with any RowMatrix input, not
562  // just CrsMatrix. (That would require rewriting IlukGraph to
563  // handle a Tpetra::RowGraph.) However, to make it work for now,
564  // we just copy the input matrix if it's not a CrsMatrix.
565  {
566  RCP<const crs_matrix_type> A_local_crs =
567  rcp_dynamic_cast<const crs_matrix_type> (A_local_);
568  if (A_local_crs.is_null ()) {
569  // FIXME (mfh 24 Jan 2014) It would be smarter to count up the
570  // number of elements in each row of A_local, so that we can
571  // create A_local_crs_nc using static profile. The code below is
572  // correct but potentially slow.
573  RCP<crs_matrix_type> A_local_crs_nc =
574  rcp (new crs_matrix_type (A_local_->getRowMap (),
575  A_local_->getColMap (), 0));
576  // FIXME (mfh 24 Jan 2014) This Import approach will only work
577  // if A_ has a one-to-one row Map. This is generally the case
578  // with matrices given to Ifpack2.
579  //
580  // Source and destination Maps are the same in this case.
581  // That way, the Import just implements a copy.
582  typedef Tpetra::Import<local_ordinal_type, global_ordinal_type,
583  node_type> import_type;
584  import_type import (A_local_->getRowMap (), A_local_->getRowMap ());
585  A_local_crs_nc->doImport (*A_local_, import, Tpetra::REPLACE);
586  A_local_crs_nc->fillComplete (A_local_->getDomainMap (), A_local_->getRangeMap ());
587  A_local_crs = rcp_const_cast<const crs_matrix_type> (A_local_crs_nc);
588  }
589  Graph_ = rcp (new Ifpack2::IlukGraph<crs_graph_type> (A_local_crs->getCrsGraph (),
590  LevelOfFill_, 0));
591 #ifdef IFPACK2_ILUK_EXPERIMENTAL
592  if (isExperimental_) A_local_crs_ = A_local_crs;
593 #endif
594  }
595 
596  if(!isExperimental_)
597  {
598  Graph_->initialize ();
599  allocate_L_and_U ();
600  checkOrderingConsistency (*A_local_);
601  L_solver_->setMatrix (L_);
602  L_solver_->initialize ();
603  U_solver_->setMatrix( U_);
604  U_solver_->initialize ();
605  // Do not call initAllValues. compute() always calls initAllValues to
606  // fill L and U with possibly new numbers. initialize() is concerned
607  // only with the nonzero pattern.
608  }
609  else
610  {
611 #ifdef IFPACK2_ILUK_EXPERIMENTAL
612  typedef typename node_type::device_type kokkos_device;
613  typedef typename kokkos_device::execution_space kokkos_exe;
614  typedef typename crs_matrix_type::local_matrix_type kokkos_csr_matrix;
615 
616  static_assert( std::is_same< kokkos_exe,
617  Kokkos::OpenMP>::value,
618  "Kokkos node type not supported by experimental thread basker RILUK");
619 
620 
621  myBasker = rcp( new BaskerNS::Basker<local_ordinal_type, scalar_type, Kokkos::OpenMP>);
622  myBasker->Options.no_pivot = true;
623  myBasker->Options.transpose = true; //CRS not CCS
624  myBasker->Options.symmetric = false;
625  myBasker->Options.realloc = true;
626  myBasker->Options.btf = false;
627  myBasker->Options.incomplete = true;
628  myBasker->Options.inc_lvl = LevelOfFill_;
629  myBasker->Options.user_fill = basker_user_fill;
630  myBasker->Options.same_pattern = false;
631  myBasker->SetThreads(basker_threads);
632  basker_reuse = false;
633 
634  kokkos_csr_matrix kcsr = A_local_crs_->getLocalMatrix();
635 
636  local_ordinal_type* r_ptr;
637  r_ptr = new local_ordinal_type[(local_ordinal_type)A_local_crs_->getNodeNumRows()+1];
638 
639  //Still need to convert
640  //Lost on why Trilinos uses such odd types for row_ptrs
641  for(local_ordinal_type bi = 0;
642  bi < A_local_crs_->getNodeNumRows()+1; bi++)
643  {
644  r_ptr[bi] = (local_ordinal_type)kcsr.graph.row_map(bi);
645  }
646 
647  int basker_error =
648  myBasker->Symbolic(
649  ((local_ordinal_type)A_local_crs_->getNodeNumRows()),
650  ((local_ordinal_type)A_local_crs_->getNodeNumCols()),
651  ((local_ordinal_type)A_local_crs_->getNodeNumEntries()),
652  r_ptr,
653  &(kcsr.graph.entries(0)),
654  &(kcsr.values(0)));
655 
656  TEUCHOS_TEST_FOR_EXCEPTION(
657  basker_error != 0, std::logic_error, "Ifpack2::RILUK::initialize:"
658  "Error in basker Symbolic");
659 
660 
661 #else
662  TEUCHOS_TEST_FOR_EXCEPTION(
663  0==0, std::logic_error, "Ifpack2::RILUK::initialize: "
664  "Using experimental ILUK without compiling experimental "
665  "Try again with -DIFPACK2_ILUK_EXPERIMENAL.");
666 #endif
667  }
668 
669  } // Stop timing
670 
671  isInitialized_ = true;
672  ++numInitialize_;
673  initializeTime_ += timer.totalElapsedTime ();
674 }
675 
676 #ifdef IFPACK2_ILUK_EXPERIMENTAL
677 // Basker needs to refresh numbers using A_local_crs_, not just A_local_.
678 template<class MatrixType>
679 void
681 initLocalCrs ()
682 {
683  using Teuchos::RCP;
684  using Teuchos::rcp;
685  using Teuchos::rcp_dynamic_cast;
686  using Teuchos::rcp_implicit_cast;
687  using Teuchos::rcp_const_cast;
688 
689  RCP<crs_matrix_type> A_local_crs_nc = rcp_const_cast<crs_matrix_type> (A_local_crs_);
690  A_local_crs_ = rcp_dynamic_cast<const crs_matrix_type> (A_local_);
691  if (A_local_crs_.is_null ()) {
692  Teuchos::Array<local_ordinal_type> lclColInds;
693  Teuchos::Array<scalar_type> vals;
694  A_local_crs_nc->resumeFill();
695  for (size_t i = 0; i < A_local_crs_nc->getNodeNumRows(); ++i) {
696  size_t numEnt;
697  const auto nc = A_local_->getNumEntriesInLocalRow(i);
698  if (static_cast<size_t>(lclColInds.size()) < nc) {
699  lclColInds.resize(nc);
700  vals.resize(nc);
701  }
702  A_local_->getLocalRowCopy(i, lclColInds(), vals(), numEnt);
703  A_local_crs_nc->replaceLocalValues(i, lclColInds.view(0, numEnt), vals.view(0, numEnt));
704  }
705  A_local_crs_nc->fillComplete();
706  }
707  A_local_crs_ = rcp_const_cast<const crs_matrix_type> (A_local_crs_nc);
708 }
709 #endif
710 
711 template<class MatrixType>
712 void
715 {
716  // First check that the local row map ordering is the same as the local portion of the column map.
717  // The extraction of the strictly lower/upper parts of A, as well as the factorization,
718  // implicitly assume that this is the case.
719  Teuchos::ArrayView<const global_ordinal_type> rowGIDs = A.getRowMap()->getNodeElementList();
720  Teuchos::ArrayView<const global_ordinal_type> colGIDs = A.getColMap()->getNodeElementList();
721  bool gidsAreConsistentlyOrdered=true;
722  global_ordinal_type indexOfInconsistentGID=0;
723  for (global_ordinal_type i=0; i<rowGIDs.size(); ++i) {
724  if (rowGIDs[i] != colGIDs[i]) {
725  gidsAreConsistentlyOrdered=false;
726  indexOfInconsistentGID=i;
727  break;
728  }
729  }
730  TEUCHOS_TEST_FOR_EXCEPTION(gidsAreConsistentlyOrdered==false, std::runtime_error,
731  "The ordering of the local GIDs in the row and column maps is not the same"
732  << std::endl << "at index " << indexOfInconsistentGID
733  << ". Consistency is required, as all calculations are done with"
734  << std::endl << "local indexing.");
735 }
736 
737 template<class MatrixType>
738 void
741 {
742  using Teuchos::ArrayRCP;
743  using Teuchos::Comm;
744  using Teuchos::ptr;
745  using Teuchos::RCP;
746  using Teuchos::REDUCE_SUM;
747  using Teuchos::reduceAll;
748  typedef Tpetra::Map<local_ordinal_type,global_ordinal_type,node_type> map_type;
749 
750  size_t NumIn = 0, NumL = 0, NumU = 0;
751  bool DiagFound = false;
752  size_t NumNonzeroDiags = 0;
753  size_t MaxNumEntries = A.getGlobalMaxNumRowEntries();
754 
755  // Allocate temporary space for extracting the strictly
756  // lower and upper parts of the matrix A.
757  Teuchos::Array<local_ordinal_type> InI(MaxNumEntries);
758  Teuchos::Array<local_ordinal_type> LI(MaxNumEntries);
759  Teuchos::Array<local_ordinal_type> UI(MaxNumEntries);
760  Teuchos::Array<scalar_type> InV(MaxNumEntries);
761  Teuchos::Array<scalar_type> LV(MaxNumEntries);
762  Teuchos::Array<scalar_type> UV(MaxNumEntries);
763 
764  // Check if values should be inserted or replaced
765  const bool ReplaceValues = L_->isStaticGraph () || L_->isLocallyIndexed ();
766 
767  L_->resumeFill ();
768  U_->resumeFill ();
769  if (ReplaceValues) {
770  L_->setAllToScalar (STS::zero ()); // Zero out L and U matrices
771  U_->setAllToScalar (STS::zero ());
772  }
773 
774  D_->putScalar (STS::zero ()); // Set diagonal values to zero
775  ArrayRCP<scalar_type> DV = D_->get1dViewNonConst (); // Get view of diagonal
776 
777  RCP<const map_type> rowMap = L_->getRowMap ();
778 
779  // First we copy the user's matrix into L and U, regardless of fill level.
780  // It is important to note that L and U are populated using local indices.
781  // This means that if the row map GIDs are not monotonically increasing
782  // (i.e., permuted or gappy), then the strictly lower (upper) part of the
783  // matrix is not the one that you would get if you based L (U) on GIDs.
784  // This is ok, as the *order* of the GIDs in the rowmap is a better
785  // expression of the user's intent than the GIDs themselves.
786 
787  Teuchos::ArrayView<const global_ordinal_type> nodeGIDs = rowMap->getNodeElementList();
788  for (size_t myRow=0; myRow<A.getNodeNumRows(); ++myRow) {
789  local_ordinal_type local_row = myRow;
790 
791  //TODO JJH 4April2014 An optimization is to use getLocalRowView. Not all matrices support this,
792  // we'd need to check via the Tpetra::RowMatrix method supportsRowViews().
793  A.getLocalRowCopy (local_row, InI(), InV(), NumIn); // Get Values and Indices
794 
795  // Split into L and U (we don't assume that indices are ordered).
796 
797  NumL = 0;
798  NumU = 0;
799  DiagFound = false;
800 
801  for (size_t j = 0; j < NumIn; ++j) {
802  const local_ordinal_type k = InI[j];
803 
804  if (k == local_row) {
805  DiagFound = true;
806  // Store perturbed diagonal in Tpetra::Vector D_
807  DV[local_row] += Rthresh_ * InV[j] + IFPACK2_SGN(InV[j]) * Athresh_;
808  }
809  else if (k < 0) { // Out of range
810  TEUCHOS_TEST_FOR_EXCEPTION(
811  true, std::runtime_error, "Ifpack2::RILUK::initAllValues: current "
812  "GID k = " << k << " < 0. I'm not sure why this is an error; it is "
813  "probably an artifact of the undocumented assumptions of the "
814  "original implementation (likely copied and pasted from Ifpack). "
815  "Nevertheless, the code I found here insisted on this being an error "
816  "state, so I will throw an exception here.");
817  }
818  else if (k < local_row) {
819  LI[NumL] = k;
820  LV[NumL] = InV[j];
821  NumL++;
822  }
823  else if (Teuchos::as<size_t>(k) <= rowMap->getNodeNumElements()) {
824  UI[NumU] = k;
825  UV[NumU] = InV[j];
826  NumU++;
827  }
828  }
829 
830  // Check in things for this row of L and U
831 
832  if (DiagFound) {
833  ++NumNonzeroDiags;
834  } else {
835  DV[local_row] = Athresh_;
836  }
837 
838  if (NumL) {
839  if (ReplaceValues) {
840  L_->replaceLocalValues(local_row, LI(0, NumL), LV(0,NumL));
841  } else {
842  //FIXME JJH 24April2014 Is this correct? I believe this case is when there aren't already values
843  //FIXME in this row in the column locations corresponding to UI.
844  L_->insertLocalValues(local_row, LI(0,NumL), LV(0,NumL));
845  }
846  }
847 
848  if (NumU) {
849  if (ReplaceValues) {
850  U_->replaceLocalValues(local_row, UI(0,NumU), UV(0,NumU));
851  } else {
852  //FIXME JJH 24April2014 Is this correct? I believe this case is when there aren't already values
853  //FIXME in this row in the column locations corresponding to UI.
854  U_->insertLocalValues(local_row, UI(0,NumU), UV(0,NumU));
855  }
856  }
857  }
858 
859  // At this point L and U have the values of A in the structure of L
860  // and U, and diagonal vector D
861 
862  isInitialized_ = true;
863 }
864 
865 
866 template<class MatrixType>
868 {
869  using Teuchos::rcp;
870  const char prefix[] = "Ifpack2::RILUK::compute: ";
871 
872  // initialize() checks this too, but it's easier for users if the
873  // error shows them the name of the method that they actually
874  // called, rather than the name of some internally called method.
875  TEUCHOS_TEST_FOR_EXCEPTION
876  (A_.is_null (), std::runtime_error, prefix << "The matrix is null. Please "
877  "call setMatrix() with a nonnull input before calling this method.");
878  TEUCHOS_TEST_FOR_EXCEPTION
879  (! A_->isFillComplete (), std::runtime_error, prefix << "The matrix is not "
880  "fill complete. You may not invoke initialize() or compute() with this "
881  "matrix until the matrix is fill complete. If your matrix is a "
882  "Tpetra::CrsMatrix, please call fillComplete on it (with the domain and "
883  "range Maps, if appropriate) before calling this method.");
884 
885  if (! isInitialized ()) {
886  initialize (); // Don't count this in the compute() time
887  }
888 
889  Teuchos::Time timer ("RILUK::compute");
890  if ( ! isExperimental_) {
891  // Start timing
892  Teuchos::TimeMonitor timeMon (timer);
893 
894  isComputed_ = false;
895 
896  // Fill L and U with numbers. This supports nonzero pattern reuse by calling
897  // initialize() once and then compute() multiple times.
898  initAllValues (*A_local_);
899 
900  // MinMachNum should be officially defined, for now pick something a little
901  // bigger than IEEE underflow value
902 
903  const scalar_type MinDiagonalValue = STS::rmin ();
904  const scalar_type MaxDiagonalValue = STS::one () / MinDiagonalValue;
905 
906  size_t NumIn, NumL, NumU;
907 
908  // Get Maximum Row length
909  const size_t MaxNumEntries =
910  L_->getNodeMaxNumRowEntries () + U_->getNodeMaxNumRowEntries () + 1;
911 
912  Teuchos::Array<local_ordinal_type> InI(MaxNumEntries); // Allocate temp space
913  Teuchos::Array<scalar_type> InV(MaxNumEntries);
914  size_t num_cols = U_->getColMap()->getNodeNumElements();
915  Teuchos::Array<int> colflag(num_cols);
916 
917  Teuchos::ArrayRCP<scalar_type> DV = D_->get1dViewNonConst(); // Get view of diagonal
918 
919  // Now start the factorization.
920 
921  // Need some integer workspace and pointers
922  size_t NumUU;
923  Teuchos::ArrayView<const local_ordinal_type> UUI;
924  Teuchos::ArrayView<const scalar_type> UUV;
925  for (size_t j = 0; j < num_cols; ++j) {
926  colflag[j] = -1;
927  }
928 
929  for (size_t i = 0; i < L_->getNodeNumRows (); ++i) {
930  local_ordinal_type local_row = i;
931 
932  // Fill InV, InI with current row of L, D and U combined
933 
934  NumIn = MaxNumEntries;
935  L_->getLocalRowCopy (local_row, InI (), InV (), NumL);
936 
937  InV[NumL] = DV[i]; // Put in diagonal
938  InI[NumL] = local_row;
939 
940  U_->getLocalRowCopy (local_row, InI (NumL+1, MaxNumEntries-NumL-1),
941  InV (NumL+1, MaxNumEntries-NumL-1), NumU);
942  NumIn = NumL+NumU+1;
943 
944  // Set column flags
945  for (size_t j = 0; j < NumIn; ++j) {
946  colflag[InI[j]] = j;
947  }
948 
949  scalar_type diagmod = STS::zero (); // Off-diagonal accumulator
950 
951  for (size_t jj = 0; jj < NumL; ++jj) {
952  local_ordinal_type j = InI[jj];
953  scalar_type multiplier = InV[jj]; // current_mults++;
954 
955  InV[jj] *= DV[j];
956 
957  U_->getLocalRowView(j, UUI, UUV); // View of row above
958  NumUU = UUI.size();
959 
960  if (RelaxValue_ == STM::zero ()) {
961  for (size_t k = 0; k < NumUU; ++k) {
962  const int kk = colflag[UUI[k]];
963  // FIXME (mfh 23 Dec 2013) Wait a second, we just set
964  // colflag above using size_t (which is generally unsigned),
965  // but now we're querying it using int (which is signed).
966  if (kk > -1) {
967  InV[kk] -= multiplier * UUV[k];
968  }
969  }
970  }
971  else {
972  for (size_t k = 0; k < NumUU; ++k) {
973  // FIXME (mfh 23 Dec 2013) Wait a second, we just set
974  // colflag above using size_t (which is generally unsigned),
975  // but now we're querying it using int (which is signed).
976  const int kk = colflag[UUI[k]];
977  if (kk > -1) {
978  InV[kk] -= multiplier*UUV[k];
979  }
980  else {
981  diagmod -= multiplier*UUV[k];
982  }
983  }
984  }
985  }
986  if (NumL) {
987  // Replace current row of L
988  L_->replaceLocalValues (local_row, InI (0, NumL), InV (0, NumL));
989  }
990 
991  DV[i] = InV[NumL]; // Extract Diagonal value
992 
993  if (RelaxValue_ != STM::zero ()) {
994  DV[i] += RelaxValue_*diagmod; // Add off diagonal modifications
995  }
996 
997  if (STS::magnitude (DV[i]) > STS::magnitude (MaxDiagonalValue)) {
998  if (STS::real (DV[i]) < STM::zero ()) {
999  DV[i] = -MinDiagonalValue;
1000  }
1001  else {
1002  DV[i] = MinDiagonalValue;
1003  }
1004  }
1005  else {
1006  DV[i] = STS::one () / DV[i]; // Invert diagonal value
1007  }
1008 
1009  for (size_t j = 0; j < NumU; ++j) {
1010  InV[NumL+1+j] *= DV[i]; // Scale U by inverse of diagonal
1011  }
1012 
1013  if (NumU) {
1014  // Replace current row of L and U
1015  U_->replaceLocalValues (local_row, InI (NumL+1, NumU), InV (NumL+1, NumU));
1016  }
1017 
1018  // Reset column flags
1019  for (size_t j = 0; j < NumIn; ++j) {
1020  colflag[InI[j]] = -1;
1021  }
1022  }
1023 
1024  // The domain of L and the range of U are exactly their own row maps
1025  // (there is no communication). The domain of U and the range of L
1026  // must be the same as those of the original matrix, However if the
1027  // original matrix is a VbrMatrix, these two latter maps are
1028  // translation from a block map to a point map.
1029  // FIXME (mfh 23 Dec 2013) Do we know that the column Map of L_ is
1030  // always one-to-one?
1031  L_->fillComplete (L_->getColMap (), A_local_->getRangeMap ());
1032  U_->fillComplete (A_local_->getDomainMap (), U_->getRowMap ());
1033 
1034  // Validate that the L and U factors are actually lower and upper triangular
1035 
1036  //18-Aug-2016 The following two Teuchos tests-for-exceptions were changed by Massimiliano Lupo Pasini
1037  TEUCHOS_TEST_FOR_EXCEPTION(
1038  0 < L_->getNodeNumRows() &&
1039  ! L_->isLowerTriangular (), std::runtime_error,
1040  "Ifpack2::RILUK::compute: L isn't lower triangular.");
1041  TEUCHOS_TEST_FOR_EXCEPTION(
1042  0 < U_->getNodeNumRows() &&
1043  ! U_->isUpperTriangular (), std::runtime_error,
1044  "Ifpack2::RILUK::compute: U isn't lower triangular.");
1045 
1046  L_solver_->compute ();
1047  U_solver_->compute ();
1048  }
1049  else {
1050 #ifdef IFPACK2_ILUK_EXPERIMENTAL
1051  Teuchos::Time timerbasker ("RILUK::basercompute");
1052  {
1053  // Start timing
1054  Teuchos::TimeMonitor timeMon (timer);
1055  //
1056  if(basker_reuse == false)
1057  {
1058  //We don't have to reimport Matrix because same
1059  {
1060  //Teuchos::TimeMonitor timeMon(timerbasker);
1061  myBasker->Factor_Inc(0);
1062  basker_reuse = true;
1063  }
1064  }
1065  else
1066  {
1067  //Do we need to import Matrix with file again?
1068  myBasker->Options.same_pattern = true;
1069 
1070  typedef typename crs_matrix_type::local_matrix_type kokkos_csr_matrix;
1071  kokkos_csr_matrix kcsr = A_local_crs_->getLocalMatrix();
1072 
1073 
1074  local_ordinal_type* r_ptr;
1075  r_ptr = new local_ordinal_type[(local_ordinal_type)A_local_crs_->getNodeNumRows()+1];
1076 
1077  //Still need to convert
1078  for(local_ordinal_type bi = 0; bi < A_local_crs_->getNodeNumRows()+1; bi++)
1079  {
1080  r_ptr[bi] = (local_ordinal_type)kcsr.graph.row_map(bi);
1081  }
1082 
1083  int basker_error =
1084  myBasker->Factor(
1085  ((local_ordinal_type)A_local_crs_->getNodeNumRows()),
1086  ((local_ordinal_type)A_local_crs_->getNodeNumCols()),
1087  ((local_ordinal_type)A_local_crs_->getNodeNumEntries()),
1088  r_ptr,
1089  &(kcsr.graph.entries(0)),
1090  &(kcsr.values(0)));
1091 
1092  //myBasker->DEBUG_PRINT();
1093 
1094  TEUCHOS_TEST_FOR_EXCEPTION(
1095  basker_error != 0, std::logic_error, "Ifpack2::RILUK::initialize:"
1096  "Error in basker compute");
1097 
1098 
1099  }
1100  }
1101 # ifdef IFPACK2_HTS_EXPERIMENTAL
1102  //TODO Reuse symbolic information.
1103  if (use_hts_) {
1104  Teuchos::Time basker_getL("basker_getL");
1105  Teuchos::Time hts_buildL ("hts_buildL");
1106  Teuchos::Time basker_getU("basker_getU");
1107  Teuchos::Time hts_buildU ("hts_buildU");
1108 
1109  hts_mgr_ = Teuchos::rcp(new HTSManager());
1110  local_ordinal_type* p, * q;
1111  local_ordinal_type nnz;
1112 
1113  myBasker->GetPerm(&p, &q);
1114  {
1115  HTSData d;
1116  myBasker->GetL(d.n, nnz, &d.ir, &d.jc, &d.v);
1117  d.sort();
1118  typename HTST::CrsMatrix* T = HTST::make_CrsMatrix(d.n, d.ir, d.jc, d.v, true);
1119  hts_mgr_->Limpl = HTST::preprocess(T, 1, hts_nthreads_, true, p, 0);
1120  HTST::delete_CrsMatrix(T);
1121  delete[] p;
1122  }
1123  {
1124  HTSData d;
1125  myBasker->GetU(d.n, nnz, &d.ir, &d.jc, &d.v);
1126  d.sort();
1127  typename HTST::CrsMatrix* T = HTST::make_CrsMatrix(d.n, d.ir, d.jc, d.v, true);
1128  hts_mgr_->Uimpl = HTST::preprocess(T, 1, hts_nthreads_, true, 0, q);
1129  HTST::delete_CrsMatrix(T);
1130  delete[] q;
1131  }
1132  }
1133 # endif
1134 
1135 #else
1136  TEUCHOS_TEST_FOR_EXCEPTION(
1137  false, std::runtime_error,
1138  "Ifpack2::RILUK::compute: experimental not enabled");
1139 #endif
1140  }//end -- if experimental
1141 
1142  isComputed_ = true;
1143  ++numCompute_;
1144  computeTime_ += timer.totalElapsedTime ();
1145 }
1146 
1147 
1148 template<class MatrixType>
1149 void
1151 apply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
1152  Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
1153  Teuchos::ETransp mode,
1154  scalar_type alpha,
1155  scalar_type beta) const
1156 {
1157  using Teuchos::RCP;
1158  using Teuchos::rcpFromRef;
1159 
1160  TEUCHOS_TEST_FOR_EXCEPTION(
1161  A_.is_null (), std::runtime_error, "Ifpack2::RILUK::apply: The matrix is "
1162  "null. Please call setMatrix() with a nonnull input, then initialize() "
1163  "and compute(), before calling this method.");
1164  TEUCHOS_TEST_FOR_EXCEPTION(
1165  ! isComputed (), std::runtime_error,
1166  "Ifpack2::RILUK::apply: If you have not yet called compute(), "
1167  "you must call compute() before calling this method.");
1168  TEUCHOS_TEST_FOR_EXCEPTION(
1169  X.getNumVectors () != Y.getNumVectors (), std::invalid_argument,
1170  "Ifpack2::RILUK::apply: X and Y do not have the same number of columns. "
1171  "X.getNumVectors() = " << X.getNumVectors ()
1172  << " != Y.getNumVectors() = " << Y.getNumVectors () << ".");
1173  TEUCHOS_TEST_FOR_EXCEPTION(
1174  STS::isComplex && mode == Teuchos::CONJ_TRANS, std::logic_error,
1175  "Ifpack2::RILUK::apply: mode = Teuchos::CONJ_TRANS is not implemented for "
1176  "complex Scalar type. Please talk to the Ifpack2 developers to get this "
1177  "fixed. There is a FIXME in this file about this very issue.");
1178 #ifdef HAVE_IFPACK2_DEBUG
1179  {
1180  const magnitude_type D_nrm1 = D_->norm1 ();
1181  TEUCHOS_TEST_FOR_EXCEPTION( STM::isnaninf (D_nrm1), std::runtime_error, "Ifpack2::RILUK::apply: The 1-norm of the stored diagonal is NaN or Inf.");
1182  Teuchos::Array<magnitude_type> norms (X.getNumVectors ());
1183  X.norm1 (norms ());
1184  bool good = true;
1185  for (size_t j = 0; j < X.getNumVectors (); ++j) {
1186  if (STM::isnaninf (norms[j])) {
1187  good = false;
1188  break;
1189  }
1190  }
1191  TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error, "Ifpack2::RILUK::apply: The 1-norm of the input X is NaN or Inf.");
1192  }
1193 #endif // HAVE_IFPACK2_DEBUG
1194 
1195  const scalar_type one = STS::one ();
1196  const scalar_type zero = STS::zero ();
1197 
1198  Teuchos::Time timer ("RILUK::apply");
1199  { // Start timing
1200  if(!isExperimental_){
1201  Teuchos::TimeMonitor timeMon (timer);
1202  if (alpha == one && beta == zero) {
1203  if (mode == Teuchos::NO_TRANS) { // Solve L (D (U Y)) = X for Y.
1204  // Start by solving L Y = X for Y.
1205  L_solver_->apply (X, Y, mode);
1206 
1207  // Solve D Y = Y. The operation lets us do this in place in Y, so we can
1208  // write "solve D Y = Y for Y."
1209  Y.elementWiseMultiply (one, *D_, Y, zero);
1210 
1211  U_solver_->apply (Y, Y, mode); // Solve U Y = Y.
1212  }
1213  else { // Solve U^P (D^P (U^P Y)) = X for Y (where P is * or T).
1214 
1215  // Start by solving U^P Y = X for Y.
1216  U_solver_->apply (X, Y, mode);
1217 
1218  // Solve D^P Y = Y.
1219  //
1220  // FIXME (mfh 24 Jan 2014) If mode = Teuchos::CONJ_TRANS, we
1221  // need to do an elementwise multiply with the conjugate of
1222  // D_, not just with D_ itself.
1223  Y.elementWiseMultiply (one, *D_, Y, zero);
1224 
1225  L_solver_->apply (Y, Y, mode); // Solve L^P Y = Y.
1226  }
1227  }
1228  else { // alpha != 1 or beta != 0
1229  if (alpha == zero) {
1230  if (beta == zero) {
1231  Y.putScalar (zero);
1232  } else {
1233  Y.scale (beta);
1234  }
1235  } else { // alpha != zero
1236  apply (X, Y, mode);
1237  Y.update (alpha, Y, beta);
1238  }
1239  }
1240  }
1241  else
1242  {
1243 #ifdef IFPACK2_ILUK_EXPERIMENTAL
1244  Teuchos::ArrayRCP<const scalar_type> XX;
1245  Teuchos::ArrayRCP<const scalar_type> YY;
1246  XX = X.get1dView();
1247  YY = Y.get1dView();
1248 
1249 # ifdef IFPACK2_HTS_EXPERIMENTAL
1250  if (use_hts_) {
1251  HTST::solve_omp(hts_mgr_->Limpl, const_cast<scalar_type*>(XX.getRawPtr()),
1252  X.getNumVectors(), const_cast<scalar_type*>(YY.getRawPtr()));
1253  HTST::solve_omp(hts_mgr_->Uimpl, const_cast<scalar_type*>(YY.getRawPtr()),
1254  X.getNumVectors());
1255  } else
1256 # endif
1257  {
1258  myBasker->Solve(((local_ordinal_type)X.getNumVectors()),
1259  (const_cast<scalar_type *>(XX.getRawPtr())),
1260  (const_cast<scalar_type *>(YY.getRawPtr())));
1261  }
1262 #else
1263  TEUCHOS_TEST_FOR_EXCEPTION(
1264  0==1, std::runtime_error,
1265  "Ifpack2::RILUK::apply: Experimental no enabled");
1266 #endif
1267  }//end isExperimental
1268  }//end timing
1269 
1270 #ifdef HAVE_IFPACK2_DEBUG
1271  {
1272  Teuchos::Array<magnitude_type> norms (Y.getNumVectors ());
1273  Y.norm1 (norms ());
1274  bool good = true;
1275  for (size_t j = 0; j < Y.getNumVectors (); ++j) {
1276  if (STM::isnaninf (norms[j])) {
1277  good = false;
1278  break;
1279  }
1280  }
1281  TEUCHOS_TEST_FOR_EXCEPTION( ! good, std::runtime_error, "Ifpack2::RILUK::apply: The 1-norm of the output Y is NaN or Inf.");
1282  }
1283 #endif // HAVE_IFPACK2_DEBUG
1284 
1285  ++numApply_;
1286  applyTime_ = timer.totalElapsedTime ();
1287 }
1288 
1289 
1290 template<class MatrixType>
1292 multiply (const Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& X,
1293  Tpetra::MultiVector<scalar_type,local_ordinal_type,global_ordinal_type,node_type>& Y,
1294  const Teuchos::ETransp mode) const
1295 {
1296  const scalar_type zero = STS::zero ();
1297  const scalar_type one = STS::one ();
1298 
1299  if (mode != Teuchos::NO_TRANS) {
1300  U_->apply (X, Y, mode); //
1301  Y.update (one, X, one); // Y = Y + X (account for implicit unit diagonal)
1302 
1303  // FIXME (mfh 24 Jan 2014) If mode = Teuchos::CONJ_TRANS, we need
1304  // to do an elementwise multiply with the conjugate of D_, not
1305  // just with D_ itself.
1306  Y.elementWiseMultiply (one, *D_, Y, zero); // y = D*y (D_ has inverse of diagonal)
1307 
1308  MV Y_tmp (Y, Teuchos::Copy); // Need a temp copy of Y
1309  L_->apply (Y_tmp, Y, mode);
1310  Y.update (one, Y_tmp, one); // (account for implicit unit diagonal)
1311  }
1312  else {
1313  L_->apply (X, Y, mode);
1314  Y.update (one, X, one); // Y = Y + X (account for implicit unit diagonal)
1315  Y.elementWiseMultiply (one, *D_, Y, zero); // y = D*y (D_ has inverse of diagonal)
1316  MV Y_tmp (Y, Teuchos::Copy); // Need a temp copy of Y1
1317  U_->apply (Y_tmp, Y, mode);
1318  Y.update (one, Y_tmp, one); // (account for implicit unit diagonal)
1319  }
1320 }
1321 
1322 
1323 template<class MatrixType>
1325 {
1326  std::ostringstream os;
1327 
1328  // Output is a valid YAML dictionary in flow style. If you don't
1329  // like everything on a single line, you should call describe()
1330  // instead.
1331  os << "\"Ifpack2::RILUK\": {";
1332  os << "Initialized: " << (isInitialized () ? "true" : "false") << ", "
1333  << "Computed: " << (isComputed () ? "true" : "false") << ", ";
1334 
1335  os << "Level-of-fill: " << getLevelOfFill() << ", ";
1336 
1337  if (A_.is_null ()) {
1338  os << "Matrix: null";
1339  }
1340  else {
1341  os << "Global matrix dimensions: ["
1342  << A_->getGlobalNumRows () << ", " << A_->getGlobalNumCols () << "]"
1343  << ", Global nnz: " << A_->getGlobalNumEntries();
1344  }
1345 
1346  if (! L_solver_.is_null ()) os << ", " << L_solver_->description ();
1347  if (! U_solver_.is_null ()) os << ", " << U_solver_->description ();
1348 
1349  os << "}";
1350  return os.str ();
1351 }
1352 
1353 #if defined IFPACK2_ILUK_EXPERIMENTAL && defined IFPACK2_HTS_EXPERIMENTAL
1354 template<class MatrixType>
1356  : Limpl(0), Uimpl(0)
1357 {}
1358 
1359 template<class MatrixType>
1361 {
1362  HTST::delete_Impl(Limpl);
1363  HTST::delete_Impl(Uimpl);
1364 }
1365 
1366 template<class MatrixType>
1368  : jc(0), ir(0), v(0)
1369 {}
1370 
1371 template<class MatrixType>
1373 {
1374  free_CrsMatrix_data();
1375 }
1376 
1377 template<class MatrixType>
1379 {
1380  if (jc) delete[] jc;
1381  if (ir) delete[] ir;
1382  if (v) delete[] v;
1383  jc = ir = 0;
1384  v = 0;
1385 }
1386 
1387 template<class MatrixType>
1389 {
1390  if ( ! ir || ! jc) return;
1391  std::vector<Entry> es;
1392  for (local_ordinal_type i = 0; i < n; ++i) {
1393  es.resize(ir[i+1] - ir[i]);
1394  const local_ordinal_type os = ir[i];
1395  for (local_ordinal_type j = 0; j < ir[i+1] - os; ++j) {
1396  es[j].j = jc[os+j];
1397  es[j].v = v[os+j];
1398  }
1399  std::sort(es.begin(), es.end());
1400  for (local_ordinal_type j = 0; j < ir[i+1] - os; ++j) {
1401  jc[os+j] = es[j].j;
1402  v[os+j] = es[j].v;
1403  }
1404  }
1405 }
1406 #endif
1407 
1408 } // namespace Ifpack2
1409 
1410 #define IFPACK2_RILUK_INSTANT(S,LO,GO,N) \
1411  template class Ifpack2::RILUK< Tpetra::RowMatrix<S, LO, GO, N> >;
1412 
1413 #endif
MatrixType::global_ordinal_type global_ordinal_type
The type of global indices in the input MatrixType.
Definition: Ifpack2_RILUK_decl.hpp:272
Tpetra::RowMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > row_matrix_type
Tpetra::RowMatrix specialization used by this class.
Definition: Ifpack2_RILUK_decl.hpp:284
virtual void setMatrix(const Teuchos::RCP< const row_matrix_type > &A)
Change the matrix to be preconditioned.
Definition: Ifpack2_RILUK_def.hpp:116
ILU(k) factorization of a given Tpetra::RowMatrix.
Definition: Ifpack2_RILUK_decl.hpp:254
Tpetra::CrsMatrix< scalar_type, local_ordinal_type, global_ordinal_type, node_type > crs_matrix_type
Tpetra::CrsMatrix specialization used by this class for representing L and U.
Definition: Ifpack2_RILUK_decl.hpp:287
MatrixType::node_type node_type
The Node type used by the input MatrixType.
Definition: Ifpack2_RILUK_decl.hpp:275
MatrixType::local_ordinal_type local_ordinal_type
The type of local indices in the input MatrixType.
Definition: Ifpack2_RILUK_decl.hpp:269
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
Definition: Ifpack2_RILUK_def.hpp:199
"Preconditioner" that solves local sparse triangular systems.
Definition: Ifpack2_LocalSparseTriangularSolver_decl.hpp:83
Construct a level filled graph for use in computing an ILU(k) incomplete factorization.
Definition: Ifpack2_IlukGraph.hpp:97
Tpetra::global_size_t getGlobalNumEntries() const
Returns the number of nonzero entries in the global graph.
Definition: Ifpack2_RILUK_decl.hpp:524
Definition: Ifpack2_Container.hpp:761
Access only local rows and columns of a sparse matrix.
Definition: Ifpack2_LocalFilter_decl.hpp:160
Preconditioners and smoothers for Tpetra sparse matrices.
Definition: Ifpack2_AdditiveSchwarz_decl.hpp:72
Teuchos::RCP< const Tpetra::Map< local_ordinal_type, global_ordinal_type, node_type > > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
Definition: Ifpack2_RILUK_def.hpp:218
Tpetra::RowMatrix< MatrixType::scalar_type, MatrixType::local_ordinal_type, MatrixType::global_ordinal_type, MatrixType::node_type > ::scalar_type scalar_type
The type of the entries of the input MatrixType.
Definition: Ifpack2_RILUK_decl.hpp:266