12 #include "../config/config.hpp" 16 #include "restriction.hpp" 21 #include "../general/forall.hpp" 31 interpolations(fes, ordering, type)
33 if (
nf==0) {
return; }
38 ComputeScatterIndicesAndOffsets(ordering,
type);
40 ComputeGatherIndices(ordering,
type);
56 const int num_nc_faces = nc_interp_config.Size();
57 if ( num_nc_faces == 0 ) {
return; }
58 auto interp_config_ptr = nc_interp_config.Read();
61 nface_dofs, nface_dofs, nc_size);
62 static constexpr
int max_nd = 16*16;
63 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
64 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
66 MFEM_SHARED
double dof_values[max_nd];
70 const int interp_index = conf.index;
71 const int face = conf.face_index;
72 for (int c = 0; c < vd; ++c)
74 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
76 dof_values[dof] = d_y(dof, c, face);
79 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
82 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
84 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
86 d_y(dof_out, c, face) = res;
94 void ParNCH1FaceRestriction::AddMultTranspose(
const Vector &x,
Vector &y,
97 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
98 if (nf==0) {
return; }
99 NonconformingTransposeInterpolation(x);
100 H1FaceRestriction::AddMultTranspose(x_interp, y);
103 void ParNCH1FaceRestriction::AddMultTransposeInPlace(
Vector &x,
Vector &y)
const 105 if (nf==0) {
return; }
106 NonconformingTransposeInterpolationInPlace(x);
107 H1FaceRestriction::AddMultTranspose(x, y);
110 void ParNCH1FaceRestriction::NonconformingTransposeInterpolation(
113 if (x_interp.Size()==0)
115 x_interp.SetSize(x.
Size());
118 NonconformingTransposeInterpolationInPlace(x_interp);
121 void ParNCH1FaceRestriction::NonconformingTransposeInterpolationInPlace(
125 const int nface_dofs = face_dofs;
127 if ( type==FaceType::Interior )
131 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
132 const int num_nc_faces = nc_interp_config.Size();
133 if ( num_nc_faces == 0 ) {
return; }
134 auto interp_config_ptr = nc_interp_config.Read();
135 const int nc_size = interpolations.GetNumInterpolators();
136 auto d_interp =
Reshape(interpolations.GetInterpolators().Read(),
137 nface_dofs, nface_dofs, nc_size);
138 static constexpr
int max_nd = 1024;
139 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
140 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
142 MFEM_SHARED
double dof_values[max_nd];
147 const int interp_index = conf.index;
148 const int face = conf.face_index;
150 for (int c = 0; c < vd; ++c)
152 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
154 dof_values[dof] = d_x(dof, c, face);
157 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
160 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
162 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
164 d_x(dof_out, c, face) = res;
173 void ParNCH1FaceRestriction::ComputeScatterIndicesAndOffsets(
177 Mesh &mesh = *fes.GetMesh();
180 for (
int i = 0; i <= ndofs; ++i)
182 gather_offsets[i] = 0;
187 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
189 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
190 if ( face.IsNonconformingCoarse() )
196 else if (face_type==FaceType::Interior && face.IsInterior())
198 if ( face.IsConforming() )
200 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
201 SetFaceDofsScatterIndices(face, f_ind, ordering);
206 SetFaceDofsScatterIndices(face, f_ind, ordering);
207 if ( face.element[0].conformity==Mesh::ElementConformity::Superset )
211 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
217 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
222 else if (face_type==FaceType::Boundary && face.IsBoundary())
224 SetFaceDofsScatterIndices(face, f_ind, ordering);
228 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
231 for (
int i = 1; i <= ndofs; ++i)
233 gather_offsets[i] += gather_offsets[i - 1];
237 interpolations.LinearizeInterpolatorMapIntoVector();
238 interpolations.InitializeNCInterpConfig();
241 void ParNCH1FaceRestriction::ComputeGatherIndices(
245 Mesh &mesh = *fes.GetMesh();
249 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
251 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
252 if ( face.IsNonconformingCoarse() )
258 else if (face.IsOfFaceType(face_type))
260 SetFaceDofsGatherIndices(face, f_ind, ordering);
264 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
267 for (
int i = ndofs; i > 0; --i)
269 gather_offsets[i] = gather_offsets[i - 1];
271 gather_offsets[0] = 0;
281 if (!build) {
return; }
282 if (
nf==0) {
return; }
286 ComputeScatterIndicesAndOffsets(ordering,
type);
288 ComputeGatherIndices(ordering,
type);
303 "This method should be called when m == L2FaceValues::DoubleValued.");
307 x_gf.
MakeRef(const_cast<ParFiniteElementSpace*>(&pfes),
308 const_cast<Vector&>(x), 0);
315 const int threshold =
ndofs;
321 t?vd:nsdofs,
t?nsdofs:vd);
325 const int dof = i % nface_dofs;
326 const int face = i / nface_dofs;
327 const int idx1 = d_indices1[i];
328 for (
int c = 0; c < vd; ++c)
330 d_y(dof, c, 0, face) = d_x(
t?c:idx1,
t?idx1:c);
332 const int idx2 = d_indices2[i];
333 for (
int c = 0; c < vd; ++c)
335 if (idx2>-1 && idx2<threshold)
337 d_y(dof, c, 1, face) = d_x(
t?c:idx2,
t?idx2:c);
339 else if (idx2>=threshold)
341 d_y(dof, c, 1, face) = d_x_shared(
t?c:(idx2-threshold),
342 t?(idx2-threshold):c);
346 d_y(dof, c, 1, face) = 0.0;
354 if (
nf==0) {
return; }
365 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
372 const bool keep_nbr_block)
const 379 const int Ndofs =
ndofs;
383 MFEM_FORALL(fdof,
nf*nface_dofs,
385 const int f = fdof/nface_dofs;
386 const int iF = fdof%nface_dofs;
387 const int iE1 = d_indices1[
f*nface_dofs+iF];
390 AddNnz(iE1,I,nface_dofs);
392 const int iE2 = d_indices2[
f*nface_dofs+iF];
395 AddNnz(iE2,I,nface_dofs);
404 const int Ndofs =
ndofs;
413 MFEM_FORALL(fdof,
nf*nface_dofs,
415 const int f = fdof/nface_dofs;
416 const int iF = fdof%nface_dofs;
417 const int iE1 = d_indices1[
f*nface_dofs+iF];
420 for (
int jF = 0; jF < nface_dofs; jF++)
422 const int jE2 = d_indices2[
f*nface_dofs+jF];
429 AddNnz(iE1,I_face,1);
433 const int iE2 = d_indices2[
f*nface_dofs+iF];
436 for (
int jF = 0; jF < nface_dofs; jF++)
438 const int jE1 = d_indices1[
f*nface_dofs+jF];
445 AddNnz(iE2,I_face,1);
454 const bool keep_nbr_block)
const 461 const int Ndofs =
ndofs;
464 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
468 MFEM_FORALL(fdof,
nf*nface_dofs,
470 const int f = fdof/nface_dofs;
471 const int iF = fdof%nface_dofs;
472 const int iE1 = d_indices1[
f*nface_dofs+iF];
475 const int offset = AddNnz(iE1,I,nface_dofs);
476 for (
int jF = 0; jF < nface_dofs; jF++)
478 const int jE2 = d_indices2[
f*nface_dofs+jF];
480 Data[offset+jF] = mat_fea(jF,iF,1,
f);
483 const int iE2 = d_indices2[
f*nface_dofs+iF];
486 const int offset = AddNnz(iE2,I,nface_dofs);
487 for (
int jF = 0; jF < nface_dofs; jF++)
489 const int jE1 = d_indices1[
f*nface_dofs+jF];
491 Data[offset+jF] = mat_fea(jF,iF,0,
f);
502 const int Ndofs =
ndofs;
505 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
509 auto J_face = face_mat.
WriteJ();
512 MFEM_FORALL(fdof,
nf*nface_dofs,
514 const int f = fdof/nface_dofs;
515 const int iF = fdof%nface_dofs;
516 const int iE1 = d_indices1[
f*nface_dofs+iF];
519 for (
int jF = 0; jF < nface_dofs; jF++)
521 const int jE2 = d_indices2[
f*nface_dofs+jF];
524 const int offset = AddNnz(iE1,I,1);
526 Data[offset] = mat_fea(jF,iF,1,
f);
530 const int offset = AddNnz(iE1,I_face,1);
531 J_face[offset] = jE2-Ndofs;
532 Data_face[offset] = mat_fea(jF,iF,1,
f);
536 const int iE2 = d_indices2[
f*nface_dofs+iF];
539 for (
int jF = 0; jF < nface_dofs; jF++)
541 const int jE1 = d_indices1[
f*nface_dofs+jF];
544 const int offset = AddNnz(iE2,I,1);
546 Data[offset] = mat_fea(jF,iF,0,
f);
550 const int offset = AddNnz(iE2,I_face,1);
551 J_face[offset] = jE1-Ndofs;
552 Data_face[offset] = mat_fea(jF,iF,0,
f);
559 void ParL2FaceRestriction::ComputeScatterIndicesAndOffsets(
568 for (
int i = 0; i <=
ndofs; ++i)
575 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
604 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
607 for (
int i = 1; i <=
ndofs; ++i)
614 void ParL2FaceRestriction::ComputeGatherIndices(
625 if (face.IsOfFaceType(
type))
637 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
640 for (
int i =
ndofs; i > 0; --i)
655 if (
nf==0) {
return; }
660 ComputeScatterIndicesAndOffsets(ordering,
type);
662 ComputeGatherIndices(ordering,
type);
670 "This method should be called when m == L2FaceValues::SingleValued.");
675 const int threshold =
ndofs;
682 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
683 static constexpr
int max_nd = 16*16;
684 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
685 MFEM_FORALL_3D(face,
nf, nface_dofs, 1, 1,
687 MFEM_SHARED
double dof_values[max_nd];
690 const int interp_index = conf.
index;
694 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
696 const int i = face*nface_dofs + dof;
697 const int idx = d_indices1[i];
698 if (idx>-1 && idx<threshold)
700 for (int c = 0; c < vd; ++c)
702 d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
707 for (int c = 0; c < vd; ++c)
709 d_y(dof, c, face) = 0.0;
716 for (
int c = 0; c < vd; ++c)
718 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
720 const int i = face*nface_dofs + dof;
721 const int idx = d_indices1[i];
722 if (idx>-1 && idx<threshold)
724 dof_values[dof] = d_x(
t?c:idx,
t?idx:c);
728 dof_values[dof] = 0.0;
732 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
735 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
737 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
739 d_y(dof_out, c, face) = res;
756 if (
nf==0) {
return; }
775 MFEM_ABORT(
"Unknown type and multiplicity combination.");
780 const double a)
const 782 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
783 if (
nf==0) {
return; }
812 if (
nf==0) {
return; }
840 const bool keep_nbr_block)
const 842 MFEM_ABORT(
"Not yet implemented.");
848 MFEM_ABORT(
"Not yet implemented.");
853 const bool keep_nbr_block)
const 855 MFEM_ABORT(
"Not yet implemented.");
862 MFEM_ABORT(
"Not yet implemented.");
865 void ParNCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
872 for (
int i = 0; i <=
ndofs; ++i)
882 if ( face.IsNonconformingCoarse() )
890 if ( face.IsConforming() )
896 if ( face.IsShared() )
912 if ( face.IsShared() )
934 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
936 " faces: " << f_ind <<
" vs " <<
nf );
939 for (
int i = 1; i <=
ndofs; ++i)
949 void ParNCL2FaceRestriction::ComputeGatherIndices(
957 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
960 if ( face.IsNonconformingCoarse() )
966 else if ( face.IsOfFaceType(
type) )
978 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
980 " faces: " << f_ind <<
" vs " <<
nf );
983 for (
int i =
ndofs; i > 0; --i)
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
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< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
Operator that extracts Face degrees of freedom in parallel.
void DoubleValuedNonconformingMult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with no...
void ExchangeFaceNbrData()
void SingleValuedNonconformingTransposeInterpolation(const Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
void FillJAndData(const Vector &fea_data, SparseMatrix &mat, SparseMatrix &face_mat) const
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...
Operator that extracts Face degrees of freedom for H1 FiniteElementSpaces.
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
ParL2FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering ordering, FaceType type, L2FaceValues m, bool build)
Constructs an ParL2FaceRestriction.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
ParNCH1FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering ordering, FaceType type)
Constructs an ParNCH1FaceRestriction.
void SetBoundaryDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem2 for the boundary face described by the face.
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
int Size() const
Returns the size of the vector.
InterpolationManager interpolations
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void DoubleValuedNonconformingTransposeInterpolation(const Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
Abstract parallel finite element space.
int GetFaceNbrVSize() const
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...
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
ParNCL2FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering ordering, FaceType type, L2FaceValues m=L2FaceValues::DoubleValued)
Constructs an ParNCL2FaceRestriction.
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...
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
void SingleValuedNonconformingMult(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 AddMultTransposeInPlace(Vector &x, Vector &y) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
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...
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...
const FiniteElementSpace & fes
double f(const Vector &xvec)
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 ...
Operator that extracts Face degrees of freedom for L2 spaces.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
void InitializeNCInterpConfig()
void CheckFESpace(const ElementDofOrdering ordering)
Verify that H1FaceRestriction is build from an H1 FESpace.
void LinearizeInterpolatorMapIntoVector()
Transform the interpolation matrix map into a contiguous memory structure.
int * ReadWriteI(bool on_dev=true)
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...
uint32_t is_non_conforming
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Array< int > gather_offsets
Mesh * GetMesh() const
Returns the mesh.
void DoubleValuedConformingMult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector. Should only be used with co...
const Array< InterpConfig > & GetFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void FillJAndData(const Vector &ea_data, SparseMatrix &mat, SparseMatrix &face_mat) const
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...
int * WriteJ(bool on_dev=true)
Array< int > scatter_indices1
void CheckFESpace(const ElementDofOrdering ordering)
Verify that L2FaceRestriction is build from an L2 FESpace.
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
int GetNumInterpolators() const
Return the total number of interpolators.
void NonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
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...
FaceInformation GetFaceInformation(int f) const
void SingleValuedNonconformingTransposeInterpolationInPlace(Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
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 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...
Class for parallel grid function.
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
uint32_t is_non_conforming
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...
InterpolationManager interpolations
void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const override
Array< int > scatter_indices2
void DoubleValuedNonconformingTransposeInterpolationInPlace(Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
double f(const Vector &p)
double * WriteData(bool on_dev=true)
void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const override
Fill the I array of SparseMatrix corresponding to the sparsity pattern given by this ParNCL2FaceRestr...