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);
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 AddMultTranspose<ADD>(x, y);
188 constexpr
bool ADD =
true;
189 AddMultTranspose<ADD>(x, y);
202 MFEM_FORALL(i,
ndofs,
204 const int offset = d_offsets[i];
205 const int next_offset = d_offsets[i + 1];
206 for (
int c = 0; c < vd; ++c)
208 double dof_value = 0;
209 for (
int j = offset; j < next_offset; ++j)
211 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
212 dof_value += d_x(idx_j % nd, c, idx_j / nd);
214 d_y(t?c:i,t?i:c) = dof_value;
229 MFEM_FORALL(i,
ndofs,
231 const int next_offset = d_offsets[i + 1];
232 for (
int c = 0; c < vd; ++c)
234 double dof_value = 0;
235 const int j = next_offset - 1;
236 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
237 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
238 -d_x(idx_j % nd, c, idx_j / nd);
239 d_y(t?c:i,t?i:c) = dof_value;
258 for (
int i = 0; i <
ndofs; ++i)
260 const int offset = d_offsets[i];
261 const int next_offset = d_offsets[i+1];
262 for (
int c = 0; c < vd; ++c)
264 for (
int j = offset; j < next_offset; ++j)
266 const int idx_j = d_indices[j];
267 if (d_x(t?c:i,t?i:c))
269 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
273 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
274 d_x(t?c:i,t?i:c) = 1;
285 const int nnz =
FillI(mat);
291 static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
292 const int *nbr_elts,
const int nbrNbElts)
295 int min_el = INT_MAX;
296 for (
int i = 0; i < nbElts; i++)
298 const int e_i = my_elts[i];
299 if (e_i >= min_el) {
continue; }
300 for (
int j = 0; j < nbrNbElts; j++)
302 if (e_i==nbr_elts[j])
314 static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
322 static constexpr
int Max = MaxNbNbr;
323 const int all_dofs =
ndofs;
325 const int elt_dofs =
dof;
330 MFEM_FORALL(i_L, vd*all_dofs+1,
334 MFEM_FORALL(l_dof,
ne*elt_dofs,
336 const int e = l_dof/elt_dofs;
337 const int i = l_dof%elt_dofs;
340 const int i_gm = e*elt_dofs + i;
341 const int i_L = d_gather_map[i_gm];
342 const int i_offset = d_offsets[i_L];
343 const int i_next_offset = d_offsets[i_L+1];
344 const int i_nbElts = i_next_offset - i_offset;
347 "The connectivity of this mesh is beyond the max, increase the "
348 "MaxNbNbr variable to comply with your mesh.");
349 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
351 const int i_E = d_indices[i_offset+e_i];
352 i_elts[e_i] = i_E/elt_dofs;
354 for (
int j = 0; j < elt_dofs; j++)
356 const int j_gm = e*elt_dofs + j;
357 const int j_L = d_gather_map[j_gm];
358 const int j_offset = d_offsets[j_L];
359 const int j_next_offset = d_offsets[j_L+1];
360 const int j_nbElts = j_next_offset - j_offset;
361 if (i_nbElts == 1 || j_nbElts == 1)
363 GetAndIncrementNnzIndex(i_L, I);
368 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
370 const int j_E = d_indices[j_offset+e_j];
371 const int elt = j_E/elt_dofs;
374 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
377 GetAndIncrementNnzIndex(i_L, I);
384 const int nTdofs = vd*all_dofs;
386 for (
int i = 0; i < nTdofs; i++)
388 const int nnz = h_I[i];
400 static constexpr
int Max = MaxNbNbr;
401 const int all_dofs =
ndofs;
403 const int elt_dofs =
dof;
410 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
411 MFEM_FORALL(l_dof,
ne*elt_dofs,
413 const int e = l_dof/elt_dofs;
414 const int i = l_dof%elt_dofs;
418 const int i_gm = e*elt_dofs + i;
419 const int i_L = d_gather_map[i_gm];
420 const int i_offset = d_offsets[i_L];
421 const int i_next_offset = d_offsets[i_L+1];
422 const int i_nbElts = i_next_offset - i_offset;
425 "The connectivity of this mesh is beyond the max, increase the "
426 "MaxNbNbr variable to comply with your mesh.");
427 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
429 const int i_E = d_indices[i_offset+e_i];
430 i_elts[e_i] = i_E/elt_dofs;
431 i_B[e_i] = i_E%elt_dofs;
433 for (
int j = 0; j < elt_dofs; j++)
435 const int j_gm = e*elt_dofs + j;
436 const int j_L = d_gather_map[j_gm];
437 const int j_offset = d_offsets[j_L];
438 const int j_next_offset = d_offsets[j_L+1];
439 const int j_nbElts = j_next_offset - j_offset;
440 if (i_nbElts == 1 || j_nbElts == 1)
442 const int nnz = GetAndIncrementNnzIndex(i_L, I);
444 Data[nnz] = mat_ea(j,i,e);
450 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
452 const int j_E = d_indices[j_offset+e_j];
453 const int elt = j_E/elt_dofs;
455 j_B[e_j] = j_E%elt_dofs;
457 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
461 for (
int k = 0; k < i_nbElts; k++)
463 const int e_i = i_elts[k];
464 const int i_Bloc = i_B[k];
465 for (
int l = 0; l < j_nbElts; l++)
467 const int e_j = j_elts[l];
468 const int j_Bloc = j_B[l];
471 val += mat_ea(j_Bloc, i_Bloc, e_i);
475 const int nnz = GetAndIncrementNnzIndex(i_L, I);
485 const int size = vd*all_dofs;
486 for (
int i = 0; i < size; i++)
488 h_I[size-i] = h_I[size-(i+1)];
497 ndof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
498 ndofs(fes.GetNDofs())
501 width = vdim*ne*ndof;
508 const bool t = byvdim;
509 auto d_x =
Reshape(x.
Read(), t?vd:ndofs, t?ndofs:vd);
511 MFEM_FORALL(i, ndofs,
514 const int dof = idx % nd;
515 const int e = idx / nd;
516 for (
int c = 0; c < vd; ++c)
518 d_y(dof, c, e) = d_x(t?c:idx, t?idx:c);
528 const bool t = byvdim;
531 MFEM_FORALL(i, ndofs,
534 const int dof = idx % nd;
535 const int e = idx / nd;
536 for (
int c = 0; c < vd; ++c)
538 if (ADD) { d_y(t?c:idx,t?idx:c) += d_x(dof, c, e); }
539 else { d_y(t?c:idx,t?idx:c) = d_x(dof, c, e); }
546 constexpr
bool ADD =
false;
547 AddMultTranspose<ADD>(x, y);
552 constexpr
bool ADD =
true;
553 AddMultTranspose<ADD>(x, y);
558 const int elem_dofs = ndof;
561 const int isize = mat.
Height() + 1;
562 const int interior_dofs = ne*elem_dofs*vd;
563 MFEM_FORALL(dof, isize,
565 I[dof] = dof<interior_dofs ? elem_dofs : 0;
569 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
578 const int elem_dofs = ndof;
583 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
584 MFEM_FORALL(iE, ne*elem_dofs*vd,
586 const int offset = AddNnz(iE,I,elem_dofs);
587 const int e = iE/elem_dofs;
588 const int i = iE%elem_dofs;
589 for (
int j = 0; j < elem_dofs; j++)
591 J[offset+j] = e*elem_dofs+j;
592 Data[offset+j] = mat_ea(j,i,e);
611 face_map[0] = dof1d-1;
619 for (
int i = 0; i < dof1d; ++i)
625 for (
int i = 0; i < dof1d; ++i)
627 face_map[i] = dof1d-1 + i*dof1d;
631 for (
int i = 0; i < dof1d; ++i)
633 face_map[i] = (dof1d-1)*dof1d + i;
637 for (
int i = 0; i < dof1d; ++i)
639 face_map[i] = i*dof1d;
648 for (
int i = 0; i < dof1d; ++i)
650 for (
int j = 0; j < dof1d; ++j)
652 face_map[i+j*dof1d] = i + j*dof1d;
657 for (
int i = 0; i < dof1d; ++i)
659 for (
int j = 0; j < dof1d; ++j)
661 face_map[i+j*dof1d] = i + j*dof1d*dof1d;
666 for (
int i = 0; i < dof1d; ++i)
668 for (
int j = 0; j < dof1d; ++j)
670 face_map[i+j*dof1d] = dof1d-1 + i*dof1d + j*dof1d*dof1d;
675 for (
int i = 0; i < dof1d; ++i)
677 for (
int j = 0; j < dof1d; ++j)
679 face_map[i+j*dof1d] = (dof1d-1)*dof1d + i + j*dof1d*dof1d;
684 for (
int i = 0; i < dof1d; ++i)
686 for (
int j = 0; j < dof1d; ++j)
688 face_map[i+j*dof1d] = i*dof1d + j*dof1d*dof1d;
693 for (
int i = 0; i < dof1d; ++i)
695 for (
int j = 0; j < dof1d; ++j)
697 face_map[i+j*dof1d] = (dof1d-1)*dof1d*dof1d + i + j*dof1d;
711 nf(fes.GetNFbyType(type)),
714 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
715 elem_dofs(fes.GetFE(0)->GetDof()),
716 nfdofs(nf*face_dofs),
717 ndofs(fes.GetNDofs()),
718 scatter_indices(nf*face_dofs),
719 gather_offsets(ndofs+1),
720 gather_indices(nf*face_dofs),
725 if (!build) {
return; }
726 if (
nf==0) {
return; }
730 ComputeScatterIndicesAndOffsets(e_ordering, type);
732 ComputeGatherIndices(e_ordering,type);
743 if (
nf==0) {
return; }
753 const int idx = d_indices[i];
754 const int dof = i % nface_dofs;
755 const int face = i / nface_dofs;
756 for (
int c = 0; c < vd; ++c)
758 d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
765 if (
nf==0) {
return; }
774 MFEM_FORALL(i,
ndofs,
776 const int offset = d_offsets[i];
777 const int next_offset = d_offsets[i + 1];
778 for (
int c = 0; c < vd; ++c)
780 double dof_value = 0;
781 for (
int j = offset; j < next_offset; ++j)
783 const int idx_j = d_indices[j];
784 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
786 d_y(t?c:i,t?i:c) += dof_value;
798 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
800 pfes->GetParMesh()->ExchangeFaceNbrData();
809 MFEM_VERIFY(tfe != NULL &&
812 "Only Gauss-Lobatto and Bernstein basis are supported in "
813 "H1FaceRestriction.");
817 if (dof_reorder &&
nf > 0)
824 if (el) {
continue; }
825 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
831 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
836 void H1FaceRestriction::ComputeScatterIndicesAndOffsets(
843 for (
int i = 0; i <=
ndofs; ++i)
853 if ( face.IsNonconformingCoarse() )
859 else if ( face.IsOfFaceType(type) )
865 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
868 for (
int i = 1; i <=
ndofs; ++i)
874 void H1FaceRestriction::ComputeGatherIndices(
885 if ( face.IsNonconformingCoarse() )
891 else if ( face.IsOfFaceType(type) )
897 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
900 for (
int i =
ndofs; i > 0; --i)
909 const int face_index,
913 "This method should not be used on nonconforming coarse faces.");
915 "FaceRestriction used on degenerated mesh.");
921 const int* elem_map = e2dTable.
GetJ();
929 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
931 const int nat_volume_dof =
face_map[face_dof];
932 const int volume_dof = (!dof_reorder)?
934 dof_map[nat_volume_dof];
935 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
936 const int restriction_dof = face_dofs*face_index + face_dof;
944 const int face_index,
948 "This method should not be used on nonconforming coarse faces.");
954 const int* elem_map = e2dTable.
GetJ();
962 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
964 const int nat_volume_dof =
face_map[face_dof];
965 const int volume_dof = (!dof_reorder)?nat_volume_dof:dof_map[nat_volume_dof];
966 const int global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
967 const int restriction_dof = face_dofs*face_index + face_dof;
972 static int ToLexOrdering2D(
const int face_id,
const int size1d,
const int i)
974 if (face_id==2 || face_id==3)
984 static int PermuteFace2D(
const int face_id1,
const int face_id2,
985 const int orientation,
986 const int size1d,
const int index)
990 if (face_id1==2 || face_id1==3)
992 new_index = size1d-1-
index;
1001 new_index = size1d-1-new_index;
1003 return ToLexOrdering2D(face_id2, size1d, new_index);
1006 static int ToLexOrdering3D(
const int face_id,
const int size1d,
const int i,
1009 if (face_id==2 || face_id==1 || face_id==5)
1011 return i + j*size1d;
1013 else if (face_id==3 || face_id==4)
1015 return (size1d-1-i) + j*size1d;
1019 return i + (size1d-1-j)*size1d;
1023 static int PermuteFace3D(
const int face_id1,
const int face_id2,
1024 const int orientation,
1025 const int size1d,
const int index)
1027 int i=0, j=0, new_i=0, new_j=0;
1031 if (face_id1==3 || face_id1==4)
1035 else if (face_id1==0)
1040 switch (orientation)
1052 new_j = (size1d-1-i);
1055 new_i = (size1d-1-i);
1059 new_i = (size1d-1-i);
1060 new_j = (size1d-1-j);
1063 new_i = (size1d-1-j);
1064 new_j = (size1d-1-i);
1067 new_i = (size1d-1-j);
1072 new_j = (size1d-1-j);
1075 return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
1080 const int face_id2,
const int orientation,
1081 const int size1d,
const int index)
1088 return PermuteFace2D(face_id1, face_id2, orientation, size1d, index);
1090 return PermuteFace3D(face_id1, face_id2, orientation, size1d, index);
1092 MFEM_ABORT(
"Unsupported dimension.");
1103 nf(fes.GetNFbyType(type)),
1105 vdim(fes.GetVDim()),
1108 fes.GetTraceElement(0, fes.
GetMesh()->GetFaceBaseGeometry(0))->GetDof()
1110 elem_dofs(fes.GetFE(0)->GetDof()),
1111 nfdofs(nf*face_dofs),
1112 ndofs(fes.GetNDofs()),
1115 scatter_indices1(nf*face_dofs),
1117 gather_offsets(ndofs+1),
1123 if (!build) {
return; }
1127 ComputeScatterIndicesAndOffsets(e_ordering,type);
1129 ComputeGatherIndices(e_ordering, type);
1144 "This method should be called when m == L2FaceValues::SingleValued.");
1147 const int vd =
vdim;
1154 const int dof = i % nface_dofs;
1155 const int face = i / nface_dofs;
1156 const int idx1 = d_indices1[i];
1157 for (
int c = 0; c < vd; ++c)
1159 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
1169 "This method should be called when m == L2FaceValues::DoubleValued.");
1172 const int vd =
vdim;
1180 const int dof = i % nface_dofs;
1181 const int face = i / nface_dofs;
1182 const int idx1 = d_indices1[i];
1183 for (
int c = 0; c < vd; ++c)
1185 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
1187 const int idx2 = d_indices2[i];
1188 for (
int c = 0; c < vd; ++c)
1190 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(t?c:idx2, t?idx2:c);
1197 if (
nf==0) {
return; }
1213 const int vd =
vdim;
1219 MFEM_FORALL(i,
ndofs,
1221 const int offset = d_offsets[i];
1222 const int next_offset = d_offsets[i + 1];
1223 for (
int c = 0; c < vd; ++c)
1225 double dof_value = 0;
1226 for (
int j = offset; j < next_offset; ++j)
1228 int idx_j = d_indices[j];
1229 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1231 d_y(t?c:i,t?i:c) += dof_value;
1241 const int vd =
vdim;
1248 MFEM_FORALL(i,
ndofs,
1250 const int offset = d_offsets[i];
1251 const int next_offset = d_offsets[i + 1];
1252 for (
int c = 0; c < vd; ++c)
1254 double dof_value = 0;
1255 for (
int j = offset; j < next_offset; ++j)
1257 int idx_j = d_indices[j];
1258 bool isE1 = idx_j < dofs;
1259 idx_j = isE1 ? idx_j : idx_j - dofs;
1261 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1262 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1264 d_y(t?c:i,t?i:c) += dof_value;
1271 if (
nf==0) {
return; }
1283 const bool keep_nbr_block)
const
1289 MFEM_FORALL(fdof,
nf*nface_dofs,
1291 const int iE1 = d_indices1[fdof];
1292 const int iE2 = d_indices2[fdof];
1293 AddNnz(iE1,I,nface_dofs);
1294 AddNnz(iE2,I,nface_dofs);
1300 const bool keep_nbr_block)
const
1306 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1309 MFEM_FORALL(fdof,
nf*nface_dofs,
1311 const int f = fdof/nface_dofs;
1312 const int iF = fdof%nface_dofs;
1313 const int iE1 = d_indices1[f*nface_dofs+iF];
1314 const int iE2 = d_indices2[f*nface_dofs+iF];
1315 const int offset1 = AddNnz(iE1,I,nface_dofs);
1316 const int offset2 = AddNnz(iE2,I,nface_dofs);
1317 for (
int jF = 0; jF < nface_dofs; jF++)
1319 const int jE1 = d_indices1[f*nface_dofs+jF];
1320 const int jE2 = d_indices2[f*nface_dofs+jF];
1321 J[offset2+jF] = jE1;
1322 J[offset1+jF] = jE2;
1323 Data[offset2+jF] = mat_fea(jF,iF,0,f);
1324 Data[offset1+jF] = mat_fea(jF,iF,1,f);
1339 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1343 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1344 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1345 for (
int j = 0; j < nface_dofs; j++)
1347 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1348 for (
int i = 0; i < nface_dofs; i++)
1350 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1351 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1356 for (
int j = 0; j < nface_dofs; j++)
1358 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1359 for (
int i = 0; i < nface_dofs; i++)
1361 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1362 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1371 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1375 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1376 for (
int j = 0; j < nface_dofs; j++)
1378 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1379 for (
int i = 0; i < nface_dofs; i++)
1381 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1396 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
1398 pfes->GetParMesh()->ExchangeFaceNbrData();
1407 MFEM_VERIFY(tfe != NULL &&
1410 "Only Gauss-Lobatto and Bernstein basis are supported in "
1411 "L2FaceRestriction.");
1412 if (
nf==0) {
return; }
1416 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1418 if (dof_reorder &&
nf > 0)
1426 if (el) {
continue; }
1427 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1433 void L2FaceRestriction::ComputeScatterIndicesAndOffsets(
1439 for (
int i = 0; i <=
ndofs; ++i)
1449 MFEM_ASSERT(!face.IsShared(),
1450 "Unexpected shared face in L2FaceRestriction.");
1451 if ( face.IsOfFaceType(face_type) )
1468 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1471 for (
int i = 1; i <=
ndofs; ++i)
1477 void L2FaceRestriction::ComputeGatherIndices(
1487 MFEM_ASSERT(!face.IsShared(),
1488 "Unexpected shared face in L2FaceRestriction.");
1489 if ( face.IsOfFaceType(face_type) )
1501 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1504 for (
int i =
ndofs; i > 0; --i)
1513 const int face_index)
1516 "This method should not be used on nonconforming coarse faces.");
1518 const int* elem_map = e2dTable.
GetJ();
1525 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1527 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1528 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1529 const int restriction_dof_elem1 = face_dofs*face_index + face_dof_elem1;
1537 const int face_index)
1540 "This method should only be used on local faces.");
1542 const int* elem_map = e2dTable.
GetJ();
1551 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1553 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1556 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1557 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1558 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1566 const int face_index)
1570 "This method should only be used on shared faces.");
1583 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1585 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1586 orientation, dof1d, face_dof_elem1);
1587 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1588 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1589 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1598 const int face_index)
1601 "This method should only be used on boundary faces.");
1605 const int restriction_dof_elem2 = face_dofs*face_index + d;
1612 const int face_index)
1615 "This method should not be used on nonconforming coarse faces.");
1617 const int* elem_map = e2dTable.
GetJ();
1624 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1626 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1627 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1628 const int restriction_dof_elem1 = face_dofs*face_index + face_dof_elem1;
1636 const int face_index)
1639 "This method should only be used on local faces.");
1641 const int* elem_map = e2dTable.
GetJ();
1650 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1652 const int face_dof_elem2 =
PermuteFaceL2(dim, face_id1, face_id2,
1655 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1656 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1657 const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
1660 restriction_dof_elem2;
1685 "Registering face as nonconforming even though it is not.");
1688 const int master_side =
1690 const int face_key = (master_side == 0 ? 1000 : 0) +
1695 Key key(ptMat, face_key);
1700 GetCoarseToFineInterpolation(face,ptMat);
1707 interp_config[face_index] = {master_side, itr->second.first};
1711 const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1716 "The following interpolation operator is only implemented for"
1717 "lexicographic ordering.");
1719 "This method should not be called on conforming faces.")
1723 const bool is_ghost_slave =
1725 const int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1732 const int face_dofs = trace_fe->
GetDof();
1746 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1748 DenseMatrix native_interpolator(face_dofs,face_dofs);
1749 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1750 const int dim = trace_fe->GetDim()+1;
1751 const int dof1d = trace_fe->GetOrder()+1;
1753 for (
int i = 0; i < face_dofs; i++)
1755 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1757 if ( !is_ghost_slave )
1761 orientation, dof1d, li);
1763 for (
int j = 0; j < face_dofs; j++)
1766 if ( !is_ghost_slave )
1770 orientation, dof1d, lj);
1772 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1773 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1776 return interpolator;
1784 const int face_dofs = trace_fe->
GetDof();
1786 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1791 const int idx = val.second.first;
1792 const DenseMatrix &interpolator = *val.second.second;
1793 for (
int i = 0; i < face_dofs; i++)
1795 for (
int j = 0; j < face_dofs; j++)
1797 d_interp(i,j,idx) = interpolator(i,j);
1800 delete val.second.second;
1808 int num_nc_faces = 0;
1822 if ( config.is_non_conforming )
1836 interpolations(fes, ordering, type)
1838 if (!build) {
return; }
1843 ComputeScatterIndicesAndOffsets(ordering, type);
1845 ComputeGatherIndices(ordering, type);
1867 const int vd =
vdim;
1870 const int num_nc_faces = nc_interp_config.Size();
1871 if ( num_nc_faces == 0 ) {
return; }
1872 auto interp_config_ptr = nc_interp_config.Read();
1875 nface_dofs, nface_dofs, nc_size);
1876 static constexpr
int max_nd = 16*16;
1877 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1878 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
1880 MFEM_SHARED
double dof_values[max_nd];
1885 const int interp_index = conf.
index;
1887 for (
int c = 0; c < vd; ++c)
1889 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1891 dof_values[dof] = d_y(dof, c, master_side, face);
1894 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1897 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
1899 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1901 d_y(dof_out, c, master_side, face) = res;
1911 if (nf==0) {
return; }
1912 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1914 DoubleValuedNonconformingMult(x, y);
1916 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1918 DoubleValuedConformingMult(x, y);
1922 SingleValuedConformingMult(x, y);
1926 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1930 m == L2FaceValues::SingleValued,
1931 "This method should be called when m == L2FaceValues::SingleValued.");
1932 if (x_interp.Size()==0)
1934 x_interp.SetSize(x.
Size());
1937 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1941 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1945 const int nface_dofs = face_dofs;
1946 const int vd = vdim;
1948 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1949 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1950 const int num_nc_faces = nc_interp_config.Size();
1951 if ( num_nc_faces == 0 ) {
return; }
1952 auto interp_config_ptr = nc_interp_config.Read();
1953 auto interpolators = interpolations.GetInterpolators().Read();
1954 const int nc_size = interpolations.GetNumInterpolators();
1955 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1956 static constexpr
int max_nd = 16*16;
1957 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1958 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
1960 MFEM_SHARED
double dof_values[max_nd];
1963 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, 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, face) = res;
1990 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1994 m == L2FaceValues::DoubleValued,
1995 "This method should be called when m == L2FaceValues::DoubleValued.");
1996 if (x_interp.Size()==0)
1998 x_interp.SetSize(x.
Size());
2001 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
2004 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
2008 const int nface_dofs = face_dofs;
2009 const int vd = vdim;
2012 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
2013 const int num_nc_faces = nc_interp_config.Size();
2014 if ( num_nc_faces == 0 ) {
return; }
2015 auto interp_config_ptr = nc_interp_config.Read();
2016 auto interpolators = interpolations.GetInterpolators().Read();
2017 const int nc_size = interpolations.GetNumInterpolators();
2018 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2019 static constexpr
int max_nd = 16*16;
2020 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
2021 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
2023 MFEM_SHARED
double dof_values[max_nd];
2026 const int interp_index = conf.
index;
2031 for (
int c = 0; c < vd; ++c)
2033 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
2035 dof_values[dof] = d_x(dof, c, master_side, face);
2038 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
2041 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
2043 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
2045 d_x(dof_out, c, master_side, face) = res;
2053 void NCL2FaceRestriction::AddMultTranspose(
const Vector& x,
Vector& y)
const
2055 if (nf==0) {
return; }
2056 if (type==FaceType::Interior)
2058 if ( m==L2FaceValues::DoubleValued )
2060 DoubleValuedNonconformingTransposeInterpolation(x);
2061 DoubleValuedConformingAddMultTranspose(x_interp, y);
2063 else if ( m==L2FaceValues::SingleValued )
2065 SingleValuedNonconformingTransposeInterpolation(x);
2066 SingleValuedConformingAddMultTranspose(x_interp, y);
2071 if ( m==L2FaceValues::DoubleValued )
2073 DoubleValuedConformingAddMultTranspose(x, y);
2075 else if ( m==L2FaceValues::SingleValued )
2077 SingleValuedConformingAddMultTranspose(x, y);
2082 void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const
2084 if (nf==0) {
return; }
2085 if (type==FaceType::Interior)
2087 if ( m==L2FaceValues::DoubleValued )
2089 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
2090 DoubleValuedConformingAddMultTranspose(x, y);
2092 else if ( m==L2FaceValues::SingleValued )
2094 SingleValuedNonconformingTransposeInterpolationInPlace(x);
2095 SingleValuedConformingAddMultTranspose(x, y);
2100 if ( m==L2FaceValues::DoubleValued )
2102 DoubleValuedConformingAddMultTranspose(x, y);
2104 else if ( m==L2FaceValues::SingleValued )
2106 SingleValuedConformingAddMultTranspose(x, y);
2112 const bool keep_nbr_block)
const
2114 MFEM_ABORT(
"Not yet implemented.");
2117 void NCL2FaceRestriction::FillJAndData(
const Vector &ea_data,
2119 const bool keep_nbr_block)
const
2121 MFEM_ABORT(
"Not yet implemented.");
2124 void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2129 MFEM_ABORT(
"Not yet implemented.");
2140 return ToLexOrdering2D(face_id, size1d, index);
2142 return ToLexOrdering3D(face_id, size1d, index%size1d, index/size1d);
2144 MFEM_ABORT(
"Unsupported dimension.");
2149 void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
2153 Mesh &mesh = *fes.GetMesh();
2156 for (
int i = 0; i <= ndofs; ++i)
2158 gather_offsets[i] = 0;
2163 for (
int f = 0;
f < fes.GetNF(); ++
f)
2165 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2166 if ( face.IsNonconformingCoarse() )
2172 else if ( type==FaceType::Interior && face.IsInterior() )
2174 SetFaceDofsScatterIndices1(face,f_ind);
2175 if ( m==L2FaceValues::DoubleValued )
2177 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2178 if ( face.IsConforming() )
2180 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2184 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2189 else if ( type==FaceType::Boundary && face.IsBoundary() )
2191 SetFaceDofsScatterIndices1(face,f_ind);
2192 if ( m==L2FaceValues::DoubleValued )
2194 SetBoundaryDofsScatterIndices2(face,f_ind);
2199 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2200 (type==FaceType::Interior?
"interior" :
"boundary") <<
2201 " faces: " << f_ind <<
" vs " << nf );
2204 for (
int i = 1; i <= ndofs; ++i)
2206 gather_offsets[i] += gather_offsets[i - 1];
2210 interpolations.LinearizeInterpolatorMapIntoVector();
2211 interpolations.InitializeNCInterpConfig();
2214 void NCL2FaceRestriction::ComputeGatherIndices(
2218 Mesh &mesh = *fes.GetMesh();
2221 for (
int f = 0;
f < fes.GetNF(); ++
f)
2223 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2224 MFEM_ASSERT(!face.IsShared(),
2225 "Unexpected shared face in NCL2FaceRestriction.");
2226 if ( face.IsNonconformingCoarse() )
2232 else if ( face.IsOfFaceType(type) )
2234 SetFaceDofsGatherIndices1(face,f_ind);
2235 if ( m==L2FaceValues::DoubleValued &&
2236 type==FaceType::Interior &&
2239 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2244 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2245 (type==FaceType::Interior?
"interior" :
"boundary") <<
2246 " faces: " << f_ind <<
" vs " << nf );
2249 for (
int i = ndofs; i > 0; --i)
2251 gather_offsets[i] = gather_offsets[i - 1];
2253 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.
Array< NCInterpConfig > nc_interp_config
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
void AddMultTranspose(const Vector &x, Vector &y) const
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
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...
const Array< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
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()
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
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
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 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)
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.
uint32_t is_non_conforming
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.
void AddMultTranspose(const Vector &x, Vector &y) const
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
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...
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.
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
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 ...