// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ /*! * \file * \copydoc Opm::Linear::SuperLUBackend */ #ifndef EWOMS_SUPER_LU_BACKEND_HH #define EWOMS_SUPER_LU_BACKEND_HH #if HAVE_SUPERLU #include #include #include #include #include #include #include namespace Opm::Properties::TTag { struct SuperLULinearSolver {}; } // namespace Opm::Properties::TTag namespace Opm { namespace Linear { template class SuperLUSolve_; /*! * \ingroup Linear * \brief A linear solver backend for the SuperLU sparse matrix library. */ template class SuperLUBackend { using Scalar = GetPropType; using Simulator = GetPropType; using SparseMatrixAdapter = GetPropType; using Matrix = typename SparseMatrixAdapter::block_type; static_assert(std::is_same::value, "The SuperLU linear solver backend requires the IstlSparseMatrixAdapter"); public: SuperLUBackend(Simulator&) {} static void registerParameters() { EWOMS_REGISTER_PARAM(TypeTag, int, LinearSolverVerbosity, "The verbosity level of the linear solver"); } /*! * \brief Causes the solve() method to discared the structure of the linear system of * equations the next time it is called. * * Since the SuperLU backend does not create any internal matrices, this is a no-op. */ void eraseMatrix() { } void prepare(const SparseMatrixAdapter& M, const Vector& b) { } void setResidual(const Vector& b) { b_ = &b; } void getResidual(Vector& b) const { b = *b_; } void setMatrix(const SparseMatrixAdapter& M) { M_ = &M; } bool solve(Vector& x) { return SuperLUSolve_::solve_(*M_, x, *b_); } private: const Matrix* M_; Vector* b_; }; template class SuperLUSolve_ { public: static bool solve_(const Matrix& A, Vector& x, const Vector& b) { Vector bTmp(b); int verbosity = EWOMS_GET_PARAM(TypeTag, int, LinearSolverVerbosity); Dune::InverseOperatorResult result; Dune::SuperLU solver(A, verbosity > 0); solver.apply(x, bTmp, result); if (result.converged) { // make sure that the result only contains finite values. Scalar tmp = 0; for (unsigned i = 0; i < x.size(); ++i) { const auto& xi = x[i]; for (unsigned j = 0; j < Vector::block_type::dimension; ++j) tmp += xi[j]; } result.converged = std::isfinite(tmp); } return result.converged; } }; // the following is required to make the SuperLU adapter of dune-istl happy with // quadruple precision math on Dune 2.4. this is because the most which SuperLU can // handle is double precision (i.e., the linear systems of equations are always solved // with at most double precision if chosing SuperLU as the linear solver...) #if HAVE_QUAD template class SuperLUSolve_<__float128, TypeTag, Matrix, Vector> { public: static bool solve_(const Matrix& A, Vector& x, const Vector& b) { static const int numEq = getPropValue(); using DoubleEqVector = Dune::FieldVector; using DoubleEqMatrix = Dune::FieldMatrix; using DoubleVector = Dune::BlockVector; using DoubleMatrix = Dune::BCRSMatrix; // copy the inputs into the double precision data structures DoubleVector bDouble(b); DoubleVector xDouble(x); DoubleMatrix ADouble(A); bool res = SuperLUSolve_::solve_(ADouble, xDouble, bDouble); // copy the result back into the quadruple precision vector. x = xDouble; return res; } }; #endif } // namespace Linear } // namespace Opm namespace Opm::Properties { template struct LinearSolverVerbosity { static constexpr int value = 0; }; template struct LinearSolverBackend { using type = Opm::Linear::SuperLUBackend; }; } // namespace Opm::Properties #endif // HAVE_SUPERLU #endif