MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_vectorfemass_pa.cpp
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#include "../bilininteg.hpp"
13#include "../gridfunc.hpp"
14#include "../qfunction.hpp"
19
20namespace mfem
21{
22
27
29 const FiniteElementSpace &test_fes)
30{
31 // Assumes tensor-product elements
32 Mesh *mesh = trial_fes.GetMesh();
33
34 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
35 const VectorTensorFiniteElement *trial_el =
36 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
37 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
38
39 const FiniteElement *test_fel = test_fes.GetTypicalFE();
40 const VectorTensorFiniteElement *test_el =
41 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
42 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
43
44 const IntegrationRule *ir
45 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
47 const int dims = trial_el->GetDim();
48 MFEM_VERIFY(dims == 2 || dims == 3, "");
49
50 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
51 nq = ir->GetNPoints();
52 dim = mesh->Dimension();
53 MFEM_VERIFY(dim == 2 || dim == 3, "");
54
55 ne = trial_fes.GetNE();
56 MFEM_VERIFY(ne == test_fes.GetNE(),
57 "Different meshes for test and trial spaces");
59 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
60 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
61 dofs1D = mapsC->ndof;
62 quad1D = mapsC->nqpt;
63
67
68 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
69
70 trial_fetype = trial_el->GetDerivType();
71 test_fetype = test_el->GetDerivType();
72
73 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
74 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
75 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
76 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
77
78 QuadratureSpace qs(*mesh, *ir);
80 if (Q) { coeff.Project(*Q); }
81 else if (MQ) { coeff.ProjectTranspose(*MQ); }
82 else if (DQ) { coeff.Project(*DQ); }
83 else { coeff.SetConstant(1.0); }
84
85 const int coeff_dim = coeff.GetVDim();
86 symmetric = (coeff_dim != dim*dim);
87
88 if ((trial_curl && test_div) || (trial_div && test_curl))
89 {
90 pa_data.SetSize((coeff_dim == 1 ? 1 : dim*dim) * nq * ne,
92 }
93 else
94 {
95 pa_data.SetSize((symmetric ? symmDims : dims*dims) * nq * ne,
97 }
98 if (trial_curl && test_curl && dim == 3)
99 {
100 internal::PADiffusionSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
101 coeff, pa_data);
102 }
103 else if (trial_curl && test_curl && dim == 2)
104 {
105 internal::PADiffusionSetup2D<2>(quad1D, coeff_dim, ne, ir->GetWeights(),
106 geom->J, coeff, pa_data);
107 }
108 else if (trial_div && test_div && dim == 3)
109 {
110 internal::PAHdivMassSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
111 coeff, pa_data);
112 }
113 else if (trial_div && test_div && dim == 2)
114 {
115 internal::PAHdivMassSetup2D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
116 coeff, pa_data);
117 }
118 else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
119 test_fel->GetOrder() == trial_fel->GetOrder())
120 {
121 if (coeff_dim == 1)
122 {
123 internal::PAHcurlL2Setup3D(nq, coeff_dim, ne, ir->GetWeights(), coeff, pa_data);
124 }
125 else
126 {
127 const bool tr = (trial_div && test_curl);
128 if (dim == 3)
129 {
130 internal::PAHcurlHdivMassSetup3D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
131 geom->J, coeff, pa_data);
132 }
133 else
134 {
135 internal::PAHcurlHdivMassSetup2D(quad1D, coeff_dim, ne, tr, ir->GetWeights(),
136 geom->J, coeff, pa_data);
137 }
138 }
139 }
140 else
141 {
142 MFEM_ABORT("Unknown kernel.");
143 }
144}
145
147{
148 if (dim == 3)
149 {
151 {
153 {
154 const int ID = (dofs1D << 4) | quad1D;
155 switch (ID)
156 {
157 case 0x23:
158 return internal::SmemPAHcurlMassAssembleDiagonal3D<2,3>(
160 mapsO->B, mapsC->B, pa_data, diag);
161 case 0x34:
162 return internal::SmemPAHcurlMassAssembleDiagonal3D<3,4>(
164 mapsO->B, mapsC->B, pa_data, diag);
165 case 0x45:
166 return internal::SmemPAHcurlMassAssembleDiagonal3D<4,5>(
168 mapsO->B, mapsC->B, pa_data, diag);
169 case 0x56:
170 return internal::SmemPAHcurlMassAssembleDiagonal3D<5,6>(
172 mapsO->B, mapsC->B, pa_data, diag);
173 default:
174 return internal::SmemPAHcurlMassAssembleDiagonal3D(
176 mapsO->B, mapsC->B, pa_data, diag);
177 }
178 }
179 else
180 {
181 internal::PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
182 mapsO->B, mapsC->B, pa_data, diag);
183 }
184 }
187 {
188 internal::PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
189 mapsO->B, mapsC->B, pa_data, diag);
190 }
191 else
192 {
193 MFEM_ABORT("Unknown kernel.");
194 }
195 }
196 else // 2D
197 {
199 {
200 internal::PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
201 mapsO->B, mapsC->B, pa_data, diag);
202 }
205 {
206 internal::PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
207 mapsO->B, mapsC->B, pa_data, diag);
208 }
209 else
210 {
211 MFEM_ABORT("Unknown kernel.");
212 }
213 }
214}
215
217{
218 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
219 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
220 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
221 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
222
223 if (dim == 3)
224 {
225 if (trial_curl && test_curl)
226 {
228 {
229 const int ID = (dofs1D << 4) | quad1D;
230 switch (ID)
231 {
232 case 0x23:
233 return internal::SmemPAHcurlMassApply3D<2,3>(
235 mapsO->B, mapsC->B, mapsO->Bt,
236 mapsC->Bt, pa_data, x, y);
237 case 0x34:
238 return internal::SmemPAHcurlMassApply3D<3,4>(
240 mapsO->B, mapsC->B, mapsO->Bt,
241 mapsC->Bt, pa_data, x, y);
242 case 0x45:
243 return internal::SmemPAHcurlMassApply3D<4,5>(
245 mapsO->B, mapsC->B, mapsO->Bt,
246 mapsC->Bt, pa_data, x, y);
247 case 0x56:
248 return internal::SmemPAHcurlMassApply3D<5,6>(
250 mapsO->B, mapsC->B, mapsO->Bt,
251 mapsC->Bt, pa_data, x, y);
252 default:
253 return internal::SmemPAHcurlMassApply3D(
255 mapsO->B, mapsC->B, mapsO->Bt,
256 mapsC->Bt, pa_data, x, y);
257 }
258 }
259 else
260 {
261 internal::PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
262 mapsO->Bt, mapsC->Bt, pa_data, x, y);
263 }
264 }
265 else if (trial_div && test_div)
266 {
267 internal::PAHdivMassApply(3, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
268 mapsO->Bt, mapsC->Bt, pa_data, x, y);
269 }
270 else if (trial_curl && test_div)
271 {
272 const bool scalarCoeff = !(DQ || MQ);
273 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
274 true, false, mapsO->B, mapsC->B, mapsOtest->Bt,
275 mapsCtest->Bt, pa_data, x, y);
276 }
277 else if (trial_div && test_curl)
278 {
279 const bool scalarCoeff = !(DQ || MQ);
280 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
281 false, false, mapsO->B, mapsC->B, mapsOtest->Bt,
282 mapsCtest->Bt, pa_data, x, y);
283 }
284 else
285 {
286 MFEM_ABORT("Unknown kernel.");
287 }
288 }
289 else // 2D
290 {
291 if (trial_curl && test_curl)
292 {
293 internal::PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
294 mapsO->Bt, mapsC->Bt, pa_data, x, y);
295 }
296 else if (trial_div && test_div)
297 {
298 internal::PAHdivMassApply(2, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
299 mapsO->Bt,
300 mapsC->Bt, pa_data, x, y);
301 }
302 else if ((trial_curl && test_div) || (trial_div && test_curl))
303 {
304 const bool scalarCoeff = !(DQ || MQ);
305 internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
306 trial_curl, false, mapsO->B, mapsC->B,
307 mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
308 }
309 else
310 {
311 MFEM_ABORT("Unknown kernel.");
312 }
313 }
314}
315
317{
318 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
319 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
320 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
321 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
322
323 Vector abs_pa_data(pa_data);
324 abs_pa_data.Abs();
325
326 Array<real_t> absBo(mapsO->B);
327 Array<real_t> absBc(mapsC->B);
328 Array<real_t> absBto(mapsO->Bt);
329 Array<real_t> absBtc(mapsC->Bt);
330 Array<real_t> absBto_t(mapsOtest->Bt);
331 Array<real_t> absBtc_t(mapsCtest->Bt);
332
333 absBo.Abs();
334 absBc.Abs();
335 absBto.Abs();
336 absBtc.Abs();
337 absBto_t.Abs();
338 absBtc_t.Abs();
339
340 if (dim == 3)
341 {
342 if (trial_curl && test_curl)
343 {
345 {
346 const int ID = (dofs1D << 4) | quad1D;
347 switch (ID)
348 {
349 case 0x23:
350 return internal::SmemPAHcurlMassApply3D<2,3>(
352 absBo, absBc, absBto, absBtc,
353 abs_pa_data, x, y);
354 case 0x34:
355 return internal::SmemPAHcurlMassApply3D<3,4>(
357 absBo, absBc, absBto, absBtc,
358 abs_pa_data, x, y);
359 case 0x45:
360 return internal::SmemPAHcurlMassApply3D<4,5>(
362 absBo, absBc, absBto, absBtc,
363 abs_pa_data, x, y);
364 case 0x56:
365 return internal::SmemPAHcurlMassApply3D<5,6>(
367 absBo, absBc, absBto, absBtc,
368 abs_pa_data, x, y);
369 default:
370 return internal::SmemPAHcurlMassApply3D(
372 absBo, absBc, absBto, absBtc,
373 abs_pa_data, x, y);
374 }
375 }
376 else
377 {
378 internal::PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric,
379 absBo, absBc, absBto, absBtc,
380 abs_pa_data, x, y);
381 }
382 }
383 else if (trial_div && test_div)
384 {
385 internal::PAHdivMassApply(3, dofs1D, quad1D, ne, symmetric,
386 absBo, absBc, absBto, absBtc,
387 abs_pa_data, x, y);
388 }
389 else if (trial_curl && test_div)
390 {
391 const bool scalarCoeff = !(DQ || MQ);
392 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne,
393 scalarCoeff, true, false,
394 absBo, absBc, absBto_t, absBtc_t,
395 abs_pa_data, x, y);
396 }
397 else if (trial_div && test_curl)
398 {
399 const bool scalarCoeff = !(DQ || MQ);
400 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne,
401 scalarCoeff, false, false,
402 absBo, absBc, absBto_t, absBtc_t,
403 abs_pa_data, x, y);
404 }
405 else
406 {
407 MFEM_ABORT("Unknown kernel.");
408 }
409 }
410 else // 2D
411 {
412 if (trial_curl && test_curl)
413 {
414 internal::PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric,
415 absBo, absBc, absBto, absBtc,
416 abs_pa_data, x, y);
417 }
418 else if (trial_div && test_div)
419 {
420 internal::PAHdivMassApply(2, dofs1D, quad1D, ne, symmetric,
421 absBo, absBc, absBto, absBtc,
422 abs_pa_data, x, y);
423 }
424 else if ((trial_curl && test_div) || (trial_div && test_curl))
425 {
426 const bool scalarCoeff = !(DQ || MQ);
427 internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne,
428 scalarCoeff, trial_curl, false,
429 absBo, absBc, absBto_t, absBtc_t,
430 abs_pa_data, x, y);
431 }
432 else
433 {
434 MFEM_ABORT("Unknown kernel.");
435 }
436 }
437}
438
440 Vector &y) const
441{
442 const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
443 const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
444 const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
445 const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
446
447 bool symmetricSpaces = true;
448 if (dim == 3 && ((trial_div && test_curl) || (trial_curl && test_div)))
449 {
450 const bool scalarCoeff = !(DQ || MQ);
451 internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
452 trial_div, true, mapsO->B, mapsC->B,
453 mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
454 symmetricSpaces = false;
455 }
456 else if (dim == 2 && ((trial_curl && test_div) || (trial_div && test_curl)))
457 {
458 const bool scalarCoeff = !(DQ || MQ);
459 internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
460 !trial_curl, true, mapsO->B, mapsC->B,
461 mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
462 symmetricSpaces = false;
463 }
464 if (symmetricSpaces)
465 {
466 if (MQ && dynamic_cast<SymmetricMatrixCoefficient*>(MQ) == NULL)
467 {
468 MFEM_ABORT("VectorFEMassIntegrator transpose not implemented for asymmetric MatrixCoefficient");
469 }
470 AddMultPA(x, y);
471 }
472}
473
474} // namespace mfem
void Abs()
Replace each entry of the array with its absolute value.
Definition array.cpp:115
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.
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:281
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:262
@ 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:193
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:178
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:182
Array< real_t > Bt
Transpose of B.
Definition fe_base.hpp:199
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:869
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
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:3860
Abstract class for all finite elements.
Definition fe_base.hpp:247
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:341
int GetDerivType() const
Returns the FiniteElement::DerivType of the element describing the spatial derivative method implemen...
Definition fe_base.hpp:368
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:324
@ DIV
Implements CalcDivShape methods.
Definition fe_base.hpp:309
@ CURL
Implements CalcCurlShape methods.
Definition fe_base.hpp:310
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:3115
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:86
const IntegrationRule * IntRule
static const IntegrationRule & GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe, const ElementTransformation &Trans)
Mesh data type.
Definition mesh.hpp:65
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:393
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:883
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.
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.
void AddAbsMultPA(const Vector &x, Vector &y) const override
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.
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:1365
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:1357
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:584
@ SYMMETRIC
Store the triangular part of symmetric matrices.
@ DEVICE_MASK
Biwise-OR of all device backends.
Definition device.hpp:99