MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_elasticity_kernels.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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 "../bilininteg.hpp"
42#include "../coefficient.hpp"
43#include "../qfunction.hpp"
44
45namespace mfem
46{
47
48namespace internal
49{
50
51/// @brief Elasticity kernel for AddMultPA.
52///
53/// Performs y += Ax. Implemented for byNODES ordering only, and does not use
54/// tensor basis, so it should work for any H1 element.
55///
56/// @param[in] dim 2 or 3
57/// @param[in] nDofs Number of scalar dofs per element.
58/// @param[in] fespace Vector-valued finite element space.
59/// @param[in] lambda Quadrature function for first Lame param.
60/// @param[in] mu Quadrature function for second Lame param.
61/// @param[in] geom Geometric factors corresponding to fespace.
62/// @param[in] maps DofToQuad maps for one element (assume elements all same).
63/// @param[in] x Input vector. nDofs x dim x numEls.
64/// @param Q Scratch Q-Vector. nQuad x dim x dim x numEls.
65/// @param[in,out] y Ax gets added to this. nDofs x dim x numEls.
66void ElasticityAddMultPA(const int dim, const int nDofs,
67 const FiniteElementSpace &fespace, const CoefficientVector &lambda,
68 const CoefficientVector &mu, const GeometricFactors &geom,
69 const DofToQuad &maps, const Vector &x, QuadratureFunction &QVec, Vector &y);
70
71/// @brief Elasticity component kernel for AddMultPA.
72///
73/// Performs y += Ax. Implemented for byNODES ordering only, and does not use
74/// tensor basis, so it should work for any H1 element. i_block and j_block are
75/// the dimensional component that is integrated. They must both be
76/// non-negative.
77///
78/// Example: In 2D, A = [A_00 A_01], x = [x_0], y = [y_0]
79/// [A_10 A_11] [x_1] [y_1].
80/// So i_block = 0, j_block = 1 implies only y_0 += A_01*x_1 is evaluated.
81///
82/// @param[in] dim 2 or 3
83/// @param[in] nDofs Number of scalar dofs per element.
84/// @param[in] fespace Scalar-valued finite element space.
85/// @param[in] lambda Quadrature function for first Lame param.
86/// @param[in] mu Quadrature function for second Lame param.
87/// @param[in] geom Geometric factors corresponding to fespace.
88/// @param[in] maps DofToQuad maps for one element (assume elements all same).
89/// @param[in] x Input vector. nDofs x numEls.
90/// @param Q Scratch Q-Vector. nQuad x dim x numEls.
91/// @param[in,out] y Ax gets added to this. nDofs x numEls.
92/// @param[in] i_block The row dimensional component. <= dim - 1
93/// @param[in] j_block The column dimensional component. <= dim -1
94void ElasticityComponentAddMultPA(
95 const int dim, const int nDofs, const FiniteElementSpace &fespace,
96 const CoefficientVector &lambda, const CoefficientVector &mu,
97 const GeometricFactors &geom, const DofToQuad &maps, const Vector &x,
98 QuadratureFunction &QVec, Vector &y, const int i_block, const int j_block);
99
100/// @brief Elasticity kernel for AssembleEA.
101///
102/// Assembles the E-Matrix for a single dimensional component. Does not require
103/// tensor product elements.
104///
105/// Example: In 2D, A = [A_00 A_01]
106/// [A_10 A_11].
107/// So i_block = 0, j_block = 1 implies only A_01 is assembled.
108///
109/// Mainly intended to be used for order 1 elements on gpus to enable
110/// preconditioning with a LOR-AMG operator. It's expected behavior that higher
111/// orders may request too many resources.
112///
113/// @param[in] dim 2 or 3
114/// @param[in] i_block The row dimensional component. 0 <= i_block <= dim - 1
115/// @param[in] j_block The column dimensional component. 0 <= j_block<= dim -1
116/// @param[in] nDofs Number of scalar dofs per element.
117/// @param[in] lambda Quadrature function for first Lame param.
118/// @param[in] mu Quadrature function for second Lame param.
119/// @param[in] geom Geometric factors corresponding to fespace.
120/// @param[in] maps DofToQuad maps for one element (assume elements all same).
121/// @param[out] emat Resulting E-Matrix Vector. nDofs x nDofs x numEls.
122void ElasticityAssembleEA(const int dim, const int i_block, const int j_block,
123 const int nDofs, const IntegrationRule &ir,
124 const CoefficientVector &lambda,
125 const CoefficientVector &mu, const GeometricFactors &geom,
126 const DofToQuad &maps, Vector &emat);
127
128/// @brief Elasticity kernel for AssembleDiagonalPA.
129///
130/// @param[in] dim 2 or 3
131/// @param[in] nDofs Number of scalar dofs per element.
132/// @param[in] lambda Quadrature function for first Lame param.
133/// @param[in] mu Quadrature function for second Lame param.
134/// @param[in] geom Geometric factors corresponding to fespace.
135/// @param[in] maps DofToQuad maps for one element (assume elements all same).
136/// @param QVec Scratch Q-Vector. nQuad x dim x dim x dim x dim x numEls.
137/// @param[out] diag diagonal of A. nDofs x dim x numEls.
138void ElasticityAssembleDiagonalPA(const int dim, const int nDofs,
139 const CoefficientVector &lambda,
140 const CoefficientVector &mu, const GeometricFactors &geom,
141 const DofToQuad &maps, QuadratureFunction &QVec, Vector &diag);
142
143/// Templated implementation of ElasticityAddMultPA.
144template<int dim, int i_block = -1, int j_block = -1>
145void ElasticityAddMultPA_(const int nDofs, const FiniteElementSpace &fespace,
146 const CoefficientVector &lambda, const CoefficientVector &mu,
147 const GeometricFactors &geom, const DofToQuad &maps, const Vector &x,
148 QuadratureFunction &QVec, Vector &y)
149{
150 static_assert((i_block < 0) == (j_block < 0),
151 "i_block and j_block must both be non-negative or strictly negative.");
152 static constexpr int d = dim;
153 static constexpr int qLower = (i_block < 0) ? 0 : i_block;
154 static constexpr int qUpper = (i_block < 0) ? d : i_block+1;
155 static constexpr int qSize = qUpper-qLower;
156 static constexpr int aLower = (j_block < 0) ? 0 : j_block;
157 static constexpr int aUpper = (j_block < 0) ? d : j_block+1;
158 static constexpr int aSize = aUpper-aLower;
159 static constexpr bool isComponent = (i_block >= 0);
160
161 // Assuming all elements are the same
162 const auto &ir = QVec.GetIntRule(0);
163 const QuadratureInterpolator *E_To_Q_Map = fespace.GetQuadratureInterpolator(
164 ir);
165 E_To_Q_Map->SetOutputLayout(QVectorLayout::byNODES);
166 // interpolate physical derivatives to quadrature points.
167 E_To_Q_Map->PhysDerivatives(x, QVec);
168
169 const int numPoints = ir.GetNPoints();
170 const int numEls = fespace.GetNE();
171 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
172 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
173 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
174 auto Q = Reshape(QVec.ReadWrite(), numPoints, d, qSize, numEls);
175 const real_t *ipWeights = ir.GetWeights().Read();
176 mfem::forall_2D(numEls, numPoints, 1, [=] MFEM_HOST_DEVICE (int e)
177 {
178 // for(int p = 0; p < numPoints, )
179 MFEM_FOREACH_THREAD(p, x,numPoints)
180 {
181 auto invJ = inv(make_tensor<d, d>(
182 [&](int i, int j) { return J(p, i, j, e); }));
183 tensor<real_t, aSize, d> gradx;
184 // load grad(x) into gradx
185 if (isComponent)
186 {
187 for (int i = 0; i < d; i++)
188 {
189 gradx(0,i) = Q(p, i, 0, e);
190 }
191 }
192 else
193 {
194 for (int j = 0; j < d; j++)
195 {
196 for (int i = 0; i < d; i++)
197 {
198 gradx(i,j) = Q(p, i, j, e);
199 }
200 }
201 }
202 // compute divergence
203 real_t div = 0.;
204 for (int i = aLower; i < aUpper; i++)
205 {
206 // take size of gradx into account
207 const int iIndex = isComponent ? 0 : i;
208 div += gradx(iIndex,i);
209 }
210 const real_t w = ipWeights[p] /det(invJ);
211 for (int m = 0; m < d; m++)
212 {
213 for (int q = qLower; q < qUpper; q++)
214 {
215 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
216 // this contraction could be made slightly cheaper using Voigt
217 // notation, but repeated entries are summed for simplicity.
218 real_t contraction = 0.;
219 // not sure how to combine cases
220 if (isComponent)
221 {
222 for (int a = 0; a < d; a++)
223 {
224 contraction += 2*((a == q)*invJ(m,j_block) + (j_block==q)*invJ(m,a))*(gradx(0,
225 a));
226 }
227 }
228 else
229 {
230 for (int a = 0; a < d; a++)
231 {
232 for (int b = 0; b < d; b++)
233 {
234 contraction += ((a == q)*invJ(m,b) + (b==q)*invJ(m,a))
235 *(gradx(a,b) + gradx(b, a));
236 }
237 }
238 }
239 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
240 // contraction = 4*sym(grad(u))sym(grad(v))
241 const int qIndex = isComponent ? 0 : q;
242 Q(p,m,qIndex,e) = w*(lamDev(p, e)*invJ(m,q)*div + 0.5*muDev(p, e)*contraction);
243 }
244 }
245 }
246 });
247
248 // Reduce quadrature function to an E-Vector
249 const auto QRead = Reshape(QVec.Read(), numPoints, d, qSize, numEls);
250 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
251 auto yDev = Reshape(y.ReadWrite(), nDofs, qSize, numEls);
252 mfem::forall_2D(numEls, qSize, nDofs, [=] MFEM_HOST_DEVICE (int e)
253 {
254 MFEM_FOREACH_THREAD(i, y, nDofs)
255 {
256 MFEM_FOREACH_THREAD(q, x, qSize)
257 {
258 const int qIndex = isComponent ? 0 : q;
259 real_t sum = 0.;
260 for (int m = 0; m < d; m++ )
261 {
262 for (int p = 0; p < numPoints; p++ )
263 {
264 sum += QRead(p,m,qIndex,e)*G(p,m,i);
265 }
266 }
267 yDev(i, qIndex, e) += sum;
268 }
269 }
270 });
271}
272
273/// Templated implementation of ElasticityAssembleDiagonalPA.
274template<int dim>
275void ElasticityAssembleDiagonalPA_(const int nDofs,
276 const CoefficientVector &lambda,
277 const CoefficientVector &mu, const GeometricFactors &geom,
278 const DofToQuad &maps, QuadratureFunction &QVec, Vector &diag)
279{
280 // Assuming all elements are the same
281 const auto &ir = QVec.GetIntRule(0);
282 static constexpr int d = dim;
283 const int numPoints = ir.GetNPoints();
284 const int numEls = lambda.Size()/numPoints;
285 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
286 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
287 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
288 auto Q = Reshape(QVec.ReadWrite(), numPoints, d,d, d, numEls);
289 const real_t *ipWeights = ir.GetWeights().Read();
290 mfem::forall_2D(numEls, numPoints,1, [=] MFEM_HOST_DEVICE (int e)
291 {
292 MFEM_FOREACH_THREAD(p, x,numPoints)
293 {
294 auto invJ = inv(make_tensor<d, d>(
295 [&](int i, int j) { return J(p, i, j, e); }));
296 const real_t w = ipWeights[p] /det(invJ);
297 for (int n = 0; n < d; n++)
298 {
299 for (int m = 0; m < d; m++)
300 {
301 for (int q = 0; q < d; q++)
302 {
303 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
304 // this contraction could be made slightly cheaper using Voigt
305 // notation, but repeated entries are summed for simplicity.
306 real_t contraction = 0.;
307 for (int a = 0; a < d; a++)
308 {
309 for (int b = 0; b < d; b++)
310 {
311 contraction += ((a == q)*invJ(m,b) + (b==q)*invJ(m,a))*((a == q)
312 *invJ(n, b) + (b==q)*invJ(n,a));
313 }
314 }
315 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
316 // contraction = 4*sym(grad(u))sym(grad(v))
317 Q(p,m,n,q,e) = w*(lamDev(p, e)*invJ(m,q)*invJ(n,q)
318 + 0.5*muDev(p, e)*contraction);
319 }
320 }
321 }
322 }
323 });
324
325 // Reduce quadrature function to an E-Vector
326 const auto QRead = Reshape(QVec.Read(), numPoints, d, d, d, numEls);
327 auto diagDev = Reshape(diag.Write(), nDofs, d, numEls);
328 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
329 mfem::forall_2D(numEls, d, nDofs, [=] MFEM_HOST_DEVICE (int e)
330 {
331 MFEM_FOREACH_THREAD(i, y, nDofs)
332 {
333 MFEM_FOREACH_THREAD(q, x, d)
334 {
335 real_t sum = 0.;
336 for (int n = 0; n < d; n++)
337 {
338 for (int m = 0; m < d; m++)
339 {
340 for (int p = 0; p < numPoints; p++ )
341 {
342 sum += QRead(p,m,n,q,e)*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 // Assuming all elements are the same
365 static constexpr int d = dim;
366 const int numPoints = ir.GetNPoints();
367 const int numEls = lambda.Size()/numPoints;
368 const auto lamDev = Reshape(lambda.Read(), numPoints, numEls);
369 const auto muDev = Reshape(mu.Read(), numPoints, numEls);
370 const auto J = Reshape(geom.J.Read(), numPoints, d, d, numEls);
371 const auto G = Reshape(maps.G.Read(), numPoints, d, nDofs);
372 auto ematDev = Reshape(emat.Write(), nDofs, nDofs, numEls);
373 const real_t *ipWeights = ir.GetWeights().Read();
374 mfem::forall_2D(numEls, nDofs, nDofs, [=] MFEM_HOST_DEVICE (int e)
375 {
376 MFEM_FOREACH_THREAD(JDof, y, nDofs)
377 {
378 MFEM_FOREACH_THREAD(IDof, x, nDofs)
379 {
380 real_t sum = 0;
381 for (int p = 0 ; p < numPoints; p++)
382 {
383 auto invJ = inv(make_tensor<d, d>(
384 [&](int i, int j) { return J(p, i, j, e); }));
385 const real_t w = ipWeights[p] /det(invJ);
386 for (int n = 0; n < d; n++)
387 {
388 for (int m = 0; m < d; m++)
389 {
390 // compute contraction of 4*sym(grad(u))sym(grad(v)) term.
391 real_t contraction = 0.;
392 for (int a = 0; a < d; a++)
393 {
394 for (int b = 0; b < d; b++)
395 {
396 contraction += ((a == i_block)*invJ(m,b) + (b==i_block)*invJ(m,
397 a))*((a == j_block)*invJ(n,
398 b) + (b==j_block)*invJ(n,a));
399 }
400 }
401 // lambda*div(u)*div(v) + 2*mu*sym(grad(u))*sym(grad(v))
402 // contraction = 4*sym(grad(u))sym(grad(v))
403 sum += w*(lamDev(p, e)*invJ(m,i_block)*invJ(n,j_block)
404 + 0.5*muDev(p, e)*contraction)*G(p,m,IDof)*G(p,n,JDof);
405 }
406 }
407 }
408 ematDev(IDof, JDof, e) = sum;
409 }
410 }
411 });
412}
413
414} // namespace internal
415
416} // namespace mfem
417
418#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_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:131
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:762
float real_t
Definition config.hpp:43
real_t p(const Vector &x, real_t t)
Implementation of the tensor class.