32 ndofs(fes.GetNDofs()),
33 dof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
43 const int *dof_map = NULL;
44 if (dof_reorder &&
ne > 0)
46 for (
int e = 0; e <
ne; ++e)
52 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
58 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
62 const int* element_map = e2dTable.
GetJ();
64 for (
int i = 0; i <=
ndofs; ++i)
68 for (
int e = 0; e <
ne; ++e)
70 for (
int d = 0; d <
dof; ++d)
72 const int sgid = element_map[
dof*e + d];
73 const int gid = (sgid >= 0) ? sgid : -1 - sgid;
78 for (
int i = 1; i <=
ndofs; ++i)
83 for (
int e = 0; e <
ne; ++e)
85 for (
int d = 0; d <
dof; ++d)
87 const int sdid = dof_reorder ? dof_map[d] : 0;
88 const int did = (!dof_reorder)?d:(sdid >= 0 ? sdid : -1-sdid);
89 const int sgid = element_map[
dof*e + did];
90 const int gid = (sgid >= 0) ? sgid : -1-sgid;
91 const int lid =
dof*e + d;
92 const bool plus = (sgid >= 0 && sdid >= 0) || (sgid < 0 && sdid < 0);
99 for (
int i =
ndofs; i > 0; --i)
117 const int gid = d_gather_map[i];
118 const bool plus = gid >= 0;
119 const int j = plus ? gid : -1-gid;
120 for (
int c = 0; c < vd; ++c)
122 const real_t dof_value = d_x(
t?c:j,
t?j:c);
123 d_y(i % nd, c, i / nd) = plus ? dof_value : -dof_value;
140 const int gid = d_gather_map[i];
141 const int j = gid >= 0 ? gid : -1-gid;
142 for (
int c = 0; c < vd; ++c)
144 d_y(i % nd, c, i / nd) = d_x(
t?c:j,
t?j:c);
150void ElementRestriction::TAddMultTranspose(
const Vector& x,
Vector& y)
const
162 const int offset = d_offsets[i];
163 const int next_offset = d_offsets[i + 1];
164 for (
int c = 0; c < vd; ++c)
167 for (
int j = offset; j < next_offset; ++j)
169 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
170 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
171 -d_x(idx_j % nd, c, idx_j / nd));
173 if (ADD) { d_y(
t?c:i,
t?i:c) += dof_value; }
174 else { d_y(
t?c:i,
t?i:c) = dof_value; }
181 constexpr bool ADD =
false;
182 TAddMultTranspose<ADD>(x, y);
188 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
189 constexpr bool ADD =
true;
190 TAddMultTranspose<ADD>(x, y);
205 const int offset = d_offsets[i];
206 const int next_offset = d_offsets[i + 1];
207 for (
int c = 0; c < vd; ++c)
210 for (
int j = offset; j < next_offset; ++j)
212 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
213 dof_value += d_x(idx_j % nd, c, idx_j / nd);
215 d_y(
t?c:i,
t?i:c) = dof_value;
232 const int next_offset = d_offsets[i + 1];
233 for (
int c = 0; c < vd; ++c)
236 const int j = next_offset - 1;
237 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
238 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
239 -d_x(idx_j % nd, c, idx_j / nd);
240 d_y(
t?c:i,
t?i:c) = dof_value;
259 for (
int i = 0; i <
ndofs; ++i)
261 const int offset = d_offsets[i];
262 const int next_offset = d_offsets[i+1];
263 for (
int c = 0; c < vd; ++c)
265 for (
int j = offset; j < next_offset; ++j)
267 const int idx_j = d_indices[j];
268 if (d_x(
t?c:i,
t?i:c))
270 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
274 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
275 d_x(
t?c:i,
t?i:c) = 1;
286 const int nnz =
FillI(mat);
292static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
293 const int *nbr_elts,
const int nbrNbElts)
296 int min_el = INT_MAX;
297 for (
int i = 0; i < nbElts; i++)
299 const int e_i = my_elts[i];
300 if (e_i >= min_el) {
continue; }
301 for (
int j = 0; j < nbrNbElts; j++)
303 if (e_i==nbr_elts[j])
315static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
323 static constexpr int Max = MaxNbNbr;
324 const int all_dofs =
ndofs;
326 const int elt_dofs =
dof;
331 mfem::forall(vd*all_dofs+1, [=] MFEM_HOST_DEVICE (
int i_L)
337 const int e = l_dof/elt_dofs;
338 const int i = l_dof%elt_dofs;
341 const int i_gm = e*elt_dofs + i;
342 const int i_L = d_gather_map[i_gm];
343 const int i_offset = d_offsets[i_L];
344 const int i_next_offset = d_offsets[i_L+1];
345 const int i_nbElts = i_next_offset - i_offset;
348 "The connectivity of this mesh is beyond the max, increase the "
349 "MaxNbNbr variable to comply with your mesh.");
350 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
352 const int i_E = d_indices[i_offset+e_i];
353 i_elts[e_i] = i_E/elt_dofs;
355 for (
int j = 0; j < elt_dofs; j++)
357 const int j_gm = e*elt_dofs + j;
358 const int j_L = d_gather_map[j_gm];
359 const int j_offset = d_offsets[j_L];
360 const int j_next_offset = d_offsets[j_L+1];
361 const int j_nbElts = j_next_offset - j_offset;
364 "The connectivity of this mesh is beyond the max, increase the "
365 "MaxNbNbr variable to comply with your mesh.");
366 if (i_nbElts == 1 || j_nbElts == 1)
368 GetAndIncrementNnzIndex(i_L, I);
373 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
375 const int j_E = d_indices[j_offset+e_j];
376 const int elt = j_E/elt_dofs;
379 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
382 GetAndIncrementNnzIndex(i_L, I);
389 const int nTdofs = vd*all_dofs;
391 for (
int i = 0; i < nTdofs; i++)
393 const int nnz = h_I[i];
405 static constexpr int Max = MaxNbNbr;
406 const int all_dofs =
ndofs;
408 const int elt_dofs =
dof;
415 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
418 const int e = l_dof/elt_dofs;
419 const int i = l_dof%elt_dofs;
423 const int i_gm = e*elt_dofs + i;
424 const int i_L = d_gather_map[i_gm];
425 const int i_offset = d_offsets[i_L];
426 const int i_next_offset = d_offsets[i_L+1];
427 const int i_nbElts = i_next_offset - i_offset;
430 "The connectivity of this mesh is beyond the max, increase the "
431 "MaxNbNbr variable to comply with your mesh.");
432 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
434 const int i_E = d_indices[i_offset+e_i];
435 i_elts[e_i] = i_E/elt_dofs;
436 i_B[e_i] = i_E%elt_dofs;
438 for (
int j = 0; j < elt_dofs; j++)
440 const int j_gm = e*elt_dofs + j;
441 const int j_L = d_gather_map[j_gm];
442 const int j_offset = d_offsets[j_L];
443 const int j_next_offset = d_offsets[j_L+1];
444 const int j_nbElts = j_next_offset - j_offset;
445 if (i_nbElts == 1 || j_nbElts == 1)
447 const int nnz = GetAndIncrementNnzIndex(i_L, I);
449 Data[nnz] = mat_ea(j,i,e);
455 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
457 const int j_E = d_indices[j_offset+e_j];
458 const int elt = j_E/elt_dofs;
460 j_B[e_j] = j_E%elt_dofs;
462 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
466 for (
int k = 0; k < i_nbElts; k++)
468 const int e_i = i_elts[k];
469 const int i_Bloc = i_B[k];
470 for (
int l = 0; l < j_nbElts; l++)
472 const int e_j = j_elts[l];
473 const int j_Bloc = j_B[l];
476 val += mat_ea(j_Bloc, i_Bloc, e_i);
480 const int nnz = GetAndIncrementNnzIndex(i_L, I);
490 const int size = vd*all_dofs;
491 for (
int i = 0; i < size; i++)
493 h_I[size-i] = h_I[size-(i+1)];
502 ndof(ne > 0 ? fes.GetFE(0)->GetDof() : 0),
503 ndofs(fes.GetNDofs())
506 width = vdim*ne*ndof;
513 const bool t = byvdim;
519 const int dof = idx % nd;
520 const int e = idx / nd;
521 for (
int c = 0; c < vd; ++c)
523 d_y(dof, c, e) = d_x(
t?c:idx,
t?idx:c);
529void L2ElementRestriction::TAddMultTranspose(
const Vector &x,
Vector &y)
const
533 const bool t = byvdim;
539 const int dof = idx % nd;
540 const int e = idx / nd;
541 for (
int c = 0; c < vd; ++c)
543 if (ADD) { d_y(
t?c:idx,
t?idx:c) += d_x(dof, c, e); }
544 else { d_y(
t?c:idx,
t?idx:c) = d_x(dof, c, e); }
551 constexpr bool ADD =
false;
552 TAddMultTranspose<ADD>(x, y);
558 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
559 constexpr bool ADD =
true;
560 TAddMultTranspose<ADD>(x, y);
565 const int elem_dofs = ndof;
568 const int isize = mat.
Height() + 1;
569 const int interior_dofs = ne*elem_dofs*vd;
572 I[dof] = dof<interior_dofs ? elem_dofs : 0;
576static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
585 const int elem_dofs = ndof;
590 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
591 mfem::forall(ne*elem_dofs*vd, [=] MFEM_HOST_DEVICE (
int iE)
593 const int offset = AddNnz(iE,I,elem_dofs);
594 const int e = iE/elem_dofs;
595 const int i = iE%elem_dofs;
596 for (
int j = 0; j < elem_dofs; j++)
598 J[offset+j] = e*elem_dofs+j;
599 Data[offset+j] = mat_ea(j,i,e);
610 nf(fes.GetNFbyType(type)),
613 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
614 elem_dofs(fes.GetFE(0)->GetDof()),
615 nfdofs(nf*face_dofs),
616 ndofs(fes.GetNDofs()),
617 scatter_indices(nf*face_dofs),
618 gather_offsets(ndofs+1),
619 gather_indices(nf*face_dofs),
624 if (
nf==0) {
return; }
632 if (dof_map_.
Size() > 0)
645 if (!build) {
return; }
646 ComputeScatterIndicesAndOffsets(f_ordering, type);
647 ComputeGatherIndices(f_ordering,type);
659 if (
nf==0) {
return; }
669 const int s_idx = d_indices[i];
670 const int sgn = (s_idx >= 0) ? 1 : -1;
671 const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
672 const int dof = i % nface_dofs;
673 const int face = i / nface_dofs;
674 for (
int c = 0; c < vd; ++c)
676 d_y(dof, c, face) = sgn*d_x(
t?c:idx,
t?idx:c);
681static void ConformingFaceRestriction_AddMultTranspose(
694 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
695 if (nf==0) {
return; }
697 auto d_offsets = gather_offsets.
Read();
698 auto d_indices = gather_indices.
Read();
703 const int offset = d_offsets[i];
704 const int next_offset = d_offsets[i + 1];
705 for (
int c = 0; c < vdim; ++c)
708 for (
int j = offset; j < next_offset; ++j)
710 const int s_idx_j = d_indices[j];
711 const real_t sgn = (s_idx_j >= 0 || !use_signs) ? 1.0 : -1.0;
712 const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
713 dof_value += sgn*d_x(idx_j % face_dofs, c, idx_j / face_dofs);
715 d_y(by_vdim?c:i,by_vdim?i:c) += dof_value;
723 ConformingFaceRestriction_AddMultTranspose(
731 ConformingFaceRestriction_AddMultTranspose(
746 pfes->GetParMesh()->ExchangeFaceNbrData();
754 MFEM_VERIFY(tfe != NULL &&
757 "Only Gauss-Lobatto and Bernstein basis are supported in "
758 "ConformingFaceRestriction.");
762 if (dof_reorder &&
nf > 0)
769 if (el) {
continue; }
770 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
776void ConformingFaceRestriction::ComputeScatterIndicesAndOffsets(
783 for (
int i = 0; i <=
ndofs; ++i)
793 if ( face.IsNonconformingCoarse() )
799 else if ( face.IsOfFaceType(type) )
805 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
808 for (
int i = 1; i <=
ndofs; ++i)
814void ConformingFaceRestriction::ComputeGatherIndices(
825 if ( face.IsNonconformingCoarse() )
831 else if ( face.IsOfFaceType(type) )
837 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
840 for (
int i =
ndofs; i > 0; --i)
847static inline int absdof(
int i) {
return i < 0 ? -1-i : i; }
851 const int face_index,
855 "This method should not be used on nonconforming coarse faces.");
857 "FaceRestriction used on degenerated mesh.");
858 MFEM_CONTRACT_VAR(f_ordering);
863 const int* elem_map = e2dTable.
GetJ();
866 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
868 const int lex_volume_dof =
face_map[face_dof];
870 const int volume_dof = absdof(s_volume_dof);
871 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
872 const int global_dof = absdof(s_global_dof);
873 const int restriction_dof =
face_dofs*face_index + face_dof;
881 const int face_index,
885 "This method should not be used on nonconforming coarse faces.");
886 MFEM_CONTRACT_VAR(f_ordering);
891 const int* elem_map = e2dTable.
GetJ();
894 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
896 const int lex_volume_dof =
face_map[face_dof];
898 const int volume_dof = absdof(s_volume_dof);
899 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
900 const int sgn = (s_global_dof >= 0) ? 1 : -1;
901 const int global_dof = absdof(s_global_dof);
902 const int restriction_dof =
face_dofs*face_index + face_dof;
903 const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
911 const int face_id2,
const int orientation,
912 const int size1d,
const int index)
919 return internal::PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
921 return internal::PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
923 MFEM_ABORT(
"Unsupported dimension.");
934 ordering(f_ordering),
935 nf(fes.GetNFbyType(type)),
940 fes.GetTraceElement(0, fes.
GetMesh()->GetFaceGeometry(0))->GetDof()
942 elem_dofs(fes.GetFE(0)->GetDof()),
943 nfdofs(nf*face_dofs),
944 ndofs(fes.GetNDofs()),
947 scatter_indices1(nf*face_dofs),
949 gather_offsets(ndofs+1),
955 if (!build) {
return; }
958 ComputeScatterIndicesAndOffsets();
959 ComputeGatherIndices();
972 if (
nf == 0) {
return; }
975 "This method should be called when m == L2FaceValues::SingleValued.");
985 const int dof = i % nface_dofs;
986 const int face = i / nface_dofs;
987 const int idx1 = d_indices1[i];
988 for (
int c = 0; c < vd; ++c)
990 d_y(dof, c, face) = d_x(
t?c:idx1,
t?idx1:c);
1000 "This method should be called when m == L2FaceValues::DoubleValued.");
1003 const int vd =
vdim;
1011 const int dof = i % nface_dofs;
1012 const int face = i / nface_dofs;
1013 const int idx1 = d_indices1[i];
1014 for (
int c = 0; c < vd; ++c)
1016 d_y(dof, c, 0, face) = d_x(
t?c:idx1,
t?idx1:c);
1018 const int idx2 = d_indices2[i];
1019 for (
int c = 0; c < vd; ++c)
1021 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(
t?c:idx2,
t?idx2:c);
1028 if (
nf==0) {
return; }
1044 const int vd =
vdim;
1052 const int offset = d_offsets[i];
1053 const int next_offset = d_offsets[i + 1];
1054 for (
int c = 0; c < vd; ++c)
1057 for (
int j = offset; j < next_offset; ++j)
1059 int idx_j = d_indices[j];
1060 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1062 d_y(
t?c:i,
t?i:c) += dof_value;
1072 const int vd =
vdim;
1081 const int offset = d_offsets[i];
1082 const int next_offset = d_offsets[i + 1];
1083 for (
int c = 0; c < vd; ++c)
1086 for (
int j = offset; j < next_offset; ++j)
1088 int idx_j = d_indices[j];
1089 bool isE1 = idx_j < dofs;
1090 idx_j = isE1 ? idx_j : idx_j - dofs;
1092 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1093 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1095 d_y(
t?c:i,
t?i:c) += dof_value;
1103 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1104 if (
nf==0) {
return; }
1116 const bool keep_nbr_block)
const
1124 const int iE1 = d_indices1[fdof];
1125 const int iE2 = d_indices2[fdof];
1126 AddNnz(iE1,I,nface_dofs);
1127 AddNnz(iE2,I,nface_dofs);
1133 const bool keep_nbr_block)
const
1139 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1144 const int f = fdof/nface_dofs;
1145 const int iF = fdof%nface_dofs;
1146 const int iE1 = d_indices1[
f*nface_dofs+iF];
1147 const int iE2 = d_indices2[
f*nface_dofs+iF];
1148 const int offset1 = AddNnz(iE1,I,nface_dofs);
1149 const int offset2 = AddNnz(iE2,I,nface_dofs);
1150 for (
int jF = 0; jF < nface_dofs; jF++)
1152 const int jE1 = d_indices1[
f*nface_dofs+jF];
1153 const int jE2 = d_indices2[
f*nface_dofs+jF];
1154 J[offset2+jF] = jE1;
1155 J[offset1+jF] = jE2;
1156 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1157 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1172 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1176 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1177 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1178 for (
int j = 0; j < nface_dofs; j++)
1180 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1181 for (
int i = 0; i < nface_dofs; i++)
1183 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1184 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1189 for (
int j = 0; j < nface_dofs; j++)
1191 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1192 for (
int i = 0; i < nface_dofs; i++)
1194 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1195 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1204 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1208 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1209 for (
int j = 0; j < nface_dofs; j++)
1211 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1212 for (
int i = 0; i < nface_dofs; i++)
1214 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1231 pfes->GetParMesh()->ExchangeFaceNbrData();
1240 MFEM_VERIFY(tfe != NULL &&
1243 "Only Gauss-Lobatto and Bernstein basis are supported in "
1244 "L2FaceRestriction.");
1245 if (
nf==0) {
return; }
1249 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1251 if (dof_reorder &&
nf > 0)
1259 if (el) {
continue; }
1260 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1266void L2FaceRestriction::ComputeScatterIndicesAndOffsets()
1270 for (
int i = 0; i <=
ndofs; ++i)
1280 MFEM_ASSERT(!face.IsShared(),
1281 "Unexpected shared face in L2FaceRestriction.");
1282 if ( face.IsOfFaceType(
type) )
1299 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1302 for (
int i = 1; i <=
ndofs; ++i)
1308void L2FaceRestriction::ComputeGatherIndices()
1316 MFEM_ASSERT(!face.IsShared(),
1317 "Unexpected shared face in L2FaceRestriction.");
1318 if ( face.IsOfFaceType(
type) )
1330 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1333 for (
int i =
ndofs; i > 0; --i)
1342 const int face_index)
1345 "This method should not be used on nonconforming coarse faces.");
1347 const int* elem_map = e2dTable.
GetJ();
1352 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1354 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1355 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1356 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1364 const int face_index)
1367 "This method should only be used on local faces.");
1369 const int* elem_map = e2dTable.
GetJ();
1378 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1383 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1384 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1385 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1393 const int face_index)
1397 "This method should only be used on shared faces.");
1410 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1413 orientation, dof1d, face_dof_elem1);
1414 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1415 const int global_dof_elem2 = face_nbr_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
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) +
1542 Key key(ptMat, face_key);
1547 GetCoarseToFineInterpolation(face,ptMat);
1554 interp_config[face_index] = {master_side, itr->second.first};
1558const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1563 "The following interpolation operator is only implemented for"
1564 "lexicographic ordering.");
1566 "This method should not be called on conforming faces.")
1567 const
int face_id1 = face.element[0].local_face_id;
1568 const
int face_id2 = face.element[1].local_face_id;
1570 const
bool is_ghost_slave =
1571 face.element[0].conformity ==
Mesh::ElementConformity::Superset;
1572 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);
1591 if ( trace_fe->GetGeomType()==
Geometry::SEGMENT && !is_ghost_slave )
1593 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1595 DenseMatrix native_interpolator(face_dofs,face_dofs);
1596 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1597 const int dim = trace_fe->GetDim()+1;
1598 const int dof1d = trace_fe->GetOrder()+1;
1600 for (
int i = 0; i < face_dofs; i++)
1602 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1604 if ( !is_ghost_slave )
1608 orientation, dof1d, li);
1610 for (
int j = 0; j < face_dofs; j++)
1613 if ( !is_ghost_slave )
1617 orientation, dof1d, lj);
1619 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1620 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1623 return interpolator;
1631 const int face_dofs = trace_fe->
GetDof();
1633 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1638 const int idx = val.second.first;
1639 const DenseMatrix &interpolator = *val.second.second;
1640 for (
int i = 0; i < face_dofs; i++)
1642 for (
int j = 0; j < face_dofs; j++)
1644 d_interp(i,j,idx) = interpolator(i,j);
1647 delete val.second.second;
1655 int num_nc_faces = 0;
1669 if ( config.is_non_conforming )
1683 interpolations(fes, f_ordering, type)
1685 if (!build) {
return; }
1690 ComputeScatterIndicesAndOffsets();
1692 ComputeGatherIndices();
1712 if (
nf == 0) {
return; }
1715 const int vd =
vdim;
1718 const int num_nc_faces = nc_interp_config.Size();
1719 if ( num_nc_faces == 0 ) {
return; }
1720 auto interp_config_ptr = nc_interp_config.Read();
1723 nface_dofs, nface_dofs, nc_size);
1724 static constexpr int max_nd = 16*16;
1725 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1726 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1728 MFEM_SHARED
real_t dof_values[max_nd];
1732 const int master_side = conf.master_side;
1733 const int interp_index = conf.index;
1734 const int face = conf.face_index;
1735 for (int c = 0; c < vd; ++c)
1737 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1739 dof_values[dof] = d_y(dof, c, master_side, face);
1742 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1745 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1747 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1749 d_y(dof_out, c, master_side, face) = res;
1759 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1761 DoubleValuedNonconformingMult(x, y);
1763 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1765 DoubleValuedConformingMult(x, y);
1769 SingleValuedConformingMult(x, y);
1773void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1777 m == L2FaceValues::SingleValued,
1778 "This method should be called when m == L2FaceValues::SingleValued.");
1779 if (x_interp.Size()==0)
1781 x_interp.SetSize(x.
Size());
1784 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1788void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1792 const int nface_dofs = face_dofs;
1793 const int vd = vdim;
1795 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1796 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1797 const int num_nc_faces = nc_interp_config.Size();
1798 if ( num_nc_faces == 0 ) {
return; }
1799 auto interp_config_ptr = nc_interp_config.Read();
1800 auto interpolators = interpolations.GetInterpolators().Read();
1801 const int nc_size = interpolations.GetNumInterpolators();
1802 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1803 static constexpr int max_nd = 16*16;
1804 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1805 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1807 MFEM_SHARED
real_t dof_values[max_nd];
1810 const int interp_index = conf.
index;
1815 for (int c = 0; c < vd; ++c)
1817 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1819 dof_values[dof] = d_x(dof, c, face);
1822 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1825 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1827 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1829 d_x(dof_out, c, face) = res;
1837void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1841 m == L2FaceValues::DoubleValued,
1842 "This method should be called when m == L2FaceValues::DoubleValued.");
1843 if (x_interp.Size()==0)
1845 x_interp.SetSize(x.
Size());
1848 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1851void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
1855 const int nface_dofs = face_dofs;
1856 const int vd = vdim;
1859 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1860 const int num_nc_faces = nc_interp_config.Size();
1861 if ( num_nc_faces == 0 ) {
return; }
1862 auto interp_config_ptr = nc_interp_config.Read();
1863 auto interpolators = interpolations.GetInterpolators().Read();
1864 const int nc_size = interpolations.GetNumInterpolators();
1865 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1866 static constexpr int max_nd = 16*16;
1867 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1868 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1870 MFEM_SHARED
real_t dof_values[max_nd];
1873 const int interp_index = conf.
index;
1878 for (int c = 0; c < vd; ++c)
1880 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1882 dof_values[dof] = d_x(dof, c, master_side, face);
1885 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1888 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1890 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1892 d_x(dof_out, c, master_side, face) = res;
1903 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1904 if (nf==0) {
return; }
1905 if (type==FaceType::Interior)
1907 if ( m==L2FaceValues::DoubleValued )
1909 DoubleValuedNonconformingTransposeInterpolation(x);
1910 DoubleValuedConformingAddMultTranspose(x_interp, y);
1912 else if ( m==L2FaceValues::SingleValued )
1914 SingleValuedNonconformingTransposeInterpolation(x);
1915 SingleValuedConformingAddMultTranspose(x_interp, y);
1920 if ( m==L2FaceValues::DoubleValued )
1922 DoubleValuedConformingAddMultTranspose(x, y);
1924 else if ( m==L2FaceValues::SingleValued )
1926 SingleValuedConformingAddMultTranspose(x, y);
1931void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const
1933 if (nf==0) {
return; }
1934 if (type==FaceType::Interior)
1936 if ( m==L2FaceValues::DoubleValued )
1938 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
1939 DoubleValuedConformingAddMultTranspose(x, y);
1941 else if ( m==L2FaceValues::SingleValued )
1943 SingleValuedNonconformingTransposeInterpolationInPlace(x);
1944 SingleValuedConformingAddMultTranspose(x, y);
1949 if ( m==L2FaceValues::DoubleValued )
1951 DoubleValuedConformingAddMultTranspose(x, y);
1953 else if ( m==L2FaceValues::SingleValued )
1955 SingleValuedConformingAddMultTranspose(x, y);
1961 const bool keep_nbr_block)
const
1963 const int nface_dofs = face_dofs;
1964 auto d_indices1 = scatter_indices1.Read();
1965 auto d_indices2 = scatter_indices2.Read();
1967 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1969 const int iE1 = d_indices1[fdof];
1970 const int iE2 = d_indices2[fdof];
1971 AddNnz(iE1,I,nface_dofs);
1972 AddNnz(iE2,I,nface_dofs);
1976void NCL2FaceRestriction::FillJAndData(
const Vector &fea_data,
1978 const bool keep_nbr_block)
const
1980 const int nface_dofs = face_dofs;
1981 auto d_indices1 = scatter_indices1.Read();
1982 auto d_indices2 = scatter_indices2.Read();
1984 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
1987 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1988 auto interpolators = interpolations.GetInterpolators().Read();
1989 const int nc_size = interpolations.GetNumInterpolators();
1990 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1991 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1993 const int f = fdof/nface_dofs;
1996 const int interp_index = conf.
index;
1997 const int iF = fdof%nface_dofs;
1998 const int iE1 = d_indices1[
f*nface_dofs+iF];
1999 const int iE2 = d_indices2[
f*nface_dofs+iF];
2000 const int offset1 = AddNnz(iE1,I,nface_dofs);
2001 const int offset2 = AddNnz(iE2,I,nface_dofs);
2002 for (
int jF = 0; jF < nface_dofs; jF++)
2004 const int jE1 = d_indices1[
f*nface_dofs+jF];
2005 const int jE2 = d_indices2[
f*nface_dofs+jF];
2006 J[offset2+jF] = jE1;
2007 J[offset1+jF] = jE2;
2012 for (
int kF = 0; kF < nface_dofs; kF++)
2014 val1 += mat_fea(kF,iF,0,
f) * d_interp(kF, jF, interp_index);
2015 val2 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,1,
f);
2020 for (
int kF = 0; kF < nface_dofs; kF++)
2022 val1 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,0,
f);
2023 val2 += mat_fea(kF,iF,1,
f) * d_interp(kF, jF, interp_index);
2028 val1 = mat_fea(jF,iF,0,
f);
2029 val2 = mat_fea(jF,iF,1,
f);
2031 Data[offset2+jF] = val1;
2032 Data[offset1+jF] = val2;
2037void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2042 const int nface_dofs = face_dofs;
2043 const int nelem_dofs = elem_dofs;
2045 if (m==L2FaceValues::DoubleValued)
2047 auto d_indices1 = scatter_indices1.Read();
2048 auto d_indices2 = scatter_indices2.Read();
2049 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
2051 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2052 auto interpolators = interpolations.GetInterpolators().Read();
2053 const int nc_size = interpolations.GetNumInterpolators();
2054 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2059 const int interp_index = conf.
index;
2060 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
2061 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
2062 for (
int j = 0; j < nface_dofs; j++)
2064 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
2065 for (
int i = 0; i < nface_dofs; i++)
2067 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
2071 for (int k = 0; k < nface_dofs; k++)
2073 for (int l = 0; l < nface_dofs; l++)
2075 val += d_interp(l, j, interp_index)
2077 * d_interp(k, i, interp_index);
2083 val = mat_fea(i,j,0,
f);
2090 for (
int j = 0; j < nface_dofs; j++)
2092 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
2093 for (
int i = 0; i < nface_dofs; i++)
2095 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
2097 if ( conf.is_non_conforming && master_side==1 )
2099 for (
int k = 0; k < nface_dofs; k++)
2101 for (
int l = 0; l < nface_dofs; l++)
2103 val += d_interp(l, j, interp_index)
2105 * d_interp(k, i, interp_index);
2111 val = mat_fea(i,j,1,
f);
2121 auto d_indices = scatter_indices1.Read();
2122 auto mat_fea =
Reshape(fea_data.Read(), nface_dofs, nface_dofs, nf);
2123 auto mat_ea =
Reshape(ea_data.ReadWrite(), nelem_dofs, nelem_dofs, ne);
2124 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2125 auto interpolators = interpolations.GetInterpolators().Read();
2126 const int nc_size = interpolations.GetNumInterpolators();
2127 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2132 const int interp_index = conf.
index;
2133 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
2134 for (
int j = 0; j < nface_dofs; j++)
2136 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
2137 for (
int i = 0; i < nface_dofs; i++)
2139 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
2143 for (int k = 0; k < nface_dofs; k++)
2145 for (int l = 0; l < nface_dofs; l++)
2147 val += d_interp(l, j, interp_index)
2149 * d_interp(k, i, interp_index);
2155 val = mat_fea(i,j,
f);
2172 return internal::ToLexOrdering2D(face_id, size1d,
index);
2174 return internal::ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2176 MFEM_ABORT(
"Unsupported dimension.");
2181void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets()
2183 Mesh &mesh = *fes.GetMesh();
2186 for (
int i = 0; i <= ndofs; ++i)
2188 gather_offsets[i] = 0;
2193 for (
int f = 0;
f < fes.GetNF(); ++
f)
2195 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2196 if ( face.IsNonconformingCoarse() )
2202 else if ( type==FaceType::Interior && face.IsInterior() )
2204 SetFaceDofsScatterIndices1(face,f_ind);
2205 if ( m==L2FaceValues::DoubleValued )
2207 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2209 if ( face.IsConforming() )
2211 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2215 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2219 else if ( type==FaceType::Boundary && face.IsBoundary() )
2221 SetFaceDofsScatterIndices1(face,f_ind);
2222 if ( m==L2FaceValues::DoubleValued )
2224 SetBoundaryDofsScatterIndices2(face,f_ind);
2226 interpolations.RegisterFaceConformingInterpolation(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];
2241 interpolations.LinearizeInterpolatorMapIntoVector();
2242 interpolations.InitializeNCInterpConfig();
2245void NCL2FaceRestriction::ComputeGatherIndices()
2247 Mesh &mesh = *fes.GetMesh();
2250 for (
int f = 0;
f < fes.GetNF(); ++
f)
2252 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2253 MFEM_ASSERT(!face.IsShared(),
2254 "Unexpected shared face in NCL2FaceRestriction.");
2255 if ( face.IsNonconformingCoarse() )
2261 else if ( face.IsOfFaceType(type) )
2263 SetFaceDofsGatherIndices1(face,f_ind);
2264 if ( m==L2FaceValues::DoubleValued &&
2265 type==FaceType::Interior &&
2268 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2273 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2274 (type==FaceType::Interior?
"interior" :
"boundary") <<
2275 " faces: " << f_ind <<
" vs " << nf );
2278 for (
int i = ndofs; i > 0; --i)
2280 gather_offsets[i] = gather_offsets[i - 1];
2282 gather_offsets[0] = 0;
2289 if (ftype == FaceType::Interior)
2297 Vector &gf_face_nbr = x_gf->FaceNbrData();
2298 if (gf_face_nbr.
Size() == 0) { x_gf->ExchangeFaceNbrData(); }
2300 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 * GetData()
Returns the data.
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 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 MultTransposeUnsigned(const Vector &x, Vector &y) const
Compute MultTranspose without applying signs based on DOF orientations.
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 MultUnsigned(const Vector &x, Vector &y) const
Compute Mult 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,...
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 * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
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().
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.
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 conforming face for the interpolation of the de...
int GetNumInterpolators() const
Return the total number of interpolators.
Array< NCInterpConfig > nc_interp_config
InterpolationManager()=delete
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
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
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 methods adds the DG face matrices to the element matrices.
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...
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
int Dimension() const
Dimension of the reference space used within the elements.
FaceInformation GetFaceInformation(int f) const
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
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 ...
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.
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
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)
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).
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.
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)
@ byVDIM
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
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.
@ LEXICOGRAPHIC
Lexicographic ordering for tensor-product FiniteElements.
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