// Copyright (c) 2010-2021, 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 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 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 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 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 shared memory template 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); MFEM_FOREACH_THREAD(dy,y,D1D) { MFEM_FOREACH_THREAD(dx,x,D1D) { X(dx,dy) = x(dx,dy,e); } } MFEM_SYNC_THREAD; } /// 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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