39 vdim = vector_dimension;
54 vdim = vector_dimension;
88 vdim = (vdim == -1) ? fes.
GetVDim() : vdim;
89 MFEM_VERIFY(vdim == fes.
GetVDim(),
"vdim != fes.GetVDim()");
98 const int nq = ir->GetNPoints();
105 if (!(
dim == 2 ||
dim == 3)) { MFEM_ABORT(
"Dimension not supported."); }
117 MFEM_VERIFY(
VQ->
GetVDim() == vdim,
"VQ vdim vs. vdim error");
122 MFEM_VERIFY(
MQ->
GetVDim() == vdim,
"MQ dimension vs. vdim error");
123 MFEM_VERIFY(coeff.
Size() == (vdim*vdim) *
ne * nq,
"MQ size error");
130 const bool matrix_coeff =
coeff_vdim == vdim * vdim;
131 MFEM_VERIFY(scalar_coeff + vector_coeff + matrix_coeff == 1,
"");
133 const int pa_size =
dim *
dim;
138 MFEM_VERIFY(scalar_coeff,
"");
140 const auto W =
Reshape(ir->GetWeights().Read(), q1d, q1d);
144 vdim * (matrix_coeff ?
dim : 1),
ne);
148 MFEM_FOREACH_THREAD(qy, y, q1d)
150 MFEM_FOREACH_THREAD(qx, x, q1d)
152 for (
int i = 0; i < nc; ++i)
154 const real_t wq = W(qx, qy);
155 const real_t J11 = J(qx, qy, 0, 0, e);
156 const real_t J21 = J(qx, qy, 1, 0, e);
157 const real_t J31 = J(qx, qy, 2, 0, e);
158 const real_t J12 = J(qx, qy, 0, 1, e);
159 const real_t J22 = J(qx, qy, 1, 1, e);
160 const real_t J32 = J(qx, qy, 2, 1, e);
161 const real_t E = J11*J11 + J21*J21 + J31*J31;
162 const real_t G = J12*J12 + J22*J22 + J32*J32;
163 const real_t F = J11*J12 + J21*J22 + J31*J32;
164 const real_t iw = 1.0 / sqrt(E*G - F*F);
165 const auto C0 = C(0, qx, qy, e);
167 D(qx, qy, 0, i, e) =
alpha * G;
168 D(qx, qy, 1, i, e) = -
alpha * F;
169 D(qx, qy, 2, i, e) = -
alpha * F;
170 D(qx, qy, 3, i, e) =
alpha * E;
176 else if (
dim == 2 &&
sdim == 2)
179 const auto W =
Reshape(ir->GetWeights().Read(), q1d, q1d);
183 vdim * (matrix_coeff ?
dim : 1),
ne);
186 MFEM_FOREACH_THREAD(qy, y, q1d)
188 MFEM_FOREACH_THREAD(qx, x, q1d)
190 const real_t J11 = J(qx, qy, 0, 0, e);
191 const real_t J21 = J(qx, qy, 1, 0, e);
192 const real_t J12 = J(qx, qy, 0, 1, e);
193 const real_t J22 = J(qx, qy, 1, 1, e);
194 const real_t w_detJ = W(qx, qy) / ((J11*J22)-(J21*J12));
195 const real_t D0 = w_detJ * (J12*J12 + J22*J22);
196 const real_t D1 = -w_detJ * (J12*J11 + J22*J21);
197 const real_t D2 = w_detJ * (J11*J11 + J21*J21);
198 const int map[4] = {0, 2, 1, 3};
200 for (
int i = 0; i < (matrix_coeff ? cvdim : nc); ++i)
202 const auto k = matrix_coeff ? map[i] : (vector_coeff ? i : 0);
203 const auto Cc = C(k, qx, qy, e);
204 DE(qx, qy, 0, i, e) = D0 * Cc;
205 DE(qx, qy, 1, i, e) = D1 * Cc;
206 DE(qx, qy, 2, i, e) = D1 * Cc;
207 DE(qx, qy, 3, i, e) = D2 * Cc;
213 else if (
dim == 3 &&
sdim == 3)
216 const auto W =
Reshape(ir->GetWeights().Read(), q1d, q1d, q1d);
220 vdim * (matrix_coeff ?
dim : 1),
ne);
224 MFEM_FOREACH_THREAD(qz, z, q1d)
226 MFEM_FOREACH_THREAD(qy, y, q1d)
228 MFEM_FOREACH_THREAD(qx, x, q1d)
230 const real_t J11 = J(qx, qy, qz, 0, 0, e);
231 const real_t J21 = J(qx, qy, qz, 1, 0, e);
232 const real_t J31 = J(qx, qy, qz, 2, 0, e);
233 const real_t J12 = J(qx, qy, qz, 0, 1, e);
234 const real_t J22 = J(qx, qy, qz, 1, 1, e);
235 const real_t J32 = J(qx, qy, qz, 2, 1, e);
236 const real_t J13 = J(qx, qy, qz, 0, 2, e);
237 const real_t J23 = J(qx, qy, qz, 1, 2, e);
238 const real_t J33 = J(qx, qy, qz, 2, 2, e);
239 const real_t detJ = J11 * (J22 * J33 - J32 * J23) -
240 J21 * (J12 * J33 - J32 * J13) +
241 J31 * (J12 * J23 - J22 * J13);
242 const real_t c_detJ = W(qx, qy, qz) / detJ;
244 const real_t A11 = (J22 * J33) - (J23 * J32);
245 const real_t A12 = (J32 * J13) - (J12 * J33);
246 const real_t A13 = (J12 * J23) - (J22 * J13);
247 const real_t A21 = (J31 * J23) - (J21 * J33);
248 const real_t A22 = (J11 * J33) - (J13 * J31);
249 const real_t A23 = (J21 * J13) - (J11 * J23);
250 const real_t A31 = (J21 * J32) - (J31 * J22);
251 const real_t A32 = (J31 * J12) - (J11 * J32);
252 const real_t A33 = (J11 * J22) - (J12 * J21);
254 const real_t D11 = c_detJ * (A11*A11 + A12*A12 + A13*A13);
255 const real_t D21 = c_detJ * (A11*A21 + A12*A22 + A13*A23);
256 const real_t D31 = c_detJ * (A11*A31 + A12*A32 + A13*A33);
257 const real_t D22 = c_detJ * (A21*A21 + A22*A22 + A23*A23);
258 const real_t D32 = c_detJ * (A21*A31 + A22*A32 + A23*A33);
259 const real_t D33 = c_detJ * (A31*A31 + A32*A32 + A33*A33);
260 const int map[9] = {0, 3, 6, 1, 4, 7, 2, 5, 8};
262 for (
int i = 0; i < (matrix_coeff ? cvdim : nc); ++i)
264 const auto k = matrix_coeff ? map[i] : vector_coeff ? i : 0;
265 const auto Ck = C(k, qx, qy, qz, e);
266 DE(qx, qy, qz, 0, i, e) = D11 * Ck;
267 DE(qx, qy, qz, 1, i, e) = D21 * Ck;
268 DE(qx, qy, qz, 2, i, e) = D31 * Ck;
269 DE(qx, qy, qz, 3, i, e) = D22 * Ck;
270 DE(qx, qy, qz, 4, i, e) = D32 * Ck;
271 DE(qx, qy, qz, 5, i, e) = D33 * Ck;
280 MFEM_ABORT(
"Unknown VectorDiffusionIntegrator::AssemblePA kernel for"
281 <<
" dim:" <<
dim <<
", vdim:" << vdim <<
", sdim:" <<
sdim);
292 static const auto vector_diffusion_kernel_specializations =
295 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 2,2>::Add(),
296 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 3,3>::Add(),
297 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 4,4>::Add(),
298 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 5,5>::Add(),
299 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 6,6>::Add(),
300 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 7,7>::Add(),
301 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 8,8>::Add(),
302 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,2, 9,9>::Add(),
304 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,3, 2,2>::Add(),
305 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,3, 3,3>::Add(),
306 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,3, 4,4>::Add(),
307 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<2,3, 5,5>::Add(),
309 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 2,2>::Add(),
310 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 2,3>::Add(),
311 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 3,4>::Add(),
312 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 4,5>::Add(),
313 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 4,6>::Add(),
314 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 5,6>::Add(),
315 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 5,8>::Add(),
316 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 6,7>::Add(),
317 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 7,8>::Add(),
318 VectorDiffusionIntegrator::ApplyPAKernels::Specialization<3,3, 8,9>::Add(),
320 MFEM_CONTRACT_VAR(vector_diffusion_kernel_specializations);
328template<
int T_D1D = 0,
int T_Q1D = 0>
329static void PAVectorDiffusionDiagonal2D(
const int NE,
337 const int D1D = T_D1D ? T_D1D : d1d;
338 const int Q1D = T_Q1D ? T_Q1D : q1d;
342 const auto B =
Reshape(
b.Read(), Q1D, D1D);
346 MFEM_VERIFY(d.
Size() == Q1D*Q1D*4*2*NE,
"");
347 const auto D =
Reshape(d.
Read(), Q1D*Q1D, 4, 2, NE);
352 const int D1D = T_D1D ? T_D1D : d1d;
353 const int Q1D = T_Q1D ? T_Q1D : q1d;
354 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
355 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
360 for (
int qx = 0; qx < Q1D; ++qx)
362 for (
int dy = 0; dy < D1D; ++dy)
367 for (
int qy = 0; qy < Q1D; ++qy)
369 const int q = qx + qy * Q1D;
370 const real_t D0 = D(q,0,0,e);
371 const real_t D1 = D(q,1,0,e);
372 const real_t D2 = D(q,3,0,e);
373 QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D0;
374 QD1[qx][dy] += B(qy, dy) * G(qy, dy) * D1;
375 QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D2;
379 for (
int dy = 0; dy < D1D; ++dy)
381 for (
int dx = 0; dx < D1D; ++dx)
384 for (
int qx = 0; qx < Q1D; ++qx)
386 temp += G(qx, dx) * G(qx, dx) * QD0[qx][dy];
387 temp += G(qx, dx) * B(qx, dx) * QD1[qx][dy];
388 temp += B(qx, dx) * G(qx, dx) * QD1[qx][dy];
389 temp += B(qx, dx) * B(qx, dx) * QD2[qx][dy];
391 Y(dx,dy,0,e) += temp;
392 Y(dx,dy,1,e) += temp;
398template<
int T_D1D = 0,
int T_Q1D = 0>
399static void PAVectorDiffusionDiagonal3D(
const int NE,
400 const Array<real_t> &
b,
401 const Array<real_t> &g,
407 constexpr int DIM = 3;
408 const int D1D = T_D1D ? T_D1D : d1d;
409 const int Q1D = T_Q1D ? T_Q1D : q1d;
412 MFEM_VERIFY(D1D <= max_d1d,
"");
413 MFEM_VERIFY(Q1D <= max_q1d,
"");
414 auto B =
Reshape(
b.Read(), Q1D, D1D);
415 auto G =
Reshape(g.Read(), Q1D, D1D);
416 MFEM_VERIFY(d.Size() == Q1D*Q1D*Q1D*9*3*NE,
"");
417 auto Q =
Reshape(d.Read(), Q1D*Q1D*Q1D, 9, 3, NE);
418 auto Y =
Reshape(y.ReadWrite(), D1D, D1D, D1D, 3, NE);
421 const int D1D = T_D1D ? T_D1D : d1d;
422 const int Q1D = T_Q1D ? T_Q1D : q1d;
423 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
424 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
425 real_t QQD[MQ1][MQ1][MD1];
426 real_t QDD[MQ1][MD1][MD1];
427 for (
int i = 0; i <
DIM; ++i)
429 for (
int j = 0; j <
DIM; ++j)
432 for (
int qx = 0; qx < Q1D; ++qx)
434 for (
int qy = 0; qy < Q1D; ++qy)
436 for (
int dz = 0; dz < D1D; ++dz)
438 QQD[qx][qy][dz] = 0.0;
439 for (
int qz = 0; qz < Q1D; ++qz)
441 const int q = qx + (qy + qz * Q1D) * Q1D;
442 const int k = j >= i ?
443 3 - (3-i)*(2-i)/2 + j:
444 3 - (3-j)*(2-j)/2 + i;
446 const real_t O = Q(q,k,0,e);
447 const real_t Bz = B(qz,dz);
448 const real_t Gz = G(qz,dz);
449 const real_t L = i==2 ? Gz : Bz;
450 const real_t R = j==2 ? Gz : Bz;
451 QQD[qx][qy][dz] += L * O * R;
457 for (
int qx = 0; qx < Q1D; ++qx)
459 for (
int dz = 0; dz < D1D; ++dz)
461 for (
int dy = 0; dy < D1D; ++dy)
463 QDD[qx][dy][dz] = 0.0;
464 for (
int qy = 0; qy < Q1D; ++qy)
466 const real_t By = B(qy,dy);
467 const real_t Gy = G(qy,dy);
468 const real_t L = i==1 ? Gy : By;
469 const real_t R = j==1 ? Gy : By;
470 QDD[qx][dy][dz] += L * QQD[qx][qy][dz] * R;
476 for (
int dz = 0; dz < D1D; ++dz)
478 for (
int dy = 0; dy < D1D; ++dy)
480 for (
int dx = 0; dx < D1D; ++dx)
483 for (
int qx = 0; qx < Q1D; ++qx)
485 const real_t Bx = B(qx,dx);
486 const real_t Gx = G(qx,dx);
487 const real_t L = i==0 ? Gx : Bx;
488 const real_t R = j==0 ? Gx : Bx;
489 temp += L * QDD[qx][dy][dz] * R;
491 Y(dx, dy, dz, 0, e) += temp;
492 Y(dx, dy, dz, 1, e) += temp;
493 Y(dx, dy, dz, 2, e) += temp;
502static void PAVectorDiffusionAssembleDiagonal(
const int dim,
506 const Array<real_t> &B,
507 const Array<real_t> &G,
513 return PAVectorDiffusionDiagonal2D(NE, B, G, op, y, D1D, Q1D);
517 return PAVectorDiffusionDiagonal3D(NE, B, G, op, y, D1D, Q1D);
519 MFEM_ABORT(
"Dimension not implemented.");
530 MFEM_VERIFY(!
VQ && !
MQ,
"VQ and MQ not supported.");
561VectorDiffusionIntegrator::ApplyKernelType
562VectorDiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int, int)
564 if (DIM == 2) { return internal::PAVectorDiffusionApply2D; }
565 else if (DIM == 3) { return internal::PAVectorDiffusionApply3D; }
566 else { MFEM_ABORT(""); }
569VectorDiffusionIntegrator::Kernels::Kernels()
571 VectorDiffusionIntegrator::AddSpecialization<2, 3, 2, 2>();
572 VectorDiffusionIntegrator::AddSpecialization<2, 3, 3, 3>();
573 VectorDiffusionIntegrator::AddSpecialization<2, 3, 4, 4>();
574 VectorDiffusionIntegrator::AddSpecialization<2, 3, 5, 5>();
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
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 GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
static const IntegrationRule & GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe)
Array< real_t > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Array< real_t > B
Basis functions evaluated at quadrature points.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
int GetNE() const
Returns number of elements in the mesh.
Mesh * GetMesh() const
Returns the mesh.
int GetVDim() const
Returns the vector dimension of the finite element space.
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Abstract class for all finite elements.
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...
Vector J
Jacobians of the element transformations at all quadrature points.
Class for an integration rule - an Array of IntegrationPoint.
const IntegrationRule * IntRule
Base class for Matrix Coefficients that optionally depend on time and space.
int GetVDim() const
For backward compatibility get the width of the matrix.
int Dimension() const
Dimension of the reference space used within the elements.
int SpaceDimension() const
Dimension of the physical space containing the mesh.
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.
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Class representing the storage layout of a QuadratureFunction.
Base class for vector Coefficients that optionally depend on time and space.
int GetVDim()
Returns dimension of the vector.
void AssemblePA(const FiniteElementSpace &fes) override
Method defining partial assembly.
const DofToQuad * maps
Not owned.
VectorDiffusionIntegrator(const IntegrationRule *ir=nullptr)
void AddMultPA(const Vector &x, Vector &y) const override
Method for partially assembled action.
const GeometricFactors * geom
Not owned.
void AssembleDiagonalPA(Vector &diag) override
Assemble diagonal and add it to Vector diag.
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
void GetDiagonal(mfem::Vector &diag) const
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).
Represent a DiffusionIntegrator with AssemblyLevel::Partial using libCEED.
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
bool DeviceCanUseCeed()
Function that determines if a CEED kernel should be used, based on the current mfem::Device configura...
@ FULL
Store the coefficient as a full QuadratureFunction.
void forall_2D(int N, int X, int Y, lambda &&body)
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
MemoryType
Memory types supported by MFEM.
void forall(int N, lambda &&body)
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
int MAX_D1D
Maximum number of 1D nodal points.
int MAX_Q1D
Maximum number of 1D quadrature points.