chebyshev.cpp serif/solver/preconditioner/backend/mfem/inverse/chebyshev.hpp utility cmath mfem/linalg/solvers.hpp serif/solver/preconditioner/backend/mfem/inverse/validation.hpp serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::backend serif::solver::preconditioner::backend::mfem #include"serif/solver/preconditioner/backend/mfem/inverse/chebyshev.hpp" #include<utility> #include<cmath> #include"mfem/linalg/solvers.hpp" #include"serif/solver/preconditioner/backend/mfem/inverse/validation.hpp" namespaceserif::solver::preconditioner::backend::mfem { namespace { classChebyshevInversefinal:public::mfem::Operator { public: ChebyshevInverse(OperatorHandlemass,conststd::span<constdouble>diagonal,conststrategies::inverse::Chebyshev&options):Operator(mass->Height()),m_mass(std::move(mass)),m_diagonal(Height()),m_input(Height()) { for(intindex=0;index<Height();++index) { m_diagonal[index]=diagonal[index]; } m_smoother=std::make_unique<::mfem::OperatorChebyshevSmoother>(*m_mass,m_diagonal,m_essential_dofs,options.order, #ifdefMFEM_USE_MPI MPI_COMM_NULL, #endif options.power_iterations,options.power_tolerance,options.power_seed); m_smoother->iterative_mode=false; } voidMult(const::mfem::Vector&input,::mfem::Vector&output)constoverride { detail::require_application_size(*this,input,output); const::mfem::Vector*source=&input; if(detail::vectors_overlap(input,output)) { m_input=input; source=&m_input; } output=0.0; m_smoother->Mult(*source,output); } voidMultTranspose(const::mfem::Vector&input,::mfem::Vector&output)constoverride { Mult(input,output); } private: OperatorHandlem_mass; ::mfem::Vectorm_diagonal; ::mfem::Array<int>m_essential_dofs; std::unique_ptr<::mfem::OperatorChebyshevSmoother>m_smoother; mutable::mfem::Vectorm_input; }; }//namespace std::expected<Inverse,Failure>try_chebyshev_inverse(OperatorHandlemass,conststd::span<constdouble>diagonal,conststrategies::inverse::Chebyshev&options) { usingenumutils::errors::SERiFErrorCode; if(constautovalid=detail::check_square(mass.get());!valid) { returnstd::unexpected(valid.error()); } if(diagonal.size()!=static_cast<std::size_t>(mass->Height())) { returndetail::failure<PRECONDITIONER_SIZE_MISMATCH>("ThemassactionanditsChebyshevdiagonalmustdescribethesamecoordinates."); } if(options.order<1||options.order>5||options.power_iterations<=0||options.power_seed<=0|| !std::isfinite(options.power_tolerance)||options.power_tolerance<=0.0||options.power_tolerance>=1.0) { returndetail::failure<PRECONDITIONER_INVALID_OPTIONS>("Chebyshevrequirespolynomialorder1–5,positivepoweriterations/seed,andafinitepowertolerancein(0,1)."); } for(constdoubleentry:diagonal) { if(!std::isfinite(entry)||entry<=0.0||!std::isfinite(1.0/entry)) { returndetail::failure<PRECONDITIONER_INVALID_OPERATOR>("Chebyshevrequiresastrictlypositivefinitemassdiagonalwithrepresentablereciprocals.Rescalethemasscoordinatesifnecessary."); } } returnInverse{.action=std::make_shared<constChebyshevInverse>(std::move(mass),diagonal,options)}; } }//namespaceserif::solver::preconditioner::backend::mfem