12#ifndef MFEM_DGMASSINV_KERNELS_HPP
13#define MFEM_DGMASSINV_KERNELS_HPP
26template <
int DIM,
int D1D,
int Q1D>
27MFEM_HOST_DEVICE
inline
28void DGMassApply(
const int e,
38 constexpr bool use_smem = (D1D > 0 && Q1D > 0);
39 constexpr bool ACCUM =
false;
40 constexpr int NBZ = 1;
44 PAMassApply1D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
52 constexpr int TD1D = D1D ? D1D : 1;
53 constexpr int TQ1D = Q1D ? Q1D : 1;
56 SmemPAMassApply2D_Element<TD1D,TQ1D,NBZ,ACCUM>(e, NE, B, pa_data, x, y);
60 SmemPAMassApply3D_Element<TD1D,TQ1D,NBZ,ACCUM>(e, NE, B, pa_data, x, y);
64 MFEM_ABORT_KERNEL(
"Unsupported dimension.");
71 PAMassApply2D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
75 PAMassApply3D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
79 MFEM_ABORT_KERNEL(
"Unsupported dimension.");
84MFEM_HOST_DEVICE
inline
85void DGMassPreconditioner(
const int e,
96 const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
97 const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
99 for (
int i = tid; i < ND; i += bxy)
101 Y(i, e) = D(i, e)*X(i, e);
106MFEM_HOST_DEVICE
inline
107void DGMassAxpy(
const int e,
120 const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
121 const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
123 for (
int i = tid; i < ND; i += bxy)
125 Z(i, e) =
a*X(i, e) +
b*Y(i, e);
131MFEM_HOST_DEVICE
inline
132real_t DGMassDot(
const int e,
141 const int tid = MFEM_THREAD_ID(x) + MFEM_THREAD_SIZE(x)*MFEM_THREAD_ID(y);
142 const int bxy = MFEM_THREAD_SIZE(x)*MFEM_THREAD_SIZE(y);
144 MFEM_SHARED
real_t s_dot[NB*NB];
147 for (
int i = tid; i < ND; i += bxy) { s_dot[tid] += X(i,e)*Y(i,e); }
150 if (bxy > 512 && tid + 512 < bxy) { s_dot[tid] += s_dot[tid + 512]; }
153 if (bxy > 256 && tid < 256 && tid + 256 < bxy) { s_dot[tid] += s_dot[tid + 256]; }
156 if (bxy > 128 && tid < 128 && tid + 128 < bxy) { s_dot[tid] += s_dot[tid + 128]; }
159 if (bxy > 64 && tid < 64 && tid + 64 < bxy) { s_dot[tid] += s_dot[tid + 64]; }
162 if (bxy > 32 && tid < 32 && tid + 32 < bxy) { s_dot[tid] += s_dot[tid + 32]; }
165 if (bxy > 16 && tid < 16 && tid + 16 < bxy) { s_dot[tid] += s_dot[tid + 16]; }
168 if (bxy > 8 && tid < 8 && tid + 8 < bxy) { s_dot[tid] += s_dot[tid + 8]; }
171 if (bxy > 4 && tid < 4 && tid + 4 < bxy) { s_dot[tid] += s_dot[tid + 4]; }
174 if (bxy > 2 && tid < 2 && tid + 2 < bxy) { s_dot[tid] += s_dot[tid + 2]; }
177 if (bxy > 1 && tid < 1 && tid + 1 < bxy) { s_dot[tid] += s_dot[tid + 1]; }
183template<
int T_D1D = 0>
184MFEM_HOST_DEVICE
inline
185void DGMassBasis1D(
const int e,
192 const int D1D = T_D1D ? T_D1D : d1d;
194 const auto b =
Reshape(b_, D1D, D1D);
195 const auto x =
Reshape(x_, D1D, NE);
198 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
201 MFEM_FOREACH_THREAD(i,x,D1D)
204 for (
int j = 0; j < D1D; ++j)
206 val +=
b(i,j)*x(j,e);
211 if (MFEM_THREAD_ID(y) == 0)
213 MFEM_FOREACH_THREAD(i,x,D1D)
220template<
int T_D1D = 0>
221MFEM_HOST_DEVICE
inline
222void DGMassBasis2D(
const int e,
229 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
230 const int D1D = T_D1D ? T_D1D : d1d;
232 const auto b =
Reshape(b_, D1D, D1D);
233 const auto x =
Reshape(x_, D1D, D1D, NE);
234 auto y =
Reshape(y_, D1D, D1D, NE);
236 MFEM_SHARED
real_t sB[MD1*MD1];
237 MFEM_SHARED
real_t sm0[MD1*MD1];
238 MFEM_SHARED
real_t sm1[MD1*MD1];
240 kernels::internal::LoadB<MD1,MD1>(D1D,D1D,
b,sB);
247 kernels::internal::LoadX(e,D1D,x,DD);
248 kernels::internal::EvalX(D1D,D1D,B,DD,DQ);
249 kernels::internal::EvalY(D1D,D1D,B,DQ,QQ);
251 MFEM_FOREACH_THREAD(qy,y,D1D)
253 MFEM_FOREACH_THREAD(qx,x,D1D)
255 y(qx,qy,e) = QQ(qx,qy);
261template<
int T_D1D = 0>
262MFEM_HOST_DEVICE
inline
263void DGMassBasis3D(
const int e,
270 const int D1D = T_D1D ? T_D1D : d1d;
272 const auto b =
Reshape(b_, D1D, D1D);
273 const auto x =
Reshape(x_, D1D, D1D, D1D, NE);
274 auto y =
Reshape(y_, D1D, D1D, D1D, NE);
276 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
278 MFEM_SHARED
real_t sB[MD1*MD1];
279 MFEM_SHARED
real_t sm0[MD1*MD1*MD1];
280 MFEM_SHARED
real_t sm1[MD1*MD1*MD1];
282 kernels::internal::LoadB<MD1,MD1>(D1D,D1D,
b,sB);
290 kernels::internal::LoadX(e,D1D,x,DDD);
291 kernels::internal::EvalX(D1D,D1D,B,DDD,DDQ);
292 kernels::internal::EvalY(D1D,D1D,B,DDQ,DQQ);
293 kernels::internal::EvalZ(D1D,D1D,B,DQQ,QQQ);
295 MFEM_FOREACH_THREAD(qz,z,D1D)
297 MFEM_FOREACH_THREAD(qy,y,D1D)
299 for (
int qx = 0; qx < D1D; ++qx)
301 y(qx,qy,qz,e) = QQQ(qz,qy,qx);
308template<
int DIM,
int T_D1D = 0>
309MFEM_HOST_DEVICE
inline
310void DGMassBasis(
const int e,
319 DGMassBasis1D<T_D1D>(e, NE, b_, x_, y_, d1d);
323 DGMassBasis2D<T_D1D>(e, NE, b_, x_, y_, d1d);
327 DGMassBasis3D<T_D1D>(e, NE, b_, x_, y_, d1d);
331 MFEM_ABORT_KERNEL(
"Dimension not supported.");
337template<
int DIM,
int D1D,
int Q1D>
340 using namespace internal;
346 const int ND =
static_cast<int>(pow(d1d,
DIM));
361 const bool CHANGE_BASIS = (
d2q !=
nullptr);
369 const real_t *b_orig =
nullptr;
370 const real_t *d2q_B =
nullptr;
371 const real_t *q2d_B =
nullptr;
372 const real_t *q2d_Bt =
nullptr;
388 static constexpr int NB = Q1D ? Q1D : 1;
396 DGMassBasis<DIM,D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
400 DGMassBasis<DIM,D1D>(e, NE, d2q_B,
u,
u, d1d);
404 const int tid = MFEM_THREAD_ID(x) + NB*MFEM_THREAD_ID(y);
409 DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data,
u, r, d1d, q1d);
410 DGMassAxpy(e, NE, ND, 1.0,
b, -1.0, r, r);
415 const int BX = MFEM_THREAD_SIZE(x);
416 const int BY = MFEM_THREAD_SIZE(y);
417 const int bxy = BX*BY;
421 for (
int i = tid; i < ND; i += bxy)
429 DGMassPreconditioner(e, NE, ND, dinv, r, z);
430 DGMassAxpy(e, NE, ND, 1.0, z, 0.0, z, d);
432 real_t nom = DGMassDot<NB>(e, NE, ND, d, r);
433 if (nom < 0.0) {
return; }
434 real_t r0 = fmax(nom*RELTOL*RELTOL, ABSTOL*ABSTOL);
435 if (nom <= r0) {
return; }
437 DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data, d, z, d1d, q1d);
438 real_t den = DGMassDot<NB>(e, NE, ND, z, d);
441 DGMassDot<NB>(e, NE, ND, d, d);
443 if (den == 0.0) {
return; }
451 DGMassAxpy(e, NE, ND, 1.0,
u,
alpha, d,
u);
452 DGMassAxpy(e, NE, ND, 1.0, r, -
alpha, z, r);
454 DGMassPreconditioner(e, NE, ND, dinv, r, z);
456 real_t betanom = DGMassDot<NB>(e, NE, ND, r, z);
457 if (betanom < 0.0) {
return; }
458 if (betanom <= r0) {
break; }
460 if (++i > MAXIT) {
break; }
462 const real_t beta = betanom/nom;
463 DGMassAxpy(e, NE, ND, 1.0, z, beta, d, d);
464 DGMassApply<DIM,D1D,Q1D>(e, NE, B, Bt, pa_data, d, z, d1d, q1d);
465 den = DGMassDot<NB>(e, NE, ND, d, z);
468 DGMassDot<NB>(e, NE, ND, d, d);
470 if (den == 0.0) {
break; }
477 DGMassBasis<DIM,D1D>(e, NE, q2d_B,
u,
u, d1d);
484template <
int DIM,
int D1D,
int Q1D>
496 else { MFEM_ABORT(
"Unsupported dimension."); }
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Vector diag_inv
Jacobi preconditioner.
class MassIntegrator * m
Mass integrator, owned by the form M.
void(DGMassInverse::*)(const Vector &b_, Vector &u) const CGKernelType
real_t rel_tol
Relative CG tolerance.
int max_iter
Maximum number of CG iterations;.
Array< real_t > B_
Inverse of change of basis.
real_t abs_tol
Absolute CG tolerance.
Array< real_t > Bt_
Inverse of change of basis, transposed.
void DGMassCGIteration(const Vector &b_, Vector &u_) const
Solve the system M b = u. Not part of the public interface.
FiniteElementSpace fes
FE space in requested basis.
const DofToQuad * d2q
Change of basis. Not owned.
Array< real_t > B
Basis functions evaluated at quadrature points.
Array< real_t > Bt
Transpose of B.
int GetNE() const
Returns number of elements in the mesh.
const DofToQuad * maps
Not owned.
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
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).
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
DeviceTensor< 3, real_t > DeviceCube
real_t u(const Vector &xvec)
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
void forall_2D(int N, int X, int Y, lambda &&body)
DeviceTensor< 2, const real_t > ConstDeviceMatrix
DeviceTensor< 2, real_t > DeviceMatrix