Files
mfem/fem/kernels.hpp
T

1561 lines
48 KiB
C++

// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_FEM_KERNELS_HPP
#define MFEM_FEM_KERNELS_HPP
#include "../config/config.hpp"
#include "../linalg/dtensor.hpp"
namespace mfem
{
namespace kernels
{
// Experimental helper functions for MFEM_FORALL FEM kernels
// For the 2D functions, NBZ should be tied to '1' for now
namespace internal
{
/// Load B1d matrice into shared memory
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void LoadB(const int D1D, const int Q1D,
const ConstDeviceMatrix &b,
double (&sB)[MQ1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix B(sB, D1D, Q1D);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B(d,q) = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
}
/// Load Bt1d matrices into shared memory
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void LoadBt(const int D1D, const int Q1D,
const ConstDeviceMatrix &b,
double (&sB)[MQ1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix Bt(sB, Q1D, D1D);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bt(q,d) = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
}
/// Load B1d & G1d matrices into shared memory
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void LoadBG(const int D1D, const int Q1D,
const ConstDeviceMatrix &b,
const ConstDeviceMatrix &g,
double (&sBG)[2][MQ1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix B(sBG[0], D1D, Q1D);
DeviceMatrix G(sBG[1], D1D, Q1D);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B(d,q) = b(q,d);
G(d,q) = g(q,d);
}
}
}
MFEM_SYNC_THREAD;
}
/// Load Bt1d & Gt1d matrices into shared memory
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void LoadBGt(const int D1D, const int Q1D,
const ConstDeviceMatrix &b,
const ConstDeviceMatrix &g,
double (&sBG)[2][MQ1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix Bt(sBG[0], Q1D, D1D);
DeviceMatrix Gt(sBG[1], Q1D, D1D);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bt(q,d) = b(q,d);
Gt(q,d) = g(q,d);
}
}
}
MFEM_SYNC_THREAD;
}
/// Load 2D input scalar into given DeviceMatrix
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<3, const double> &x,
DeviceMatrix &DD)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
DD(dx,dy) = x(dx,dy,e);
}
}
MFEM_SYNC_THREAD;
}
/// Load 2D input scalar into shared memory
template<int MD1, int NBZ>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<3, const double> &x,
double (&sX)[NBZ][MD1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix X(sX[tidz], D1D, D1D);
LoadX(e, D1D, x, X);
}
/// Load 2D input scalar into shared memory, with comp
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D, const int c,
const DeviceTensor<4, const double> &x,
DeviceMatrix &DD)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
DD(dx,dy) = x(dx,dy,c,e);
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int NBZ>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D, const int c,
const DeviceTensor<4, const double> &x,
double (&sm)[NBZ][MD1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix DD(sm[tidz], D1D, D1D);
LoadX(e,D1D,c,x,DD);
}
/// 2D Scalar Evaluation, 1/2
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
ConstDeviceMatrix &B,
DeviceMatrix &DD,
DeviceMatrix &DQ)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
u += B(dx,qx) * DD(dx,dy);
}
DQ(dy,qx) = u;
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
double (&sDD)[NBZ][MD1*MD1],
double (&sDQ)[NBZ][MD1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sB, D1D, Q1D);
DeviceMatrix DD(sDD[tidz], D1D, D1D);
DeviceMatrix DQ(sDQ[tidz], D1D, Q1D);
EvalX(D1D,Q1D,B,DD,DQ);
}
/// 2D Scalar Evaluation, 2/2
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
ConstDeviceMatrix &B,
DeviceMatrix &DQ,
DeviceMatrix &QQ)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
u += DQ(dy,qx) * B(dy,qy);
}
QQ(qx,qy) = u;
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
double (&sDQ)[NBZ][MD1*MQ1],
double (&sQQ)[NBZ][MQ1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sB, D1D, Q1D);
DeviceMatrix DQ(sDQ[tidz], D1D, Q1D);
DeviceMatrix QQ(sQQ[tidz], Q1D, Q1D);
EvalY(D1D,Q1D,B,DQ,QQ);
}
/// Pull 2D Scalar Evaluation
MFEM_HOST_DEVICE inline void PullEval(const int qx, const int qy,
DeviceMatrix &QQ,
double &P)
{
P = QQ(qx,qy);
}
template<int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void PullEval(const int Q1D,
const int qx, const int qy,
double (&sQQ)[NBZ][MQ1*MQ1],
double &P)
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix QQ(sQQ[tidz], Q1D, Q1D);
PullEval(qx,qy,QQ,P);
}
/// Load 2D input vector into shared memory
template<int MD1, int NBZ>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<4, const double> &X,
double (&sX)[2][NBZ][MD1*MD1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix X0(sX[0][tidz], D1D, D1D);
DeviceMatrix X1(sX[1][tidz], D1D, D1D);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
X0(dx,dy) = X(dx,dy,0,e);
X1(dx,dy) = X(dx,dy,1,e);
}
}
MFEM_SYNC_THREAD;
}
/// 2D Evaluation, 1/2 (only B)
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sX)[2][NBZ][MD1*MD1],
double (&sDQ)[2][NBZ][MD1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sB, D1D, Q1D);
ConstDeviceMatrix X0(sX[0][tidz], D1D, D1D);
ConstDeviceMatrix X1(sX[1][tidz], D1D, D1D);
DeviceMatrix DQ0(sDQ[0][tidz], Q1D, D1D);
DeviceMatrix DQ1(sDQ[1][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[2] = {0.0, 0.0};
for (int dx = 0; dx < D1D; ++dx)
{
const double xx = X0(dx,dy);
const double xy = X1(dx,dy);
u[0] += B(dx,qx) * xx;
u[1] += B(dx,qx) * xy;
}
DQ0(qx,dy) = u[0];
DQ1(qx,dy) = u[1];
}
}
MFEM_SYNC_THREAD;
}
/// 2D Evaluation, 2/2 (only B)
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDQ)[2][NBZ][MD1*MQ1],
double (&sQQ)[2][NBZ][MQ1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sB, D1D, Q1D);
ConstDeviceMatrix DQ0(sDQ[0][tidz], Q1D, D1D);
ConstDeviceMatrix DQ1(sDQ[1][tidz], Q1D, D1D);
DeviceMatrix QQ0(sQQ[0][tidz], Q1D, Q1D);
DeviceMatrix QQ1(sQQ[1][tidz], Q1D, Q1D);
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[2] = {0.0, 0.0};
for (int dy = 0; dy < D1D; ++dy)
{
u[0] += DQ0(qx,dy) * B(dy,qy);
u[1] += DQ1(qx,dy) * B(dy,qy);
}
QQ0(qx,qy) = u[0];
QQ1(qx,qy) = u[1];
}
}
MFEM_SYNC_THREAD;
}
/// Pull 2D Evaluation
template<int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void PullEval(const int Q1D,
const int qx, const int qy,
const double (&sQQ)[2][NBZ][MQ1*MQ1],
double (&P)[2])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix QQ0(sQQ[0][tidz], Q1D, Q1D);
ConstDeviceMatrix QQ1(sQQ[1][tidz], Q1D, Q1D);
P[0] = QQ0(qx,qy);
P[1] = QQ1(qx,qy);
}
/// Push 2D Evaluation
template<int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void PushEval(const int Q1D,
const int qx, const int qy,
const double *P,
double (&sQQ)[2][NBZ][MQ1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix QQ0(sQQ[0][tidz], Q1D, Q1D);
DeviceMatrix QQ1(sQQ[1][tidz], Q1D, Q1D);
QQ0(qx,qy) = P[0];
QQ1(qx,qy) = P[1];
}
/// 2D Transposed evaluation, 1/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalXt(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sQQ)[2][NBZ][MQ1*MQ1],
double (&sDQ)[2][NBZ][MD1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix Bt(sB, Q1D, D1D);
ConstDeviceMatrix QQ0(sQQ[0][tidz], Q1D, Q1D);
ConstDeviceMatrix QQ1(sQQ[1][tidz], Q1D, Q1D);
DeviceMatrix DQ0(sDQ[0][tidz], Q1D, D1D);
DeviceMatrix DQ1(sDQ[1][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[2] = {0.0, 0.0};
for (int qx = 0; qx < Q1D; ++qx)
{
u[0] += QQ0(qx,qy) * Bt(qx,dx);
u[1] += QQ1(qx,qy) * Bt(qx,dx);
}
DQ0(qy,dx) = u[0];
DQ1(qy,dx) = u[1];
}
}
MFEM_SYNC_THREAD;
}
/// 2D Transposed evaluation, 2/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void EvalYt(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDQ)[2][NBZ][MD1*MQ1],
const DeviceTensor<4> &Y, // output
const int e)
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix Bt(sB, Q1D, D1D);
ConstDeviceMatrix DQ0(sDQ[0][tidz], Q1D, D1D);
ConstDeviceMatrix DQ1(sDQ[1][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[2] = {0.0, 0.0};
for (int qy = 0; qy < Q1D; ++qy)
{
u[0] += Bt(qy,dy) * DQ0(qy,dx);
u[1] += Bt(qy,dy) * DQ1(qy,dx);
}
Y(dx,dy,0,e) += u[0];
Y(dx,dy,1,e) += u[1];
}
}
MFEM_SYNC_THREAD;
}
/// 2D Gradient, 1/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void GradX(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&sX)[2][NBZ][MD1*MD1],
double (&sDQ)[4][NBZ][MD1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sBG[0], D1D, Q1D);
ConstDeviceMatrix G(sBG[1], D1D, Q1D);
ConstDeviceMatrix X0(sX[0][tidz], D1D, D1D);
ConstDeviceMatrix X1(sX[1][tidz], D1D, D1D);
DeviceMatrix X0B(sDQ[0][tidz], Q1D, D1D);
DeviceMatrix X0G(sDQ[1][tidz], Q1D, D1D);
DeviceMatrix X1B(sDQ[2][tidz], Q1D, D1D);
DeviceMatrix X1G(sDQ[3][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[2] = {0.0, 0.0};
double v[2] = {0.0, 0.0};
for (int dx = 0; dx < D1D; ++dx)
{
const double Bx = B(dx,qx);
const double Gx = G(dx,qx);
const double x0 = X0(dx,dy);
const double x1 = X1(dx,dy);
u[0] += Bx * x0;
v[0] += Gx * x0;
u[1] += Bx * x1;
v[1] += Gx * x1;
}
X0B(qx,dy) = u[0];
X0G(qx,dy) = v[0];
X1B(qx,dy) = u[1];
X1G(qx,dy) = v[1];
}
}
MFEM_SYNC_THREAD;
}
/// 2D Gradient, 2/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void GradY(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&sDQ)[4][NBZ][MD1*MQ1],
double (&sQQ)[4][NBZ][MQ1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix B(sBG[0], D1D, Q1D);
ConstDeviceMatrix G(sBG[1], D1D, Q1D);
ConstDeviceMatrix X0B(sDQ[0][tidz], Q1D, D1D);
ConstDeviceMatrix X0G(sDQ[1][tidz], Q1D, D1D);
ConstDeviceMatrix X1B(sDQ[2][tidz], Q1D, D1D);
ConstDeviceMatrix X1G(sDQ[3][tidz], Q1D, D1D);
DeviceMatrix X0GB(sQQ[0][tidz], Q1D, Q1D);
DeviceMatrix X0BG(sQQ[1][tidz], Q1D, Q1D);
DeviceMatrix X1GB(sQQ[2][tidz], Q1D, Q1D);
DeviceMatrix X1BG(sQQ[3][tidz], Q1D, Q1D);
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[2] = {0.0, 0.0};
double v[2] = {0.0, 0.0};
for (int dy = 0; dy < D1D; ++dy)
{
const double By = B(dy,qy);
const double Gy = G(dy,qy);
u[0] += X0G(qx,dy) * By;
v[0] += X0B(qx,dy) * Gy;
u[1] += X1G(qx,dy) * By;
v[1] += X1B(qx,dy) * Gy;
}
X0GB(qx,qy) = u[0];
X0BG(qx,qy) = v[0];
X1GB(qx,qy) = u[1];
X1BG(qx,qy) = v[1];
}
}
MFEM_SYNC_THREAD;
}
/// Pull 2D Gradient
template<int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void PullGrad(const int Q1D,
const int qx, const int qy,
const double (&sQQ)[4][NBZ][MQ1*MQ1],
double *Jpr)
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix X0GB(sQQ[0][tidz], Q1D, Q1D);
ConstDeviceMatrix X0BG(sQQ[1][tidz], Q1D, Q1D);
ConstDeviceMatrix X1GB(sQQ[2][tidz], Q1D, Q1D);
ConstDeviceMatrix X1BG(sQQ[3][tidz], Q1D, Q1D);
Jpr[0] = X0GB(qx,qy);
Jpr[1] = X1GB(qx,qy);
Jpr[2] = X0BG(qx,qy);
Jpr[3] = X1BG(qx,qy);
}
/// Push 2D Gradient
template<int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void PushGrad(const int Q1D,
const int qx, const int qy,
const double *A,
double (&sQQ)[4][NBZ][MQ1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
DeviceMatrix X0GB(sQQ[0][tidz], Q1D, Q1D);
DeviceMatrix X0BG(sQQ[1][tidz], Q1D, Q1D);
DeviceMatrix X1GB(sQQ[2][tidz], Q1D, Q1D);
DeviceMatrix X1BG(sQQ[3][tidz], Q1D, Q1D);
X0GB(qx,qy) = A[0];
X1GB(qx,qy) = A[2];
X0BG(qx,qy) = A[1];
X1BG(qx,qy) = A[3];
}
/// 2D Transposed gradient, 1/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void GradYt(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&GQ)[4][NBZ][MQ1*MQ1],
double (&GD)[4][NBZ][MD1*MQ1])
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix Bt(sBG[0], Q1D, D1D);
ConstDeviceMatrix Gt(sBG[1], Q1D, D1D);
ConstDeviceMatrix QQx0(GQ[0][tidz], Q1D, Q1D);
ConstDeviceMatrix QQx1(GQ[1][tidz], Q1D, Q1D);
ConstDeviceMatrix QQy0(GQ[2][tidz], Q1D, Q1D);
ConstDeviceMatrix QQy1(GQ[3][tidz], Q1D, Q1D);
DeviceMatrix DQxB(GD[0][tidz], Q1D, D1D);
DeviceMatrix DQxG(GD[1][tidz], Q1D, D1D);
DeviceMatrix DQyB(GD[2][tidz], Q1D, D1D);
DeviceMatrix DQyG(GD[3][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[2] = {0.0, 0.0};
double v[2] = {0.0, 0.0};
for (int qx = 0; qx < Q1D; ++qx)
{
u[0] += Gt(qx,dx) * QQx0(qx,qy);
u[1] += Gt(qx,dx) * QQy0(qx,qy);
v[0] += Bt(qx,dx) * QQx1(qx,qy);
v[1] += Bt(qx,dx) * QQy1(qx,qy);
}
DQxB(qy,dx) = u[0];
DQyB(qy,dx) = u[1];
DQxG(qy,dx) = v[0];
DQyG(qy,dx) = v[1];
}
}
MFEM_SYNC_THREAD;
}
/// 2D Transposed gradient, 2/2
template<int MD1, int MQ1, int NBZ>
MFEM_HOST_DEVICE inline void GradXt(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&GD)[4][NBZ][MD1*MQ1],
const DeviceTensor<4> &Y, // output
const int e)
{
const int tidz = MFEM_THREAD_ID(z);
ConstDeviceMatrix Bt(sBG[0], Q1D, D1D);
ConstDeviceMatrix Gt(sBG[1], Q1D, D1D);
ConstDeviceMatrix DQxB(GD[0][tidz], Q1D, D1D);
ConstDeviceMatrix DQxG(GD[1][tidz], Q1D, D1D);
ConstDeviceMatrix DQyB(GD[2][tidz], Q1D, D1D);
ConstDeviceMatrix DQyG(GD[3][tidz], Q1D, D1D);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[2] = {0.0, 0.0};
double v[2] = {0.0, 0.0};
for (int qy = 0; qy < Q1D; ++qy)
{
u[0] += DQxB(qy,dx) * Bt(qy,dy);
u[1] += DQyB(qy,dx) * Bt(qy,dy);
v[0] += DQxG(qy,dx) * Gt(qy,dy);
v[1] += DQyG(qy,dx) * Gt(qy,dy);
}
Y(dx,dy,0,e) += u[0] + v[0];
Y(dx,dy,1,e) += u[1] + v[1];
}
}
MFEM_SYNC_THREAD;
}
/// Load 3D scalar input vector into shared memory
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<4, const double> &x,
DeviceCube &X)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
X(dx,dy,dz) = x(dx,dy,dz,e);
}
}
}
MFEM_SYNC_THREAD;
}
template<int MD1>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<4, const double> &x,
double (&sm)[MD1*MD1*MD1])
{
DeviceCube X(sm, D1D,D1D,D1D);
LoadX(e,D1D,x,X);
}
/// Load 3D scalar input vector into shared memory, with comp & DeviceTensor
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D, const int c,
const DeviceTensor<5, const double> &x,
DeviceTensor<3> &X)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
X(dx,dy,dz) = x(dx,dy,dz,c,e);
}
}
}
MFEM_SYNC_THREAD;
}
/// Load 3D scalar input vector into shared memory, with comp & pointer
template<int MD1>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D, const int c,
const DeviceTensor<5, const double> &x,
double (&sm)[MD1*MD1*MD1])
{
DeviceCube X(sm, D1D, D1D, D1D);
return LoadX<MD1>(e,D1D,c,x,X);
}
/// 3D Scalar Evaluation, 1/3
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
ConstDeviceMatrix &B,
const DeviceCube &DDD,
DeviceCube &DDQ)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const double Bx = B(dx,qx);
u += Bx * DDD(dx,dy,dz);
}
DDQ(dz,dy,qx) = u;
}
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDDD)[MD1*MD1*MD1],
double (&sDDQ)[MD1*MD1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
const DeviceCube DDD(sDDD, D1D, D1D, D1D);
DeviceCube DDQ(sDDQ, Q1D, D1D, D1D);
EvalX(D1D,Q1D,B,DDD,DDQ);
}
/// 3D Scalar Evaluation, 2/3
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
ConstDeviceMatrix &B,
const DeviceCube &DDQ,
DeviceCube &DQQ)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
const double By = B(dy,qy);
u += DDQ(dz,dy,qx) * By;
}
DQQ(dz,qy,qx) = u;
}
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDDQ)[MD1*MD1*MQ1],
double (&sDQQ)[MD1*MQ1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
const DeviceCube DDQ(sDDQ, Q1D, D1D, D1D);
DeviceCube DQQ(sDQQ, Q1D, Q1D, D1D);
EvalY(D1D,Q1D,B,DDQ,DQQ);
}
/// 3D Scalar Evaluation, 3/3
MFEM_HOST_DEVICE inline void EvalZ(const int D1D, const int Q1D,
ConstDeviceMatrix &B,
const DeviceCube &DQQ,
DeviceCube &QQQ)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0;
for (int dz = 0; dz < D1D; ++dz)
{
const double Bz = B(dz,qz);
u += DQQ(dz,qy,qx) * Bz;
}
QQQ(qz,qy,qx) = u;
}
}
}
MFEM_SYNC_THREAD;
}
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalZ(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDQQ)[MD1*MQ1*MQ1],
double (&sQQQ)[MQ1*MQ1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
const DeviceCube DQQ(sDQQ, Q1D, Q1D, D1D);
DeviceCube QQQ(sQQQ, Q1D, Q1D, Q1D);
EvalZ(D1D,Q1D,B,DQQ,QQQ);
}
/// Pull 3D Scalar Evaluation
MFEM_HOST_DEVICE inline void PullEval(const int x, const int y, const int z,
const DeviceCube &QQQ,
double &X)
{
X = QQQ(z,y,x);
}
template<int MQ1>
MFEM_HOST_DEVICE inline void PullEval(const int Q1D,
const int x, const int y, const int z,
const double (&sQQQ)[MQ1*MQ1*MQ1],
double &X)
{
const DeviceCube QQQ(sQQQ, Q1D, Q1D, Q1D);
PullEval(x,y,z,QQQ,X);
}
/// Load 3D input vector into shared memory
template<int MD1>
MFEM_HOST_DEVICE inline void LoadX(const int e, const int D1D,
const DeviceTensor<5, const double> &X,
double (*sm)[MD1*MD1*MD1])
{
DeviceCube Xx(sm[0], D1D, D1D, D1D);
DeviceCube Xy(sm[1], D1D, D1D, D1D);
DeviceCube Xz(sm[2], D1D, D1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
Xx(dx,dy,dz) = X(dx,dy,dz,0,e);
Xy(dx,dy,dz) = X(dx,dy,dz,1,e);
Xz(dx,dy,dz) = X(dx,dy,dz,2,e);
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Vector Evaluation, 1/3 (only B)
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalX(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDDD)[3][MD1*MD1*MD1],
double (&sDDQ)[3][MD1*MD1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
ConstDeviceCube Xx(sDDD[0], D1D, D1D, D1D);
ConstDeviceCube Xy(sDDD[1], D1D, D1D, D1D);
ConstDeviceCube Xz(sDDD[2], D1D, D1D, D1D);
DeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
DeviceCube XyB(sDDQ[1], Q1D, D1D, D1D);
DeviceCube XzB(sDDQ[2], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int dx = 0; dx < D1D; ++dx)
{
const double Bx = B(dx,qx);
u[0] += Bx * Xx(dx,dy,dz);
u[1] += Bx * Xy(dx,dy,dz);
u[2] += Bx * Xz(dx,dy,dz);
}
XxB(qx,dy,dz) = u[0];
XyB(qx,dy,dz) = u[1];
XzB(qx,dy,dz) = u[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Vector Evaluation, 2/3 (only B)
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalY(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDDQ)[3][MD1*MD1*MQ1],
double (&sDQQ)[3][MD1*MQ1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
ConstDeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
ConstDeviceCube XyB(sDDQ[1], Q1D, D1D, D1D);
ConstDeviceCube XzB(sDDQ[2], Q1D, D1D, D1D);
DeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
DeviceCube XyBB(sDQQ[1], Q1D, Q1D, D1D);
DeviceCube XzBB(sDQQ[2], Q1D, Q1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int dy = 0; dy < D1D; ++dy)
{
const double By = B(dy,qy);
u[0] += XxB(qx,dy,dz) * By;
u[1] += XyB(qx,dy,dz) * By;
u[2] += XzB(qx,dy,dz) * By;
}
XxBB(qx,qy,dz) = u[0];
XyBB(qx,qy,dz) = u[1];
XzBB(qx,qy,dz) = u[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Vector Evaluation, 3/3 (only B)
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalZ(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDQQ)[3][MD1*MQ1*MQ1],
double (&sQQQ)[3][MQ1*MQ1*MQ1])
{
ConstDeviceMatrix B(sB, D1D, Q1D);
ConstDeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
ConstDeviceCube XyBB(sDQQ[1], Q1D, Q1D, D1D);
ConstDeviceCube XzBB(sDQQ[2], Q1D, Q1D, D1D);
DeviceCube XxBBB(sQQQ[0], Q1D, Q1D, Q1D);
DeviceCube XyBBB(sQQQ[1], Q1D, Q1D, Q1D);
DeviceCube XzBBB(sQQQ[2], Q1D, Q1D, Q1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int dz = 0; dz < D1D; ++dz)
{
const double Bz = B(dz,qz);
u[0] += XxBB(qx,qy,dz) * Bz;
u[1] += XyBB(qx,qy,dz) * Bz;
u[2] += XzBB(qx,qy,dz) * Bz;
}
XxBBB(qx,qy,qz) = u[0];
XyBBB(qx,qy,qz) = u[1];
XzBBB(qx,qy,qz) = u[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// Pull 3D Vector Evaluation
template<int MQ1>
MFEM_HOST_DEVICE inline void PullEval(const int Q1D,
const int x, const int y, const int z,
const double (&sQQQ)[3][MQ1*MQ1*MQ1],
double (&X)[3])
{
ConstDeviceCube XxBBB(sQQQ[0], Q1D, Q1D, Q1D);
ConstDeviceCube XyBBB(sQQQ[1], Q1D, Q1D, Q1D);
ConstDeviceCube XzBBB(sQQQ[2], Q1D, Q1D, Q1D);
X[0] = XxBBB(x,y,z);
X[1] = XyBBB(x,y,z);
X[2] = XzBBB(x,y,z);
}
/// Push 3D Vector Evaluation
template<int MQ1>
MFEM_HOST_DEVICE inline void PushEval(const int Q1D,
const int x, const int y, const int z,
const double (&A)[3],
double (&sQQQ)[3][MQ1*MQ1*MQ1])
{
DeviceCube XxBBB(sQQQ[0], Q1D, Q1D, Q1D);
DeviceCube XyBBB(sQQQ[1], Q1D, Q1D, Q1D);
DeviceCube XzBBB(sQQQ[2], Q1D, Q1D, Q1D);
XxBBB(x,y,z) = A[0];
XyBBB(x,y,z) = A[1];
XzBBB(x,y,z) = A[2];
}
/// 3D Transposed Vector Evaluation, 1/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalXt(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sQQQ)[3][MQ1*MQ1*MQ1],
double (&sDQQ)[3][MD1*MQ1*MQ1])
{
ConstDeviceMatrix Bt(sB, Q1D, D1D);
ConstDeviceCube XxBBB(sQQQ[0], Q1D, Q1D, Q1D);
ConstDeviceCube XyBBB(sQQQ[1], Q1D, Q1D, Q1D);
ConstDeviceCube XzBBB(sQQQ[2], Q1D, Q1D, Q1D);
DeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
DeviceCube XyBB(sDQQ[1], Q1D, Q1D, D1D);
DeviceCube XzBB(sDQQ[2], Q1D, Q1D, D1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int qx = 0; qx < Q1D; ++qx)
{
const double Btx = Bt(qx,dx);
u[0] += XxBBB(qx,qy,qz) * Btx;
u[1] += XyBBB(qx,qy,qz) * Btx;
u[2] += XzBBB(qx,qy,qz) * Btx;
}
XxBB(qz,qy,dx) = u[0];
XyBB(qz,qy,dx) = u[1];
XzBB(qz,qy,dx) = u[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Transposed Vector Evaluation, 2/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalYt(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDQQ)[3][MD1*MQ1*MQ1],
double (&sDDQ)[3][MD1*MD1*MQ1])
{
ConstDeviceMatrix Bt(sB, Q1D, D1D);
ConstDeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
ConstDeviceCube XyBB(sDQQ[1], Q1D, Q1D, D1D);
ConstDeviceCube XzBB(sDQQ[2], Q1D, Q1D, D1D);
DeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
DeviceCube XyB(sDDQ[1], Q1D, D1D, D1D);
DeviceCube XzB(sDDQ[2], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int qy = 0; qy < Q1D; ++qy)
{
const double Bty = Bt(qy,dy);
u[0] += XxBB(qz,qy,dx) * Bty;
u[1] += XyBB(qz,qy,dx) * Bty;
u[2] += XzBB(qz,qy,dx) * Bty;
}
XxB(qz,dy,dx) = u[0];
XyB(qz,dy,dx) = u[1];
XzB(qz,dy,dx)= u[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Transposed Vector Evaluation, 3/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void EvalZt(const int D1D, const int Q1D,
const double (&sB)[MQ1*MD1],
const double (&sDDQ)[3][MD1*MD1*MQ1],
const DeviceTensor<5> &Y, // output
const int e)
{
ConstDeviceMatrix Bt(sB, Q1D, D1D);
ConstDeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
ConstDeviceCube XyB(sDDQ[1], Q1D, D1D, D1D);
ConstDeviceCube XzB(sDDQ[2], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
for (int qz = 0; qz < Q1D; ++qz)
{
const double Btz = Bt(qz,dz);
u[0] += XxB(qz,dy,dx) * Btz;
u[1] += XyB(qz,dy,dx) * Btz;
u[2] += XzB(qz,dy,dx) * Btz;
}
Y(dx,dy,dz,0,e) += u[0];
Y(dx,dy,dz,1,e) += u[1];
Y(dx,dy,dz,2,e) += u[2];
}
}
}
}
/// 3D Gradient, 1/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradX(const int D1D, const int Q1D,
const double (*sBG)[MQ1*MD1],
const double (*sDDD)[MD1*MD1*MD1],
double (*sDDQ)[MD1*MD1*MQ1])
{
ConstDeviceMatrix B(sBG[0], D1D, Q1D);
ConstDeviceMatrix G(sBG[1], D1D, Q1D);
ConstDeviceCube Xx(sDDD[0], D1D, D1D, D1D);
ConstDeviceCube Xy(sDDD[1], D1D, D1D, D1D);
ConstDeviceCube Xz(sDDD[2], D1D, D1D, D1D);
DeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
DeviceCube XxG(sDDQ[1], Q1D, D1D, D1D);
DeviceCube XyB(sDDQ[2], Q1D, D1D, D1D);
DeviceCube XyG(sDDQ[3], Q1D, D1D, D1D);
DeviceCube XzB(sDDQ[4], Q1D, D1D, D1D);
DeviceCube XzG(sDDQ[5], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
for (int dx = 0; dx < D1D; ++dx)
{
const double xx = Xx(dx,dy,dz);
const double xy = Xy(dx,dy,dz);
const double xz = Xz(dx,dy,dz);
const double Bx = B(dx,qx);
const double Gx = G(dx,qx);
u[0] += Bx * xx;
u[1] += Bx * xy;
u[2] += Bx * xz;
v[0] += Gx * xx;
v[1] += Gx * xy;
v[2] += Gx * xz;
}
XxB(qx,dy,dz) = u[0];
XyB(qx,dy,dz) = u[1];
XzB(qx,dy,dz) = u[2];
XxG(qx,dy,dz) = v[0];
XyG(qx,dy,dz) = v[1];
XzG(qx,dy,dz) = v[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Gradient, 2/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradY(const int D1D, const int Q1D,
const double (*sBG)[MQ1*MD1],
const double (*sDDQ)[MD1*MD1*MQ1],
double (*sDQQ)[MD1*MQ1*MQ1])
{
ConstDeviceMatrix B(sBG[0], D1D, Q1D);
ConstDeviceMatrix G(sBG[1], D1D, Q1D);
ConstDeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
ConstDeviceCube XxG(sDDQ[1], Q1D, D1D, D1D);
ConstDeviceCube XyB(sDDQ[2], Q1D, D1D, D1D);
ConstDeviceCube XyG(sDDQ[3], Q1D, D1D, D1D);
ConstDeviceCube XzB(sDDQ[4], Q1D, D1D, D1D);
ConstDeviceCube XzG(sDDQ[5], Q1D, D1D, D1D);
DeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
DeviceCube XxBG(sDQQ[1], Q1D, Q1D, D1D);
DeviceCube XxGB(sDQQ[2], Q1D, Q1D, D1D);
DeviceCube XyBB(sDQQ[3], Q1D, Q1D, D1D);
DeviceCube XyBG(sDQQ[4], Q1D, Q1D, D1D);
DeviceCube XyGB(sDQQ[5], Q1D, Q1D, D1D);
DeviceCube XzBB(sDQQ[6], Q1D, Q1D, D1D);
DeviceCube XzBG(sDQQ[7], Q1D, Q1D, D1D);
DeviceCube XzGB(sDQQ[8], Q1D, Q1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
double w[3] = {0.0, 0.0, 0.0};
for (int dy = 0; dy < D1D; ++dy)
{
const double By = B(dy,qy);
const double Gy = G(dy,qy);
u[0] += XxB(qx,dy,dz) * By;
u[1] += XyB(qx,dy,dz) * By;
u[2] += XzB(qx,dy,dz) * By;
v[0] += XxG(qx,dy,dz) * By;
v[1] += XyG(qx,dy,dz) * By;
v[2] += XzG(qx,dy,dz) * By;
w[0] += XxB(qx,dy,dz) * Gy;
w[1] += XyB(qx,dy,dz) * Gy;
w[2] += XzB(qx,dy,dz) * Gy;
}
XxBB(qx,qy,dz) = u[0];
XyBB(qx,qy,dz) = u[1];
XzBB(qx,qy,dz) = u[2];
XxBG(qx,qy,dz) = v[0];
XyBG(qx,qy,dz) = v[1];
XzBG(qx,qy,dz) = v[2];
XxGB(qx,qy,dz) = w[0];
XyGB(qx,qy,dz) = w[1];
XzGB(qx,qy,dz) = w[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Gradient, 3/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradZ(const int D1D, const int Q1D,
const double (*sBG)[MQ1*MD1],
const double (*sDQQ)[MD1*MQ1*MQ1],
double (*sQQQ)[MQ1*MQ1*MQ1])
{
ConstDeviceMatrix B(sBG[0], D1D, Q1D);
ConstDeviceMatrix G(sBG[1], D1D, Q1D);
ConstDeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
ConstDeviceCube XxBG(sDQQ[1], Q1D, Q1D, D1D);
ConstDeviceCube XxGB(sDQQ[2], Q1D, Q1D, D1D);
ConstDeviceCube XyBB(sDQQ[3], Q1D, Q1D, D1D);
ConstDeviceCube XyBG(sDQQ[4], Q1D, Q1D, D1D);
ConstDeviceCube XyGB(sDQQ[5], Q1D, Q1D, D1D);
ConstDeviceCube XzBB(sDQQ[6], Q1D, Q1D, D1D);
ConstDeviceCube XzBG(sDQQ[7], Q1D, Q1D, D1D);
ConstDeviceCube XzGB(sDQQ[8], Q1D, Q1D, D1D);
DeviceCube XxBBG(sQQQ[0], Q1D, Q1D, Q1D);
DeviceCube XxBGB(sQQQ[1], Q1D, Q1D, Q1D);
DeviceCube XxGBB(sQQQ[2], Q1D, Q1D, Q1D);
DeviceCube XyBBG(sQQQ[3], Q1D, Q1D, Q1D);
DeviceCube XyBGB(sQQQ[4], Q1D, Q1D, Q1D);
DeviceCube XyGBB(sQQQ[5], Q1D, Q1D, Q1D);
DeviceCube XzBBG(sQQQ[6], Q1D, Q1D, Q1D);
DeviceCube XzBGB(sQQQ[7], Q1D, Q1D, Q1D);
DeviceCube XzGBB(sQQQ[8], Q1D, Q1D, Q1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
double w[3] = {0.0, 0.0, 0.0};
for (int dz = 0; dz < D1D; ++dz)
{
const double Bz = B(dz,qz);
const double Gz = G(dz,qz);
u[0] += XxBG(qx,qy,dz) * Bz;
u[1] += XyBG(qx,qy,dz) * Bz;
u[2] += XzBG(qx,qy,dz) * Bz;
v[0] += XxGB(qx,qy,dz) * Bz;
v[1] += XyGB(qx,qy,dz) * Bz;
v[2] += XzGB(qx,qy,dz) * Bz;
w[0] += XxBB(qx,qy,dz) * Gz;
w[1] += XyBB(qx,qy,dz) * Gz;
w[2] += XzBB(qx,qy,dz) * Gz;
}
XxBBG(qx,qy,qz) = u[0];
XyBBG(qx,qy,qz) = u[1];
XzBBG(qx,qy,qz) = u[2];
XxBGB(qx,qy,qz) = v[0];
XyBGB(qx,qy,qz) = v[1];
XzBGB(qx,qy,qz) = v[2];
XxGBB(qx,qy,qz)= w[0];
XyGBB(qx,qy,qz) = w[1];
XzGBB(qx,qy,qz) = w[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// Pull 3D Gradient
template<int MQ1>
MFEM_HOST_DEVICE inline void PullGrad(const int Q1D,
const int x, const int y, const int z,
const double (*sQQQ)[MQ1*MQ1*MQ1],
double *Jpr)
{
ConstDeviceCube XxBBG(sQQQ[0], Q1D, Q1D, Q1D);
ConstDeviceCube XxBGB(sQQQ[1], Q1D, Q1D, Q1D);
ConstDeviceCube XxGBB(sQQQ[2], Q1D, Q1D, Q1D);
ConstDeviceCube XyBBG(sQQQ[3], Q1D, Q1D, Q1D);
ConstDeviceCube XyBGB(sQQQ[4], Q1D, Q1D, Q1D);
ConstDeviceCube XyGBB(sQQQ[5], Q1D, Q1D, Q1D);
ConstDeviceCube XzBBG(sQQQ[6], Q1D, Q1D, Q1D);
ConstDeviceCube XzBGB(sQQQ[7], Q1D, Q1D, Q1D);
ConstDeviceCube XzGBB(sQQQ[8], Q1D, Q1D, Q1D);
Jpr[0] = XxBBG(x,y,z);
Jpr[3] = XxBGB(x,y,z);
Jpr[6] = XxGBB(x,y,z);
Jpr[1] = XyBBG(x,y,z);
Jpr[4] = XyBGB(x,y,z);
Jpr[7] = XyGBB(x,y,z);
Jpr[2] = XzBBG(x,y,z);
Jpr[5] = XzBGB(x,y,z);
Jpr[8] = XzGBB(x,y,z);
}
/// Push 3D Gradient
template<int MQ1>
MFEM_HOST_DEVICE inline void PushGrad(const int Q1D,
const int x, const int y, const int z,
const double *A,
double (&sQQQ)[9][MQ1*MQ1*MQ1])
{
DeviceCube XxBBG(sQQQ[0], Q1D, Q1D, Q1D);
DeviceCube XxBGB(sQQQ[1], Q1D, Q1D, Q1D);
DeviceCube XxGBB(sQQQ[2], Q1D, Q1D, Q1D);
DeviceCube XyBBG(sQQQ[3], Q1D, Q1D, Q1D);
DeviceCube XyBGB(sQQQ[4], Q1D, Q1D, Q1D);
DeviceCube XyGBB(sQQQ[5], Q1D, Q1D, Q1D);
DeviceCube XzBBG(sQQQ[6], Q1D, Q1D, Q1D);
DeviceCube XzBGB(sQQQ[7], Q1D, Q1D, Q1D);
DeviceCube XzGBB(sQQQ[8], Q1D, Q1D, Q1D);
XxBBG(x,y,z) = A[0];
XxBGB(x,y,z) = A[1];
XxGBB(x,y,z) = A[2];
XyBBG(x,y,z) = A[3];
XyBGB(x,y,z) = A[4];
XyGBB(x,y,z) = A[5];
XzBBG(x,y,z) = A[6];
XzBGB(x,y,z) = A[7];
XzGBB(x,y,z) = A[8];
}
/// 3D Transposed Gradient, 1/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradZt(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&sQQQ)[9][MQ1*MQ1*MQ1],
double (&sDQQ)[9][MD1*MQ1*MQ1])
{
ConstDeviceMatrix Bt(sBG[0], Q1D, D1D);
ConstDeviceMatrix Gt(sBG[1], Q1D, D1D);
ConstDeviceCube XxBBG(sQQQ[0], Q1D, Q1D, Q1D);
ConstDeviceCube XxBGB(sQQQ[1], Q1D, Q1D, Q1D);
ConstDeviceCube XxGBB(sQQQ[2], Q1D, Q1D, Q1D);
ConstDeviceCube XyBBG(sQQQ[3], Q1D, Q1D, Q1D);
ConstDeviceCube XyBGB(sQQQ[4], Q1D, Q1D, Q1D);
ConstDeviceCube XyGBB(sQQQ[5], Q1D, Q1D, Q1D);
ConstDeviceCube XzBBG(sQQQ[6], Q1D, Q1D, Q1D);
ConstDeviceCube XzBGB(sQQQ[7], Q1D, Q1D, Q1D);
ConstDeviceCube XzGBB(sQQQ[8], Q1D, Q1D, Q1D);
DeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
DeviceCube XxBG(sDQQ[1], Q1D, Q1D, D1D);
DeviceCube XxGB(sDQQ[2], Q1D, Q1D, D1D);
DeviceCube XyBB(sDQQ[3], Q1D, Q1D, D1D);
DeviceCube XyBG(sDQQ[4], Q1D, Q1D, D1D);
DeviceCube XyGB(sDQQ[5], Q1D, Q1D, D1D);
DeviceCube XzBB(sDQQ[6], Q1D, Q1D, D1D);
DeviceCube XzBG(sDQQ[7], Q1D, Q1D, D1D);
DeviceCube XzGB(sDQQ[8], Q1D, Q1D, D1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
double w[3] = {0.0, 0.0, 0.0};
for (int qx = 0; qx < Q1D; ++qx)
{
const double Btx = Bt(qx,dx);
const double Gtx = Gt(qx,dx);
u[0] += XxBBG(qx,qy,qz) * Gtx;
v[0] += XxBGB(qx,qy,qz) * Btx;
w[0] += XxGBB(qx,qy,qz) * Btx;
u[1] += XyBBG(qx,qy,qz) * Gtx;
v[1] += XyBGB(qx,qy,qz) * Btx;
w[1] += XyGBB(qx,qy,qz) * Btx;
u[2] += XzBBG(qx,qy,qz) * Gtx;
v[2] += XzBGB(qx,qy,qz) * Btx;
w[2] += XzGBB(qx,qy,qz) * Btx;
}
XxBB(qz,qy,dx) = u[0];
XxBG(qz,qy,dx) = v[0];
XxGB(qz,qy,dx) = w[0];
XyBB(qz,qy,dx) = u[1];
XyBG(qz,qy,dx) = v[1];
XyGB(qz,qy,dx) = w[1];
XzBB(qz,qy,dx) = u[2];
XzBG(qz,qy,dx) = v[2];
XzGB(qz,qy,dx) = w[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Transposed Gradient, 2/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradYt(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&sDQQ)[9][MD1*MQ1*MQ1],
double (&sDDQ)[9][MD1*MD1*MQ1])
{
ConstDeviceMatrix Bt(sBG[0], Q1D, D1D);
ConstDeviceMatrix Gt(sBG[1], Q1D, D1D);
ConstDeviceCube XxBB(sDQQ[0], Q1D, Q1D, D1D);
ConstDeviceCube XxBG(sDQQ[1], Q1D, Q1D, D1D);
ConstDeviceCube XxGB(sDQQ[2], Q1D, Q1D, D1D);
ConstDeviceCube XyBB(sDQQ[3], Q1D, Q1D, D1D);
ConstDeviceCube XyBG(sDQQ[4], Q1D, Q1D, D1D);
ConstDeviceCube XyGB(sDQQ[5], Q1D, Q1D, D1D);
ConstDeviceCube XzBB(sDQQ[6], Q1D, Q1D, D1D);
ConstDeviceCube XzBG(sDQQ[7], Q1D, Q1D, D1D);
ConstDeviceCube XzGB(sDQQ[8], Q1D, Q1D, D1D);
DeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
DeviceCube XxG(sDDQ[1], Q1D, D1D, D1D);
DeviceCube XyB(sDDQ[2], Q1D, D1D, D1D);
DeviceCube XyG(sDDQ[3], Q1D, D1D, D1D);
DeviceCube XzB(sDDQ[4], Q1D, D1D, D1D);
DeviceCube XzG(sDDQ[5], Q1D, D1D, D1D);
DeviceCube XxC(sDDQ[6], Q1D, D1D, D1D);
DeviceCube XyC(sDDQ[7], Q1D, D1D, D1D);
DeviceCube XzC(sDDQ[8], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
double w[3] = {0.0, 0.0, 0.0};
for (int qy = 0; qy < Q1D; ++qy)
{
const double Bty = Bt(qy,dy);
const double Gty = Gt(qy,dy);
u[0] += XxBB(qz,qy,dx) * Bty;
v[0] += XxBG(qz,qy,dx) * Gty;
w[0] += XxGB(qz,qy,dx) * Bty;
u[1] += XyBB(qz,qy,dx) * Bty;
v[1] += XyBG(qz,qy,dx) * Gty;
w[1] += XyGB(qz,qy,dx) * Bty;
u[2] += XzBB(qz,qy,dx) * Bty;
v[2] += XzBG(qz,qy,dx) * Gty;
w[2] += XzGB(qz,qy,dx) * Bty;
}
XxB(qz,dy,dx) = u[0];
XxC(qz,dy,dx) = v[0];
XxG(qz,dy,dx) = w[0];
XyB(qz,dy,dx) = u[1];
XyC(qz,dy,dx) = v[1];
XyG(qz,dy,dx) = w[1];
XzB(qz,dy,dx) = u[2];
XzC(qz,dy,dx) = v[2];
XzG(qz,dy,dx) = w[2];
}
}
}
MFEM_SYNC_THREAD;
}
/// 3D Transposed Gradient, 3/3
template<int MD1, int MQ1>
MFEM_HOST_DEVICE inline void GradXt(const int D1D, const int Q1D,
const double (&sBG)[2][MQ1*MD1],
const double (&sDDQ)[9][MD1*MD1*MQ1],
const DeviceTensor<5> &Y, // output
const int e)
{
ConstDeviceMatrix Bt(sBG[0], Q1D, D1D);
ConstDeviceMatrix Gt(sBG[1], Q1D, D1D);
ConstDeviceCube XxB(sDDQ[0], Q1D, D1D, D1D);
ConstDeviceCube XxG(sDDQ[1], Q1D, D1D, D1D);
ConstDeviceCube XyB(sDDQ[2], Q1D, D1D, D1D);
ConstDeviceCube XyG(sDDQ[3], Q1D, D1D, D1D);
ConstDeviceCube XzB(sDDQ[4], Q1D, D1D, D1D);
ConstDeviceCube XzG(sDDQ[5], Q1D, D1D, D1D);
ConstDeviceCube XxC(sDDQ[6], Q1D, D1D, D1D);
ConstDeviceCube XyC(sDDQ[7], Q1D, D1D, D1D);
ConstDeviceCube XzC(sDDQ[8], Q1D, D1D, D1D);
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[3] = {0.0, 0.0, 0.0};
double v[3] = {0.0, 0.0, 0.0};
double w[3] = {0.0, 0.0, 0.0};
for (int qz = 0; qz < Q1D; ++qz)
{
const double Btz = Bt(qz,dz);
const double Gtz = Gt(qz,dz);
u[0] += XxB(qz,dy,dx) * Btz;
v[0] += XxC(qz,dy,dx) * Btz;
w[0] += XxG(qz,dy,dx) * Gtz;
u[1] += XyB(qz,dy,dx) * Btz;
v[1] += XyC(qz,dy,dx)* Btz;
w[1] += XyG(qz,dy,dx) * Gtz;
u[2] += XzB(qz,dy,dx) * Btz;
v[2] += XzC(qz,dy,dx) * Btz;
w[2] += XzG(qz,dy,dx) * Gtz;
}
Y(dx,dy,dz,0,e) += u[0] + v[0] + w[0];
Y(dx,dy,dz,1,e) += u[1] + v[1] + w[1];
Y(dx,dy,dz,2,e) += u[2] + v[2] + w[2];
}
}
}
}
} // namespace kernels::internal
} // namespace kernels
} // namespace mfem
#endif // MFEM_FEM_KERNELS_HPP