IPPL API Reference
Independent Parallel Particle Layer C++ API
Loading...
Searching...
No Matches
PreconditionedFEMPoissonSolver.h
1// Class FEMPoissonSolver
2// Solves the poisson equation using finite element methods and Conjugate
3// Gradient + a Preconditioner.
4
5#ifndef IPPL_PRECONFEMPOISSONSOLVER_H
6#define IPPL_PRECONFEMPOISSONSOLVER_H
7
8// #include "FEM/FiniteElementSpace.h"
9#include "EvalFunctor.h"
10#include "LaplaceHelpers.h"
11#include "LinearSolvers/PCG.h"
12#include "LinearSolvers/PreconditionerValidation.h"
13#include "Poisson.h"
14
15namespace ippl {
23 template <typename FieldLHS, typename FieldRHS = FieldLHS>
24 class PreconditionedFEMPoissonSolver : public Poisson<FieldLHS, FieldRHS> {
25 constexpr static unsigned Dim = FieldLHS::dim;
26 using Tlhs = typename FieldLHS::value_type;
27
28 public:
30 using typename Base::lhs_type, typename Base::rhs_type;
31 using MeshType = typename FieldRHS::Mesh_t;
32
33 // PCG (Preconditioned Conjugate Gradient) is the solver algorithm used
36
37 // FEM Space types
38 using ElementType =
39 std::conditional_t<Dim == 1, ippl::EdgeElement<Tlhs>,
40 std::conditional_t<Dim == 2, ippl::QuadrilateralElement<Tlhs>,
42
44
45 using LagrangeType =
47
48 // default constructor (compatibility with Alpine)
50 : Base()
51 , refElement_m()
52 , quadrature_m(refElement_m, 0.0, 0.0)
53 , lagrangeSpace_m(*(new MeshType(NDIndex<Dim>(Vector<unsigned, Dim>(0)),
55 refElement_m, quadrature_m) {
57 }
58
59 PreconditionedFEMPoissonSolver(lhs_type& lhs, rhs_type& rhs)
60 : Base(lhs, rhs)
61 , refElement_m()
62 , quadrature_m(refElement_m, 0.0, 0.0)
63 , lagrangeSpace_m(rhs.get_mesh(), refElement_m, quadrature_m, rhs.getLayout()) {
64 static_assert(std::is_floating_point<Tlhs>::value, "Not a floating point type");
66 }
67
68 void setRhs(rhs_type& rhs) override {
69 Base::setRhs(rhs);
70
71 lagrangeSpace_m.initialize(rhs.get_mesh(), rhs.getLayout());
72 }
73
77 LagrangeType& getSpace() { return lagrangeSpace_m; }
78
83 void solve() override {
84 // create load vector for the problem
85 this->rhs_mp->fillHalo();
86 lagrangeSpace_m.evaluateLoadVector(*(this->rhs_mp));
87
88 const Vector<size_t, Dim> zeroNdIndex = Vector<size_t, Dim>(0);
89
90 // We can pass the zeroNdIndex here, since the transformation jacobian does not depend
91 // on translation
92 const auto firstElementVertexPoints =
93 lagrangeSpace_m.getElementMeshVertexPoints(zeroNdIndex);
94
95 // Compute Inverse Transpose Transformation Jacobian ()
96 const Vector<Tlhs, Dim> DPhiInvT =
97 refElement_m.getInverseTransposeTransformationJacobian(firstElementVertexPoints);
98
99 // Compute absolute value of the determinant of the transformation jacobian (|det D
100 // Phi_K|)
101 const Tlhs absDetDPhi = Kokkos::abs(
102 refElement_m.getDeterminantOfTransformationJacobian(firstElementVertexPoints));
103
104 EvalFunctor<Tlhs, Dim, LagrangeType::numElementDOFs> poissonEquationEval(DPhiInvT,
105 absDetDPhi);
106
107 // get BC type of our RHS
108 BConds<FieldRHS, Dim>& bcField = (this->rhs_mp)->getFieldBC();
109 FieldBC bcType = bcField[0]->getBCType();
110
111 const auto algoOperator = [poissonEquationEval, &bcField,
112 this](rhs_type field) -> lhs_type {
113 // set appropriate BCs for the field as the info gets lost in the CG iteration
114 field.setFieldBC(bcField);
115
116 field.fillHalo();
117
118 auto return_field = lagrangeSpace_m.evaluateAx(field, poissonEquationEval);
119
120 return return_field;
121 };
122
123 const auto algoOperatorL = [poissonEquationEval, &bcField,
124 this](lhs_type field) -> lhs_type {
125 // set appropriate BCs for the field as the info gets lost in the CG iteration
126 field.setFieldBC(bcField);
127
128 field.fillHalo();
129
130 auto return_field = lagrangeSpace_m.evaluateAx_lower(field, poissonEquationEval);
131
132 return return_field;
133 };
134
135 const auto algoOperatorU = [poissonEquationEval, &bcField,
136 this](lhs_type field) -> lhs_type {
137 // set appropriate BCs for the field as the info gets lost in the CG iteration
138 field.setFieldBC(bcField);
139
140 field.fillHalo();
141
142 auto return_field = lagrangeSpace_m.evaluateAx_upper(field, poissonEquationEval);
143
144 return return_field;
145 };
146
147 const auto algoOperatorUL = [poissonEquationEval, &bcField,
148 this](lhs_type field) -> lhs_type {
149 // set appropriate BCs for the field as the info gets lost in the CG iteration
150 field.setFieldBC(bcField);
151
152 field.fillHalo();
153
154 auto return_field =
155 lagrangeSpace_m.evaluateAx_upperlower(field, poissonEquationEval);
156
157 return return_field;
158 };
159
160 const auto algoOperatorInvD = [poissonEquationEval, &bcField,
161 this](lhs_type field) -> lhs_type {
162 // set appropriate BCs for the field as the info gets lost in the CG iteration
163 field.setFieldBC(bcField);
164
165 field.fillHalo();
166
167 auto return_field =
168 lagrangeSpace_m.evaluateAx_inversediag(field, poissonEquationEval);
169
170 return return_field;
171 };
172
173 const auto algoOperatorD = [poissonEquationEval, &bcField,
174 this](lhs_type field) -> lhs_type {
175 // set appropriate BCs for the field as the info gets lost in the CG iteration
176 field.setFieldBC(bcField);
177
178 field.fillHalo();
179
180 auto return_field = lagrangeSpace_m.evaluateAx_diag(field, poissonEquationEval);
181
182 return return_field;
183 };
184
185 // set preconditioner for PCG
186 std::string preconditioner_type =
187 this->params_m.template get<std::string>("preconditioner_type");
188 preconditioner_validation::throwIfUnknownType(preconditioner_type,
189 "PreconditionedFEMPoissonSolver::solve");
190
191 Inform warn("PreconditionedFEMPoissonSolver");
192 int level = this->params_m.template get<int>("newton_level");
193 int degree = this->params_m.template get<int>("chebyshev_degree");
194 int inner = this->params_m.template get<int>("gauss_seidel_inner_iterations");
195 int outer = this->params_m.template get<int>("gauss_seidel_outer_iterations");
196 double omega = this->params_m.template get<double>("ssor_omega");
197 int richardson_iterations = this->params_m.template get<int>("richardson_iterations");
198 preconditioner_validation::sanitizeParams(preconditioner_type, warn, level, degree,
199 richardson_iterations, inner, outer, omega);
200
201 pcg_algo_m.setPreconditioner(algoOperator, algoOperatorL, algoOperatorU, algoOperatorUL,
202 algoOperatorInvD, algoOperatorD, 0, 0, preconditioner_type,
203 level, degree, richardson_iterations, inner, outer, omega);
204
205 pcg_algo_m.setOperator(algoOperator);
206
207 // send boundary values to RHS (load vector) i.e. lifting (Dirichlet BCs)
208 if (bcType == CONSTANT_FACE) {
209 // Set per-face Dirichlet values on physical boundary nodes before halo exchange;
210 // fillHalo must see the correct boundary state after load vector assembly.
211 bcField.apply(*(this->rhs_mp));
212 bcField.assignGhostToPhysical(*(this->rhs_mp));
213 this->rhs_mp->fillHalo();
214 *(this->rhs_mp) =
215 *(this->rhs_mp)
216 - lagrangeSpace_m.evaluateAx_lift(*(this->rhs_mp), poissonEquationEval);
217 }
218
219 // start a timer
220 static IpplTimings::TimerRef pcgTimer = IpplTimings::getTimer("pcg");
221 IpplTimings::startTimer(pcgTimer);
222
223 // run PCG -> lhs contains solution
224 pcg_algo_m(*(this->lhs_mp), *(this->rhs_mp), this->params_m);
225
226 // added for BCs to be imposed properly
227 // (they are not propagated through the preconditioner)
228 if (bcType == CONSTANT_FACE) {
229 bcField.assignGhostToPhysical(*(this->lhs_mp));
230 }
231 (this->lhs_mp)->fillHalo();
232
233 IpplTimings::stopTimer(pcgTimer);
234 }
235
241 int getIterationCount() { return pcg_algo_m.getIterationCount(); }
242
247 Tlhs getResidue() const { return pcg_algo_m.getResidue(); }
248
253 template <typename F>
254 Tlhs getL2Error(const F& analytic) {
255 Tlhs error_norm = this->lagrangeSpace_m.computeErrorL2(*(this->lhs_mp), analytic);
256 return error_norm;
257 }
258
264 Tlhs getAvg(bool Vol = false) {
265 Tlhs avg = this->lagrangeSpace_m.computeAvg(*(this->lhs_mp));
266 if (Vol) {
267 lhs_type unit((this->lhs_mp)->get_mesh(), (this->lhs_mp)->getLayout());
268 unit = 1.0;
269 Tlhs vol = this->lagrangeSpace_m.computeAvg(unit);
270 return avg / vol;
271 } else {
272 return avg;
273 }
274 }
275
276 protected:
277 PCGSolverAlgorithm_t pcg_algo_m;
278
279 virtual void setDefaultParameters() override {
280 this->params_m.add("max_iterations", 1000);
281 this->params_m.add("tolerance", (Tlhs)1e-13);
282 }
283
284 ElementType refElement_m;
285 QuadratureType quadrature_m;
286 LagrangeType lagrangeSpace_m;
287 };
288
289} // namespace ippl
290
291#endif
Definition Inform.h:40
Definition BConds.h:23
virtual int getIterationCount()
Definition PCG.h:106
virtual void setOperator(OperatorF op)
Definition PCG.h:70
KOKKOS_FUNCTION vertex_points_t getElementMeshVertexPoints(const indices_t &elementNDIndex) const
Get all the global vertex points of an element (given by its NDIndex).
Definition FiniteElementSpace.hpp:271
Definition HexahedralElement.h:14
A class representing a Lagrange space for finite element methods on a structured, rectilinear grid.
Definition LagrangeSpace.h:36
T computeAvg(const FieldLHS &u_h) const
Given a field, compute the average.
Definition LagrangeSpace.hpp:1609
void initialize(UniformCartesian< T, Dim > &mesh, Layout_t &layout)
Initialize a LagrangeSpace object created with the default constructor.
Definition LagrangeSpace.hpp:41
void evaluateLoadVector(FieldRHS &field) const
Assemble the load vector b of the system Ax = b.
Definition LagrangeSpace.hpp:1330
FieldLHS evaluateAx(FieldLHS &field, F &evalFunction)
Assembly operations ///////////////////////////////////////////////.
Definition LagrangeSpace.hpp:372
T computeErrorL2(const FieldLHS &u_h, const F &u_sol) const
Error norm computations ///////////////////////////////////////////.
Definition LagrangeSpace.hpp:1525
FieldLHS evaluateAx_lift(FieldLHS &field, F &evalFunction)
Assemble the left stiffness matrix A of the system but only for the boundary values,...
Definition LagrangeSpace.hpp:1212
Definition NDIndex.h:21
Definition PCG.h:338
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 add(const std::string &key, const T &value)
Definition ParameterList.h:44
Definition Poisson.h:16
virtual void setRhs(rhs_type &rhs)
Definition Poisson.h:96
A solver for the poisson equation using finite element methods and Conjugate Gradient (CG)
Definition PreconditionedFEMPoissonSolver.h:24
void solve() override
Solve the poisson equation using finite element methods. The problem is described by -laplace(lhs) = ...
Definition PreconditionedFEMPoissonSolver.h:83
int getIterationCount()
Definition PreconditionedFEMPoissonSolver.h:241
Tlhs getL2Error(const F &analytic)
Definition PreconditionedFEMPoissonSolver.h:254
virtual void setDefaultParameters() override
Definition PreconditionedFEMPoissonSolver.h:279
void setRhs(rhs_type &rhs) override
Definition PreconditionedFEMPoissonSolver.h:68
LagrangeType & getSpace()
Return the LagrangeSpace object.
Definition PreconditionedFEMPoissonSolver.h:77
Tlhs getResidue() const
Definition PreconditionedFEMPoissonSolver.h:247
Tlhs getAvg(bool Vol=false)
Definition PreconditionedFEMPoissonSolver.h:264
Definition Vector.h:23
Definition Archive.h:20
Representation of the lhs of the problem we are trying to solve.
Definition FEMMaxwellDiffusionSolver.h:29