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)
155 MFEM_VERIFY(el_restr !=
nullptr,
"Bad element restriction");
161 const auto el_dof_lex =
Reshape(el_dof_lex_.
Read(), ndof_per_el, nel_ho);
162 const auto dof_glob2loc = dof_glob2loc_.
Read();
163 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;
179 const int i_offset = K[ii];
180 const int i_next_offset = K[ii+1];
181 const int i_ne = i_next_offset - i_offset;
182 int *i_elts = &d_ij_elts(i_offset, 0);
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)
205 int *j_elts = &d_ij_elts(j_offset, 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]; });
275 mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (
int i)
277 const int ii_el = i%ndof_per_el;
278 const int iel_ho = i/ndof_per_el;
280 const int sii = el_dof_lex(ii_el, iel_ho);
281 const int ii = (sii >= 0) ? sii : -1 - sii;
283 const int i_offset = K[ii];
284 const int i_next_offset = K[ii+1];
285 const int i_ne = i_next_offset - i_offset;
287 int *i_elts = &d_ij_B_el(i_offset, 0);
288 int *i_B = &d_ij_B_el(i_offset, 1);
290 for (
int e_i = 0; e_i < i_ne; ++e_i)
292 const int si_E = dof_glob2loc[i_offset+e_i];
293 const bool plus = si_E >= 0;
294 const int i_E = plus ? si_E : -1 - si_E;
295 i_elts[e_i] = i_E/ndof_per_el;
296 const int i_Bi = i_E % ndof_per_el;
297 i_B[e_i] = plus ? i_Bi : -1 - i_Bi;
299 for (
int j=0; j<nnz_per_row; ++j)
301 int jj_el = map(j, ii_el);
302 if (jj_el < 0) {
continue; }
304 const int sjj = el_dof_lex(jj_el, iel_ho);
305 const int jj = (sjj >= 0) ? sjj : -1 - sjj;
306 const int sgn = ((sjj >=0 && sii >= 0) || (sjj < 0 && sii <0)) ? 1 : -1;
307 const int j_offset = K[jj];
308 const int j_next_offset = K[jj+1];
309 const int j_ne = j_next_offset - j_offset;
310 if (i_ne == 1 || j_ne == 1)
312 const int nnz = GetAndIncrementNnzIndex(ii, I);
314 AV[nnz] = sgn*V(j, ii_el, iel_ho);
318 int *j_elts = &d_ij_B_el(j_offset, 2);
319 int *j_B = &d_ij_B_el(j_offset, 3);
320 for (
int e_j = 0; e_j < j_ne; ++e_j)
322 const int sj_E = dof_glob2loc[j_offset+e_j];
323 const bool plus = sj_E >= 0;
324 const int j_E = plus ? sj_E : -1 - sj_E;
325 j_elts[e_j] = j_E/ndof_per_el;
326 const int j_Bj = j_E % ndof_per_el;
327 j_B[e_j] = plus ? j_Bj : -1 - j_Bj;
329 const int min_e = GetMinElt(i_elts, i_ne, j_elts, j_ne);
333 for (
int k = 0; k < i_ne; k++)
335 const int iel_ho_2 = i_elts[k];
336 const int sii_el_2 = i_B[k];
337 const int ii_el_2 = (sii_el_2 >= 0) ? sii_el_2 : -1 -sii_el_2;
338 for (
int l = 0; l < j_ne; l++)
340 const int jel_ho_2 = j_elts[l];
341 if (iel_ho_2 == jel_ho_2)
343 const int sjj_el_2 = j_B[l];
344 const int jj_el_2 = (sjj_el_2 >= 0) ? sjj_el_2 : -1 -sjj_el_2;
345 const int sgn_2 = ((sjj_el_2 >=0 && sii_el_2 >= 0)
346 || (sjj_el_2 < 0 && sii_el_2 <0)) ? 1 : -1;
349 for (
int m = 0; m < nnz_per_row; ++m)
351 if (map(m, ii_el_2) == jj_el_2)
357 MFEM_ASSERT_KERNEL(j >= 0,
"Can't find nonzero");
358 val += sgn_2*V(j2, ii_el_2, iel_ho_2);
362 const int nnz = GetAndIncrementNnzIndex(ii, I);
377 const int nrows = nel_ho*ndof_per_el;
379 const int pp1 =
p + 1;
380 const int nnz = nrows*nnz_per_row;
382 const int face_nbr_vsize = [&]()
387 return par_fes->GetFaceNbrVSize();
414 for (
int f = 0;
f < num_faces;
f++)
421 h_nbr_info(e0,f0,0) = -1;
422 h_nbr_info(e0,f0,1)= -1;
423 h_nbr_info(e0,f0,2)= -1;
436 h_nbr_info(e0,f0,0) = e1;
438 h_nbr_info(e0,f0,2)= f1;
439 h_nbr_info(e1,f1,0) = e0;
441 h_nbr_info(e1,f1,2) = f0;
447 for (
int i = 0; i < nrows; ++i)
449 const int iel_ho = i / ndof_per_el;
450 const int iloc = i % ndof_per_el;
451 static const int lex_map_2[4] = {3, 1, 0, 2};
452 static const int lex_map_3[6] = {4, 2, 1, 3, 0, 5};
453 const int local_i[3] = {iloc % pp1, (iloc/pp1)%pp1, iloc/pp1/pp1};
455 for (
int n_idx = 0; n_idx <
dim; ++n_idx)
457 for (
int e_i = 0; e_i < 2; ++e_i)
459 const int j_lex = e_i + n_idx*2;
460 const int f = (
dim == 3) ? lex_map_3[j_lex]:lex_map_2[j_lex];
461 const bool boundary = (local_i[n_idx] == e_i *
p);
464 int neighbor_idx = h_nbr_info(iel_ho,
f, 0);
465 if (neighbor_idx == -1)
472 h_I[i+1] = h_I[i] + (nnz_per_row - bdr_count);
478 auto I = A_mat->
ReadI();
483 const int e = i / ndof_per_el;
484 const int iloc = i % ndof_per_el;
485 const int local_x = iloc % pp1;
486 const int local_y = (iloc/pp1)%pp1;
487 const int local_z = iloc/pp1/pp1;
488 const int local_i[3] = {local_x, local_y, local_z};
490 static const int lex_map_2[4] = {3, 1, 0, 2};
491 static const int lex_map_3[6] = {4,2,1,3,0,5};
492 const int *lex_map = (
dim == 2) ? lex_map_2 : lex_map_3;
493 AV[offset] = V(0, iloc, e);
496 for (
int n_idx = 0; n_idx <
dim; ++n_idx)
502 for (
int d = 0; d <
dim; ++d)
506 qi += local_i[d]*stride;
510 for (
int e_i = 0; e_i < 2; ++e_i)
512 const int j_lex = e_i + n_idx*2;
513 const int f = lex_map[j_lex];
514 const bool bdr = (local_i[n_idx] == e_i *
p);
517 const int nbr_e = d_nbr_info(e,
f, 0);
518 const int nbr_ori = d_nbr_info(e,
f, 1);
519 const int nbr_f = d_nbr_info(e,
f, 2);
522 const int nbr_loc_idx = internal::FaceIdxToVolIdx(
523 dim, qi, pp1,
f, nbr_f, 1, nbr_ori);
524 J[offset] = nbr_e*ndof_per_el + nbr_loc_idx;
525 AV[offset] = V(
f+1, iloc, e);
531 int shift = (e_i == 0) ? -1 : 1;
532 for (
int n = 0; n < n_idx; ++n) { shift *= pp1; }
533 J[offset] = i + shift;
534 AV[offset] = V(
f+1, iloc, e);
558 const int nnz =
FillI(*A_mat);
564template <
int ORDER,
int SDIM,
typename LOR_KERNEL>
565static void Assemble_(LOR_KERNEL &kernel,
int dim)
567 if (
dim == 2) { kernel.template Assemble2D<ORDER,SDIM>(); }
568 else if (
dim == 3) { kernel.template Assemble3D<ORDER>(); }
569 else { MFEM_ABORT(
"Unsupported dimension"); }
572template <
int ORDER,
typename LOR_KERNEL>
573static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim)
575 if (sdim == 2) { Assemble_<ORDER,2>(kernel,
dim); }
576 else if (sdim == 3) { Assemble_<ORDER,3>(kernel,
dim); }
577 else { MFEM_ABORT(
"Unsupported space dimension."); }
580template <
typename LOR_KERNEL>
581static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim,
int order)
585 case 1: Assemble_<1>(kernel,
dim, sdim);
break;
586 case 2: Assemble_<2>(kernel,
dim, sdim);
break;
587 case 3: Assemble_<3>(kernel,
dim, sdim);
break;
588 case 4: Assemble_<4>(kernel,
dim, sdim);
break;
589 case 5: Assemble_<5>(kernel,
dim, sdim);
break;
590 case 6: Assemble_<6>(kernel,
dim, sdim);
break;
591 case 7: Assemble_<7>(kernel,
dim, sdim);
break;
592 case 8: Assemble_<8>(kernel,
dim, sdim);
break;
593 default: MFEM_ABORT(
"No kernel order " << order <<
"!");
597template <
typename LOR_KERNEL>
606 Assemble_(kernel,
dim, sdim, order);
659 const int lvsize = par_fes.
GetVSize();
661 par_fes.GetFaceNbrGlobalDofMapArray();
662 const HYPRE_BigInt ldof_offset = par_fes.GetMyDofOffset();
668 const int *d_J = A_local.
ReadJ();
675 d_glob_J[i] = d_J[i] + ldof_offset;
679 d_glob_J[i] = d_face_nbr_glob_ldof[d_J[i] - lvsize];
684 par_fes.GetComm(), lvsize, par_fes.GlobalVSize(),
687 par_fes.GetDofOffsets(), par_fes.GetDofOffsets()));
727 std::unique_ptr<SparseMatrix> R(
Transpose(*P));
745 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)