Line data Source code
1 : // Class LagrangeSpace
2 : // This is the LagrangeSpace class. It is a class representing a Lagrange space
3 : // for finite element methods on a structured grid.
4 :
5 : #ifndef IPPL_LAGRANGESPACE_H
6 : #define IPPL_LAGRANGESPACE_H
7 :
8 : #include <cmath>
9 :
10 : #include "FEM/FiniteElementSpace.h"
11 :
12 : constexpr unsigned getLagrangeNumElementDOFs(unsigned Dim, unsigned Order) {
13 : // needs to be constexpr pow function to work at compile time. Kokkos::pow doesn't work.
14 : return static_cast<unsigned>(power(static_cast<int>(Order + 1), static_cast<int>(Dim)));
15 : }
16 :
17 : namespace ippl {
18 :
19 : /**
20 : * @brief A class representing a Lagrange space for finite element methods on a structured,
21 : * rectilinear grid.
22 : *
23 : * @tparam T The floating point number type of the field values
24 : * @tparam Dim The dimension of the mesh
25 : * @tparam Order The order of the Lagrange space
26 : * @tparam QuadratureType The type of the quadrature rule
27 : * @tparam FieldLHS The type of the left hand side field
28 : * @tparam FieldRHS The type of the right hand side field
29 : */
30 : template <typename T, unsigned Dim, unsigned Order, typename ElementType,
31 : typename QuadratureType, typename FieldLHS, typename FieldRHS>
32 : // requires IsQuadrature<QuadratureType>
33 : class LagrangeSpace
34 : : public FiniteElementSpace<T, Dim, getLagrangeNumElementDOFs(Dim, Order), ElementType,
35 : QuadratureType, FieldLHS, FieldRHS> {
36 : public:
37 : // The number of degrees of freedom per element
38 : static constexpr unsigned numElementDOFs = getLagrangeNumElementDOFs(Dim, Order);
39 :
40 : // The dimension of the mesh
41 : static constexpr unsigned dim = FiniteElementSpace<T, Dim, numElementDOFs, ElementType,
42 : QuadratureType, FieldLHS, FieldRHS>::dim;
43 :
44 : // The order of the Lagrange space
45 : static constexpr unsigned order = Order;
46 :
47 : // The number of mesh vertices per element
48 : static constexpr unsigned numElementVertices =
49 : FiniteElementSpace<T, Dim, numElementDOFs, ElementType, QuadratureType, FieldLHS,
50 : FieldRHS>::numElementVertices;
51 :
52 : // A vector with the position of the element in the mesh in each dimension
53 : typedef typename FiniteElementSpace<T, Dim, numElementDOFs, ElementType, QuadratureType,
54 : FieldLHS, FieldRHS>::indices_t indices_t;
55 :
56 : // A point in the global coordinate system
57 : typedef typename FiniteElementSpace<T, Dim, numElementDOFs, ElementType, QuadratureType,
58 : FieldLHS, FieldRHS>::point_t point_t;
59 :
60 : typedef typename FiniteElementSpace<T, Dim, numElementDOFs, ElementType, QuadratureType,
61 : FieldLHS, FieldRHS>::vertex_points_t vertex_points_t;
62 :
63 : // Field layout type for domain decomposition info
64 : typedef FieldLayout<Dim> Layout_t;
65 :
66 : // View types
67 : typedef typename detail::ViewType<T, Dim>::view_type ViewType;
68 : typedef typename detail::ViewType<T, Dim, Kokkos::MemoryTraits<Kokkos::Atomic>>::view_type
69 : AtomicViewType;
70 :
71 : ///////////////////////////////////////////////////////////////////////
72 : // Constructors ///////////////////////////////////////////////////////
73 : ///////////////////////////////////////////////////////////////////////
74 :
75 : /**
76 : * @brief Construct a new LagrangeSpace object
77 : *
78 : * @param mesh Reference to the mesh
79 : * @param ref_element Reference to the reference element
80 : * @param quadrature Reference to the quadrature rule
81 : * @param layout Reference to the field layout
82 : */
83 : LagrangeSpace(UniformCartesian<T, Dim>& mesh, ElementType& ref_element,
84 : const QuadratureType& quadrature, const Layout_t& layout);
85 :
86 : /**
87 : * @brief Construct a new LagrangeSpace object (without layout)
88 : * This constructor is made to work with the default constructor in
89 : * FEMPoissonSolver.h such that it is compatible with alpine.
90 : *
91 : * @param mesh Reference to the mesh
92 : * @param ref_element Reference to the reference element
93 : * @param quadrature Reference to the quadrature rule
94 : */
95 : LagrangeSpace(UniformCartesian<T, Dim>& mesh, ElementType& ref_element,
96 : const QuadratureType& quadrature);
97 :
98 : /**
99 : * @brief Initialize a LagrangeSpace object created with the default constructor
100 : *
101 : * @param mesh Reference to the mesh
102 : * @param layout Reference to the field layout
103 : */
104 : void initialize(UniformCartesian<T, Dim>& mesh, const Layout_t& layout);
105 :
106 : ///////////////////////////////////////////////////////////////////////
107 : /**
108 : * @brief Initialize a Kokkos view containing the element indices.
109 : * This distributes the elements among MPI ranks.
110 : */
111 : void initializeElementIndices(const Layout_t& layout);
112 :
113 : /// Degree of Freedom operations //////////////////////////////////////
114 : ///////////////////////////////////////////////////////////////////////
115 :
116 : /**
117 : * @brief Get the number of global degrees of freedom in the space
118 : *
119 : * @return size_t - unsigned integer number of global degrees of freedom
120 : */
121 : KOKKOS_FUNCTION size_t numGlobalDOFs() const override;
122 :
123 : /**
124 : * @brief Get the elements local DOF from the element index and global DOF
125 : * index
126 : *
127 : * @param elementIndex size_t - The index of the element
128 : * @param globalDOFIndex size_t - The global DOF index
129 : *
130 : * @return size_t - The local DOF index
131 : */
132 : KOKKOS_FUNCTION size_t getLocalDOFIndex(const size_t& elementIndex,
133 : const size_t& globalDOFIndex) const override;
134 :
135 : /**
136 : * @brief Get the global DOF index from the element index and local DOF
137 : *
138 : * @param elementIndex size_t - The index of the element
139 : * @param localDOFIndex size_t - The local DOF index
140 : *
141 : * @return size_t - The global DOF index
142 : */
143 : KOKKOS_FUNCTION size_t getGlobalDOFIndex(const size_t& elementIndex,
144 : const size_t& localDOFIndex) const override;
145 :
146 : /**
147 : * @brief Get the local DOF indices (vector of local DOF indices)
148 : * They are independent of the specific element because it only depends on
149 : * the reference element type
150 : *
151 : * @return Vector<size_t, NumElementDOFs> - The local DOF indices
152 : */
153 : KOKKOS_FUNCTION Vector<size_t, numElementDOFs> getLocalDOFIndices() const override;
154 :
155 : /**
156 : * @brief Get the global DOF indices (vector of global DOF indices) of an element
157 : *
158 : * @param elementIndex size_t - The index of the element
159 : *
160 : * @return Vector<size_t, NumElementDOFs> - The global DOF indices
161 : */
162 : KOKKOS_FUNCTION Vector<size_t, numElementDOFs> getGlobalDOFIndices(
163 : const size_t& element_index) const override;
164 :
165 : ///////////////////////////////////////////////////////////////////////
166 : /// Basis functions and gradients /////////////////////////////////////
167 : ///////////////////////////////////////////////////////////////////////
168 :
169 : /**
170 : * @brief Evaluate the shape function of a local degree of freedom at a given point in the
171 : * reference element
172 : *
173 : * @param localDOF size_t - The local degree of freedom index
174 : * @param localPoint point_t (Vector<T, Dim>) - The point in the reference element
175 : *
176 : * @return T - The value of the shape function at the given point
177 : */
178 : KOKKOS_FUNCTION T evaluateRefElementShapeFunction(const size_t& localDOF,
179 : const point_t& localPoint) const override;
180 :
181 : /**
182 : * @brief Evaluate the gradient of the shape function of a local degree of freedom at a
183 : * given point in the reference element
184 : *
185 : * @param localDOF size_t - The local degree of freedom index
186 : * @param localPoint point_t (Vector<T, Dim>) - The point in the reference element
187 : *
188 : * @return point_t (Vector<T, Dim>) - The gradient of the shape function at the given
189 : * point
190 : */
191 : KOKKOS_FUNCTION point_t evaluateRefElementShapeFunctionGradient(
192 : const size_t& localDOF, const point_t& localPoint) const override;
193 :
194 : ///////////////////////////////////////////////////////////////////////
195 : /// Assembly operations ///////////////////////////////////////////////
196 : ///////////////////////////////////////////////////////////////////////
197 :
198 : /**
199 : * @brief Assemble the left stiffness matrix A of the system Ax = b
200 : *
201 : * @param field The field to assemble the matrix for
202 : * @param evalFunction The lambda telling us the form which A takes
203 : *
204 : * @return FieldLHS - The LHS field containing A*x
205 : */
206 : template <typename F>
207 : FieldLHS evaluateAx(FieldLHS& field, F& evalFunction) const;
208 :
209 : /**
210 : * @brief Assemble the left stiffness matrix A of the system
211 : * but only for the boundary values, so that they can be
212 : * subtracted from the RHS for treatment of Dirichlet BCs
213 : *
214 : * @param field The field to assemble the matrix for
215 : * @param evalFunction The lambda telling us the form which A takes
216 : *
217 : * @return FieldLHS - The LHS field containing A*x
218 : */
219 : template <typename F>
220 : FieldLHS evaluateAx_lift(FieldLHS& field, F& evalFunction) const;
221 :
222 : /**
223 : * @brief Assemble the load vector b of the system Ax = b
224 : *
225 : * @param rhs_field The field to set with the load vector
226 : *
227 : * @return FieldRHS - The RHS field containing b
228 : */
229 : void evaluateLoadVector(FieldRHS& field) const override;
230 :
231 : ///////////////////////////////////////////////////////////////////////
232 : /// Error norm computations ///////////////////////////////////////////
233 : ///////////////////////////////////////////////////////////////////////
234 :
235 : /**
236 : * @brief Given two fields, compute the L2 norm error
237 : *
238 : * @param u_h The numerical solution found using FEM
239 : * @param u_sol The analytical solution (functor)
240 : *
241 : * @return error - The error ||u_h - u_sol||_L2
242 : */
243 : template <typename F>
244 : T computeErrorL2(const FieldLHS& u_h, const F& u_sol) const;
245 :
246 : /**
247 : * @brief Given a field, compute the average
248 : *
249 : * @param u_h The numerical solution found using FEM
250 : *
251 : * @return avg The average of the field on the domain
252 : */
253 : T computeAvg(const FieldLHS& u_h) const;
254 :
255 : private:
256 : /**
257 : * @brief Check if a DOF is on the boundary of the mesh
258 : *
259 : * @param ndindex The NDIndex of the global DOF
260 : *
261 : * @return true - If the DOF is on the boundary
262 : * @return false - If the DOF is not on the boundary
263 : */
264 216 : KOKKOS_FUNCTION bool isDOFOnBoundary(const indices_t& ndindex) const {
265 388 : for (size_t d = 0; d < Dim; ++d) {
266 216 : if (ndindex[d] <= 0 || ndindex[d] >= this->nr_m[d] - 1) {
267 44 : return true;
268 : }
269 : }
270 172 : return false;
271 : }
272 :
273 : Kokkos::View<size_t*> elementIndices;
274 : };
275 :
276 : } // namespace ippl
277 :
278 : #include "FEM/LagrangeSpace.hpp"
279 :
280 : #endif
|