surface.hpp serif/solver/preconditioner/recipes/surface.hpp serif/solver/preconditioner/computations/inverse.hpp serif/solver/preconditioner/backend/mfem/coupling.hpp serif/solver/preconditioner/backend/mfem/surface/fitted_h1.hpp src/include/serif/solver/preconditioner/graph.hpp serif serif::solver serif::solver::preconditioner serif::solver::preconditioner::computations #pragmaonce #include"serif/solver/preconditioner/recipes/surface.hpp" #include"serif/solver/preconditioner/computations/inverse.hpp" #include"serif/solver/preconditioner/backend/mfem/coupling.hpp" #include"serif/solver/preconditioner/backend/mfem/surface/fitted_h1.hpp" namespaceserif::solver::preconditioner::computations { template<typenameField,typenameRow,typenameStrategy,typenameBackend> requires(!std::same_as<Strategy,strategies::surface::ReferenceSurfaceMass>) [[nodiscard]]autosurface_target(constSurfacePreconditioner<Field,Row,Strategy,Backend>&choice) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,Strategy,Backend>; usingTargets=backend::mfem::SurfaceTargets; returnmake_computation<keys::SurfaceTarget<typenameRecipe::Rows,typenameRecipe::Values>,InputList<keys::Block<typenameRecipe::Rows,typenameRecipe::Values>>>( [target=choice.surface.target](constoperators::backend::mfem::LinearizedBlock&physical)->std::expected<Targets,Failure> { if(target!=strategies::surface::CalibrationTarget::surface_jacobian) { returnstd::unexpected(Failure{.code=utils::errors::SERiFErrorCode::PRECONDITIONER_INCOMPATIBLE_STRATEGY,.message="AstandalonesurfacefitrequiresthesurfaceJacobiantarget.Coupleittoamaterialrecipetofitmaterialrelaxation."}); } returnTargets{.surface_jacobian=physical.action()}; }); } template<typenameField,typenameRow,typenameStrategy,typenameBackend,typenameMaterial> requires(!std::same_as<Strategy,strategies::surface::ReferenceSurfaceMass>) [[nodiscard]]autosurface_target(constSurfacePreconditioner<Field,Row,Strategy,Backend>&choice,constMaterial&) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,Strategy,Backend>; usingBlock=operators::backend::mfem::LinearizedBlock; usingTargets=backend::mfem::SurfaceTargets; returnmake_computation<keys::SurfaceTarget<typenameRecipe::Rows,typenameRecipe::Values>,InputList<keys::Block<typenameRecipe::Rows,typenameRecipe::Values>,typenameMaterial::Result,keys::Block<typename Material::Rows, typename Recipe::Values>,keys::Block<typename Recipe::Rows, typename Material::Values>>>( [target=choice.surface.target](constBlock&physical,constbackend::mfem::Inverse&material,constBlock&material_from_surface,constBlock&surface_from_material)->std::expected<Targets,Failure> { if(target==strategies::surface::CalibrationTarget::surface_jacobian) { returnTargets{.surface_jacobian=physical.action()}; } if(target!=strategies::surface::CalibrationTarget::material_schur) { returnstd::unexpected(Failure{.code=utils::errors::SERiFErrorCode::PRECONDITIONER_INVALID_OPTIONS,.message="ChoosethesurfaceJacobianormaterialSchurtargetforsurfacecalibration."}); } constautoschur=backend::mfem::try_schur_operator(physical.action(),material,{.first_from_second=material_from_surface.action(),.second_from_first=surface_from_material.action()}); if(!schur) { returnstd::unexpected(schur.error()); } returnTargets{.material_schur=*schur}; }); } template<typenameField,typenameRow,typenameStrategy,typenameBackend> requires(!std::same_as<Strategy,strategies::surface::FittedSurfaceH1>) [[nodiscard]]autosurface_mass(constSurfacePreconditioner<Field,Row,Strategy,Backend>&choice) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,Strategy,Backend>; usingResult=keys::SurfaceMassInverse<typenameRecipe::Rows,typenameRecipe::Values>; ifconstexpr(std::same_as<Strategy,strategies::surface::ReferenceSurfaceMass>) { returnmake_computation<Result,InputList<keys::SurfaceMetric<typenameRecipe::Values>>>( [options=choice.surface](conststd::vector<double>&metric) { returnbackend::mfem::try_reference_surface_mass_inverse(metric,options); }); } else { returnmake_computation<Result,InputList<keys::SurfaceMetric<typenameRecipe::Values>,keys::SurfaceTarget<typenameRecipe::Rows,typenameRecipe::Values>>>( [options=choice.surface](conststd::vector<double>&metric,constbackend::mfem::SurfaceTargets&targets) { returnbackend::mfem::try_calibrated_surface_mass_inverse(metric,targets,options); }); } } template<typenameField,typenameRow,typenameBackend> [[nodiscard]]autosurface_h1_fit(constSurfacePreconditioner<Field,Row,strategies::surface::FittedSurfaceH1,Backend>&choice) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,strategies::surface::FittedSurfaceH1,Backend>; returnmake_computation<keys::SurfaceH1Fit<typenameRecipe::Rows,typenameRecipe::Values>,InputList<keys::SurfaceMatrices<typenameRecipe::Values>,keys::SurfaceTarget<typenameRecipe::Rows,typenameRecipe::Values>>>( [options=choice.surface](conststd::shared_ptr<constbackend::mfem::SurfaceH1Matrices>&matrices,constbackend::mfem::SurfaceTargets&targets)->std::expected<backend::mfem::FittedSurfaceOperator,Failure> { if(!matrices) { returnstd::unexpected(Failure{.code=utils::errors::SERiFErrorCode::PRECONDITIONER_INVALID_OPERATOR,.message="SurfaceH1preparationrequiresacceptedreferencemassandstiffnessmatrices."}); } returnbackend::mfem::try_fitted_surface_h1(*matrices,targets,options); }); } template<typenameField,typenameRow,typenameBackend> [[nodiscard]]autosurface_positive_inverse(constSurfacePreconditioner<Field,Row,strategies::surface::FittedSurfaceH1,Backend>&choice) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,strategies::surface::FittedSurfaceH1,Backend>; returnmake_computation<keys::SurfacePositiveInverse<typenameRecipe::Rows,typenameRecipe::Values>,InputList<keys::SurfaceH1Fit<typenameRecipe::Rows,typenameRecipe::Values>>>( [strategy=choice.inverse](constbackend::mfem::FittedSurfaceOperator&fitted) { returninvert_matrix(fitted.positive_operator,strategy); }); } template<typenameField,typenameRow,typenameStrategy,typenameBackend> [[nodiscard]]autosurface_inverse(constSurfacePreconditioner<Field,Row,Strategy,Backend>&) { usingnamespaceutils::dependencies; usingRecipe=SurfacePreconditioner<Field,Row,Strategy,Backend>; ifconstexpr(std::same_as<Strategy,strategies::surface::FittedSurfaceH1>) { returnmake_computation<typenameRecipe::Result,InputList<keys::SurfaceH1Fit<typenameRecipe::Rows,typenameRecipe::Values>,keys::SurfacePositiveInverse<typenameRecipe::Rows,typenameRecipe::Values>>>( [](constbackend::mfem::FittedSurfaceOperator&fitted,constbackend::mfem::Inverse&positive) { returnbackend::mfem::try_signed_surface_inverse(positive,fitted.fit.sign); }); } else { returnmake_computation<typenameRecipe::Result,InputList<keys::SurfaceMassInverse<typenameRecipe::Rows,typenameRecipe::Values>>>( [](constbackend::mfem::SurfaceMassInverse&mass) { returnmass.inverse; }); } } }//namespaceserif::solver::preconditioner::computations