diagonal.cpp serif/solver/preconditioner/backend/mfem/inverse/diagonal.hpp utility cmath limits functional vector serif/solver/preconditioner/backend/mfem/inverse/validation.hpp serif/solver/preconditioner/backend/mfem/inverse/regularization.hpp serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::backend serif::solver::preconditioner::backend::mfem #include"serif/solver/preconditioner/backend/mfem/inverse/diagonal.hpp" #include<utility> #include<cmath> #include<limits> #include<functional> #include<vector> #include"serif/solver/preconditioner/backend/mfem/inverse/validation.hpp" #include"serif/solver/preconditioner/backend/mfem/inverse/regularization.hpp" namespaceserif::solver::preconditioner::backend::mfem { namespace { classIdentityInversefinal:public::mfem::IdentityOperator { public: explicitIdentityInverse(constintsize):IdentityOperator(size) { } voidMult(const::mfem::Vector&input,::mfem::Vector&output)constoverride { detail::require_application_size(*this,input,output); detail::copy_coordinates(input,output); } voidMultTranspose(const::mfem::Vector&input,::mfem::Vector&output)constoverride { Mult(input,output); } }; classDiagonalInversefinal:public::mfem::Operator { public: explicitDiagonalInverse(std::vector<double>reciprocal):Operator(static_cast<int>(reciprocal.size())),m_reciprocal(std::move(reciprocal)) { } voidMult(const::mfem::Vector&input,::mfem::Vector&output)constoverride { detail::require_application_size(*this,input,output); if(detail::vectors_overlap(input,output)&&std::less<constdouble*>{}(input.GetData(),output.GetData())) { for(intindex=Height()-1;index>=0;--index) { output[index]=m_reciprocal[index]*input[index]; } return; } for(intindex=0;index<Height();++index) { output[index]=m_reciprocal[index]*input[index]; } } voidMultTranspose(const::mfem::Vector&input,::mfem::Vector&output)constoverride { Mult(input,output); } private: std::vector<double>m_reciprocal; }; }//namespace std::expected<Inverse,Failure>try_identity(constintsize) { usingenumutils::errors::SERiFErrorCode; if(size<=0) { returndetail::failure<PRECONDITIONER_SIZE_MISMATCH>("Anidentityinverserequiresapositivesize,received{}.",size); } returnInverse{.action=std::make_shared<constIdentityInverse>(size)}; } std::expected<Inverse,Failure>try_diagonal_inverse(conststd::span<constdouble>diagonal) { usingenumutils::errors::SERiFErrorCode; if(diagonal.empty()||diagonal.size()>static_cast<std::size_t>(std::numeric_limits<int>::max())) { returndetail::failure<PRECONDITIONER_SIZE_MISMATCH>("AdiagonalinverseneedsanonemptyMFEM-sizedcoordinateblock."); } std::vector<double>reciprocal(diagonal.size()); for(std::size_tindex=0;index<diagonal.size();++index) { if(!std::isfinite(diagonal[index])) { returndetail::failure<PRECONDITIONER_NONFINITE_VALUE>("Diagonalentry{}isnotfinite.Prepareafinitephysicaloperatorbeforeinversion.",index); } if(diagonal[index]==0.0) { returndetail::failure<PRECONDITIONER_SINGULAR_OPERATOR>("Diagonalentry{}iszero;thiscoordinatehasnoinverse.",index); } reciprocal[index]=1.0/diagonal[index]; if(!std::isfinite(reciprocal[index])) { returndetail::failure<PRECONDITIONER_NONFINITE_VALUE>("Thereciprocalofdiagonalentry{}isnotrepresentable.Rescalethesecoordinatesbeforepreparingtheinverse.",index); } } returnInverse{.action=std::make_shared<constDiagonalInverse>(std::move(reciprocal))}; } std::expected<Inverse,Failure>try_diagonal_inverse(conststd::span<constdouble>diagonal,conststrategies::inverse::Diagonal&options) { if(!options.regularization) { returntry_diagonal_inverse(diagonal); } constautoregularized=try_regularize_diagonal(diagonal,*options.regularization); if(!regularized) { returnstd::unexpected(regularized.error()); } returntry_diagonal_inverse(regularized->values); } }//namespaceserif::solver::preconditioner::backend::mfem