9#include "FEM/FEMVector.h"
10#include "Preconditioner.h"
11#include "SolverAlgorithm.h"
16 namespace pcg_preconditioner_defaults {
17 inline constexpr int newton_level = 5;
18 inline constexpr int chebyshev_degree = 31;
19 inline constexpr int richardson_iterations = 4;
20 inline constexpr int gauss_seidel_inner = 2;
21 inline constexpr int gauss_seidel_outer = 2;
22 inline constexpr int communication = 0;
23 inline constexpr double ssor_omega = 1.57079632679;
25 inline constexpr std::array<const char*, 7> valid_types = {
26 "jacobi",
"newton",
"chebyshev",
"richardson",
"richardson_alt",
"gauss-seidel",
"ssor"
29 inline bool is_valid_type(
const std::string& type) {
30 return std::find(valid_types.begin(), valid_types.end(), type) != valid_types.end();
34 template <
typename OperatorRet,
typename LowerRet,
typename UpperRet,
typename UpperLowerRet,
35 typename InverseDiagRet,
typename DiagRet,
typename FieldLHS,
36 typename FieldRHS = FieldLHS>
39 typedef typename Base::lhs_type::value_type T;
42 using typename Base::lhs_type,
typename Base::rhs_type;
43 using OperatorF = std::function<OperatorRet(lhs_type&)>;
44 using LowerF = std::function<LowerRet(lhs_type&)>;
45 using UpperF = std::function<UpperRet(lhs_type&)>;
46 using UpperLowerF = std::function<UpperLowerRet(lhs_type&)>;
47 using InverseDiagF = std::function<InverseDiagRet(lhs_type&)>;
48 using DiagF = std::function<DiagRet(lhs_type&)>;
49 using mesh_type =
typename lhs_type::Mesh_t;
50 using layout_type =
typename lhs_type::Layout_t;
52 virtual ~CG() =
default;
60 virtual void initializeFields(mesh_type& mesh, layout_type& layout) {
61 r.initialize(mesh, layout);
62 d.initialize(mesh, layout);
63 q.initialize(mesh, layout);
70 virtual void setOperator(OperatorF op) { op_m = std::move(op); }
71 virtual void setPreconditioner(
72 [[maybe_unused]] OperatorF&& op,
73 [[maybe_unused]] LowerF&& lower,
74 [[maybe_unused]] UpperF&& upper,
75 [[maybe_unused]] UpperLowerF&&
77 [[maybe_unused]] InverseDiagF&&
79 [[maybe_unused]] DiagF&& diagonal,
80 [[maybe_unused]]
double alpha,
81 [[maybe_unused]]
double beta,
82 [[maybe_unused]] std::string preconditioner_type =
84 [[maybe_unused]]
int level =
85 pcg_preconditioner_defaults::newton_level,
87 [[maybe_unused]]
int degree =
88 pcg_preconditioner_defaults::chebyshev_degree,
90 [[maybe_unused]]
int richardson_iterations =
91 pcg_preconditioner_defaults::richardson_iterations,
93 [[maybe_unused]]
int inner =
94 pcg_preconditioner_defaults::gauss_seidel_inner,
96 [[maybe_unused]]
int outer =
97 pcg_preconditioner_defaults::gauss_seidel_outer,
98 [[maybe_unused]]
double omega = pcg_preconditioner_defaults::ssor_omega
110 constexpr unsigned Dim = lhs_type::dim;
112 static IpplTimings::TimerRef cg_ops = IpplTimings::getTimer(
"CG");
113 static IpplTimings::TimerRef up_layout = IpplTimings::getTimer(
"updateLayout");
114 static IpplTimings::TimerRef
apply = IpplTimings::getTimer(
"applyOp");
115 static IpplTimings::TimerRef inner = IpplTimings::getTimer(
"innerProduct");
117 IpplTimings::startTimer(cg_ops);
120 const int maxIterations = params.
get<
int>(
"max_iterations");
124 IpplTimings::startTimer(up_layout);
125 r.updateLayout(lhs.getLayout());
126 d.updateLayout(lhs.getLayout());
127 q.updateLayout(lhs.getLayout());
128 IpplTimings::stopTimer(up_layout);
131 bc_type lhsBCs = lhs.getFieldBC();
134 bool allFacesPeriodic =
true;
135 for (
unsigned int i = 0; i < 2 * Dim; ++i) {
136 FieldBC bcType = lhsBCs[i]->getBCType();
137 if (bcType == PERIODIC_FACE) {
139 bc[i] = std::make_shared<PeriodicFace<lhs_type>>(i);
140 }
else if (bcType & CONSTANT_FACE) {
143 bc[i] = std::make_shared<ZeroFace<lhs_type>>(i);
144 allFacesPeriodic =
false;
147 "Only periodic or constant BCs for LHS supported.");
152 IpplTimings::startTimer(
apply);
154 IpplTimings::stopTimer(
apply);
159 IpplTimings::startTimer(inner);
161 IpplTimings::stopTimer(inner);
163 residueNorm = Kokkos::sqrt(delta1);
164 const T tolerance = params.
get<T>(
"tolerance") * norm(rhs);
166 while (iterations_m < maxIterations && residueNorm > tolerance) {
167 IpplTimings::startTimer(
apply);
169 IpplTimings::stopTimer(
apply);
171 IpplTimings::startTimer(inner);
173 IpplTimings::stopTimer(inner);
174 lhs = lhs + alpha * d;
185 IpplTimings::startTimer(inner);
187 IpplTimings::stopTimer(inner);
188 T beta = delta1 / delta0;
190 residueNorm = Kokkos::sqrt(delta1);
195 if (allFacesPeriodic) {
196 T avg = lhs.getVolumeAverage();
199 IpplTimings::stopTimer(cg_ops);
202 virtual T getResidue()
const {
return residueNorm; }
207 int iterations_m = 0;
218 template <
typename OperatorRet,
typename LowerRet,
typename UpperRet,
typename UpperLowerRet,
219 typename InverseDiagRet,
typename T>
220 class CG<OperatorRet, LowerRet, UpperRet, UpperLowerRet, InverseDiagRet,
FEMVector<T>,
226 using OperatorF = std::function<OperatorRet(
lhs_type&)>;
227 using LowerF = std::function<LowerRet(
lhs_type&)>;
228 using UpperF = std::function<UpperRet(
lhs_type&)>;
229 using UpperLowerF = std::function<UpperLowerRet(
lhs_type&)>;
230 using InverseDiagF = std::function<InverseDiagRet(
lhs_type&)>;
232 virtual ~CG() =
default;
239 virtual void setPreconditioner(
240 [[maybe_unused]] OperatorF&& op,
241 [[maybe_unused]] LowerF&& lower,
242 [[maybe_unused]] UpperF&& upper,
243 [[maybe_unused]] UpperLowerF&&
245 [[maybe_unused]] InverseDiagF&&
247 [[maybe_unused]]
double alpha,
248 [[maybe_unused]]
double beta,
249 [[maybe_unused]] std::string preconditioner_type =
251 [[maybe_unused]]
int level =
252 pcg_preconditioner_defaults::newton_level,
254 [[maybe_unused]]
int degree =
255 pcg_preconditioner_defaults::chebyshev_degree,
257 [[maybe_unused]]
int richardson_iterations =
258 pcg_preconditioner_defaults::richardson_iterations,
260 [[maybe_unused]]
int inner =
261 pcg_preconditioner_defaults::gauss_seidel_inner,
263 [[maybe_unused]]
int outer = pcg_preconditioner_defaults::gauss_seidel_outer
280 const int maxIterations = params.
get<
int>(
"max_iterations");
295 residueNorm = Kokkos::sqrt(delta1);
296 const T tolerance = params.
get<T>(
"tolerance") * norm(rhs);
301 while (iterations_m < maxIterations && residueNorm > tolerance) {
305 lhs = lhs + alpha * d;
318 T beta = delta1 / delta0;
320 residueNorm = Kokkos::sqrt(delta1);
326 virtual T getResidue()
const {
return residueNorm; }
331 int iterations_m = 0;
334 template <
typename OperatorRet,
typename LowerRet,
typename UpperRet,
typename UpperLowerRet,
335 typename InverseDiagRet,
typename DiagRet,
typename FieldLHS,
336 typename FieldRHS = FieldLHS>
337 class PCG :
public CG<OperatorRet, LowerRet, UpperRet, UpperLowerRet, InverseDiagRet, DiagRet,
338 FieldLHS, FieldRHS> {
340 typedef typename Base::lhs_type::value_type T;
343 using typename Base::lhs_type,
typename Base::rhs_type;
344 using OperatorF = std::function<OperatorRet(lhs_type&)>;
345 using LowerF = std::function<LowerRet(lhs_type&)>;
346 using UpperF = std::function<UpperRet(lhs_type&)>;
347 using UpperLowerF = std::function<UpperLowerRet(lhs_type&)>;
348 using InverseDiagF = std::function<InverseDiagRet(lhs_type&)>;
349 using DiagF = std::function<DiagRet(lhs_type&)>;
351 using mesh_type =
typename lhs_type::Mesh_t;
352 using layout_type =
typename lhs_type::Layout_t;
355 :
CG<OperatorRet, LowerRet, UpperRet, UpperLowerRet, InverseDiagRet, DiagRet, FieldLHS,
357 , preconditioner_m(
nullptr) {};
359 void initializeFields(mesh_type& mesh, layout_type& layout)
override {
360 CG<OperatorRet, LowerRet, UpperRet, UpperLowerRet, InverseDiagRet, DiagRet, FieldLHS,
361 FieldRHS>::initializeFields(mesh, layout);
362 s.initialize(mesh, layout);
363 pcond_out.initialize(mesh, layout);
374 UpperLowerF&& upper_and_lower,
375 InverseDiagF&& inverse_diagonal,
379 std::string preconditioner_type =
"",
380 int level = pcg_preconditioner_defaults::newton_level,
382 int degree = pcg_preconditioner_defaults::chebyshev_degree,
384 int richardson_iterations = pcg_preconditioner_defaults::richardson_iterations,
386 int inner = pcg_preconditioner_defaults::gauss_seidel_inner,
388 int outer = pcg_preconditioner_defaults::gauss_seidel_outer,
390 double omega = pcg_preconditioner_defaults::ssor_omega
396 if (preconditioner_type ==
"jacobi") {
405 std::move(inverse_diagonal)));
406 }
else if (preconditioner_type ==
"newton") {
407 preconditioner_m = std::move(
409 std::move(op), alpha, beta, level, 1e-3));
410 }
else if (preconditioner_type ==
"chebyshev") {
411 preconditioner_m = std::move(
413 std::move(op), alpha, beta, degree, 1e-3));
414 }
else if (preconditioner_type ==
"richardson") {
416 std::move(std::make_unique<
418 std::move(upper_and_lower), std::move(inverse_diagonal),
419 richardson_iterations));
420 }
else if (preconditioner_type ==
"richardson_alt") {
422 std::move(std::make_unique<
424 std::move(op), std::move(inverse_diagonal), richardson_iterations));
425 }
else if (preconditioner_type ==
"gauss-seidel") {
426 preconditioner_m = std::move(
428 std::move(lower), std::move(upper), std::move(inverse_diagonal), inner,
430 }
else if (preconditioner_type ==
"ssor") {
432 std::move(std::make_unique<
434 std::move(lower), std::move(upper), std::move(inverse_diagonal),
435 std::move(diagonal), inner, outer, omega));
442 constexpr unsigned Dim = lhs_type::dim;
444 if (preconditioner_m ==
nullptr) {
446 "Preconditioner has not been set for PCG solver");
449 this->iterations_m = 0;
450 const int maxIterations = params.
get<
int>(
"max_iterations");
457 this->r.updateLayout(lhs.getLayout());
458 this->d.updateLayout(lhs.getLayout());
459 s.updateLayout(lhs.getLayout());
460 pcond_out.updateLayout(lhs.getLayout());
461 this->q.updateLayout(lhs.getLayout());
466 preconditioner_m->init_fields(lhs);
469 bc_type lhsBCs = lhs.getFieldBC();
472 bool allFacesPeriodic =
true;
473 for (
unsigned int i = 0; i < 2 * Dim; ++i) {
474 FieldBC bcType = lhsBCs[i]->getBCType();
475 if (bcType == PERIODIC_FACE) {
477 bc[i] = std::make_shared<PeriodicFace<lhs_type>>(i);
478 }
else if (bcType & CONSTANT_FACE) {
481 bc[i] = std::make_shared<ZeroFace<lhs_type>>(i);
482 allFacesPeriodic =
false;
485 "Only periodic or constant BCs for LHS supported.");
490 this->r = rhs - this->op_m(lhs);
491 (*preconditioner_m)(this->r, pcond_out);
492 this->d = T(1) * pcond_out;
493 this->d.setFieldBC(bc);
497 this->residueNorm = Kokkos::sqrt(Kokkos::abs(delta1));
498 const T tolerance = params.
get<T>(
"tolerance") * this->residueNorm;
500 while (this->iterations_m<maxIterations&& this->residueNorm> tolerance) {
503 this->q = this->op_m(this->d);
505 lhs = lhs + alpha * this->d;
514 this->r = this->r - alpha * this->q;
516 (*preconditioner_m)(this->r, s);
521 T beta = delta1 / delta0;
522 this->residueNorm = Kokkos::sqrt(Kokkos::abs(delta1));
524 this->d = s + beta * this->d;
525 ++this->iterations_m;
528 if (allFacesPeriodic) {
529 T avg = lhs.getVolumeAverage();
535 std::unique_ptr<preconditioner<FieldLHS>> preconditioner_m;
Definition IpplException.h:6
virtual void operator()(lhs_type &lhs, rhs_type &rhs, const ParameterList ¶ms) override
Definition PCG.h:273
virtual int getIterationCount()
Definition PCG.h:271
virtual void setOperator(OperatorF op)
Definition PCG.h:238
virtual int getIterationCount()
Definition PCG.h:106
virtual void setOperator(OperatorF op)
Definition PCG.h:70
virtual void operator()(lhs_type &lhs, rhs_type &rhs, const ParameterList ¶ms) override
Definition PCG.h:108
1D vector used in the context of FEM.
Definition FEMVector.h:34
FEMVector< T > deepCopy() const
Create a deep copy, where all the information of this vector is copied to a new one.
Definition FEMVector.hpp:234
void setHalo(T setValue)
Set the halo cells to setValue.
Definition FEMVector.hpp:152
void setPreconditioner(OperatorF &&op, LowerF &&lower, UpperF &&upper, UpperLowerF &&upper_and_lower, InverseDiagF &&inverse_diagonal, DiagF &&diagonal, double alpha, double beta, std::string preconditioner_type="", int level=pcg_preconditioner_defaults::newton_level, int degree=pcg_preconditioner_defaults::chebyshev_degree, int richardson_iterations=pcg_preconditioner_defaults::richardson_iterations, int inner=pcg_preconditioner_defaults::gauss_seidel_inner, int outer=pcg_preconditioner_defaults::gauss_seidel_outer, double omega=pcg_preconditioner_defaults::ssor_omega) override
Definition PCG.h:370
void operator()(lhs_type &lhs, rhs_type &rhs, const ParameterList ¶ms) override
Definition PCG.h:441
Definition ParameterList.h:29
T get(const std::string &key) const
Definition ParameterList.h:59
Definition SolverAlgorithm.h:16
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
Definition IpplOperations.h:64
T innerProduct(const FEMVector< T > &a, const FEMVector< T > &b)
Calculate the inner product between two ippl::FEMVector(s).
Definition FEMVector.h:407
Definition Preconditioner.h:503
Definition Preconditioner.h:69
Definition Preconditioner.h:245
Definition Preconditioner.h:109
Definition Preconditioner.h:32
Definition Preconditioner.h:434
Definition Preconditioner.h:367
Definition Preconditioner.h:598