22static void NormalDerivativeSetupFaceIndexMap2D(
23 int nf,
int d,
const Array<int>& face_to_elem, Array<int>& face_to_vol)
25 const auto f2e =
Reshape(face_to_elem.HostRead(), 2, 2, nf);
26 auto f2v =
Reshape(face_to_vol.HostWrite(), d, 2, nf);
28 for (
int f = 0;
f < nf; ++
f)
30 const int fid0 = f2e(0, 1,
f);
31 const int fid1 = f2e(1, 1,
f);
32 for (
int side = 0; side < 2; ++side)
34 const int el = f2e(side, 0,
f);
38 for (
int p = 0;
p < d; ++
p)
45 for (
int p = 0;
p < d; ++
p)
48 internal::FaceIdxToVolIdx2D(
p, d, fid0, fid1, side, i, j);
50 f2v(
p, side,
f) = i + d * j;
58static void NormalDerivativeSetupFaceIndexMap3D(
59 int nf,
int d,
const Array<int>& face_to_elem, Array<int>& face_to_vol)
61 const auto f2e =
Reshape(face_to_elem.HostRead(), 2, 3, nf);
62 auto f2v =
Reshape(face_to_vol.HostWrite(), d*d, 2, nf);
64 for (
int f = 0;
f < nf; ++
f)
66 const int fid0 = f2e(0, 1,
f);
67 const int fid1 = f2e(1, 1,
f);
68 for (
int side = 0; side < 2; ++side)
70 const int el = f2e(side, 0,
f);
71 const int orientation = f2e(side, 2,
f);
75 for (
int p = 0;
p < d*d; ++
p)
82 for (
int p = 0;
p < d*d; ++
p)
85 internal::FaceIdxToVolIdx3D(
p, d, fid0, fid1, side, orientation, i, j, k);
87 f2v(
p, side,
f) = i + d * (j + d * k);
99 face_type(face_type_),
101 nf(fes.GetNFbyType(face_type)),
105 "Non-lexicographic ordering not currently supported in "
106 "L2NormalDerivativeFaceRestriction.");
127 MFEM_ABORT(
"Unsupported dimension.");
158 f2e(1, 0, f_ind) =
ne + el_idx_1;
163 f2e(1, 0, f_ind) = el_idx_1;
164 elem_indicator[el_idx_1] = 1;
175 f2e(1, 0, f_ind) = -1;
176 f2e(1, 1, f_ind) = -1;
180 f2e(1, 2, f_ind) = -1;
199 ne_type = elem_indicator.Sum();
203 const int elem_data_sz = (
dim == 2) ? 9 : 13;
209 elem_indicator.PartialSum();
212 const int side_begin = (
dim == 2) ? 5 : 7;
213 for (
int f = 0;
f <
nf; ++
f)
215 for (
int side = 0; side < nsides; ++side)
217 const int el = f2e(side, 0,
f);
221 const int face_id = f2e(side, 1,
f);
223 const int e = elem_indicator[el] - 1;
225 e2f(1 + face_id, e) =
f;
226 e2f(side_begin + face_id, e) = side;
234 if (
nf == 0) {
return; }
250 default:
Mult2D(x, y);
break;
267 default:
Mult3D(x, y);
break;
271 default: MFEM_ABORT(
"Dimension not supported.");
break;
278 if (
nf == 0) {
return; }
315 default: MFEM_ABORT(
"Not yet implemented");
break;
324 const int num_elem =
ne;
329 const int q = maps.
nqpt;
330 const int d = maps.
ndof;
333 const int ne_shared = face_nbr_data.
Size() / d / d / vd;
335 MFEM_VERIFY(q == d,
"");
336 MFEM_VERIFY(T_D1D == d || T_D1D == 0,
"");
348 const auto d_x_shared =
Reshape(face_nbr_data.
Read(),
349 t?vd:d, d,
t?d:ne_shared,
t?ne_shared:vd);
354 constexpr int MD = (T_D1D) ? T_D1D : DofQuadLimits::MAX_D1D;
356 MFEM_SHARED
real_t G_s[MD*MD];
359 MFEM_SHARED
int E[2];
360 MFEM_SHARED
int FID[2];
361 MFEM_SHARED
int F2V[2][MD];
363 if (MFEM_THREAD_ID(x) == 0)
365 MFEM_FOREACH_THREAD(j, y, d)
367 for (
int i = 0; i < q; ++i)
374 MFEM_FOREACH_THREAD(side, x, 2)
376 if (MFEM_THREAD_ID(y) == 0)
378 E[side] = f2e(side, 0,
f);
379 FID[side] = f2e(side, 1,
f);
382 MFEM_FOREACH_THREAD(j, y, d)
384 F2V[side][j] = f2v(j, side,
f);
389 MFEM_FOREACH_THREAD(side, x, 2)
391 const int el = E[side];
392 const bool shared = (el >= num_elem);
393 const auto &d_x_e = shared ? d_x_shared : d_x;
394 const int el_idx = shared ? el - num_elem : el;
396 const int face_id = FID[side];
398 MFEM_FOREACH_THREAD(
p, y, q)
402 for (
int c = 0; c < vd; ++c)
404 d_y(
p, c, side,
f) = 0.0;
409 const int ij = F2V[side][
p];
410 const int i = ij % q;
411 const int j = ij / q;
413 for (
int c=0; c < vd; ++c)
416 for (
int kk=0; kk < d; ++kk)
418 const int k = (face_id == 0 || face_id == 2) ? i : kk;
419 const int l = (face_id == 0 || face_id == 2) ? kk : j;
420 const real_t g = (face_id == 0 || face_id == 2) ? G(j,l) : G(i,k);
421 grad_n += g * d_x_e(
t?c:k,
t?k:l,
t?l:el_idx,
t?el_idx:c);
423 d_y(
p, c, side,
f) = grad_n;
436 const int num_elem =
ne;
441 const int q = maps.
nqpt;
442 const int d = maps.
ndof;
443 const int q2d = q * q;
446 const int ne_shared = face_nbr_data.
Size() / d / d / d / vd;
448 MFEM_VERIFY(q == d,
"");
449 MFEM_VERIFY(T_D1D == d || T_D1D == 0,
"");
458 const auto d_x_shared =
Reshape(face_nbr_data.
Read(),
459 t?vd:d, d, d,
t?d:ne_shared,
t?ne_shared:vd);
464 static constexpr int MD = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
466 MFEM_SHARED
real_t G_s[MD*MD];
469 MFEM_SHARED
int E[2];
470 MFEM_SHARED
int FID[2];
471 MFEM_SHARED
int F2V[2][MD*MD];
474 if (MFEM_THREAD_ID(y) == 0)
476 MFEM_FOREACH_THREAD(j, x, d*q)
484 MFEM_FOREACH_THREAD(side, y, 2)
486 if (MFEM_THREAD_ID(x) == 0)
488 E[side] = f2e(side, 0,
f);
489 FID[side] = f2e(side, 1,
f);
491 MFEM_FOREACH_THREAD(j, x, q2d)
493 F2V[side][j] = f2v(j, side,
f);
498 MFEM_FOREACH_THREAD(side, y, 2)
500 const int el = E[side];
501 const bool shared = (el >= num_elem);
502 const auto &d_x_e = shared ? d_x_shared : d_x;
503 const int el_idx = shared ? el - num_elem : el;
505 const int face_id = FID[side];
508 const bool xy_plane = (face_id == 0 || face_id == 5);
509 const bool xz_plane = (face_id == 1 || face_id == 3);
510 const bool yz_plane = (face_id == 2 || face_id == 4);
512 MFEM_FOREACH_THREAD(
p, x, q2d)
516 for (
int c = 0; c < vd; ++c)
518 d_y(
p, c, side,
f) = 0.0;
523 const int ijk = F2V[side][
p];
524 const int k = ijk / q2d;
525 const int i = ijk % q;
526 const int j = (ijk - q2d*k) / q;
530 const int g_row = yz_plane ? i : xz_plane ? j : k;
532 for (
int c = 0; c < vd; ++c)
536 for (
int kk = 0; kk < d; ++kk)
540 const int l = yz_plane ? kk : i;
541 const int m = xz_plane ? kk : j;
542 const int n = xy_plane ? kk : k;
544 const real_t g = G(kk, g_row);
546 grad_n += g * d_x_e(
t?c:l,
t?l:m,
t?m:n,
t?n:el_idx,
t?el_idx:c);
548 d_y(
p, c, side,
f) = grad_n;
566 const int q = maps.
nqpt;
567 const int d = maps.
ndof;
584 constexpr int MD = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
586 MFEM_SHARED
real_t y_s[MD];
587 MFEM_SHARED
int pp[MD];
589 if (MFEM_THREAD_ID(x) == 0 && MFEM_THREAD_ID(y) == 0) { jj = 0; }
591 MFEM_SHARED
real_t BG[MD*MD];
594 MFEM_SHARED
real_t x_s[MD*MD];
598 MFEM_SHARED
int faces[4];
599 MFEM_SHARED
int sides[4];
601 MFEM_FOREACH_THREAD(i,x,d)
603 MFEM_FOREACH_THREAD(
p,y,q)
605 G(
p,i) =
a * G_(
p,i);
610 if (MFEM_THREAD_ID(y) == 0)
612 if (MFEM_THREAD_ID(x) == 0)
617 MFEM_FOREACH_THREAD(i, x, 4)
619 faces[i] = e2f(1 + i, e);
620 sides[i] = e2f(5 + i, e);
625 for (
int face_id=0; face_id < 4; ++face_id)
627 const int f = faces[face_id];
629 if (
f < 0) {
continue; }
631 const int side = sides[face_id];
633 if (MFEM_THREAD_ID(y) == 0)
635 MFEM_FOREACH_THREAD(
p,x,d)
637 y_s[
p] = d_y(
p, 0, side,
f);
639 const int ij = f2v(
p, side,
f);
640 const int i = ij % q;
641 const int j = ij / q;
643 pp[(face_id == 0 || face_id == 2) ? i : j] =
p;
644 if (MFEM_THREAD_ID(x) == 0)
646 jj = (face_id == 0 || face_id == 2) ? j : i;
652 MFEM_FOREACH_THREAD(k,x,d)
654 MFEM_FOREACH_THREAD(l,y,d)
656 const int p = (face_id == 0 || face_id == 2) ? pp[k] : pp[l];
657 const int kk = (face_id == 0 || face_id == 2) ? l : k;
658 const real_t g = G(jj, kk);
659 xx(k,l) += g * y_s[
p];
665 MFEM_FOREACH_THREAD(k,x,d)
667 MFEM_FOREACH_THREAD(l,y,d)
670 d_x(
t?c:k,
t?k:l,
t?l:el,
t?el:c) += xx(k,l);
683 MFEM_VERIFY(vd == 1,
"vdim > 1 not supported.");
688 const int q = maps.
nqpt;
689 const int d = maps.
ndof;
690 const int q2d = q * q;
692 MFEM_VERIFY(q == d,
"");
693 MFEM_VERIFY(T_D1D == d || T_D1D == 0,
"");
707 static constexpr int MD = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
709 MFEM_SHARED
int pp[MD][MD];
710 MFEM_SHARED
real_t y_s[MD*MD];
712 if (MFEM_THREAD_ID(x) == 0 && MFEM_THREAD_ID(y) == 0) { jj = 0; }
714 MFEM_SHARED
real_t xx_s[MD*MD*MD];
715 auto xx =
Reshape(xx_s, d, d, d);
717 MFEM_SHARED
real_t G_s[MD*MD];
721 MFEM_SHARED
int faces[6];
722 MFEM_SHARED
int sides[6];
725 MFEM_FOREACH_THREAD(j, x, d)
727 MFEM_FOREACH_THREAD(i, y, q)
729 G(i, j) =
a * G_(i, j);
730 G(i, j) =
a * G_(i, j);
731 G(i, j) =
a * G_(i, j);
735 if (MFEM_THREAD_ID(y) == 0)
737 if (MFEM_THREAD_ID(x) == 0)
742 MFEM_FOREACH_THREAD(i, x, 6)
744 faces[i] = e2f(1 + i, e);
745 sides[i] = e2f(7 + i, e);
749 MFEM_FOREACH_THREAD(k, x, d)
751 MFEM_FOREACH_THREAD(j, y, d)
753 for (
int i = 0; i < d; ++i)
761 for (
int face_id = 0; face_id < 6; ++face_id)
763 const int f = faces[face_id];
770 const int side = sides[face_id];
773 const bool xy_plane = (face_id == 0 || face_id == 5);
774 const bool xz_plane = (face_id == 1 || face_id == 3);
776 MFEM_FOREACH_THREAD(p1, x, q)
778 MFEM_FOREACH_THREAD(p2, y, q)
780 const int p = p1 + q * p2;
781 y_s[
p] = d_y(
p, 0, side,
f);
783 const int ijk = f2v(
p, side,
f);
784 const int k = ijk / q2d;
785 const int i = ijk % q;
786 const int j = (ijk - q2d*k) / q;
788 pp[(xy_plane || xz_plane) ? i : j][(xy_plane) ? j : k] =
p;
789 if (MFEM_THREAD_ID(x) == 0 && MFEM_THREAD_ID(y) == 0)
791 jj = (xy_plane) ? k : (xz_plane) ? j : i;
797 MFEM_FOREACH_THREAD(n, x, d)
799 MFEM_FOREACH_THREAD(m, y, d)
801 for (
int l = 0; l < d; ++l)
803 const int p = (xy_plane) ? pp[l][m] : (xz_plane) ? pp[l][n] : pp[m][n];
804 const int kk = (xy_plane) ? n : (xz_plane) ? m : l;
805 const real_t g = G(jj, kk);
806 xx(l, m, n) += g * y_s[
p];
814 MFEM_FOREACH_THREAD(n, x, d)
816 MFEM_FOREACH_THREAD(m, y, d)
818 for (
int l = 0; l < d; ++l)
821 d_x(
t?c:l,
t?l:m,
t?m:n,
t?n:el,
t?el:c) += xx(l, m, n);
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
A basic generic Tensor class, appropriate for use on the GPU.
Structure representing the matrices/tensors needed to evaluate (in reference space) the values,...
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...
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...
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Ordering::Type GetOrdering() const
Return the ordering method.
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Mesh * GetMesh() const
Returns the mesh.
int GetVDim() const
Returns vector dimension.
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...
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
void Mult(const Vector &x, Vector &y) const
Computes the normal derivatives on the face_type faces of the mesh.
Array< int > elem_to_face
Element-wise information array.
L2NormalDerivativeFaceRestriction(const FiniteElementSpace &fes_, const ElementDofOrdering f_ordering, const FaceType face_type_)
Constructor.
const int nf
Number of faces of the given face_type.
Array< int > face_to_elem
Face-wise information array.
const FiniteElementSpace & fes
The L2 finite element space.
int ne_type
Number of elements with faces of type face type.
const FaceType face_type
Face type: either boundary or interior.
void Mult2D(const Vector &x, Vector &y) const
const int ne
Number of elements.
void Mult3D(const Vector &x, Vector &y) const
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const
Computes the transpose of the action of Mult(), accumulating into y with coefficient a.
Array< int > face_to_vol
maps face index to volume index
const int dim
Dimension of the mesh.
void AddMultTranspose2D(const Vector &x, Vector &y, const real_t a) const
void AddMultTranspose3D(const Vector &x, Vector &y, const real_t a) const
FaceInformation GetFaceInformation(int f) const
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.
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Vector GetLVectorFaceNbrData(const FiniteElementSpace &fes, const Vector &x, FaceType ftype)
Return the face-neighbor data given the L-vector x.
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)
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
@ LEXICOGRAPHIC
Lexicographic ordering for tensor-product FiniteElements.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
real_t p(const Vector &x, real_t t)