IPPL API Reference
Independent Parallel Particle Layer C++ API
Loading...
Searching...
No Matches
PoissonCG.h
1//
2// Class PoissonCG
3// Solves the Poisson problem with the CG algorithm
4//
5
6#ifndef IPPL_POISSON_CG_H
7#define IPPL_POISSON_CG_H
8
9#include "LaplaceHelpers.h"
10#include "LinearSolvers/PCG.h"
11#include "LinearSolvers/PreconditionerValidation.h"
12#include "Poisson.h"
13namespace ippl {
14
15 // IPPL_SOLVER_OPERATOR_WRAPPER is defined once in LinearSolvers/Preconditioner.h
16 // (re-exported through this header via PCG.h). Defining it again here used to
17 // silently shadow that definition with a by-value lambda, which copies the
18 // Field on every op_m() call and reintroduces the per-iteration cudaMalloc
19 // in the halo exchange (the realloc never propagates back to the original
20 // Field). Keep a single by-reference definition.
21
22 template <typename FieldLHS, typename FieldRHS = FieldLHS>
23 class PoissonCG : public Poisson<FieldLHS, FieldRHS> {
24 using Tlhs = typename FieldLHS::value_type;
25
26 public:
28 constexpr static unsigned Dim = FieldLHS::dim;
29 using typename Base::lhs_type, typename Base::rhs_type;
30 using OperatorRet = UnaryMinus<detail::meta_laplace<lhs_type>>;
31 using LowerRet = UnaryMinus<detail::meta_lower_laplace<lhs_type>>;
32 using UpperRet = UnaryMinus<detail::meta_upper_laplace<lhs_type>>;
33 using UpperAndLowerRet = UnaryMinus<detail::meta_upper_and_lower_laplace<lhs_type>>;
34 using InverseDiagonalRet = double;
35 using DiagRet = double;
36
37 PoissonCG()
38 : Base()
39 , algo_m(nullptr) {
40 static_assert(std::is_floating_point<Tlhs>::value, "Not a floating point type");
42 }
43
44 PoissonCG(lhs_type& lhs, rhs_type& rhs)
45 : Base(lhs, rhs)
46 , algo_m(nullptr) {
47 static_assert(std::is_floating_point<Tlhs>::value, "Not a floating point type");
49 setSolver(*(this->lhs_mp));
50 }
51
52 void setLhs(lhs_type& lhs) override {
53 Base::setLhs(lhs);
54 setSolver(lhs);
55 }
56
57 void setSolver(lhs_type lhs) {
58 std::string solver_type = this->params_m.template get<std::string>("solver");
59 typename lhs_type::Mesh_t mesh = lhs.get_mesh();
60 typename lhs_type::Layout_t layout = lhs.getLayout();
61 double beta = 0;
62 double alpha = 0;
63 if (solver_type == "preconditioned") {
64 algo_m = std::move(
65 std::make_unique<PCG<OperatorRet, LowerRet, UpperRet, UpperAndLowerRet,
66 InverseDiagonalRet, DiagRet, FieldLHS, FieldRHS>>());
67 // Get the preconditioner type,
68 // if it is not part of the valid list of preconditioners, throw an error.
69 std::string preconditioner_type =
70 this->params_m.template get<std::string>("preconditioner_type");
71 preconditioner_validation::throwIfUnknownType(preconditioner_type, "PoissonCG::setSolver");
72
73 // Read in the preconditioner parameters
74 int level = this->params_m.template get<int>("newton_level");
75 int degree = this->params_m.template get<int>("chebyshev_degree");
76 int inner = this->params_m.template get<int>("gauss_seidel_inner_iterations");
77 int outer = this->params_m.template get<int>("gauss_seidel_outer_iterations");
78 double omega = this->params_m.template get<double>("ssor_omega");
79 int richardson_iterations =
80 this->params_m.template get<int>("richardson_iterations");
81 int communication = this->params_m.template get<int>("communication");
82
83 Inform warn("PoissonCG");
84 // After reading in preconditioner parameters, if they are invalid,
85 // the user is warned that the parameter is invalid, and a default
86 // parameter is used.
87 preconditioner_validation::sanitizeParams(preconditioner_type, warn, level, degree,
88 richardson_iterations, inner, outer, omega,
89 &communication);
90 // Analytical eigenvalues for the d dimensional laplace operator
91 // Going brute force through all possible eigenvalues seems to be the only way to
92 // find max and min
93
94 unsigned long n;
95 double h;
96 for (unsigned int d = 0; d < Dim; ++d) {
97 n = mesh.getGridsize(d);
98 h = mesh.getMeshSpacing(d);
99 double local_min = 4 / std::pow(h, 2); // theoretical maximum
100 double local_max = 0;
101 double test;
102 for (unsigned int i = 1; i < n; ++i) {
103 test = 4. / std::pow(h, 2) * std::pow(std::sin(i * M_PI * h / 2.), 2);
104 if (test > local_max) {
105 local_max = test;
106 }
107 if (test < local_min) {
108 local_min = test;
109 }
110 }
111 beta += local_max;
112 alpha += local_min;
113 }
114 if (communication) {
115 algo_m->setPreconditioner(
116 IPPL_SOLVER_OPERATOR_WRAPPER(-laplace, lhs_type),
117 IPPL_SOLVER_OPERATOR_WRAPPER(-lower_laplace, lhs_type),
118 IPPL_SOLVER_OPERATOR_WRAPPER(-upper_laplace, lhs_type),
119 IPPL_SOLVER_OPERATOR_WRAPPER(-upper_and_lower_laplace, lhs_type),
120 IPPL_SOLVER_OPERATOR_WRAPPER(negative_inverse_diagonal_laplace, lhs_type),
121 IPPL_SOLVER_OPERATOR_WRAPPER(diagonal_laplace, lhs_type), alpha, beta,
122 preconditioner_type, level, degree, richardson_iterations, inner, outer,
123 omega);
124 } else {
125 algo_m->setPreconditioner(
126 IPPL_SOLVER_OPERATOR_WRAPPER(-laplace, lhs_type),
127 IPPL_SOLVER_OPERATOR_WRAPPER(-lower_laplace_no_comm, lhs_type),
128 IPPL_SOLVER_OPERATOR_WRAPPER(-upper_laplace_no_comm, lhs_type),
129 IPPL_SOLVER_OPERATOR_WRAPPER(-upper_and_lower_laplace_no_comm, lhs_type),
130 IPPL_SOLVER_OPERATOR_WRAPPER(negative_inverse_diagonal_laplace, lhs_type),
131 IPPL_SOLVER_OPERATOR_WRAPPER(diagonal_laplace, lhs_type), alpha, beta,
132 preconditioner_type, level, degree, richardson_iterations, inner, outer,
133 omega);
134 }
135 } else {
136 algo_m = std::move(
137 std::make_unique<CG<OperatorRet, LowerRet, UpperRet, UpperAndLowerRet,
138 InverseDiagonalRet, DiagRet, FieldLHS, FieldRHS>>());
139 }
140 algo_m->initializeFields(lhs.get_mesh(), lhs.getLayout());
141 }
142
143 void solve() override {
144 // \todo TODO add a check for mesh changes for alpha and beta for preconditioners
145
146 algo_m->setOperator(IPPL_SOLVER_OPERATOR_WRAPPER(-laplace, lhs_type));
147 algo_m->operator()(*(this->lhs_mp), *(this->rhs_mp), this->params_m);
148
149 int output = this->params_m.template get<int>("output_type");
150 if (output & Base::GRAD) {
151 *(this->grad_mp) = -grad(*(this->lhs_mp));
152 }
153 }
154
160 int getIterationCount() { return algo_m->getIterationCount(); }
161
166 Tlhs getResidue() const { return algo_m->getResidue(); }
167
168 protected:
169 std::unique_ptr<CG<OperatorRet, LowerRet, UpperRet, UpperAndLowerRet, InverseDiagonalRet,
170 DiagRet, FieldLHS, FieldRHS>>
171 algo_m;
172
173 void setDefaultParameters() override {
174 this->params_m.add("max_iterations", 2000);
175 this->params_m.add("tolerance", (Tlhs)1e-13);
176 this->params_m.add("solver", "non-preconditioned");
177 }
178 };
179
180} // namespace ippl
181
182#endif
Definition Inform.h:40
Definition PCG.h:37
Definition PCG.h:338
void add(const std::string &key, const T &value)
Definition ParameterList.h:44
Definition PoissonCG.h:23
int getIterationCount()
Definition PoissonCG.h:160
void solve() override
Definition PoissonCG.h:143
void setLhs(lhs_type &lhs) override
Definition PoissonCG.h:52
void setDefaultParameters() override
Definition PoissonCG.h:173
Tlhs getResidue() const
Definition PoissonCG.h:166
Definition Poisson.h:16
virtual void setLhs(lhs_type &lhs)
Definition Poisson.h:90
Definition Archive.h:20
detail::meta_upper_laplace< Field > upper_laplace(Field &u)
Definition LaplaceHelpers.h:258
detail::meta_upper_and_lower_laplace< Field > upper_and_lower_laplace_no_comm(Field &u)
Definition LaplaceHelpers.h:309
detail::meta_lower_laplace< Field > lower_laplace(Field &u)
Definition LaplaceHelpers.h:222
double negative_inverse_diagonal_laplace(Field &u)
Definition LaplaceHelpers.h:329
detail::meta_upper_laplace< Field > upper_laplace_no_comm(Field &u)
Definition LaplaceHelpers.h:273
detail::meta_grad< Field > grad(Field &u)
Definition FieldOperations.hpp:12
detail::meta_laplace< Field > laplace(Field &u)
Definition FieldOperations.hpp:60
detail::meta_lower_laplace< Field > lower_laplace_no_comm(Field &u)
Definition LaplaceHelpers.h:237
detail::meta_upper_and_lower_laplace< Field > upper_and_lower_laplace(Field &u)
Definition LaplaceHelpers.h:294