44 #ifndef IFPACK2_POWERMETHOD_HPP
45 #define IFPACK2_POWERMETHOD_HPP
54 #include "Kokkos_ArithTraits.hpp"
55 #include "Teuchos_FancyOStream.hpp"
56 #include "Teuchos_oblackholestream.hpp"
57 #include "Tpetra_Details_residual.hpp"
62 namespace PowerMethod {
69 template<
class OneDViewType,
70 class LocalOrdinal =
typename OneDViewType::size_type>
71 class PositivizeVector {
72 static_assert (Kokkos::is_view<OneDViewType>::value,
73 "OneDViewType must be a 1-D Kokkos::View.");
74 static_assert (static_cast<int> (OneDViewType::rank) == 1,
75 "This functor only works with a 1-D View.");
76 static_assert (std::is_integral<LocalOrdinal>::value,
77 "The second template parameter, LocalOrdinal, "
78 "must be an integer type.");
80 PositivizeVector (
const OneDViewType& x) : x_ (x) {}
82 KOKKOS_INLINE_FUNCTION
void
83 operator () (
const LocalOrdinal& i)
const
85 typedef typename OneDViewType::non_const_value_type IST;
86 typedef Kokkos::ArithTraits<IST> STS;
87 typedef Kokkos::ArithTraits<typename STS::mag_type> STM;
89 if(STS::real (x_(i)) < STM::zero ()) {
121 template<
class OperatorType,
class V>
122 typename V::scalar_type
123 powerMethodWithInitGuess(
const OperatorType& A,
129 const int eigNormalizationFreq = 1,
131 const bool computeSpectralRadius =
true)
133 typedef typename V::scalar_type ST;
137 bool verbose = (out != Teuchos::null);
141 *out <<
" powerMethodWithInitGuess:" << endl;
144 const ST zero =
static_cast<ST
> (0.0);
145 const ST one =
static_cast<ST
> (1.0);
147 ST lambdaMaxOld = one;
152 (norm == zero, std::runtime_error,
153 "Ifpack2::PowerMethod::powerMethodWithInitGuess: The initial guess "
154 "has zero norm. This could be either because Tpetra::Vector::"
155 "randomize filled the vector with zeros (if that was used to "
156 "compute the initial guess), or because the norm2 method has a "
157 "bug. The first is not impossible, but unlikely.");
160 *out <<
" Original norm1(x): " << x->norm1()
161 <<
", norm2(x): " << norm << endl;
164 x->scale(one / norm);
167 *out <<
" norm1(x.scale(one/norm)): " << x->norm1() << endl;
180 if(computeSpectralRadius) {
184 *out <<
" PowerMethod using spectral radius route" << endl;
186 for(
int iter = 0; iter < numIters-1; ++iter) {
188 *out <<
" Iteration " << iter << endl;
191 x->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
193 if(((iter+1) % eigNormalizationFreq == 0) && (iter < numIters-2)) {
197 *out <<
" norm is zero; returning zero" << endl;
198 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
202 lambdaMaxOld = lambdaMax;
206 *out <<
" lambdaMax: " << lambdaMax << endl;
207 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
211 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
212 *out <<
" lambdaMax: " << lambdaMax << endl;
216 x->scale(one / norm);
220 *out <<
" lambdaMax: " << lambdaMax << endl;
226 *out <<
" norm is zero; returning zero" << endl;
227 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
231 x->scale(one / norm);
233 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
234 lambdaMax = y->norm2();
240 *out <<
" PowerMethod using largest eigenvalue route" << endl;
242 for (
int iter = 0; iter < numIters-1; ++iter) {
244 *out <<
" Iteration " << iter << endl;
247 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
249 if(((iter+1) % eigNormalizationFreq == 0) && (iter < numIters-2)) {
250 xDinvAx = x->dot(*y);
251 if(xDinvAx == zero) {
253 *out <<
" xDinvAx is zero; returning zero" << endl;
254 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
258 lambdaMaxOld = lambdaMax;
262 *out <<
" lambdaMax: " << lambdaMax << endl;
263 *out <<
" Power method terminated after "<< iter <<
" iterations." << endl;
267 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
268 *out <<
" lambdaMax: " << lambdaMax << endl;
274 x->scale(one / norm);
278 *out <<
" lambdaMax: " << lambdaMax << endl;
284 *out <<
" norm is zero; returning zero" << endl;
285 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
289 x->scale(one / norm);
291 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
292 lambdaMax = y->dot(*x);
296 *out <<
" lambdaMax: " << lambdaMax << endl;
297 *out <<
" Power method terminated after "<< numIters <<
" iterations." << endl;
317 computeInitialGuessForPowerMethod (V& x,
const bool nonnegativeRealParts)
319 typedef typename V::device_type::execution_space dev_execution_space;
320 typedef typename V::local_ordinal_type LO;
324 if(nonnegativeRealParts) {
325 auto x_lcl = x.getLocalViewDevice (Tpetra::Access::ReadWrite);
326 auto x_lcl_1d = Kokkos::subview (x_lcl, Kokkos::ALL (), 0);
328 const LO lclNumRows =
static_cast<LO
> (x.getLocalLength ());
329 Kokkos::RangePolicy<dev_execution_space, LO> range (0, lclNumRows);
330 PositivizeVector<decltype (x_lcl_1d), LO> functor (x_lcl_1d);
331 Kokkos::parallel_for (range, functor);
352 template<
class OperatorType,
class V>
353 typename V::scalar_type
354 powerMethod(
const OperatorType& A,
359 const int eigNormalizationFreq = 1,
361 const bool computeSpectralRadius =
true)
363 typedef typename V::scalar_type ST;
366 bool verbose = (out != Teuchos::null);
369 *out <<
"powerMethod:" << std::endl;
372 const ST zero =
static_cast<ST
> (0.0);
378 computeInitialGuessForPowerMethod (*x,
false);
380 ST lambdaMax = powerMethodWithInitGuess (A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
389 if(STS::real (lambdaMax) < STS::real (zero)) {
391 *out <<
"real(lambdaMax) = " << STS::real (lambdaMax) <<
" < 0; "
392 "try again with a different random initial guess" << std::endl;
401 computeInitialGuessForPowerMethod (*x,
true);
402 lambdaMax = powerMethodWithInitGuess (A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
410 #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)