674 lines
28 KiB
C++
674 lines
28 KiB
C++
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#ifndef MFEM_TRANSFER_HPP
|
|
#define MFEM_TRANSFER_HPP
|
|
|
|
#include "../linalg/linalg.hpp"
|
|
#include "fespace.hpp"
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
#include "pfespace.hpp"
|
|
#endif
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
/** @brief Base class for transfer algorithms that construct transfer Operator%s
|
|
between two finite element (FE) spaces. */
|
|
/** Generally, the two FE spaces (domain and range) can be defined on different
|
|
meshes. */
|
|
class GridTransfer
|
|
{
|
|
protected:
|
|
FiniteElementSpace &dom_fes; ///< Domain FE space
|
|
FiniteElementSpace &ran_fes; ///< Range FE space
|
|
|
|
/** @brief Desired Operator::Type for the construction of all operators
|
|
defined by the underlying transfer algorithm. It can be ignored by
|
|
derived classes. */
|
|
Operator::Type oper_type;
|
|
|
|
OperatorHandle fw_t_oper; ///< Forward true-dof operator
|
|
OperatorHandle bw_t_oper; ///< Backward true-dof operator
|
|
|
|
bool use_ea;
|
|
|
|
MemoryType d_mt;
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
bool parallel;
|
|
#endif
|
|
bool Parallel() const
|
|
{
|
|
#ifndef MFEM_USE_MPI
|
|
return false;
|
|
#else
|
|
return parallel;
|
|
#endif
|
|
}
|
|
|
|
const Operator &MakeTrueOperator(FiniteElementSpace &fes_in,
|
|
FiniteElementSpace &fes_out,
|
|
const Operator &oper,
|
|
OperatorHandle &t_oper);
|
|
|
|
public:
|
|
/** Construct a transfer algorithm between the domain, @a dom_fes_, and
|
|
range, @a ran_fes_, FE spaces, d_mt_ will specify memory space for
|
|
large data structures */
|
|
GridTransfer(FiniteElementSpace &dom_fes_,
|
|
FiniteElementSpace &ran_fes_);
|
|
|
|
/// Virtual destructor
|
|
virtual ~GridTransfer() { }
|
|
|
|
/** Uses device friendly element assembly versions for L2Projection
|
|
transfers, L2, H1 FEM spaces currently supported */
|
|
void UseEA(bool use_ea_) { use_ea = use_ea_;}
|
|
|
|
/** Set memory type for large data structures */
|
|
void SetMemType(MemoryType d_mt_) {d_mt = d_mt_;}
|
|
|
|
/** @brief Set the desired Operator::Type for the construction of all
|
|
operators defined by the underlying transfer algorithm. */
|
|
/** The default value is Operator::ANY_TYPE which typically corresponds to a
|
|
matrix-free operator representation. Note that derived classes are not
|
|
required to support this setting and can ignore it. */
|
|
void SetOperatorType(Operator::Type type) { oper_type = type; }
|
|
|
|
/** @brief Return an Operator that transfers GridFunction%s from the domain
|
|
FE space to GridFunction%s in the range FE space. */
|
|
virtual const Operator &ForwardOperator() = 0;
|
|
|
|
/** @brief Return an Operator that transfers GridFunction%s from the range FE
|
|
space back to GridFunction%s in the domain FE space. */
|
|
virtual const Operator &BackwardOperator() = 0;
|
|
|
|
/** @brief Return an Operator that transfers true-dof Vector%s from the
|
|
domain FE space to true-dof Vector%s in the range FE space. */
|
|
/** This method is implemented in the base class, based on ForwardOperator(),
|
|
however, derived classes can overload the construction, if necessary. */
|
|
virtual const Operator &TrueForwardOperator()
|
|
{
|
|
return MakeTrueOperator(dom_fes, ran_fes, ForwardOperator(), fw_t_oper);
|
|
}
|
|
|
|
/** @brief Return an Operator that transfers true-dof Vector%s from the range
|
|
FE space back to true-dof Vector%s in the domain FE space. */
|
|
/** This method is implemented in the base class, based on
|
|
BackwardOperator(), however, derived classes can overload the
|
|
construction, if necessary. */
|
|
virtual const Operator &TrueBackwardOperator()
|
|
{
|
|
return MakeTrueOperator(ran_fes, dom_fes, BackwardOperator(), bw_t_oper);
|
|
}
|
|
|
|
virtual bool SupportsBackwardsOperator() const { return true; }
|
|
};
|
|
|
|
|
|
/** @brief Transfer data between a coarse mesh and an embedded refined mesh
|
|
using interpolation. */
|
|
/** The forward, coarse-to-fine, transfer uses nodal interpolation. The
|
|
backward, fine-to-coarse, transfer is defined locally (on a coarse element)
|
|
as B = (F^t M_f F)^{-1} F^t M_f, where F is the forward transfer matrix, and
|
|
M_f is a mass matrix on the union of all fine elements comprising the coarse
|
|
element. Note that the backward transfer operator, B, is a left inverse of
|
|
the forward transfer operator, F, i.e. B F = I. Both F and B are defined in
|
|
reference space and do not depend on the actual physical shape of the mesh
|
|
elements.
|
|
|
|
It is assumed that both the coarse and the fine FiniteElementSpace%s use
|
|
compatible types of elements, e.g. finite elements with the same map-type
|
|
(VALUE, INTEGRAL, H_DIV, H_CURL - see class FiniteElement). Generally, the
|
|
FE spaces can have different orders, however, in order for the backward
|
|
operator to be well-defined, the (local) number of the fine dofs should not
|
|
be smaller than the number of coarse dofs. */
|
|
class InterpolationGridTransfer : public GridTransfer
|
|
{
|
|
protected:
|
|
BilinearFormIntegrator *mass_integ; ///< Ownership depends on #own_mass_integ
|
|
bool own_mass_integ; ///< Ownership flag for #mass_integ
|
|
|
|
OperatorHandle F; ///< Forward, coarse-to-fine, operator
|
|
OperatorHandle B; ///< Backward, fine-to-coarse, operator
|
|
|
|
public:
|
|
InterpolationGridTransfer(FiniteElementSpace &coarse_fes,
|
|
FiniteElementSpace &fine_fes)
|
|
: GridTransfer(coarse_fes, fine_fes),
|
|
mass_integ(NULL), own_mass_integ(false)
|
|
{ }
|
|
|
|
virtual ~InterpolationGridTransfer();
|
|
|
|
/** @brief Assign a mass integrator to be used in the construction of the
|
|
backward, fine-to-coarse, transfer operator. */
|
|
void SetMassIntegrator(BilinearFormIntegrator *mass_integ_,
|
|
bool own_mass_integ_ = true);
|
|
|
|
const Operator &ForwardOperator() override;
|
|
|
|
const Operator &BackwardOperator() override;
|
|
};
|
|
|
|
|
|
/** @brief Transfer data in L2 and H1 finite element spaces between a coarse
|
|
mesh and an embedded refined mesh using L2 projection. */
|
|
/** The forward, coarse-to-fine, transfer uses L2 projection. The backward,
|
|
fine-to-coarse, transfer is defined as B = (F^t M_f F)^{-1} F^t M_f, where F
|
|
is the forward transfer matrix, and M_f is the mass matrix on the coarse
|
|
element. For L2 spaces, M_f is the mass matrix on the union of all fine
|
|
elements comprising the coarse element. For H1 spaces, M_f is a diagonal
|
|
(lumped) mass matrix computed through row-summation. Note that the backward
|
|
transfer operator, B, is a left inverse of the forward transfer operator, F,
|
|
i.e. B F = I. Both F and B are defined in physical space and, generally for
|
|
L2 spaces, vary between different mesh elements.
|
|
|
|
This class supports H1 and L2 finite element spaces. Fine meshes are a
|
|
uniform refinement of the coarse mesh, usually created through
|
|
Mesh::MakeRefined. Generally, the coarse and fine FE spaces can have
|
|
different orders, however, in order for the backward operator to be
|
|
well-defined, the number of fine dofs (in a coarse element) should not be
|
|
smaller than the number of coarse dofs. */
|
|
class L2ProjectionGridTransfer : public GridTransfer
|
|
{
|
|
// Must be public due to host device lambdas
|
|
public:
|
|
/** Abstract class representing projection operator between a high-order
|
|
finite element space on a coarse mesh, and a low-order finite element
|
|
space on a refined mesh (LOR). We assume that the low-order space,
|
|
fes_lor, lives on a mesh obtained by refining the mesh of the high-order
|
|
space, fes_ho. */
|
|
class L2Projection : public Operator
|
|
{
|
|
public:
|
|
virtual void Prolongate(const Vector& x, Vector& y) const = 0;
|
|
virtual void ProlongateTranspose(const Vector& x, Vector& y) const = 0;
|
|
/// @brief Sets relative tolerance in preconditioned conjugate gradient
|
|
/// solver.
|
|
///
|
|
/// Only used for H1 spaces.
|
|
virtual void SetRelTol(real_t p_rtol_) = 0;
|
|
/// @brief Sets absolute tolerance in preconditioned conjugate gradient
|
|
/// solver.
|
|
///
|
|
/// Only used for H1 spaces.
|
|
virtual void SetAbsTol(real_t p_atol_) = 0;
|
|
protected:
|
|
const FiniteElementSpace& fes_ho;
|
|
const FiniteElementSpace& fes_lor;
|
|
|
|
MemoryType d_mt;
|
|
Array<int> offsets;
|
|
Table ho2lor;
|
|
|
|
L2Projection(const FiniteElementSpace& fes_ho_,
|
|
const FiniteElementSpace& fes_lor_,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType());
|
|
|
|
void BuildHo2Lor(int nel_ho, int nel_lor,
|
|
const CoarseFineTransformations& cf_tr);
|
|
|
|
void ElemMixedMass(Geometry::Type geom, const FiniteElement& fe_ho,
|
|
const FiniteElement& fe_lor, ElementTransformation* tr_ho,
|
|
ElementTransformation* tr_lor,
|
|
IntegrationPointTransformation& ip_tr,
|
|
DenseMatrix& M_mixed_el) const;
|
|
|
|
void ElemMixedMass(Geometry::Type geom, const FiniteElement& fe_ho,
|
|
const FiniteElement& fe_lor,
|
|
ElementTransformation* el_tr,
|
|
IntegrationPointTransformation& ip_tr,
|
|
DenseMatrix& B_L, DenseMatrix& B_H) const;
|
|
public:
|
|
/* Returns the Mixed Mass M_LH via device element assembly by building the
|
|
basis functions and data at the quadrature points. */
|
|
void MixedMassEA(const FiniteElementSpace& fes_ho_,
|
|
const FiniteElementSpace& fes_lor_,
|
|
Vector &M_LH,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType());
|
|
};
|
|
|
|
// Class below must be public as we now have device code
|
|
public:
|
|
class H1SpaceMixedMassOperator : public Operator
|
|
{
|
|
protected:
|
|
const FiniteElementSpace* fes_ho;
|
|
const FiniteElementSpace* fes_lor;
|
|
Table* ho2lor;
|
|
Vector* M_LH_ea;
|
|
public:
|
|
H1SpaceMixedMassOperator(const FiniteElementSpace* fes_ho_,
|
|
const FiniteElementSpace* fes_lor_,
|
|
Table* ho2lor_, Vector* M_LH_ea_);
|
|
void Mult(const Vector& x, Vector& y) const;
|
|
void MultTranspose(const Vector& x, Vector& y) const;
|
|
};
|
|
|
|
class H1SpaceLumpedMassOperator : public Operator
|
|
{
|
|
protected:
|
|
const FiniteElementSpace* fes_ho;
|
|
const FiniteElementSpace* fes_lor;
|
|
Vector* ML_inv; // inverse of lumped M_L
|
|
public:
|
|
H1SpaceLumpedMassOperator(const FiniteElementSpace* fes_ho_,
|
|
const FiniteElementSpace* fes_lor_,
|
|
Vector& ML_inv_);
|
|
void Mult(const Vector& x, Vector& y) const;
|
|
void MultTranspose(const Vector& x, Vector& y) const;
|
|
};
|
|
|
|
/** Class for projection operator between a L2 high-order finite element
|
|
space on a coarse mesh, and a L2 low-order finite element space on a
|
|
refined mesh (LOR). */
|
|
class L2ProjectionL2Space : public L2Projection
|
|
{
|
|
/// The restriction and prolongation operators are represented as dense
|
|
/// elementwise matrices (of potentially different sizes, because of mixed
|
|
/// meshes or p-refinement). The matrix entries are stored in the R and P
|
|
/// arrays. The entries of the i'th high-order element are stored at the
|
|
/// index given by offsets[i].
|
|
mutable Array<real_t> R, P;
|
|
|
|
const bool use_ea;
|
|
|
|
public:
|
|
L2ProjectionL2Space(const FiniteElementSpace& fes_ho_,
|
|
const FiniteElementSpace& fes_lor_,
|
|
const bool use_ea_,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType());
|
|
|
|
/*Same as above but assembles and stores R_ea, P_ea */
|
|
void EAL2ProjectionL2Space();
|
|
|
|
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
|
|
/// with a higher order L2 finite element space, to <tt>y</tt>, primal
|
|
/// field coefficients defined on a refined mesh with a low order L2
|
|
/// finite element space. Refined mesh should be a uniform refinement of
|
|
/// the coarse mesh. Coefficients are computed through minimization of L2
|
|
/// error between the fields.
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Perform mult on the device (same as above)
|
|
void EAMult(const Vector& x, Vector& y) const;
|
|
|
|
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
|
|
/// with a low order L2 finite element space, to <tt>y</tt>, dual field
|
|
/// coefficients defined on a coarse mesh with a higher order L2 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed through minimization of L2
|
|
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
|
|
/// come from ProlongateTranspose, then mass is conserved.
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
|
|
void EAMultTranspose(const Vector& x, Vector& y) const;
|
|
|
|
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
|
|
/// with a low order L2 finite element space, to <tt>y</tt>, primal field
|
|
/// coefficients defined on a coarse mesh with a higher order L2 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed from the mass conservative
|
|
/// left-inverse prolongation operation. This functionality is also
|
|
/// provided as an Operator by L2Prolongation.
|
|
void Prolongate(const Vector& x, Vector& y) const override;
|
|
|
|
void EAProlongate(const Vector& x, Vector& y) const;
|
|
|
|
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
|
|
/// a higher order L2 finite element space, to <tt>y</tt>, dual field
|
|
/// coefficients defined on a refined mesh with a low order L2 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed from the transpose of the mass
|
|
/// conservative left-inverse prolongation operation. This functionality
|
|
/// is also provided as an Operator by L2Prolongation.
|
|
void ProlongateTranspose(const Vector& x, Vector& y) const override;
|
|
|
|
void EAProlongateTranspose(const Vector& x, Vector& y) const;
|
|
|
|
void SetRelTol(real_t p_rtol_) override { } ///< No-op.
|
|
void SetAbsTol(real_t p_atol_) override { } ///< No-op.
|
|
};
|
|
|
|
protected:
|
|
|
|
/// Class below must be public as we now have device code
|
|
public:
|
|
|
|
/** Projection operator between a H1 high-order finite element space on a
|
|
coarse mesh, and a H1 low-order finite element space on a refined mesh
|
|
(LOR). */
|
|
class L2ProjectionH1Space : public L2Projection
|
|
{
|
|
const bool use_ea;
|
|
|
|
public:
|
|
L2ProjectionH1Space(const FiniteElementSpace &fes_ho_,
|
|
const FiniteElementSpace &fes_lor_,
|
|
const bool use_ea_,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType());
|
|
#ifdef MFEM_USE_MPI
|
|
L2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
|
|
const ParFiniteElementSpace &pfes_lor_,
|
|
const bool use_ea_,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType());
|
|
#endif
|
|
/// Same as above but assembles action of R through 4 parts:
|
|
/// ( ) inv( lumped(M_L) ), which is a diagonal matrix (essentially a vector)
|
|
/// ( ) ElementRestrictionOperator for LOR space
|
|
/// ( ) mixed mass matrix M_{LH}
|
|
/// ( ) ElementRestrictionOperator for HO space
|
|
void EAL2ProjectionH1Space();
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
void EAL2ProjectionH1Space(const ParFiniteElementSpace &pfes_ho_,
|
|
const ParFiniteElementSpace &pfes_lor_);
|
|
#endif
|
|
/// Maps <tt>x</tt>, primal field coefficients defined on a coarse mesh
|
|
/// with a higher order H1 finite element space, to <tt>y</tt>, primal
|
|
/// field coefficients defined on a refined mesh with a low order H1
|
|
/// finite element space. Refined mesh should be a uniform refinement of
|
|
/// the coarse mesh. Coefficients are computed through minimization of L2
|
|
/// error between the fields.
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Maps <tt>x</tt>, dual field coefficients defined on a refined mesh
|
|
/// with a low order H1 finite element space, to <tt>y</tt>, dual field
|
|
/// coefficients defined on a coarse mesh with a higher order H1 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed through minimization of L2
|
|
/// error between the primal fields. Note, if the <tt>x</tt>-coefficients
|
|
/// come from ProlongateTranspose, then mass is conserved.
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
|
|
/// Maps <tt>x</tt>, primal field coefficients defined on a refined mesh
|
|
/// with a low order H1 finite element space, to <tt>y</tt>, primal field
|
|
/// coefficients defined on a coarse mesh with a higher order H1 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed from the mass conservative
|
|
/// left-inverse prolongation operation. This functionality is also
|
|
/// provided as an Operator by L2Prolongation.
|
|
void Prolongate(const Vector& x, Vector& y) const override;
|
|
|
|
/// Maps <tt>x</tt>, dual field coefficients defined on a coarse mesh with
|
|
/// a higher order H1 finite element space, to <tt>y</tt>, dual field
|
|
/// coefficients defined on a refined mesh with a low order H1 finite
|
|
/// element space. Refined mesh should be a uniform refinement of the
|
|
/// coarse mesh. Coefficients are computed from the transpose of the mass
|
|
/// conservative left-inverse prolongation operation. This functionality
|
|
/// is also provided as an Operator by L2Prolongation.
|
|
void ProlongateTranspose(const Vector& x, Vector& y) const override;
|
|
|
|
/// Returns the inverse of an on-rank lumped mass matrix
|
|
void LumpedMassInverse(Vector& ML_inv) const;
|
|
|
|
void SetRelTol(real_t p_rtol_) override;
|
|
void SetAbsTol(real_t p_atol_) override;
|
|
|
|
protected:
|
|
/// Sets up the PCG solver (sets parameters, operator, and preconditioner)
|
|
void SetupPCG();
|
|
|
|
/// @brief Computes on-rank R and M_LH matrices. If true, computes mixed mass and/or
|
|
/// inverse lumped mass matrix error when compared to device implementation.
|
|
std::pair<std::unique_ptr<SparseMatrix>,
|
|
std::unique_ptr<SparseMatrix>> ComputeSparseRAndM_LH();
|
|
|
|
/// @brief Recovers vector of tdofs given a vector of dofs and a finite
|
|
/// element space
|
|
void GetTDofs(const FiniteElementSpace& fes, const Vector& x, Vector& X) const;
|
|
/// Sets dof values given a vector of tdofs and a finite element space
|
|
void SetFromTDofs(const FiniteElementSpace& fes,
|
|
const Vector& X,
|
|
Vector& x) const;
|
|
/// @brief Recovers a vector of dual field coefficients on the tdofs given
|
|
/// a vector of dual coefficients and a finite element space
|
|
void GetTDofsTranspose(const FiniteElementSpace& fes,
|
|
const Vector& x,
|
|
Vector& X) const;
|
|
/// @brief Sets dual field coefficients given a vector of dual field
|
|
/// coefficients on the tdofs and a finite element space
|
|
void SetFromTDofsTranspose(const FiniteElementSpace& fes,
|
|
const Vector& X,
|
|
Vector& x) const;
|
|
/// @brief Fills the vdofs_list array with a list of vdofs for a given
|
|
/// vdim and a given finite element space
|
|
void TDofsListByVDim(const FiniteElementSpace& fes,
|
|
int vdim,
|
|
Array<int>& vdofs_list) const;
|
|
|
|
/// @brief Computes sparsity pattern and initializes R matrix.
|
|
/// Based on BilinearForm::AllocMat(), except maps between coarse HO
|
|
/// elements and refined LOR elements.
|
|
std::unique_ptr<SparseMatrix> AllocR();
|
|
|
|
CGSolver pcg;
|
|
std::unique_ptr<Solver> precon;
|
|
// The restriction operator is represented as an Operator R. The
|
|
// prolongation operator is a dense matrix computed as the inverse of (R^T
|
|
// M_L R), and hence, is not stored.
|
|
// If element assembly is enabled
|
|
std::unique_ptr<Operator> R;
|
|
// Used to compute P = (RT*M_LH)^(-1) M_LH^T
|
|
std::unique_ptr<Operator> M_LH;
|
|
// Inverted operator in P = (RT*M_LH)^(-1) M_LH^T. Used to compute P via PCG.
|
|
std::unique_ptr<Operator> RTxM_LH;
|
|
// Lumped M_L inverse operator built via EA. Wrapped with restriction maps
|
|
// to multiply with scalar TDof LOR vectors.
|
|
std::unique_ptr<Operator> ML_inv_vea;
|
|
// LDof Mixed mass operator built via EA. Wrapped with restriction maps to send
|
|
// scalar LDof HO vectors to LDof LOR vectors.
|
|
Operator *M_LH_local_op;
|
|
|
|
// Scalar finite element spaces for stored Tdof-to-and-from-LDof maps.
|
|
std::unique_ptr<FiniteElementSpace> fes_ho_scalar;
|
|
std::unique_ptr<FiniteElementSpace> fes_lor_scalar;
|
|
// Element Assembled mixed mass
|
|
Vector M_LH_ea;
|
|
// Element Assembled lumped M_L inverse built via EA. Stores diagonal as a Ldof vector.
|
|
Vector ML_inv_ea;
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
std::unique_ptr<ParFiniteElementSpace> pfes_ho_scalar;
|
|
std::unique_ptr<ParFiniteElementSpace> pfes_lor_scalar;
|
|
Vector RML_inv;
|
|
#endif
|
|
|
|
friend class L2ProjectionL2Space;
|
|
};
|
|
|
|
/** Mass-conservative prolongation operator going in the opposite direction
|
|
as L2Projection. This operator is a left inverse to the L2Projection. */
|
|
class L2Prolongation : public Operator
|
|
{
|
|
const L2Projection &l2proj;
|
|
|
|
public:
|
|
L2Prolongation(const L2Projection &l2proj_)
|
|
: Operator(l2proj_.Width(), l2proj_.Height()), l2proj(l2proj_) { }
|
|
void Mult(const Vector &x, Vector &y) const
|
|
{
|
|
l2proj.Prolongate(x, y);
|
|
}
|
|
void MultTranspose(const Vector &x, Vector &y) const
|
|
{
|
|
l2proj.ProlongateTranspose(x, y);
|
|
}
|
|
virtual ~L2Prolongation() { }
|
|
};
|
|
|
|
L2Projection *F; ///< Forward, coarse-to-fine, operator
|
|
L2Prolongation *B; ///< Backward, fine-to-coarse, operator
|
|
bool force_l2_space;
|
|
|
|
public:
|
|
L2ProjectionGridTransfer(FiniteElementSpace &coarse_fes_,
|
|
FiniteElementSpace &fine_fes_,
|
|
bool force_l2_space_ = false,
|
|
MemoryType d_mt_ = Device::GetHostMemoryType()) // move to method
|
|
: GridTransfer(coarse_fes_, fine_fes_),
|
|
F(NULL), B(NULL), force_l2_space(force_l2_space_)
|
|
{ }
|
|
virtual ~L2ProjectionGridTransfer();
|
|
|
|
const Operator &ForwardOperator() override;
|
|
|
|
const Operator &BackwardOperator() override;
|
|
|
|
bool SupportsBackwardsOperator() const override;
|
|
private:
|
|
void BuildF();
|
|
};
|
|
|
|
/// Matrix-free transfer operator between finite element spaces
|
|
class TransferOperator : public Operator
|
|
{
|
|
private:
|
|
Operator* opr;
|
|
|
|
public:
|
|
/// Constructs a transfer operator from \p lFESpace to \p hFESpace.
|
|
/** No matrices are assembled, only the action to a vector is being computed.
|
|
If both spaces' FE collection pointers are pointing to the same
|
|
collection, we assume that the grid was refined while keeping the order
|
|
constant. If the FE collections are different, it is assumed that both
|
|
spaces are using the same mesh. If the first element of the high-order
|
|
space is a `TensorBasisElement`, the optimized tensor-product transfers
|
|
are used. If not, the general transfers used. */
|
|
TransferOperator(const FiniteElementSpace& lFESpace,
|
|
const FiniteElementSpace& hFESpace);
|
|
|
|
/// Destructor
|
|
virtual ~TransferOperator();
|
|
|
|
/// @brief Interpolation or prolongation of a vector \p x corresponding to
|
|
/// the coarse space to the vector \p y corresponding to the fine space.
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Restriction by applying the transpose of the Mult method.
|
|
/** The vector \p x corresponding to the fine space is restricted to the
|
|
vector \p y corresponding to the coarse space. */
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
};
|
|
|
|
/// Matrix-free transfer operator between finite element spaces on the same mesh
|
|
class PRefinementTransferOperator : public Operator
|
|
{
|
|
private:
|
|
const FiniteElementSpace& lFESpace;
|
|
const FiniteElementSpace& hFESpace;
|
|
bool isvar_order;
|
|
|
|
public:
|
|
/// @brief Constructs a transfer operator from \p lFESpace to \p hFESpace
|
|
/// which have different FE collections.
|
|
/** No matrices are assembled, only the action to a vector is being computed.
|
|
The underlying finite elements need to implement the GetTransferMatrix
|
|
methods. */
|
|
PRefinementTransferOperator(const FiniteElementSpace& lFESpace_,
|
|
const FiniteElementSpace& hFESpace_);
|
|
|
|
/// Destructor
|
|
virtual ~PRefinementTransferOperator() { }
|
|
|
|
/// @brief Interpolation or prolongation of a vector \p x corresponding to
|
|
/// the coarse space to the vector \p y corresponding to the fine space.
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Restriction by applying the transpose of the Mult method.
|
|
/** The vector \p x corresponding to the fine space is restricted to the
|
|
vector \p y corresponding to the coarse space. */
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
};
|
|
|
|
/// @brief Matrix-free transfer operator between finite element spaces on the
|
|
/// same mesh exploiting the tensor product structure of the finite elements
|
|
class TensorProductPRefinementTransferOperator : public Operator
|
|
{
|
|
private:
|
|
const FiniteElementSpace& lFESpace;
|
|
const FiniteElementSpace& hFESpace;
|
|
int dim;
|
|
int NE;
|
|
int D1D;
|
|
int Q1D;
|
|
Array<real_t> B;
|
|
Array<real_t> Bt;
|
|
const Operator* elem_restrict_lex_l;
|
|
const Operator* elem_restrict_lex_h;
|
|
Vector mask;
|
|
mutable Vector localL;
|
|
mutable Vector localH;
|
|
|
|
public:
|
|
/// @brief Constructs a transfer operator from \p lFESpace to \p hFESpace
|
|
/// which have different FE collections.
|
|
/** No matrices are assembled, only the action to a vector is being computed.
|
|
The underlying finite elements need to be of type `TensorBasisElement`. It is
|
|
also assumed that all the elements in the spaces are of the same type. */
|
|
TensorProductPRefinementTransferOperator(
|
|
const FiniteElementSpace& lFESpace_,
|
|
const FiniteElementSpace& hFESpace_);
|
|
|
|
/// Destructor
|
|
virtual ~TensorProductPRefinementTransferOperator() { }
|
|
|
|
/// @brief Interpolation or prolongation of a vector \p x corresponding to
|
|
/// the coarse space to the vector \p y corresponding to the fine space.
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Restriction by applying the transpose of the Mult method.
|
|
/** The vector \p x corresponding to the fine space is restricted to the
|
|
vector \p y corresponding to the coarse space. */
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
};
|
|
|
|
/// @brief Matrix-free transfer operator between finite element spaces working
|
|
/// on true degrees of freedom
|
|
class TrueTransferOperator : public Operator
|
|
{
|
|
private:
|
|
const FiniteElementSpace& lFESpace;
|
|
const FiniteElementSpace& hFESpace;
|
|
const Operator * P = nullptr;
|
|
const SparseMatrix * R = nullptr;
|
|
TransferOperator* localTransferOperator;
|
|
mutable Vector tmpL;
|
|
mutable Vector tmpH;
|
|
|
|
public:
|
|
/// @brief Constructs a transfer operator working on true degrees of freedom
|
|
/// from \p lFESpace to \p hFESpace
|
|
TrueTransferOperator(const FiniteElementSpace& lFESpace_,
|
|
const FiniteElementSpace& hFESpace_);
|
|
|
|
/// Destructor
|
|
~TrueTransferOperator();
|
|
|
|
/// @brief Interpolation or prolongation of a true dof vector \p x to a true
|
|
/// dof vector \p y.
|
|
/** The true dof vector \p x corresponding to the coarse space is restricted
|
|
to the true dof vector \p y corresponding to the fine space. */
|
|
void Mult(const Vector& x, Vector& y) const override;
|
|
|
|
/// Restriction by applying the transpose of the Mult method.
|
|
/** The true dof vector \p x corresponding to the fine space is restricted to
|
|
the true dof vector \p y corresponding to the coarse space. */
|
|
void MultTranspose(const Vector& x, Vector& y) const override;
|
|
};
|
|
|
|
} // namespace mfem
|
|
|
|
#endif
|