12 #include "../config/config.hpp"
21 #include "../general/forall.hpp"
32 if (
nf==0) {
return; }
38 MFEM_VERIFY(tfe != NULL &&
41 "Only Gauss-Lobatto and Bernstein basis are supported in "
42 "ParL2FaceRestriction.");
44 "Non-conforming meshes not yet supported with partial assembly.");
51 mfem_error(
"Non-Tensor L2FaceRestriction not yet implemented.");
53 if (dof_reorder &&
nf > 0)
55 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
62 mfem_error(
"Finite element not suitable for lexicographic ordering");
66 const int* elementMap = e2dTable.
GetJ();
70 int face_id1, face_id2;
77 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
83 orientation = inf1 % 64;
86 orientation = inf2 % 64;
92 mfem_error(
"FaceRestriction not yet implemented for this type of "
96 face_id1 = face_id2 = 0;
99 (e2>=0 || (e2<0 && inf2>=0) ))
101 for (
int d = 0; d <
dof; ++d)
103 const int face_dof = faceMap1[d];
104 const int did = face_dof;
105 const int gid = elementMap[e1*elem_dofs + did];
106 const int lid = dof*f_ind + d;
113 for (
int d = 0; d <
dof; ++d)
116 orientation, dof1d, d);
117 const int face_dof = faceMap2[pd];
118 const int did = face_dof;
119 const int gid = elementMap[e2*elem_dofs + did];
120 const int lid = dof*f_ind + d;
126 const int se2 = -1 - e2;
129 for (
int d = 0; d <
dof; ++d)
132 orientation, dof1d, d);
133 const int face_dof = faceMap2[pd];
134 const int did = face_dof;
135 const int gid = sharedDofs[did];
136 const int lid = dof*f_ind + d;
146 for (
int d = 0; d <
dof; ++d)
148 const int face_dof = faceMap1[d];
149 const int did = face_dof;
150 const int gid = elementMap[e1*elem_dofs + did];
151 const int lid = dof*f_ind + d;
156 for (
int d = 0; d <
dof; ++d)
158 const int lid = dof*f_ind + d;
165 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
167 for (
int i = 0; i <=
ndofs; ++i)
172 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
179 orientation = inf1 % 64;
180 face_id1 = inf1 / 64;
182 orientation = inf2 % 64;
183 face_id2 = inf2 / 64;
185 for (
int d = 0; d <
dof; ++d)
187 const int did = faceMap1[d];
188 const int gid = elementMap[e1*elem_dofs + did];
193 for (
int d = 0; d <
dof; ++d)
198 orientation, dof1d, d);
199 const int did = faceMap2[pd];
200 const int gid = elementMap[e2*elem_dofs + did];
208 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
209 for (
int i = 1; i <=
ndofs; ++i)
214 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
221 orientation = inf1 % 64;
222 face_id1 = inf1 / 64;
224 orientation = inf2 % 64;
225 face_id2 = inf2 / 64;
227 for (
int d = 0; d <
dof; ++d)
229 const int did = faceMap1[d];
230 const int gid = elementMap[e1*elem_dofs + did];
231 const int lid = dof*f_ind + d;
237 for (
int d = 0; d <
dof; ++d)
242 orientation, dof1d, d);
243 const int did = faceMap2[pd];
244 const int gid = elementMap[e2*elem_dofs + did];
245 const int lid = dof*f_ind + d;
254 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
255 for (
int i =
ndofs; i > 0; --i)
267 x_gf.
MakeRef(const_cast<ParFiniteElementSpace*>(&pfes),
268 const_cast<Vector&>(x), 0);
275 const int threshold =
ndofs;
287 const int dof = i % nd;
288 const int face = i / nd;
289 const int idx1 = d_indices1[i];
290 for (
int c = 0; c < vd; ++c)
292 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
294 const int idx2 = d_indices2[i];
295 for (
int c = 0; c < vd; ++c)
297 if (idx2>-1 && idx2<threshold)
299 d_y(dof, c, 1, face) = d_x(t?c:idx2, t?idx2:c);
301 else if (idx2>=threshold)
303 d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
304 t?(idx2-threshold):c);
308 d_y(dof, c, 1, face) = 0.0;
320 const int dof = i % nd;
321 const int face = i / nd;
322 const int idx1 = d_indices1[i];
323 for (
int c = 0; c < vd; ++c)
325 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
331 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
340 const int face_dofs =
dof;
341 const int Ndofs =
ndofs;
350 MFEM_FORALL(fdof,
nf*face_dofs,
352 const int f = fdof/face_dofs;
353 const int iF = fdof%face_dofs;
354 const int iE1 = d_indices1[f*face_dofs+iF];
357 for (
int jF = 0; jF < face_dofs; jF++)
359 const int jE2 = d_indices2[f*face_dofs+jF];
366 AddNnz(iE1,I_face,1);
370 const int iE2 = d_indices2[f*face_dofs+iF];
373 for (
int jF = 0; jF < face_dofs; jF++)
375 const int jE1 = d_indices1[f*face_dofs+jF];
382 AddNnz(iE2,I_face,1);
393 const int face_dofs =
dof;
394 const int Ndofs =
ndofs;
397 auto mat_fea =
Reshape(ea_data.
Read(), face_dofs, face_dofs, 2,
nf);
401 auto J_face = face_mat.
WriteJ();
404 MFEM_FORALL(fdof,
nf*face_dofs,
406 const int f = fdof/face_dofs;
407 const int iF = fdof%face_dofs;
408 const int iE1 = d_indices1[f*face_dofs+iF];
411 for (
int jF = 0; jF < face_dofs; jF++)
413 const int jE2 = d_indices2[f*face_dofs+jF];
416 const int offset = AddNnz(iE1,I,1);
418 Data[offset] = mat_fea(jF,iF,1,f);
422 const int offset = AddNnz(iE1,I_face,1);
423 J_face[offset] = jE2-Ndofs;
424 Data_face[offset] = mat_fea(jF,iF,1,f);
428 const int iE2 = d_indices2[f*face_dofs+iF];
431 for (
int jF = 0; jF < face_dofs; jF++)
433 const int jE1 = d_indices1[f*face_dofs+jF];
436 const int offset = AddNnz(iE2,I,1);
438 Data[offset] = mat_fea(jF,iF,0,f);
442 const int offset = AddNnz(iE2,I_face,1);
443 J_face[offset] = jE1-Ndofs;
444 Data_face[offset] = mat_fea(jF,iF,0,f);
Abstract class for all finite elements.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
void ExchangeFaceNbrData()
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Geometry::Type GetFaceBaseGeometry(int i) const
Abstract parallel finite element space.
double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Array< int > gather_indices
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the ParGridFunction reference external data on a new FiniteElementSpace.
const FiniteElementSpace & fes
Mesh * GetMesh() const
Returns the mesh.
Operator that extracts Face degrees of freedom.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
int * ReadWriteI(bool on_dev=true)
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
int SpaceDimension() const
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
int GetDof() const
Returns the number of degrees of freedom in the finite element.
void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
void GetFaceDofs(const int dim, const int face_id, const int dof1d, Array< int > &faceMap)
int * WriteJ(bool on_dev=true)
int height
Dimension of the output / number of rows in the matrix.
Array< int > scatter_indices1
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void FillI(SparseMatrix &mat, SparseMatrix &face_mat) const
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Lexicographic ordering for tensor-product FiniteElements.
ParL2FaceRestriction(const ParFiniteElementSpace &, ElementDofOrdering, FaceType type, L2FaceValues m=L2FaceValues::DoubleValued)
void FillJAndData(const Vector &ea_data, SparseMatrix &mat, SparseMatrix &face_mat) const
int PermuteFaceL2(const int dim, const int face_id1, const int face_id2, const int orientation, const int size1d, const int index)
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element...
Class for parallel grid function.
int width
Dimension of the input / number of columns in the matrix.
Array< int > scatter_indices2
double f(const Vector &p)
double * WriteData(bool on_dev=true)