MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_elasticity_kernels.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12/**
13 * @file
14 * @brief Header for small strain, isotropic, linear elasticity kernels.
15 *
16 * Strong form: -div(sigma(u))
17 *
18 * The constitutive model is given in terms of Lame parameters,
19 * sigma(u) = lambda*div(u)I + 2*mu*sym(grad(u)).
20 * The weak form implemented is (suppressing integral)
21 *
22 * Weak form : lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
23 *
24 * DATA LAYOUT ASSUMPTIONS :
25 * Finite element space - Ordering::byNODES
26 * Finite element basis - ElementDofOrdering::NATIVE
27 * Quadrature functions - QVectorLayout::byNODES
28 * All elements in "fespace" are the same.
29 */
30
31#ifndef MFEM_BILININTEG_ELASTICITY_KERNELS_HPP
32#define MFEM_BILININTEG_ELASTICITY_KERNELS_HPP
33
41#include "../coefficient.hpp"
42#include "../qfunction.hpp"
43
44namespace mfem
45{
46
47namespace internal
48{
49
50/// @brief Elasticity kernel for AddMultPA.
51///
52/// Performs y += Ax. Implemented for byNODES ordering only, and does not use
53/// tensor basis, so it should work for any H1 element.
54///
55/// @param[in] dim 2 or 3
56/// @param[in] nDofs Number of scalar dofs per element.
57/// @param[in] fespace Vector-valued finite element space.
58/// @param[in] lambda Quadrature function for first Lame param.
59/// @param[in] mu Quadrature function for second Lame param.
60/// @param[in] geom Geometric factors corresponding to fespace.
61/// @param[in] maps DofToQuad maps for one element (assume elements all same).
62/// @param[in] x Input vector. nDofs x dim x numEls.
63/// @param Q Scratch Q-Vector. nQuad x dim x dim x numEls.
64/// @param[in,out] y Ax gets added to this. nDofs x dim x numEls.
65void ElasticityAddMultPA(const int dim, const int nDofs,
66 const FiniteElementSpace &fespace, const CoefficientVector &lambda,
67 const CoefficientVector &mu, const GeometricFactors &geom,
68 const DofToQuad &maps, const Vector &x, QuadratureFunction &QVec, Vector &y);
69
70/// @brief Elasticity component kernel for AddMultPA.
71///
72/// Performs y += Ax. Implemented for byNODES ordering only, and does not use
73/// tensor basis, so it should work for any H1 element. i_block and j_block are
74/// the dimensional component that is integrated. They must both be
75/// non-negative.
76///
77/// Example: In 2D, A = [A_00 A_01], x = [x_0], y = [y_0]
78/// [A_10 A_11] [x_1] [y_1].
79/// So i_block = 0, j_block = 1 implies only y_0 += A_01*x_1 is evaluated.
80///
81/// @param[in] dim 2 or 3
82/// @param[in] nDofs Number of scalar dofs per element.
83/// @param[in] fespace Scalar-valued finite element space.
84/// @param[in] lambda Quadrature function for first Lame param.
85/// @param[in] mu Quadrature function for second Lame param.
86/// @param[in] geom Geometric factors corresponding to fespace.
87/// @param[in] maps DofToQuad maps for one element (assume elements all same).
88/// @param[in] x Input vector. nDofs x numEls.
89/// @param Q Scratch Q-Vector. nQuad x dim x numEls.
90/// @param[in,out] y Ax gets added to this. nDofs x numEls.
91/// @param[in] i_block The row dimensional component. <= dim - 1
92/// @param[in] j_block The column dimensional component. <= dim -1
93void ElasticityComponentAddMultPA(
94 const int dim, const int nDofs, const FiniteElementSpace &fespace,
95 const CoefficientVector &lambda, const CoefficientVector &mu,
96 const GeometricFactors &geom, const DofToQuad &maps, const Vector &x,
97 QuadratureFunction &QVec, Vector &y, const int i_block, const int j_block);
98
99/// @brief Elasticity kernel for AssembleEA.
100///
101/// Assembles the E-Matrix for a single dimensional component. Does not require
102/// tensor product elements.
103///
104/// Example: In 2D, A = [A_00 A_01]
105/// [A_10 A_11].
106/// So i_block = 0, j_block = 1 implies only A_01 is assembled.
107///
108/// Mainly intended to be used for order 1 elements on gpus to enable
109/// preconditioning with a LOR-AMG operator. It's expected behavior that higher
110/// orders may request too many resources.
111///
112/// @param[in] dim 2 or 3
113/// @param[in] i_block The row dimensional component. 0 <= i_block <= dim - 1
114/// @param[in] j_block The column dimensional component. 0 <= j_block<= dim -1
115/// @param[in] nDofs Number of scalar dofs per element.
116/// @param[in] lambda Quadrature function for first Lame param.
117/// @param[in] mu Quadrature function for second Lame param.
118/// @param[in] geom Geometric factors corresponding to fespace.
119/// @param[in] maps DofToQuad maps for one element (assume elements all same).
120/// @param[out] emat Resulting E-Matrix Vector. nDofs x nDofs x numEls.
121void ElasticityAssembleEA(const int dim, const int i_block, const int j_block,
122 const int nDofs, const IntegrationRule &ir,
123 const CoefficientVector &lambda,
124 const CoefficientVector &mu, const GeometricFactors &geom,
125 const DofToQuad &maps, Vector &emat);
126
127/// @brief Elasticity kernel for AssembleDiagonalPA.
128///
129/// @param[in] dim 2 or 3
130/// @param[in] nDofs Number of scalar dofs per element.
131/// @param[in] lambda Quadrature function for first Lame param.
132/// @param[in] mu Quadrature function for second Lame param.
133/// @param[in] geom Geometric factors corresponding to fespace.
134/// @param[in] maps DofToQuad maps for one element (assume elements all same).
135/// @param[in] ir Integration rule.
136/// @param[out] diag diagonal of A. nDofs x dim x numEls.
137void ElasticityAssembleDiagonalPA(const int dim, const int nDofs,
138 const CoefficientVector &lambda,
139 const CoefficientVector &mu, const GeometricFactors &geom,
140 const DofToQuad &maps, const IntegrationRule &ir, Vector &diag);
141
142/// Templated implementation of ElasticityAddMultPA.
143template<int dim, int i_block = -1, int j_block = -1>
144void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
145 const CoefficientVector &lambda, const CoefficientVector &mu,
146 const GeometricFactors &geom, const DofToQuad &maps, const Vector &x,
147 QuadratureFunction &QVec, Vector &y)
148{
149 using future::tensor;
151 using future::det;
152 using future::inv;
153
154 static_assert((i_block < 0) == (j_block < 0),
155 "i_block and j_block must both be non-negative or strictly negative.");
156 static constexpr int d = dim;
157 static constexpr int qLower = (i_block < 0) ? 0 : i_block;
158 static constexpr int qUpper = (i_block < 0) ? d : i_block+1;
159 static constexpr int qSize = qUpper-qLower;
160 static constexpr int aLower = (j_block < 0) ? 0 : j_block;
161 static constexpr int aUpper = (j_block < 0) ? d : j_block+1;
162 static constexpr int aSize = aUpper-aLower;
163 static constexpr bool isComponent = (i_block >= 0);
164
165 // Assuming all elements are the same
166 const auto &ir = QVec.GetIntRule(0);
167 const QuadratureInterpolator *E_To_Q_Map = fespace.GetQuadratureInterpolator(
168 ir);
169 E_To_Q_Map->SetOutputLayout(QVectorLayout::byNODES);
170 // interpolate physical derivatives to quadrature points.
171 E_To_Q_Map->PhysDerivatives(x, QVec);
172
173 const int numPoints = ir.GetNPoints();
174 const int numEls = fespace.GetNE();
175 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
176 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
177 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
178 auto Q = Reshape(QVec.ReadWrite(), numPoints, d, qSize, numEls);
179 const real_t *ipWeights = ir.GetWeights().Read();
180 mfem::forall_2D(numEls, numPoints, 1, [=] MFEM_HOST_DEVICE (int e)
181 {
182 // for(int p = 0; p < numPoints, )
183 MFEM_FOREACH_THREAD(p, x,numPoints)
184 {
185 auto invJ = inv(make_tensor<d, d>(
186 [&](int i, int j) { return J(p, i, j, e); }));
187 tensor<real_t, aSize, d> gradx;
188 // load grad(x) into gradx
189 if (isComponent)
190 {
191 for (int i = 0; i < d; i++)
192 {
193 gradx(0,i) = Q(p, i, 0, e);
194 }
195 }
196 else
197 {
198 for (int j = 0; j < d; j++)
199 {
200 for (int i = 0; i < d; i++)
201 {
202 gradx(i,j) = Q(p, i, j, e);
203 }
204 }
205 }
206 // compute divergence
207 real_t div = 0.;
208 for (int i = aLower; i < aUpper; i++)
209 {
210 // take size of gradx into account
211 const int iIndex = isComponent ? 0 : i;
212 div += gradx(iIndex,i);
213 }
214 const real_t w = ipWeights[p]/det(invJ);
215 for (int m = 0; m < d; m++)
216 {
217 for (int q = qLower; q < qUpper; q++)
218 {
219 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
220 // this contraction could be made slightly cheaper using Voigt
221 // notation, but repeated entries are summed for simplicity.
222 real_t contraction = 0.;
223 // not sure how to combine cases
224 if (isComponent)
225 {
226 for (int a = 0; a < d; a++)
227 {
228 contraction += 2*((a == q)*invJ(m,j_block)
229 + (j_block==q)*invJ(m,a))*(gradx(0, a));
230 }
231 }
232 else
233 {
234 for (int a = 0; a < d; a++)
235 {
236 for (int b = 0; b < d; b++)
237 {
238 contraction += ((a == q)*invJ(m,b) + (b == q)*invJ(m,a))
239 *(gradx(a,b) + gradx(b, a));
240 }
241 }
242 }
243 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
244 // contraction = 4*sym(grad(u))sym(grad(v))
245 const int qIndex = isComponent ? 0 : q;
246 Q(p,m,qIndex,e) = w*(lamDev(p, e)*invJ(m,q)*div
247 + 0.5*muDev(p, e)*contraction);
248 }
249 }
250 }
251 });
252
253 // Reduce quadrature function to an E-Vector
254 const auto QRead = Reshape(QVec.Read(), numPoints, d, qSize, numEls);
255 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
256 auto yDev = Reshape(y.ReadWrite(), nDofs, qSize, numEls);
257 mfem::forall_2D(numEls, qSize, nDofs, [=] MFEM_HOST_DEVICE (int e)
258 {
259 MFEM_FOREACH_THREAD(i, y, nDofs)
260 {
261 MFEM_FOREACH_THREAD(q, x, qSize)
262 {
263 const int qIndex = isComponent ? 0 : q;
264 real_t sum = 0.;
265 for (int m = 0; m < d; m++ )
266 {
267 for (int p = 0; p < numPoints; p++ )
268 {
269 sum += QRead(p,m,qIndex,e)*G(p,m,i);
270 }
271 }
272 yDev(i, qIndex, e) += sum;
273 }
274 }
275 });
276}
277
278/// Templated implementation of ElasticityAssembleDiagonalPA.
279template<int dim>
280void ElasticityAssembleDiagonalPA_(const int nDofs,
281 const CoefficientVector &lambda,
282 const CoefficientVector &mu,
283 const GeometricFactors &geom,
284 const DofToQuad &maps,
285 const IntegrationRule &ir,
286 Vector &diag)
287{
288 using future::det;
289 using future::inv;
291 using future::tensor;
292
293 // Assuming all elements are the same
294 static constexpr int d = dim;
295 const int numPoints = ir.GetNPoints();
296 const int numEls = lambda.Size() / numPoints;
297
298 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
299 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
300 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
301 const real_t *ipWeights = ir.GetWeights().Read();
302 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
303 auto diagDev = Reshape(diag.Write(), nDofs, d, numEls);
304
305 mfem::forall_2D(numEls, d, nDofs, [=] MFEM_HOST_DEVICE (int e)
306 {
307 MFEM_FOREACH_THREAD_DIRECT(i, y, nDofs)
308 {
309 MFEM_FOREACH_THREAD_DIRECT(q, x, d)
310 {
311 real_t sum = 0.0;
312 for (int p = 0; p < numPoints; p++)
313 {
314 const auto invJ = inv(make_tensor<d, d>([&](int r, int c)
315 {
316 return J(p, r, c, e);
317 }));
318 const real_t w = ipWeights[p] / det(invJ);
319
320 for (int n = 0; n < d; n++)
321 {
322 for (int m = 0; m < d; m++)
323 {
324 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
325 // this contraction could be made slightly cheaper using Voigt
326 // notation, but repeated entries are summed for simplicity.
327 real_t contraction = 0.0;
328 for (int a = 0; a < d; a++)
329 {
330 for (int b = 0; b < d; b++)
331 {
332 contraction +=
333 ((a == q) * invJ(m, b) + (b == q) * invJ(m, a)) *
334 ((a == q) * invJ(n, b) + (b == q) * invJ(n, a));
335 }
336 }
337 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
338 // contraction = 4*sym(grad(u))sym(grad(v))
339 const real_t Q =
340 w * (lamDev(p, e) * invJ(m, q) * invJ(n, q)
341 + 0.5 * muDev(p, e) * contraction);
342 sum += Q * G(p, m, i) * G(p, n, i);
343 }
344 }
345 }
346 diagDev(i, q, e) = sum;
347 }
348 }
349 });
350}
351
352// Templated implementation of ElasticityAssembleEA.
353template<int dim>
354void ElasticityAssembleEA_(const int i_block,
355 const int j_block,
356 const int nDofs,
357 const IntegrationRule &ir,
358 const CoefficientVector &lambda,
359 const CoefficientVector &mu,
360 const GeometricFactors &geom,
361 const DofToQuad &maps,
362 Vector &emat)
363{
364 using future::tensor;
366 using future::det;
367 using future::inv;
368
369 // Assuming all elements are the same
370 static constexpr int d = dim;
371 const int numPoints = ir.GetNPoints();
372 const int numEls = lambda.Size()/numPoints;
373 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
374 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
375 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
376 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
377 auto ematDev = Reshape(emat.Write(), nDofs, nDofs, numEls);
378 const real_t *ipWeights = ir.GetWeights().Read();
379 mfem::forall_2D(numEls, nDofs, nDofs, [=] MFEM_HOST_DEVICE (int e)
380 {
381 MFEM_FOREACH_THREAD(JDof, y, nDofs)
382 {
383 MFEM_FOREACH_THREAD(IDof, x, nDofs)
384 {
385 real_t sum = 0;
386 for (int p = 0 ; p < numPoints; p++)
387 {
388 auto invJ = inv(make_tensor<d, d>(
389 [&](int i, int j) { return J(p, i, j, e); }));
390 const real_t w = ipWeights[p] /det(invJ);
391 for (int n = 0; n < d; n++)
392 {
393 for (int m = 0; m < d; m++)
394 {
395 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
396 real_t contraction = 0.;
397 for (int a = 0; a < d; a++)
398 {
399 for (int b = 0; b < d; b++)
400 {
401 contraction += ((a == i_block)*invJ(m,b) + (b==i_block)*invJ(m,
402 a))*((a == j_block)*invJ(n,
403 b) + (b==j_block)*invJ(n,a));
404 }
405 }
406 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
407 // contraction = 4*sym(grad(u))sym(grad(v))
408 sum += w*(lamDev(p, e)*invJ(m,i_block)*invJ(n,j_block)
409 + 0.5*muDev(p, e)*contraction)*G(p,m,IDof)*G(p,n,JDof);
410 }
411 }
412 }
413 ematDev(IDof, JDof, e) = sum;
414 }
415 }
416 });
417}
418
419} // namespace internal
420
421} // namespace mfem
422
423#endif
int dim
Definition ex24.cpp:53
real_t mu
Definition ex25.cpp:140
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
mfem::real_t real_t
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
Definition tensor.hpp:1406
MFEM_HOST_DEVICE constexpr auto make_tensor(lambda_type f) -> tensor< decltype(f())>
Creates a tensor of requested dimension by subsequent calls to a functor Can be thought of as analogo...
Definition tensor.hpp:327
MFEM_HOST_DEVICE tensor< T, 1, 1 > inv(const tensor< T, 1, 1 > &A)
Inverts a matrix.
Definition tensor.hpp:1707
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:1220
real_t p(const Vector &x, real_t t)
Implementation of the tensor class.