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;
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)
const
96 if (nf==0) {
return; }
97 NonconformingTransposeInterpolation(x);
98 H1FaceRestriction::AddMultTranspose(x_interp, y);
101 void ParNCH1FaceRestriction::AddMultTransposeInPlace(
Vector &x,
Vector &y)
const
103 if (nf==0) {
return; }
104 NonconformingTransposeInterpolationInPlace(x);
105 H1FaceRestriction::AddMultTranspose(x, y);
108 void ParNCH1FaceRestriction::NonconformingTransposeInterpolation(
111 if (x_interp.Size()==0)
113 x_interp.SetSize(x.
Size());
116 NonconformingTransposeInterpolationInPlace(x_interp);
119 void ParNCH1FaceRestriction::NonconformingTransposeInterpolationInPlace(
123 const int nface_dofs = face_dofs;
125 if ( type==FaceType::Interior )
129 auto &nc_interp_config = interpolations.GetNCFaceInterpConfig();
130 const int num_nc_faces = nc_interp_config.Size();
131 if ( num_nc_faces == 0 ) {
return; }
132 auto interp_config_ptr = nc_interp_config.Read();
133 const int nc_size = interpolations.GetNumInterpolators();
134 auto d_interp =
Reshape(interpolations.GetInterpolators().Read(),
135 nface_dofs, nface_dofs, nc_size);
136 static constexpr
int max_nd = 1024;
137 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
138 MFEM_FORALL_3D(nc_face, num_nc_faces, nface_dofs, 1, 1,
140 MFEM_SHARED
double dof_values[max_nd];
145 const int interp_index = conf.
index;
148 for (
int c = 0; c < vd; ++c)
150 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
152 dof_values[dof] = d_x(dof, c, face);
155 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
158 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
160 res += d_interp(dof_in, dof_out, interp_index)*dof_values[dof_in];
162 d_x(dof_out, c, face) = res;
171 void ParNCH1FaceRestriction::ComputeScatterIndicesAndOffsets(
175 Mesh &mesh = *fes.GetMesh();
178 for (
int i = 0; i <= ndofs; ++i)
180 gather_offsets[i] = 0;
185 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
187 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
188 if ( face.IsNonconformingCoarse() )
194 else if (face_type==FaceType::Interior && face.IsInterior())
196 if ( face.IsConforming() )
198 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
199 SetFaceDofsScatterIndices(face, f_ind, ordering);
204 SetFaceDofsScatterIndices(face, f_ind, ordering);
205 if ( face.element[0].conformity==Mesh::ElementConformity::Superset )
209 interpolations.RegisterFaceCoarseToFineInterpolation(face,f_ind);
215 interpolations.RegisterFaceConformingInterpolation(face,f_ind);
220 else if (face_type==FaceType::Boundary && face.IsBoundary())
222 SetFaceDofsScatterIndices(face, f_ind, ordering);
226 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
229 for (
int i = 1; i <= ndofs; ++i)
231 gather_offsets[i] += gather_offsets[i - 1];
235 interpolations.LinearizeInterpolatorMapIntoVector();
236 interpolations.InitializeNCInterpConfig();
239 void ParNCH1FaceRestriction::ComputeGatherIndices(
243 Mesh &mesh = *fes.GetMesh();
247 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
249 Mesh::FaceInformation face = mesh.GetFaceInformation(
f);
250 if ( face.IsNonconformingCoarse() )
256 else if (face.IsOfFaceType(face_type))
258 SetFaceDofsGatherIndices(face, f_ind, ordering);
262 MFEM_VERIFY(f_ind==nf,
"Unexpected number of faces.");
265 for (
int i = ndofs; i > 0; --i)
267 gather_offsets[i] = gather_offsets[i - 1];
269 gather_offsets[0] = 0;
279 if (!build) {
return; }
280 if (
nf==0) {
return; }
284 ComputeScatterIndicesAndOffsets(ordering, type);
286 ComputeGatherIndices(ordering, type);
301 "This method should be called when m == L2FaceValues::DoubleValued.");
305 x_gf.
MakeRef(const_cast<ParFiniteElementSpace*>(&pfes),
306 const_cast<Vector&>(x), 0);
313 const int threshold =
ndofs;
319 t?vd:nsdofs, t?nsdofs:vd);
323 const int dof = i % nface_dofs;
324 const int face = i / nface_dofs;
325 const int idx1 = d_indices1[i];
326 for (
int c = 0; c < vd; ++c)
328 d_y(dof, c, 0, face) = d_x(t?c:idx1, t?idx1:c);
330 const int idx2 = d_indices2[i];
331 for (
int c = 0; c < vd; ++c)
333 if (idx2>-1 && idx2<threshold)
335 d_y(dof, c, 1, face) = d_x(t?c:idx2, t?idx2:c);
337 else if (idx2>=threshold)
339 d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
340 t?(idx2-threshold):c);
344 d_y(dof, c, 1, face) = 0.0;
352 if (
nf==0) {
return; }
363 static MFEM_HOST_DEVICE
int AddNnz(
const int iE,
int *I,
const int dofs)
370 const bool keep_nbr_block)
const
377 const int Ndofs =
ndofs;
381 MFEM_FORALL(fdof,
nf*nface_dofs,
383 const int f = fdof/nface_dofs;
384 const int iF = fdof%nface_dofs;
385 const int iE1 = d_indices1[f*nface_dofs+iF];
388 AddNnz(iE1,I,nface_dofs);
390 const int iE2 = d_indices2[f*nface_dofs+iF];
393 AddNnz(iE2,I,nface_dofs);
402 const int Ndofs =
ndofs;
411 MFEM_FORALL(fdof,
nf*nface_dofs,
413 const int f = fdof/nface_dofs;
414 const int iF = fdof%nface_dofs;
415 const int iE1 = d_indices1[f*nface_dofs+iF];
418 for (
int jF = 0; jF < nface_dofs; jF++)
420 const int jE2 = d_indices2[f*nface_dofs+jF];
427 AddNnz(iE1,I_face,1);
431 const int iE2 = d_indices2[f*nface_dofs+iF];
434 for (
int jF = 0; jF < nface_dofs; jF++)
436 const int jE1 = d_indices1[f*nface_dofs+jF];
443 AddNnz(iE2,I_face,1);
452 const bool keep_nbr_block)
const
459 const int Ndofs =
ndofs;
462 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
466 MFEM_FORALL(fdof,
nf*nface_dofs,
468 const int f = fdof/nface_dofs;
469 const int iF = fdof%nface_dofs;
470 const int iE1 = d_indices1[f*nface_dofs+iF];
473 const int offset = AddNnz(iE1,I,nface_dofs);
474 for (
int jF = 0; jF < nface_dofs; jF++)
476 const int jE2 = d_indices2[f*nface_dofs+jF];
478 Data[offset+jF] = mat_fea(jF,iF,1,f);
481 const int iE2 = d_indices2[f*nface_dofs+iF];
484 const int offset = AddNnz(iE2,I,nface_dofs);
485 for (
int jF = 0; jF < nface_dofs; jF++)
487 const int jE1 = d_indices1[f*nface_dofs+jF];
489 Data[offset+jF] = mat_fea(jF,iF,0,f);
500 const int Ndofs =
ndofs;
503 auto mat_fea =
Reshape(ea_data.
Read(), nface_dofs, nface_dofs, 2,
nf);
507 auto J_face = face_mat.
WriteJ();
510 MFEM_FORALL(fdof,
nf*nface_dofs,
512 const int f = fdof/nface_dofs;
513 const int iF = fdof%nface_dofs;
514 const int iE1 = d_indices1[f*nface_dofs+iF];
517 for (
int jF = 0; jF < nface_dofs; jF++)
519 const int jE2 = d_indices2[f*nface_dofs+jF];
522 const int offset = AddNnz(iE1,I,1);
524 Data[offset] = mat_fea(jF,iF,1,f);
528 const int offset = AddNnz(iE1,I_face,1);
529 J_face[offset] = jE2-Ndofs;
530 Data_face[offset] = mat_fea(jF,iF,1,f);
534 const int iE2 = d_indices2[f*nface_dofs+iF];
537 for (
int jF = 0; jF < nface_dofs; jF++)
539 const int jE1 = d_indices1[f*nface_dofs+jF];
542 const int offset = AddNnz(iE2,I,1);
544 Data[offset] = mat_fea(jF,iF,0,f);
548 const int offset = AddNnz(iE2,I_face,1);
549 J_face[offset] = jE1-Ndofs;
550 Data_face[offset] = mat_fea(jF,iF,0,f);
557 void ParL2FaceRestriction::ComputeScatterIndicesAndOffsets(
566 for (
int i = 0; i <=
ndofs; ++i)
573 for (
int f = 0;
f < pfes.
GetNF(); ++
f)
602 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
605 for (
int i = 1; i <=
ndofs; ++i)
612 void ParL2FaceRestriction::ComputeGatherIndices(
623 if (face.IsOfFaceType(type))
635 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of faces.");
638 for (
int i =
ndofs; i > 0; --i)
653 if (
nf==0) {
return; }
658 ComputeScatterIndicesAndOffsets(ordering, type);
660 ComputeGatherIndices(ordering, type);
668 "This method should be called when m == L2FaceValues::SingleValued.");
673 const int threshold =
ndofs;
680 auto d_interp =
Reshape(interpolators, nface_dofs, nface_dofs, nc_size);
681 static constexpr
int max_nd = 16*16;
682 MFEM_VERIFY(nface_dofs<=max_nd,
"Too many degrees of freedom.");
683 MFEM_FORALL_3D(face,
nf, nface_dofs, 1, 1,
685 MFEM_SHARED
double dof_values[max_nd];
688 const int interp_index = conf.
index;
692 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
694 const int i = face*nface_dofs + dof;
695 const int idx = d_indices1[i];
696 if (idx>-1 && idx<threshold)
698 for (
int c = 0; c < vd; ++c)
700 d_y(dof, c, face) = d_x(t?c:idx, t?idx:c);
705 for (
int c = 0; c < vd; ++c)
707 d_y(dof, c, face) = 0.0;
714 for (
int c = 0; c < vd; ++c)
716 MFEM_FOREACH_THREAD(dof,x,nface_dofs)
718 const int i = face*nface_dofs + dof;
719 const int idx = d_indices1[i];
720 if (idx>-1 && idx<threshold)
722 dof_values[dof] = d_x(t?c:idx, t?idx:c);
726 dof_values[dof] = 0.0;
730 MFEM_FOREACH_THREAD(dof_out,x,nface_dofs)
733 for (
int dof_in = 0; dof_in<nface_dofs; dof_in++)
735 res += d_interp(dof_out, dof_in, interp_index)*dof_values[dof_in];
737 d_y(dof_out, c, face) = res;
754 if (
nf==0) {
return; }
773 MFEM_ABORT(
"Unknown type and multiplicity combination.");
779 if (
nf==0) {
return; }
808 if (
nf==0) {
return; }
836 const bool keep_nbr_block)
const
838 MFEM_ABORT(
"Not yet implemented.");
844 MFEM_ABORT(
"Not yet implemented.");
849 const bool keep_nbr_block)
const
851 MFEM_ABORT(
"Not yet implemented.");
858 MFEM_ABORT(
"Not yet implemented.");
861 void ParNCL2FaceRestriction::ComputeScatterIndicesAndOffsets(
868 for (
int i = 0; i <=
ndofs; ++i)
878 if ( face.IsNonconformingCoarse() )
886 if ( face.IsConforming() )
892 if ( face.IsShared() )
908 if ( face.IsShared() )
930 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
932 " faces: " << f_ind <<
" vs " <<
nf );
935 for (
int i = 1; i <=
ndofs; ++i)
945 void ParNCL2FaceRestriction::ComputeGatherIndices(
953 for (
int f = 0;
f < mesh.GetNumFacesWithGhost(); ++
f)
956 if ( face.IsNonconformingCoarse() )
962 else if ( face.IsOfFaceType(type) )
974 MFEM_VERIFY(f_ind==
nf,
"Unexpected number of " <<
976 " faces: " << f_ind <<
" vs " <<
nf );
979 for (
int i =
ndofs; i > 0; --i)
void DoubleValuedNonconformingTransposeInterpolationInPlace(Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
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 Mult(const Vector &x, Vector &y) const override
Scatter the degrees of freedom, i.e. goes from L-Vector to face E-Vector.
FaceInformation GetFaceInformation(int f) const
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 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.
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)
InterpolationManager interpolations
int Size() const
Returns the size of the vector.
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
const Array< NCInterpConfig > & GetNCFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
Abstract parallel finite element space.
void SetFaceDofsGatherIndices1(const Mesh::FaceInformation &face, const int face_index)
Set the gathering indices of elem1 for the interior face described by the face.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
void DoubleValuedNonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
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 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...
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...
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void AddMultTransposeInPlace(Vector &x, Vector &y) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
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 ...
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...
Mesh * GetMesh() const
Returns the mesh.
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)
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
void FillJAndData(const Vector &fea_data, SparseMatrix &mat, SparseMatrix &face_mat) const
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
uint32_t is_non_conforming
Array< int > gather_offsets
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...
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...
int GetNumInterpolators() const
Return the total number of interpolators.
int * WriteJ(bool on_dev=true)
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...
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).
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
int GetFaceNbrVSize() const
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 SingleValuedNonconformingTransposeInterpolationInPlace(Vector &x) const
Apply a change of basis from fine element basis to coarse element basis for the coarse face dofs...
void DoubleValuedNonconformingTransposeInterpolation(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 &ea_data, SparseMatrix &mat, SparseMatrix &face_mat) const
void NonconformingInterpolation(Vector &x) const
Apply a change of basis from coarse element basis to fine element basis for the coarse face dofs...
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 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.
uint32_t is_non_conforming
const Array< InterpConfig > & GetFaceInterpConfig() const
Return an array containing the interpolation configuration for each face registered with RegisterFace...
void AddMultTranspose(const Vector &x, Vector &y) const override
Gather the degrees of freedom, i.e. goes from face E-Vector to L-Vector.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
InterpolationManager interpolations
void FillI(SparseMatrix &mat, const bool keep_nbr_block=false) const override
Array< int > scatter_indices2
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...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
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...
const Vector & GetInterpolators() const
Return an mfem::Vector containing the interpolators in the following format: face_dofs x face_dofs x ...