coupling_selection.cpp serif/utils/error/nonfinite.hpp serif/backend/mfem/solver/preconditioner/border.hpp cmath utility vector mfem/linalg/vector.hpp serif/utils/error/errors.hpp serif/backend/mfem/solver/preconditioner/inverse/validation.hpp serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::backend serif::solver::preconditioner::backend::mfem #include"serif/utils/error/nonfinite.hpp" #include"serif/backend/mfem/solver/preconditioner/border.hpp" #include<cmath> #include<utility> #include<vector> #include"mfem/linalg/vector.hpp" #include"serif/utils/error/errors.hpp" #include"serif/backend/mfem/solver/preconditioner/inverse/validation.hpp" namespaceserif::solver::preconditioner::backend::mfem { namespace { usingutils::errors::SERiFErrorCode; usingdetail::failure; [[nodiscard]]boolvalid_indices(std::span<constint>indices,intsize) { if(size<0||indices.size()>static_cast<std::size_t>(size)) { returnfalse; } std::vector<bool>used(static_cast<std::size_t>(size)); for(constintindex:indices) { if(index<0||index>=size||used[static_cast<std::size_t>(index)]) { returnfalse; } used[static_cast<std::size_t>(index)]=true; } returntrue; } classSelectedOperatorfinal:public::mfem::Operator { public: SelectedOperator(OperatorHandleoperation,std::span<constint>rows,std::span<constint>columns):Operator(static_cast<int>(rows.size()),static_cast<int>(columns.size())),m_operation(std::move(operation)), m_rows(rows.begin(),rows.end()),m_columns(columns.begin(),columns.end()), m_input(m_operation->Width()),m_output(m_operation->Height()) { } voidMult(const::mfem::Vector&input,::mfem::Vector&output)constoverride { apply(input,output,false); } voidMultTranspose(const::mfem::Vector&input,::mfem::Vector&output)constoverride { apply(input,output,true); } private: voidapply(const::mfem::Vector&input,::mfem::Vector&output,booltranspose)const { usingnamespaceutils::errors; conststd::vector<int>&input_indices=transpose?m_rows:m_columns; conststd::vector<int>&output_indices=transpose?m_columns:m_rows; ::mfem::Vector&full_input=transpose?m_output:m_input; ::mfem::Vector&full_output=transpose?m_input:m_output; serif_ensure<SERiFErrorCode::PRECONDITIONER_SIZE_MISMATCH>(input.Size()==static_cast<int>(input_indices.size())&&output.Size()==static_cast<int>(output_indices.size()),"Arestrictedoperatorrequirespreallocatedvectorsmatchingtheselectedrowsandcolumns."); full_input=0.0; for(intindex=0;index<input.Size();++index) { serif_ensure<SERiFErrorCode::PRECONDITIONER_NONFINITE_VALUE,utils::errors::NonFiniteValue>(std::isfinite(input[index]),"Arestrictedoperatorrequiresfiniteinputs."); full_input[input_indices[static_cast<std::size_t>(index)]]=input[index]; } full_output=0.0; if(transpose) { m_operation->MultTranspose(full_input,full_output); } else { m_operation->Mult(full_input,full_output); } for(intindex=0;index<full_output.Size();++index) { serif_ensure<SERiFErrorCode::PRECONDITIONER_NONFINITE_VALUE,utils::errors::NonFiniteValue>(std::isfinite(full_output[index]),"Theunderlyingoperatorreturnednonfinitevaluesbeforecoordinaterestriction."); } for(intindex=0;index<output.Size();++index) { output[index]=full_output[output_indices[static_cast<std::size_t>(index)]]; } } OperatorHandlem_operation; std::vector<int>m_rows; std::vector<int>m_columns; mutable::mfem::Vectorm_input; mutable::mfem::Vectorm_output; }; }//namespace std::expected<OperatorHandle,Failure>try_restrict_operator(OperatorHandleoperation,std::span<constint>rows,std::span<constint>columns) { if(!operation) { returnfailure<SERiFErrorCode::PRECONDITIONER_INVALID_OPERATOR>("Acoordinaterestrictionrequiresanownedoperator."); } if(!valid_indices(rows,operation->Height())||!valid_indices(columns,operation->Width())) { returnfailure<SERiFErrorCode::PRECONDITIONER_SIZE_MISMATCH>("Selectedequationrowsandunknowncolumnsmusteachbedistinctandwithintheiroperatordimensions."); } returnstd::make_shared<SelectedOperator>(std::move(operation),rows,columns); } }//namespaceserif::solver::preconditioner::backend::mfem