Files
mfem/linalg/operator.hpp
T
2020-04-21 11:48:59 -07:00

802 lines
33 KiB
C++

// Copyright (c) 2010-2020, 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_OPERATOR
#define MFEM_OPERATOR
#include "vector.hpp"
namespace mfem
{
class ConstrainedOperator;
class RectangularConstrainedOperator;
/// Abstract operator
class Operator
{
protected:
int height; ///< Dimension of the output / number of rows in the matrix.
int width; ///< Dimension of the input / number of columns in the matrix.
/// see FormSystemOperator()
void FormConstrainedSystemOperator(
const Array<int> &ess_tdof_list, ConstrainedOperator* &Aout);
/// see FormRectangularSystemOperator()
void FormRectangularConstrainedSystemOperator(
const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
RectangularConstrainedOperator* &Aout);
/// Returns RAP Operator of this, taking in input/output Prolongation matrices
Operator *SetupRAP(const Operator *Pi, const Operator *Po);
public:
/// Initializes memory for true vectors of linear system
void InitTVectors(const Operator *Po, const Operator *Ri, const Operator *Pi,
Vector &x, Vector &b,
Vector &X, Vector &B) const;
/// Construct a square Operator with given size s (default 0).
explicit Operator(int s = 0) { height = width = s; }
/** @brief Construct an Operator with the given height (output size) and
width (input size). */
Operator(int h, int w) { height = h; width = w; }
/// Get the height (size of output) of the Operator. Synonym with NumRows().
inline int Height() const { return height; }
/** @brief Get the number of rows (size of output) of the Operator. Synonym
with Height(). */
inline int NumRows() const { return height; }
/// Get the width (size of input) of the Operator. Synonym with NumCols().
inline int Width() const { return width; }
/** @brief Get the number of columns (size of input) of the Operator. Synonym
with Width(). */
inline int NumCols() const { return width; }
/// Return the MemoryClass preferred by the Operator.
/** This is the MemoryClass that will be used to access the input and output
vectors in the Mult() and MultTranspose() methods.
For example, classes using the MFEM_FORALL macro for implementation can
return the value returned by Device::GetMemoryClass().
The default implementation of this method in class Operator returns
MemoryClass::HOST. */
virtual MemoryClass GetMemoryClass() const { return MemoryClass::HOST; }
/// Operator application: `y=A(x)`.
virtual void Mult(const Vector &x, Vector &y) const = 0;
/** @brief Action of the transpose operator: `y=A^t(x)`. The default behavior
in class Operator is to generate an error. */
virtual void MultTranspose(const Vector &x, Vector &y) const
{ mfem_error("Operator::MultTranspose() is not overloaded!"); }
/** @brief Evaluate the gradient operator at the point @a x. The default
behavior in class Operator is to generate an error. */
virtual Operator &GetGradient(const Vector &x) const
{
mfem_error("Operator::GetGradient() is not overloaded!");
return const_cast<Operator &>(*this);
}
/** @brief Prolongation operator from linear algebra (linear system) vectors,
to input vectors for the operator. `NULL` means identity. */
virtual const Operator *GetProlongation() const { return NULL; }
/** @brief Restriction operator from input vectors for the operator to linear
algebra (linear system) vectors. `NULL` means identity. */
virtual const Operator *GetRestriction() const { return NULL; }
/** @brief Prolongation operator from linear algebra (linear system) vectors,
to output vectors for the operator. `NULL` means identity. */
virtual const Operator *GetOutputProlongation() const
{
return GetProlongation(); // Assume square unless specialized
}
/** @brief Restriction operator from output vectors for the operator to linear
algebra (linear system) vectors. `NULL` means identity. */
virtual const Operator *GetOutputRestriction() const
{
return GetRestriction(); // Assume square unless specialized
}
/** @brief Form a constrained linear system using a matrix-free approach.
Assuming square operator, form the operator linear system `A(X)=B`,
corresponding to it and the right-hand side @a b, by applying any
necessary transformations such as: parallel assembly, conforming
constraints for non-conforming AMR and eliminating boundary conditions.
@note Static condensation and hybridization are not supported for general
operators (cf. the analogous methods BilinearForm::FormLinearSystem() and
ParBilinearForm::FormLinearSystem()).
The constraints are specified through the prolongation P from
GetProlongation(), and restriction R from GetRestriction() methods, which
are e.g. available through the (parallel) finite element space of any
(parallel) bilinear form operator. We assume that the operator is square,
using the same input and output space, so we have: `A(X)=[P^t (*this)
P](X)`, `B=P^t(b)`, and `X=R(x)`.
The vector @a x must contain the essential boundary condition values.
These are eliminated through the ConstrainedOperator class and the vector
@a X is initialized by setting its essential entries to the boundary
conditions and all other entries to zero (@a copy_interior == 0) or
copied from @a x (@a copy_interior != 0).
After solving the system `A(X)=B`, the (finite element) solution @a x can
be recovered by calling Operator::RecoverFEMSolution() with the same
vectors @a X, @a b, and @a x.
@note The caller is responsible for destroying the output operator @a A!
@note If there are no transformations, @a X simply reuses the data of @a
x. */
void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
Operator* &A, Vector &X, Vector &B,
int copy_interior = 0);
/** @brief Form a column-constrained linear system using a matrix-free approach.
Form the operator linear system `A(X)=B` corresponding to the operator
and the right-hand side @a b, by applying any necessary transformations
such as: parallel assembly, conforming constraints for non-conforming AMR
and eliminating boundary conditions. @note Static condensation and
hybridization are not supported for general operators (cf. the method
MixedBilinearForm::FormRectangularLinearSystem())
The constraints are specified through the input prolongation Pi from
GetProlongation(), and output restriction Ro from GetOutputRestriction()
methods, which are e.g. available through the (parallel) finite element
spaces of any (parallel) mixed bilinear form operator. So we have:
`A(X)=[Ro (*this) Pi](X)`, `B=Ro(b)`, and `X=Pi^T(x)`.
The vector @a x must contain the essential boundary condition values.
The "columns" in this operator corresponding to these values are
eliminated through the RectangularConstrainedOperator class.
After solving the system `A(X)=B`, the (finite element) solution @a x can
be recovered by calling Operator::RecoverFEMSolution() with the same
vectors @a X, @a b, and @a x.
@note The caller is responsible for destroying the output operator @a A!
@note If there are no transformations, @a X simply reuses the data of @a
x. */
void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
Vector &x, Vector &b,
Operator* &A, Vector &X, Vector &B);
/** @brief Reconstruct a solution vector @a x (e.g. a GridFunction) from the
solution @a X of a constrained linear system obtained from
Operator::FormLinearSystem() or Operator::FormRectangularLinearSystem().
Call this method after solving a linear system constructed using
Operator::FormLinearSystem() to recover the solution as an input vector,
@a x, for this Operator (presumably a finite element grid function). This
method has identical signature to the analogous method for bilinear
forms, though currently @a b is not used in the implementation. */
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x);
/** @brief Return in @a A a parallel (on truedofs) version of this square
operator.
This returns the same operator as FormLinearSystem(), but does without
the transformations of the right-hand side and initial guess. */
void FormSystemOperator(const Array<int> &ess_tdof_list,
Operator* &A);
/** @brief Return in @a A a parallel (on truedofs) version of this
rectangular operator (including constraints).
This returns the same operator as FormRectangularLinearSystem(), but does
without the transformations of the right-hand side. */
void FormRectangularSystemOperator(const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
Operator* &A);
/** @brief Return in @a A a parallel (on truedofs) version of this
rectangular operator.
This is similar to FormSystemOperator(), but for dof-to-dof mappings
(discrete linear operators), which can also correspond to rectangular
matrices. The user should provide specializations of GetProlongation()
for the input dofs and GetOutputRestriction() for the output dofs in
their Operator implementation that are appropriate for the two spaces the
Operator maps between. These are e.g. available through the (parallel)
finite element space of any (parallel) bilinear form operator. We have:
`A(X)=[Rout (*this) Pin](X)`. */
void FormDiscreteOperator(Operator* &A);
/// Prints operator with input size n and output size m in Matlab format.
void PrintMatlab(std::ostream & out, int n = 0, int m = 0) const;
/// Virtual destructor.
virtual ~Operator() { }
/// Enumeration defining IDs for some classes derived from Operator.
/** This enumeration is primarily used with class OperatorHandle. */
enum Type
{
ANY_TYPE, ///< ID for the base class Operator, i.e. any type.
MFEM_SPARSEMAT, ///< ID for class SparseMatrix.
Hypre_ParCSR, ///< ID for class HypreParMatrix.
PETSC_MATAIJ, ///< ID for class PetscParMatrix, MATAIJ format.
PETSC_MATIS, ///< ID for class PetscParMatrix, MATIS format.
PETSC_MATSHELL, ///< ID for class PetscParMatrix, MATSHELL format.
PETSC_MATNEST, ///< ID for class PetscParMatrix, MATNEST format.
PETSC_MATHYPRE, ///< ID for class PetscParMatrix, MATHYPRE format.
PETSC_MATGENERIC, ///< ID for class PetscParMatrix, unspecified format.
Complex_Operator, ///< ID for class ComplexOperator.
MFEM_ComplexSparseMat, ///< ID for class ComplexSparseMatrix.
Complex_Hypre_ParCSR ///< ID for class ComplexHypreParMatrix.
};
/// Return the type ID of the Operator class.
/** This method is intentionally non-virtual, so that it returns the ID of
the specific pointer or reference type used when calling this method. If
not overridden by derived classes, they will automatically use the type ID
of the base Operator class, ANY_TYPE. */
Type GetType() const { return ANY_TYPE; }
};
/// Base abstract class for first order time dependent operators.
/** Operator of the form: (x,t) -> f(x,t), where k = f(x,t) generally solves the
algebraic equation F(x,k,t) = G(x,t). The functions F and G represent the
_implicit_ and _explicit_ parts of the operator, respectively. For explicit
operators, F(x,k,t) = k, so f(x,t) = G(x,t). */
class TimeDependentOperator : public Operator
{
public:
enum Type
{
EXPLICIT, ///< This type assumes F(x,k,t) = k, i.e. k = f(x,t) = G(x,t).
IMPLICIT, ///< This is the most general type, no assumptions on F and G.
HOMOGENEOUS ///< This type assumes that G(x,t) = 0.
};
/// Evaluation mode. See SetEvalMode() for details.
enum EvalMode
{
/** Normal evaluation. */
NORMAL,
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
first term, f1. */
ADDITIVE_TERM_1,
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
second term, f2. */
ADDITIVE_TERM_2
};
protected:
double t; ///< Current time.
Type type; ///< Describes the form of the TimeDependentOperator.
EvalMode eval_mode; ///< Current evaluation mode.
public:
/** @brief Construct a "square" TimeDependentOperator y = f(x,t), where x and
y have the same dimension @a n. */
explicit TimeDependentOperator(int n = 0, double t_ = 0.0,
Type type_ = EXPLICIT)
: Operator(n) { t = t_; type = type_; eval_mode = NORMAL; }
/** @brief Construct a TimeDependentOperator y = f(x,t), where x and y have
dimensions @a w and @a h, respectively. */
TimeDependentOperator(int h, int w, double t_ = 0.0, Type type_ = EXPLICIT)
: Operator(h, w) { t = t_; type = type_; eval_mode = NORMAL; }
/// Read the currently set time.
virtual double GetTime() const { return t; }
/// Set the current time.
virtual void SetTime(const double _t) { t = _t; }
/// True if #type is #EXPLICIT.
bool isExplicit() const { return (type == EXPLICIT); }
/// True if #type is #IMPLICIT or #HOMOGENEOUS.
bool isImplicit() const { return !isExplicit(); }
/// True if #type is #HOMOGENEOUS.
bool isHomogeneous() const { return (type == HOMOGENEOUS); }
/// Return the current evaluation mode. See SetEvalMode() for details.
EvalMode GetEvalMode() const { return eval_mode; }
/// Set the evaluation mode of the time-dependent operator.
/** The evaluation mode is a switch that allows time-stepping methods to
request evaluation of separate components/terms of the time-dependent
operator. For example, IMEX methods typically assume additive split of
the operator: f(x,t) = f1(x,t) + f2(x,t) and they rely on the ability to
evaluate the two terms separately.
Generally, setting the evaluation mode should affect the behavior of all
evaluation-related methods in the class, such as Mult(), ImplicitSolve(),
etc. However, the exact list of methods that need to support a specific
mode will depend on the used time-stepping method. */
virtual void SetEvalMode(const EvalMode new_eval_mode)
{ eval_mode = new_eval_mode; }
/** @brief Perform the action of the explicit part of the operator, G:
@a y = G(@a x, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual void ExplicitMult(const Vector &x, Vector &y) const;
/** @brief Perform the action of the implicit part of the operator, F:
@a y = F(@a x, @a k, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual.*/
virtual void ImplicitMult(const Vector &x, const Vector &k, Vector &y) const;
/** @brief Perform the action of the operator: @a y = k = f(@a x, t), where
k solves the algebraic equation F(@a x, k, t) = G(@a x, t) and t is the
current time. */
virtual void Mult(const Vector &x, Vector &y) const;
/** @brief Solve the equation: @a k = f(@a x + @a dt @a k, t), for the
unknown @a k at the current time t.
For general F and G, the equation for @a k becomes:
F(@a x + @a dt @a k, @a k, t) = G(@a x + @a dt @a k, t).
The input vector @a x corresponds to time index (or cycle) n, while the
currently set time, #t, and the result vector @a k correspond to time
index n+1. The time step @a dt corresponds to the time interval between
cycles n and n+1.
This method allows for the abstract implementation of some time
integration methods, including diagonal implicit Runge-Kutta (DIRK)
methods and the backward Euler method in particular.
If not re-implemented, this method simply generates an error. */
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
/** @brief Return an Operator representing (dF/dk @a shift + dF/dx) at the
given @a x, @a k, and the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetImplicitGradient(const Vector &x, const Vector &k,
double shift) const;
/** @brief Return an Operator representing dG/dx at the given point @a x and
the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetExplicitGradient(const Vector &x) const;
/** @brief Setup the ODE linear system \f$ A(x,t) = (I - gamma J) \f$ or
\f$ A = (M - gamma J) \f$, where \f$ J(x,t) = \frac{df}{dt(x,t)} \f$.
@param[in] x The state at which \f$A(x,t)\f$ should be evaluated.
@param[in] fx The current value of the ODE rhs function, \f$f(x,t)\f$.
@param[in] jok Flag indicating if the Jacobian should be updated.
@param[out] jcur Flag to signal if the Jacobian was updated.
@param[in] gamma The scaled time step value.
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ODE solvers, for more
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
int jok, int *jcur, double gamma);
/** @brief Solve the ODE linear system \f$ A x = b \f$ as setup by
the method SUNImplicitSetup().
@param[in] b The linear system right-hand side.
@param[in,out] x On input, the initial guess. On output, the solution.
@param[in] tol Linear solve tolerance.
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ODE solvers, for more
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
/** @brief Setup the mass matrix in the ODE system \f$ M y' = f(y,t) \f$ .
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ARKStep integrator, for more
details, see the ARKode User Guide. */
virtual int SUNMassSetup();
/** @brief Solve the mass matrix linear system \f$ M x = b \f$
as setup by the method SUNMassSetup().
@param[in] b The linear system right-hand side.
@param[in,out] x On input, the initial guess. On output, the solution.
@param[in] tol Linear solve tolerance.
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ARKStep integrator, for more
details, see the ARKode User Guide. */
virtual int SUNMassSolve(const Vector &b, Vector &x, double tol);
/** @brief Compute the mass matrix-vector product \f$ v = M x \f$ .
@param[in] x The vector to multiply.
@param[out] v The result of the matrix-vector product.
If not re-implemented, this method simply generates an error.
Presently, this method is used by SUNDIALS ARKStep integrator, for more
details, see the ARKode User Guide. */
virtual int SUNMassMult(const Vector &x, Vector &v);
virtual ~TimeDependentOperator() { }
};
/// Base abstract class for second order time dependent operators.
/** Operator of the form: (x,dxdt,t) -> f(x,dxdt,t), where k = f(x,dxdt,t)
generally solves the algebraic equation F(x,dxdt,k,t) = G(x,dxdt,t).
The functions F and G represent the_implicit_ and _explicit_ parts of
the operator, respectively. For explicit operators,
F(x,dxdt,k,t) = k, so f(x,dxdt,t) = G(x,dxdt,t). */
class SecondOrderTimeDependentOperator : public TimeDependentOperator
{
public:
/** @brief Construct a "square" SecondOrderTimeDependentOperator
y = f(x,dxdt,t), where x, dxdt and y have the same dimension @a n. */
explicit SecondOrderTimeDependentOperator(int n = 0, double t_ = 0.0,
Type type_ = EXPLICIT)
: TimeDependentOperator(n, t_,type_) { }
/** @brief Construct a SecondOrderTimeDependentOperator y = f(x,dxdt,t),
where x, dxdt and y have the same dimension @a n. */
SecondOrderTimeDependentOperator(int h, int w, double t_ = 0.0,
Type type_ = EXPLICIT)
: TimeDependentOperator(h, w, t_,type_) { }
using TimeDependentOperator::Mult;
/** @brief Perform the action of the operator: @a y = k = f(@a x,@ dxdt, t),
where k solves the algebraic equation
F(@a x,@ dxdt, k, t) = G(@a x,@ dxdt, t) and t is the current time. */
virtual void Mult(const Vector &x, const Vector &dxdt, Vector &y) const;
using TimeDependentOperator::ImplicitSolve;
/** @brief Solve the equation:
@a k = f(@a x + 1/2 @a dt0^2 @a k, @a dxdt + @a dt1 @a k, t), for the
unknown @a k at the current time t.
For general F and G, the equation for @a k becomes:
F(@a x + 1/2 @a dt0^2 @a k, @a dxdt + @a dt1 @a k, t)
= G(@a x + 1/2 @a dt0^2 @a k, @a dxdt + @a dt1 @a k, t).
The input vector @a x corresponds to time index (or cycle) n, while the
currently set time, #t, and the result vector @a k correspond to time
index n+1. The time step @a dt corresponds to the time interval between
cycles n and n+1.
This method allows for the abstract implementation of some time
integration methods.
If not re-implemented, this method simply generates an error. */
virtual void ImplicitSolve(const double dt0, const double dt1,
const Vector &x, const Vector &dxdt, Vector &k);
virtual ~SecondOrderTimeDependentOperator() { }
};
/// Base class for solvers
class Solver : public Operator
{
public:
/// If true, use the second argument of Mult() as an initial guess.
bool iterative_mode;
/** @brief Initialize a square Solver with size @a s.
@warning Use a Boolean expression for the second parameter (not an int)
to distinguish this call from the general rectangular constructor. */
explicit Solver(int s = 0, bool iter_mode = false)
: Operator(s) { iterative_mode = iter_mode; }
/// Initialize a Solver with height @a h and width @a w.
Solver(int h, int w, bool iter_mode = false)
: Operator(h, w) { iterative_mode = iter_mode; }
/// Set/update the solver for the given operator.
virtual void SetOperator(const Operator &op) = 0;
};
/// Identity Operator I: x -> x.
class IdentityOperator : public Operator
{
public:
/// Create an identity operator of size @a n.
explicit IdentityOperator(int n) : Operator(n) { }
/// Operator application
virtual void Mult(const Vector &x, Vector &y) const { y = x; }
/// Application of the transpose
virtual void MultTranspose(const Vector &x, Vector &y) const { y = x; }
};
/// Returns true if P is the identity prolongation, i.e. if it is either NULL or
/// an IdentityOperator.
inline bool IsIdentityProlongation(const Operator *P)
{
return !P || dynamic_cast<const IdentityOperator*>(P);
}
/// Scaled Operator B: x -> a A(x).
class ScaledOperator : public Operator
{
private:
const Operator &A_;
double a_;
public:
/// Create an operator which is a scalar multiple of A.
explicit ScaledOperator(const Operator *A, double a)
: Operator(A->Width(), A->Height()), A_(*A), a_(a) { }
/// Operator application
virtual void Mult(const Vector &x, Vector &y) const
{ A_.Mult(x, y); y *= a_; }
};
/** @brief The transpose of a given operator. Switches the roles of the methods
Mult() and MultTranspose(). */
class TransposeOperator : public Operator
{
private:
const Operator &A;
public:
/// Construct the transpose of a given operator @a *a.
TransposeOperator(const Operator *a)
: Operator(a->Width(), a->Height()), A(*a) { }
/// Construct the transpose of a given operator @a a.
TransposeOperator(const Operator &a)
: Operator(a.Width(), a.Height()), A(a) { }
/// Operator application. Apply the transpose of the original Operator.
virtual void Mult(const Vector &x, Vector &y) const
{ A.MultTranspose(x, y); }
/// Application of the transpose. Apply the original Operator.
virtual void MultTranspose(const Vector &x, Vector &y) const
{ A.Mult(x, y); }
};
/// General product operator: x -> (A*B)(x) = A(B(x)).
class ProductOperator : public Operator
{
const Operator *A, *B;
bool ownA, ownB;
mutable Vector z;
public:
ProductOperator(const Operator *A, const Operator *B, bool ownA, bool ownB);
virtual void Mult(const Vector &x, Vector &y) const
{ B->Mult(x, z); A->Mult(z, y); }
virtual void MultTranspose(const Vector &x, Vector &y) const
{ A->MultTranspose(x, z); B->MultTranspose(z, y); }
virtual ~ProductOperator();
};
/// The operator x -> R*A*P*x constructed through the actions of R^T, A and P
class RAPOperator : public Operator
{
private:
const Operator & Rt;
const Operator & A;
const Operator & P;
mutable Vector Px;
mutable Vector APx;
MemoryClass mem_class;
public:
/// Construct the RAP operator given R^T, A and P.
RAPOperator(const Operator &Rt_, const Operator &A_, const Operator &P_);
virtual MemoryClass GetMemoryClass() const { return mem_class; }
/// Operator application.
virtual void Mult(const Vector & x, Vector & y) const
{ P.Mult(x, Px); A.Mult(Px, APx); Rt.MultTranspose(APx, y); }
/// Application of the transpose.
virtual void MultTranspose(const Vector & x, Vector & y) const
{ Rt.Mult(x, APx); A.MultTranspose(APx, Px); P.MultTranspose(Px, y); }
};
/// General triple product operator x -> A*B*C*x, with ownership of the factors.
class TripleProductOperator : public Operator
{
const Operator *A;
const Operator *B;
const Operator *C;
bool ownA, ownB, ownC;
mutable Vector t1, t2;
MemoryClass mem_class;
public:
TripleProductOperator(const Operator *A, const Operator *B,
const Operator *C, bool ownA, bool ownB, bool ownC);
virtual MemoryClass GetMemoryClass() const { return mem_class; }
virtual void Mult(const Vector &x, Vector &y) const
{ C->Mult(x, t1); B->Mult(t1, t2); A->Mult(t2, y); }
virtual void MultTranspose(const Vector &x, Vector &y) const
{ A->MultTranspose(x, t2); B->MultTranspose(t2, t1); C->MultTranspose(t1, y); }
virtual ~TripleProductOperator();
};
/** @brief Square Operator for imposing essential boundary conditions using only
the action, Mult(), of a given unconstrained Operator.
Square operator constrained by fixing certain entries in the solution to
given "essential boundary condition" values. This class is used by the
general, matrix-free system formulation of Operator::FormLinearSystem. */
class ConstrainedOperator : public Operator
{
protected:
Array<int> constraint_list; ///< List of constrained indices/dofs.
Operator *A; ///< The unconstrained Operator.
bool own_A; ///< Ownership flag for A.
mutable Vector z, w; ///< Auxiliary vectors.
MemoryClass mem_class;
public:
/** @brief Constructor from a general Operator and a list of essential
indices/dofs.
Specify the unconstrained operator @a *A and a @a list of indices to
constrain, i.e. each entry @a list[i] represents an essential-dof. If the
ownership flag @a own_A is true, the operator @a *A will be destroyed
when this object is destroyed. */
ConstrainedOperator(Operator *A, const Array<int> &list, bool own_A = false);
/// Returns the type of memory in which the solution and temporaries are stored.
virtual MemoryClass GetMemoryClass() const { return mem_class; }
/** @brief Eliminate "essential boundary condition" values specified in @a x
from the given right-hand side @a b.
Performs the following steps:
z = A((0,x_b)); b_i -= z_i; b_b = x_b;
where the "_b" subscripts denote the essential (boundary) indices/dofs of
the vectors, and "_i" -- the rest of the entries. */
void EliminateRHS(const Vector &x, Vector &b) const;
/** @brief Constrained operator action.
Performs the following steps:
z = A((x_i,0)); y_i = z_i; y_b = x_b;
where the "_b" subscripts denote the essential (boundary) indices/dofs of
the vectors, and "_i" -- the rest of the entries. */
virtual void Mult(const Vector &x, Vector &y) const;
/// Destructor: destroys the unconstrained Operator, if owned.
virtual ~ConstrainedOperator() { if (own_A) { delete A; } }
};
/** @brief Rectangular Operator for imposing essential boundary conditions on
the input space using only the action, Mult(), of a given unconstrained
Operator.
Rectangular operator constrained by fixing certain entries in the solution
to given "essential boundary condition" values. This class is used by the
general matrix-free formulation of Operator::FormRectangularLinearSystem. */
class RectangularConstrainedOperator : public Operator
{
protected:
Array<int> trial_constraints, test_constraints;
Operator *A;
bool own_A;
mutable Vector z, w;
MemoryClass mem_class;
public:
/** @brief Constructor from a general Operator and a list of essential
indices/dofs.
Specify the unconstrained operator @a *A and two lists of indices to
constrain, i.e. each entry @a trial_list[i] represents an essential trial
dof. If the ownership flag @a own_A is true, the operator @a *A will be
destroyed when this object is destroyed. */
RectangularConstrainedOperator(Operator *A, const Array<int> &trial_list,
const Array<int> &test_list, bool own_A = false);
/// Returns the type of memory in which the solution and temporaries are stored.
virtual MemoryClass GetMemoryClass() const { return mem_class; }
/** @brief Eliminate columns corresponding to "essential boundary condition"
values specified in @a x from the given right-hand side @a b.
Performs the following steps:
b -= A((0,x_b));
b_j = 0
where the "_b" subscripts denote the essential (boundary) indices and the
"_j" subscript denotes the essential test indices */
void EliminateRHS(const Vector &x, Vector &b) const;
/** @brief Rectangular-constrained operator action.
Performs the following steps:
y = A((x_i,0));
y_j = 0
where the "_i" subscripts denote all the nonessential (boundary) trial
indices and the "_j" subscript denotes the essential test indices */
virtual void Mult(const Vector &x, Vector &y) const;
virtual void MultTranspose(const Vector &x, Vector &y) const;
virtual ~RectangularConstrainedOperator() { if (own_A) { delete A; } }
};
/** @brief PowerMethod helper class to estimate the largest eigenvalue of an
operator using the iterative power method. */
class PowerMethod
{
Vector v1;
#ifdef MFEM_USE_MPI
MPI_Comm comm;
#endif
public:
#ifdef MFEM_USE_MPI
PowerMethod() : comm(MPI_COMM_NULL) {}
#else
PowerMethod() {}
#endif
#ifdef MFEM_USE_MPI
PowerMethod(MPI_Comm _comm) : comm(_comm) {}
#endif
/// @brief Returns an estimate of the largest eigenvalue of the operator \p opr
/// using the iterative power method.
/** \p v0 is being used as the vector for the iterative process and will contain
the eigenvector corresponding to the largest eigenvalue after convergence.
The maximum number of iterations may set with \p numSteps, the relative
tolerance with \p tolerance and the seed of the random initialization of
\p v0 with \p seed. */
double EstimateLargestEigenvalue(Operator& opr, Vector& v0,
int numSteps = 10, double tolerance = 1e-8,
int seed = 12345);
};
}
#endif