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;
284 t?vd:nsdofs, t?nsdofs:vd);
288 const int dof = i % nd;
289 const int face = i / nd;
290 const int idx1 = d_indices1[i];
291 for (
int c = 0; c < vd; ++c)
293 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
295 const int idx2 = d_indices2[i];
296 for (
int c = 0; c < vd; ++c)
298 if (idx2>-1 && idx2<threshold)
300 d_y(dof, c, 1, face) = d_x(t?c:idx2, t?idx2:c);
302 else if (idx2>=threshold)
304 d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
305 t?(idx2-threshold):c);
309 d_y(dof, c, 1, face) = 0.0;
321 const int dof = i % nd;
322 const int face = i / nd;
323 const int idx1 = d_indices1[i];
324 for (
int c = 0; c < vd; ++c)
326 d_y(dof, c, face) = d_x(t?c:idx1, t?idx1:c);
332 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
339 const bool keep_nbr_block)
const
345 const int face_dofs =
dof;
346 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 AddNnz(iE1,I,face_dofs);
359 const int iE2 = d_indices2[f*face_dofs+iF];
362 AddNnz(iE2,I,face_dofs);
370 const int face_dofs =
dof;
371 const int Ndofs =
ndofs;
380 MFEM_FORALL(fdof,
nf*face_dofs,
382 const int f = fdof/face_dofs;
383 const int iF = fdof%face_dofs;
384 const int iE1 = d_indices1[f*face_dofs+iF];
387 for (
int jF = 0; jF < face_dofs; jF++)
389 const int jE2 = d_indices2[f*face_dofs+jF];
396 AddNnz(iE1,I_face,1);
400 const int iE2 = d_indices2[f*face_dofs+iF];
403 for (
int jF = 0; jF < face_dofs; jF++)
405 const int jE1 = d_indices1[f*face_dofs+jF];
412 AddNnz(iE2,I_face,1);
421 const bool keep_nbr_block)
const
427 const int face_dofs =
dof;
428 const int Ndofs =
ndofs;
431 auto mat_fea =
Reshape(ea_data.
Read(), face_dofs, face_dofs, 2,
nf);
435 MFEM_FORALL(fdof,
nf*face_dofs,
437 const int f = fdof/face_dofs;
438 const int iF = fdof%face_dofs;
439 const int iE1 = d_indices1[f*face_dofs+iF];
442 const int offset = AddNnz(iE1,I,face_dofs);
443 for (
int jF = 0; jF < face_dofs; jF++)
445 const int jE2 = d_indices2[f*face_dofs+jF];
447 Data[offset+jF] = mat_fea(jF,iF,1,f);
450 const int iE2 = d_indices2[f*face_dofs+iF];
453 const int offset = AddNnz(iE2,I,face_dofs);
454 for (
int jF = 0; jF < face_dofs; jF++)
456 const int jE1 = d_indices1[f*face_dofs+jF];
458 Data[offset+jF] = mat_fea(jF,iF,0,f);
468 const int face_dofs =
dof;
469 const int Ndofs =
ndofs;
472 auto mat_fea =
Reshape(ea_data.
Read(), face_dofs, face_dofs, 2,
nf);
476 auto J_face = face_mat.
WriteJ();
479 MFEM_FORALL(fdof,
nf*face_dofs,
481 const int f = fdof/face_dofs;
482 const int iF = fdof%face_dofs;
483 const int iE1 = d_indices1[f*face_dofs+iF];
486 for (
int jF = 0; jF < face_dofs; jF++)
488 const int jE2 = d_indices2[f*face_dofs+jF];
491 const int offset = AddNnz(iE1,I,1);
493 Data[offset] = mat_fea(jF,iF,1,f);
497 const int offset = AddNnz(iE1,I_face,1);
498 J_face[offset] = jE2-Ndofs;
499 Data_face[offset] = mat_fea(jF,iF,1,f);
503 const int iE2 = d_indices2[f*face_dofs+iF];
506 for (
int jF = 0; jF < face_dofs; jF++)
508 const int jE1 = d_indices1[f*face_dofs+jF];
511 const int offset = AddNnz(iE2,I,1);
513 Data[offset] = mat_fea(jF,iF,0,f);
517 const int offset = AddNnz(iE2,I_face,1);
518 J_face[offset] = jE1-Ndofs;
519 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()
virtual void FillJAndData(const Vector &ea_data, SparseMatrix &mat, const bool keep_nbr_block=false) const
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.
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
double f(const Vector &xvec)
virtual const FiniteElement * GetFE(int i) const
Mesh * GetMesh() const
Returns the mesh.
Operator that extracts Face degrees of freedom on L2 FiniteElementSpaces.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
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
Extract the face degrees of freedom from x into y.
virtual void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const
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
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Lexicographic ordering for tensor-product FiniteElements.
int GetFaceNbrVSize() const
ParL2FaceRestriction(const ParFiniteElementSpace &, ElementDofOrdering, FaceType type, L2FaceValues m=L2FaceValues::DoubleValued)
virtual 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.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
int width
Dimension of the input / number of columns in the matrix.
Array< int > scatter_indices2
virtual void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const
double * WriteData(bool on_dev=true)