ordering.hpp limits vector serif/backend/mfem/operators/linearized_block.hpp serif/operators/linearized_system_view.hpp serif/discretization/blocks/system_layout.hpp serif/discretization/blocks/keys.hpp serif/backend/mfem/solver/preconditioner/border.hpp serif/utils/dependencies/computation.hpp src/compile_time_checks/serif/solver/preconditioner/layout.cpp src/include/serif/backend/mfem/solver/preconditioner/graph.hpp serif::solver::preconditioner::keys::Preconditioner serif::solver::preconditioner::computations::detail::PhysicalSources< utils::dependencies::KeyList< Keys... > > serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::keys serif::solver::preconditioner::computations serif::solver::preconditioner::computations::detail #pragmaonce #include<limits> #include<vector> #include"serif/backend/mfem/operators/linearized_block.hpp" #include"serif/operators/linearized_system_view.hpp" #include"serif/discretization/blocks/system_layout.hpp" #include"serif/discretization/blocks/keys.hpp" #include"serif/backend/mfem/solver/preconditioner/border.hpp" #include"serif/utils/dependencies/computation.hpp" namespaceserif::solver::preconditioner::keys { usingLayout=discretization::blocks::keys::Layout; structPreconditioner { }; }//namespaceserif::solver::preconditioner::keys namespaceserif::solver::preconditioner::computations { namespacedetail { template<typenameKey> inlineconstexprboolis_physical_block=false; template<typenameRows,typenameValues> inlineconstexprboolis_physical_block<operators::PhysicalBlock<Rows, Values>>=true; template<typenameKeys> structPhysicalSources; template<typename...Keys> structPhysicalSources<utils::dependencies::KeyList<Keys...>> { usingType=utils::dependencies::CombinedKeyList<std::conditional_t<is_physical_block<Keys>,utils::dependencies::KeyList<Keys>,utils::dependencies::KeyList<>>...>; }; }//namespacedetail template<discretization::blocks::RepresentedValueKindKind,typenameLayout,typename...Coordinates> [[nodiscard]]std::size_tselected_size(constLayout&layout,utils::dependencies::KeyList<Coordinates...>) { conststd::array<std::size_t,sizeof...(Coordinates)>sizes{layout.templatesize<Kind,Coordinates>()...}; returndiscretization::blocks::checked_block_size(sizes); } template<typenameKey,typenameLayout> [[nodiscard]]std::expected<void,Failure>validate_physical_layout(constLayout&layout,constoperators::backend::mfem::LinearizedBlock&block) { usingKind=discretization::blocks::RepresentedValueKind; if(selected_size<Kind::residual>(layout,typenameKey::Rows{})!=static_cast<std::size_t>(block.action()->Height())|| selected_size<Kind::value>(layout,typenameKey::Values{})!=static_cast<std::size_t>(block.action()->Width())) { returnstd::unexpected(Failure{utils::errors::SERiFErrorCode::PRECONDITIONER_SIZE_MISMATCH, "Aphysicalblockdoesnotmatchthesizesofitsnamedequationrowsandunknowncoordinates.Correctthesharedlayoutorselectedblock."}); } return{}; } template<discretization::blocks::RepresentedValueKindKind,typenameLayout,typename...Coordinates> [[nodiscard]]std::expected<std::vector<int>,Failure>ordered_indices(constLayout&layout,utils::dependencies::KeyList<Coordinates...>) { conststd::size_tcount=layout.templatetotal_size<Kind>(); if(count>static_cast<std::size_t>(std::numeric_limits<int>::max())) { returnstd::unexpected(Failure{utils::errors::SERiFErrorCode::PRECONDITIONER_SIZE_MISMATCH,"PackedsystemexceedstheMFEMindexrange."}); } std::vector<int>indices(count,-1); intgrouped_offset=0; constautoappend=[&]<typenameCoordinate>() { conststd::size_toffset=layout.templateoffset<Kind,Coordinate>(); conststd::size_tsize=layout.templatesize<Kind,Coordinate>(); for(std::size_tindex=0;index<size;++index) { indices[offset+index]=grouped_offset++; } }; (append.templateoperator()<Coordinates>(),...); returnindices; } template<typenameRecipe,typenameLayout,typename...PhysicalKeys> [[nodiscard]]autoordering(utils::dependencies::KeyList<PhysicalKeys...>) { usingnamespaceutils::dependencies; usingKind=discretization::blocks::RepresentedValueKind; static_assert(key_count_v<CombinedKeyList<typenameRecipe::Rows,typenameLayout::Residuals>>==key_count_v<typenameRecipe::Rows>&& key_count_v<typenameRecipe::Rows>==key_count_v<typenameLayout::Residuals>, "Thepreconditionermustcovereveryresidualidentityexactlyonce."); static_assert(key_count_v<CombinedKeyList<typenameRecipe::Values,typenameLayout::Values>>==key_count_v<typenameRecipe::Values>&& key_count_v<typenameRecipe::Values>==key_count_v<typenameLayout::Values>, "Thepreconditionermustcovereverystateidentityexactlyonce."); returnmake_computation<keys::Preconditioner,InputList<typenameRecipe::Result,keys::Layout,PhysicalKeys...>>( [](constbackend::mfem::Inverse&inverse,constLayout&layout,constauto&...blocks)->std::expected<backend::mfem::Inverse,Failure> { std::expected<void,Failure>validation; constautovalidate=[&]<typenameKey>(Key,constauto&block) { if(validation) { validation=validate_physical_layout<Key>(layout,block); } }; (validate(PhysicalKeys{},blocks),...); if(!validation) { returnstd::unexpected(validation.error()); } autorows=ordered_indices<Kind::value>(layout,typenameRecipe::Values{}); autocolumns=ordered_indices<Kind::residual>(layout,typenameRecipe::Rows{}); if(!rows) { returnstd::unexpected(rows.error()); } if(!columns) { returnstd::unexpected(columns.error()); } if(inverse.action->Height()!=static_cast<int>(rows->size())||inverse.action->Width()!=static_cast<int>(columns->size())) { returnstd::unexpected(Failure{utils::errors::SERiFErrorCode::PRECONDITIONER_SIZE_MISMATCH,"Thecomposedinversedoesnotmatchthesharedsystemlayout."}); } autoordered=backend::mfem::try_restrict_operator(inverse.action,*rows,*columns); if(!ordered) { returnstd::unexpected(ordered.error()); } returnbackend::mfem::Inverse{.action=*ordered,.contract=inverse.contract}; }); } }//namespaceserif::solver::preconditioner::computations