28template <
typename T1,
typename T2>
32 if (integs == NULL) {
return false; }
33 if (integs->
Size() == 1)
36 if (
dynamic_cast<T1*
>(i0) ||
dynamic_cast<T2*
>(i0)) {
return true; }
38 else if (integs->
Size() == 2)
42 if ((
dynamic_cast<T1*
>(i0) &&
dynamic_cast<T2*
>(i1)) ||
43 (
dynamic_cast<T2*
>(i0) &&
dynamic_cast<T1*
>(i1)))
86 const int nel_ho = mesh_ho.
GetNE();
88 const int nd1d = dg ? order + 2 : order + 1;
89 const int ndof_per_el =
static_cast<int>(pow(nd1d,
dim));
98 nodal_restriction->
Mult(*nodal_gf, nodal_evec);
115static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int n_my_elts,
116 const int *nbr_elts,
const int n_nbr_elts)
118 int min_el = INT_MAX;
119 for (
int i = 0; i < n_my_elts; i++)
121 const int e_i = my_elts[i];
122 if (e_i >= min_el) {
continue; }
123 for (
int j = 0; j < n_nbr_elts; j++)
125 if (e_i==nbr_elts[j])
137static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
145 static constexpr int Max = 16;
157 MFEM_VERIFY(el_restr !=
nullptr,
"Bad element restriction");
163 const auto el_dof_lex =
Reshape(el_dof_lex_.
Read(), ndof_per_el, nel_ho);
164 const auto dof_glob2loc = dof_glob2loc_.
Read();
165 const auto K = dof_glob2loc_offsets_.
Read();
171 mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (
int ii) { I[ii] = 0; });
172 mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (
int i)
174 const int ii_el = i%ndof_per_el;
175 const int iel_ho = i/ndof_per_el;
176 const int sii = el_dof_lex(ii_el, iel_ho);
177 const int ii = (sii >= 0) ? sii : -1 -sii;
180 const int i_offset = K[ii];
181 const int i_next_offset = K[ii+1];
182 const int i_ne = i_next_offset - i_offset;
183 for (
int e_i = 0; e_i < i_ne; ++e_i)
185 const int si_E = dof_glob2loc[i_offset+e_i];
186 const int i_E = (si_E >= 0) ? si_E : -1 - si_E;
187 i_elts[e_i] = i_E/ndof_per_el;
189 for (
int j = 0; j < nnz_per_row; ++j)
191 int jj_el = map(j, ii_el);
192 if (jj_el < 0) {
continue; }
194 const int sjj = el_dof_lex(jj_el, iel_ho);
195 const int jj = (sjj >= 0) ? sjj : -1 - sjj;
196 const int j_offset = K[jj];
197 const int j_next_offset = K[jj+1];
198 const int j_ne = j_next_offset - j_offset;
199 if (i_ne == 1 || j_ne == 1)
206 for (
int e_j = 0; e_j < j_ne; ++e_j)
208 const int sj_E = dof_glob2loc[j_offset+e_j];
209 const int j_E = (sj_E >= 0) ? sj_E : -1 - sj_E;
210 const int elt = j_E/ndof_per_el;
213 const int min_e = GetMinElt(i_elts, i_ne, j_elts, j_ne);
225 for (
int i = 0; i < nvdof; i++)
227 const int nnz = h_I[i];
248 MFEM_VERIFY(el_restr !=
nullptr,
"Bad element restriction");
254 const auto el_dof_lex =
Reshape(el_dof_lex_.
Read(), ndof_per_el, nel_ho);
255 const auto dof_glob2loc = dof_glob2loc_.
Read();
256 const auto K = dof_glob2loc_offsets_.
Read();
262 const auto I = I_.
Write();
263 const auto J = A.
WriteJ();
268 const auto I2 = A.
ReadI();
269 mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (
int i) { I[i] = I2[i]; });
272 static constexpr int Max = 16;
274 mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (
int i)
276 const int ii_el = i%ndof_per_el;
277 const int iel_ho = i/ndof_per_el;
279 const int sii = el_dof_lex(ii_el, iel_ho);
280 const int ii = (sii >= 0) ? sii : -1 - sii;
284 const int i_offset = K[ii];
285 const int i_next_offset = K[ii+1];
286 const int i_ne = i_next_offset - i_offset;
287 for (
int e_i = 0; e_i < i_ne; ++e_i)
289 const int si_E = dof_glob2loc[i_offset+e_i];
290 const bool plus = si_E >= 0;
291 const int i_E = plus ? si_E : -1 - si_E;
292 i_elts[e_i] = i_E/ndof_per_el;
293 const int i_Bi = i_E % ndof_per_el;
294 i_B[e_i] = plus ? i_Bi : -1 - i_Bi;
296 for (
int j=0; j<nnz_per_row; ++j)
298 int jj_el = map(j, ii_el);
299 if (jj_el < 0) {
continue; }
301 const int sjj = el_dof_lex(jj_el, iel_ho);
302 const int jj = (sjj >= 0) ? sjj : -1 - sjj;
303 const int sgn = ((sjj >=0 && sii >= 0) || (sjj < 0 && sii <0)) ? 1 : -1;
304 const int j_offset = K[jj];
305 const int j_next_offset = K[jj+1];
306 const int j_ne = j_next_offset - j_offset;
307 if (i_ne == 1 || j_ne == 1)
309 const int nnz = GetAndIncrementNnzIndex(ii, I);
311 AV[nnz] = sgn*V(j, ii_el, iel_ho);
317 for (
int e_j = 0; e_j < j_ne; ++e_j)
319 const int sj_E = dof_glob2loc[j_offset+e_j];
320 const bool plus = sj_E >= 0;
321 const int j_E = plus ? sj_E : -1 - sj_E;
322 j_elts[e_j] = j_E/ndof_per_el;
323 const int j_Bj = j_E % ndof_per_el;
324 j_B[e_j] = plus ? j_Bj : -1 - j_Bj;
326 const int min_e = GetMinElt(i_elts, i_ne, j_elts, j_ne);
330 for (
int k = 0; k < i_ne; k++)
332 const int iel_ho_2 = i_elts[k];
333 const int sii_el_2 = i_B[k];
334 const int ii_el_2 = (sii_el_2 >= 0) ? sii_el_2 : -1 -sii_el_2;
335 for (
int l = 0; l < j_ne; l++)
337 const int jel_ho_2 = j_elts[l];
338 if (iel_ho_2 == jel_ho_2)
340 const int sjj_el_2 = j_B[l];
341 const int jj_el_2 = (sjj_el_2 >= 0) ? sjj_el_2 : -1 -sjj_el_2;
342 const int sgn_2 = ((sjj_el_2 >=0 && sii_el_2 >= 0)
343 || (sjj_el_2 < 0 && sii_el_2 <0)) ? 1 : -1;
346 for (
int m = 0; m < nnz_per_row; ++m)
348 if (map(m, ii_el_2) == jj_el_2)
354 MFEM_ASSERT_KERNEL(j >= 0,
"Can't find nonzero");
355 val += sgn_2*V(j2, ii_el_2, iel_ho_2);
359 const int nnz = GetAndIncrementNnzIndex(ii, I);
374 const int nrows = nel_ho*ndof_per_el;
376 const int pp1 =
p + 1;
377 const int nnz = nrows*nnz_per_row;
379 const int face_nbr_vsize = [&]()
384 return par_fes->GetFaceNbrVSize();
411 for (
int f = 0;
f < num_faces;
f++)
418 h_nbr_info(e0,f0,0) = -1;
419 h_nbr_info(e0,f0,1)= -1;
420 h_nbr_info(e0,f0,2)= -1;
433 h_nbr_info(e0,f0,0) = e1;
435 h_nbr_info(e0,f0,2)= f1;
436 h_nbr_info(e1,f1,0) = e0;
438 h_nbr_info(e1,f1,2) = f0;
444 for (
int i = 0; i < nrows; ++i)
446 const int iel_ho = i / ndof_per_el;
447 const int iloc = i % ndof_per_el;
448 static const int lex_map_2[4] = {3, 1, 0, 2};
449 static const int lex_map_3[6] = {4, 2, 1, 3, 0, 5};
450 const int local_i[3] = {iloc % pp1, (iloc/pp1)%pp1, iloc/pp1/pp1};
452 for (
int n_idx = 0; n_idx <
dim; ++n_idx)
454 for (
int e_i = 0; e_i < 2; ++e_i)
456 const int j_lex = e_i + n_idx*2;
457 const int f = (
dim == 3) ? lex_map_3[j_lex]:lex_map_2[j_lex];
458 const bool boundary = (local_i[n_idx] == e_i *
p);
461 int neighbor_idx = h_nbr_info(iel_ho,
f, 0);
462 if (neighbor_idx == -1)
469 h_I[i+1] = h_I[i] + (nnz_per_row - bdr_count);
475 auto I = A_mat->
ReadI();
480 const int e = i / ndof_per_el;
481 const int iloc = i % ndof_per_el;
482 const int local_x = iloc % pp1;
483 const int local_y = (iloc/pp1)%pp1;
484 const int local_z = iloc/pp1/pp1;
485 const int local_i[3] = {local_x, local_y, local_z};
487 static const int lex_map_2[4] = {3, 1, 0, 2};
488 static const int lex_map_3[6] = {4,2,1,3,0,5};
489 const int *lex_map = (
dim == 2) ? lex_map_2 : lex_map_3;
490 AV[offset] = V(0, iloc, e);
493 for (
int n_idx = 0; n_idx <
dim; ++n_idx)
499 for (
int d = 0; d <
dim; ++d)
503 qi += local_i[d]*stride;
507 for (
int e_i = 0; e_i < 2; ++e_i)
509 const int j_lex = e_i + n_idx*2;
510 const int f = lex_map[j_lex];
511 const bool bdr = (local_i[n_idx] == e_i *
p);
514 const int nbr_e = d_nbr_info(e,
f, 0);
515 const int nbr_ori = d_nbr_info(e,
f, 1);
516 const int nbr_f = d_nbr_info(e,
f, 2);
519 const int nbr_loc_idx = internal::FaceIdxToVolIdx(
520 dim, qi, pp1,
f, nbr_f, 1, nbr_ori);
521 J[offset] = nbr_e*ndof_per_el + nbr_loc_idx;
522 AV[offset] = V(
f+1, iloc, e);
528 int shift = (e_i == 0) ? -1 : 1;
529 for (
int n = 0; n < n_idx; ++n) { shift *= pp1; }
530 J[offset] = i + shift;
531 AV[offset] = V(
f+1, iloc, e);
555 const int nnz =
FillI(*A_mat);
561template <
int ORDER,
int SDIM,
typename LOR_KERNEL>
562static void Assemble_(LOR_KERNEL &kernel,
int dim)
564 if (
dim == 2) { kernel.template Assemble2D<ORDER,SDIM>(); }
565 else if (
dim == 3) { kernel.template Assemble3D<ORDER>(); }
566 else { MFEM_ABORT(
"Unsupported dimension"); }
569template <
int ORDER,
typename LOR_KERNEL>
570static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim)
572 if (sdim == 2) { Assemble_<ORDER,2>(kernel,
dim); }
573 else if (sdim == 3) { Assemble_<ORDER,3>(kernel,
dim); }
574 else { MFEM_ABORT(
"Unsupported space dimension."); }
577template <
typename LOR_KERNEL>
578static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim,
int order)
582 case 1: Assemble_<1>(kernel,
dim, sdim);
break;
583 case 2: Assemble_<2>(kernel,
dim, sdim);
break;
584 case 3: Assemble_<3>(kernel,
dim, sdim);
break;
585 case 4: Assemble_<4>(kernel,
dim, sdim);
break;
586 case 5: Assemble_<5>(kernel,
dim, sdim);
break;
587 case 6: Assemble_<6>(kernel,
dim, sdim);
break;
588 case 7: Assemble_<7>(kernel,
dim, sdim);
break;
589 case 8: Assemble_<8>(kernel,
dim, sdim);
break;
590 default: MFEM_ABORT(
"No kernel order " << order <<
"!");
594template <
typename LOR_KERNEL>
603 Assemble_(kernel,
dim, sdim, order);
656 const int lvsize = par_fes.
GetVSize();
658 par_fes.GetFaceNbrGlobalDofMapArray();
659 const HYPRE_BigInt ldof_offset = par_fes.GetMyDofOffset();
665 const int *d_J = A_local.
ReadJ();
672 d_glob_J[i] = d_J[i] + ldof_offset;
676 d_glob_J[i] = d_face_nbr_glob_ldof[d_J[i] - lvsize];
681 par_fes.GetComm(), lvsize, par_fes.GlobalVSize(),
684 par_fes.GetDofOffsets(), par_fes.GetDofOffsets()));
724 std::unique_ptr<SparseMatrix> R(
Transpose(*P));
742 return irs.
Get(geom, 2*nd1d - 3);
MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
int Size() const
Return the logical size of the array.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
void FillJAndData(SparseMatrix &A) const
Fill the J and data arrays of the sparse matrix A.
void SparseIJToCSR(OperatorHandle &A) const
After assembling the "sparse IJ" format, convert it to CSR.
void AssemblyKernel(BilinearForm &a)
Fill in sparse_ij and sparse_mapping using one of the specialized LOR assembly kernel classes.
Array< int > sparse_mapping
The sparsity pattern of the element matrices.
void AssembleWithoutBC(BilinearForm &a, OperatorHandle &A)
Assemble the system without eliminating essential DOFs.
Vector X_vert
LOR vertex coordinates.
void ParAssemble_DG(SparseMatrix &A_local, OperatorHandle &A)
Assemble the parallel DG matrix (with shared faces).
Vector sparse_ij
The elementwise LOR matrices in a sparse "ij" format.
static void FormLORVertexCoordinates(FiniteElementSpace &fes_ho, Vector &X_vert)
Compute the vertices of the LOR mesh and place the result in X_vert.
void ParAssemble(BilinearForm &a, const Array< int > &ess_dofs, OperatorHandle &A)
Assemble the system in parallel and place the result in A.
static bool FormIsSupported(BilinearForm &a)
Returns true if the form a supports batched assembly, false otherwise.
FiniteElementSpace & fes_ho
The high-order space.
BatchedLORAssembly(FiniteElementSpace &fes_ho_)
Construct the batched assembly object corresponding to fes_ho_.
void Assemble(BilinearForm &a, const Array< int > ess_dofs, OperatorHandle &A)
Assemble the given form as a matrix and place the result in A.
int FillI(SparseMatrix &A) const
Fill the I array of the sparse matrix A.
void SparseIJToCSR_DG(OperatorHandle &A) const
Specialized implementation of SparseIJToCSR for DG spaces.
Operator that converts FiniteElementSpace L-vectors to E-vectors.
const Array< int > & GatherMap() const
const Array< int > & Offsets() const
const Array< int > & Indices() const
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int GetNE() const
Returns number of elements in the mesh.
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
const SparseMatrix * GetConformingProlongation() const
const FiniteElementCollection * FEColl() const
Mesh * GetMesh() const
Returns the mesh.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Class for grid function - Vector with associated FE space.
FiniteElementSpace * FESpace()
Arbitrary order H1-conforming (continuous) finite elements.
Wrapper for hypre's ParCSR matrix class.
Class for an integration rule - an Array of IntegrationPoint.
Container class for integration rules.
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Arbitrary order "L2-conforming" discontinuous finite elements.
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
int GetNE() const
Returns number of elements.
int Dimension() const
Dimension of the reference space used within the elements.
FaceInformation GetFaceInformation(int f) const
int SpaceDimension() const
Dimension of the physical space containing the mesh.
void GetNodes(Vector &node_coord) const
Geometry::Type GetTypicalFaceGeometry() const
If the local mesh is not empty, return GetFaceGeometry(0); otherwise return a typical face geometry p...
Arbitrary order H(curl)-conforming Nedelec finite elements.
Pointer to an Operator of a specified type.
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
OpType * Is() const
Return the Operator pointer dynamically cast to a specified OpType.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
@ DIAG_ONE
Set the diagonal value to one.
@ DIAG_KEEP
Keep the diagonal value.
Abstract parallel finite element space.
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
void Values(const Vector &e_vec, Vector &q_val) const
Interpolate the values of the E-vector e_vec at quadrature points.
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
int * WriteJ(bool on_dev=true)
Memory< int > & GetMemoryI()
const int * ReadI(bool on_dev=true) const
int * WriteI(bool on_dev=true)
real_t * HostReadWriteData()
const int * ReadJ(bool on_dev=true) const
void OverrideSize(int height_, int width_)
Sets the height and width of the matrix.
Memory< int > & GetMemoryJ()
Memory< real_t > & GetMemoryData()
real_t * WriteData(bool on_dev=true)
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
void EnsureCapacity(Memory< T > &mem, int capacity)
Ensure that mem has at least capacity capacity.
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
bool HasIntegrators(BilinearForm &a)
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
IntegrationRule GetLobattoIntRule(Geometry::Type geom, int nd1d)
Return the Gauss-Lobatto rule for geometry geom with nd1d points per dimension.
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
void EliminateBC(const HypreParMatrix &A, const HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Eliminate essential BC specified by ess_dof_list from the solution X to the r.h.s....
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes)
Return the Gauss-Lobatto rule collocated with the element nodes.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
void forall(int N, lambda &&body)
IntegrationRule GetCollocatedFaceIntRule(FiniteElementSpace &fes)
Return the Gauss-Lobatto rule collocated with face nodes.
real_t p(const Vector &x, real_t t)