32 ndofs(fes.GetNDofs()),
33 dof(fes.GetTypicalFE()->GetDof()),
40 MFEM_VERIFY(!
f.IsVariableOrder(),
"Variable-order spaces are not supported");
45 const int *dof_map = NULL;
46 if (dof_reorder &&
ne > 0)
48 for (
int e = 0; e <
ne; ++e)
55 if (el_t || el_n || el_p) {
continue; }
56 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
64 el_n ? el_n->GetLexicographicOrdering() :
65 el_t ? el_t->GetDofMap() :
66 el_p_tri ? el_p_tri->GetDofMap() :
67 el_p_tet->GetDofMap();
68 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
72 const int* element_map = e2dTable.
GetJ();
74 for (
int i = 0; i <=
ndofs; ++i)
78 for (
int e = 0; e <
ne; ++e)
80 for (
int d = 0; d <
dof; ++d)
82 const int sgid = element_map[
dof*e + d];
83 const int gid = (sgid >= 0) ? sgid : -1 - sgid;
88 for (
int i = 1; i <=
ndofs; ++i)
93 for (
int e = 0; e <
ne; ++e)
95 for (
int d = 0; d <
dof; ++d)
97 const int sdid = dof_reorder ? dof_map[d] : 0;
98 const int did = (!dof_reorder)?d:(sdid >= 0 ? sdid : -1-sdid);
99 const int sgid = element_map[
dof*e + did];
100 const int gid = (sgid >= 0) ? sgid : -1-sgid;
101 const int lid =
dof*e + d;
102 const bool plus = (sgid >= 0 && sdid >= 0) || (sgid < 0 && sdid < 0);
109 for (
int i =
ndofs; i > 0; --i)
127 const int gid = d_gather_map[i];
128 const bool plus = gid >= 0;
129 const int j = plus ? gid : -1-gid;
130 for (
int c = 0; c < vd; ++c)
132 const real_t dof_value = d_x(t?c:j, t?j:c);
133 d_y(i % nd, c, i / nd) = plus ? dof_value : -dof_value;
150 const int gid = d_gather_map[i];
151 const int j = gid >= 0 ? gid : -1-gid;
152 for (
int c = 0; c < vd; ++c)
154 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
160void ElementRestriction::TAddMultTranspose(
const Vector& x,
Vector& y)
const
172 const int offset = d_offsets[i];
173 const int next_offset = d_offsets[i + 1];
174 for (
int c = 0; c < vd; ++c)
177 for (
int j = offset; j < next_offset; ++j)
179 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
180 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
181 -d_x(idx_j % nd, c, idx_j / nd));
183 if (ADD) { d_y(t?c:i,t?i:c) += dof_value; }
184 else { d_y(t?c:i,t?i:c) = dof_value; }
191 constexpr bool ADD =
false;
192 TAddMultTranspose<ADD>(x, y);
198 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
199 constexpr bool ADD =
true;
200 TAddMultTranspose<ADD>(x, y);
215 const int offset = d_offsets[i];
216 const int next_offset = d_offsets[i + 1];
217 for (
int c = 0; c < vd; ++c)
220 for (
int j = offset; j < next_offset; ++j)
222 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
223 dof_value += d_x(idx_j % nd, c, idx_j / nd);
225 d_y(t?c:i,t?i:c) = dof_value;
242 const int next_offset = d_offsets[i + 1];
243 for (
int c = 0; c < vd; ++c)
246 const int j = next_offset - 1;
247 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
248 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
249 -d_x(idx_j % nd, c, idx_j / nd);
250 d_y(t?c:i,t?i:c) = dof_value;
269 for (
int i = 0; i <
ndofs; ++i)
271 const int offset = d_offsets[i];
272 const int next_offset = d_offsets[i+1];
273 for (
int c = 0; c < vd; ++c)
275 for (
int j = offset; j < next_offset; ++j)
277 const int idx_j = d_indices[j];
278 if (d_x(t?c:i,t?i:c))
280 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
284 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
285 d_x(t?c:i,t?i:c) = 1;
296 const int nnz =
FillI(mat);
302static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
303 const int *nbr_elts,
const int nbrNbElts)
306 int min_el = INT_MAX;
307 for (
int i = 0; i < nbElts; i++)
309 const int e_i = my_elts[i];
310 if (e_i >= min_el) {
continue; }
311 for (
int j = 0; j < nbrNbElts; j++)
313 if (e_i==nbr_elts[j])
325static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
333 const int all_dofs =
ndofs;
335 const int elt_dofs =
dof;
344 mfem::forall(vd*all_dofs+1, [=] MFEM_HOST_DEVICE (
int i_L)
350 const int e = l_dof/elt_dofs;
351 const int i = l_dof%elt_dofs;
353 const int i_gm = e*elt_dofs + i;
354 const int i_L = d_gather_map[i_gm];
355 const int i_offset = d_offsets[i_L];
356 const int i_next_offset = d_offsets[i_L+1];
357 const int i_nbElts = i_next_offset - i_offset;
359 int *i_elts = &d_ij_elts(i_offset, 0);
360 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
362 const int i_E = d_indices[i_offset+e_i];
363 i_elts[e_i] = i_E/elt_dofs;
365 for (
int j = 0; j < elt_dofs; j++)
367 const int j_gm = e*elt_dofs + j;
368 const int j_L = d_gather_map[j_gm];
369 const int j_offset = d_offsets[j_L];
370 const int j_next_offset = d_offsets[j_L+1];
371 const int j_nbElts = j_next_offset - j_offset;
372 if (i_nbElts == 1 || j_nbElts == 1)
374 GetAndIncrementNnzIndex(i_L, I);
378 int *j_elts = &d_ij_elts(j_offset, 1);
379 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
381 const int j_E = d_indices[j_offset+e_j];
382 const int elt = j_E/elt_dofs;
385 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
388 GetAndIncrementNnzIndex(i_L, I);
395 const int nTdofs = vd*all_dofs;
397 for (
int i = 0; i < nTdofs; i++)
399 const int nnz = h_I[i];
411 const int all_dofs =
ndofs;
413 const int elt_dofs =
dof;
420 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
427 const int e = l_dof/elt_dofs;
428 const int i = l_dof%elt_dofs;
430 const int i_gm = e*elt_dofs + i;
431 const int i_L = d_gather_map[i_gm];
432 const int i_offset = d_offsets[i_L];
433 const int i_next_offset = d_offsets[i_L+1];
434 const int i_nbElts = i_next_offset - i_offset;
436 int *i_elts = &d_ij_B_el(i_offset, 0);
437 int *i_B = &d_ij_B_el(i_offset, 1);
438 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
440 const int i_E = d_indices[i_offset+e_i];
441 i_elts[e_i] = i_E/elt_dofs;
442 i_B[e_i] = i_E%elt_dofs;
444 for (
int j = 0; j < elt_dofs; j++)
446 const int j_gm = e*elt_dofs + j;
447 const int j_L = d_gather_map[j_gm];
448 const int j_offset = d_offsets[j_L];
449 const int j_next_offset = d_offsets[j_L+1];
450 const int j_nbElts = j_next_offset - j_offset;
451 if (i_nbElts == 1 || j_nbElts == 1)
453 const int nnz = GetAndIncrementNnzIndex(i_L, I);
455 Data[nnz] = mat_ea(j,i,e);
459 int *j_elts = &d_ij_B_el(j_offset, 2);
460 int *j_B = &d_ij_B_el(j_offset, 3);
461 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
463 const int j_E = d_indices[j_offset+e_j];
464 const int elt = j_E/elt_dofs;
466 j_B[e_j] = j_E%elt_dofs;
468 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
472 for (
int k = 0; k < i_nbElts; k++)
474 const int e_i = i_elts[k];
475 const int i_Bloc = i_B[k];
476 for (
int l = 0; l < j_nbElts; l++)
478 const int e_j = j_elts[l];
479 const int j_Bloc = j_B[l];
482 val += mat_ea(j_Bloc, i_Bloc, e_i);
486 const int nnz = GetAndIncrementNnzIndex(i_L, I);
496 const int size = vd*all_dofs;
497 for (
int i = 0; i < size; i++)
499 h_I[size-i] = h_I[size-(i+1)];
508 ndof(fes.GetTypicalFE()->GetDof()),
509 ndofs(fes.GetNDofs())
512 width = vdim*ne*ndof;
519 const bool t = byvdim;
520 auto d_x =
Reshape(x.
Read(), t?vd:ndofs, t?ndofs:vd);
525 const int dof = idx % nd;
526 const int e = idx / nd;
527 for (
int c = 0; c < vd; ++c)
529 d_y(dof, c, e) = d_x(t?c:idx, t?idx:c);
535void L2ElementRestriction::TAddMultTranspose(
const Vector &x,
Vector &y)
const
539 const bool t = byvdim;
545 const int dof = idx % nd;
546 const int e = idx / nd;
547 for (
int c = 0; c < vd; ++c)
549 if (ADD) { d_y(t?c:idx,t?idx:c) += d_x(dof, c, e); }
550 else { d_y(t?c:idx,t?idx:c) = d_x(dof, c, e); }
557 constexpr bool ADD =
false;
558 TAddMultTranspose<ADD>(x, y);
564 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
565 constexpr bool ADD =
true;
566 TAddMultTranspose<ADD>(x, y);
571 const int elem_dofs = ndof;
574 const int isize = mat.
Height() + 1;
575 const int interior_dofs = ne*elem_dofs*vd;
578 I[dof] = dof<interior_dofs ? elem_dofs : 0;
582static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
591 const int elem_dofs = ndof;
596 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
597 mfem::forall(ne*elem_dofs*vd, [=] MFEM_HOST_DEVICE (
int iE)
599 const int offset = AddNnz(iE,I,elem_dofs);
600 const int e = iE/elem_dofs;
601 const int i = iE%elem_dofs;
602 for (
int j = 0; j < elem_dofs; j++)
604 J[offset+j] = e*elem_dofs+j;
605 Data[offset+j] = mat_ea(j,i,e);
616 nf(fes.GetNFbyType(type)),
619 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
620 elem_dofs(fes.GetTypicalFE()->GetDof()),
621 nfdofs(nf*face_dofs),
622 ndofs(fes.GetNDofs()),
623 scatter_indices(nf*face_dofs),
624 gather_offsets(ndofs+1),
625 gather_indices(nf*face_dofs),
630 if (
nf==0) {
return; }
638 if (dof_map_.
Size() > 0)
651 if (!build) {
return; }
652 ComputeScatterIndicesAndOffsets(f_ordering, type);
653 ComputeGatherIndices(f_ordering,type);
664 const bool useAbs)
const
666 if (
nf==0) {
return; }
676 const int s_idx = d_indices[i];
677 const int sgn = (useAbs || s_idx >= 0) ? 1 : -1;
678 const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
679 const int dof = i % nface_dofs;
680 const int face = i / nface_dofs;
681 for (
int c = 0; c < vd; ++c)
683 d_y(dof, c, face) = sgn*d_x(t?c:idx, t?idx:c);
688static void ConformingFaceRestriction_AddMultTranspose(
701 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
702 if (nf==0) {
return; }
704 auto d_offsets = gather_offsets.
Read();
705 auto d_indices = gather_indices.
Read();
710 const int offset = d_offsets[i];
711 const int next_offset = d_offsets[i + 1];
712 for (
int c = 0; c < vdim; ++c)
715 for (
int j = offset; j < next_offset; ++j)
717 const int s_idx_j = d_indices[j];
718 const real_t sgn = (s_idx_j >= 0 || !use_signs) ? 1.0 : -1.0;
719 const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
720 dof_value += sgn*d_x(idx_j % face_dofs, c, idx_j / face_dofs);
722 d_y(by_vdim?c:i,by_vdim?i:c) += dof_value;
730 ConformingFaceRestriction_AddMultTranspose(
738 ConformingFaceRestriction_AddMultTranspose(
753 pfes->GetParMesh()->ExchangeFaceNbrData();
761 MFEM_VERIFY(tfe != NULL,
762 "ConformingFaceRestriction only supports TensorBasisElements");
765 "ConformingFaceRestriction only supports Gauss-Lobatto and Bernstein bases");
769 if (dof_reorder &&
nf > 0)
776 if (el) {
continue; }
777 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
783void ConformingFaceRestriction::ComputeScatterIndicesAndOffsets(
790 for (
int i = 0; i <=
ndofs; ++i)
800 if ( face.IsNonconformingCoarse() )
806 else if ( face.IsOfFaceType(type) )
812 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
815 for (
int i = 1; i <=
ndofs; ++i)
821void ConformingFaceRestriction::ComputeGatherIndices(
832 if ( face.IsNonconformingCoarse() )
838 else if ( face.IsOfFaceType(type) )
844 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
847 for (
int i =
ndofs; i > 0; --i)
856 const int face_index,
860 "This method should not be used on nonconforming coarse faces.");
862 "FaceRestriction used on degenerated mesh.");
864 "NATIVE ordering is not supported yet");
869 const int* elem_map = e2dTable.
GetJ();
872 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
874 const int lex_volume_dof =
face_map[face_dof];
877 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
879 const int restriction_dof =
face_dofs*face_index + face_dof;
887 const int face_index,
891 "This method should not be used on nonconforming coarse faces.");
893 "NATIVE ordering is not supported yet");
898 const int* elem_map = e2dTable.
GetJ();
901 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
903 const int lex_volume_dof =
face_map[face_dof];
906 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
907 const int sgn = (s_global_dof >= 0) ? 1 : -1;
909 const int restriction_dof =
face_dofs*face_index + face_dof;
910 const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
918 const int face_id2,
const int orientation,
919 const int size1d,
const int index)
926 return internal::PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
928 return internal::PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
930 MFEM_ABORT(
"Unsupported dimension.");
941 ordering(f_ordering),
942 nf(fes.GetNFbyType(type)),
946 face_dofs(fes.GetTypicalTraceElement()->GetDof()),
947 elem_dofs(fes.GetTypicalFE()->GetDof()),
948 nfdofs(nf*face_dofs),
949 ndofs(fes.GetNDofs()),
952 scatter_indices1(nf*face_dofs),
954 gather_offsets(ndofs+1),
960 if (!build) {
return; }
963 ComputeScatterIndicesAndOffsets();
964 ComputeGatherIndices();
977 if (
nf == 0) {
return; }
980 "This method should be called when m == L2FaceValues::SingleValued.");
990 const int dof = i % nface_dofs;
991 const int face = i / nface_dofs;
992 const int idx1 = d_indices1[i];
993 for (
int c = 0; c < vd; ++c)
995 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
1005 "This method should be called when m == L2FaceValues::DoubleValued.");
1008 const int vd =
vdim;
1016 const int dof = i % nface_dofs;
1017 const int face = i / nface_dofs;
1018 const int idx1 = d_indices1[i];
1019 for (
int c = 0; c < vd; ++c)
1021 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
1023 const int idx2 = d_indices2[i];
1024 for (
int c = 0; c < vd; ++c)
1026 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(t?c:idx2, t?idx2:c);
1033 if (
nf==0) {
return; }
1049 const int vd =
vdim;
1057 const int offset = d_offsets[i];
1058 const int next_offset = d_offsets[i + 1];
1059 for (
int c = 0; c < vd; ++c)
1062 for (
int j = offset; j < next_offset; ++j)
1064 int idx_j = d_indices[j];
1065 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1067 d_y(t?c:i,t?i:c) += dof_value;
1077 const int vd =
vdim;
1086 const int offset = d_offsets[i];
1087 const int next_offset = d_offsets[i + 1];
1088 for (
int c = 0; c < vd; ++c)
1091 for (
int j = offset; j < next_offset; ++j)
1093 int idx_j = d_indices[j];
1094 bool isE1 = idx_j < dofs;
1095 idx_j = isE1 ? idx_j : idx_j - dofs;
1097 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1098 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1100 d_y(t?c:i,t?i:c) += dof_value;
1108 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1109 if (
nf==0) {
return; }
1121 const bool keep_nbr_block)
const
1129 const int iE1 = d_indices1[fdof];
1130 const int iE2 = d_indices2[fdof];
1131 AddNnz(iE1,I,nface_dofs);
1132 AddNnz(iE2,I,nface_dofs);
1138 const bool keep_nbr_block)
const
1144 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1149 const int f = fdof/nface_dofs;
1150 const int iF = fdof%nface_dofs;
1151 const int iE1 = d_indices1[
f*nface_dofs+iF];
1152 const int iE2 = d_indices2[
f*nface_dofs+iF];
1153 const int offset1 = AddNnz(iE1,I,nface_dofs);
1154 const int offset2 = AddNnz(iE2,I,nface_dofs);
1155 for (
int jF = 0; jF < nface_dofs; jF++)
1157 const int jE1 = d_indices1[
f*nface_dofs+jF];
1158 const int jE2 = d_indices2[
f*nface_dofs+jF];
1159 J[offset2+jF] = jE1;
1160 J[offset1+jF] = jE2;
1161 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1162 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1177 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1181 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1182 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1183 for (
int j = 0; j < nface_dofs; j++)
1185 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1186 for (
int i = 0; i < nface_dofs; i++)
1188 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1189 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1194 for (
int j = 0; j < nface_dofs; j++)
1196 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1197 for (
int i = 0; i < nface_dofs; i++)
1199 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1200 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1209 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1213 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1214 for (
int j = 0; j < nface_dofs; j++)
1216 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1217 for (
int i = 0; i < nface_dofs; i++)
1219 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1236 pfes->GetParMesh()->ExchangeFaceNbrData();
1245 MFEM_VERIFY(tfe != NULL &&
1248 "Only Gauss-Lobatto and Bernstein basis are supported in "
1249 "L2FaceRestriction.");
1250 if (
nf==0) {
return; }
1254 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1256 if (dof_reorder &&
nf > 0)
1262 if (el) {
continue; }
1263 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1269void L2FaceRestriction::ComputeScatterIndicesAndOffsets()
1273 for (
int i = 0; i <=
ndofs; ++i)
1283 MFEM_ASSERT(!face.IsShared(),
1284 "Unexpected shared face in L2FaceRestriction.");
1285 if ( face.IsOfFaceType(
type) )
1302 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1305 for (
int i = 1; i <=
ndofs; ++i)
1311void L2FaceRestriction::ComputeGatherIndices()
1319 MFEM_ASSERT(!face.IsShared(),
1320 "Unexpected shared face in L2FaceRestriction.");
1321 if ( face.IsOfFaceType(
type) )
1333 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1336 for (
int i =
ndofs; i > 0; --i)
1345 const int face_index)
1348 "This method should not be used on nonconforming coarse faces.");
1350 const int* elem_map = e2dTable.
GetJ();
1355 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1357 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1358 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1359 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1367 const int face_index)
1370 "This method should only be used on local faces.");
1372 const int* elem_map = e2dTable.
GetJ();
1381 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1386 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1387 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1388 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1396 const int face_index)
1400 "This method should only be used on shared faces.");
1409 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1412 orientation, dof1d, face_dof_elem1);
1413 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1415 const int global_dof_elem2 = elem_index*
elem_dofs + volume_dof_elem2;
1416 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1425 const int face_index)
1428 "This method should only be used on boundary faces.");
1432 const int restriction_dof_elem2 =
face_dofs*face_index + d;
1439 const int face_index)
1442 "This method should not be used on nonconforming coarse faces.");
1444 const int* elem_map = e2dTable.
GetJ();
1449 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1451 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1452 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1453 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1461 const int face_index)
1464 "This method should only be used on local faces.");
1466 const int* elem_map = e2dTable.
GetJ();
1475 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1480 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1481 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1482 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1485 restriction_dof_elem2;
1491 EnsureNormalDerivativeRestriction();
1498 EnsureNormalDerivativeRestriction();
1502void L2FaceRestriction::EnsureNormalDerivativeRestriction()
const
1515 ordering(ordering_),
1516 interp_config(fes.GetNFbyType(type)),
1532 "Registering face as nonconforming even though it is not.");
1535 const int master_side =
1537 const int face_key = (master_side == 0 ? 1000 : 0) +
1543 Key key(ptMat, face_key);
1548 GetCoarseToFineInterpolation(face,ptMat);
1555 interp_config[face_index] = {master_side, itr->second.first};
1559const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1564 "The following interpolation operator is only implemented for"
1565 "lexicographic ordering.");
1567 "This method should not be called on conforming faces.")
1568 const
int face_id1 = face.element[0].local_face_id;
1569 const
int face_id2 = face.element[1].local_face_id;
1571 const
bool is_ghost_slave =
1572 face.element[0].conformity ==
Mesh::ElementConformity::Superset;
1573 const
int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1579 const
int face_dofs = trace_fe->GetDof();
1582 const auto dof_map = el->GetDofMap();
1587 isotr.SetIdentityTransformation(trace_fe->GetGeomType());
1588 isotr.SetPointMat(*ptMat);
1589 DenseMatrix native_interpolator(face_dofs,face_dofs);
1590 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1596 native_interpolator *= (isotr.
Weight() >= 0) ? 1.0 : -1.0;
1599 const int dim = trace_fe->GetDim()+1;
1600 const int dof1d = trace_fe->GetOrder()+1;
1610 for (
int i = 0; i < face_dofs; i++)
1612 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1614 if ( !is_ghost_slave )
1618 orientation_i, dof1d, li);
1620 for (
int j = 0; j < face_dofs; j++)
1623 if ( !is_ghost_slave )
1627 orientation_j, dof1d, lj);
1629 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1630 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1633 return interpolator;
1640 const int face_dofs = trace_fe->
GetDof();
1641 const int nc_size =
static_cast<int>(
interp_map.size());
1642 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1647 const int idx = val.second.first;
1648 const DenseMatrix &interpolator = *val.second.second;
1649 for (
int i = 0; i < face_dofs; i++)
1651 for (
int j = 0; j < face_dofs; j++)
1653 d_interp(i,j,idx) = interpolator(i,j);
1656 delete val.second.second;
1664 int num_nc_faces = 0;
1678 if ( config.is_non_conforming )
1692 interpolations(fes.GetInterpolationManager(ordering, type))
1694 if (!build) {
return; }
1699 ComputeScatterIndicesAndOffsets();
1701 ComputeGatherIndices();
1721 if (
nf == 0) {
return; }
1724 const int vd =
vdim;
1727 const int num_nc_faces = nc_interp_config.Size();
1728 if ( num_nc_faces == 0 ) {
return; }
1729 auto interp_config_ptr = nc_interp_config.Read();
1732 nface_dofs, nface_dofs, nc_size);
1733 static constexpr int max_nd = 16*16;
1734 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1735 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1737 MFEM_SHARED
real_t dof_values[max_nd];
1741 const int master_side = conf.master_side;
1742 const int interp_index = conf.index;
1743 const int face = conf.face_index;
1744 for (int c = 0; c < vd; ++c)
1746 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1748 dof_values[dof] = d_y(dof, c, master_side, face);
1751 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1754 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1756 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1758 d_y(dof_out, c, master_side, face) = res;
1768 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1770 DoubleValuedNonconformingMult(x, y);
1772 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1774 DoubleValuedConformingMult(x, y);
1778 SingleValuedConformingMult(x, y);
1782void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1786 m == L2FaceValues::SingleValued,
1787 "This method should be called when m == L2FaceValues::SingleValued.");
1788 if (x_interp.Size()==0)
1790 x_interp.SetSize(x.
Size());
1793 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1797void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1801 const int nface_dofs = face_dofs;
1802 const int vd = vdim;
1804 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1805 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1806 const int num_nc_faces = nc_interp_config.Size();
1807 if ( num_nc_faces == 0 ) {
return; }
1808 auto interp_config_ptr = nc_interp_config.Read();
1809 auto interpolators = interpolations.GetInterpolators().Read();
1810 const int nc_size = interpolations.GetNumInterpolators();
1811 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1812 static constexpr int max_nd = 16*16;
1813 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1814 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1816 MFEM_SHARED
real_t dof_values[max_nd];
1819 const int interp_index = conf.
index;
1824 for (int c = 0; c < vd; ++c)
1826 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1828 dof_values[dof] = d_x(dof, c, face);
1831 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1834 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1836 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1838 d_x(dof_out, c, face) = res;
1846void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1850 m == L2FaceValues::DoubleValued,
1851 "This method should be called when m == L2FaceValues::DoubleValued.");
1852 if (x_interp.Size()==0)
1854 x_interp.SetSize(x.
Size());
1857 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1860void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
1864 const int nface_dofs = face_dofs;
1865 const int vd = vdim;
1868 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1869 const int num_nc_faces = nc_interp_config.Size();
1870 if ( num_nc_faces == 0 ) {
return; }
1871 auto interp_config_ptr = nc_interp_config.Read();
1872 auto interpolators = interpolations.GetInterpolators().Read();
1873 const int nc_size = interpolations.GetNumInterpolators();
1874 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1875 static constexpr int max_nd = 16*16;
1876 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1877 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1879 MFEM_SHARED
real_t dof_values[max_nd];
1882 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_x(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_in, dof_out, interp_index)*dof_values[dof_in];
1901 d_x(dof_out, c, master_side, face) = res;
1912 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1913 if (nf==0) {
return; }
1914 if (type==FaceType::Interior)
1916 if ( m==L2FaceValues::DoubleValued )
1918 DoubleValuedNonconformingTransposeInterpolation(x);
1919 DoubleValuedConformingAddMultTranspose(x_interp, y);
1921 else if ( m==L2FaceValues::SingleValued )
1923 SingleValuedNonconformingTransposeInterpolation(x);
1924 SingleValuedConformingAddMultTranspose(x_interp, y);
1929 if ( m==L2FaceValues::DoubleValued )
1931 DoubleValuedConformingAddMultTranspose(x, y);
1933 else if ( m==L2FaceValues::SingleValued )
1935 SingleValuedConformingAddMultTranspose(x, y);
1940void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const
1942 if (nf==0) {
return; }
1943 if (type==FaceType::Interior)
1945 if ( m==L2FaceValues::DoubleValued )
1947 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
1948 DoubleValuedConformingAddMultTranspose(x, y);
1950 else if ( m==L2FaceValues::SingleValued )
1952 SingleValuedNonconformingTransposeInterpolationInPlace(x);
1953 SingleValuedConformingAddMultTranspose(x, y);
1958 if ( m==L2FaceValues::DoubleValued )
1960 DoubleValuedConformingAddMultTranspose(x, y);
1962 else if ( m==L2FaceValues::SingleValued )
1964 SingleValuedConformingAddMultTranspose(x, y);
1970 const bool keep_nbr_block)
const
1972 const int nface_dofs = face_dofs;
1973 auto d_indices1 = scatter_indices1.Read();
1974 auto d_indices2 = scatter_indices2.Read();
1976 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1978 const int iE1 = d_indices1[fdof];
1979 const int iE2 = d_indices2[fdof];
1980 AddNnz(iE1,I,nface_dofs);
1981 AddNnz(iE2,I,nface_dofs);
1985void NCL2FaceRestriction::FillJAndData(
const Vector &fea_data,
1987 const bool keep_nbr_block)
const
1989 const int nface_dofs = face_dofs;
1990 auto d_indices1 = scatter_indices1.Read();
1991 auto d_indices2 = scatter_indices2.Read();
1993 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
1996 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1997 auto interpolators = interpolations.GetInterpolators().Read();
1998 const int nc_size = interpolations.GetNumInterpolators();
1999 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2000 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
2002 const int f = fdof/nface_dofs;
2005 const int interp_index = conf.
index;
2006 const int iF = fdof%nface_dofs;
2007 const int iE1 = d_indices1[
f*nface_dofs+iF];
2008 const int iE2 = d_indices2[
f*nface_dofs+iF];
2009 const int offset1 = AddNnz(iE1,I,nface_dofs);
2010 const int offset2 = AddNnz(iE2,I,nface_dofs);
2011 for (
int jF = 0; jF < nface_dofs; jF++)
2013 const int jE1 = d_indices1[
f*nface_dofs+jF];
2014 const int jE2 = d_indices2[
f*nface_dofs+jF];
2015 J[offset2+jF] = jE1;
2016 J[offset1+jF] = jE2;
2021 for (
int kF = 0; kF < nface_dofs; kF++)
2023 val1 += mat_fea(kF,iF,0,
f) * d_interp(kF, jF, interp_index);
2024 val2 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,1,
f);
2029 for (
int kF = 0; kF < nface_dofs; kF++)
2031 val1 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,0,
f);
2032 val2 += mat_fea(kF,iF,1,
f) * d_interp(kF, jF, interp_index);
2037 val1 = mat_fea(jF,iF,0,
f);
2038 val2 = mat_fea(jF,iF,1,
f);
2040 Data[offset2+jF] = val1;
2041 Data[offset1+jF] = val2;
2046void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2051 const int nface_dofs = face_dofs;
2052 const int nelem_dofs = elem_dofs;
2054 if (m==L2FaceValues::DoubleValued)
2056 auto d_indices1 = scatter_indices1.Read();
2057 auto d_indices2 = scatter_indices2.Read();
2058 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
2060 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2061 auto interpolators = interpolations.GetInterpolators().Read();
2062 const int nc_size = interpolations.GetNumInterpolators();
2063 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2068 const int interp_index = conf.
index;
2069 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
2070 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
2071 for (
int j = 0; j < nface_dofs; j++)
2073 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
2074 for (
int i = 0; i < nface_dofs; i++)
2076 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
2080 for (int k = 0; k < nface_dofs; k++)
2082 for (int l = 0; l < nface_dofs; l++)
2084 val += d_interp(l, j, interp_index)
2086 * d_interp(k, i, interp_index);
2092 val = mat_fea(i,j,0,
f);
2099 for (
int j = 0; j < nface_dofs; j++)
2101 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
2102 for (
int i = 0; i < nface_dofs; i++)
2104 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
2106 if ( conf.is_non_conforming && master_side==1 )
2108 for (
int k = 0; k < nface_dofs; k++)
2110 for (
int l = 0; l < nface_dofs; l++)
2112 val += d_interp(l, j, interp_index)
2114 * d_interp(k, i, interp_index);
2120 val = mat_fea(i,j,1,
f);
2130 auto d_indices = scatter_indices1.Read();
2131 auto mat_fea =
Reshape(fea_data.Read(), nface_dofs, nface_dofs, nf);
2132 auto mat_ea =
Reshape(ea_data.ReadWrite(), nelem_dofs, nelem_dofs, ne);
2133 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2134 auto interpolators = interpolations.GetInterpolators().Read();
2135 const int nc_size = interpolations.GetNumInterpolators();
2136 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2141 const int interp_index = conf.
index;
2142 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
2143 for (
int j = 0; j < nface_dofs; j++)
2145 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
2146 for (
int i = 0; i < nface_dofs; i++)
2148 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
2152 for (int k = 0; k < nface_dofs; k++)
2154 for (int l = 0; l < nface_dofs; l++)
2156 val += d_interp(l, j, interp_index)
2158 * d_interp(k, i, interp_index);
2164 val = mat_fea(i,j,
f);
2181 return internal::ToLexOrdering2D(face_id, size1d,
index);
2183 return internal::ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2185 MFEM_ABORT(
"Unsupported dimension.");
2190void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets()
2192 Mesh &mesh = *fes.GetMesh();
2195 for (
int i = 0; i <= ndofs; ++i)
2197 gather_offsets[i] = 0;
2202 for (
int f = 0;
f < fes.GetNF(); ++
f)
2204 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2205 if ( face.IsNonconformingCoarse() )
2211 else if ( type==FaceType::Interior && face.IsInterior() )
2213 SetFaceDofsScatterIndices1(face,f_ind);
2214 if ( m==L2FaceValues::DoubleValued )
2216 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2220 else if ( type==FaceType::Boundary && face.IsBoundary() )
2222 SetFaceDofsScatterIndices1(face,f_ind);
2223 if ( m==L2FaceValues::DoubleValued )
2225 SetBoundaryDofsScatterIndices2(face,f_ind);
2230 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2231 (type==FaceType::Interior?
"interior" :
"boundary") <<
2232 " faces: " << f_ind <<
" vs " << nf );
2235 for (
int i = 1; i <= ndofs; ++i)
2237 gather_offsets[i] += gather_offsets[i - 1];
2241void NCL2FaceRestriction::ComputeGatherIndices()
2243 Mesh &mesh = *fes.GetMesh();
2246 for (
int f = 0;
f < fes.GetNF(); ++
f)
2248 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2249 MFEM_ASSERT(!face.IsShared(),
2250 "Unexpected shared face in NCL2FaceRestriction.");
2251 if ( face.IsNonconformingCoarse() )
2257 else if ( face.IsOfFaceType(type) )
2259 SetFaceDofsGatherIndices1(face,f_ind);
2260 if ( m==L2FaceValues::DoubleValued &&
2261 type==FaceType::Interior &&
2264 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2269 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2270 (type==FaceType::Interior?
"interior" :
"boundary") <<
2271 " faces: " << f_ind <<
" vs " << nf );
2274 for (
int i = ndofs; i > 0; --i)
2276 gather_offsets[i] = gather_offsets[i - 1];
2278 gather_offsets[0] = 0;
2281static int GetSharedVSize(
const FiniteElementSpace &fes)
2284 if (
auto pfes =
dynamic_cast<const ParFiniteElementSpace*
>(&fes))
2286 const_cast<ParFiniteElementSpace*
>(pfes)->ExchangeFaceNbrData();
2287 return pfes->GetFaceNbrVSize();
2293L2InterfaceFaceRestriction::L2InterfaceFaceRestriction(
2298 ordering(ordering_),
2300 nfaces(fes.GetNFbyType(type)),
2301 vdim(fes.GetVDim()),
2303 face_dofs(fes.GetTypicalTraceElement()->GetDof()),
2304 nfdofs(face_dofs*nfaces),
2305 ndofs(fes.GetNDofs()),
2306 nsdofs(GetSharedVSize(fes))
2343 MFEM_ASSERT(pfes !=
nullptr,
"");
2344 pfes->GetFaceNbrFaceVDofs(
f, dofs);
2358 const int NDOFS =
ndofs;
2361 const int vd =
vdim;
2366 MFEM_ASSERT(face_nbr_data.
Size() / vd ==
nsdofs,
"");
2369 const auto d_x_shared =
Reshape(face_nbr_data.
Read(),
2375 const int j = map[i];
2376 for (
int c = 0; c < vd; ++c)
2378 if (j < NDOFS) { d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c); }
2379 else { d_y(i % nd, c, i / nd) = d_x_shared(t?c:(j-NDOFS), t?(j-NDOFS):c); }
2389 const int vd =
vdim;
2398 const int j = map[i];
2399 if (j < 0) {
return; }
2400 for (
int c = 0; c < vd; ++c)
2402 d_y(t?c:i, t?i:c) +=
a*d_x(j % nd, c, j / nd);
2412 const int vd =
vdim;
2422 const int j = map[i];
2423 if (j < 0) {
return; }
2424 for (
int c = 0; c < vd; ++c)
2426 d_y(t?c:i, t?i:c) = d_x(j % nd, c, j / nd);
2453 Vector &gf_face_nbr = x_gf->FaceNbrData();
2454 if (gf_face_nbr.
Size() == 0) { x_gf->ExchangeFaceNbrData(); }
2456 return Vector(gf_face_nbr, 0, gf_face_nbr.
Size());
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
@ GaussLobatto
Closed type.
@ Positive
Bernstein polynomials.
Data type dense matrix using column-major storage.
ElementRestriction(const FiniteElementSpace &, ElementDofOrdering)
const FiniteElementSpace & fes
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
void AbsMult(const Vector &x, Vector &y) const override
Compute Mult without applying signs based on DOF orientations.
void FillSparseMatrix(const Vector &mat_ea, SparseMatrix &mat) const
Fill a Sparse Matrix with Element Matrices.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
void MultLeftInverse(const Vector &x, Vector &y) const
void BooleanMask(Vector &y) const
Fills the E-vector y with boolean values 0.0 and 1.0 such that each each entry of the L-vector is uni...
void AbsMultTranspose(const Vector &x, Vector &y) const override
Compute MultTranspose without applying signs based on DOF orientations.
int FillI(SparseMatrix &mat) const
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
const Table & GetFaceToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each face in the m...
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
const FiniteElement * GetTypicalTraceElement() const
Return a "typical" trace element.
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Mesh * GetMesh() const
Returns the mesh.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Abstract class for all finite elements.
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
virtual void GetFaceMap(const int face_id, Array< int > &face_map) const
Return the mapping from lexicographic face DOFs to lexicographic element DOFs for the given local fac...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
const IntegrationPoint & GetCenter(int GeomType) const
Return the center of the given Geometry::Type, GeomType.
Arbitrary order H1 elements in 2D utilizing the Bernstein basis on a triangle.
InterpolationManager(const FiniteElementSpace &fes, ElementDofOrdering ordering, FaceType type)
Constructor.
std::pair< const DenseMatrix *, int > Key
const Array< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void RegisterFaceCoarseToFineInterpolation(const Mesh::FaceInformation &face, int face_index)
Register the face with face and index face_index as a nonconforming (master-slave) face,...
int GetNumInterpolators() const
Return the total number of interpolators.
Array< NCInterpConfig > nc_interp_config
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...
void InitializeNCInterpConfig()
void LinearizeInterpolatorMapIntoVector()
Transform the interpolation matrix map into a contiguous memory structure.
const FiniteElementSpace & fes
const ElementDofOrdering ordering
Array< InterpConfig > interp_config
void RegisterFaceConformingInterpolation(const Mesh::FaceInformation &face, int face_index)
Register the face with face and index face_index as a conforming face for the interpolation of the de...
L2ElementRestriction(const FiniteElementSpace &)
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the E-vector degrees of freedom x to the L-vector degrees of freedom y.
void FillJAndData(const Vector &ea_data, SparseMatrix &mat) const
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
void FillI(SparseMatrix &mat) const
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
Operator that extracts Face degrees of freedom for L2 spaces.
void PermuteAndSetFaceDofsGatherIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the gathering indices of elem2 for the interior face described by the face....
virtual void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const
Fill the I array of SparseMatrix corresponding to the sparsity pattern given by this L2FaceRestrictio...
Array< int > scatter_indices2
void SingleValuedConformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with co...
L2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an L2FaceRestriction.
void NormalDerivativeMult(const Vector &x, Vector &y) const override
For each face, sets y to the partial derivative of x with respect to the reference coordinate perpend...
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
void NormalDerivativeAddMultTranspose(const Vector &x, Vector &y) const override
Add the face reference-normal derivative degrees of freedom in x to the element degrees of freedom in...
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
void SingleValuedConformingAddMultTranspose(const Vector &x, Vector &y) const
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector. Should only be used with con...
std::unique_ptr< L2NormalDerivativeFaceRestriction > normal_deriv_restr
void PermuteAndSetSharedFaceDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the scattering indices of elem2 for the shared face described by the face....
void CheckFESpace()
Verify that L2FaceRestriction is built from an L2 FESpace.
Array< int > gather_offsets
virtual void DoubleValuedConformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with co...
void PermuteAndSetFaceDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Permute and set the scattering indices of elem2, and increment the offsets for the face described by ...
Array< int > scatter_indices1
const FiniteElementSpace & fes
void SetBoundaryDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem2 for the boundary face described by the face.
void SetFaceDofsScatterIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem1, and increment the offsets for the face described by the face....
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
const ElementDofOrdering ordering
void DoubleValuedConformingAddMultTranspose(const Vector &x, Vector &y) const
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector. Should only be used with con...
virtual void FillJAndData(const Vector &fea_data, SparseMatrix &mat, const bool keep_nbr_block=false) const
Fill the J and Data arrays of the SparseMatrix corresponding to the sparsity pattern given by this L2...
Array< int > gather_indices
virtual void AddFaceMatricesToElementMatrices(const Vector &fea_data, Vector &ea_data) const
This method adds the DG face matrices to the element matrices.
const int face_dofs
Number of dofs on each face.
const int ndofs
Number of dofs in the space (L-vector size)
const int nfdofs
Total number of dofs on the faces (E-vector size)
Array< int > scatter_map
Scatter map.
const FiniteElementSpace & fes
The finite element space.
Array< int > gather_map
Gather map.
const int vdim
vdim of the space
const Array< int > & ScatterMap() const
Return the low-level mapping from L-dofs to E-dofs.
const int nfaces
Number of faces of the requested type.
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
const int nsdofs
Number of shared face neighbor (ghost) dofs.
const Array< int > & GatherMap() const override
Low-level access to the underlying gather map.
void MultTransposeShared(const Vector &x, Vector &y) const
Gather degrees of freedom, from face E-vector to L-vector and shared (ghost) DOFs.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
const FaceType type
Face type (interior or boundary)
const bool byvdim
DOF ordering (by nodes or by vdim)
Class to compute face normal derivatives (in reference coordinate) of an L2 grid function (used inter...
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
int Dimension() const
Dimension of the reference space used within the elements.
FaceInformation GetFaceInformation(int f) const
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
const InterpolationManager & interpolations
virtual void DoubleValuedNonconformingMult(const Vector &x, Vector &y) const
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with no...
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs.
NCL2FaceRestriction(const FiniteElementSpace &fes, const ElementDofOrdering f_ordering, const FaceType type, const L2FaceValues m, bool build)
Constructs an NCL2FaceRestriction, this is a specialization of a L2FaceRestriction for nonconforming ...
Class for standard nodal finite elements.
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
Abstract parallel finite element space.
Class for parallel grid function.
void ExchangeFaceNbrData()
int * ReadWriteI(bool on_dev=true)
int * WriteJ(bool on_dev=true)
Memory< int > & GetMemoryI()
int * WriteI(bool on_dev=true)
Memory< int > & GetMemoryJ()
Memory< real_t > & GetMemoryData()
real_t * WriteData(bool on_dev=true)
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
void SyncMemory(const Vector &v) const
Update the memory location of the vector to match v.
int Size() const
Returns the size of the vector.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void SetSize(int s)
Resize the vector to size s.
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
int index(int i, int j, int nx, int ny)
real_t f(const Vector &p)
Vector GetLVectorFaceNbrData(const FiniteElementSpace &fes, const Vector &x, FaceType ftype)
Return the face-neighbor data given the L-vector x.
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
MFEM_HOST_DEVICE int UnsignIndex(int i)
int ToLexOrdering(const int dim, const int face_id, const int size1d, const int index)
Convert a dof face index from Native ordering to lexicographic ordering for quads and hexes.
void forall_2D(int N, int X, int Y, lambda &&body)
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
int PermuteFaceL2(const int dim, const int face_id1, const int face_id2, const int orientation, const int size1d, const int index)
Compute the dof face index of elem2 corresponding to the given dof face index.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
void forall(int N, lambda &&body)
uint32_t is_non_conforming
uint32_t is_non_conforming