26template <
typename T1,
typename T2>
30 if (integs == NULL) {
return false; }
31 if (integs->
Size() == 1)
34 if (
dynamic_cast<T1*
>(i0) ||
dynamic_cast<T2*
>(i0)) {
return true; }
36 else if (integs->
Size() == 2)
40 if ((
dynamic_cast<T1*
>(i0) &&
dynamic_cast<T2*
>(i1)) ||
41 (
dynamic_cast<T2*
>(i0) &&
dynamic_cast<T1*
>(i1)))
81 const int nel_ho = mesh_ho.
GetNE();
83 const int nd1d = order + 1;
84 const int ndof_per_el =
static_cast<int>(pow(nd1d,
dim));
93 nodal_restriction->
Mult(*nodal_gf, nodal_evec);
109static MFEM_HOST_DEVICE
int GetMinElt(
const int *my_elts,
const int n_my_elts,
110 const int *nbr_elts,
const int n_nbr_elts)
112 int min_el = INT_MAX;
113 for (
int i = 0; i < n_my_elts; i++)
115 const int e_i = my_elts[i];
116 if (e_i >= min_el) {
continue; }
117 for (
int j = 0; j < n_nbr_elts; j++)
119 if (e_i==nbr_elts[j])
131static MFEM_HOST_DEVICE
int GetAndIncrementNnzIndex(
const int i_L,
int* I)
139 static constexpr int Max = 16;
151 MFEM_VERIFY(el_restr !=
nullptr,
"Bad element restriction");
157 const auto el_dof_lex =
Reshape(el_dof_lex_.
Read(), ndof_per_el, nel_ho);
158 const auto dof_glob2loc = dof_glob2loc_.
Read();
159 const auto K = dof_glob2loc_offsets_.
Read();
164 mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (
int ii) { I[ii] = 0; });
165 mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (
int i)
167 const int ii_el = i%ndof_per_el;
168 const int iel_ho = i/ndof_per_el;
169 const int sii = el_dof_lex(ii_el, iel_ho);
170 const int ii = (sii >= 0) ? sii : -1 -sii;
173 const int i_offset = K[ii];
174 const int i_next_offset = K[ii+1];
175 const int i_ne = i_next_offset - i_offset;
176 for (
int e_i = 0; e_i < i_ne; ++e_i)
178 const int si_E = dof_glob2loc[i_offset+e_i];
179 const int i_E = (si_E >= 0) ? si_E : -1 - si_E;
180 i_elts[e_i] = i_E/ndof_per_el;
182 for (
int j = 0; j < nnz_per_row; ++j)
184 int jj_el = map(j, ii_el);
185 if (jj_el < 0) {
continue; }
187 const int sjj = el_dof_lex(jj_el, iel_ho);
188 const int jj = (sjj >= 0) ? sjj : -1 - sjj;
189 const int j_offset = K[jj];
190 const int j_next_offset = K[jj+1];
191 const int j_ne = j_next_offset - j_offset;
192 if (i_ne == 1 || j_ne == 1)
199 for (
int e_j = 0; e_j < j_ne; ++e_j)
201 const int sj_E = dof_glob2loc[j_offset+e_j];
202 const int j_E = (sj_E >= 0) ? sj_E : -1 - sj_E;
203 const int elt = j_E/ndof_per_el;
206 const int min_e = GetMinElt(i_elts, i_ne, j_elts, j_ne);
218 for (
int i = 0; i < nvdof; i++)
220 const int nnz = h_I[i];
241 MFEM_VERIFY(el_restr !=
nullptr,
"Bad element restriction");
247 const auto el_dof_lex =
Reshape(el_dof_lex_.
Read(), ndof_per_el, nel_ho);
248 const auto dof_glob2loc = dof_glob2loc_.
Read();
249 const auto K = dof_glob2loc_offsets_.
Read();
255 const auto I = I_.
Write();
256 const auto J = A.
WriteJ();
261 const auto I2 = A.
ReadI();
262 mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (
int i) { I[i] = I2[i]; });
265 static constexpr int Max = 16;
267 mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (
int i)
269 const int ii_el = i%ndof_per_el;
270 const int iel_ho = i/ndof_per_el;
272 const int sii = el_dof_lex(ii_el, iel_ho);
273 const int ii = (sii >= 0) ? sii : -1 - sii;
277 const int i_offset = K[ii];
278 const int i_next_offset = K[ii+1];
279 const int i_ne = i_next_offset - i_offset;
280 for (
int e_i = 0; e_i < i_ne; ++e_i)
282 const int si_E = dof_glob2loc[i_offset+e_i];
283 const bool plus = si_E >= 0;
284 const int i_E = plus ? si_E : -1 - si_E;
285 i_elts[e_i] = i_E/ndof_per_el;
286 const int i_Bi = i_E % ndof_per_el;
287 i_B[e_i] = plus ? i_Bi : -1 - i_Bi;
289 for (
int j=0; j<nnz_per_row; ++j)
291 int jj_el = map(j, ii_el);
292 if (jj_el < 0) {
continue; }
294 const int sjj = el_dof_lex(jj_el, iel_ho);
295 const int jj = (sjj >= 0) ? sjj : -1 - sjj;
296 const int sgn = ((sjj >=0 && sii >= 0) || (sjj < 0 && sii <0)) ? 1 : -1;
297 const int j_offset = K[jj];
298 const int j_next_offset = K[jj+1];
299 const int j_ne = j_next_offset - j_offset;
300 if (i_ne == 1 || j_ne == 1)
302 const int nnz = GetAndIncrementNnzIndex(ii, I);
304 AV[nnz] = sgn*V(j, ii_el, iel_ho);
310 for (
int e_j = 0; e_j < j_ne; ++e_j)
312 const int sj_E = dof_glob2loc[j_offset+e_j];
313 const bool plus = sj_E >= 0;
314 const int j_E = plus ? sj_E : -1 - sj_E;
315 j_elts[e_j] = j_E/ndof_per_el;
316 const int j_Bj = j_E % ndof_per_el;
317 j_B[e_j] = plus ? j_Bj : -1 - j_Bj;
319 const int min_e = GetMinElt(i_elts, i_ne, j_elts, j_ne);
323 for (
int k = 0; k < i_ne; k++)
325 const int iel_ho_2 = i_elts[k];
326 const int sii_el_2 = i_B[k];
327 const int ii_el_2 = (sii_el_2 >= 0) ? sii_el_2 : -1 -sii_el_2;
328 for (
int l = 0; l < j_ne; l++)
330 const int jel_ho_2 = j_elts[l];
331 if (iel_ho_2 == jel_ho_2)
333 const int sjj_el_2 = j_B[l];
334 const int jj_el_2 = (sjj_el_2 >= 0) ? sjj_el_2 : -1 -sjj_el_2;
335 const int sgn_2 = ((sjj_el_2 >=0 && sii_el_2 >= 0)
336 || (sjj_el_2 < 0 && sii_el_2 <0)) ? 1 : -1;
339 for (
int m = 0; m < nnz_per_row; ++m)
341 if (map(m, ii_el_2) == jj_el_2)
347 MFEM_ASSERT_KERNEL(j >= 0,
"Can't find nonzero");
348 val += sgn_2*V(j2, ii_el_2, iel_ho_2);
352 const int nnz = GetAndIncrementNnzIndex(ii, I);
377 int nnz =
FillI(*A_mat);
384template <
int ORDER,
int SDIM,
typename LOR_KERNEL>
385static void Assemble_(LOR_KERNEL &kernel,
int dim)
387 if (
dim == 2) { kernel.template Assemble2D<ORDER,SDIM>(); }
388 else if (
dim == 3) { kernel.template Assemble3D<ORDER>(); }
389 else { MFEM_ABORT(
"Unsupported dimension"); }
392template <
int ORDER,
typename LOR_KERNEL>
393static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim)
395 if (sdim == 2) { Assemble_<ORDER,2>(kernel,
dim); }
396 else if (sdim == 3) { Assemble_<ORDER,3>(kernel,
dim); }
397 else { MFEM_ABORT(
"Unsupported space dimension."); }
400template <
typename LOR_KERNEL>
401static void Assemble_(LOR_KERNEL &kernel,
int dim,
int sdim,
int order)
405 case 1: Assemble_<1>(kernel,
dim, sdim);
break;
406 case 2: Assemble_<2>(kernel,
dim, sdim);
break;
407 case 3: Assemble_<3>(kernel,
dim, sdim);
break;
408 case 4: Assemble_<4>(kernel,
dim, sdim);
break;
409 case 5: Assemble_<5>(kernel,
dim, sdim);
break;
410 case 6: Assemble_<6>(kernel,
dim, sdim);
break;
411 case 7: Assemble_<7>(kernel,
dim, sdim);
break;
412 case 8: Assemble_<8>(kernel,
dim, sdim);
break;
413 default: MFEM_ABORT(
"No kernel order " << order <<
"!");
417template <
typename LOR_KERNEL>
426 Assemble_(kernel,
dim, sdim, order);
505 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).
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.
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.
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
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 FiniteElementCollection * FEColl() const
Mesh * GetMesh() const
Returns the mesh.
int GetMaxElementOrder() const
Return the maximum polynomial order.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
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.
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
Geometry::Type GetElementGeometry(int i) const
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
int GetNE() const
Returns number of elements.
int Dimension() const
Dimension of the reference space used within the elements.
int SpaceDimension() const
Dimension of the physical space containing the mesh.
void GetNodes(Vector &node_coord) const
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.
void EliminateBC(const Array< int > &ess_dofs, DiagonalPolicy diag_policy)
Eliminate essential (Dirichlet) boundary conditions.
int * WriteJ(bool on_dev=true)
Memory< int > & GetMemoryI()
const int * ReadI(bool on_dev=true) const
int * WriteI(bool on_dev=true)
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).
void SetSize(int s)
Resize the vector to size s.
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.
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
@ byVDIM
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
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.
@ LEXICOGRAPHIC
Lexicographic ordering for tensor-product FiniteElements.
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes)
void forall(int N, lambda &&body)