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)
53 if (el_t || el_n) {
continue; }
54 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
60 (el_t) ? el_t->GetDofMap() : el_n->GetLexicographicOrdering();
61 MFEM_VERIFY(fe_dof_map.
Size() > 0,
"invalid dof map");
65 const int* element_map = e2dTable.
GetJ();
67 for (
int i = 0; i <=
ndofs; ++i)
71 for (
int e = 0; e <
ne; ++e)
73 for (
int d = 0; d <
dof; ++d)
75 const int sgid = element_map[
dof*e + d];
76 const int gid = (sgid >= 0) ? sgid : -1 - sgid;
81 for (
int i = 1; i <=
ndofs; ++i)
86 for (
int e = 0; e <
ne; ++e)
88 for (
int d = 0; d <
dof; ++d)
90 const int sdid = dof_reorder ? dof_map[d] : 0;
91 const int did = (!dof_reorder)?d:(sdid >= 0 ? sdid : -1-sdid);
92 const int sgid = element_map[
dof*e + did];
93 const int gid = (sgid >= 0) ? sgid : -1-sgid;
94 const int lid =
dof*e + d;
95 const bool plus = (sgid >= 0 && sdid >= 0) || (sgid < 0 && sdid < 0);
102 for (
int i =
ndofs; i > 0; --i)
120 const int gid = d_gather_map[i];
121 const bool plus = gid >= 0;
122 const int j = plus ? gid : -1-gid;
123 for (
int c = 0; c < vd; ++c)
125 const real_t dof_value = d_x(t?c:j, t?j:c);
126 d_y(i % nd, c, i / nd) = plus ? dof_value : -dof_value;
143 const int gid = d_gather_map[i];
144 const int j = gid >= 0 ? gid : -1-gid;
145 for (
int c = 0; c < vd; ++c)
147 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
153void ElementRestriction::TAddMultTranspose(
const Vector& x,
Vector& y)
const
165 const int offset = d_offsets[i];
166 const int next_offset = d_offsets[i + 1];
167 for (
int c = 0; c < vd; ++c)
170 for (
int j = offset; j < next_offset; ++j)
172 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
173 dof_value += ((d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
174 -d_x(idx_j % nd, c, idx_j / nd));
176 if (ADD) { d_y(t?c:i,t?i:c) += dof_value; }
177 else { d_y(t?c:i,t?i:c) = dof_value; }
184 constexpr bool ADD =
false;
185 TAddMultTranspose<ADD>(x, y);
191 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
192 constexpr bool ADD =
true;
193 TAddMultTranspose<ADD>(x, y);
208 const int offset = d_offsets[i];
209 const int next_offset = d_offsets[i + 1];
210 for (
int c = 0; c < vd; ++c)
213 for (
int j = offset; j < next_offset; ++j)
215 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
216 dof_value += d_x(idx_j % nd, c, idx_j / nd);
218 d_y(t?c:i,t?i:c) = dof_value;
235 const int next_offset = d_offsets[i + 1];
236 for (
int c = 0; c < vd; ++c)
239 const int j = next_offset - 1;
240 const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j];
241 dof_value = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) :
242 -d_x(idx_j % nd, c, idx_j / nd);
243 d_y(t?c:i,t?i:c) = dof_value;
262 for (
int i = 0; i <
ndofs; ++i)
264 const int offset = d_offsets[i];
265 const int next_offset = d_offsets[i+1];
266 for (
int c = 0; c < vd; ++c)
268 for (
int j = offset; j < next_offset; ++j)
270 const int idx_j = d_indices[j];
271 if (d_x(t?c:i,t?i:c))
273 d_y(idx_j % nd, c, idx_j / nd) = 0.0;
277 d_y(idx_j % nd, c, idx_j / nd) = 1.0;
278 d_x(t?c:i,t?i:c) = 1;
289 const int nnz =
FillI(mat);
295static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int nbElts,
296 const int *nbr_elts,
const int nbrNbElts)
299 int min_el = INT_MAX;
300 for (
int i = 0; i < nbElts; i++)
302 const int e_i = my_elts[i];
303 if (e_i >= min_el) {
continue; }
304 for (
int j = 0; j < nbrNbElts; j++)
306 if (e_i==nbr_elts[j])
318static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
326 const int all_dofs =
ndofs;
328 const int elt_dofs =
dof;
337 mfem::forall(vd*all_dofs+1, [=] MFEM_HOST_DEVICE (
int i_L)
343 const int e = l_dof/elt_dofs;
344 const int i = l_dof%elt_dofs;
346 const int i_gm = e*elt_dofs + i;
347 const int i_L = d_gather_map[i_gm];
348 const int i_offset = d_offsets[i_L];
349 const int i_next_offset = d_offsets[i_L+1];
350 const int i_nbElts = i_next_offset - i_offset;
352 int *i_elts = &d_ij_elts(i_offset, 0);
353 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
355 const int i_E = d_indices[i_offset+e_i];
356 i_elts[e_i] = i_E/elt_dofs;
358 for (
int j = 0; j < elt_dofs; j++)
360 const int j_gm = e*elt_dofs + j;
361 const int j_L = d_gather_map[j_gm];
362 const int j_offset = d_offsets[j_L];
363 const int j_next_offset = d_offsets[j_L+1];
364 const int j_nbElts = j_next_offset - j_offset;
365 if (i_nbElts == 1 || j_nbElts == 1)
367 GetAndIncrementNnzIndex(i_L, I);
371 int *j_elts = &d_ij_elts(j_offset, 1);
372 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
374 const int j_E = d_indices[j_offset+e_j];
375 const int elt = j_E/elt_dofs;
378 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
381 GetAndIncrementNnzIndex(i_L, I);
388 const int nTdofs = vd*all_dofs;
390 for (
int i = 0; i < nTdofs; i++)
392 const int nnz = h_I[i];
404 const int all_dofs =
ndofs;
406 const int elt_dofs =
dof;
413 auto mat_ea =
Reshape(ea_data.
Read(), elt_dofs, elt_dofs,
ne);
420 const int e = l_dof/elt_dofs;
421 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;
429 int *i_elts = &d_ij_B_el(i_offset, 0);
430 int *i_B = &d_ij_B_el(i_offset, 1);
431 for (
int e_i = 0; e_i < i_nbElts; ++e_i)
433 const int i_E = d_indices[i_offset+e_i];
434 i_elts[e_i] = i_E/elt_dofs;
435 i_B[e_i] = i_E%elt_dofs;
437 for (
int j = 0; j < elt_dofs; j++)
439 const int j_gm = e*elt_dofs + j;
440 const int j_L = d_gather_map[j_gm];
441 const int j_offset = d_offsets[j_L];
442 const int j_next_offset = d_offsets[j_L+1];
443 const int j_nbElts = j_next_offset - j_offset;
444 if (i_nbElts == 1 || j_nbElts == 1)
446 const int nnz = GetAndIncrementNnzIndex(i_L, I);
448 Data[nnz] = mat_ea(j,i,e);
452 int *j_elts = &d_ij_B_el(j_offset, 2);
453 int *j_B = &d_ij_B_el(j_offset, 3);
454 for (
int e_j = 0; e_j < j_nbElts; ++e_j)
456 const int j_E = d_indices[j_offset+e_j];
457 const int elt = j_E/elt_dofs;
459 j_B[e_j] = j_E%elt_dofs;
461 int min_e = GetMinElt(i_elts, i_nbElts, j_elts, j_nbElts);
465 for (
int k = 0; k < i_nbElts; k++)
467 const int e_i = i_elts[k];
468 const int i_Bloc = i_B[k];
469 for (
int l = 0; l < j_nbElts; l++)
471 const int e_j = j_elts[l];
472 const int j_Bloc = j_B[l];
475 val += mat_ea(j_Bloc, i_Bloc, e_i);
479 const int nnz = GetAndIncrementNnzIndex(i_L, I);
489 const int size = vd*all_dofs;
490 for (
int i = 0; i < size; i++)
492 h_I[size-i] = h_I[size-(i+1)];
501 ndof(fes.GetTypicalFE()->GetDof()),
502 ndofs(fes.GetNDofs())
505 width = vdim*ne*ndof;
512 const bool t = byvdim;
513 auto d_x =
Reshape(x.
Read(), t?vd:ndofs, t?ndofs:vd);
518 const int dof = idx % nd;
519 const int e = idx / nd;
520 for (
int c = 0; c < vd; ++c)
522 d_y(dof, c, e) = d_x(t?c:idx, t?idx:c);
528void L2ElementRestriction::TAddMultTranspose(
const Vector &x,
Vector &y)
const
532 const bool t = byvdim;
538 const int dof = idx % nd;
539 const int e = idx / nd;
540 for (
int c = 0; c < vd; ++c)
542 if (ADD) { d_y(t?c:idx,t?idx:c) += d_x(dof, c, e); }
543 else { d_y(t?c:idx,t?idx:c) = d_x(dof, c, e); }
550 constexpr bool ADD =
false;
551 TAddMultTranspose<ADD>(x, y);
557 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
558 constexpr bool ADD =
true;
559 TAddMultTranspose<ADD>(x, y);
564 const int elem_dofs = ndof;
567 const int isize = mat.
Height() + 1;
568 const int interior_dofs = ne*elem_dofs*vd;
571 I[dof] = dof<interior_dofs ? elem_dofs : 0;
575static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
584 const int elem_dofs = ndof;
589 auto mat_ea =
Reshape(ea_data.
Read(), elem_dofs, elem_dofs, ne);
590 mfem::forall(ne*elem_dofs*vd, [=] MFEM_HOST_DEVICE (
int iE)
592 const int offset = AddNnz(iE,I,elem_dofs);
593 const int e = iE/elem_dofs;
594 const int i = iE%elem_dofs;
595 for (
int j = 0; j < elem_dofs; j++)
597 J[offset+j] = e*elem_dofs+j;
598 Data[offset+j] = mat_ea(j,i,e);
609 nf(fes.GetNFbyType(type)),
612 face_dofs(nf > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
613 elem_dofs(fes.GetTypicalFE()->GetDof()),
614 nfdofs(nf*face_dofs),
615 ndofs(fes.GetNDofs()),
616 scatter_indices(nf*face_dofs),
617 gather_offsets(ndofs+1),
618 gather_indices(nf*face_dofs),
623 if (
nf==0) {
return; }
631 if (dof_map_.
Size() > 0)
644 if (!build) {
return; }
645 ComputeScatterIndicesAndOffsets(f_ordering, type);
646 ComputeGatherIndices(f_ordering,type);
658 if (
nf==0) {
return; }
668 const int s_idx = d_indices[i];
669 const int sgn = (s_idx >= 0) ? 1 : -1;
670 const int idx = (s_idx >= 0) ? s_idx : -1 - s_idx;
671 const int dof = i % nface_dofs;
672 const int face = i / nface_dofs;
673 for (
int c = 0; c < vd; ++c)
675 d_y(dof, c, face) = sgn*d_x(t?c:idx, t?idx:c);
680static void ConformingFaceRestriction_AddMultTranspose(
693 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
694 if (nf==0) {
return; }
696 auto d_offsets = gather_offsets.
Read();
697 auto d_indices = gather_indices.
Read();
702 const int offset = d_offsets[i];
703 const int next_offset = d_offsets[i + 1];
704 for (
int c = 0; c < vdim; ++c)
707 for (
int j = offset; j < next_offset; ++j)
709 const int s_idx_j = d_indices[j];
710 const real_t sgn = (s_idx_j >= 0 || !use_signs) ? 1.0 : -1.0;
711 const int idx_j = (s_idx_j >= 0) ? s_idx_j : -1 - s_idx_j;
712 dof_value += sgn*d_x(idx_j % face_dofs, c, idx_j / face_dofs);
714 d_y(by_vdim?c:i,by_vdim?i:c) += dof_value;
722 ConformingFaceRestriction_AddMultTranspose(
730 ConformingFaceRestriction_AddMultTranspose(
745 pfes->GetParMesh()->ExchangeFaceNbrData();
753 MFEM_VERIFY(tfe != NULL,
754 "ConformingFaceRestriction only supports TensorBasisElements");
757 "ConformingFaceRestriction only supports Gauss-Lobatto and Bernstein bases");
761 if (dof_reorder &&
nf > 0)
768 if (el) {
continue; }
769 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
775void ConformingFaceRestriction::ComputeScatterIndicesAndOffsets(
782 for (
int i = 0; i <=
ndofs; ++i)
792 if ( face.IsNonconformingCoarse() )
798 else if ( face.IsOfFaceType(type) )
804 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
807 for (
int i = 1; i <=
ndofs; ++i)
813void ConformingFaceRestriction::ComputeGatherIndices(
824 if ( face.IsNonconformingCoarse() )
830 else if ( face.IsOfFaceType(type) )
836 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
839 for (
int i =
ndofs; i > 0; --i)
846static inline int absdof(
int i) {
return i < 0 ? -1-i : i; }
850 const int face_index,
854 "This method should not be used on nonconforming coarse faces.");
856 "FaceRestriction used on degenerated mesh.");
858 "NATIVE ordering is not supported yet");
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.");
887 "NATIVE ordering is not supported yet");
892 const int* elem_map = e2dTable.
GetJ();
895 for (
int face_dof = 0; face_dof <
face_dofs; ++face_dof)
897 const int lex_volume_dof =
face_map[face_dof];
899 const int volume_dof = absdof(s_volume_dof);
900 const int s_global_dof = elem_map[elem_index*
elem_dofs + volume_dof];
901 const int sgn = (s_global_dof >= 0) ? 1 : -1;
902 const int global_dof = absdof(s_global_dof);
903 const int restriction_dof =
face_dofs*face_index + face_dof;
904 const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
912 const int face_id2,
const int orientation,
913 const int size1d,
const int index)
920 return internal::PermuteFace2D(face_id1, face_id2, orientation, size1d,
index);
922 return internal::PermuteFace3D(face_id1, face_id2, orientation, size1d,
index);
924 MFEM_ABORT(
"Unsupported dimension.");
935 ordering(f_ordering),
936 nf(fes.GetNFbyType(type)),
940 face_dofs(fes.GetTypicalTraceElement()->GetDof()),
941 elem_dofs(fes.GetTypicalFE()->GetDof()),
942 nfdofs(nf*face_dofs),
943 ndofs(fes.GetNDofs()),
946 scatter_indices1(nf*face_dofs),
948 gather_offsets(ndofs+1),
954 if (!build) {
return; }
957 ComputeScatterIndicesAndOffsets();
958 ComputeGatherIndices();
971 if (
nf == 0) {
return; }
974 "This method should be called when m == L2FaceValues::SingleValued.");
984 const int dof = i % nface_dofs;
985 const int face = i / nface_dofs;
986 const int idx1 = d_indices1[i];
987 for (
int c = 0; c < vd; ++c)
989 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
999 "This method should be called when m == L2FaceValues::DoubleValued.");
1002 const int vd =
vdim;
1010 const int dof = i % nface_dofs;
1011 const int face = i / nface_dofs;
1012 const int idx1 = d_indices1[i];
1013 for (
int c = 0; c < vd; ++c)
1015 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
1017 const int idx2 = d_indices2[i];
1018 for (
int c = 0; c < vd; ++c)
1020 d_y(dof, c, 1, face) = idx2==-1 ? 0.0 : d_x(t?c:idx2, t?idx2:c);
1027 if (
nf==0) {
return; }
1043 const int vd =
vdim;
1051 const int offset = d_offsets[i];
1052 const int next_offset = d_offsets[i + 1];
1053 for (
int c = 0; c < vd; ++c)
1056 for (
int j = offset; j < next_offset; ++j)
1058 int idx_j = d_indices[j];
1059 dof_value += d_x(idx_j % nface_dofs, c, idx_j / nface_dofs);
1061 d_y(t?c:i,t?i:c) += dof_value;
1071 const int vd =
vdim;
1080 const int offset = d_offsets[i];
1081 const int next_offset = d_offsets[i + 1];
1082 for (
int c = 0; c < vd; ++c)
1085 for (
int j = offset; j < next_offset; ++j)
1087 int idx_j = d_indices[j];
1088 bool isE1 = idx_j < dofs;
1089 idx_j = isE1 ? idx_j : idx_j - dofs;
1091 d_x(idx_j % nface_dofs, c, 0, idx_j / nface_dofs)
1092 :d_x(idx_j % nface_dofs, c, 1, idx_j / nface_dofs);
1094 d_y(t?c:i,t?i:c) += dof_value;
1102 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1103 if (
nf==0) {
return; }
1115 const bool keep_nbr_block)
const
1123 const int iE1 = d_indices1[fdof];
1124 const int iE2 = d_indices2[fdof];
1125 AddNnz(iE1,I,nface_dofs);
1126 AddNnz(iE2,I,nface_dofs);
1132 const bool keep_nbr_block)
const
1138 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1143 const int f = fdof/nface_dofs;
1144 const int iF = fdof%nface_dofs;
1145 const int iE1 = d_indices1[
f*nface_dofs+iF];
1146 const int iE2 = d_indices2[
f*nface_dofs+iF];
1147 const int offset1 = AddNnz(iE1,I,nface_dofs);
1148 const int offset2 = AddNnz(iE2,I,nface_dofs);
1149 for (
int jF = 0; jF < nface_dofs; jF++)
1151 const int jE1 = d_indices1[
f*nface_dofs+jF];
1152 const int jE2 = d_indices2[
f*nface_dofs+jF];
1153 J[offset2+jF] = jE1;
1154 J[offset1+jF] = jE2;
1155 Data[offset2+jF] = mat_fea(jF,iF,0,
f);
1156 Data[offset1+jF] = mat_fea(jF,iF,1,
f);
1171 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
1175 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
1176 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
1177 for (
int j = 0; j < nface_dofs; j++)
1179 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
1180 for (
int i = 0; i < nface_dofs; i++)
1182 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
1183 AtomicAdd(mat_ea(iB1,jB1,e1), mat_fea(i,j,0,
f));
1188 for (
int j = 0; j < nface_dofs; j++)
1190 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
1191 for (
int i = 0; i < nface_dofs; i++)
1193 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
1194 AtomicAdd(mat_ea(iB2,jB2,e2), mat_fea(i,j,1,
f));
1203 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs,
nf);
1207 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
1208 for (
int j = 0; j < nface_dofs; j++)
1210 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
1211 for (
int i = 0; i < nface_dofs; i++)
1213 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
1230 pfes->GetParMesh()->ExchangeFaceNbrData();
1239 MFEM_VERIFY(tfe != NULL &&
1242 "Only Gauss-Lobatto and Bernstein basis are supported in "
1243 "L2FaceRestriction.");
1244 if (
nf==0) {
return; }
1248 MFEM_ABORT(
"Non-Tensor L2FaceRestriction not yet implemented.");
1250 if (dof_reorder &&
nf > 0)
1256 if (el) {
continue; }
1257 MFEM_ABORT(
"Finite element not suitable for lexicographic ordering");
1263void L2FaceRestriction::ComputeScatterIndicesAndOffsets()
1267 for (
int i = 0; i <=
ndofs; ++i)
1277 MFEM_ASSERT(!face.IsShared(),
1278 "Unexpected shared face in L2FaceRestriction.");
1279 if ( face.IsOfFaceType(
type) )
1296 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1299 for (
int i = 1; i <=
ndofs; ++i)
1305void L2FaceRestriction::ComputeGatherIndices()
1313 MFEM_ASSERT(!face.IsShared(),
1314 "Unexpected shared face in L2FaceRestriction.");
1315 if ( face.IsOfFaceType(
type) )
1327 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
1330 for (
int i =
ndofs; i > 0; --i)
1339 const int face_index)
1342 "This method should not be used on nonconforming coarse faces.");
1344 const int* elem_map = e2dTable.
GetJ();
1349 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1351 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1352 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1353 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1361 const int face_index)
1364 "This method should only be used on local faces.");
1366 const int* elem_map = e2dTable.
GetJ();
1375 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1380 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1381 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1382 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1390 const int face_index)
1394 "This method should only be used on shared faces.");
1407 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1410 orientation, dof1d, face_dof_elem1);
1411 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1412 const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
1413 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1422 const int face_index)
1425 "This method should only be used on boundary faces.");
1429 const int restriction_dof_elem2 =
face_dofs*face_index + d;
1436 const int face_index)
1439 "This method should not be used on nonconforming coarse faces.");
1441 const int* elem_map = e2dTable.
GetJ();
1446 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1448 const int volume_dof_elem1 =
face_map[face_dof_elem1];
1449 const int global_dof_elem1 = elem_map[elem_index*
elem_dofs + volume_dof_elem1];
1450 const int restriction_dof_elem1 =
face_dofs*face_index + face_dof_elem1;
1458 const int face_index)
1461 "This method should only be used on local faces.");
1463 const int* elem_map = e2dTable.
GetJ();
1472 for (
int face_dof_elem1 = 0; face_dof_elem1 <
face_dofs; ++face_dof_elem1)
1477 const int volume_dof_elem2 =
face_map[face_dof_elem2];
1478 const int global_dof_elem2 = elem_map[elem_index*
elem_dofs + volume_dof_elem2];
1479 const int restriction_dof_elem2 =
face_dofs*face_index + face_dof_elem1;
1482 restriction_dof_elem2;
1488 EnsureNormalDerivativeRestriction();
1495 EnsureNormalDerivativeRestriction();
1499void L2FaceRestriction::EnsureNormalDerivativeRestriction()
const
1513 interp_config( fes.GetNFbyType(type) ),
1529 "Registering face as nonconforming even though it is not.");
1532 const int master_side =
1534 const int face_key = (master_side == 0 ? 1000 : 0) +
1539 Key key(ptMat, face_key);
1544 GetCoarseToFineInterpolation(face,ptMat);
1551 interp_config[face_index] = {master_side, itr->second.first};
1555const DenseMatrix* InterpolationManager::GetCoarseToFineInterpolation(
1560 "The following interpolation operator is only implemented for"
1561 "lexicographic ordering.");
1563 "This method should not be called on conforming faces.")
1564 const
int face_id1 = face.element[0].local_face_id;
1565 const
int face_id2 = face.element[1].local_face_id;
1567 const
bool is_ghost_slave =
1568 face.element[0].conformity ==
Mesh::ElementConformity::Superset;
1569 const
int master_face_id = is_ghost_slave ? face_id1 : face_id2;
1575 const
int face_dofs = trace_fe->GetDof();
1578 const auto dof_map = el->GetDofMap();
1583 isotr.SetIdentityTransformation(trace_fe->GetGeomType());
1584 isotr.SetPointMat(*ptMat);
1587 if ( trace_fe->GetGeomType()==
Geometry::SEGMENT && !is_ghost_slave )
1589 std::swap(trans_pt_mat(0,0),trans_pt_mat(0,1));
1591 DenseMatrix native_interpolator(face_dofs,face_dofs);
1592 trace_fe->GetLocalInterpolation(isotr, native_interpolator);
1593 const int dim = trace_fe->GetDim()+1;
1594 const int dof1d = trace_fe->GetOrder()+1;
1596 for (
int i = 0; i < face_dofs; i++)
1598 const int ni = (dof_map.Size()==0) ? i : dof_map[i];
1600 if ( !is_ghost_slave )
1604 orientation, dof1d, li);
1606 for (
int j = 0; j < face_dofs; j++)
1609 if ( !is_ghost_slave )
1613 orientation, dof1d, lj);
1615 const int nj = (dof_map.Size()==0) ? j : dof_map[j];
1616 (*interpolator)(li,lj) = native_interpolator(ni,nj);
1619 return interpolator;
1626 const int face_dofs = trace_fe->
GetDof();
1627 const int nc_size =
static_cast<int>(
interp_map.size());
1628 MFEM_VERIFY(
nc_cpt==nc_size,
"Unexpected number of interpolators.");
1633 const int idx = val.second.first;
1634 const DenseMatrix &interpolator = *val.second.second;
1635 for (
int i = 0; i < face_dofs; i++)
1637 for (
int j = 0; j < face_dofs; j++)
1639 d_interp(i,j,idx) = interpolator(i,j);
1642 delete val.second.second;
1650 int num_nc_faces = 0;
1664 if ( config.is_non_conforming )
1678 interpolations(fes, f_ordering, type)
1680 if (!build) {
return; }
1685 ComputeScatterIndicesAndOffsets();
1687 ComputeGatherIndices();
1707 if (
nf == 0) {
return; }
1710 const int vd =
vdim;
1713 const int num_nc_faces = nc_interp_config.Size();
1714 if ( num_nc_faces == 0 ) {
return; }
1715 auto interp_config_ptr = nc_interp_config.Read();
1718 nface_dofs, nface_dofs, nc_size);
1719 static constexpr int max_nd = 16*16;
1720 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1721 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1723 MFEM_SHARED
real_t dof_values[max_nd];
1727 const int master_side = conf.master_side;
1728 const int interp_index = conf.index;
1729 const int face = conf.face_index;
1730 for (int c = 0; c < vd; ++c)
1732 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1734 dof_values[dof] = d_y(dof, c, master_side, face);
1737 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1740 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1742 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
1744 d_y(dof_out, c, master_side, face) = res;
1754 if ( type==FaceType::Interior && m==L2FaceValues::DoubleValued )
1756 DoubleValuedNonconformingMult(x, y);
1758 else if ( type==FaceType::Boundary && m==L2FaceValues::DoubleValued )
1760 DoubleValuedConformingMult(x, y);
1764 SingleValuedConformingMult(x, y);
1768void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation(
1772 m == L2FaceValues::SingleValued,
1773 "This method should be called when m == L2FaceValues::SingleValued.");
1774 if (x_interp.Size()==0)
1776 x_interp.SetSize(x.
Size());
1779 SingleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1768void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolation( {
…}
1783void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace(
1787 const int nface_dofs = face_dofs;
1788 const int vd = vdim;
1790 auto d_x =
Reshape(x_interp.ReadWrite(), nface_dofs, vd, nf);
1791 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1792 const int num_nc_faces = nc_interp_config.Size();
1793 if ( num_nc_faces == 0 ) {
return; }
1794 auto interp_config_ptr = nc_interp_config.Read();
1795 auto interpolators = interpolations.GetInterpolators().Read();
1796 const int nc_size = interpolations.GetNumInterpolators();
1797 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1798 static constexpr int max_nd = 16*16;
1799 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1800 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1802 MFEM_SHARED
real_t dof_values[max_nd];
1805 const int interp_index = conf.
index;
1810 for (int c = 0; c < vd; ++c)
1812 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1814 dof_values[dof] = d_x(dof, c, face);
1817 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1820 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1822 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1824 d_x(dof_out, c, face) = res;
1783void NCL2FaceRestriction::SingleValuedNonconformingTransposeInterpolationInPlace( {
…}
1832void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation(
1836 m == L2FaceValues::DoubleValued,
1837 "This method should be called when m == L2FaceValues::DoubleValued.");
1838 if (x_interp.Size()==0)
1840 x_interp.SetSize(x.
Size());
1843 DoubleValuedNonconformingTransposeInterpolationInPlace(x_interp);
1832void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolation( {
…}
1846void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace(
1850 const int nface_dofs = face_dofs;
1851 const int vd = vdim;
1854 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
1855 const int num_nc_faces = nc_interp_config.Size();
1856 if ( num_nc_faces == 0 ) {
return; }
1857 auto interp_config_ptr = nc_interp_config.Read();
1858 auto interpolators = interpolations.GetInterpolators().Read();
1859 const int nc_size = interpolations.GetNumInterpolators();
1860 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1861 static constexpr int max_nd = 16*16;
1862 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
1863 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
1865 MFEM_SHARED
real_t dof_values[max_nd];
1868 const int interp_index = conf.
index;
1873 for (int c = 0; c < vd; ++c)
1875 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
1877 dof_values[dof] = d_x(dof, c, master_side, face);
1880 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
1883 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
1885 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
1887 d_x(dof_out, c, master_side, face) = res;
1846void NCL2FaceRestriction::DoubleValuedNonconformingTransposeInterpolationInPlace( {
…}
1898 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
1899 if (nf==0) {
return; }
1900 if (type==FaceType::Interior)
1902 if ( m==L2FaceValues::DoubleValued )
1904 DoubleValuedNonconformingTransposeInterpolation(x);
1905 DoubleValuedConformingAddMultTranspose(x_interp, y);
1907 else if ( m==L2FaceValues::SingleValued )
1909 SingleValuedNonconformingTransposeInterpolation(x);
1910 SingleValuedConformingAddMultTranspose(x_interp, y);
1915 if ( m==L2FaceValues::DoubleValued )
1917 DoubleValuedConformingAddMultTranspose(x, y);
1919 else if ( m==L2FaceValues::SingleValued )
1921 SingleValuedConformingAddMultTranspose(x, y);
1926void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const
1928 if (nf==0) {
return; }
1929 if (type==FaceType::Interior)
1931 if ( m==L2FaceValues::DoubleValued )
1933 DoubleValuedNonconformingTransposeInterpolationInPlace(x);
1934 DoubleValuedConformingAddMultTranspose(x, y);
1936 else if ( m==L2FaceValues::SingleValued )
1938 SingleValuedNonconformingTransposeInterpolationInPlace(x);
1939 SingleValuedConformingAddMultTranspose(x, y);
1944 if ( m==L2FaceValues::DoubleValued )
1946 DoubleValuedConformingAddMultTranspose(x, y);
1948 else if ( m==L2FaceValues::SingleValued )
1950 SingleValuedConformingAddMultTranspose(x, y);
1926void NCL2FaceRestriction::AddMultTransposeInPlace(
Vector& x,
Vector& y)
const {
…}
1956 const bool keep_nbr_block)
const
1958 const int nface_dofs = face_dofs;
1959 auto d_indices1 = scatter_indices1.Read();
1960 auto d_indices2 = scatter_indices2.Read();
1962 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1964 const int iE1 = d_indices1[fdof];
1965 const int iE2 = d_indices2[fdof];
1966 AddNnz(iE1,I,nface_dofs);
1967 AddNnz(iE2,I,nface_dofs);
1971void NCL2FaceRestriction::FillJAndData(
const Vector &fea_data,
1973 const bool keep_nbr_block)
const
1975 const int nface_dofs = face_dofs;
1976 auto d_indices1 = scatter_indices1.Read();
1977 auto d_indices2 = scatter_indices2.Read();
1979 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
1982 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
1983 auto interpolators = interpolations.GetInterpolators().Read();
1984 const int nc_size = interpolations.GetNumInterpolators();
1985 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
1986 mfem::forall(nf*nface_dofs, [=] MFEM_HOST_DEVICE (
int fdof)
1988 const int f = fdof/nface_dofs;
1991 const int interp_index = conf.
index;
1992 const int iF = fdof%nface_dofs;
1993 const int iE1 = d_indices1[
f*nface_dofs+iF];
1994 const int iE2 = d_indices2[
f*nface_dofs+iF];
1995 const int offset1 = AddNnz(iE1,I,nface_dofs);
1996 const int offset2 = AddNnz(iE2,I,nface_dofs);
1997 for (
int jF = 0; jF < nface_dofs; jF++)
1999 const int jE1 = d_indices1[
f*nface_dofs+jF];
2000 const int jE2 = d_indices2[
f*nface_dofs+jF];
2001 J[offset2+jF] = jE1;
2002 J[offset1+jF] = jE2;
2007 for (
int kF = 0; kF < nface_dofs; kF++)
2009 val1 += mat_fea(kF,iF,0,
f) * d_interp(kF, jF, interp_index);
2010 val2 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,1,
f);
2015 for (
int kF = 0; kF < nface_dofs; kF++)
2017 val1 += d_interp(kF, iF, interp_index) * mat_fea(jF,kF,0,
f);
2018 val2 += mat_fea(kF,iF,1,
f) * d_interp(kF, jF, interp_index);
2023 val1 = mat_fea(jF,iF,0,
f);
2024 val2 = mat_fea(jF,iF,1,
f);
2026 Data[offset2+jF] = val1;
2027 Data[offset1+jF] = val2;
1971void NCL2FaceRestriction::FillJAndData(
const Vector &fea_data, {
…}
2032void NCL2FaceRestriction::AddFaceMatricesToElementMatrices(
2037 const int nface_dofs = face_dofs;
2038 const int nelem_dofs = elem_dofs;
2040 if (m==L2FaceValues::DoubleValued)
2042 auto d_indices1 = scatter_indices1.Read();
2043 auto d_indices2 = scatter_indices2.Read();
2044 auto mat_fea =
Reshape(fea_data.
Read(), nface_dofs, nface_dofs, 2, nf);
2046 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2047 auto interpolators = interpolations.GetInterpolators().Read();
2048 const int nc_size = interpolations.GetNumInterpolators();
2049 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2054 const int interp_index = conf.
index;
2055 const int e1 = d_indices1[
f*nface_dofs]/nelem_dofs;
2056 const int e2 = d_indices2[
f*nface_dofs]/nelem_dofs;
2057 for (
int j = 0; j < nface_dofs; j++)
2059 const int jB1 = d_indices1[
f*nface_dofs+j]%nelem_dofs;
2060 for (
int i = 0; i < nface_dofs; i++)
2062 const int iB1 = d_indices1[
f*nface_dofs+i]%nelem_dofs;
2066 for (int k = 0; k < nface_dofs; k++)
2068 for (int l = 0; l < nface_dofs; l++)
2070 val += d_interp(l, j, interp_index)
2072 * d_interp(k, i, interp_index);
2078 val = mat_fea(i,j,0,
f);
2085 for (
int j = 0; j < nface_dofs; j++)
2087 const int jB2 = d_indices2[
f*nface_dofs+j]%nelem_dofs;
2088 for (
int i = 0; i < nface_dofs; i++)
2090 const int iB2 = d_indices2[
f*nface_dofs+i]%nelem_dofs;
2092 if ( conf.is_non_conforming && master_side==1 )
2094 for (
int k = 0; k < nface_dofs; k++)
2096 for (
int l = 0; l < nface_dofs; l++)
2098 val += d_interp(l, j, interp_index)
2100 * d_interp(k, i, interp_index);
2106 val = mat_fea(i,j,1,
f);
2116 auto d_indices = scatter_indices1.Read();
2117 auto mat_fea =
Reshape(fea_data.Read(), nface_dofs, nface_dofs, nf);
2118 auto mat_ea =
Reshape(ea_data.ReadWrite(), nelem_dofs, nelem_dofs, ne);
2119 auto interp_config_ptr = interpolations.GetFaceInterpConfig().Read();
2120 auto interpolators = interpolations.GetInterpolators().Read();
2121 const int nc_size = interpolations.GetNumInterpolators();
2122 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
2127 const int interp_index = conf.
index;
2128 const int e = d_indices[
f*nface_dofs]/nelem_dofs;
2129 for (
int j = 0; j < nface_dofs; j++)
2131 const int jE = d_indices[
f*nface_dofs+j]%nelem_dofs;
2132 for (
int i = 0; i < nface_dofs; i++)
2134 const int iE = d_indices[
f*nface_dofs+i]%nelem_dofs;
2138 for (int k = 0; k < nface_dofs; k++)
2140 for (int l = 0; l < nface_dofs; l++)
2142 val += d_interp(l, j, interp_index)
2144 * d_interp(k, i, interp_index);
2150 val = mat_fea(i,j,
f);
2032void NCL2FaceRestriction::AddFaceMatricesToElementMatrices( {
…}
2167 return internal::ToLexOrdering2D(face_id, size1d,
index);
2169 return internal::ToLexOrdering3D(face_id, size1d,
index%size1d,
index/size1d);
2171 MFEM_ABORT(
"Unsupported dimension.");
2176void NCL2FaceRestriction::ComputeScatterIndicesAndOffsets()
2178 Mesh &mesh = *fes.GetMesh();
2181 for (
int i = 0; i <= ndofs; ++i)
2183 gather_offsets[i] = 0;
2188 for (
int f = 0;
f < fes.GetNF(); ++
f)
2190 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2191 if ( face.IsNonconformingCoarse() )
2197 else if ( type==FaceType::Interior && face.IsInterior() )
2199 SetFaceDofsScatterIndices1(face,f_ind);
2200 if ( m==L2FaceValues::DoubleValued )
2202 PermuteAndSetFaceDofsScatterIndices2(face,f_ind);
2204 if ( face.IsConforming() )
2206 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2210 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
2214 else if ( type==FaceType::Boundary && face.IsBoundary() )
2216 SetFaceDofsScatterIndices1(face,f_ind);
2217 if ( m==L2FaceValues::DoubleValued )
2219 SetBoundaryDofsScatterIndices2(face,f_ind);
2221 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
2225 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2226 (type==FaceType::Interior?
"interior" :
"boundary") <<
2227 " faces: " << f_ind <<
" vs " << nf );
2230 for (
int i = 1; i <= ndofs; ++i)
2232 gather_offsets[i] += gather_offsets[i - 1];
2236 interpolations.LinearizeInterpolatorMapIntoVector();
2237 interpolations.InitializeNCInterpConfig();
2240void NCL2FaceRestriction::ComputeGatherIndices()
2242 Mesh &mesh = *fes.GetMesh();
2245 for (
int f = 0;
f < fes.GetNF(); ++
f)
2247 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
2248 MFEM_ASSERT(!face.IsShared(),
2249 "Unexpected shared face in NCL2FaceRestriction.");
2250 if ( face.IsNonconformingCoarse() )
2256 else if ( face.IsOfFaceType(type) )
2258 SetFaceDofsGatherIndices1(face,f_ind);
2259 if ( m==L2FaceValues::DoubleValued &&
2260 type==FaceType::Interior &&
2263 PermuteAndSetFaceDofsGatherIndices2(face,f_ind);
2268 MFEM_VERIFY(f_ind==nf,
"Unexpected number of " <<
2269 (type==FaceType::Interior?
"interior" :
"boundary") <<
2270 " faces: " << f_ind <<
" vs " << nf );
2273 for (
int i = ndofs; i > 0; --i)
2275 gather_offsets[i] = gather_offsets[i - 1];
2277 gather_offsets[0] = 0;
2280L2InterfaceFaceRestriction::L2InterfaceFaceRestriction(
2285 ordering(ordering_),
2287 nfaces(fes.GetNFbyType(type)),
2288 vdim(fes.GetVDim()),
2290 face_dofs(nfaces > 0 ? fes.GetFaceElement(0)->GetDof() : 0),
2291 nfdofs(face_dofs*nfaces),
2292 ndofs(fes.GetNDofs())
2280L2InterfaceFaceRestriction::L2InterfaceFaceRestriction( {
…}
2318 const int vd =
vdim;
2327 const int j = map[i];
2328 for (
int c = 0; c < vd; ++c)
2330 d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
2340 const int vd =
vdim;
2350 const int j = map[i];
2351 for (
int c = 0; c < vd; ++c)
2353 d_y(t?c:j, t?j:c) = d_x(i % nd, c, i / nd);
2375 Vector &gf_face_nbr = x_gf->FaceNbrData();
2376 if (gf_face_nbr.
Size() == 0) { x_gf->ExchangeFaceNbrData(); }
2378 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 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,...
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.
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.
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)
const FiniteElementSpace & fes
The finite element space.
Array< int > gather_map
Gather map.
const int vdim
vdim of the space
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 Array< int > & GatherMap() const override
Low-level access to the underlying gather map.
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
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 ...
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.
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)
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