32 ndofs(fes.GetNDofs()),
33 dof(fes.GetTypicalFE()->GetDof()),
40 MFEM_VERIFY(!
f.IsVariableOrder(),
"Variable-order spaces are not supported");
45 const int *dof_map = NULL;
46 if (dof_reorder &&
ne > 0)
48 for (
int e = 0; e <
ne; ++e)
53 if (el_t || el_n) {
continue; }
54 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
60 (el_t) ? el_t->GetDofMap() : el_n->GetLexicographicOrdering();
61 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
65 const int* element_map = e2dTable.
GetJ();
67 for (
int i = 0; i <=
ndofs; ++i)
71 for (
int e = 0; e <
ne; ++e)
73 for (
int d = 0; d <
dof; ++d)
75 const int sgid = element_map[
dof*e + d];
76 const int gid = (sgid >= 0) ? sgid : -1 - sgid;
81 for (
int i = 1; i <=
ndofs; ++i)
86 for (
int e = 0; e <
ne; ++e)
88 for (
int d = 0; d <
dof; ++d)
90 const int sdid = dof_reorder ? dof_map[d] : 0;
91 const int did = (!dof_reorder)?d:(sdid >= 0 ? sdid : -1-sdid);
92 const int sgid = element_map[
dof*e + did];
93 const int gid = (sgid >= 0) ? sgid : -1-sgid;
94 const int lid =
dof*e + d;
95 const bool plus = (sgid >= 0 && sdid >= 0) || (sgid < 0 && sdid < 0);
102 for (
int i =
ndofs; i > 0; --i)
120 const int gid = d_gather_map[i];
121 const bool plus = gid >= 0;
122 const int j = plus ? gid : -1-gid;
123 for (
int c = 0; c < vd; ++c)
125 const real_t dof_value = d_x(t?c:j, t?j:c);
126 d_y(i % nd, c, i / nd) = plus ? dof_value : -dof_value;
143 const int gid = d_gather_map[i];
144 const int j = gid >= 0 ? gid : -1-gid;
145 for (
int c = 0; c < vd; ++c)
147 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
153void ElementRestriction::TAddMultTranspose(
const Vector& x,
Vector& y)
const
165 const int offset = d_offsets[i];
166 const int next_offset = d_offsets[i + 1];
167 for (
int c = 0; c < vd; ++c)
170 for (
int j = offset; j < next_offset; ++j)
172 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
173 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
174 -d_x(idx_j % nd, c, idx_j / nd));
176 if (ADD) { d_y(t?c:i,t?i:c) += dof_value; }
177 else { d_y(t?c:i,t?i:c) = dof_value; }
184 constexpr bool ADD =
false;
185 TAddMultTranspose<ADD>(x, y);
191 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
192 constexpr bool ADD =
true;
193 TAddMultTranspose<ADD>(x, y);
208 const int offset = d_offsets[i];
209 const int next_offset = d_offsets[i + 1];
210 for (
int c = 0; c < vd; ++c)
213 for (
int j = offset; j < next_offset; ++j)
215 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
216 dof_value += d_x(idx_j % nd, c, idx_j / nd);
218 d_y(t?c:i,t?i:c) = dof_value;
235 const int next_offset = d_offsets[i + 1];
236 for (
int c = 0; c < vd; ++c)
239 const int j = next_offset - 1;
240 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
241 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
242 -d_x(idx_j % nd, c, idx_j / nd);
243 d_y(t?c:i,t?i:c) = dof_value;
262 for (
int i = 0; i <
ndofs; ++i)
264 const int offset = d_offsets[i];
265 const int next_offset = d_offsets[i+1];
266 for (
int c = 0; c < vd; ++c)
268 for (
int j = offset; j < next_offset; ++j)
270 const int idx_j = d_indices[j];
271 if (d_x(t?c:i,t?i:c))
273 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
277 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
278 d_x(t?c:i,t?i:c) = 1;
289 const int nnz =
FillI(mat);
295static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
296 const int *nbr_elts,
const int nbrNbElts)
299 int min_el = INT_MAX;
300 for (
int i = 0; i < nbElts; i++)
302 const int e_i = my_elts[i];
303 if (e_i >= min_el) {
continue; }
304 for (
int j = 0; j < nbrNbElts; j++)
306 if (e_i==nbr_elts[j])
318static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
326 const int all_dofs =
ndofs;
328 const int elt_dofs =
dof;
337 mfem::forall(vd*all_dofs+1, [=] MFEM_HOST_DEVICE (
int i_L)
343 const int e = l_dof/elt_dofs;
344 const int i = l_dof%elt_dofs;
346 const int i_gm = e*elt_dofs + i;
347 const int i_L = d_gather_map[i_gm];
348 const int i_offset = d_offsets[i_L];
349 const int i_next_offset = d_offsets[i_L+1];
350 const int i_nbElts = i_next_offset - i_offset;
352 int *i_elts = &d_ij_elts(i_offset, 0);
353 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
355 const int i_E = d_indices[i_offset+e_i];
356 i_elts[e_i] = i_E/elt_dofs;
358 for (
int j = 0; j < elt_dofs; j++)
360 const int j_gm = e*elt_dofs + j;
361 const int j_L = d_gather_map[j_gm];
362 const int j_offset = d_offsets[j_L];
363 const int j_next_offset = d_offsets[j_L+1];
364 const int j_nbElts = j_next_offset - j_offset;
365 if (i_nbElts == 1 || j_nbElts == 1)
367 GetAndIncrementNnzIndex(i_L, I);
371 int *j_elts = &d_ij_elts(j_offset, 1);
372 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
374 const int j_E = d_indices[j_offset+e_j];
375 const int elt = j_E/elt_dofs;
378 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
381 GetAndIncrementNnzIndex(i_L, I);
388 const int nTdofs = vd*all_dofs;
390 for (
int i = 0; i < nTdofs; i++)
392 const int nnz = h_I[i];
404 const int all_dofs =
ndofs;
406 const int elt_dofs =
dof;
413 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
420 const int e = l_dof/elt_dofs;
421 const int i = l_dof%elt_dofs;
423 const int i_gm = e*elt_dofs + i;
424 const int i_L = d_gather_map[i_gm];
425 const int i_offset = d_offsets[i_L];
426 const int i_next_offset = d_offsets[i_L+1];
427 const int i_nbElts = i_next_offset - i_offset;
429 int *i_elts = &d_ij_B_el(i_offset, 0);
430 int *i_B = &d_ij_B_el(i_offset, 1);
431 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
433 const int i_E = d_indices[i_offset+e_i];
434 i_elts[e_i] = i_E/elt_dofs;
435 i_B[e_i] = i_E%elt_dofs;
437 for (
int j = 0; j < elt_dofs; j++)
439 const int j_gm = e*elt_dofs + j;
440 const int j_L = d_gather_map[j_gm];
441 const int j_offset = d_offsets[j_L];
442 const int j_next_offset = d_offsets[j_L+1];
443 const int j_nbElts = j_next_offset - j_offset;
444 if (i_nbElts == 1 || j_nbElts == 1)
446 const int nnz = GetAndIncrementNnzIndex(i_L, I);
448 Data[nnz] = mat_ea(j,i,e);
452 int *j_elts = &d_ij_B_el(j_offset, 2);
453 int *j_B = &d_ij_B_el(j_offset, 3);
454 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
456 const int j_E = d_indices[j_offset+e_j];
457 const int elt = j_E/elt_dofs;
459 j_B[e_j] = j_E%elt_dofs;
461 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
465 for (
int k = 0; k < i_nbElts; k++)
467 const int e_i = i_elts[k];
468 const int i_Bloc = i_B[k];
469 for (
int l = 0; l < j_nbElts; l++)
471 const int e_j = j_elts[l];
472 const int j_Bloc = j_B[l];
475 val += mat_ea(j_Bloc, i_Bloc, e_i);
479 const int nnz = GetAndIncrementNnzIndex(i_L, I);
489 const int size = vd*all_dofs;
490 for (
int i = 0; i < size; i++)
492 h_I[size-i] = h_I[size-(i+1)];
501 ndof(fes.GetTypicalFE()->GetDof()),
502 ndofs(fes.GetNDofs())
505 width = vdim*ne*ndof;
512 const bool t = byvdim;
513 auto d_x =
Reshape(x.
Read(), t?vd:ndofs, t?ndofs:vd);
518 const int dof = idx % nd;
519 const int e = idx / nd;
520 for (
int c = 0; c < vd; ++c)
522 d_y(dof, c, e) = d_x(t?c:idx, t?idx:c);
528void L2ElementRestriction::TAddMultTranspose(
const Vector &x,
Vector &y)
const
532 const bool t = byvdim;
538 const int dof = idx % nd;
539 const int e = idx / nd;
540 for (
int c = 0; c < vd; ++c)
542 if (ADD) { d_y(t?c:idx,t?idx:c) += d_x(dof, c, e); }
543 else { d_y(t?c:idx,t?idx:c) = d_x(dof, c, e); }
550 constexpr bool ADD =
false;
551 TAddMultTranspose<ADD>(x, y);
557 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
558 constexpr bool ADD =
true;
559 TAddMultTranspose<ADD>(x, y);
564 const int elem_dofs = ndof;
567 const int isize = mat.
Height() + 1;
568 const int interior_dofs = ne*elem_dofs*vd;
571 I[dof] = dof<interior_dofs ? elem_dofs : 0;
575static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
584 const int elem_dofs = ndof;
589 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
590 mfem::forall(ne*elem_dofs*vd, [=] MFEM_HOST_DEVICE (
int iE)
592 const int offset = AddNnz(iE,I,elem_dofs);
593 const int e = iE/elem_dofs;
594 const int i = iE%elem_dofs;
595 for (
int j = 0; j < elem_dofs; j++)
597 J[offset+j] = e*elem_dofs+j;
598 Data[offset+j] = mat_ea(j,i,e);
609 nf(fes.GetNFbyType(type)),
612 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
613 elem_dofs(fes.GetTypicalFE()->GetDof()),
614 nfdofs(nf*face_dofs),
615 ndofs(fes.GetNDofs()),
616 scatter_indices(nf*face_dofs),
617 gather_offsets(ndofs+1),
618 gather_indices(nf*face_dofs),
623 if (
nf==0) {
return; }
631 if (dof_map_.
Size() > 0)
644 if (!build) {
return; }
645 ComputeScatterIndicesAndOffsets(f_ordering, type);
646 ComputeGatherIndices(f_ordering,type);
657 const bool useAbs)
const
659 if (
nf==0) {
return; }
669 const int s_idx = d_indices[i];
670 const int sgn = (useAbs || s_idx >= 0) ? 1 : -1;
671 const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
672 const int dof = i % nface_dofs;
673 const int face = i / nface_dofs;
674 for (
int c = 0; c < vd; ++c)
676 d_y(dof, c, face) = sgn*d_x(t?c:idx, t?idx:c);
681static void ConformingFaceRestriction_AddMultTranspose(
694 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
695 if (nf==0) {
return; }
697 auto d_offsets = gather_offsets.
Read();
698 auto d_indices = gather_indices.
Read();
703 const int offset = d_offsets[i];
704 const int next_offset = d_offsets[i + 1];
705 for (
int c = 0; c < vdim; ++c)
708 for (
int j = offset; j < next_offset; ++j)
710 const int s_idx_j = d_indices[j];
711 const real_t sgn = (s_idx_j >= 0 || !use_signs) ? 1.0 : -1.0;
712 const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
713 dof_value += sgn*d_x(idx_j % face_dofs, c, idx_j / face_dofs);
715 d_y(by_vdim?c:i,by_vdim?i:c) += dof_value;
723 ConformingFaceRestriction_AddMultTranspose(
731 ConformingFaceRestriction_AddMultTranspose(
746 pfes->GetParMesh()->ExchangeFaceNbrData();
754 MFEM_VERIFY(tfe != NULL,
755 "ConformingFaceRestriction only supports TensorBasisElements");
758 "ConformingFaceRestriction only supports Gauss-Lobatto and Bernstein bases");
762 if (dof_reorder &&
nf > 0)
769 if (el) {
continue; }
770 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
776void ConformingFaceRestriction::ComputeScatterIndicesAndOffsets(
783 for (
int i = 0; i <=
ndofs; ++i)
793 if ( face.IsNonconformingCoarse() )
799 else if ( face.IsOfFaceType(type) )
805 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
808 for (
int i = 1; i <=
ndofs; ++i)
814void ConformingFaceRestriction::ComputeGatherIndices(
825 if ( face.IsNonconformingCoarse() )
831 else if ( face.IsOfFaceType(type) )
837 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
840 for (
int i =
ndofs; i > 0; --i)
847static inline int absdof(
int i) {
return i < 0 ? -1-i : i; }
851 const int face_index,
855 "This method should not be used on nonconforming coarse faces.");
857 "FaceRestriction used on degenerated mesh.");
859 "NATIVE ordering is not supported yet");
864 const int* elem_map = e2dTable.
GetJ();
867 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
869 const int lex_volume_dof =
face_map[face_dof];
871 const int volume_dof = absdof(s_volume_dof);
872 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
873 const int global_dof = absdof(s_global_dof);
874 const int restriction_dof =
face_dofs*face_index + face_dof;
882 const int face_index,
886 "This method should not be used on nonconforming coarse faces.");
888 "NATIVE ordering is not supported yet");
893 const int* elem_map = e2dTable.
GetJ();
896 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
898 const int lex_volume_dof =
face_map[face_dof];
900 const int volume_dof = absdof(s_volume_dof);
901 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
902 const int sgn = (s_global_dof >= 0) ? 1 : -1;
903 const int global_dof = absdof(s_global_dof);
904 const int restriction_dof =
face_dofs*face_index + face_dof;
905 const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
913 const int face_id2,
const int orientation,
914 const int size1d,
const int index)
921 return internal::PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
923 return internal::PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
925 MFEM_ABORT(
"Unsupported dimension.");
936 ordering(f_ordering),
937 nf(fes.GetNFbyType(type)),
941 face_dofs(fes.GetTypicalTraceElement()->GetDof()),
942 elem_dofs(fes.GetTypicalFE()->GetDof()),
943 nfdofs(nf*face_dofs),
944 ndofs(fes.GetNDofs()),
947 scatter_indices1(nf*face_dofs),
949 gather_offsets(ndofs+1),
955 if (!build) {
return; }
958 ComputeScatterIndicesAndOffsets();
959 ComputeGatherIndices();
972 if (
nf == 0) {
return; }
975 "This method should be called when m == L2FaceValues::SingleValued.");
985 const int dof = i % nface_dofs;
986 const int face = i / nface_dofs;
987 const int idx1 = d_indices1[i];
988 for (
int c = 0; c < vd; ++c)
990 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
1000 "This method should be called when m == L2FaceValues::DoubleValued.");
1003 const int vd =
vdim;
1011 const int dof = i % nface_dofs;
1012 const int face = i / nface_dofs;
1013 const int idx1 = d_indices1[i];
1014 for (
int c = 0; c < vd; ++c)
1016 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
1018 const int idx2 = d_indices2[i];
1019 for (
int c = 0; c < vd; ++c)
1021 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(t?c:idx2, t?idx2:c);
1028 if (
nf==0) {
return; }
1044 const int vd =
vdim;
1052 const int offset = d_offsets[i];
1053 const int next_offset = d_offsets[i + 1];
1054 for (
int c = 0; c < vd; ++c)
1057 for (
int j = offset; j < next_offset; ++j)
1059 int idx_j = d_indices[j];
1060 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1062 d_y(t?c:i,t?i:c) += dof_value;
1072 const int vd =
vdim;
1081 const int offset = d_offsets[i];
1082 const int next_offset = d_offsets[i + 1];
1083 for (
int c = 0; c < vd; ++c)
1086 for (
int j = offset; j < next_offset; ++j)
1088 int idx_j = d_indices[j];
1089 bool isE1 = idx_j < dofs;
1090 idx_j = isE1 ? idx_j : idx_j - dofs;
1092 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1093 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1095 d_y(t?c:i,t?i:c) += dof_value;
1103 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1104 if (
nf==0) {
return; }
1116 const bool keep_nbr_block)
const
1124 const int iE1 = d_indices1[fdof];
1125 const int iE2 = d_indices2[fdof];
1126 AddNnz(iE1,I,nface_dofs);
1127 AddNnz(iE2,I,nface_dofs);
1133 const bool keep_nbr_block)
const
1139 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1144 const int f = fdof/nface_dofs;
1145 const int iF = fdof%nface_dofs;
1146 const int iE1 = d_indices1[
f*nface_dofs+iF];
1147 const int iE2 = d_indices2[
f*nface_dofs+iF];
1148 const int offset1 = AddNnz(iE1,I,nface_dofs);
1149 const int offset2 = AddNnz(iE2,I,nface_dofs);
1150 for (
int jF = 0; jF < nface_dofs; jF++)
1152 const int jE1 = d_indices1[
f*nface_dofs+jF];
1153 const int jE2 = d_indices2[
f*nface_dofs+jF];
1154 J[offset2+jF] = jE1;
1155 J[offset1+jF] = jE2;
1156 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1157 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1172 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1176 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1177 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1178 for (
int j = 0; j < nface_dofs; j++)
1180 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1181 for (
int i = 0; i < nface_dofs; i++)
1183 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1184 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1189 for (
int j = 0; j < nface_dofs; j++)
1191 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1192 for (
int i = 0; i < nface_dofs; i++)
1194 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1195 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1204 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1208 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1209 for (
int j = 0; j < nface_dofs; j++)
1211 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1212 for (
int i = 0; i < nface_dofs; i++)
1214 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1231 pfes->GetParMesh()->ExchangeFaceNbrData();
1240 MFEM_VERIFY(tfe != NULL &&
1243 "Only Gauss-Lobatto and Bernstein basis are supported in "
1244 "L2FaceRestriction.");
1245 if (
nf==0) {
return; }
1249 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1251 if (dof_reorder &&
nf > 0)
1257 if (el) {
continue; }
1258 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1264void L2FaceRestriction::ComputeScatterIndicesAndOffsets()
1268 for (
int i = 0; i <=
ndofs; ++i)
1278 MFEM_ASSERT(!face.IsShared(),
1279 "Unexpected shared face in L2FaceRestriction.");
1280 if ( face.IsOfFaceType(
type) )
1297 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1300 for (
int i = 1; i <=
ndofs; ++i)
1306void L2FaceRestriction::ComputeGatherIndices()
1314 MFEM_ASSERT(!face.IsShared(),
1315 "Unexpected shared face in L2FaceRestriction.");
1316 if ( face.IsOfFaceType(
type) )
1328 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1331 for (
int i =
ndofs; i > 0; --i)
1340 const int face_index)
1343 "This method should not be used on nonconforming coarse faces.");
1345 const int* elem_map = e2dTable.
GetJ();
1350 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1352 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1353 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1354 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1362 const int face_index)
1365 "This method should only be used on local faces.");
1367 const int* elem_map = e2dTable.
GetJ();
1376 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1381 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1382 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1383 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1391 const int face_index)
1395 "This method should only be used on shared faces.");
1408 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1411 orientation, dof1d, face_dof_elem1);
1412 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1413 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1414 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1423 const int face_index)
1426 "This method should only be used on boundary faces.");
1430 const int restriction_dof_elem2 =
face_dofs*face_index + d;
1437 const int face_index)
1440 "This method should not be used on nonconforming coarse faces.");
1442 const int* elem_map = e2dTable.
GetJ();
1447 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1449 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1450 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1451 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1459 const int face_index)
1462 "This method should only be used on local faces.");
1464 const int* elem_map = e2dTable.
GetJ();
1473 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1478 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1479 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1480 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1483 restriction_dof_elem2;
1489 EnsureNormalDerivativeRestriction();
1496 EnsureNormalDerivativeRestriction();
1500void L2FaceRestriction::EnsureNormalDerivativeRestriction()
const
1514 interp_config( fes.GetNFbyType(type) ),
1530 "Registering face as nonconforming even though it is not.");
1533 const int master_side =
1535 const int face_key = (master_side == 0 ? 1000 : 0) +
1540 Key key(ptMat, face_key);
1545 GetCoarseToFineInterpolation(face,ptMat);
1552 interp_config[face_index] = {master_side, itr->second.first};
1556const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1561 "The following interpolation operator is only implemented for"
1562 "lexicographic ordering.");
1564 "This method should not be called on conforming faces.")
1565 const
int face_id1 = face.element[0].local_face_id;
1566 const
int face_id2 = face.element[1].local_face_id;
1568 const
bool is_ghost_slave =
1569 face.element[0].conformity ==
Mesh::ElementConformity::Superset;
1570 const
int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1576 const
int face_dofs = trace_fe->GetDof();
1579 const auto dof_map = el->GetDofMap();
1584 isotr.SetIdentityTransformation(trace_fe->GetGeomType());
1585 isotr.SetPointMat(*ptMat);
1588 if ( trace_fe->GetGeomType()==
Geometry::SEGMENT && !is_ghost_slave )
1590 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1592 DenseMatrix native_interpolator(face_dofs,face_dofs);
1593 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1594 const int dim = trace_fe->GetDim()+1;
1595 const int dof1d = trace_fe->GetOrder()+1;
1597 for (
int i = 0; i < face_dofs; i++)
1599 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1601 if ( !is_ghost_slave )
1605 orientation, dof1d, li);
1607 for (
int j = 0; j < face_dofs; j++)
1610 if ( !is_ghost_slave )
1614 orientation, dof1d, lj);
1616 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1617 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1620 return interpolator;
1627 const int face_dofs = trace_fe->
GetDof();
1628 const int nc_size =
static_cast<int>(
interp_map.size());
1629 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1634 const int idx = val.second.first;
1635 const DenseMatrix &interpolator = *val.second.second;
1636 for (
int i = 0; i < face_dofs; i++)
1638 for (
int j = 0; j < face_dofs; j++)
1640 d_interp(i,j,idx) = interpolator(i,j);
1643 delete val.second.second;
1651 int num_nc_faces = 0;
1665 if ( config.is_non_conforming )
1679 interpolations(fes, f_ordering, type)
1681 if (!build) {
return; }
1686 ComputeScatterIndicesAndOffsets();
1688 ComputeGatherIndices();
1708 if (
nf == 0) {
return; }
1711 const int vd =
vdim;
1714 const int num_nc_faces = nc_interp_config.Size();
1715 if ( num_nc_faces == 0 ) {
return; }
1716 auto interp_config_ptr = nc_interp_config.Read();
1719 nface_dofs, nface_dofs, nc_size);
1720 static constexpr int max_nd = 16*16;
1721 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1722 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1724 MFEM_SHARED
real_t dof_values[max_nd];
1728 const int master_side = conf.master_side;
1729 const int interp_index = conf.index;
1730 const int face = conf.face_index;
1731 for (int c = 0; c < vd; ++c)
1733 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1735 dof_values[dof] = d_y(dof, c, master_side, face);
1738 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1741 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1743 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1745 d_y(dof_out, c, master_side, face) = res;
1755 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1757 DoubleValuedNonconformingMult(x, y);
1759 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1761 DoubleValuedConformingMult(x, y);
1765 SingleValuedConformingMult(x, y);
1769void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1773 m == L2FaceValues::SingleValued,
1774 "This method should be called when m == L2FaceValues::SingleValued.");
1775 if (x_interp.Size()==0)
1777 x_interp.SetSize(x.
Size());
1780 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1784void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1788 const int nface_dofs = face_dofs;
1789 const int vd = vdim;
1791 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1792 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1793 const int num_nc_faces = nc_interp_config.Size();
1794 if ( num_nc_faces == 0 ) {
return; }
1795 auto interp_config_ptr = nc_interp_config.Read();
1796 auto interpolators = interpolations.GetInterpolators().Read();
1797 const int nc_size = interpolations.GetNumInterpolators();
1798 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1799 static constexpr int max_nd = 16*16;
1800 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1801 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1803 MFEM_SHARED
real_t dof_values[max_nd];
1806 const int interp_index = conf.
index;
1811 for (int c = 0; c < vd; ++c)
1813 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1815 dof_values[dof] = d_x(dof, c, face);
1818 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1821 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1823 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1825 d_x(dof_out, c, face) = res;
1833void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1837 m == L2FaceValues::DoubleValued,
1838 "This method should be called when m == L2FaceValues::DoubleValued.");
1839 if (x_interp.Size()==0)
1841 x_interp.SetSize(x.
Size());
1844 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1847void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
1851 const int nface_dofs = face_dofs;
1852 const int vd = vdim;
1855 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1856 const int num_nc_faces = nc_interp_config.Size();
1857 if ( num_nc_faces == 0 ) {
return; }
1858 auto interp_config_ptr = nc_interp_config.Read();
1859 auto interpolators = interpolations.GetInterpolators().Read();
1860 const int nc_size = interpolations.GetNumInterpolators();
1861 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1862 static constexpr int max_nd = 16*16;
1863 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1864 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1866 MFEM_SHARED
real_t dof_values[max_nd];
1869 const int interp_index = conf.
index;
1874 for (int c = 0; c < vd; ++c)
1876 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1878 dof_values[dof] = d_x(dof, c, master_side, face);
1881 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1884 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1886 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1888 d_x(dof_out, c, master_side, face) = res;
1899 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1900 if (nf==0) {
return; }
1901 if (type==FaceType::Interior)
1903 if ( m==L2FaceValues::DoubleValued )
1905 DoubleValuedNonconformingTransposeInterpolation(x);
1906 DoubleValuedConformingAddMultTranspose(x_interp, y);
1908 else if ( m==L2FaceValues::SingleValued )
1910 SingleValuedNonconformingTransposeInterpolation(x);
1911 SingleValuedConformingAddMultTranspose(x_interp, y);
1916 if ( m==L2FaceValues::DoubleValued )
1918 DoubleValuedConformingAddMultTranspose(x, y);
1920 else if ( m==L2FaceValues::SingleValued )
1922 SingleValuedConformingAddMultTranspose(x, y);
1927void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const
1929 if (nf==0) {
return; }
1930 if (type==FaceType::Interior)
1932 if ( m==L2FaceValues::DoubleValued )
1934 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
1935 DoubleValuedConformingAddMultTranspose(x, y);
1937 else if ( m==L2FaceValues::SingleValued )
1939 SingleValuedNonconformingTransposeInterpolationInPlace(x);
1940 SingleValuedConformingAddMultTranspose(x, y);
1945 if ( m==L2FaceValues::DoubleValued )
1947 DoubleValuedConformingAddMultTranspose(x, y);
1949 else if ( m==L2FaceValues::SingleValued )
1951 SingleValuedConformingAddMultTranspose(x, y);
1957 const bool keep_nbr_block)
const
1959 const int nface_dofs = face_dofs;
1960 auto d_indices1 = scatter_indices1.Read();
1961 auto d_indices2 = scatter_indices2.Read();
1963 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1965 const int iE1 = d_indices1[fdof];
1966 const int iE2 = d_indices2[fdof];
1967 AddNnz(iE1,I,nface_dofs);
1968 AddNnz(iE2,I,nface_dofs);
1972void NCL2FaceRestriction::FillJAndData(
const Vector &fea_data,
1974 const bool keep_nbr_block)
const
1976 const int nface_dofs = face_dofs;
1977 auto d_indices1 = scatter_indices1.Read();
1978 auto d_indices2 = scatter_indices2.Read();
1980 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
1983 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1984 auto interpolators = interpolations.GetInterpolators().Read();
1985 const int nc_size = interpolations.GetNumInterpolators();
1986 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1987 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1989 const int f = fdof/nface_dofs;
1992 const int interp_index = conf.
index;
1993 const int iF = fdof%nface_dofs;
1994 const int iE1 = d_indices1[
f*nface_dofs+iF];
1995 const int iE2 = d_indices2[
f*nface_dofs+iF];
1996 const int offset1 = AddNnz(iE1,I,nface_dofs);
1997 const int offset2 = AddNnz(iE2,I,nface_dofs);
1998 for (
int jF = 0; jF < nface_dofs; jF++)
2000 const int jE1 = d_indices1[
f*nface_dofs+jF];
2001 const int jE2 = d_indices2[
f*nface_dofs+jF];
2002 J[offset2+jF] = jE1;
2003 J[offset1+jF] = jE2;
2008 for (
int kF = 0; kF < nface_dofs; kF++)
2010 val1 += mat_fea(kF,iF,0,
f) * d_interp(kF, jF, interp_index);
2011 val2 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,1,
f);
2016 for (
int kF = 0; kF < nface_dofs; kF++)
2018 val1 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,0,
f);
2019 val2 += mat_fea(kF,iF,1,
f) * d_interp(kF, jF, interp_index);
2024 val1 = mat_fea(jF,iF,0,
f);
2025 val2 = mat_fea(jF,iF,1,
f);
2027 Data[offset2+jF] = val1;
2028 Data[offset1+jF] = val2;
2033void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2038 const int nface_dofs = face_dofs;
2039 const int nelem_dofs = elem_dofs;
2041 if (m==L2FaceValues::DoubleValued)
2043 auto d_indices1 = scatter_indices1.Read();
2044 auto d_indices2 = scatter_indices2.Read();
2045 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
2047 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2048 auto interpolators = interpolations.GetInterpolators().Read();
2049 const int nc_size = interpolations.GetNumInterpolators();
2050 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2055 const int interp_index = conf.
index;
2056 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
2057 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
2058 for (
int j = 0; j < nface_dofs; j++)
2060 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
2061 for (
int i = 0; i < nface_dofs; i++)
2063 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
2067 for (int k = 0; k < nface_dofs; k++)
2069 for (int l = 0; l < nface_dofs; l++)
2071 val += d_interp(l, j, interp_index)
2073 * d_interp(k, i, interp_index);
2079 val = mat_fea(i,j,0,
f);
2086 for (
int j = 0; j < nface_dofs; j++)
2088 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
2089 for (
int i = 0; i < nface_dofs; i++)
2091 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
2093 if ( conf.is_non_conforming && master_side==1 )
2095 for (
int k = 0; k < nface_dofs; k++)
2097 for (
int l = 0; l < nface_dofs; l++)
2099 val += d_interp(l, j, interp_index)
2101 * d_interp(k, i, interp_index);
2107 val = mat_fea(i,j,1,
f);
2117 auto d_indices = scatter_indices1.Read();
2118 auto mat_fea =
Reshape(fea_data.Read(), nface_dofs, nface_dofs, nf);
2119 auto mat_ea =
Reshape(ea_data.ReadWrite(), nelem_dofs, nelem_dofs, ne);
2120 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2121 auto interpolators = interpolations.GetInterpolators().Read();
2122 const int nc_size = interpolations.GetNumInterpolators();
2123 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2128 const int interp_index = conf.
index;
2129 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
2130 for (
int j = 0; j < nface_dofs; j++)
2132 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
2133 for (
int i = 0; i < nface_dofs; i++)
2135 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
2139 for (int k = 0; k < nface_dofs; k++)
2141 for (int l = 0; l < nface_dofs; l++)
2143 val += d_interp(l, j, interp_index)
2145 * d_interp(k, i, interp_index);
2151 val = mat_fea(i,j,
f);
2168 return internal::ToLexOrdering2D(face_id, size1d,
index);
2170 return internal::ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2172 MFEM_ABORT(
"Unsupported dimension.");
2177void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets()
2179 Mesh &mesh = *fes.GetMesh();
2182 for (
int i = 0; i <= ndofs; ++i)
2184 gather_offsets[i] = 0;
2189 for (
int f = 0;
f < fes.GetNF(); ++
f)
2191 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2192 if ( face.IsNonconformingCoarse() )
2198 else if ( type==FaceType::Interior && face.IsInterior() )
2200 SetFaceDofsScatterIndices1(face,f_ind);
2201 if ( m==L2FaceValues::DoubleValued )
2203 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2205 if ( face.IsConforming() )
2207 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2211 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2215 else if ( type==FaceType::Boundary && face.IsBoundary() )
2217 SetFaceDofsScatterIndices1(face,f_ind);
2218 if ( m==L2FaceValues::DoubleValued )
2220 SetBoundaryDofsScatterIndices2(face,f_ind);
2222 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2226 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2227 (type==FaceType::Interior?
"interior" :
"boundary") <<
2228 " faces: " << f_ind <<
" vs " << nf );
2231 for (
int i = 1; i <= ndofs; ++i)
2233 gather_offsets[i] += gather_offsets[i - 1];
2237 interpolations.LinearizeInterpolatorMapIntoVector();
2238 interpolations.InitializeNCInterpConfig();
2241void NCL2FaceRestriction::ComputeGatherIndices()
2243 Mesh &mesh = *fes.GetMesh();
2246 for (
int f = 0;
f < fes.GetNF(); ++
f)
2248 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2249 MFEM_ASSERT(!face.IsShared(),
2250 "Unexpected shared face in NCL2FaceRestriction.");
2251 if ( face.IsNonconformingCoarse() )
2257 else if ( face.IsOfFaceType(type) )
2259 SetFaceDofsGatherIndices1(face,f_ind);
2260 if ( m==L2FaceValues::DoubleValued &&
2261 type==FaceType::Interior &&
2264 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2269 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2270 (type==FaceType::Interior?
"interior" :
"boundary") <<
2271 " faces: " << f_ind <<
" vs " << nf );
2274 for (
int i = ndofs; i > 0; --i)
2276 gather_offsets[i] = gather_offsets[i - 1];
2278 gather_offsets[0] = 0;
2281L2InterfaceFaceRestriction::L2InterfaceFaceRestriction(
2286 ordering(ordering_),
2288 nfaces(fes.GetNFbyType(type)),
2289 vdim(fes.GetVDim()),
2291 face_dofs(nfaces > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
2292 nfdofs(face_dofs*nfaces),
2293 ndofs(fes.GetNDofs())
2319 const int vd =
vdim;
2328 const int j = map[i];
2329 for (
int c = 0; c < vd; ++c)
2331 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
2341 const int vd =
vdim;
2351 const int j = map[i];
2352 for (
int c = 0; c < vd; ++c)
2354 d_y(t?c:j, t?j:c) = d_x(i % nd, c, i / nd);
2376 Vector &gf_face_nbr = x_gf->FaceNbrData();
2377 if (gf_face_nbr.
Size() == 0) { x_gf->ExchangeFaceNbrData(); }
2379 return Vector(gf_face_nbr, 0, gf_face_nbr.
Size());
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
@ GaussLobatto
Closed type.
@ Positive
Bernstein polynomials.
Data type dense matrix using column-major storage.
ElementRestriction(const FiniteElementSpace &, ElementDofOrdering)
const FiniteElementSpace & fes
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
void AbsMult(const Vector &x, Vector &y) const override
Compute Mult without applying signs based on DOF orientations.
void FillSparseMatrix(const Vector &mat_ea, SparseMatrix &mat) const
Fill a Sparse Matrix with Element Matrices.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
void MultLeftInverse(const Vector &x, Vector &y) const
void BooleanMask(Vector &y) const
Fills the E-vector y with boolean values 0.0 and 1.0 such that each each entry of the L-vector is uni...
void AbsMultTranspose(const Vector &x, Vector &y) const override
Compute MultTranspose without applying signs based on DOF orientations.
int FillI(SparseMatrix &mat) const
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
const Table & GetFaceToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each face in the m...
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...
const FiniteElement * GetTypicalTraceElement() const
Return a "typical" trace element.
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Mesh * GetMesh() const
Returns the mesh.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Abstract class for all finite elements.
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
virtual void GetFaceMap(const int face_id, Array< int > &face_map) const
Return the mapping from lexicographic face DOFs to lexicographic element DOFs for the given local fac...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
std::pair< const DenseMatrix *, int > Key
const Array< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void RegisterFaceCoarseToFineInterpolation(const Mesh::FaceInformation &face, int face_index)
Register the face with face and index face_index as a conforming face for the interpolation of the de...
int GetNumInterpolators() const
Return the total number of interpolators.
Array< NCInterpConfig > nc_interp_config
InterpolationManager()=delete
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...
void InitializeNCInterpConfig()
void LinearizeInterpolatorMapIntoVector()
Transform the interpolation matrix map into a contiguous memory structure.
const FiniteElementSpace & fes
const ElementDofOrdering ordering
Array< InterpConfig > interp_config
void RegisterFaceConformingInterpolation(const Mesh::FaceInformation &face, int face_index)
Register the face with face and index face_index as a conforming face for the interpolation of the de...
L2ElementRestriction(const FiniteElementSpace &)
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
void FillI(SparseMatrix &mat) const
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
Operator that extracts Face degrees of freedom for L2 spaces.
void PermuteAndSetFaceDofsGatherIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the gathering indices of elem2 for the interior face described by the face....
virtual void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const
Fill the I array of SparseMatrix corresponding to the sparsity pattern given by this L2FaceRestrictio...
Array< int > scatter_indices2
void SingleValuedConformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with co...
L2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an L2FaceRestriction.
void NormalDerivativeMult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
void NormalDerivativeAddMultTranspose(const Vector &x, Vector &y) const override
Add the face reference-normal derivative degrees of freedom in x to the element degrees of freedom in...
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
void SingleValuedConformingAddMultTranspose(const Vector &x, Vector &y) const
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector. Should only be used with con...
std::unique_ptr< L2NormalDerivativeFaceRestriction > normal_deriv_restr
void PermuteAndSetSharedFaceDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the scattering indices of elem2 for the shared face described by the face....
void CheckFESpace()
Verify that L2FaceRestriction is built from an L2 FESpace.
Array< int > gather_offsets
virtual void DoubleValuedConformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with co...
void PermuteAndSetFaceDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the scattering indices of elem2, and increment the offsets for the face described by ...
Array< int > scatter_indices1
const FiniteElementSpace & fes
void SetBoundaryDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem2 for the boundary face described by the face.
void SetFaceDofsScatterIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem1, and increment the offsets for the face described by the face....
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
const ElementDofOrdering ordering
void DoubleValuedConformingAddMultTranspose(const Vector &x, Vector &y) const
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector. Should only be used with con...
virtual void FillJAndData(const Vector &fea_data, SparseMatrix &mat, const bool keep_nbr_block=false) const
Fill the J and Data arrays of the SparseMatrix corresponding to the sparsity pattern given by this L2...
Array< int > gather_indices
virtual void AddFaceMatricesToElementMatrices(const Vector &fea_data, Vector &ea_data) const
This methods adds the DG face matrices to the element matrices.
const int face_dofs
Number of dofs on each face.
const int ndofs
Number of dofs in the space (L-vector size)
const int nfdofs
Total number of dofs on the faces (E-vector size)
const FiniteElementSpace & fes
The finite element space.
Array< int > gather_map
Gather map.
const int vdim
vdim of the space
const int nfaces
Number of faces of the requested type.
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
const Array< int > & GatherMap() const override
Low-level access to the underlying gather map.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
const FaceType type
Face type (interior or boundary)
const bool byvdim
DOF ordering (by nodes or by vdim)
Class to compute face normal derivatives (in reference coordinate) of an L2 grid function (used inter...
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
int Dimension() const
Dimension of the reference space used within the elements.
FaceInformation GetFaceInformation(int f) const
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
InterpolationManager interpolations
virtual void DoubleValuedNonconformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with no...
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs.
NCL2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an NCL2FaceRestriction, this is a specialization of a L2FaceRestriction for nonconforming ...
Class for standard nodal finite elements.
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
Abstract parallel finite element space.
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
Class for parallel grid function.
void ExchangeFaceNbrData()
int * ReadWriteI(bool on_dev=true)
int * WriteJ(bool on_dev=true)
Memory< int > & GetMemoryI()
int * WriteI(bool on_dev=true)
Memory< int > & GetMemoryJ()
Memory< real_t > & GetMemoryData()
real_t * WriteData(bool on_dev=true)
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
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 void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void SetSize(int s)
Resize the vector to size s.
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
int index(int i, int j, int nx, int ny)
real_t f(const Vector &p)
Vector GetLVectorFaceNbrData(const FiniteElementSpace &fes, const Vector &x, FaceType ftype)
Return the face-neighbor data given the L-vector x.
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
int ToLexOrdering(const int dim, const int face_id, const int size1d, const int index)
Convert a dof face index from Native ordering to lexicographic ordering for quads and hexes.
void forall_2D(int N, int X, int Y, lambda &&body)
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
int PermuteFaceL2(const int dim, const int face_id1, const int face_id2, const int orientation, const int size1d, const int index)
Compute the dof face index of elem2 corresponding to the given dof face index.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
void forall(int N, lambda &&body)
uint32_t is_non_conforming
uint32_t is_non_conforming