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)
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;
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 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);
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;
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(vd*all_dofs+1, [=] MFEM_HOST_DEVICE (
int i_L)
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);
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;
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;
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;
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(ne*elem_dofs*vd, [=] MFEM_HOST_DEVICE (
int iE)
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);
607 nf(fes.GetNFbyType(type)),
610 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
611 elem_dofs(fes.GetFE(0)->GetDof()),
612 nfdofs(nf*face_dofs),
613 ndofs(fes.GetNDofs()),
614 scatter_indices(nf*face_dofs),
615 gather_offsets(ndofs+1),
616 gather_indices(nf*face_dofs),
621 if (
nf==0) {
return; }
629 if (dof_map_.
Size() > 0)
642 if (!build) {
return; }
643 ComputeScatterIndicesAndOffsets(f_ordering, type);
644 ComputeGatherIndices(f_ordering,type);
656 if (
nf==0) {
return; }
666 const int s_idx = d_indices[i];
667 const int sgn = (s_idx >= 0) ? 1 : -1;
668 const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
669 const int dof = i % nface_dofs;
670 const int face = i / nface_dofs;
671 for (
int c = 0; c < vd; ++c)
673 d_y(dof, c, face) = sgn*d_x(
t?c:idx,
t?idx:c);
678 static void ConformingFaceRestriction_AddMultTranspose(
691 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
692 if (nf==0) {
return; }
694 auto d_offsets = gather_offsets.
Read();
695 auto d_indices = gather_indices.
Read();
700 const int offset = d_offsets[i];
701 const int next_offset = d_offsets[i + 1];
702 for (
int c = 0; c < vdim; ++c)
704 double dof_value = 0;
705 for (
int j = offset; j < next_offset; ++j)
707 const int s_idx_j = d_indices[j];
708 const double sgn = (s_idx_j >= 0 || !use_signs) ? 1.0 : -1.0;
709 const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
710 dof_value += sgn*d_x(idx_j % face_dofs, c, idx_j / face_dofs);
712 d_y(by_vdim?c:i,by_vdim?i:c) += dof_value;
720 ConformingFaceRestriction_AddMultTranspose(
728 ConformingFaceRestriction_AddMultTranspose(
741 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
743 pfes->GetParMesh()->ExchangeFaceNbrData();
751 MFEM_VERIFY(tfe != NULL &&
754 "Only Gauss-Lobatto and Bernstein basis are supported in " 755 "ConformingFaceRestriction.");
759 if (dof_reorder &&
nf > 0)
766 if (el) {
continue; }
767 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
773 void ConformingFaceRestriction::ComputeScatterIndicesAndOffsets(
780 for (
int i = 0; i <=
ndofs; ++i)
790 if ( face.IsNonconformingCoarse() )
796 else if ( face.IsOfFaceType(type) )
802 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
805 for (
int i = 1; i <=
ndofs; ++i)
811 void ConformingFaceRestriction::ComputeGatherIndices(
822 if ( face.IsNonconformingCoarse() )
828 else if ( face.IsOfFaceType(type) )
834 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
837 for (
int i =
ndofs; i > 0; --i)
844 static inline int absdof(
int i) {
return i < 0 ? -1-i : i; }
848 const int face_index,
852 "This method should not be used on nonconforming coarse faces.");
854 "FaceRestriction used on degenerated mesh.");
855 MFEM_CONTRACT_VAR(f_ordering);
860 const int* elem_map = e2dTable.
GetJ();
863 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
865 const int lex_volume_dof =
face_map[face_dof];
867 const int volume_dof = absdof(s_volume_dof);
868 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
869 const int global_dof = absdof(s_global_dof);
870 const int restriction_dof =
face_dofs*face_index + face_dof;
878 const int face_index,
882 "This method should not be used on nonconforming coarse faces.");
883 MFEM_CONTRACT_VAR(f_ordering);
888 const int* elem_map = e2dTable.
GetJ();
891 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
893 const int lex_volume_dof =
face_map[face_dof];
895 const int volume_dof = absdof(s_volume_dof);
896 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
897 const int sgn = (s_global_dof >= 0) ? 1 : -1;
898 const int global_dof = absdof(s_global_dof);
899 const int restriction_dof =
face_dofs*face_index + face_dof;
900 const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
906 static int ToLexOrdering2D(
const int face_id,
const int size1d,
const int i)
908 if (face_id==2 || face_id==3)
918 static int PermuteFace2D(
const int face_id1,
const int face_id2,
919 const int orientation,
920 const int size1d,
const int index)
924 if (face_id1==2 || face_id1==3)
926 new_index = size1d-1-
index;
935 new_index = size1d-1-new_index;
937 return ToLexOrdering2D(face_id2, size1d, new_index);
940 static int ToLexOrdering3D(
const int face_id,
const int size1d,
const int i,
943 if (face_id==2 || face_id==1 || face_id==5)
947 else if (face_id==3 || face_id==4)
949 return (size1d-1-i) + j*size1d;
953 return i + (size1d-1-j)*size1d;
957 static int PermuteFace3D(
const int face_id1,
const int face_id2,
958 const int orientation,
959 const int size1d,
const int index)
961 int i=0, j=0, new_i=0, new_j=0;
965 if (face_id1==3 || face_id1==4)
969 else if (face_id1==0)
986 new_j = (size1d-1-i);
989 new_i = (size1d-1-i);
993 new_i = (size1d-1-i);
994 new_j = (size1d-1-j);
997 new_i = (size1d-1-j);
998 new_j = (size1d-1-i);
1001 new_i = (size1d-1-j);
1006 new_j = (size1d-1-j);
1009 return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
1014 const int face_id2,
const int orientation,
1015 const int size1d,
const int index)
1022 return PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
1024 return PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
1026 MFEM_ABORT(
"Unsupported dimension.");
1037 nf(fes.GetNFbyType(type)),
1039 vdim(fes.GetVDim()),
1042 fes.GetTraceElement(0, fes.
GetMesh()->GetFaceGeometry(0))->GetDof()
1044 elem_dofs(fes.GetFE(0)->GetDof()),
1045 nfdofs(nf*face_dofs),
1046 ndofs(fes.GetNDofs()),
1049 scatter_indices1(nf*face_dofs),
1051 gather_offsets(ndofs+1),
1057 if (!build) {
return; }
1061 ComputeScatterIndicesAndOffsets(f_ordering,
type);
1063 ComputeGatherIndices(f_ordering,
type);
1076 if (
nf == 0) {
return; }
1079 "This method should be called when m == L2FaceValues::SingleValued.");
1082 const int vd =
vdim;
1089 const int dof = i % nface_dofs;
1090 const int face = i / nface_dofs;
1091 const int idx1 = d_indices1[i];
1092 for (
int c = 0; c < vd; ++c)
1094 d_y(dof, c, face) = d_x(
t?c:idx1,
t?idx1:c);
1104 "This method should be called when m == L2FaceValues::DoubleValued.");
1107 const int vd =
vdim;
1115 const int dof = i % nface_dofs;
1116 const int face = i / nface_dofs;
1117 const int idx1 = d_indices1[i];
1118 for (
int c = 0; c < vd; ++c)
1120 d_y(dof, c, 0, face) = d_x(
t?c:idx1,
t?idx1:c);
1122 const int idx2 = d_indices2[i];
1123 for (
int c = 0; c < vd; ++c)
1125 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(
t?c:idx2,
t?idx2:c);
1132 if (
nf==0) {
return; }
1148 const int vd =
vdim;
1156 const int offset = d_offsets[i];
1157 const int next_offset = d_offsets[i + 1];
1158 for (
int c = 0; c < vd; ++c)
1160 double dof_value = 0;
1161 for (
int j = offset; j < next_offset; ++j)
1163 int idx_j = d_indices[j];
1164 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1166 d_y(
t?c:i,
t?i:c) += dof_value;
1176 const int vd =
vdim;
1185 const int offset = d_offsets[i];
1186 const int next_offset = d_offsets[i + 1];
1187 for (
int c = 0; c < vd; ++c)
1189 double dof_value = 0;
1190 for (
int j = offset; j < next_offset; ++j)
1192 int idx_j = d_indices[j];
1193 bool isE1 = idx_j < dofs;
1194 idx_j = isE1 ? idx_j : idx_j - dofs;
1196 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1197 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1199 d_y(
t?c:i,
t?i:c) += dof_value;
1205 const double a)
const 1207 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1208 if (
nf==0) {
return; }
1220 const bool keep_nbr_block)
const 1228 const int iE1 = d_indices1[fdof];
1229 const int iE2 = d_indices2[fdof];
1230 AddNnz(iE1,I,nface_dofs);
1231 AddNnz(iE2,I,nface_dofs);
1237 const bool keep_nbr_block)
const 1243 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1248 const int f = fdof/nface_dofs;
1249 const int iF = fdof%nface_dofs;
1250 const int iE1 = d_indices1[
f*nface_dofs+iF];
1251 const int iE2 = d_indices2[
f*nface_dofs+iF];
1252 const int offset1 = AddNnz(iE1,I,nface_dofs);
1253 const int offset2 = AddNnz(iE2,I,nface_dofs);
1254 for (
int jF = 0; jF < nface_dofs; jF++)
1256 const int jE1 = d_indices1[
f*nface_dofs+jF];
1257 const int jE2 = d_indices2[
f*nface_dofs+jF];
1258 J[offset2+jF] = jE1;
1259 J[offset1+jF] = jE2;
1260 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1261 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1276 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1280 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1281 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1282 for (
int j = 0; j < nface_dofs; j++)
1284 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1285 for (
int i = 0; i < nface_dofs; i++)
1287 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1288 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1293 for (
int j = 0; j < nface_dofs; j++)
1295 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1296 for (
int i = 0; i < nface_dofs; i++)
1298 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1299 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1308 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1312 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1313 for (
int j = 0; j < nface_dofs; j++)
1315 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1316 for (
int i = 0; i < nface_dofs; i++)
1318 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1333 = dynamic_cast<const ParFiniteElementSpace*>(&
fes))
1335 pfes->GetParMesh()->ExchangeFaceNbrData();
1344 MFEM_VERIFY(tfe != NULL &&
1347 "Only Gauss-Lobatto and Bernstein basis are supported in " 1348 "L2FaceRestriction.");
1349 if (
nf==0) {
return; }
1353 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1355 if (dof_reorder &&
nf > 0)
1363 if (el) {
continue; }
1364 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1370 void L2FaceRestriction::ComputeScatterIndicesAndOffsets(
1376 for (
int i = 0; i <=
ndofs; ++i)
1386 MFEM_ASSERT(!face.IsShared(),
1387 "Unexpected shared face in L2FaceRestriction.");
1388 if ( face.IsOfFaceType(face_type) )
1405 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1408 for (
int i = 1; i <=
ndofs; ++i)
1414 void L2FaceRestriction::ComputeGatherIndices(
1424 MFEM_ASSERT(!face.IsShared(),
1425 "Unexpected shared face in L2FaceRestriction.");
1426 if ( face.IsOfFaceType(face_type) )
1438 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1441 for (
int i =
ndofs; i > 0; --i)
1450 const int face_index)
1453 "This method should not be used on nonconforming coarse faces.");
1455 const int* elem_map = e2dTable.
GetJ();
1460 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1462 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1463 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1464 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1472 const int face_index)
1475 "This method should only be used on local faces.");
1477 const int* elem_map = e2dTable.
GetJ();
1486 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1491 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1492 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1493 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1501 const int face_index)
1505 "This method should only be used on shared faces.");
1518 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1521 orientation, dof1d, face_dof_elem1);
1522 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1523 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1524 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1533 const int face_index)
1536 "This method should only be used on boundary faces.");
1540 const int restriction_dof_elem2 =
face_dofs*face_index + d;
1547 const int face_index)
1550 "This method should not be used on nonconforming coarse faces.");
1552 const int* elem_map = e2dTable.
GetJ();
1557 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1559 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1560 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1561 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1569 const int face_index)
1572 "This method should only be used on local faces.");
1574 const int* elem_map = e2dTable.
GetJ();
1583 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1588 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1589 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1590 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1593 restriction_dof_elem2;
1618 "Registering face as nonconforming even though it is not.");
1621 const int master_side =
1623 const int face_key = (master_side == 0 ? 1000 : 0) +
1628 Key key(ptMat, face_key);
1633 GetCoarseToFineInterpolation(face,ptMat);
1640 interp_config[face_index] = {master_side, itr->second.first};
1644 const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1649 "The following interpolation operator is only implemented for" 1650 "lexicographic ordering.");
1652 "This method should not be called on conforming faces.")
1656 const bool is_ghost_slave =
1658 const int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1665 const int face_dofs = trace_fe->
GetDof();
1679 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1681 DenseMatrix native_interpolator(face_dofs,face_dofs);
1682 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1683 const int dim = trace_fe->GetDim()+1;
1684 const int dof1d = trace_fe->GetOrder()+1;
1686 for (
int i = 0; i < face_dofs; i++)
1688 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1690 if ( !is_ghost_slave )
1694 orientation, dof1d, li);
1696 for (
int j = 0; j < face_dofs; j++)
1699 if ( !is_ghost_slave )
1703 orientation, dof1d, lj);
1705 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1706 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1709 return interpolator;
1717 const int face_dofs = trace_fe->
GetDof();
1719 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1724 const int idx = val.second.first;
1725 const DenseMatrix &interpolator = *val.second.second;
1726 for (
int i = 0; i < face_dofs; i++)
1728 for (
int j = 0; j < face_dofs; j++)
1730 d_interp(i,j,idx) = interpolator(i,j);
1733 delete val.second.second;
1741 int num_nc_faces = 0;
1755 if ( config.is_non_conforming )
1769 interpolations(fes, f_ordering, type)
1771 if (!build) {
return; }
1776 ComputeScatterIndicesAndOffsets(f_ordering,
type);
1778 ComputeGatherIndices(f_ordering,
type);
1798 if (
nf == 0) {
return; }
1801 const int vd =
vdim;
1804 const int num_nc_faces = nc_interp_config.Size();
1805 if ( num_nc_faces == 0 ) {
return; }
1806 auto interp_config_ptr = nc_interp_config.Read();
1809 nface_dofs, nface_dofs, nc_size);
1810 static constexpr
int max_nd = 16*16;
1811 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1812 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1814 MFEM_SHARED
double dof_values[max_nd];
1818 const int master_side = conf.master_side;
1819 const int interp_index = conf.index;
1820 const int face = conf.face_index;
1821 for (int c = 0; c < vd; ++c)
1823 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1825 dof_values[dof] = d_y(dof, c, master_side, face);
1828 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1831 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1833 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1835 d_y(dof_out, c, master_side, face) = res;
1845 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1847 DoubleValuedNonconformingMult(x, y);
1849 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1851 DoubleValuedConformingMult(x, y);
1855 SingleValuedConformingMult(x, y);
1859 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1863 m == L2FaceValues::SingleValued,
1864 "This method should be called when m == L2FaceValues::SingleValued.");
1865 if (x_interp.Size()==0)
1867 x_interp.SetSize(x.
Size());
1870 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1874 void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1878 const int nface_dofs = face_dofs;
1879 const int vd = vdim;
1881 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1882 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1883 const int num_nc_faces = nc_interp_config.Size();
1884 if ( num_nc_faces == 0 ) {
return; }
1885 auto interp_config_ptr = nc_interp_config.Read();
1886 auto interpolators = interpolations.GetInterpolators().Read();
1887 const int nc_size = interpolations.GetNumInterpolators();
1888 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1889 static constexpr
int max_nd = 16*16;
1890 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1891 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1893 MFEM_SHARED
double dof_values[max_nd];
1896 const int interp_index = conf.
index;
1901 for (int c = 0; c < vd; ++c)
1903 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1905 dof_values[dof] = d_x(dof, c, face);
1908 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1911 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1913 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1915 d_x(dof_out, c, face) = res;
1923 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1927 m == L2FaceValues::DoubleValued,
1928 "This method should be called when m == L2FaceValues::DoubleValued.");
1929 if (x_interp.Size()==0)
1931 x_interp.SetSize(x.
Size());
1934 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1937 void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
1941 const int nface_dofs = face_dofs;
1942 const int vd = vdim;
1945 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1946 const int num_nc_faces = nc_interp_config.Size();
1947 if ( num_nc_faces == 0 ) {
return; }
1948 auto interp_config_ptr = nc_interp_config.Read();
1949 auto interpolators = interpolations.GetInterpolators().Read();
1950 const int nc_size = interpolations.GetNumInterpolators();
1951 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1952 static constexpr
int max_nd = 16*16;
1953 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1954 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1956 MFEM_SHARED
double dof_values[max_nd];
1959 const int interp_index = conf.
index;
1964 for (int c = 0; c < vd; ++c)
1966 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1968 dof_values[dof] = d_x(dof, c, master_side, face);
1971 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1974 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1976 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1978 d_x(dof_out, c, master_side, face) = res;
1987 const double a)
const 1989 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1990 if (nf==0) {
return; }
1991 if (type==FaceType::Interior)
1993 if ( m==L2FaceValues::DoubleValued )
1995 DoubleValuedNonconformingTransposeInterpolation(x);
1996 DoubleValuedConformingAddMultTranspose(x_interp, y);
1998 else if ( m==L2FaceValues::SingleValued )
2000 SingleValuedNonconformingTransposeInterpolation(x);
2001 SingleValuedConformingAddMultTranspose(x_interp, y);
2006 if ( m==L2FaceValues::DoubleValued )
2008 DoubleValuedConformingAddMultTranspose(x, y);
2010 else if ( m==L2FaceValues::SingleValued )
2012 SingleValuedConformingAddMultTranspose(x, y);
2017 void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const 2019 if (nf==0) {
return; }
2020 if (type==FaceType::Interior)
2022 if ( m==L2FaceValues::DoubleValued )
2024 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
2025 DoubleValuedConformingAddMultTranspose(x, y);
2027 else if ( m==L2FaceValues::SingleValued )
2029 SingleValuedNonconformingTransposeInterpolationInPlace(x);
2030 SingleValuedConformingAddMultTranspose(x, y);
2035 if ( m==L2FaceValues::DoubleValued )
2037 DoubleValuedConformingAddMultTranspose(x, y);
2039 else if ( m==L2FaceValues::SingleValued )
2041 SingleValuedConformingAddMultTranspose(x, y);
2047 const bool keep_nbr_block)
const 2049 MFEM_ABORT(
"Not yet implemented.");
2052 void NCL2FaceRestriction::FillJAndData(
const Vector &ea_data,
2054 const bool keep_nbr_block)
const 2056 MFEM_ABORT(
"Not yet implemented.");
2059 void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2064 MFEM_ABORT(
"Not yet implemented.");
2075 return ToLexOrdering2D(face_id, size1d,
index);
2077 return ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2079 MFEM_ABORT(
"Unsupported dimension.");
2084 void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
2088 Mesh &mesh = *fes.GetMesh();
2091 for (
int i = 0; i <= ndofs; ++i)
2093 gather_offsets[i] = 0;
2098 for (
int f = 0;
f < fes.GetNF(); ++
f)
2100 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2101 if ( face.IsNonconformingCoarse() )
2107 else if ( type==FaceType::Interior && face.IsInterior() )
2109 SetFaceDofsScatterIndices1(face,f_ind);
2110 if ( m==L2FaceValues::DoubleValued )
2112 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2113 if ( face.IsConforming() )
2115 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2119 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2124 else if ( type==FaceType::Boundary && face.IsBoundary() )
2126 SetFaceDofsScatterIndices1(face,f_ind);
2127 if ( m==L2FaceValues::DoubleValued )
2129 SetBoundaryDofsScatterIndices2(face,f_ind);
2134 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2135 (type==FaceType::Interior?
"interior" :
"boundary") <<
2136 " faces: " << f_ind <<
" vs " << nf );
2139 for (
int i = 1; i <= ndofs; ++i)
2141 gather_offsets[i] += gather_offsets[i - 1];
2145 interpolations.LinearizeInterpolatorMapIntoVector();
2146 interpolations.InitializeNCInterpConfig();
2149 void NCL2FaceRestriction::ComputeGatherIndices(
2153 Mesh &mesh = *fes.GetMesh();
2156 for (
int f = 0;
f < fes.GetNF(); ++
f)
2158 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2159 MFEM_ASSERT(!face.IsShared(),
2160 "Unexpected shared face in NCL2FaceRestriction.");
2161 if ( face.IsNonconformingCoarse() )
2167 else if ( face.IsOfFaceType(type) )
2169 SetFaceDofsGatherIndices1(face,f_ind);
2170 if ( m==L2FaceValues::DoubleValued &&
2171 type==FaceType::Interior &&
2174 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2179 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2180 (type==FaceType::Interior?
"interior" :
"boundary") <<
2181 " faces: " << f_ind <<
" vs " << nf );
2184 for (
int i = ndofs; i > 0; --i)
2186 gather_offsets[i] = gather_offsets[i - 1];
2188 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 forall_2D(int N, int X, int Y, lambda &&body)
void PermuteAndSetSharedFaceDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the scattering indices of elem2 for the shared face described by the face...
void 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.
int Dimension() const
Dimension of the reference space used within the elements.
void SetSize(int s)
Resize the vector to size s.
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()
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...
std::function< double(const Vector &)> f(double mass_coeff)
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
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()
InterpolationManager()=delete
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)
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.
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 ...
void forall(int N, lambda &&body)
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...
L2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an L2FaceRestriction.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
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
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...
int Size() const
Return the logical size of the array.
FaceInformation GetFaceInformation(int f) const
void MakeRef(T *, int)
Make this Array a reference to a pointer.
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.
virtual void GetFaceMap(const int face_id, Array< int > &face_map) const
Return the mapping from lexicographic face DOFs to lexicographic element DOFs for the given local fac...
int 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 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.
void CheckFESpace(const ElementDofOrdering f_ordering)
Verify that L2FaceRestriction is built from an L2 FESpace.
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...
InterpolationManager interpolations
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
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)
NCL2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an NCL2FaceRestriction, this is a specialization of a L2FaceRestriction for nonconforming ...