geometry.hpp algorithm memory tuple vector serif/backend/mfem/geometry/deformation/geometry_step.hpp serif/backend/mfem/mapping/domain_mapper.hpp serif/backend/mfem/model/graph.hpp serif/model/state.hpp serif/discretization/blocks/vector_view.hpp serif/solver/nonlinear/options.hpp src/include/serif/backend/mfem/solver/nonlinear/stellar_problem.hpp serif::solver::admissibility::backend::mfem::GeometrySamplingRules serif::solver::admissibility::backend::mfem::GeometryDirection serif serif::solver serif::solver::admissibility serif::solver::admissibility::backend serif::solver::admissibility::backend::mfem serif::solver::admissibility::backend::mfem::detail #pragmaonce #include<algorithm> #include<memory> #include<tuple> #include<vector> #include"serif/backend/mfem/geometry/deformation/geometry_step.hpp" #include"serif/backend/mfem/mapping/domain_mapper.hpp" #include"serif/backend/mfem/model/graph.hpp" #include"serif/model/state.hpp" #include"serif/discretization/blocks/vector_view.hpp" #include"serif/solver/nonlinear/options.hpp" namespaceserif::solver::admissibility::backend::mfem{ structGeometrySamplingRules{}; namespacedetail{ template<typenameEquation,typenameScope=typenameEquation::Test> [[nodiscard]]autoequation_rule_keys(){ return[]<std::size_t...Index>(std::index_sequence<Index...>){ returnutils::dependencies::KeyList<typename operators::backend::mfem::volume_keys::Scoped<Scope>::templateBasis<Index>...>{}; }(std::make_index_sequence<std::tuple_size_v<equations::ContributionsOf<Equation>>>{}); } [[nodiscard]]inlinestd::shared_ptr<conststd::vector<mapping::DMFixedMeshGeometry>>sample_reference_geometry( ::mfem::Mesh&mesh,constintelement,const::mfem::IntegrationRule&rule){ ::mfem::ElementTransformation&transformation=*mesh.GetElementTransformation(element); autosamples=std::make_shared<std::vector<mapping::DMFixedMeshGeometry>>(); samples->reserve(static_cast<std::size_t>(rule.GetNPoints())); for(intpoint=0;point<rule.GetNPoints();++point){ autogeometry=mapping::sample_fixed_mesh_geometry(transformation,rule.IntPoint(point)); if(!geometry){ returnnullptr; } samples->push_back(std::move(*geometry)); } returnsamples; } } template<typenameBound> [[nodiscard]]automake_geometry_computations(conststd::shared_ptr<constBound>&bound){ usingnamespaceutils::dependencies; ifconstexpr(!Bound::Plan::has_shape){returnstd::tuple{};} else{ //Thesurfacepotentialhasnovolumebasisbatch.Thegeneralgeometryrulesandeveryactive //interiorequation'srulesremainintheinspectionunion. usingInputs=decltype([]<typename...Equation>(utils::types::TypeList<Equation...>){ returnCombinedKeyList<decltype(detail::equation_rule_keys<Equation>())...>{}; }(typenameBound::Description::InteriorEquations::Equations{})); returnstd::tuple{make_computation<GeometrySamplingRules,Inputs>([bound](constauto&...basis){ std::vector<geometry::deformation::backend::mfem::GeometrySampleRule>rules; constauto&space=bound->discretization->templatebinding<discretization::blocks::displacement::vector>().space(); //Thereferencemeshisfixedforthelifeoftheserules,soitsgeometryissampledhereonce //ratherthanineveryNewtonsteplimit.EquationrulessharethesamplestheirBasisalreadyowns. for(intelement=0;element<space.GetNE();++element){ constauto*finite_element=space.GetFE(element); constintorder=std::max(finite_element->GetOrder()+2,2*space.GetMesh()->Dimension()*finite_element->GetOrder()); constauto&rule=::mfem::IntRules.Get(finite_element->GetGeomType(),order); rules.push_back({.element=element,.integration_rule=&rule, .reference_geometry=detail::sample_reference_geometry(*space.GetMesh(),element,rule)}); } constautoappend=[&](constauto&batch){ for(constauto&element:batch){ rules.push_back({.element=element->element,.integration_rule=element->rule, .reference_geometry=std::shared_ptr<conststd::vector<mapping::DMFixedMeshGeometry>>(element,&element->reference_geometry)}); } }; (append(basis),...); std::ranges::sort(rules,[](constauto&left,constauto&right){ if(left.element!=right.element){returnleft.element<right.element;} returnstd::less<const::mfem::IntegrationRule*>{}(left.integration_rule,right.integration_rule); }); constautoduplicate=std::ranges::unique(rules,[](constauto&left,constauto&right){ returnleft.element==right.element&&left.integration_rule==right.integration_rule; }); rules.erase(duplicate.begin(),duplicate.end()); returnrules; })}; } } classGeometryDirection{ public: template<typenameEvaluator,typenameLayout> [[nodiscard]]autolimit(constEvaluator&evaluator,constmodel::StellarState<Layout>&state,std::span<constdouble>direction, constdoublemaximum_step,constdoublesafety,constboolenabled) ->std::expected<geometry::deformation::GeometryStepLimit,geometry::deformation::DeformationFailure>{ geometry::deformation::GeometryStepLimitunrestricted{.step=maximum_step,.boundary_step=maximum_step}; m_geometry_ready=false; ifconstexpr(Evaluator::Plan::has_shape){ constauto&derivatives=evaluator.cache().templateget<model::computations::ShapeDerivatives>(); usingMap=std::remove_cvref_t<decltype(*derivatives.deformation->map)>; ifconstexpr(geometry::deformation::is_linear_deformation<Map>){ usingShape=discretization::blocks::surface_deformation::coefficients; usingDisplacement=discretization::blocks::displacement::vector; constauto&displacement=evaluator.binding().discretization->templatebinding<Displacement>(); constautoshape_direction=discretization::blocks::StateView<Layout, const double>(state.layout(),direction).templateget<Shape>(); ::mfem::Vectorshape(const_cast<double*>(shape_direction.data()),static_cast<int>(shape_direction.size())); ::mfem::Vectorreduced(displacement.size()); derivatives.tangent.action()->Mult(shape,reduced); m_displacement_direction=displacement.scatter_true(reduced); m_accepted_displacement=displacement.scatter_true(evaluator.cache().templateget<geometry::deformation::backend::mfem::volume_displacement_keys::Coefficients>()); m_rules=evaluator.cache().templateshare<GeometrySamplingRules>(); m_geometry_ready=true; if(enabled){ returnestimate(evaluator,maximum_step,safety); } } } returnunrestricted; } [[nodiscard]]doublenext(constauto&evaluator,constdoublestep,constBacktracking&options,constboolinverted)const{ if(!inverted||!m_geometry_ready){ returnstep*options.contraction; } constautogeometry=estimate(evaluator,step,options.fraction_to_boundary); if(!geometry){ returnstep*options.contraction; } returnnext_backtracking_step(step,geometry->minimum_determinant_at_accepted, geometry->minimum_determinant_at_maximum,true,options); } private: [[nodiscard]]autoestimate(constauto&evaluator,constdoublestep,constdoublesafety)const{ constauto&discretization=*evaluator.binding().discretization; returngeometry::deformation::backend::mfem::estimate_geometry_step_limit(discretization.mapper, discretization.templatebinding<discretization::blocks::displacement::vector>().space(),discretization.compactification, m_accepted_displacement,m_displacement_direction,*m_rules,{.maximum_step=step,.fraction_to_boundary=safety}); } ::mfem::Vectorm_accepted_displacement; ::mfem::Vectorm_displacement_direction; std::shared_ptr<conststd::vector<geometry::deformation::backend::mfem::GeometrySampleRule>>m_rules; boolm_geometry_ready{false}; }; }