13#ifndef dealii_solver_gmres_h
14#define dealii_solver_gmres_h
32#include <boost/signals2/signal.hpp>
50 template <
typename,
typename>
66 namespace SolverGMRESImplementation
75 template <
typename VectorType>
123 std::vector<typename VectorMemory<VectorType>::Pointer>
data;
137 template <
typename Number>
148 const unsigned int max_basis_size,
149 const bool force_reorthogonalization);
173 template <
typename VectorType>
176 const unsigned int n,
178 const unsigned int accumulated_iterations = 0,
179 const boost::signals2::signal<
void(
int)> &reorthogonalize_signal =
180 boost::signals2::signal<
void(
int)>());
285 std::vector<std::pair<double, double>> &rotations,
412template <
typename VectorType = Vector<
double>>
433 const bool right_preconditioning =
false,
434 const bool use_default_residual =
true,
435 const bool force_re_orthogonalization =
false,
436 const bool batched_mode =
false,
438 orthogonalization_strategy =
440 delayed_classical_gram_schmidt);
526 template <
typename MatrixType,
typename PreconditionerType>
530 void solve(const MatrixType &A,
533 const PreconditionerType &preconditioner);
541 boost::signals2::connection
542 connect_condition_number_slot(const
std::function<
void(
double)> &slot,
543 const
bool every_iteration = false);
551 boost::signals2::connection
552 connect_eigenvalues_slot(
553 const
std::function<
void(const
std::vector<
std::complex<
double>> &)> &slot,
554 const
bool every_iteration = false);
563 boost::signals2::connection
564 connect_hessenberg_slot(
566 const
bool every_iteration = true);
574 boost::signals2::connection
575 connect_krylov_space_slot(
577 void(const
internal::SolverGMRESImplementation::TmpVectors<VectorType> &)>
585 boost::signals2::connection
586 connect_re_orthogonalization_slot(const
std::function<
void(
int)> &slot);
591 << "The number of temporary vectors you gave (" << arg1
592 << ") is too small. It should be at least 10
for "
593 << "any results, and much more
for reasonable ones.");
605 boost::signals2::signal<
void(
double)> condition_number_signal;
611 boost::signals2::signal<
void(
double)> all_condition_numbers_signal;
617 boost::signals2::signal<
void(const
std::vector<
std::complex<
double>> &)>
624 boost::signals2::signal<
void(const
std::vector<
std::complex<
double>> &)>
625 all_eigenvalues_signal;
638 all_hessenberg_signal;
644 boost::signals2::signal<
void(
645 const
internal::SolverGMRESImplementation::TmpVectors<VectorType> &)>
652 boost::signals2::signal<
void(
int)> re_orthogonalize_signal;
674 compute_eigs_and_cond(
676 const
unsigned int n,
677 const
boost::signals2::signal<
678 void(const
std::vector<
std::complex<
double>> &)> &eigenvalues_signal,
681 const
boost::signals2::signal<
void(
double)> &cond_signal);
687 internal::SolverGMRESImplementation::ArnoldiProcess<
688 typename VectorType::value_type>
756template <typename VectorType =
Vector<
double>>
771 orthogonalization_strategy =
773 delayed_classical_gram_schmidt,
774 const
bool use_truncated_mpgmres_strategy = true)
775 : max_basis_size(max_basis_size)
776 , orthogonalization_strategy(orthogonalization_strategy)
777 , use_truncated_mpgmres_strategy(use_truncated_mpgmres_strategy)
819 template <
typename MatrixType,
typename... PreconditionerTypes>
823 void solve(const MatrixType &A,
826 const PreconditionerTypes &...preconditioners);
845 template <
typename MatrixType,
typename... PreconditionerTypes>
851 const PreconditionerTypes &...preconditioners);
864 typename VectorType::value_type>
895template <
typename VectorType = Vector<
double>>
909 const unsigned int max_basis_size = 30,
912 delayed_classical_gram_schmidt)
913 : max_basis_size(max_basis_size)
914 , orthogonalization_strategy(orthogonalization_strategy)
946 template <
typename MatrixType,
typename... PreconditionerTypes>
950 void solve(const MatrixType &A,
953 const PreconditionerTypes &...preconditioners);
963template <
typename VectorType>
966 const unsigned int max_basis_size,
967 const bool right_preconditioning,
968 const bool use_default_residual,
969 const bool force_re_orthogonalization,
970 const bool batched_mode,
972 : max_n_tmp_vectors(0)
973 , max_basis_size(max_basis_size)
974 , right_preconditioning(right_preconditioning)
975 , use_default_residual(use_default_residual)
976 , force_re_orthogonalization(force_re_orthogonalization)
977 , batched_mode(batched_mode)
978 , orthogonalization_strategy(orthogonalization_strategy)
980 Assert(max_basis_size >= 1,
981 ExcMessage(
"SolverGMRES needs at least one vector in the "
987template <
typename VectorType>
991 const AdditionalData &
data)
993 , additional_data(
data)
999template <
typename VectorType>
1002 const AdditionalData &
data)
1004 , additional_data(
data)
1005 , solver_control(cn)
1012 namespace SolverGMRESImplementation
1014 template <
typename VectorType>
1023 template <
typename VectorType>
1025 TmpVectors<VectorType>::operator[](
const unsigned int i)
const
1035 template <
typename VectorType>
1037 TmpVectors<VectorType>::operator()(
const unsigned int i,
1038 const VectorType &temp)
1041 if (
data[i] ==
nullptr)
1044 data[i]->reinit(temp,
true);
1051 template <
typename VectorType>
1053 TmpVectors<VectorType>::size()
const
1055 return (
data.size() > 0 ?
data.size() - 1 : 0);
1060 template <
typename VectorType,
typename Enable =
void>
1061 struct is_dealii_compatible_vector;
1063 template <
typename VectorType>
1064 struct is_dealii_compatible_vector<
1066 std::enable_if_t<!internal::is_block_vector<VectorType>>>
1068 static constexpr bool value =
1073 std::is_same_v<VectorType, Vector<typename VectorType::value_type>>;
1078 template <
typename VectorType>
1079 struct is_dealii_compatible_vector<
1081 std::enable_if_t<internal::is_block_vector<VectorType>>>
1083 static constexpr bool value =
1085 typename VectorType::BlockType,
1088 std::is_same_v<VectorType, Vector<typename VectorType::value_type>>;
1094 std::enable_if_t<!IsBlockVector<VectorType>::value,
VectorType>
1105 std::enable_if_t<IsBlockVector<VectorType>::value,
VectorType> * =
1110 return vector.n_blocks();
1116 std::enable_if_t<!IsBlockVector<VectorType>::value,
VectorType>
1119 block(VectorType &vector,
const unsigned int b)
1128 std::enable_if_t<!IsBlockVector<VectorType>::value,
VectorType>
1131 block(
const VectorType &vector,
const unsigned int b)
1140 std::enable_if_t<IsBlockVector<VectorType>::value,
VectorType> * =
1142 typename VectorType::BlockType &
1143 block(VectorType &vector,
const unsigned int b)
1145 return vector.block(b);
1151 std::enable_if_t<IsBlockVector<VectorType>::value,
VectorType> * =
1153 const typename VectorType::BlockType &
1154 block(
const VectorType &vector,
const unsigned int b)
1156 return vector.block(b);
1161 template <
bool delayed_reorthogonalization,
1163 std::enable_if_t<!is_dealii_compatible_vector<VectorType>::value,
1166 Tvmult_add(
const unsigned int n,
1167 const VectorType &vv,
1168 const TmpVectors<VectorType> &orthogonal_vectors,
1170 std::vector<const typename VectorType::value_type *> &)
1172 for (
unsigned int i = 0; i < n; ++i)
1174 h(i) += vv * orthogonal_vectors[i];
1175 if (delayed_reorthogonalization)
1176 h(n + i) += orthogonal_vectors[i] * orthogonal_vectors[n - 1];
1178 if (delayed_reorthogonalization)
1179 h(n + n) += vv * vv;
1185 template <
bool delayed_reorthogonalization,
typename Number>
1189 const Number *current_vector,
1190 const std::vector<const Number *> &orthogonal_vectors,
1195 template <
bool delayed_reorthogonalization,
1197 std::enable_if_t<is_dealii_compatible_vector<VectorType>::value,
1201 const unsigned int n,
1202 const VectorType &vv,
1203 const TmpVectors<VectorType> &orthogonal_vectors,
1205 std::vector<const typename VectorType::value_type *> &vector_ptrs)
1207 for (
unsigned int b = 0;
b <
n_blocks(vv); ++
b)
1209 vector_ptrs.resize(n);
1210 for (
unsigned int i = 0; i < n; ++i)
1211 vector_ptrs[i] = block(orthogonal_vectors[i], b).begin();
1213 do_Tvmult_add<delayed_reorthogonalization>(n,
1214 block(vv, b).
end() -
1215 block(vv, b).
begin(),
1216 block(vv, b).
begin(),
1226 template <
bool delayed_reorthogonalization,
1228 std::enable_if_t<!is_dealii_compatible_vector<VectorType>::value,
1231 subtract_and_norm(
const unsigned int n,
1232 const TmpVectors<VectorType> &orthogonal_vectors,
1235 std::vector<const typename VectorType::value_type *> &)
1240 const_cast<VectorType &
>(orthogonal_vectors[n - 1]);
1241 for (
unsigned int i = 0; i < n - 1; ++i)
1243 if (delayed_reorthogonalization && i + 2 < n)
1244 last_vector.add(-h(n + i), orthogonal_vectors[i]);
1245 vv.add(-h(i), orthogonal_vectors[i]);
1248 if (delayed_reorthogonalization)
1251 last_vector.sadd(1. / h(n + n - 1),
1252 -h(n + n - 2) / h(n + n - 1),
1253 orthogonal_vectors[n - 2]);
1256 const double scaling_factor_vv = h(n + n) > 0.0 ?
1257 1. / (h(n + n - 1) * h(n + n)) :
1258 1. / (h(n + n - 1) * h(n + n - 1));
1259 vv.sadd(scaling_factor_vv,
1260 -h(n - 1) * scaling_factor_vv,
1265 return std::numeric_limits<double>::signaling_NaN();
1269 vv.add_and_dot(-h(n - 1), orthogonal_vectors[n - 1], vv));
1275 template <
bool delayed_reorthogonalization,
typename Number>
1279 const std::vector<const Number *> &orthogonal_vectors,
1281 Number *current_vector);
1285 template <
bool delayed_reorthogonalization,
1287 std::enable_if_t<is_dealii_compatible_vector<VectorType>::value,
1291 const unsigned int n,
1292 const TmpVectors<VectorType> &orthogonal_vectors,
1295 std::vector<const typename VectorType::value_type *> &vector_ptrs)
1297 double norm_vv_temp = 0.0;
1299 for (
unsigned int b = 0;
b <
n_blocks(vv); ++
b)
1301 vector_ptrs.resize(n);
1302 for (
unsigned int i = 0; i < n; ++i)
1303 vector_ptrs[i] = block(orthogonal_vectors[i], b).begin();
1305 norm_vv_temp += do_subtract_and_norm<delayed_reorthogonalization>(
1307 block(vv, b).
end() - block(vv, b).
begin(),
1310 block(vv, b).
begin());
1320 std::enable_if_t<!is_dealii_compatible_vector<VectorType>::value,
1324 const unsigned int n,
1326 const TmpVectors<VectorType> &tmp_vectors,
1327 const bool zero_out,
1328 std::vector<const typename VectorType::value_type *> &)
1331 p.equ(h(0), tmp_vectors[0]);
1333 p.add(h(0), tmp_vectors[0]);
1335 for (
unsigned int i = 1; i < n; ++i)
1336 p.add(h(i), tmp_vectors[i]);
1342 template <
typename Number>
1344 do_add(
const unsigned int n_vectors,
1346 const std::vector<const Number *> &tmp_vectors,
1348 const bool zero_out,
1354 std::enable_if_t<is_dealii_compatible_vector<VectorType>::value,
1358 const unsigned int n,
1360 const TmpVectors<VectorType> &tmp_vectors,
1361 const bool zero_out,
1362 std::vector<const typename VectorType::value_type *> &vector_ptrs)
1364 for (
unsigned int b = 0;
b <
n_blocks(p); ++
b)
1366 vector_ptrs.resize(n);
1367 for (
unsigned int i = 0; i < n; ++i)
1368 vector_ptrs[i] = block(tmp_vectors[i], b).begin();
1370 block(p, b).
end() - block(p, b).
begin(),
1374 block(p, b).
begin());
1380 template <
typename Number>
1382 ArnoldiProcess<Number>::initialize(
1384 const unsigned int basis_size,
1385 const bool force_reorthogonalization)
1387 this->orthogonalization_strategy = orthogonalization_strategy;
1388 this->do_reorthogonalization = force_reorthogonalization;
1390 hessenberg_matrix.reinit(basis_size + 1, basis_size);
1391 triangular_matrix.reinit(basis_size + 1, basis_size,
true);
1394 projected_rhs.reinit(basis_size + 1,
true);
1395 givens_rotations.reserve(basis_size);
1397 if (orthogonalization_strategy ==
1400 h.
reinit(2 * basis_size + 3);
1402 h.
reinit(basis_size + 1);
1407 template <
typename Number>
1408 template <
typename VectorType>
1410 ArnoldiProcess<Number>::orthonormalize_nth_vector(
1411 const unsigned int n,
1412 TmpVectors<VectorType> &orthogonal_vectors,
1413 const unsigned int accumulated_iterations,
1414 const boost::signals2::signal<
void(
int)> &reorthogonalize_signal)
1421 double residual_estimate = std::numeric_limits<double>::signaling_NaN();
1424 givens_rotations.clear();
1425 residual_estimate = vv.l2_norm();
1426 if (residual_estimate != 0.)
1427 vv /= residual_estimate;
1428 projected_rhs(0) = residual_estimate;
1430 else if (orthogonalization_strategy ==
1440 const double previous_scaling = n > 0 ? h(n + n - 2) : 1.;
1443 h.reinit(n + n + 1);
1446 Tvmult_add<true>(n, vv, orthogonal_vectors, h, vector_ptrs);
1450 for (
unsigned int i = 0; i < n - 1; ++i)
1451 tmp += h(n + i) * h(n + i);
1456 const double alpha_j =
1457 h(n + n - 1) == 0. ?
1459 (h(n + n - 1) > tmp ?
std::sqrt(h(n + n - 1) - tmp) :
1461 h(n + n - 1) = alpha_j;
1464 for (
unsigned int i = 0; i < n - 1; ++i)
1465 tmp += h(i) * h(n + i);
1466 h(n - 1) = (h(n - 1) - tmp) / alpha_j;
1471 for (
unsigned int i = 0; i < n - 1; ++i)
1472 hessenberg_matrix(i, n - 2) += h(n + i) * previous_scaling;
1473 hessenberg_matrix(n - 1, n - 2) = alpha_j * previous_scaling;
1475 for (
unsigned int i = 0; i < n; ++i)
1478 for (
unsigned int j = (i == 0 ? 0 : i - 1); j < n - 1; ++j)
1479 sum += hessenberg_matrix(i, j) * h(n + j);
1480 hessenberg_matrix(i, n - 1) = (h(i) -
sum) / alpha_j;
1486 for (
unsigned int i = 0; i < n - 1; ++i)
1488 sum += (2. - 1.) * h(n - 1) * h(n - 1);
1489 hessenberg_matrix(n, n - 1) =
1496 h(n + n) = hessenberg_matrix(n, n - 1);
1497 subtract_and_norm<true>(n, orthogonal_vectors, h, vv, vector_ptrs);
1501 residual_estimate = do_givens_rotation(
1502 true, n - 2, triangular_matrix, givens_rotations, projected_rhs);
1507 double norm_vv = 0.0;
1508 double norm_vv_start = 0;
1509 const bool consider_reorthogonalize =
1510 (do_reorthogonalization ==
false) && (n % 5 == 0);
1511 if (consider_reorthogonalize)
1512 norm_vv_start = vv.l2_norm();
1518 for (
unsigned int c = 0; c < 2; ++c)
1521 if (orthogonalization_strategy ==
1525 double htmp = vv * orthogonal_vectors[0];
1527 for (
unsigned int i = 1; i < n; ++i)
1529 htmp = vv.add_and_dot(-htmp,
1530 orthogonal_vectors[i - 1],
1531 orthogonal_vectors[i]);
1536 vv.add_and_dot(-htmp, orthogonal_vectors[n - 1], vv));
1538 else if (orthogonalization_strategy ==
1542 Tvmult_add<false>(n, vv, orthogonal_vectors, h, vector_ptrs);
1543 norm_vv = subtract_and_norm<false>(
1544 n, orthogonal_vectors, h, vv, vector_ptrs);
1562 if (consider_reorthogonalize)
1565 10. * norm_vv_start *
1567 typename VectorType::value_type>::epsilon()))
1572 do_reorthogonalization =
true;
1573 if (!reorthogonalize_signal.empty())
1574 reorthogonalize_signal(accumulated_iterations);
1578 if (do_reorthogonalization ==
false)
1582 for (
unsigned int i = 0; i < n; ++i)
1583 hessenberg_matrix(i, n - 1) = h(i);
1584 hessenberg_matrix(n, n - 1) = norm_vv;
1591 residual_estimate = do_givens_rotation(
1592 false, n - 1, triangular_matrix, givens_rotations, projected_rhs);
1595 return residual_estimate;
1600 template <
typename Number>
1602 ArnoldiProcess<Number>::do_givens_rotation(
1603 const bool delayed_reorthogonalization,
1606 std::vector<std::pair<double, double>> &rotations,
1614 if (delayed_reorthogonalization)
1619 matrix(0, col) = hessenberg_matrix(0, col);
1621 double H_next = hessenberg_matrix(0, col + 1);
1622 for (
int i = 0; i < col; ++i)
1624 const double c = rotations[i].first;
1625 const double s = rotations[i].second;
1626 const double Hi =
matrix(i, col);
1627 const double Hi1 = hessenberg_matrix(i + 1, col);
1628 H_next = -s * H_next + c * hessenberg_matrix(i + 1, col + 1);
1629 matrix(i, col) = c * Hi + s * Hi1;
1630 matrix(i + 1, col) = -s * Hi + c * Hi1;
1635 const double H_col1 = hessenberg_matrix(col + 1, col);
1636 const double H_col =
matrix(col, col);
1637 const double r = 1. /
std::sqrt(H_col * H_col + H_col1 * H_col1);
1638 rotations.emplace_back(H_col * r, H_col1 * r);
1640 rotations[col].first * H_col + rotations[col].second * H_col1;
1642 rhs(col + 1) = -rotations[col].second * rhs(col);
1643 rhs(col) *= rotations[col].first;
1646 -rotations[col].second * H_next +
1647 rotations[col].first * hessenberg_matrix(col + 1, col + 1);
1650 const double H_last = hessenberg_matrix(col + 2, col + 1);
1656 if (H_next == 0. && H_last == 0.)
1661 1. /
std::sqrt(H_next * H_next + H_last * H_last);
1662 return std::abs(H_last * r * rhs(col + 1));
1669 matrix(0, col) = hessenberg_matrix(0, col);
1670 for (
int i = 0; i < col; ++i)
1672 const double c = rotations[i].first;
1673 const double s = rotations[i].second;
1674 const double Hi =
matrix(i, col);
1675 const double Hi1 = hessenberg_matrix(i + 1, col);
1676 matrix(i, col) = c * Hi + s * Hi1;
1677 matrix(i + 1, col) = -s * Hi + c * Hi1;
1680 const double Hi =
matrix(col, col);
1681 const double Hi1 = hessenberg_matrix(col + 1, col);
1687 if (Hi == 0. && Hi1 == 0.)
1689 rotations.emplace_back(1, 0);
1694 const double r = (Hi * Hi + Hi1 * Hi1 == 0 ?
1697 rotations.emplace_back(Hi * r, Hi1 * r);
1699 rotations[col].first * Hi + rotations[col].second * Hi1;
1702 rhs(col + 1) = -rotations[col].second * rhs(col);
1703 rhs(col) *= rotations[col].first;
1711 template <
typename Number>
1713 ArnoldiProcess<Number>::solve_projected_system(
1714 const bool orthogonalization_finished)
1720 unsigned int n = givens_rotations.
size();
1730 if (orthogonalization_strategy ==
1735 if (!orthogonalization_finished)
1737 tmp_triangular_matrix = triangular_matrix;
1738 tmp_rhs = projected_rhs;
1739 std::vector<std::pair<double, double>> tmp_givens_rotations(
1741 do_givens_rotation(
false,
1742 givens_rotations.size(),
1743 tmp_triangular_matrix,
1744 tmp_givens_rotations,
1746 matrix = &tmp_triangular_matrix;
1750 do_givens_rotation(
false,
1751 givens_rotations.size(),
1758 projected_solution.reinit(n);
1759 for (
int i = n - 1; i >= 0; --i)
1761 double s = (*rhs)(i);
1762 for (
unsigned int j = i + 1; j < n; ++j)
1763 s -= projected_solution(j) * (*matrix)(i, j);
1765 projected_solution(i) = s / (*matrix)(i, i);
1769 return projected_solution;
1774 template <
typename Number>
1776 ArnoldiProcess<Number>::get_hessenberg_matrix()
const
1778 return hessenberg_matrix;
1785 complex_less_pred(
const std::complex<double> &x,
1786 const std::complex<double> &y)
1788 return x.real() < y.real() ||
1789 (x.real() == y.real() && x.imag() < y.imag());
1796template <
typename VectorType>
1800 const unsigned int n,
1801 const boost::signals2::signal<
void(
const std::vector<std::complex<double>> &)>
1802 &eigenvalues_signal,
1805 const boost::signals2::signal<
void(
double)> &cond_signal)
1808 if ((!eigenvalues_signal.empty() || !hessenberg_signal.empty() ||
1809 !cond_signal.empty()) &&
1813 for (
unsigned int i = 0; i < n; ++i)
1814 for (
unsigned int j = 0; j < n; ++j)
1815 mat(i, j) = H_orig(i, j);
1816 hessenberg_signal(H_orig);
1818 if (!eigenvalues_signal.empty())
1824 mat_eig.compute_eigenvalues();
1826 for (
unsigned int i = 0; i < mat_eig.n(); ++i)
1831 internal::SolverGMRESImplementation::complex_less_pred);
1836 if (!cond_signal.empty() && (mat.n() > 1))
1839 double condition_number =
1840 mat.singular_value(0) / mat.singular_value(mat.n() - 1);
1841 cond_signal(condition_number);
1848template <
typename VectorType>
1850template <
typename MatrixType,
typename PreconditionerType>
1856 const VectorType &b,
1857 const PreconditionerType &preconditioner)
1859 std::unique_ptr<LogStream::Prefix> prefix;
1861 prefix = std::make_unique<LogStream::Prefix>(
"GMRES");
1865 const unsigned int basis_size =
1872 basis_size + 2, this->memory);
1876 unsigned int accumulated_iterations = 0;
1878 const bool do_eigenvalues =
1880 (!condition_number_signal.empty() ||
1881 !all_condition_numbers_signal.empty() || !eigenvalues_signal.empty() ||
1882 !all_eigenvalues_signal.empty() || !hessenberg_signal.empty() ||
1883 !all_hessenberg_signal.empty());
1886 double res = std::numeric_limits<double>::lowest();
1898 VectorType &p = basis_vectors(basis_size + 1, x);
1904 if (!use_default_residual)
1931 if (left_precondition)
1933 if (accumulated_iterations == 0 && x.all_zero())
1934 preconditioner.vmult(v, b);
1939 preconditioner.vmult(v, p);
1944 if (accumulated_iterations == 0 && x.all_zero())
1953 const double norm_v = arnoldi_process.orthonormalize_nth_vector(
1954 0, basis_vectors, accumulated_iterations, re_orthogonalize_signal);
1959 if (use_default_residual)
1963 iteration_state = solver_control.
check(accumulated_iterations, res);
1966 this->iteration_status(accumulated_iterations, res, x);
1973 deallog <<
"default_res=" << norm_v << std::endl;
1975 if (left_precondition)
1978 r->sadd(-1., 1., b);
1981 preconditioner.vmult(*r, v);
1985 iteration_state = solver_control.
check(accumulated_iterations, res);
1988 this->iteration_status(accumulated_iterations, res, x);
1996 unsigned int inner_iteration = 0;
1997 for (; (inner_iteration < basis_size &&
2001 ++accumulated_iterations;
2003 VectorType &vv = basis_vectors(inner_iteration + 1, x);
2005 if (left_precondition)
2007 A.vmult(p, basis_vectors[inner_iteration]);
2008 preconditioner.vmult(vv, p);
2012 preconditioner.vmult(p, basis_vectors[inner_iteration]);
2017 arnoldi_process.orthonormalize_nth_vector(inner_iteration + 1,
2019 accumulated_iterations,
2020 re_orthogonalize_signal);
2022 if (use_default_residual)
2026 solver_control.
check(accumulated_iterations, res);
2029 this->iteration_status(accumulated_iterations, res, x);
2034 deallog <<
"default_res=" << res << std::endl;
2038 arnoldi_process.solve_projected_system(
false);
2040 if (left_precondition)
2041 for (
unsigned int i = 0; i < inner_iteration + 1; ++i)
2042 x_->add(projected_solution(i), basis_vectors[i]);
2046 for (
unsigned int i = 0; i < inner_iteration + 1; ++i)
2047 p.add(projected_solution(i), basis_vectors[i]);
2048 preconditioner.vmult(*r, p);
2052 r->sadd(-1., 1., b);
2055 if (left_precondition)
2059 this->iteration_status(accumulated_iterations, res, x);
2063 preconditioner.vmult(*x_, *r);
2064 res = x_->l2_norm();
2068 solver_control.
check(accumulated_iterations, res);
2071 this->iteration_status(accumulated_iterations, res, x);
2079 arnoldi_process.solve_projected_system(
true);
2082 compute_eigs_and_cond(arnoldi_process.get_hessenberg_matrix(),
2084 all_eigenvalues_signal,
2085 all_hessenberg_signal,
2086 condition_number_signal);
2088 if (left_precondition)
2089 ::internal::SolverGMRESImplementation::add(
2095 arnoldi_process.vector_ptrs);
2098 ::internal::SolverGMRESImplementation::add(
2104 arnoldi_process.vector_ptrs);
2105 preconditioner.vmult(v, p);
2113 compute_eigs_and_cond(arnoldi_process.get_hessenberg_matrix(),
2117 condition_number_signal);
2119 if (!additional_data.
batched_mode && !krylov_space_signal.empty())
2120 krylov_space_signal(basis_vectors);
2135template <
typename VectorType>
2137boost::signals2::connection
2139 const std::function<
void(
double)> &slot,
2140 const bool every_iteration)
2142 if (every_iteration)
2144 return all_condition_numbers_signal.connect(slot);
2148 return condition_number_signal.connect(slot);
2154template <
typename VectorType>
2157 const std::function<
void(
const std::vector<std::complex<double>> &)> &slot,
2158 const bool every_iteration)
2160 if (every_iteration)
2162 return all_eigenvalues_signal.connect(slot);
2166 return eigenvalues_signal.connect(slot);
2172template <
typename VectorType>
2176 const bool every_iteration)
2178 if (every_iteration)
2180 return all_hessenberg_signal.connect(slot);
2184 return hessenberg_signal.connect(slot);
2190template <
typename VectorType>
2193 const std::function<
void(
2196 return krylov_space_signal.connect(slot);
2201template <
typename VectorType>
2203boost::signals2::connection
2205 const std::function<
void(
int)> &slot)
2207 return re_orthogonalize_signal.connect(slot);
2212template <
typename VectorType>
2228template <
typename VectorType>
2232 const AdditionalData &
data)
2234 , additional_data(
data)
2239template <
typename VectorType>
2242 const AdditionalData &
data)
2244 , additional_data(
data)
2249template <
typename VectorType>
2251template <
typename MatrixType,
typename... PreconditionerTypes>
2256 const MatrixType &A,
2258 const VectorType &b,
2259 const PreconditionerTypes &...preconditioners)
2263 if (additional_data.use_truncated_mpgmres_strategy)
2265 A, x, b, IndexingStrategy::truncated_mpgmres, preconditioners...);
2268 A, x, b, IndexingStrategy::full_mpgmres, preconditioners...);
2273template <
typename VectorType>
2275template <
typename MatrixType,
typename... PreconditionerTypes>
2277 const MatrixType &A,
2279 const VectorType &b,
2280 const IndexingStrategy &indexing_strategy,
2281 const PreconditionerTypes &...preconditioners)
2283 constexpr std::size_t n_preconditioners =
sizeof...(PreconditionerTypes);
2288 const auto apply_nth_preconditioner = [&](
unsigned int n,
2294 [[maybe_unused]]
bool preconditioner_called =
false;
2296 const auto call_matching_preconditioner = [&](
const auto &preconditioner) {
2300 preconditioner_called =
true;
2301 preconditioner.vmult(dst, src);
2306 (call_matching_preconditioner(preconditioners), ...);
2310 std::size_t current_index = 0;
2316 const auto preconditioner_vmult = [&](
auto &dst,
const auto &src) {
2318 if constexpr (n_preconditioners == 0)
2322 apply_nth_preconditioner(current_index, dst, src);
2323 current_index = (current_index + 1) % n_preconditioners;
2330 const auto previous_vector_index =
2331 [indexing_strategy](
unsigned int i) ->
unsigned int {
2334 if constexpr (n_preconditioners == 0)
2338 switch (indexing_strategy)
2340 case IndexingStrategy::fgmres:
2343 case IndexingStrategy::full_mpgmres:
2345 return i / n_preconditioners;
2346 case IndexingStrategy::truncated_mpgmres:
2348 return (1 + i >= n_preconditioners) ?
2349 (1 + i - n_preconditioners) :
2364 basis_size + 1, this->memory);
2366 basis_size, this->memory);
2370 unsigned int accumulated_iterations = 0;
2378 double res = std::numeric_limits<double>::lowest();
2388 if (accumulated_iterations == 0 && x.all_zero())
2392 A.vmult(v(0, x), x);
2393 v[0].sadd(-1., 1., b);
2396 res = arnoldi_process.orthonormalize_nth_vector(0, v);
2397 iteration_state = this->iteration_status(accumulated_iterations, res, x);
2401 unsigned int inner_iteration = 0;
2402 for (; (inner_iteration < basis_size &&
2406 preconditioner_vmult(z(inner_iteration, x),
2407 v[previous_vector_index(inner_iteration)]);
2408 A.vmult(v(inner_iteration + 1, x), z[inner_iteration]);
2411 arnoldi_process.orthonormalize_nth_vector(inner_iteration + 1, v);
2418 this->iteration_status(++accumulated_iterations, res, x);
2424 arnoldi_process.solve_projected_system(
true);
2425 ::internal::SolverGMRESImplementation::add(
2431 arnoldi_process.vector_ptrs);
2447template <
typename VectorType>
2451 const AdditionalData &
data)
2456 data.max_basis_size,
2457 data.orthogonalization_strategy,
2463template <
typename VectorType>
2466 const AdditionalData &
data)
2470 data.max_basis_size,
2471 data.orthogonalization_strategy,
2477template <
typename VectorType>
2479template <
typename MatrixType,
typename... PreconditionerTypes>
2484 const MatrixType &A,
2486 const VectorType &b,
2487 const PreconditionerTypes &...preconditioners)
* * for(const auto &cell :triangulation.active_cell_iterators())
virtual State check(const unsigned int step, const double check_value)
@ iterate
Continue iteration.
@ success
Stop iteration, goal reached.
SolverFGMRES(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
SolverFGMRES(SolverControl &cn, const AdditionalData &data=AdditionalData())
SolverGMRES(const SolverGMRES< VectorType > &)=delete
boost::signals2::connection connect_condition_number_slot(const std::function< void(double)> &slot, const bool every_iteration=false)
boost::signals2::connection connect_krylov_space_slot(const std::function< void(const internal::SolverGMRESImplementation::TmpVectors< VectorType > &)> &slot)
boost::signals2::connection connect_re_orthogonalization_slot(const std::function< void(int)> &slot)
static void compute_eigs_and_cond(const FullMatrix< double > &H_orig, const unsigned int n, const boost::signals2::signal< void(const std::vector< std::complex< double > > &)> &eigenvalues_signal, const boost::signals2::signal< void(const FullMatrix< double > &)> &hessenberg_signal, const boost::signals2::signal< void(double)> &cond_signal)
SolverGMRES(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
boost::signals2::connection connect_hessenberg_slot(const std::function< void(const FullMatrix< double > &)> &slot, const bool every_iteration=true)
SolverGMRES(SolverControl &cn, const AdditionalData &data=AdditionalData())
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
virtual double criterion()
boost::signals2::connection connect_eigenvalues_slot(const std::function< void(const std::vector< std::complex< double > > &)> &slot, const bool every_iteration=false)
SolverMPGMRES(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
internal::SolverGMRESImplementation::ArnoldiProcess< typename VectorType::value_type > arnoldi_process
SolverMPGMRES(SolverControl &cn, const AdditionalData &data=AdditionalData())
AdditionalData additional_data
void solve_internal(const MatrixType &A, VectorType &x, const VectorType &b, const IndexingStrategy &indexing_strategy, const PreconditionerTypes &...preconditioners)
virtual size_type size() const override
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
const FullMatrix< double > & get_hessenberg_matrix() const
Vector< double > projected_rhs
bool do_reorthogonalization
LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy
double orthonormalize_nth_vector(const unsigned int n, TmpVectors< VectorType > &orthogonal_vectors, const unsigned int accumulated_iterations=0, const boost::signals2::signal< void(int)> &reorthogonalize_signal=boost::signals2::signal< void(int)>())
const Vector< double > & solve_projected_system(const bool orthogonalization_finished)
void initialize(const LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy, const unsigned int max_basis_size, const bool force_reorthogonalization)
Vector< double > projected_solution
FullMatrix< double > hessenberg_matrix
std::vector< const Number * > vector_ptrs
FullMatrix< double > triangular_matrix
std::vector< std::pair< double, double > > givens_rotations
double do_givens_rotation(const bool delayed_reorthogonalization, const int col, FullMatrix< double > &matrix, std::vector< std::pair< double, double > > &rotations, Vector< double > &rhs)
VectorMemory< VectorType > & mem
std::vector< typename VectorMemory< VectorType >::Pointer > data
TmpVectors(const unsigned int max_size, VectorMemory< VectorType > &vmem)
unsigned int size() const
VectorType & operator[](const unsigned int i) const
VectorType & operator()(const unsigned int i, const VectorType &temp)
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_CXX20_REQUIRES(condition)
#define DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_ASSERT_UNREACHABLE()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIsFinite(number)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
#define DeclException1(Exception1, type1, outsequence)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::vector< index_type > data
types::global_dof_index locally_owned_size
@ matrix
Contents is actually a matrix.
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
Tpetra::CrsMatrix< Number, LO, GO, NodeType< MemorySpace > > MatrixType
OrthogonalizationStrategy
@ delayed_classical_gram_schmidt
std::enable_if_t< IsBlockVector< VectorType >::value, unsigned int > n_blocks(const VectorType &vector)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
T sum(const T &t, const MPI_Comm mpi_communicator)
void do_Tvmult_add(const unsigned int n_vectors, const std::size_t locally_owned_size, const Number *current_vector, const std::vector< const Number * > &orthogonal_vectors, Vector< double > &h)
double do_subtract_and_norm(const unsigned int n_vectors, const std::size_t locally_owned_size, const std::vector< const Number * > &orthogonal_vectors, const Vector< double > &h, Number *current_vector)
void do_add(const unsigned int n_vectors, const std::size_t locally_owned_size, const std::vector< const Number * > &tmp_vectors, const Vector< double > &h, const bool zero_out, Number *output)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
AdditionalData(const unsigned int max_basis_size=30, const LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy=LinearAlgebra::OrthogonalizationStrategy::delayed_classical_gram_schmidt)
unsigned int max_basis_size
LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy
AdditionalData(const unsigned int max_basis_size=30, const bool right_preconditioning=false, const bool use_default_residual=true, const bool force_re_orthogonalization=false, const bool batched_mode=false, const LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy=LinearAlgebra::OrthogonalizationStrategy::delayed_classical_gram_schmidt)
bool right_preconditioning
bool force_re_orthogonalization
LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy
bool use_default_residual
unsigned int max_basis_size
unsigned int max_n_tmp_vectors
AdditionalData(const unsigned int max_basis_size=30, const LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy=LinearAlgebra::OrthogonalizationStrategy::delayed_classical_gram_schmidt, const bool use_truncated_mpgmres_strategy=true)
LinearAlgebra::OrthogonalizationStrategy orthogonalization_strategy
bool use_truncated_mpgmres_strategy
unsigned int max_basis_size
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)