12 #include "restriction.hpp" 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);
151 void ElementRestriction::TAddMultTranspose(
const Vector& x,
Vector& y)
const 161 MFEM_FORALL(i,
ndofs,
163 const int offset = d_offsets[i];
164 const int next_offset = d_offsets[i + 1];
165 for (
int c = 0; c < vd; ++c)
167 double dof_value = 0;
168 for (
int j = offset; j < next_offset; ++j)
170 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
171 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
172 -d_x(idx_j % nd, c, idx_j / nd));
174 if (ADD) { d_y(
t?c:i,
t?i:c) += dof_value; }
175 else { d_y(
t?c:i,
t?i:c) = dof_value; }
182 constexpr
bool ADD =
false;
183 TAddMultTranspose<ADD>(x, y);
187 const double a)
const 189 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
190 constexpr
bool ADD =
true;
191 TAddMultTranspose<ADD>(x, y);
204 MFEM_FORALL(i,
ndofs,
206 const int offset = d_offsets[i];
207 const int next_offset = d_offsets[i + 1];
208 for (
int c = 0; c < vd; ++c)
210 double dof_value = 0;
211 for (
int j = offset; j < next_offset; ++j)
213 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
214 dof_value += d_x(idx_j % nd, c, idx_j / nd);
216 d_y(
t?c:i,
t?i:c) = dof_value;
231 MFEM_FORALL(i,
ndofs,
233 const int next_offset = d_offsets[i + 1];
234 for (
int c = 0; c < vd; ++c)
236 double dof_value = 0;
237 const int j = next_offset - 1;
238 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
239 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
240 -d_x(idx_j % nd, c, idx_j / nd);
241 d_y(
t?c:i,
t?i:c) = dof_value;
260 for (
int i = 0; i <
ndofs; ++i)
262 const int offset = d_offsets[i];
263 const int next_offset = d_offsets[i+1];
264 for (
int c = 0; c < vd; ++c)
266 for (
int j = offset; j < next_offset; ++j)
268 const int idx_j = d_indices[j];
269 if (d_x(
t?c:i,
t?i:c))
271 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
275 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
276 d_x(
t?c:i,
t?i:c) = 1;
287 const int nnz =
FillI(mat);
293 static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
294 const int *nbr_elts,
const int nbrNbElts)
297 int min_el = INT_MAX;
298 for (
int i = 0; i < nbElts; i++)
300 const int e_i = my_elts[i];
301 if (e_i >= min_el) {
continue; }
302 for (
int j = 0; j < nbrNbElts; j++)
304 if (e_i==nbr_elts[j])
316 static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
324 static constexpr
int Max = MaxNbNbr;
325 const int all_dofs =
ndofs;
327 const int elt_dofs =
dof;
332 MFEM_FORALL(i_L, vd*all_dofs+1,
336 MFEM_FORALL(l_dof,
ne*elt_dofs,
338 const int e = l_dof/elt_dofs;
339 const int i = l_dof%elt_dofs;
342 const int i_gm = e*elt_dofs + i;
343 const int i_L = d_gather_map[i_gm];
344 const int i_offset = d_offsets[i_L];
345 const int i_next_offset = d_offsets[i_L+1];
346 const int i_nbElts = i_next_offset - i_offset;
349 "The connectivity of this mesh is beyond the max, increase the " 350 "MaxNbNbr variable to comply with your mesh.");
351 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
353 const int i_E = d_indices[i_offset+e_i];
354 i_elts[e_i] = i_E/elt_dofs;
356 for (
int j = 0; j < elt_dofs; j++)
358 const int j_gm = e*elt_dofs + j;
359 const int j_L = d_gather_map[j_gm];
360 const int j_offset = d_offsets[j_L];
361 const int j_next_offset = d_offsets[j_L+1];
362 const int j_nbElts = j_next_offset - j_offset;
363 if (i_nbElts == 1 || j_nbElts == 1)
365 GetAndIncrementNnzIndex(i_L, I);
370 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
372 const int j_E = d_indices[j_offset+e_j];
373 const int elt = j_E/elt_dofs;
376 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
379 GetAndIncrementNnzIndex(i_L, I);
386 const int nTdofs = vd*all_dofs;
388 for (
int i = 0; i < nTdofs; i++)
390 const int nnz = h_I[i];
402 static constexpr
int Max = MaxNbNbr;
403 const int all_dofs =
ndofs;
405 const int elt_dofs =
dof;
412 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
413 MFEM_FORALL(l_dof,
ne*elt_dofs,
415 const int e = l_dof/elt_dofs;
416 const int i = l_dof%elt_dofs;
420 const int i_gm = e*elt_dofs + i;
421 const int i_L = d_gather_map[i_gm];
422 const int i_offset = d_offsets[i_L];
423 const int i_next_offset = d_offsets[i_L+1];
424 const int i_nbElts = i_next_offset - i_offset;
427 "The connectivity of this mesh is beyond the max, increase the " 428 "MaxNbNbr variable to comply with your mesh.");
429 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
431 const int i_E = d_indices[i_offset+e_i];
432 i_elts[e_i] = i_E/elt_dofs;
433 i_B[e_i] = i_E%elt_dofs;
435 for (
int j = 0; j < elt_dofs; j++)
437 const int j_gm = e*elt_dofs + j;
438 const int j_L = d_gather_map[j_gm];
439 const int j_offset = d_offsets[j_L];
440 const int j_next_offset = d_offsets[j_L+1];
441 const int j_nbElts = j_next_offset - j_offset;
442 if (i_nbElts == 1 || j_nbElts == 1)
444 const int nnz = GetAndIncrementNnzIndex(i_L, I);
446 Data[nnz] = mat_ea(j,i,e);
452 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
454 const int j_E = d_indices[j_offset+e_j];
455 const int elt = j_E/elt_dofs;
457 j_B[e_j] = j_E%elt_dofs;
459 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
463 for (
int k = 0; k < i_nbElts; k++)
465 const int e_i = i_elts[k];
466 const int i_Bloc = i_B[k];
467 for (
int l = 0; l < j_nbElts; l++)
469 const int e_j = j_elts[l];
470 const int j_Bloc = j_B[l];
473 val += mat_ea(j_Bloc, i_Bloc, e_i);
477 const int nnz = GetAndIncrementNnzIndex(i_L, I);
487 const int size = vd*all_dofs;
488 for (
int i = 0; i < size; i++)
490 h_I[size-i] = h_I[size-(i+1)];
499 ndof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
500 ndofs(fes.GetNDofs())
503 width = vdim*ne*ndof;
510 const bool t = byvdim;
513 MFEM_FORALL(i, ndofs,
516 const int dof = idx % nd;
517 const int e = idx / nd;
518 for (
int c = 0; c < vd; ++c)
520 d_y(dof, c, e) = d_x(
t?c:idx,
t?idx:c);
526 void L2ElementRestriction::TAddMultTranspose(
const Vector &x,
Vector &y)
const 530 const bool t = byvdim;
533 MFEM_FORALL(i, ndofs,
536 const int dof = idx % nd;
537 const int e = idx / nd;
538 for (
int c = 0; c < vd; ++c)
540 if (ADD) { d_y(
t?c:idx,
t?idx:c) += d_x(dof, c, e); }
541 else { d_y(
t?c:idx,
t?idx:c) = d_x(dof, c, e); }
548 constexpr
bool ADD =
false;
549 TAddMultTranspose<ADD>(x, y);
553 const double a)
const 555 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
556 constexpr
bool ADD =
true;
557 TAddMultTranspose<ADD>(x, y);
562 const int elem_dofs = ndof;
565 const int isize = mat.
Height() + 1;
566 const int interior_dofs = ne*elem_dofs*vd;
567 MFEM_FORALL(dof, isize,
569 I[dof] = dof<interior_dofs ? elem_dofs : 0;
573 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
582 const int elem_dofs = ndof;
587 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
588 MFEM_FORALL(iE, ne*elem_dofs*vd,
590 const int offset = AddNnz(iE,I,elem_dofs);
591 const int e = iE/elem_dofs;
592 const int i = iE%elem_dofs;
593 for (
int j = 0; j < elem_dofs; j++)
595 J[offset+j] = e*elem_dofs+j;
596 Data[offset+j] = mat_ea(j,i,e);
615 face_map[0] = dof1d-1;
623 for (
int i = 0; i < dof1d; ++i)
629 for (
int i = 0; i < dof1d; ++i)
631 face_map[i] = dof1d-1 + i*dof1d;
635 for (
int i = 0; i < dof1d; ++i)
637 face_map[i] = (dof1d-1)*dof1d + i;
641 for (
int i = 0; i < dof1d; ++i)
643 face_map[i] = i*dof1d;
652 for (
int i = 0; i < dof1d; ++i)
654 for (
int j = 0; j < dof1d; ++j)
656 face_map[i+j*dof1d] = i + j*dof1d;
661 for (
int i = 0; i < dof1d; ++i)
663 for (
int j = 0; j < dof1d; ++j)
665 face_map[i+j*dof1d] = i + j*dof1d*dof1d;
670 for (
int i = 0; i < dof1d; ++i)
672 for (
int j = 0; j < dof1d; ++j)
674 face_map[i+j*dof1d] = dof1d-1 + i*dof1d + j*dof1d*dof1d;
679 for (
int i = 0; i < dof1d; ++i)
681 for (
int j = 0; j < dof1d; ++j)
683 face_map[i+j*dof1d] = (dof1d-1)*dof1d + i + j*dof1d*dof1d;
688 for (
int i = 0; i < dof1d; ++i)
690 for (
int j = 0; j < dof1d; ++j)
692 face_map[i+j*dof1d] = i*dof1d + j*dof1d*dof1d;
697 for (
int i = 0; i < dof1d; ++i)
699 for (
int j = 0; j < dof1d; ++j)
701 face_map[i+j*dof1d] = (dof1d-1)*dof1d*dof1d + i + j*dof1d;
715 nf(fes.GetNFbyType(type)),
718 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
719 elem_dofs(fes.GetFE(0)->GetDof()),
720 nfdofs(nf*face_dofs),
721 ndofs(fes.GetNDofs()),
722 scatter_indices(nf*face_dofs),
723 gather_offsets(ndofs+1),
724 gather_indices(nf*face_dofs),
729 if (!build) {
return; }
730 if (
nf==0) {
return; }
734 ComputeScatterIndicesAndOffsets(e_ordering, type);
736 ComputeGatherIndices(e_ordering,type);
747 if (
nf==0) {
return; }
757 const int idx = d_indices[i];
758 const int dof = i % nface_dofs;
759 const int face = i / nface_dofs;
760 for (
int c = 0; c < vd; ++c)
762 d_y(dof, c, face) = d_x(
t?c:idx,
t?idx:c);
768 const double a)
const 770 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
771 if (
nf==0) {
return; }
780 MFEM_FORALL(i,
ndofs,
782 const int offset = d_offsets[i];
783 const int next_offset = d_offsets[i + 1];
784 for (
int c = 0; c < vd; ++c)
786 double dof_value = 0;
787 for (
int j = offset; j < next_offset; ++j)
789 const int idx_j = d_indices[j];
790 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
792 d_y(
t?c:i,
t?i:c) += dof_value;
804 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
806 pfes->GetParMesh()->ExchangeFaceNbrData();
815 MFEM_VERIFY(tfe != NULL &&
818 "Only Gauss-Lobatto and Bernstein basis are supported in " 819 "H1FaceRestriction.");
823 if (dof_reorder &&
nf > 0)
830 if (el) {
continue; }
831 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
837 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
842 void H1FaceRestriction::ComputeScatterIndicesAndOffsets(
849 for (
int i = 0; i <=
ndofs; ++i)
859 if ( face.IsNonconformingCoarse() )
865 else if ( face.IsOfFaceType(type) )
871 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
874 for (
int i = 1; i <=
ndofs; ++i)
880 void H1FaceRestriction::ComputeGatherIndices(
891 if ( face.IsNonconformingCoarse() )
897 else if ( face.IsOfFaceType(type) )
903 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
906 for (
int i =
ndofs; i > 0; --i)
915 const int face_index,
919 "This method should not be used on nonconforming coarse faces.");
921 "FaceRestriction used on degenerated mesh.");
927 const int* elem_map = e2dTable.
GetJ();
935 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
937 const int nat_volume_dof =
face_map[face_dof];
938 const int volume_dof = (!dof_reorder)?
940 dof_map[nat_volume_dof];
941 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
942 const int restriction_dof =
face_dofs*face_index + face_dof;
950 const int face_index,
954 "This method should not be used on nonconforming coarse faces.");
960 const int* elem_map = e2dTable.
GetJ();
968 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
970 const int nat_volume_dof =
face_map[face_dof];
971 const int volume_dof = (!dof_reorder)?nat_volume_dof:dof_map[nat_volume_dof];
972 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
973 const int restriction_dof =
face_dofs*face_index + face_dof;
978 static int ToLexOrdering2D(
const int face_id,
const int size1d,
const int i)
980 if (face_id==2 || face_id==3)
990 static int PermuteFace2D(
const int face_id1,
const int face_id2,
991 const int orientation,
992 const int size1d,
const int index)
996 if (face_id1==2 || face_id1==3)
998 new_index = size1d-1-
index;
1007 new_index = size1d-1-new_index;
1009 return ToLexOrdering2D(face_id2, size1d, new_index);
1012 static int ToLexOrdering3D(
const int face_id,
const int size1d,
const int i,
1015 if (face_id==2 || face_id==1 || face_id==5)
1017 return i + j*size1d;
1019 else if (face_id==3 || face_id==4)
1021 return (size1d-1-i) + j*size1d;
1025 return i + (size1d-1-j)*size1d;
1029 static int PermuteFace3D(
const int face_id1,
const int face_id2,
1030 const int orientation,
1031 const int size1d,
const int index)
1033 int i=0, j=0, new_i=0, new_j=0;
1037 if (face_id1==3 || face_id1==4)
1041 else if (face_id1==0)
1046 switch (orientation)
1058 new_j = (size1d-1-i);
1061 new_i = (size1d-1-i);
1065 new_i = (size1d-1-i);
1066 new_j = (size1d-1-j);
1069 new_i = (size1d-1-j);
1070 new_j = (size1d-1-i);
1073 new_i = (size1d-1-j);
1078 new_j = (size1d-1-j);
1081 return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
1086 const int face_id2,
const int orientation,
1087 const int size1d,
const int index)
1094 return PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
1096 return PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
1098 MFEM_ABORT(
"Unsupported dimension.");
1109 nf(fes.GetNFbyType(type)),
1111 vdim(fes.GetVDim()),
1114 fes.GetTraceElement(0, fes.
GetMesh()->GetFaceGeometry(0))->GetDof()
1116 elem_dofs(fes.GetFE(0)->GetDof()),
1117 nfdofs(nf*face_dofs),
1118 ndofs(fes.GetNDofs()),
1121 scatter_indices1(nf*face_dofs),
1123 gather_offsets(ndofs+1),
1129 if (!build) {
return; }
1133 ComputeScatterIndicesAndOffsets(e_ordering,
type);
1135 ComputeGatherIndices(e_ordering,
type);
1150 "This method should be called when m == L2FaceValues::SingleValued.");
1153 const int vd =
vdim;
1160 const int dof = i % nface_dofs;
1161 const int face = i / nface_dofs;
1162 const int idx1 = d_indices1[i];
1163 for (
int c = 0; c < vd; ++c)
1165 d_y(dof, c, face) = d_x(
t?c:idx1,
t?idx1:c);
1175 "This method should be called when m == L2FaceValues::DoubleValued.");
1178 const int vd =
vdim;
1186 const int dof = i % nface_dofs;
1187 const int face = i / nface_dofs;
1188 const int idx1 = d_indices1[i];
1189 for (
int c = 0; c < vd; ++c)
1191 d_y(dof, c, 0, face) = d_x(
t?c:idx1,
t?idx1:c);
1193 const int idx2 = d_indices2[i];
1194 for (
int c = 0; c < vd; ++c)
1196 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(
t?c:idx2,
t?idx2:c);
1203 if (
nf==0) {
return; }
1219 const int vd =
vdim;
1225 MFEM_FORALL(i,
ndofs,
1227 const int offset = d_offsets[i];
1228 const int next_offset = d_offsets[i + 1];
1229 for (
int c = 0; c < vd; ++c)
1231 double dof_value = 0;
1232 for (
int j = offset; j < next_offset; ++j)
1234 int idx_j = d_indices[j];
1235 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1237 d_y(
t?c:i,
t?i:c) += dof_value;
1247 const int vd =
vdim;
1254 MFEM_FORALL(i,
ndofs,
1256 const int offset = d_offsets[i];
1257 const int next_offset = d_offsets[i + 1];
1258 for (
int c = 0; c < vd; ++c)
1260 double dof_value = 0;
1261 for (
int j = offset; j < next_offset; ++j)
1263 int idx_j = d_indices[j];
1264 bool isE1 = idx_j < dofs;
1265 idx_j = isE1 ? idx_j : idx_j - dofs;
1267 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1268 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1270 d_y(
t?c:i,
t?i:c) += dof_value;
1276 const double a)
const 1278 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1279 if (
nf==0) {
return; }
1291 const bool keep_nbr_block)
const 1297 MFEM_FORALL(fdof,
nf*nface_dofs,
1299 const int iE1 = d_indices1[fdof];
1300 const int iE2 = d_indices2[fdof];
1301 AddNnz(iE1,I,nface_dofs);
1302 AddNnz(iE2,I,nface_dofs);
1308 const bool keep_nbr_block)
const 1314 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1317 MFEM_FORALL(fdof,
nf*nface_dofs,
1319 const int f = fdof/nface_dofs;
1320 const int iF = fdof%nface_dofs;
1321 const int iE1 = d_indices1[
f*nface_dofs+iF];
1322 const int iE2 = d_indices2[
f*nface_dofs+iF];
1323 const int offset1 = AddNnz(iE1,I,nface_dofs);
1324 const int offset2 = AddNnz(iE2,I,nface_dofs);
1325 for (
int jF = 0; jF < nface_dofs; jF++)
1327 const int jE1 = d_indices1[
f*nface_dofs+jF];
1328 const int jE2 = d_indices2[
f*nface_dofs+jF];
1329 J[offset2+jF] = jE1;
1330 J[offset1+jF] = jE2;
1331 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1332 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1347 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1351 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1352 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1353 for (
int j = 0; j < nface_dofs; j++)
1355 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1356 for (
int i = 0; i < nface_dofs; i++)
1358 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1359 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1364 for (
int j = 0; j < nface_dofs; j++)
1366 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1367 for (
int i = 0; i < nface_dofs; i++)
1369 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1370 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1379 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1383 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1384 for (
int j = 0; j < nface_dofs; j++)
1386 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1387 for (
int i = 0; i < nface_dofs; i++)
1389 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1404 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
1406 pfes->GetParMesh()->ExchangeFaceNbrData();
1415 MFEM_VERIFY(tfe != NULL &&
1418 "Only Gauss-Lobatto and Bernstein basis are supported in " 1419 "L2FaceRestriction.");
1420 if (
nf==0) {
return; }
1424 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1426 if (dof_reorder &&
nf > 0)
1434 if (el) {
continue; }
1435 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1441 void L2FaceRestriction::ComputeScatterIndicesAndOffsets(
1447 for (
int i = 0; i <=
ndofs; ++i)
1457 MFEM_ASSERT(!face.IsShared(),
1458 "Unexpected shared face in L2FaceRestriction.");
1459 if ( face.IsOfFaceType(face_type) )
1476 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1479 for (
int i = 1; i <=
ndofs; ++i)
1485 void L2FaceRestriction::ComputeGatherIndices(
1495 MFEM_ASSERT(!face.IsShared(),
1496 "Unexpected shared face in L2FaceRestriction.");
1497 if ( face.IsOfFaceType(face_type) )
1509 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1512 for (
int i =
ndofs; i > 0; --i)
1521 const int face_index)
1524 "This method should not be used on nonconforming coarse faces.");
1526 const int* elem_map = e2dTable.
GetJ();
1533 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1535 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1536 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1537 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1545 const int face_index)
1548 "This method should only be used on local faces.");
1550 const int* elem_map = e2dTable.
GetJ();
1559 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1564 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1565 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1566 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1574 const int face_index)
1578 "This method should only be used on shared faces.");
1591 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1594 orientation, dof1d, face_dof_elem1);
1595 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1596 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1597 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1606 const int face_index)
1609 "This method should only be used on boundary faces.");
1613 const int restriction_dof_elem2 =
face_dofs*face_index + d;
1620 const int face_index)
1623 "This method should not be used on nonconforming coarse faces.");
1625 const int* elem_map = e2dTable.
GetJ();
1632 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1634 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1635 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1636 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1644 const int face_index)
1647 "This method should only be used on local faces.");
1649 const int* elem_map = e2dTable.
GetJ();
1658 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1663 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1664 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1665 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1668 restriction_dof_elem2;
1693 "Registering face as nonconforming even though it is not.");
1696 const int master_side =
1698 const int face_key = (master_side == 0 ? 1000 : 0) +
1703 Key key(ptMat, face_key);
1708 GetCoarseToFineInterpolation(face,ptMat);
1715 interp_config[face_index] = {master_side, itr->second.first};
1719 const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1724 "The following interpolation operator is only implemented for" 1725 "lexicographic ordering.");
1727 "This method should not be called on conforming faces.")
1731 const bool is_ghost_slave =
1733 const int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1740 const int face_dofs = trace_fe->
GetDof();
1754 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1756 DenseMatrix native_interpolator(face_dofs,face_dofs);
1757 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1758 const int dim = trace_fe->GetDim()+1;
1759 const int dof1d = trace_fe->GetOrder()+1;
1761 for (
int i = 0; i < face_dofs; i++)
1763 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1765 if ( !is_ghost_slave )
1769 orientation, dof1d, li);
1771 for (
int j = 0; j < face_dofs; j++)
1774 if ( !is_ghost_slave )
1778 orientation, dof1d, lj);
1780 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1781 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1784 return interpolator;
1792 const int face_dofs = trace_fe->
GetDof();
1794 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1799 const int idx = val.second.first;
1800 const DenseMatrix &interpolator = *val.second.second;
1801 for (
int i = 0; i < face_dofs; i++)
1803 for (
int j = 0; j < face_dofs; j++)
1805 d_interp(i,j,idx) = interpolator(i,j);
1808 delete val.second.second;
1816 int num_nc_faces = 0;
1830 if ( config.is_non_conforming )
1844 interpolations(fes, ordering, type)
1846 if (!build) {
return; }
1851 ComputeScatterIndicesAndOffsets(ordering,
type);
1853 ComputeGatherIndices(ordering,
type);
1875 const int vd =
vdim;
1878 const int num_nc_faces = nc_interp_config.Size();
1879 if ( num_nc_faces == 0 ) {
return; }
1880 auto interp_config_ptr = nc_interp_config.Read();
1883 nface_dofs, nface_dofs, nc_size);
1884 static constexpr
int max_nd = 16*16;
1885 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1886 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
1888 MFEM_SHARED
double dof_values[max_nd];
1892 const int master_side = conf.master_side;
1893 const int interp_index = conf.index;
1894 const int face = conf.face_index;
1895 for (int c = 0; c < vd; ++c)
1897 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1899 dof_values[dof] = d_y(dof, c, master_side, face);
1902 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1905 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1907 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1909 d_y(dof_out, c, master_side, face) = res;
1919 if (nf==0) {
return; }
1920 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1922 DoubleValuedNonconformingMult(x, y);
1924 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1926 DoubleValuedConformingMult(x, y);
1930 SingleValuedConformingMult(x, y);
1934 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1938 m == L2FaceValues::SingleValued,
1939 "This method should be called when m == L2FaceValues::SingleValued.");
1940 if (x_interp.Size()==0)
1942 x_interp.SetSize(x.
Size());
1945 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1949 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1953 const int nface_dofs = face_dofs;
1954 const int vd = vdim;
1956 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1957 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1958 const int num_nc_faces = nc_interp_config.Size();
1959 if ( num_nc_faces == 0 ) {
return; }
1960 auto interp_config_ptr = nc_interp_config.Read();
1961 auto interpolators = interpolations.GetInterpolators().Read();
1962 const int nc_size = interpolations.GetNumInterpolators();
1963 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1964 static constexpr
int max_nd = 16*16;
1965 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1966 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
1968 MFEM_SHARED
double dof_values[max_nd];
1971 const int interp_index = conf.
index;
1976 for (int c = 0; c < vd; ++c)
1978 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1980 dof_values[dof] = d_x(dof, c, face);
1983 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1986 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1988 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1990 d_x(dof_out, c, face) = res;
1998 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
2002 m == L2FaceValues::DoubleValued,
2003 "This method should be called when m == L2FaceValues::DoubleValued.");
2004 if (x_interp.Size()==0)
2006 x_interp.SetSize(x.
Size());
2009 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
2012 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
2016 const int nface_dofs = face_dofs;
2017 const int vd = vdim;
2020 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
2021 const int num_nc_faces = nc_interp_config.Size();
2022 if ( num_nc_faces == 0 ) {
return; }
2023 auto interp_config_ptr = nc_interp_config.Read();
2024 auto interpolators = interpolations.GetInterpolators().Read();
2025 const int nc_size = interpolations.GetNumInterpolators();
2026 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2027 static constexpr
int max_nd = 16*16;
2028 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
2029 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
2031 MFEM_SHARED
double dof_values[max_nd];
2034 const int interp_index = conf.
index;
2039 for (int c = 0; c < vd; ++c)
2041 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
2043 dof_values[dof] = d_x(dof, c, master_side, face);
2046 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
2049 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
2051 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
2053 d_x(dof_out, c, master_side, face) = res;
2062 const double a)
const 2064 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
2065 if (nf==0) {
return; }
2066 if (type==FaceType::Interior)
2068 if ( m==L2FaceValues::DoubleValued )
2070 DoubleValuedNonconformingTransposeInterpolation(x);
2071 DoubleValuedConformingAddMultTranspose(x_interp, y);
2073 else if ( m==L2FaceValues::SingleValued )
2075 SingleValuedNonconformingTransposeInterpolation(x);
2076 SingleValuedConformingAddMultTranspose(x_interp, y);
2081 if ( m==L2FaceValues::DoubleValued )
2083 DoubleValuedConformingAddMultTranspose(x, y);
2085 else if ( m==L2FaceValues::SingleValued )
2087 SingleValuedConformingAddMultTranspose(x, y);
2092 void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const 2094 if (nf==0) {
return; }
2095 if (type==FaceType::Interior)
2097 if ( m==L2FaceValues::DoubleValued )
2099 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
2100 DoubleValuedConformingAddMultTranspose(x, y);
2102 else if ( m==L2FaceValues::SingleValued )
2104 SingleValuedNonconformingTransposeInterpolationInPlace(x);
2105 SingleValuedConformingAddMultTranspose(x, y);
2110 if ( m==L2FaceValues::DoubleValued )
2112 DoubleValuedConformingAddMultTranspose(x, y);
2114 else if ( m==L2FaceValues::SingleValued )
2116 SingleValuedConformingAddMultTranspose(x, y);
2122 const bool keep_nbr_block)
const 2124 MFEM_ABORT(
"Not yet implemented.");
2127 void NCL2FaceRestriction::FillJAndData(
const Vector &ea_data,
2129 const bool keep_nbr_block)
const 2131 MFEM_ABORT(
"Not yet implemented.");
2134 void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2139 MFEM_ABORT(
"Not yet implemented.");
2150 return ToLexOrdering2D(face_id, size1d,
index);
2152 return ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2154 MFEM_ABORT(
"Unsupported dimension.");
2159 void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
2163 Mesh &mesh = *fes.GetMesh();
2166 for (
int i = 0; i <= ndofs; ++i)
2168 gather_offsets[i] = 0;
2173 for (
int f = 0;
f < fes.GetNF(); ++
f)
2175 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2176 if ( face.IsNonconformingCoarse() )
2182 else if ( type==FaceType::Interior && face.IsInterior() )
2184 SetFaceDofsScatterIndices1(face,f_ind);
2185 if ( m==L2FaceValues::DoubleValued )
2187 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2188 if ( face.IsConforming() )
2190 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2194 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2199 else if ( type==FaceType::Boundary && face.IsBoundary() )
2201 SetFaceDofsScatterIndices1(face,f_ind);
2202 if ( m==L2FaceValues::DoubleValued )
2204 SetBoundaryDofsScatterIndices2(face,f_ind);
2209 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2210 (type==FaceType::Interior?
"interior" :
"boundary") <<
2211 " faces: " << f_ind <<
" vs " << nf );
2214 for (
int i = 1; i <= ndofs; ++i)
2216 gather_offsets[i] += gather_offsets[i - 1];
2220 interpolations.LinearizeInterpolatorMapIntoVector();
2221 interpolations.InitializeNCInterpConfig();
2224 void NCL2FaceRestriction::ComputeGatherIndices(
2228 Mesh &mesh = *fes.GetMesh();
2231 for (
int f = 0;
f < fes.GetNF(); ++
f)
2233 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2234 MFEM_ASSERT(!face.IsShared(),
2235 "Unexpected shared face in NCL2FaceRestriction.");
2236 if ( face.IsNonconformingCoarse() )
2242 else if ( face.IsOfFaceType(type) )
2244 SetFaceDofsGatherIndices1(face,f_ind);
2245 if ( m==L2FaceValues::DoubleValued &&
2246 type==FaceType::Interior &&
2249 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2254 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2255 (type==FaceType::Interior?
"interior" :
"boundary") <<
2256 " faces: " << f_ind <<
" vs " << nf );
2259 for (
int i = ndofs; i > 0; --i)
2261 gather_offsets[i] = gather_offsets[i - 1];
2263 gather_offsets[0] = 0;
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
void FillI(SparseMatrix &mat) const
Abstract class for all finite elements.
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Array< NCInterpConfig > nc_interp_config
const Array< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
H1FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering ordering, const FaceType type, bool build)
Construct an H1FaceRestriction.
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.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
void SetSize(int s)
Resize the vector to size s.
Array< int > gather_indices
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
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
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
T * GetData()
Returns the data.
int Size() const
Returns the size of the vector.
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...
Data type dense matrix using column-major storage.
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
Abstract parallel finite element space.
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...
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
Memory< double > & GetMemoryData()
Memory< int > & GetMemoryI()
Array< int > gather_offsets
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
Array< int > gather_indices
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...
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
L2ElementRestriction(const FiniteElementSpace &)
Memory< int > & GetMemoryJ()
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
Array< InterpConfig > interp_config
DofTransformation * GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
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...
virtual void AddFaceMatricesToElementMatrices(const Vector &fea_data, Vector &ea_data) const
This methods adds the DG face matrices to the element matrices.
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 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 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 ...
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
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 InitializeNCInterpConfig()
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)
void MultLeftInverse(const Vector &x, Vector &y) const
void MultTransposeUnsigned(const Vector &x, Vector &y) const
Compute MultTranspose without applying signs based on DOF orientations.
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...
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...
uint32_t is_non_conforming
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
const ElementDofOrdering ordering
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
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
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
Mesh * GetMesh() const
Returns the mesh.
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 ...
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
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 FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
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 ...
void MultUnsigned(const Vector &x, Vector &y) const
Compute Mult without applying signs based on DOF orientations.
int GetDof() const
Returns the number of degrees of freedom in the finite element.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
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...
void FillSparseMatrix(const Vector &mat_ea, SparseMatrix &mat) const
Fill a Sparse Matrix with Element Matrices.
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.
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.
int GetNumInterpolators() const
Return the total number of interpolators.
int FillI(SparseMatrix &mat) const
int index(int i, int j, int nx, int ny)
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
const FiniteElementSpace & fes
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Lexicographic ordering for tensor-product FiniteElements.
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 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...
int Size() const
Return the logical size of the array.
FaceInformation GetFaceInformation(int f) const
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
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.
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
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...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element...
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Array< int > scatter_indices
InterpolationManager interpolations
int width
Dimension of the input / number of columns in the matrix.
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
Array< int > scatter_indices2
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
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...
double f(const Vector &p)
double * WriteData(bool on_dev=true)