12 #include "../config/config.hpp" 16 #include "restriction.hpp" 21 #include "../general/forall.hpp" 31 interpolations(fes, f_ordering, type)
33 if (
nf==0) {
return; }
38 MFEM_VERIFY(is_h1,
"ParNCH1FaceRestriction is only implemented for H1 spaces.")
42 ComputeScatterIndicesAndOffsets(f_ordering,
type);
44 ComputeGatherIndices(f_ordering,
type);
60 const int num_nc_faces = nc_interp_config.Size();
61 if ( num_nc_faces == 0 ) {
return; }
62 auto interp_config_ptr = nc_interp_config.Read();
65 nface_dofs, nface_dofs, nc_size);
66 static constexpr
int max_nd = 16*16;
67 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
68 mfem::forall_2D(num_nc_faces, nface_dofs, 1, [=] MFEM_HOST_DEVICE (
int nc_face)
70 MFEM_SHARED
double dof_values[max_nd];
74 const int interp_index = conf.index;
75 const int face = conf.face_index;
76 for (int c = 0; c < vd; ++c)
78 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
80 dof_values[dof] = d_y(dof, c, face);
83 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
86 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
88 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
90 d_y(dof_out, c, face) = res;
98 void ParNCH1FaceRestriction::AddMultTranspose(
const Vector &x,
Vector &y,
101 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
102 if (nf==0) {
return; }
103 NonconformingTransposeInterpolation(x);
104 H1FaceRestriction::AddMultTranspose(x_interp, y);
107 void ParNCH1FaceRestriction::AddMultTransposeInPlace(
Vector &x,
Vector &y)
const 109 if (nf==0) {
return; }
110 NonconformingTransposeInterpolationInPlace(x);
111 H1FaceRestriction::AddMultTranspose(x, y);
114 void ParNCH1FaceRestriction::NonconformingTransposeInterpolation(
117 if (x_interp.Size()==0)
119 x_interp.SetSize(x.
Size());
122 NonconformingTransposeInterpolationInPlace(x_interp);
125 void ParNCH1FaceRestriction::NonconformingTransposeInterpolationInPlace(
129 const int nface_dofs = face_dofs;
131 if ( type==FaceType::Interior )
135 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
136 const int num_nc_faces = nc_interp_config.Size();
137 if ( num_nc_faces == 0 ) {
return; }
138 auto interp_config_ptr = nc_interp_config.Read();
139 const int nc_size = interpolations.GetNumInterpolators();
140 auto d_interp =
Reshape(interpolations.GetInterpolators().Read(),
141 nface_dofs, nface_dofs, nc_size);
142 static constexpr
int max_nd = 1024;
143 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
145 [=] MFEM_HOST_DEVICE (
int nc_face)
147 MFEM_SHARED
double dof_values[max_nd];
152 const int interp_index = conf.index;
153 const int face = conf.face_index;
155 for (int c = 0; c < vd; ++c)
157 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
159 dof_values[dof] = d_x(dof, c, face);
162 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
165 for (int dof_in = 0; dof_in<nface_dofs; dof_in++)
167 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
169 d_x(dof_out, c, face) = res;
178 void ParNCH1FaceRestriction::ComputeScatterIndicesAndOffsets(
182 Mesh &mesh = *fes.GetMesh();
185 for (
int i = 0; i <= ndofs; ++i)
187 gather_offsets[i] = 0;
192 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
194 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
195 if ( face.IsNonconformingCoarse() )
201 else if (face_type==FaceType::Interior && face.IsInterior())
203 if ( face.IsConforming() )
205 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
206 SetFaceDofsScatterIndices(face, f_ind, f_ordering);
211 SetFaceDofsScatterIndices(face, f_ind, f_ordering);
212 if ( face.element[0].conformity==Mesh::ElementConformity::Superset )
216 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
222 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
227 else if (face_type==FaceType::Boundary && face.IsBoundary())
229 SetFaceDofsScatterIndices(face, f_ind, f_ordering);
233 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
236 for (
int i = 1; i <= ndofs; ++i)
238 gather_offsets[i] += gather_offsets[i - 1];
242 interpolations.LinearizeInterpolatorMapIntoVector();
243 interpolations.InitializeNCInterpConfig();
246 void ParNCH1FaceRestriction::ComputeGatherIndices(
250 Mesh &mesh = *fes.GetMesh();
254 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
256 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
257 if ( face.IsNonconformingCoarse() )
263 else if (face.IsOfFaceType(face_type))
265 SetFaceDofsGatherIndices(face, f_ind, f_ordering);
269 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
272 for (
int i = ndofs; i > 0; --i)
274 gather_offsets[i] = gather_offsets[i - 1];
276 gather_offsets[0] = 0;
286 if (!build) {
return; }
287 if (
nf==0) {
return; }
291 ComputeScatterIndicesAndOffsets(f_ordering,
type);
293 ComputeGatherIndices(f_ordering,
type);
308 "This method should be called when m == L2FaceValues::DoubleValued.");
312 x_gf.
MakeRef(const_cast<ParFiniteElementSpace*>(&pfes),
313 const_cast<Vector&>(x), 0);
320 if (
nf == 0) {
return; }
326 const int threshold =
ndofs;
332 t?vd:nsdofs,
t?nsdofs:vd);
336 const int dof = i % nface_dofs;
337 const int face = i / nface_dofs;
338 const int idx1 = d_indices1[i];
339 for (
int c = 0; c < vd; ++c)
341 d_y(dof, c, 0, face) = d_x(
t?c:idx1,
t?idx1:c);
343 const int idx2 = d_indices2[i];
344 for (
int c = 0; c < vd; ++c)
346 if (idx2>-1 && idx2<threshold)
348 d_y(dof, c, 1, face) = d_x(
t?c:idx2,
t?idx2:c);
350 else if (idx2>=threshold)
352 d_y(dof, c, 1, face) = d_x_shared(
t?c:(idx2-threshold),
353 t?(idx2-threshold):c);
357 d_y(dof, c, 1, face) = 0.0;
375 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
382 const bool keep_nbr_block)
const 389 const int Ndofs =
ndofs;
395 const int f = fdof/nface_dofs;
396 const int iF = fdof%nface_dofs;
397 const int iE1 = d_indices1[
f*nface_dofs+iF];
400 AddNnz(iE1,I,nface_dofs);
402 const int iE2 = d_indices2[
f*nface_dofs+iF];
405 AddNnz(iE2,I,nface_dofs);
414 const int Ndofs =
ndofs;
425 const int f = fdof/nface_dofs;
426 const int iF = fdof%nface_dofs;
427 const int iE1 = d_indices1[
f*nface_dofs+iF];
430 for (
int jF = 0; jF < nface_dofs; jF++)
432 const int jE2 = d_indices2[
f*nface_dofs+jF];
439 AddNnz(iE1,I_face,1);
443 const int iE2 = d_indices2[
f*nface_dofs+iF];
446 for (
int jF = 0; jF < nface_dofs; jF++)
448 const int jE1 = d_indices1[
f*nface_dofs+jF];
455 AddNnz(iE2,I_face,1);
464 const bool keep_nbr_block)
const 471 const int Ndofs =
ndofs;
474 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
480 const int f = fdof/nface_dofs;
481 const int iF = fdof%nface_dofs;
482 const int iE1 = d_indices1[
f*nface_dofs+iF];
485 const int offset = AddNnz(iE1,I,nface_dofs);
486 for (
int jF = 0; jF < nface_dofs; jF++)
488 const int jE2 = d_indices2[
f*nface_dofs+jF];
490 Data[offset+jF] = mat_fea(jF,iF,1,
f);
493 const int iE2 = d_indices2[
f*nface_dofs+iF];
496 const int offset = AddNnz(iE2,I,nface_dofs);
497 for (
int jF = 0; jF < nface_dofs; jF++)
499 const int jE1 = d_indices1[
f*nface_dofs+jF];
501 Data[offset+jF] = mat_fea(jF,iF,0,
f);
512 const int Ndofs =
ndofs;
515 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
519 auto J_face = face_mat.
WriteJ();
524 const int f = fdof/nface_dofs;
525 const int iF = fdof%nface_dofs;
526 const int iE1 = d_indices1[
f*nface_dofs+iF];
529 for (
int jF = 0; jF < nface_dofs; jF++)
531 const int jE2 = d_indices2[
f*nface_dofs+jF];
534 const int offset = AddNnz(iE1,I,1);
536 Data[offset] = mat_fea(jF,iF,1,
f);
540 const int offset = AddNnz(iE1,I_face,1);
541 J_face[offset] = jE2-Ndofs;
542 Data_face[offset] = mat_fea(jF,iF,1,
f);
546 const int iE2 = d_indices2[
f*nface_dofs+iF];
549 for (
int jF = 0; jF < nface_dofs; jF++)
551 const int jE1 = d_indices1[
f*nface_dofs+jF];
554 const int offset = AddNnz(iE2,I,1);
556 Data[offset] = mat_fea(jF,iF,0,
f);
560 const int offset = AddNnz(iE2,I_face,1);
561 J_face[offset] = jE1-Ndofs;
562 Data_face[offset] = mat_fea(jF,iF,0,
f);
569 void ParL2FaceRestriction::ComputeScatterIndicesAndOffsets(
578 for (
int i = 0; i <=
ndofs; ++i)
585 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
614 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
617 for (
int i = 1; i <=
ndofs; ++i)
624 void ParL2FaceRestriction::ComputeGatherIndices(
635 if (face.IsOfFaceType(
type))
647 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
650 for (
int i =
ndofs; i > 0; --i)
665 if (
nf==0) {
return; }
670 ComputeScatterIndicesAndOffsets(f_ordering,
type);
672 ComputeGatherIndices(f_ordering,
type);
678 if (
nf == 0) {
return; }
681 "This method should be called when m == L2FaceValues::SingleValued.");
686 const int threshold =
ndofs;
693 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
694 static constexpr
int max_nd = 16*16;
695 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
698 MFEM_SHARED
double dof_values[max_nd];
701 const int interp_index = conf.
index;
705 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
707 const int i = face*nface_dofs + dof;
708 const int idx = d_indices1[i];
709 if (idx>-1 && idx<threshold)
711 for (int c = 0; c < vd; ++c)
713 d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
718 for (int c = 0; c < vd; ++c)
720 d_y(dof, c, face) = 0.0;
727 for (
int c = 0; c < vd; ++c)
729 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
731 const int i = face*nface_dofs + dof;
732 const int idx = d_indices1[i];
733 if (idx>-1 && idx<threshold)
735 dof_values[dof] = d_x(
t?c:idx,
t?idx:c);
739 dof_values[dof] = 0.0;
743 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
746 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
748 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
750 d_y(dof_out, c, face) = res;
785 MFEM_ABORT(
"Unknown type and multiplicity combination.");
790 const double a)
const 792 MFEM_VERIFY(
a == 1.0,
"General coefficient case is not yet supported!");
793 if (
nf==0) {
return; }
822 if (
nf==0) {
return; }
850 const bool keep_nbr_block)
const 852 MFEM_ABORT(
"Not yet implemented.");
858 MFEM_ABORT(
"Not yet implemented.");
863 const bool keep_nbr_block)
const 865 MFEM_ABORT(
"Not yet implemented.");
872 MFEM_ABORT(
"Not yet implemented.");
875 void ParNCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
882 for (
int i = 0; i <=
ndofs; ++i)
892 if ( face.IsNonconformingCoarse() )
900 if ( face.IsConforming() )
906 if ( face.IsShared() )
922 if ( face.IsShared() )
944 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
946 " faces: " << f_ind <<
" vs " <<
nf );
949 for (
int i = 1; i <=
ndofs; ++i)
959 void ParNCL2FaceRestriction::ComputeGatherIndices(
967 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
970 if ( face.IsNonconformingCoarse() )
976 else if ( face.IsOfFaceType(
type) )
988 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
990 " faces: " << f_ind <<
" vs " <<
nf );
993 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...
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 forall_2D(int N, int X, int Y, lambda &&body)
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...
void Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void SetBoundaryDofsScatterIndices2(const Mesh::FaceInformation &face, const int face_index)
Set the scattering indices of elem2 for the boundary face described by the face.
ParNCH1FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering f_ordering, FaceType type)
Constructs an ParNCH1FaceRestriction.
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.
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...
ParL2FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering f_ordering, FaceType type, L2FaceValues m, bool build)
Constructs an ParL2FaceRestriction.
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
std::function< double(const Vector &)> f(double mass_coeff)
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
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 ...
const FiniteElementCollection * FEColl() const
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 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 forall(int N, lambda &&body)
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
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...
Arbitrary order H1-conforming (continuous) finite elements.
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
void CheckFESpace(const ElementDofOrdering f_ordering)
Verify that L2FaceRestriction is built from an L2 FESpace.
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...
ParNCL2FaceRestriction(const ParFiniteElementSpace &fes, ElementDofOrdering f_ordering, FaceType type, L2FaceValues m=L2FaceValues::DoubleValued)
Constructs an ParNCL2FaceRestriction.
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...