// Copyright (c) 2010-2023, 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_AUXILIARY #define MFEM_AUXILIARY #include "../config/config.hpp" #ifdef MFEM_USE_MPI #include "solvers.hpp" namespace mfem { // forward declarations class Coefficient; class MatrixCoefficient; class ParMesh; class ParBilinearForm; class ParDiscreteLinearOperator; /** @brief Auxiliary space solvers for MatrixFreeAMS preconditioner Given an operator A and a transfer G, create a solver that approximates (G^T A G)^{-1}. Used for two different auxiliary spaces in the AMS cycle. The produced solver is based on a low-order refined discretization for the high-order H1 problem. */ class MatrixFreeAuxiliarySpace : public Solver { public: /** @brief Pi space constructor In the AMS framework this auxiliary space has two coefficients. @param mesh_lor Low-order refined auxiliary mesh @param alpha_coeff Coefficient on curl-curl term (1 if null) @param beta_coeff Coefficient on mass term (1 if null) @param beta_mcoeff Matrix coefficient on mass term @param ess_bdr Attributes for essential boundaries @param curlcurl_oper High-order operator for the system @param pi Identity interpolation operator @param useAmgX_ Use AmgX instead of hypre for auxiliary solves @param cg_iterations Number of CG iterations used to invert auxiliary system, choosing 0 means to use a single V-cycle */ MatrixFreeAuxiliarySpace( ParMesh& mesh_lor, Coefficient* alpha_coeff, Coefficient* beta_coeff, MatrixCoefficient* beta_mcoeff, Array& ess_bdr, Operator& curlcurl_oper, Operator& pi, #ifdef MFEM_USE_AMGX bool useAmgX_, #endif int cg_iterations = 0); /** @brief G space constructor This has one coefficient in the AMS framework. @param mesh_lor Low-order refined auxiliary mesh @param beta_coeff Coefficient on mass term (1 if null) @param beta_mcoeff Matrix coefficient on mass term @param ess_bdr Attributes for essential boundaries @param curlcurl_oper High-order operator for the system @param g Gradient interpolation operator @param useAmgX_ Use AmgX instead of hypre for auxiliary solves @param cg_iterations Number of CG iterations used to invert auxiliary system, choosing 0 means to use a single V-cycle */ MatrixFreeAuxiliarySpace( ParMesh& mesh_lor, Coefficient* beta_coeff, MatrixCoefficient* beta_mcoeff, Array& ess_bdr, Operator& curlcurl_oper, Operator& g, #ifdef MFEM_USE_AMGX bool useAmgX_, #endif int cg_iterations = 1); ~MatrixFreeAuxiliarySpace(); void Mult(const Vector& x, Vector& y) const; void SetOperator(const Operator& op) {} private: /** @brief Helper routine for constructors. @param system_dimension is passed to HypreBoomerAMG::SetSystemsOptions */ void SetupAMG(int system_dimension); void SetupVCycle(); /// inner_cg_iterations > 99 applies an exact solve here void SetupCG(Operator& curlcurl_oper, Operator& conn, int inner_cg_iterations); MPI_Comm comm; Array ess_tdof_list; HypreParMatrix * lor_matrix; Solver * lor_pc; Operator* matfree; CGSolver* cg; Operator* aspacewrapper; #ifdef MFEM_USE_AMGX const bool useAmgX; #endif mutable int inner_aux_iterations; }; /** @brief Perform AMS cycle with generic Operator objects. Most users should use MatrixFreeAMS, which wraps this. */ class GeneralAMS : public Solver { public: /** @brief Constructor. Most of these arguments just need a Mult() operation, but pi and g also require MultTranspose() */ GeneralAMS(const Operator& curlcurl_op_, const Operator& pi_, const Operator& gradient_, const Operator& pispacesolver_, const Operator& gspacesolver_, const Operator& smoother_, const Array& ess_tdof_list_); virtual ~GeneralAMS(); /// in principle this should set A_ = op; void SetOperator(const Operator &op) {} virtual void Mult(const Vector& x, Vector& y) const; private: const Operator& curlcurl_op; const Operator& pi; const Operator& gradient; const Operator& pispacesolver; const Operator& gspacesolver; const Operator& smoother; const Array ess_tdof_list; void FormResidual(const Vector& rhs, const Vector& x, Vector& residual) const; }; /** @brief An auxiliary Maxwell solver for a high-order curl-curl system without high-order assembly. The auxiliary space solves are done using a low-order refined approach, but all the interpolation operators, residuals, etc. are done in a matrix-free manner. See Barker and Kolev, Matrix-free preconditioning for high-order H(curl) discretizations (https://doi.org/10.1002/nla.2348) */ class MatrixFreeAMS : public Solver { public: /** @brief Construct matrix-free AMS preconditioner @param aform BilinearForm for curl-curl problem, generally will have a CurlCurlIntegrator and possibly a VectorFEMassIntegrator. @param oper Operator to precondition. @param nd_fespace Underlying Nedelec finite element space. @param alpha_coeff Coefficient on curl-curl term in Maxwell problem (can be null, in which case constant 1 is assumed) @param beta_coeff (scalar) coefficient on mass term in Maxwell problem @param beta_mcoeff (matrix) coefficient on mass term @param ess_bdr Boundary *attributes* that are marked essential. In contrast to other MFEM cases, these are *attributes* not dofs, because we need to apply these boundary conditions to different bilinear forms. @param useAmgX Use AmgX (instead of hypre) for LOR problems @param inner_pi_its Number of CG iterations on auxiliary pi space, may need more for difficult coefficients @param inner_g_its Number of CG iterations on auxiliary g space, may need more for difficult coefficients @param nd_smoother Optional user-provided smoother for Nedelec space, this object takes ownership and will delete. */ MatrixFreeAMS(ParBilinearForm& aform, Operator& oper, ParFiniteElementSpace& nd_fespace, Coefficient* alpha_coeff, Coefficient* beta_coeff, MatrixCoefficient* beta_mcoeff, Array& ess_bdr, #ifdef MFEM_USE_AMGX bool useAmgX = false, #endif int inner_pi_its = 0, int inner_g_its = 1, Solver* nd_smoother = NULL); ~MatrixFreeAMS(); void SetOperator(const Operator &op) {} void Mult(const Vector& x, Vector& y) const { general_ams->Mult(x, y); } private: GeneralAMS * general_ams; Solver * smoother; ParDiscreteLinearOperator * pa_grad; OperatorPtr Gradient; ParDiscreteLinearOperator * pa_interp; OperatorPtr Pi; Solver * Gspacesolver; Solver * Pispacesolver; ParFiniteElementSpace * h1_fespace; ParFiniteElementSpace * h1_fespace_d; }; } // namespace mfem #endif // MFEM_USE_MPI #endif