15 #include "../general/forall.hpp"
33 ndofs(fes.GetNDofs()),
34 dof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
44 const int *dof_map = NULL;
45 if (dof_reorder &&
ne > 0)
47 for (
int e = 0; e <
ne; ++e)
53 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
59 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
63 const int* element_map = e2dTable.
GetJ();
65 for (
int i = 0; i <=
ndofs; ++i)
69 for (
int e = 0; e <
ne; ++e)
71 for (
int d = 0; d <
dof; ++d)
73 const int sgid = element_map[dof*e + d];
74 const int gid = (sgid >= 0) ? sgid : -1 - sgid;
79 for (
int i = 1; i <=
ndofs; ++i)
84 for (
int e = 0; e <
ne; ++e)
86 for (
int d = 0; d <
dof; ++d)
88 const int sdid = dof_reorder ? dof_map[d] : 0;
89 const int did = (!dof_reorder)?d:(sdid >= 0 ? sdid : -1-sdid);
90 const int sgid = element_map[dof*e + did];
91 const int gid = (sgid >= 0) ? sgid : -1-sgid;
92 const int lid = dof*e + d;
93 const bool plus = (sgid >= 0 && sdid >= 0) || (sgid < 0 && sdid < 0);
100 for (
int i =
ndofs; i > 0; --i)
116 MFEM_FORALL(i,
dof*
ne,
118 const int gid = d_gather_map[i];
119 const bool plus = gid >= 0;
120 const int j = plus ? gid : -1-gid;
121 for (
int c = 0; c < vd; ++c)
123 const double dof_value = d_x(t?c:j, t?j:c);
124 d_y(i % nd, c, i / nd) = plus ? dof_value : -dof_value;
139 MFEM_FORALL(i,
dof*
ne,
141 const int gid = d_gather_map[i];
142 const int j = gid >= 0 ? gid : -1-gid;
143 for (
int c = 0; c < vd; ++c)
145 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
160 MFEM_FORALL(i,
ndofs,
162 const int offset = d_offsets[i];
163 const int next_offset = d_offsets[i + 1];
164 for (
int c = 0; c < vd; ++c)
166 double dof_value = 0;
167 for (
int j = offset; j < next_offset; ++j)
169 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
170 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
171 -d_x(idx_j % nd, c, idx_j / nd));
173 d_y(t?c:i,t?i:c) = dof_value;
188 MFEM_FORALL(i,
ndofs,
190 const int offset = d_offsets[i];
191 const int next_offset = d_offsets[i + 1];
192 for (
int c = 0; c < vd; ++c)
194 double dof_value = 0;
195 for (
int j = offset; j < next_offset; ++j)
197 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
198 dof_value += d_x(idx_j % nd, c, idx_j / nd);
200 d_y(t?c:i,t?i:c) = dof_value;
215 MFEM_FORALL(i,
ndofs,
217 const int next_offset = d_offsets[i + 1];
218 for (
int c = 0; c < vd; ++c)
220 double dof_value = 0;
221 const int j = next_offset - 1;
222 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
223 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
224 -d_x(idx_j % nd, c, idx_j / nd);
225 d_y(t?c:i,t?i:c) = dof_value;
244 for (
int i = 0; i <
ndofs; ++i)
246 const int offset = d_offsets[i];
247 const int next_offset = d_offsets[i+1];
248 for (
int c = 0; c < vd; ++c)
250 for (
int j = offset; j < next_offset; ++j)
252 const int idx_j = d_indices[j];
253 if (d_x(t?c:i,t?i:c))
255 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
259 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
260 d_x(t?c:i,t?i:c) = 1;
271 const int nnz =
FillI(mat);
277 static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
278 const int *nbr_elts,
const int nbrNbElts)
281 int min_el = INT_MAX;
282 for (
int i = 0; i < nbElts; i++)
284 const int e_i = my_elts[i];
285 if (e_i >= min_el) {
continue; }
286 for (
int j = 0; j < nbrNbElts; j++)
288 if (e_i==nbr_elts[j])
300 static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
308 static constexpr
int Max = MaxNbNbr;
309 const int all_dofs =
ndofs;
311 const int elt_dofs =
dof;
316 MFEM_FORALL(i_L, vd*all_dofs+1,
322 for (
int i = 0; i < elt_dofs; i++)
325 const int i_gm = e*elt_dofs + i;
326 const int i_L = d_gather_map[i_gm];
327 const int i_offset = d_offsets[i_L];
328 const int i_next_offset = d_offsets[i_L+1];
329 const int i_nbElts = i_next_offset - i_offset;
332 "The connectivity of this mesh is beyond the max, increase the "
333 "MaxNbNbr variable to comply with your mesh.");
334 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
336 const int i_E = d_indices[i_offset+e_i];
337 i_elts[e_i] = i_E/elt_dofs;
339 for (
int j = 0; j < elt_dofs; j++)
341 const int j_gm = e*elt_dofs + j;
342 const int j_L = d_gather_map[j_gm];
343 const int j_offset = d_offsets[j_L];
344 const int j_next_offset = d_offsets[j_L+1];
345 const int j_nbElts = j_next_offset - j_offset;
346 if (i_nbElts == 1 || j_nbElts == 1)
348 GetAndIncrementNnzIndex(i_L, I);
353 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
355 const int j_E = d_indices[j_offset+e_j];
356 const int elt = j_E/elt_dofs;
359 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
362 GetAndIncrementNnzIndex(i_L, I);
370 const int nTdofs = vd*all_dofs;
372 for (
int i = 0; i < nTdofs; i++)
374 const int nnz = h_I[i];
386 static constexpr
int Max = MaxNbNbr;
387 const int all_dofs =
ndofs;
389 const int elt_dofs =
dof;
396 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
399 for (
int i = 0; i < elt_dofs; i++)
403 const int i_gm = e*elt_dofs + i;
404 const int i_L = d_gather_map[i_gm];
405 const int i_offset = d_offsets[i_L];
406 const int i_next_offset = d_offsets[i_L+1];
407 const int i_nbElts = i_next_offset - i_offset;
410 "The connectivity of this mesh is beyond the max, increase the "
411 "MaxNbNbr variable to comply with your mesh.");
412 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
414 const int i_E = d_indices[i_offset+e_i];
415 i_elts[e_i] = i_E/elt_dofs;
416 i_B[e_i] = i_E%elt_dofs;
418 for (
int j = 0; j < elt_dofs; j++)
420 const int j_gm = e*elt_dofs + j;
421 const int j_L = d_gather_map[j_gm];
422 const int j_offset = d_offsets[j_L];
423 const int j_next_offset = d_offsets[j_L+1];
424 const int j_nbElts = j_next_offset - j_offset;
425 if (i_nbElts == 1 || j_nbElts == 1)
427 const int nnz = GetAndIncrementNnzIndex(i_L, I);
429 Data[nnz] = mat_ea(j,i,e);
435 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
437 const int j_E = d_indices[j_offset+e_j];
438 const int elt = j_E/elt_dofs;
440 j_B[e_j] = j_E%elt_dofs;
442 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
446 for (
int k = 0; k < i_nbElts; k++)
448 const int e_i = i_elts[k];
449 const int i_Bloc = i_B[k];
450 for (
int l = 0; l < j_nbElts; l++)
452 const int e_j = j_elts[l];
453 const int j_Bloc = j_B[l];
456 val += mat_ea(j_Bloc, i_Bloc, e_i);
460 const int nnz = GetAndIncrementNnzIndex(i_L, I);
471 const int size = vd*all_dofs;
472 for (
int i = 0; i < size; i++)
474 h_I[size-i] = h_I[size-(i+1)];
483 ndof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
484 ndofs(fes.GetNDofs())
487 width = vdim*ne*ndof;
494 const bool t = byvdim;
495 auto d_x =
Reshape(x.
Read(), t?vd:ndofs, t?ndofs:vd);
497 MFEM_FORALL(i, ndofs,
500 const int dof = idx % nd;
501 const int e = idx / nd;
502 for (
int c = 0; c < vd; ++c)
504 d_y(dof, c, e) = d_x(t?c:idx, t?idx:c);
513 const bool t = byvdim;
516 MFEM_FORALL(i, ndofs,
519 const int dof = idx % nd;
520 const int e = idx / nd;
521 for (
int c = 0; c < vd; ++c)
523 d_y(t?c:idx,t?idx:c) = d_x(dof, c, e);
530 const int elem_dofs = ndof;
533 const int isize = mat.
Height() + 1;
534 const int interior_dofs = ne*elem_dofs*vd;
535 MFEM_FORALL(dof, isize,
537 I[dof] = dof<interior_dofs ? elem_dofs : 0;
541 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
550 const int elem_dofs = ndof;
555 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
556 MFEM_FORALL(iE, ne*elem_dofs*vd,
558 const int offset = AddNnz(iE,I,elem_dofs);
559 const int e = iE/elem_dofs;
560 const int i = iE%elem_dofs;
561 for (
int j = 0; j < elem_dofs; j++)
563 J[offset+j] = e*elem_dofs+j;
564 Data[offset+j] = mat_ea(j,i,e);
583 face_map[0] = dof1d-1;
591 for (
int i = 0; i < dof1d; ++i)
597 for (
int i = 0; i < dof1d; ++i)
599 face_map[i] = dof1d-1 + i*dof1d;
603 for (
int i = 0; i < dof1d; ++i)
605 face_map[i] = (dof1d-1)*dof1d + i;
609 for (
int i = 0; i < dof1d; ++i)
611 face_map[i] = i*dof1d;
620 for (
int i = 0; i < dof1d; ++i)
622 for (
int j = 0; j < dof1d; ++j)
624 face_map[i+j*dof1d] = i + j*dof1d;
629 for (
int i = 0; i < dof1d; ++i)
631 for (
int j = 0; j < dof1d; ++j)
633 face_map[i+j*dof1d] = i + j*dof1d*dof1d;
638 for (
int i = 0; i < dof1d; ++i)
640 for (
int j = 0; j < dof1d; ++j)
642 face_map[i+j*dof1d] = dof1d-1 + i*dof1d + j*dof1d*dof1d;
647 for (
int i = 0; i < dof1d; ++i)
649 for (
int j = 0; j < dof1d; ++j)
651 face_map[i+j*dof1d] = (dof1d-1)*dof1d + i + j*dof1d*dof1d;
656 for (
int i = 0; i < dof1d; ++i)
658 for (
int j = 0; j < dof1d; ++j)
660 face_map[i+j*dof1d] = i*dof1d + j*dof1d*dof1d;
665 for (
int i = 0; i < dof1d; ++i)
667 for (
int j = 0; j < dof1d; ++j)
669 face_map[i+j*dof1d] = (dof1d-1)*dof1d*dof1d + i + j*dof1d;
683 nf(fes.GetNFbyType(type)),
686 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
687 elem_dofs(fes.GetFE(0)->GetDof()),
688 nfdofs(nf*face_dofs),
689 ndofs(fes.GetNDofs()),
690 scatter_indices(nf*face_dofs),
691 gather_offsets(ndofs+1),
692 gather_indices(nf*face_dofs),
697 if (!build) {
return; }
698 if (
nf==0) {
return; }
702 ComputeScatterIndicesAndOffsets(e_ordering, type);
704 ComputeGatherIndices(e_ordering,type);
715 if (
nf==0) {
return; }
725 const int idx = d_indices[i];
726 const int dof = i % nface_dofs;
727 const int face = i / nface_dofs;
728 for (
int c = 0; c < vd; ++c)
730 d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
737 if (
nf==0) {
return; }
746 MFEM_FORALL(i,
ndofs,
748 const int offset = d_offsets[i];
749 const int next_offset = d_offsets[i + 1];
750 for (
int c = 0; c < vd; ++c)
752 double dof_value = 0;
753 for (
int j = offset; j < next_offset; ++j)
755 const int idx_j = d_indices[j];
756 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
758 d_y(t?c:i,t?i:c) += dof_value;
770 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
772 pfes->GetParMesh()->ExchangeFaceNbrData();
781 MFEM_VERIFY(tfe != NULL &&
784 "Only Gauss-Lobatto and Bernstein basis are supported in "
785 "H1FaceRestriction.");
789 if (dof_reorder &&
nf > 0)
796 if (el) {
continue; }
797 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
803 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
808 void H1FaceRestriction::ComputeScatterIndicesAndOffsets(
815 for (
int i = 0; i <=
ndofs; ++i)
825 if ( face.IsNonconformingCoarse() )
831 else if ( face.IsOfFaceType(type) )
837 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
840 for (
int i = 1; i <=
ndofs; ++i)
846 void H1FaceRestriction::ComputeGatherIndices(
857 if ( face.IsNonconformingCoarse() )
863 else if ( face.IsOfFaceType(type) )
869 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
872 for (
int i =
ndofs; i > 0; --i)
881 const int face_index,
885 "This method should not be used on nonconforming coarse faces.");
887 "FaceRestriction used on degenerated mesh.");
893 const int* elem_map = e2dTable.
GetJ();
901 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
903 const int nat_volume_dof =
face_map[face_dof];
904 const int volume_dof = (!dof_reorder)?
906 dof_map[nat_volume_dof];
907 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
908 const int restriction_dof = face_dofs*face_index + face_dof;
916 const int face_index,
920 "This method should not be used on nonconforming coarse faces.");
926 const int* elem_map = e2dTable.
GetJ();
934 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
936 const int nat_volume_dof =
face_map[face_dof];
937 const int volume_dof = (!dof_reorder)?nat_volume_dof:dof_map[nat_volume_dof];
938 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
939 const int restriction_dof = face_dofs*face_index + face_dof;
944 static int ToLexOrdering2D(
const int face_id,
const int size1d,
const int i)
946 if (face_id==2 || face_id==3)
956 static int PermuteFace2D(
const int face_id1,
const int face_id2,
957 const int orientation,
958 const int size1d,
const int index)
962 if (face_id1==2 || face_id1==3)
964 new_index = size1d-1-
index;
973 new_index = size1d-1-new_index;
975 return ToLexOrdering2D(face_id2, size1d, new_index);
978 static int ToLexOrdering3D(
const int face_id,
const int size1d,
const int i,
981 if (face_id==2 || face_id==1 || face_id==5)
985 else if (face_id==3 || face_id==4)
987 return (size1d-1-i) + j*size1d;
991 return i + (size1d-1-j)*size1d;
995 static int PermuteFace3D(
const int face_id1,
const int face_id2,
996 const int orientation,
997 const int size1d,
const int index)
999 int i=0, j=0, new_i=0, new_j=0;
1003 if (face_id1==3 || face_id1==4)
1007 else if (face_id1==0)
1012 switch (orientation)
1024 new_j = (size1d-1-i);
1027 new_i = (size1d-1-i);
1031 new_i = (size1d-1-i);
1032 new_j = (size1d-1-j);
1035 new_i = (size1d-1-j);
1036 new_j = (size1d-1-i);
1039 new_i = (size1d-1-j);
1044 new_j = (size1d-1-j);
1047 return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
1052 const int face_id2,
const int orientation,
1053 const int size1d,
const int index)
1060 return PermuteFace2D(face_id1, face_id2, orientation, size1d, index);
1062 return PermuteFace3D(face_id1, face_id2, orientation, size1d, index);
1064 MFEM_ABORT(
"Unsupported dimension.");
1075 nf(fes.GetNFbyType(type)),
1077 vdim(fes.GetVDim()),
1080 fes.GetTraceElement(0, fes.
GetMesh()->GetFaceBaseGeometry(0))->GetDof()
1082 elem_dofs(fes.GetFE(0)->GetDof()),
1083 nfdofs(nf*face_dofs),
1084 ndofs(fes.GetNDofs()),
1087 scatter_indices1(nf*face_dofs),
1089 gather_offsets(ndofs+1),
1095 if (!build) {
return; }
1099 ComputeScatterIndicesAndOffsets(e_ordering,type);
1101 ComputeGatherIndices(e_ordering, type);
1116 "This method should be called when m == L2FaceValues::SingleValued.");
1119 const int vd =
vdim;
1126 const int dof = i % nface_dofs;
1127 const int face = i / nface_dofs;
1128 const int idx1 = d_indices1[i];
1129 for (
int c = 0; c < vd; ++c)
1131 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
1141 "This method should be called when m == L2FaceValues::DoubleValued.");
1144 const int vd =
vdim;
1152 const int dof = i % nface_dofs;
1153 const int face = i / nface_dofs;
1154 const int idx1 = d_indices1[i];
1155 for (
int c = 0; c < vd; ++c)
1157 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
1159 const int idx2 = d_indices2[i];
1160 for (
int c = 0; c < vd; ++c)
1162 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(t?c:idx2, t?idx2:c);
1169 if (
nf==0) {
return; }
1185 const int vd =
vdim;
1191 MFEM_FORALL(i,
ndofs,
1193 const int offset = d_offsets[i];
1194 const int next_offset = d_offsets[i + 1];
1195 for (
int c = 0; c < vd; ++c)
1197 double dof_value = 0;
1198 for (
int j = offset; j < next_offset; ++j)
1200 int idx_j = d_indices[j];
1201 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1203 d_y(t?c:i,t?i:c) += dof_value;
1213 const int vd =
vdim;
1220 MFEM_FORALL(i,
ndofs,
1222 const int offset = d_offsets[i];
1223 const int next_offset = d_offsets[i + 1];
1224 for (
int c = 0; c < vd; ++c)
1226 double dof_value = 0;
1227 for (
int j = offset; j < next_offset; ++j)
1229 int idx_j = d_indices[j];
1230 bool isE1 = idx_j < dofs;
1231 idx_j = isE1 ? idx_j : idx_j - dofs;
1233 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1234 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1236 d_y(t?c:i,t?i:c) += dof_value;
1243 if (
nf==0) {
return; }
1255 const bool keep_nbr_block)
const
1261 MFEM_FORALL(fdof,
nf*nface_dofs,
1263 const int iE1 = d_indices1[fdof];
1264 const int iE2 = d_indices2[fdof];
1265 AddNnz(iE1,I,nface_dofs);
1266 AddNnz(iE2,I,nface_dofs);
1272 const bool keep_nbr_block)
const
1278 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1281 MFEM_FORALL(fdof,
nf*nface_dofs,
1283 const int f = fdof/nface_dofs;
1284 const int iF = fdof%nface_dofs;
1285 const int iE1 = d_indices1[f*nface_dofs+iF];
1286 const int iE2 = d_indices2[f*nface_dofs+iF];
1287 const int offset1 = AddNnz(iE1,I,nface_dofs);
1288 const int offset2 = AddNnz(iE2,I,nface_dofs);
1289 for (
int jF = 0; jF < nface_dofs; jF++)
1291 const int jE1 = d_indices1[f*nface_dofs+jF];
1292 const int jE2 = d_indices2[f*nface_dofs+jF];
1293 J[offset2+jF] = jE1;
1294 J[offset1+jF] = jE2;
1295 Data[offset2+jF] = mat_fea(jF,iF,0,f);
1296 Data[offset1+jF] = mat_fea(jF,iF,1,f);
1311 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1315 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1316 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1317 for (
int j = 0; j < nface_dofs; j++)
1319 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1320 for (
int i = 0; i < nface_dofs; i++)
1322 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1323 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1328 for (
int j = 0; j < nface_dofs; j++)
1330 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1331 for (
int i = 0; i < nface_dofs; i++)
1333 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1334 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1343 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1347 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1348 for (
int j = 0; j < nface_dofs; j++)
1350 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1351 for (
int i = 0; i < nface_dofs; i++)
1353 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1368 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
1370 pfes->GetParMesh()->ExchangeFaceNbrData();
1379 MFEM_VERIFY(tfe != NULL &&
1382 "Only Gauss-Lobatto and Bernstein basis are supported in "
1383 "L2FaceRestriction.");
1384 if (
nf==0) {
return; }
1388 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1390 if (dof_reorder &&
nf > 0)
1398 if (el) {
continue; }
1399 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1405 void L2FaceRestriction::ComputeScatterIndicesAndOffsets(
1411 for (
int i = 0; i <=
ndofs; ++i)
1421 MFEM_ASSERT(!face.IsShared(),
1422 "Unexpected shared face in L2FaceRestriction.");
1423 if ( face.IsOfFaceType(face_type) )
1440 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1443 for (
int i = 1; i <=
ndofs; ++i)
1449 void L2FaceRestriction::ComputeGatherIndices(
1459 MFEM_ASSERT(!face.IsShared(),
1460 "Unexpected shared face in L2FaceRestriction.");
1461 if ( face.IsOfFaceType(face_type) )
1473 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1476 for (
int i =
ndofs; i > 0; --i)
1485 const int face_index)
1488 "This method should not be used on nonconforming coarse faces.");
1490 const int* elem_map = e2dTable.
GetJ();
1497 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1499 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1500 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1501 const int restriction_dof_elem1 = face_dofs*face_index + face_dof_elem1;
1509 const int face_index)
1512 "This method should only be used on local faces.");
1514 const int* elem_map = e2dTable.
GetJ();
1523 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1525 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1528 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1529 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1530 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1538 const int face_index)
1542 "This method should only be used on shared faces.");
1555 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1557 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1558 orientation, dof1d, face_dof_elem1);
1559 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1560 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1561 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1570 const int face_index)
1573 "This method should only be used on boundary faces.");
1577 const int restriction_dof_elem2 = face_dofs*face_index + d;
1584 const int face_index)
1587 "This method should not be used on nonconforming coarse faces.");
1589 const int* elem_map = e2dTable.
GetJ();
1596 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1598 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1599 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1600 const int restriction_dof_elem1 = face_dofs*face_index + face_dof_elem1;
1608 const int face_index)
1611 "This method should only be used on local faces.");
1613 const int* elem_map = e2dTable.
GetJ();
1622 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1624 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1627 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1628 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1629 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1632 restriction_dof_elem2;
1657 "Registering face as nonconforming even though it is not.");
1660 const int master_side =
1662 const int face_key = (master_side == 0 ? 1000 : 0) +
1667 Key key(ptMat, face_key);
1672 GetCoarseToFineInterpolation(face,ptMat);
1679 interp_config[face_index] = {master_side, itr->second.first};
1683 const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1688 "The following interpolation operator is only implemented for"
1689 "lexicographic ordering.");
1691 "This method should not be called on conforming faces.")
1695 const bool is_ghost_slave =
1697 const int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1704 const int face_dofs = trace_fe->
GetDof();
1718 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1720 DenseMatrix native_interpolator(face_dofs,face_dofs);
1721 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1722 const int dim = trace_fe->GetDim()+1;
1723 const int dof1d = trace_fe->GetOrder()+1;
1725 for (
int i = 0; i < face_dofs; i++)
1727 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1729 if ( !is_ghost_slave )
1733 orientation, dof1d, li);
1735 for (
int j = 0; j < face_dofs; j++)
1738 if ( !is_ghost_slave )
1742 orientation, dof1d, lj);
1744 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1745 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1748 return interpolator;
1756 const int face_dofs = trace_fe->
GetDof();
1758 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1763 const int idx = val.second.first;
1764 const DenseMatrix &interpolator = *val.second.second;
1765 for (
int i = 0; i < face_dofs; i++)
1767 for (
int j = 0; j < face_dofs; j++)
1769 d_interp(i,j,idx) = interpolator(i,j);
1772 delete val.second.second;
1783 interpolations(fes, ordering, type)
1785 if (!build) {
return; }
1790 ComputeScatterIndicesAndOffsets(ordering, type);
1792 ComputeGatherIndices(ordering, type);
1807 const int vd =
vdim;
1816 nface_dofs, nface_dofs, nc_size);
1817 static constexpr
int max_nd = 16*16;
1818 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1819 MFEM_FORALL_3D(face,
nf, nface_dofs, 1, 1,
1821 MFEM_SHARED
double dof_values[max_nd];
1824 const int interp_index = conf.
index;
1825 for (
int side = 0; side < 2; side++)
1830 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1832 const int i = face*nface_dofs + dof;
1833 const int idx = side==0 ? d_indices1[i] : d_indices2[i];
1834 for (
int c = 0; c < vd; ++c)
1836 d_y(dof, c, side, face) = d_x(t?c:idx, t?idx:c);
1842 for (
int c = 0; c < vd; ++c)
1844 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1846 const int i = face*nface_dofs + dof;
1847 const int idx = side==0 ? d_indices1[i] : d_indices2[i];
1848 dof_values[dof] = d_x(t?c:idx, t?idx:c);
1851 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1854 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
1856 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1858 d_y(dof_out, c, side, face) = res;
1869 if (nf==0) {
return; }
1870 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1872 DoubleValuedNonconformingMult(x, y);
1874 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1876 DoubleValuedConformingMult(x, y);
1880 SingleValuedConformingMult(x, y);
1884 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1888 m == L2FaceValues::SingleValued,
1889 "This method should be called when m == L2FaceValues::SingleValued.");
1890 if (x_interp.Size()==0)
1892 x_interp.SetSize(x.
Size());
1896 const int nface_dofs = face_dofs;
1897 const int vd = vdim;
1899 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1900 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1901 auto interpolators = interpolations.GetInterpolators().Read();
1902 const int nc_size = interpolations.GetNumInterpolators();
1903 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1904 static constexpr
int max_nd = 16*16;
1905 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1906 MFEM_FORALL_3D(face, nf, nface_dofs, 1, 1,
1908 MFEM_SHARED
double dof_values[max_nd];
1911 const int interp_index = conf.
index;
1915 for (
int c = 0; c < vd; ++c)
1917 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1919 dof_values[dof] = d_x(dof, c, face);
1922 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1925 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
1927 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1929 d_x(dof_out, c, face) = res;
1937 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1941 m == L2FaceValues::DoubleValued,
1942 "This method should be called when m == L2FaceValues::DoubleValued.");
1943 if (x_interp.Size()==0)
1945 x_interp.SetSize(x.
Size());
1949 const int nface_dofs = face_dofs;
1950 const int vd = vdim;
1952 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, 2, nf);
1953 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1954 auto interpolators = interpolations.GetInterpolators().Read();
1955 const int nc_size = interpolations.GetNumInterpolators();
1956 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1957 static constexpr
int max_nd = 16*16;
1958 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1959 MFEM_FORALL_3D(face, nf, nface_dofs, 1, 1,
1961 MFEM_SHARED
double dof_values[max_nd];
1964 const int interp_index = conf.
index;
1968 for (
int c = 0; c < vd; ++c)
1970 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1972 dof_values[dof] = d_x(dof, c, master_side, face);
1975 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1978 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
1980 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1982 d_x(dof_out, c, master_side, face) = res;
1990 void NCL2FaceRestriction::AddMultTranspose(
const Vector& x,
Vector& y)
const
1992 if (nf==0) {
return; }
1993 if (type==FaceType::Interior)
1995 if ( m==L2FaceValues::DoubleValued )
1997 DoubleValuedNonconformingTransposeInterpolation(x);
1998 DoubleValuedConformingAddMultTranspose(x_interp, y);
2000 else if ( m==L2FaceValues::SingleValued )
2002 SingleValuedNonconformingTransposeInterpolation(x);
2003 SingleValuedConformingAddMultTranspose(x_interp, y);
2008 if ( m==L2FaceValues::DoubleValued )
2010 DoubleValuedConformingAddMultTranspose(x, y);
2012 else if ( m==L2FaceValues::SingleValued )
2014 SingleValuedConformingAddMultTranspose(x, y);
2020 const bool keep_nbr_block)
const
2022 MFEM_ABORT(
"Not yet implemented.");
2025 void NCL2FaceRestriction::FillJAndData(
const Vector &ea_data,
2027 const bool keep_nbr_block)
const
2029 MFEM_ABORT(
"Not yet implemented.");
2032 void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2037 MFEM_ABORT(
"Not yet implemented.");
2048 return ToLexOrdering2D(face_id, size1d, index);
2050 return ToLexOrdering3D(face_id, size1d, index%size1d, index/size1d);
2052 MFEM_ABORT(
"Unsupported dimension.");
2057 void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
2061 Mesh &mesh = *fes.GetMesh();
2064 for (
int i = 0; i <= ndofs; ++i)
2066 gather_offsets[i] = 0;
2071 for (
int f = 0;
f < fes.GetNF(); ++
f)
2073 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2074 if ( face.IsNonconformingCoarse() )
2080 else if ( type==FaceType::Interior && face.IsInterior() )
2082 SetFaceDofsScatterIndices1(face,f_ind);
2083 if ( m==L2FaceValues::DoubleValued )
2085 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2086 if ( face.IsConforming() )
2088 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2092 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2097 else if ( type==FaceType::Boundary && face.IsBoundary() )
2099 SetFaceDofsScatterIndices1(face,f_ind);
2100 if ( m==L2FaceValues::DoubleValued )
2102 SetBoundaryDofsScatterIndices2(face,f_ind);
2107 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2108 (type==FaceType::Interior?
"interior" :
"boundary") <<
2109 " faces: " << f_ind <<
" vs " << nf );
2112 for (
int i = 1; i <= ndofs; ++i)
2114 gather_offsets[i] += gather_offsets[i - 1];
2118 interpolations.LinearizeInterpolatorMapIntoVector();
2121 void NCL2FaceRestriction::ComputeGatherIndices(
2125 Mesh &mesh = *fes.GetMesh();
2128 for (
int f = 0;
f < fes.GetNF(); ++
f)
2130 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2131 MFEM_ASSERT(!face.IsShared(),
2132 "Unexpected shared face in NCL2FaceRestriction.");
2133 if ( face.IsNonconformingCoarse() )
2139 else if ( face.IsOfFaceType(type) )
2141 SetFaceDofsGatherIndices1(face,f_ind);
2142 if ( m==L2FaceValues::DoubleValued &&
2143 type==FaceType::Interior &&
2146 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2151 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2152 (type==FaceType::Interior?
"interior" :
"boundary") <<
2153 " faces: " << f_ind <<
" vs " << nf );
2156 for (
int i = ndofs; i > 0; --i)
2158 gather_offsets[i] = gather_offsets[i - 1];
2160 gather_offsets[0] = 0;
Abstract class for all finite elements.
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
int Size() const
Return the logical size of the array.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
FaceInformation GetFaceInformation(int f) const
H1FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering ordering, const FaceType type, bool build)
Construct an H1FaceRestriction.
void MultTransposeUnsigned(const Vector &x, Vector &y) const
Compute MultTranspose without applying signs based on DOF orientations.
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...
Operator that extracts Face degrees of freedom for H1 FiniteElementSpaces.
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
void SetSize(int s)
Resize the vector to size s.
Array< int > gather_indices
void AddMultTranspose(const Vector &x, Vector &y) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
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 Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
std::pair< const DenseMatrix *, int > Key
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
T * GetData()
Returns the data.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Data type dense matrix using column-major storage.
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
int Size() const
Returns the size of the vector.
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
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 MultLeftInverse(const Vector &x, Vector &y) const
Geometry::Type GetFaceBaseGeometry(int i) const
Abstract parallel finite element space.
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Memory< double > & GetMemoryData()
Memory< int > & GetMemoryI()
Array< int > gather_offsets
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
Array< int > gather_indices
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...
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...
L2ElementRestriction(const FiniteElementSpace &)
Memory< int > & GetMemoryJ()
Array< InterpConfig > interp_config
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
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...
const FiniteElementSpace & fes
double f(const Vector &xvec)
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 ...
int FillI(SparseMatrix &mat) const
void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
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...
void FillI(SparseMatrix &mat) const
Mesh * GetMesh() const
Returns the mesh.
Operator that extracts Face degrees of freedom for L2 spaces.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
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 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 CheckFESpace(const ElementDofOrdering ordering)
Verify that H1FaceRestriction is build from an H1 FESpace.
InterpolationManager()=delete
const FiniteElementSpace & fes
void LinearizeInterpolatorMapIntoVector()
Transform the interpolation matrix map into a contiguous memory structure.
int * ReadWriteI(bool on_dev=true)
Geometry::Type GetFaceGeometry(int i) const
void AddMultTranspose(const Vector &x, Vector &y) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
void MultUnsigned(const Vector &x, Vector &y) const
Compute Mult without applying signs based on DOF orientations.
int * WriteI(bool on_dev=true)
ElementRestriction(const FiniteElementSpace &, ElementDofOrdering)
void GetFaceDofs(const int dim, const int face_id, const int dof1d, Array< int > &face_map)
Return the face map that extracts the degrees of freedom for the requested local face of a quad or he...
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
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...
const FiniteElementSpace & fes
void SetFaceDofsGatherIndices(const Mesh::FaceInformation &face, const int face_index, const ElementDofOrdering ordering)
Set the gathering indices of elem1 for the interior face described by the face.
Array< int > gather_offsets
void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
int GetNumInterpolators() const
Return the total number of interpolators.
NCL2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an NCL2FaceRestriction, this is a specialization of a L2FaceRestriction for nonconforming ...
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
int * WriteJ(bool on_dev=true)
int height
Dimension of the output / number of rows in the matrix.
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
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...
Array< int > scatter_indices1
void CheckFESpace(const ElementDofOrdering ordering)
Verify that L2FaceRestriction is build from an L2 FESpace.
L2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an L2FaceRestriction.
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int index(int i, int j, int nx, int ny)
const FiniteElementSpace & fes
Lexicographic ordering for tensor-product FiniteElements.
void SetFaceDofsScatterIndices(const Mesh::FaceInformation &face, const int face_index, const ElementDofOrdering ordering)
Set the scattering indices of elem1, and increment the offsets for the face described by the face...
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...
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...
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.
virtual void AddFaceMatricesToElementMatrices(const Vector &fea_data, Vector &ea_data) const
This methods adds the DG face matrices to the element matrices.
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element...
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 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...
uint32_t is_non_conforming
const Array< InterpConfig > & GetFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Array< int > scatter_indices
InterpolationManager interpolations
int width
Dimension of the input / number of columns in the matrix.
Array< int > scatter_indices2
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...
void FillSparseMatrix(const Vector &mat_ea, SparseMatrix &mat) const
Fill a Sparse Matrix with Element Matrices.
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
DofTransformation * GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
double f(const Vector &p)
double * WriteData(bool on_dev=true)
void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...