MFEM v4.8.0
Finite element discretization library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
bilininteg_diffusion_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"
15#include "../../mesh/nurbs.hpp"
18
19namespace mfem
20{
21
23{
24 if (DeviceCanUseCeed())
25 {
26 ceedOp->GetDiagonal(diag);
27 }
28 else
29 {
30 if (pa_data.Size() == 0) { AssemblePA(*fespace); }
31 const Array<real_t> &B = maps->B;
32 const Array<real_t> &G = maps->G;
33 const Vector &Dv = pa_data;
34 DiagonalPAKernels::Run(dim, dofs1D, quad1D, ne, symmetric, B, G, Dv,
35 diag, dofs1D, quad1D);
36 }
37}
38
39// PA Diffusion Apply kernel
41{
42 if (DeviceCanUseCeed())
43 {
44 ceedOp->AddMult(x, y);
45 }
46 else
47 {
48 const Array<real_t> &B = maps->B;
49 const Array<real_t> &G = maps->G;
50 const Array<real_t> &Bt = maps->Bt;
51 const Array<real_t> &Gt = maps->Gt;
52 const Vector &Dv = pa_data;
53
54#ifdef MFEM_USE_OCCA
55 if (DeviceCanUseOcca())
56 {
57 if (dim == 2)
58 {
59 internal::OccaPADiffusionApply2D(dofs1D,quad1D,ne,B,G,Bt,Gt,Dv,x,y);
60 return;
61 }
62 if (dim == 3)
63 {
64 internal::OccaPADiffusionApply3D(dofs1D,quad1D,ne,B,G,Bt,Gt,Dv,x,y);
65 return;
66 }
67 MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
68 }
69#endif // MFEM_USE_OCCA
70
71 ApplyPAKernels::Run(dim, dofs1D, quad1D, ne, symmetric, B, G, Bt,
72 Gt, Dv, x, y, dofs1D, quad1D);
73 }
74}
75
77{
78 if (symmetric)
79 {
80 AddMultPA(x, y);
81 }
82 else
83 {
84 MFEM_ABORT("DiffusionIntegrator::AddMultTransposePA only implemented in "
85 "the symmetric case.")
86 }
87}
88
90{
91 const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
93 // Assuming the same element type
94 fespace = &fes;
95 Mesh *mesh = fes.GetMesh();
96 const FiniteElement &el = *fes.GetTypicalFE();
97 const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
98 if (DeviceCanUseCeed())
99 {
100 delete ceedOp;
101 MFEM_VERIFY(!VQ && !MQ,
102 "Only scalar coefficient supported for DiffusionIntegrator"
103 " with libCEED");
104 const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
105 fes.IsVariableOrder();
106 if (mixed)
107 {
108 ceedOp = new ceed::MixedPADiffusionIntegrator(*this, fes, Q);
109 }
110 else
111 {
112 ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
113 }
114 return;
115 }
116 const int dims = el.GetDim();
117 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
118 const int nq = ir->GetNPoints();
119 dim = mesh->Dimension();
120 ne = fes.GetNE();
122 const int sdim = mesh->SpaceDimension();
123 maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
124 dofs1D = maps->ndof;
125 quad1D = maps->nqpt;
126
127 QuadratureSpace qs(*mesh, *ir);
129
130 if (MQ) { coeff.ProjectTranspose(*MQ); }
131 else if (VQ) { coeff.Project(*VQ); }
132 else if (Q) { coeff.Project(*Q); }
133 else { coeff.SetConstant(1.0); }
134
135 const int coeff_dim = coeff.GetVDim();
136 symmetric = (coeff_dim != dims*dims);
137 const int pa_size = symmetric ? symmDims : dims*dims;
138
139 pa_data.SetSize(pa_size * nq * ne, mt);
140 internal::PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeff_dim, ne,
141 ir->GetWeights(), geom->J, coeff, pa_data);
142}
143
145{
146 fespace = &fes;
147 Mesh *mesh = fes.GetMesh();
148 dim = mesh->Dimension();
149 MFEM_VERIFY(3 == dim, "Only 3D so far");
150
151 numPatches = mesh->NURBSext->GetNP();
152 for (int p=0; p<numPatches; ++p)
153 {
154 AssemblePatchPA(p, fes);
155 }
156}
157
159 const FiniteElementSpace &fes)
160{
161 Mesh *mesh = fes.GetMesh();
162 SetupPatchBasisData(mesh, patch);
163
164 SetupPatchPA(patch, mesh); // For full quadrature, unitWeights = false
165}
166
167// This version uses full 1D quadrature rules, taking into account the
168// minimum interaction between basis functions and integration points.
169void DiffusionIntegrator::AddMultPatchPA(const int patch, const Vector &x,
170 Vector &y) const
171{
172 MFEM_VERIFY(3 == dim, "Only 3D so far");
173
174 const Array<int>& Q1D = pQ1D[patch];
175 const Array<int>& D1D = pD1D[patch];
176
177 const std::vector<Array2D<real_t>>& B = pB[patch];
178 const std::vector<Array2D<real_t>>& G = pG[patch];
179
180 const IntArrayVar2D& minD = pminD[patch];
181 const IntArrayVar2D& maxD = pmaxD[patch];
182 const IntArrayVar2D& minQ = pminQ[patch];
183 const IntArrayVar2D& maxQ = pmaxQ[patch];
184
185 auto X = Reshape(x.Read(), D1D[0], D1D[1], D1D[2]);
186 auto Y = Reshape(y.ReadWrite(), D1D[0], D1D[1], D1D[2]);
187
188 const auto qd = Reshape(pa_data.Read(), Q1D[0]*Q1D[1]*Q1D[2],
189 (symmetric ? 6 : 9));
190
191 // NOTE: the following is adapted from AssemblePatchMatrix_fullQuadrature
192 std::vector<Array3D<real_t>> grad(dim);
193 // TODO: Can an optimal order of dimensions be determined, for each patch?
194 Array3D<real_t> gradXY(3, std::max(Q1D[0], D1D[0]), std::max(Q1D[1], D1D[1]));
195 Array2D<real_t> gradX(3, std::max(Q1D[0], D1D[0]));
196
197 for (int d=0; d<dim; ++d)
198 {
199 grad[d].SetSize(Q1D[0], Q1D[1], Q1D[2]);
200
201 for (int qz = 0; qz < Q1D[2]; ++qz)
202 {
203 for (int qy = 0; qy < Q1D[1]; ++qy)
204 {
205 for (int qx = 0; qx < Q1D[0]; ++qx)
206 {
207 grad[d](qx,qy,qz) = 0.0;
208 }
209 }
210 }
211 }
212
213 for (int dz = 0; dz < D1D[2]; ++dz)
214 {
215 for (int qy = 0; qy < Q1D[1]; ++qy)
216 {
217 for (int qx = 0; qx < Q1D[0]; ++qx)
218 {
219 for (int d=0; d<dim; ++d)
220 {
221 gradXY(d,qx,qy) = 0.0;
222 }
223 }
224 }
225 for (int dy = 0; dy < D1D[1]; ++dy)
226 {
227 for (int qx = 0; qx < Q1D[0]; ++qx)
228 {
229 gradX(0,qx) = 0.0;
230 gradX(1,qx) = 0.0;
231 }
232 for (int dx = 0; dx < D1D[0]; ++dx)
233 {
234 const real_t s = X(dx,dy,dz);
235 for (int qx = minD[0][dx]; qx <= maxD[0][dx]; ++qx)
236 {
237 gradX(0,qx) += s * B[0](qx,dx);
238 gradX(1,qx) += s * G[0](qx,dx);
239 }
240 }
241 for (int qy = minD[1][dy]; qy <= maxD[1][dy]; ++qy)
242 {
243 const real_t wy = B[1](qy,dy);
244 const real_t wDy = G[1](qy,dy);
245 // This full range of qx values is generally necessary.
246 for (int qx = 0; qx < Q1D[0]; ++qx)
247 {
248 const real_t wx = gradX(0,qx);
249 const real_t wDx = gradX(1,qx);
250 gradXY(0,qx,qy) += wDx * wy;
251 gradXY(1,qx,qy) += wx * wDy;
252 gradXY(2,qx,qy) += wx * wy;
253 }
254 }
255 }
256 for (int qz = minD[2][dz]; qz <= maxD[2][dz]; ++qz)
257 {
258 const real_t wz = B[2](qz,dz);
259 const real_t wDz = G[2](qz,dz);
260 for (int qy = 0; qy < Q1D[1]; ++qy)
261 {
262 for (int qx = 0; qx < Q1D[0]; ++qx)
263 {
264 grad[0](qx,qy,qz) += gradXY(0,qx,qy) * wz;
265 grad[1](qx,qy,qz) += gradXY(1,qx,qy) * wz;
266 grad[2](qx,qy,qz) += gradXY(2,qx,qy) * wDz;
267 }
268 }
269 }
270 }
271
272 for (int qz = 0; qz < Q1D[2]; ++qz)
273 {
274 for (int qy = 0; qy < Q1D[1]; ++qy)
275 {
276 for (int qx = 0; qx < Q1D[0]; ++qx)
277 {
278 const int q = qx + ((qy + (qz * Q1D[1])) * Q1D[0]);
279 const real_t O00 = qd(q,0);
280 const real_t O01 = qd(q,1);
281 const real_t O02 = qd(q,2);
282 const real_t O10 = symmetric ? O01 : qd(q,3);
283 const real_t O11 = symmetric ? qd(q,3) : qd(q,4);
284 const real_t O12 = symmetric ? qd(q,4) : qd(q,5);
285 const real_t O20 = symmetric ? O02 : qd(q,6);
286 const real_t O21 = symmetric ? O12 : qd(q,7);
287 const real_t O22 = symmetric ? qd(q,5) : qd(q,8);
288
289 const real_t grad0 = grad[0](qx,qy,qz);
290 const real_t grad1 = grad[1](qx,qy,qz);
291 const real_t grad2 = grad[2](qx,qy,qz);
292
293 grad[0](qx,qy,qz) = (O00*grad0)+(O01*grad1)+(O02*grad2);
294 grad[1](qx,qy,qz) = (O10*grad0)+(O11*grad1)+(O12*grad2);
295 grad[2](qx,qy,qz) = (O20*grad0)+(O21*grad1)+(O22*grad2);
296 } // qx
297 } // qy
298 } // qz
299
300 for (int qz = 0; qz < Q1D[2]; ++qz)
301 {
302 for (int dy = 0; dy < D1D[1]; ++dy)
303 {
304 for (int dx = 0; dx < D1D[0]; ++dx)
305 {
306 for (int d=0; d<3; ++d)
307 {
308 gradXY(d,dx,dy) = 0.0;
309 }
310 }
311 }
312 for (int qy = 0; qy < Q1D[1]; ++qy)
313 {
314 for (int dx = 0; dx < D1D[0]; ++dx)
315 {
316 for (int d=0; d<3; ++d)
317 {
318 gradX(d,dx) = 0.0;
319 }
320 }
321 for (int qx = 0; qx < Q1D[0]; ++qx)
322 {
323 const real_t gX = grad[0](qx,qy,qz);
324 const real_t gY = grad[1](qx,qy,qz);
325 const real_t gZ = grad[2](qx,qy,qz);
326 for (int dx = minQ[0][qx]; dx <= maxQ[0][qx]; ++dx)
327 {
328 const real_t wx = B[0](qx,dx);
329 const real_t wDx = G[0](qx,dx);
330 gradX(0,dx) += gX * wDx;
331 gradX(1,dx) += gY * wx;
332 gradX(2,dx) += gZ * wx;
333 }
334 }
335 for (int dy = minQ[1][qy]; dy <= maxQ[1][qy]; ++dy)
336 {
337 const real_t wy = B[1](qy,dy);
338 const real_t wDy = G[1](qy,dy);
339 for (int dx = 0; dx < D1D[0]; ++dx)
340 {
341 gradXY(0,dx,dy) += gradX(0,dx) * wy;
342 gradXY(1,dx,dy) += gradX(1,dx) * wDy;
343 gradXY(2,dx,dy) += gradX(2,dx) * wy;
344 }
345 }
346 }
347 for (int dz = minQ[2][qz]; dz <= maxQ[2][qz]; ++dz)
348 {
349 const real_t wz = B[2](qz,dz);
350 const real_t wDz = G[2](qz,dz);
351 for (int dy = 0; dy < D1D[1]; ++dy)
352 {
353 for (int dx = 0; dx < D1D[0]; ++dx)
354 {
355 Y(dx,dy,dz) +=
356 ((gradXY(0,dx,dy) * wz) +
357 (gradXY(1,dx,dy) * wz) +
358 (gradXY(2,dx,dy) * wDz));
359 }
360 }
361 } // dz
362 } // qz
363}
364
366{
367 Vector xp, yp;
368
369 for (int p=0; p<numPatches; ++p)
370 {
371 Array<int> vdofs;
372 fespace->GetPatchVDofs(p, vdofs);
373
374 x.GetSubVector(vdofs, xp);
375 yp.SetSize(vdofs.Size());
376 yp = 0.0;
377
378 AddMultPatchPA(p, xp, yp);
379
380 y.AddElementVector(vdofs, yp);
381 }
382}
383
384} // namespace mfem
Dynamic 2D array using row-major layout.
Definition array.hpp:392
int Size() const
Return the logical size of the array.
Definition array.hpp:147
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 GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:274
static const IntegrationRule & GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe)
void AddMultNURBSPA(const Vector &, Vector &) const override
Method for partially assembled action on NURBS patches.
void AssemblePatchPA(const int patch, const FiniteElementSpace &fes)
MatrixCoefficient * MQ
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
void AssembleDiagonalPA(Vector &diag) override
Assemble diagonal and add it to Vector diag.
VectorCoefficient * VQ
void AddMultPatchPA(const int patch, const Vector &x, Vector &y) const
void AssembleNURBSPA(const FiniteElementSpace &fes) override
Method defining partial assembly on NURBS patches.
void AssemblePA(const FiniteElementSpace &fes) override
Method defining partial assembly.
void AddMultTransposePA(const Vector &, Vector &) const override
Method for partially assembled transposed action.
Array< real_t > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
Definition fe_base.hpp:214
@ 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
Array< real_t > Gt
Transpose of G.
Definition fe_base.hpp:221
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:244
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:709
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:891
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:679
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:3871
void GetPatchVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom in vdofs for NURBS patch i.
Definition fespace.cpp:355
Abstract class for all finite elements.
Definition fe_base.hpp:244
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:365
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:321
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:2976
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
Mesh data type.
Definition mesh.hpp:64
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:298
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1219
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:880
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:7243
int GetNP() const
Return the number of patches.
Definition nurbs.hpp:745
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:120
Vector data type.
Definition vector.hpp:82
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:494
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:510
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:745
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:653
void GetDiagonal(mfem::Vector &diag) const
Definition operator.cpp:104
void AddMult(const mfem::Vector &x, mfem::Vector &y, const real_t a=1.0) const override
Operator application: y+=A(x) (default) or y+=a*A(x).
Definition operator.cpp:72
Represent a DiffusionIntegrator with AssemblyLevel::Partial using libCEED.
Definition diffusion.hpp:27
int dim
Definition ex24.cpp:53
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
bool DeviceCanUseCeed()
Function that determines if a CEED kernel should be used, based on the current mfem::Device configura...
Definition util.cpp:33
@ COMPRESSED
Enable all above compressions.
bool DeviceCanUseOcca()
Function that determines if an OCCA kernel should be used, based on the current mfem::Device configur...
Definition occa.hpp:69
float real_t
Definition config.hpp:43
MemoryType
Memory types supported by MFEM.
real_t p(const Vector &x, real_t t)