10 #ifndef IFPACK2_POWERMETHOD_HPP
11 #define IFPACK2_POWERMETHOD_HPP
20 #include "Kokkos_ArithTraits.hpp"
21 #include "Teuchos_FancyOStream.hpp"
22 #include "Teuchos_oblackholestream.hpp"
23 #include "Tpetra_Details_residual.hpp"
28 namespace PowerMethod {
35 template<
class OneDViewType,
36 class LocalOrdinal =
typename OneDViewType::size_type>
37 class PositivizeVector {
38 static_assert (Kokkos::is_view<OneDViewType>::value,
39 "OneDViewType must be a 1-D Kokkos::View.");
40 static_assert (static_cast<int> (OneDViewType::rank) == 1,
41 "This functor only works with a 1-D View.");
42 static_assert (std::is_integral<LocalOrdinal>::value,
43 "The second template parameter, LocalOrdinal, "
44 "must be an integer type.");
46 PositivizeVector (
const OneDViewType& x) : x_ (x) {}
48 KOKKOS_INLINE_FUNCTION
void
49 operator () (
const LocalOrdinal& i)
const
51 typedef typename OneDViewType::non_const_value_type IST;
52 typedef Kokkos::ArithTraits<IST> STS;
53 typedef Kokkos::ArithTraits<typename STS::mag_type> STM;
55 if(STS::real (x_(i)) < STM::zero ()) {
87 template<
class OperatorType,
class V>
88 typename V::scalar_type
89 powerMethodWithInitGuess(
const OperatorType& A,
95 const int eigNormalizationFreq = 1,
97 const bool computeSpectralRadius =
true)
99 typedef typename V::scalar_type ST;
103 bool verbose = (out != Teuchos::null);
107 *out <<
" powerMethodWithInitGuess:" << endl;
110 const ST zero =
static_cast<ST
> (0.0);
111 const ST one =
static_cast<ST
> (1.0);
113 ST lambdaMaxOld = one;
118 (norm == zero, std::runtime_error,
119 "Ifpack2::PowerMethod::powerMethodWithInitGuess: The initial guess "
120 "has zero norm. This could be either because Tpetra::Vector::"
121 "randomize filled the vector with zeros (if that was used to "
122 "compute the initial guess), or because the norm2 method has a "
123 "bug. The first is not impossible, but unlikely.");
126 *out <<
" Original norm1(x): " << x->norm1()
127 <<
", norm2(x): " << norm << endl;
130 x->scale(one / norm);
133 *out <<
" norm1(x.scale(one/norm)): " << x->norm1() << endl;
146 if(computeSpectralRadius) {
150 *out <<
" PowerMethod using spectral radius route" << endl;
152 for(
int iter = 0; iter < numIters-1; ++iter) {
154 *out <<
" Iteration " << iter << endl;
157 x->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
159 if(((iter+1) % eigNormalizationFreq == 0) && (iter < numIters-2)) {
163 *out <<
" norm is zero; returning zero" << endl;
164 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
168 lambdaMaxOld = lambdaMax;
172 *out <<
" lambdaMax: " << lambdaMax << endl;
173 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
177 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
178 *out <<
" lambdaMax: " << lambdaMax << endl;
182 x->scale(one / norm);
186 *out <<
" lambdaMax: " << lambdaMax << endl;
192 *out <<
" norm is zero; returning zero" << endl;
193 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
197 x->scale(one / norm);
199 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
200 lambdaMax = y->norm2();
206 *out <<
" PowerMethod using largest eigenvalue route" << endl;
208 for (
int iter = 0; iter < numIters-1; ++iter) {
210 *out <<
" Iteration " << iter << endl;
213 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
215 if(((iter+1) % eigNormalizationFreq == 0) && (iter < numIters-2)) {
216 xDinvAx = x->dot(*y);
217 if(xDinvAx == zero) {
219 *out <<
" xDinvAx is zero; returning zero" << endl;
220 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
224 lambdaMaxOld = lambdaMax;
228 *out <<
" lambdaMax: " << lambdaMax << endl;
229 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
233 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
234 *out <<
" lambdaMax: " << lambdaMax << endl;
240 x->scale(one / norm);
244 *out <<
" lambdaMax: " << lambdaMax << endl;
250 *out <<
" norm is zero; returning zero" << endl;
251 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
255 x->scale(one / norm);
257 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
258 lambdaMax = y->dot(*x);
262 *out <<
" lambdaMax: " << lambdaMax << endl;
263 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
283 computeInitialGuessForPowerMethod (V& x,
const bool nonnegativeRealParts)
285 typedef typename V::device_type::execution_space dev_execution_space;
286 typedef typename V::local_ordinal_type LO;
290 if(nonnegativeRealParts) {
291 auto x_lcl = x.getLocalViewDevice (Tpetra::Access::ReadWrite);
292 auto x_lcl_1d = Kokkos::subview (x_lcl, Kokkos::ALL (), 0);
294 const LO lclNumRows =
static_cast<LO
> (x.getLocalLength ());
295 Kokkos::RangePolicy<dev_execution_space, LO> range (0, lclNumRows);
296 PositivizeVector<decltype (x_lcl_1d), LO> functor (x_lcl_1d);
297 Kokkos::parallel_for (range, functor);
318 template<
class OperatorType,
class V>
319 typename V::scalar_type
320 powerMethod(
const OperatorType& A,
325 const int eigNormalizationFreq = 1,
327 const bool computeSpectralRadius =
true)
329 typedef typename V::scalar_type ST;
332 bool verbose = (out != Teuchos::null);
335 *out <<
"powerMethod:" << std::endl;
338 const ST zero =
static_cast<ST
> (0.0);
344 computeInitialGuessForPowerMethod (*x,
false);
346 ST lambdaMax = powerMethodWithInitGuess (A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
355 if(STS::real (lambdaMax) < STS::real (zero)) {
357 *out <<
"real(lambdaMax) = " << STS::real (lambdaMax) <<
" < 0; "
358 "try again with a different random initial guess" << std::endl;
367 computeInitialGuessForPowerMethod (*x,
true);
368 lambdaMax = powerMethodWithInitGuess (A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
376 #endif // IFPACK2_POWERMETHOD_HPP
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void swap(RCP< T > &r_ptr)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static magnitudeType magnitude(T a)