MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_vectorfemass_pa.cpp
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#include "../bilininteg.hpp"
14
15namespace mfem
16{
17/// \cond DO_NOT_DOCUMENT
19VectorFEMassIntegrator::ApplyPAKernels::Fallback(
21 int dim, int, int, int)
22{
23 const bool trial_curl = (TrialType == mfem::FiniteElement::CURL);
24 const bool trial_div = (TrialType == mfem::FiniteElement::DIV);
25 const bool test_curl = (TestType == mfem::FiniteElement::CURL);
26 const bool test_div = (TestType == mfem::FiniteElement::DIV);
27
28 if (dim == 3)
29 {
30 if (trial_curl && test_curl)
31 {
32 return internal::PAHcurlMassApply3D;
33 }
34 else if (trial_div && test_div)
35 {
36 return internal::PAHdivMassApply3D;
37 }
38 else if (trial_curl && test_div)
39 {
40 return internal::PAHdivHcurlMassApply3D;
41 }
42 else if (trial_div && test_curl)
43 {
44 return internal::PAHcurlHdivMassApply3D;
45 }
46 }
47 else if (dim == 2) // 2D
48 {
49 if (trial_curl && test_curl)
50 {
51 return internal::PAHcurlMassApply2D;
52 }
53 else if (trial_div && test_div)
54 {
55 return internal::PAHdivMassApply2D;
56 }
57 else if (trial_curl && test_div)
58 {
59 return internal::PAHdivHcurlMassApply2D;
60 }
61 else if (trial_div && test_curl)
62 {
63 return internal::PAHcurlHdivMassApply2D;
64 }
65 }
66 MFEM_ABORT("Unknown kernel.");
67}
68/// \endcond DO_NOT_DOCUMENT
69
70VectorFEMassIntegrator::Kernels::Kernels()
71{
72 // h(curl), h(curl)
73 // Q = P + 1 (3D)
75 FiniteElement::CURL, 3, 2, 2, 3>();
77 FiniteElement::CURL, 3, 3, 3, 4>();
79 FiniteElement::CURL, 3, 4, 4, 5>();
81 FiniteElement::CURL, 3, 5, 5, 6>();
82 // Q = P + 2 (3D)
84 FiniteElement::CURL, 3, 2, 2, 4>();
86 FiniteElement::CURL, 3, 3, 3, 5>();
88 FiniteElement::CURL, 3, 4, 4, 6>();
90 FiniteElement::CURL, 3, 5, 5, 7>();
91 // Q = P + 4 (3D)
93 FiniteElement::CURL, 3, 2, 2, 6>();
95 FiniteElement::CURL, 3, 3, 3, 7>();
97 FiniteElement::CURL, 3, 4, 4, 8>();
99 FiniteElement::CURL, 3, 5, 5, 9>();
100 // h(div), h(div)
101 // Q = P (2D)
103 FiniteElement::DIV, 2, 2, 2, 2>();
105 FiniteElement::DIV, 2, 3, 3, 3>();
107 FiniteElement::DIV, 2, 4, 4, 4>();
109 FiniteElement::DIV, 2, 5, 5, 5>();
110
111 // Q = P + 1 (3D)
113 FiniteElement::DIV, 3, 2, 2, 3>();
115 FiniteElement::DIV, 3, 3, 3, 4>();
117 FiniteElement::DIV, 3, 4, 4, 5>();
119 FiniteElement::DIV, 3, 5, 5, 6>();
120}
121
122void VectorFEMassIntegrator::Init(Coefficient *q, DiagonalMatrixCoefficient *dq,
124{
125 static Kernels kernels{};
126 Q = q;
127 DQ = dq;
128 MQ = mq;
129}
130
132{
133 AssemblePA(fes, fes);
134}
135
137 const FiniteElementSpace &test_fes)
138{
139 // Assumes tensor-product elements
140 Mesh *mesh = trial_fes.GetMesh();
141
142 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
143 const VectorTensorFiniteElement *trial_el =
144 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
145 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
146
147 const FiniteElement *test_fel = test_fes.GetTypicalFE();
148 const VectorTensorFiniteElement *test_el =
149 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
150 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
151
152 const IntegrationRule *ir
153 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
155 const int dims = trial_el->GetDim();
156 MFEM_VERIFY(dims == 2 || dims == 3, "");
157
158 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
159 nq = ir->GetNPoints();
160 dim = mesh->Dimension();
161 MFEM_VERIFY(dim == 2 || dim == 3, "");
162
163 ne = trial_fes.GetNE();
164 MFEM_VERIFY(ne == test_fes.GetNE(),
165 "Different meshes for test and trial spaces");
167 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
168 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
169 dofs1D = mapsC->ndof;
170 quad1D = mapsC->nqpt;
171
172 mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
175
176 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
177
178 trial_fetype = static_cast<FiniteElement::DerivType>(trial_el->GetDerivType());
179 test_fetype = static_cast<FiniteElement::DerivType>(test_el->GetDerivType());
180
181 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
182 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
183 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
184 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
185
186 QuadratureSpace qs(*mesh, *ir);
188 if (Q) { coeff.Project(*Q); }
189 else if (MQ) { coeff.ProjectTranspose(*MQ); }
190 else if (DQ) { coeff.Project(*DQ); }
191 else { coeff.SetConstant(1.0); }
192
193 const int coeff_dim = coeff.GetVDim();
194 symmetric = (coeff_dim != dim*dim);
195
196 if ((trial_curl && test_div) || (trial_div && test_curl))
197 {
198 pa_data.SetSize((coeff_dim == 1 ? 1 : dim*dim) * nq * ne,
200 }
201 else
202 {
203 pa_data.SetSize((symmetric ? symmDims : dims*dims) * nq * ne,
205 }
206 if (trial_curl && test_curl && dim == 3)
207 {
208 internal::PADiffusionSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
209 coeff, pa_data);
210 }
211 else if (trial_curl && test_curl && dim == 2)
212 {
213 internal::PADiffusionSetup2D<2>(quad1D, coeff_dim, ne, ir->GetWeights(),
214 geom->J, coeff, pa_data);
215 }
216 else if (trial_div && test_div && dim == 3)
217 {
218 internal::PAHdivMassSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
219 coeff, pa_data);
220 }
221 else if (trial_div && test_div && dim == 2)
222 {
223 internal::PAHdivMassSetup2D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
224 coeff, pa_data);
225 }
226 else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
227 test_fel->GetOrder() == trial_fel->GetOrder())
228 {
229 if (coeff_dim == 1)
230 {
231 internal::PAHcurlL2Setup3D(nq, coeff_dim, ne, ir->GetWeights(), coeff, pa_data);
232 }
233 else
234 {
235 const bool tr = (trial_div && test_curl);
236 if (dim == 3)
237 {
238 internal::PAHcurlHdivMassSetup3D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
239 geom->J, coeff, pa_data);
240 }
241 else
242 {
243 internal::PAHcurlHdivMassSetup2D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
244 geom->J, coeff, pa_data);
245 }
246 }
247 }
248 else
249 {
250 MFEM_ABORT("Unknown kernel.");
251 }
252}
253
255{
256 if (dim == 3)
257 {
259 {
261 {
262 const int ID = (dofs1D << 4) | quad1D;
263 switch (ID)
264 {
265 case 0x23:
266 return internal::SmemPAHcurlMassAssembleDiagonal3D<2,3>(
268 mapsO->B, mapsC->B, pa_data, diag);
269 case 0x34:
270 return internal::SmemPAHcurlMassAssembleDiagonal3D<3,4>(
272 mapsO->B, mapsC->B, pa_data, diag);
273 case 0x45:
274 return internal::SmemPAHcurlMassAssembleDiagonal3D<4,5>(
276 mapsO->B, mapsC->B, pa_data, diag);
277 case 0x56:
278 return internal::SmemPAHcurlMassAssembleDiagonal3D<5,6>(
280 mapsO->B, mapsC->B, pa_data, diag);
281 default:
282 return internal::SmemPAHcurlMassAssembleDiagonal3D(
284 mapsO->B, mapsC->B, pa_data, diag);
285 }
286 }
287 else
288 {
289 internal::PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
290 mapsO->B, mapsC->B, pa_data, diag);
291 }
292 }
295 {
296 internal::PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
297 mapsO->B, mapsC->B, pa_data, diag);
298 }
299 else
300 {
301 MFEM_ABORT("Unknown kernel.");
302 }
303 }
304 else // 2D
305 {
307 {
308 internal::PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
309 mapsO->B, mapsC->B, pa_data, diag);
310 }
313 {
314 internal::PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
315 mapsO->B, mapsC->B, pa_data, diag);
316 }
317 else
318 {
319 MFEM_ABORT("Unknown kernel.");
320 }
321 }
322}
323
325{
326 const bool scalar_coeff = !(DQ || MQ);
327 ApplyPAKernels::Run(trial_fetype, test_fetype, dim, dofs1D, dofs1Dtest,
328 quad1D, ne, symmetric, scalar_coeff, mapsO->B, mapsC->B,
331}
332
334{
335 const bool scalar_coeff = !(DQ || MQ);
336
337 Vector abs_pa_data(pa_data);
338 abs_pa_data.Abs();
339
340 Array<real_t> absBo(mapsO->B);
341 Array<real_t> absBc(mapsC->B);
342 Array<real_t> absBto_t(mapsOtest->Bt);
343 Array<real_t> absBtc_t(mapsCtest->Bt);
344
345 absBo.Abs();
346 absBc.Abs();
347 absBto_t.Abs();
348 absBtc_t.Abs();
349
350 ApplyPAKernels::Run(trial_fetype, test_fetype, dim, dofs1D, dofs1Dtest,
351 quad1D, ne, symmetric, scalar_coeff, absBo, absBc,
352 absBto_t, absBtc_t, abs_pa_data, x, y, dofs1D,
354}
355
357 Vector &y) const
358{
359 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
360 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
361 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
362 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
363
364 bool symmetricSpaces = true;
365 if (dim == 3 && ((trial_div && test_curl) || (trial_curl && test_div)))
366 {
367 const bool scalarCoeff = !(DQ || MQ);
368 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
369 trial_div, true, mapsO->B, mapsC->B,
370 mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
371 symmetricSpaces = false;
372 }
373 else if (dim == 2 && ((trial_curl && test_div) || (trial_div && test_curl)))
374 {
375 const bool scalarCoeff = !(DQ || MQ);
376 internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
377 !trial_curl, true, mapsO->B, mapsC->B,
378 mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
379 symmetricSpaces = false;
380 }
381 if (symmetricSpaces)
382 {
383 if (MQ && dynamic_cast<SymmetricMatrixCoefficient*>(MQ) == NULL)
384 {
385 MFEM_ABORT("VectorFEMassIntegrator transpose not implemented for asymmetric MatrixCoefficient");
386 }
387 AddMultPA(x, y);
388 }
389}
390
391} // namespace mfem
void Abs()
Replace each entry of the array with its absolute value.
Definition array.cpp:134
Class to represent a coefficient evaluated at quadrature points.
void SetConstant(real_t constant)
Set this vector to the given constant.
void Project(Coefficient &coeff)
Evaluate the given Coefficient at the quadrature points defined by qs.
int GetVDim() const
Return the number of values per quadrature point.
void ProjectTranspose(MatrixCoefficient &coeff)
Project the transpose of coeff.
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:302
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition device.hpp:271
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:165
Array< real_t > B
Basis functions evaluated at quadrature points.
Definition fe_base.hpp:201
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:186
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:190
Array< real_t > Bt
Transpose of B.
Definition fe_base.hpp:207
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
Abstract class for all finite elements.
Definition fe_base.hpp:294
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:414
int GetDerivType() const
Returns the FiniteElement::DerivType of the element describing the spatial derivative method implemen...
Definition fe_base.hpp:441
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:381
DerivType
Enumeration for DerivType: defines which derivative method is implemented.
Definition fe_base.hpp:363
@ DIV
Implements CalcDivShape methods.
Definition fe_base.hpp:366
@ CURL
Implements CalcCurlShape methods.
Definition fe_base.hpp:367
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:3158
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:98
const IntegrationRule * IntRule
static const IntegrationRule & GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe, const ElementTransformation &Trans, const bool stroud=false)
Mesh data type.
Definition mesh.hpp:67
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:394
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:958
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:164
Base class for symmetric matrix coefficients that optionally depend on time and space.
Base class for vector Coefficients that optionally depend on time and space.
void AddMultPA(const Vector &x, Vector &y) const override
Method for partially assembled action.
void AssembleDiagonalPA(Vector &diag) override
Assemble diagonal and add it to Vector diag.
FiniteElement::DerivType trial_fetype
void AddAbsMultPA(const Vector &x, Vector &y) const override
void(*)(const int NE, bool symmetric, const bool scalar_coeff, const Array< real_t > &trialBO, const Array< real_t > &trialBC, const Array< real_t > &testBOt, const Array< real_t > &testBCt, const Vector &pa_data, const Vector &x, Vector &y, const int triald1d, const int testd1d, const int q1d) ApplyKernelType
const DofToQuad * mapsO
Not owned. DOF-to-quad map, open.
const DofToQuad * mapsOtest
Not owned. DOF-to-quad map, open.
void AssemblePA(const FiniteElementSpace &fes) override
Method defining partial assembly.
FiniteElement::DerivType test_fetype
bool symmetric
False if using a nonsymmetric matrix coefficient.
void AddMultTransposePA(const Vector &x, Vector &y) const override
Method for partially assembled transposed action.
DiagonalMatrixCoefficient * DQ
const DofToQuad * mapsCtest
Not owned. DOF-to-quad map, closed.
const GeometricFactors * geom
Not owned.
const DofToQuad * mapsC
Not owned. DOF-to-quad map, closed.
const DofToQuad & GetDofToQuadOpen(const IntegrationRule &ir, DofToQuad::Mode mode) const
Definition fe_base.hpp:1442
const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const override
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.hpp:1434
Vector data type.
Definition vector.hpp:82
void Abs()
(*this)(i) = abs((*this)(i))
Definition vector.cpp:392
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
int dim
Definition ex24.cpp:53
@ SYMMETRIC
Store the triangular part of symmetric matrices.
@ DEVICE_MASK
Biwise-OR of all device backends.
Definition device.hpp:104