nodal_inputs.hpp algorithm memory utility type_traits serif/discretization/backend/mfem/coefficient_tracking.hpp serif/discretization/backend/mfem/point_dofs.hpp serif/operators/backend/mfem/nodal_data.hpp serif/operators/backend/mfem/term_coefficients.hpp serif/utils/dependencies/dependency_context.hpp src/include/serif/operators/backend/mfem/nodal_computations.hpp serif::operators::backend::mfem::nodal_keys::Scoped serif::operators::backend::mfem::nodal_keys::Scoped::Bindings serif::operators::backend::mfem::nodal_keys::Scoped::Samples serif::operators::backend::mfem::nodal_keys::Scoped::Linearization serif::operators::backend::mfem::nodal_keys::Scoped::BorderLinearization serif::operators::backend::mfem::NodalBindings serif::operators::backend::mfem::NodalBindingTracking serif::operators::backend::mfem::SelectedNodalValues serif::operators::backend::mfem::NodalValueTracking serif serif::operators serif::operators::backend serif::operators::backend::mfem serif::operators::backend::mfem::nodal_keys #pragmaonce #include<algorithm> #include<memory> #include<utility> #include<type_traits> #include"serif/discretization/backend/mfem/coefficient_tracking.hpp" #include"serif/discretization/backend/mfem/point_dofs.hpp" #include"serif/operators/backend/mfem/nodal_data.hpp" #include"serif/operators/backend/mfem/term_coefficients.hpp" #include"serif/utils/dependencies/dependency_context.hpp" namespaceserif::operators::backend::mfem { namespacenodal_keys { template<typenameScope> structScoped { structBindings { }; structSamples { }; structLinearization { }; structBorderLinearization { }; }; usingLinearization=Scoped<void>::Linearization; usingBorderLinearization=Scoped<void>::BorderLinearization; template<typenameScope,typenameTest> usingSelectedInput=std::conditional_t<std::is_void_v<Scope>,Test,typenameScoped<Scope>::Samples>; }//namespacenodal_keys structNodalBindings { std::shared_ptr<constdiscretization::backend::mfem::DofSelection>selection; longnodes_sequence; [[nodiscard]]booloperator==(constNodalBindings&)const=default; }; structNodalBindingTracking { [[nodiscard]]NodalBindingscapture(constNodalBindings&input)const { usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(input.selection!=nullptr,"Nodalinputmetadatamustretainitsequation'srowselection."); input.selection->validate(); returninput; } [[nodiscard]]boolmatches(constNodalBindings&snapshot,constNodalBindings&input)const { returnsnapshot==capture(input); } [[nodiscard]]constvoid*identity(constNodalBindings&)const { returnnullptr; } }; template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> voidvalidate_nodal_selection(constNodalDiscretization<EquationT, SchemaT>&discretization) { usingnamespaceutils::errors; usingDiscretization=NodalDiscretization<EquationT, SchemaT>; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>(static_cast<bool>(discretization.selected_rows), "Anodaldiscretizationrequiresanon-nullrowselection."); constauto&selected_rows=*discretization.selected_rows; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>(&selected_rows.binding()==&discretization.residual_binding&&selected_rows.size()>0&& (Discretization::components==1||selected_rows.size()==Discretization::components), "Nodalrowsmustbelongtotheirresidualbinding;vectorconditionsselectonecompletepoint."); selected_rows.validate(); } template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> voidvalidate_nodal_discretization(constNodalDiscretization<EquationT,SchemaT>&discretization) { usingnamespaceutils::errors; validate_nodal_selection(discretization); constauto&residual_binding=discretization.residual_binding; constauto&selected_rows=*discretization.selected_rows; for(intelement=0;element<residual_binding.mesh().GetNE();++element) { serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>( dynamic_cast<const::mfem::NodalFiniteElement*>(residual_binding.space().GetFE(element))!=nullptr,"NodalvalueconditionsrequireanodalH1basis."); } ifconstexpr(discretization::domain::IsBoundary<equations::SupportOf<EquationT>>) { constautoexpected=discretization::backend::mfem::select_boundary_dofs<equations::SupportOf<EquationT>>(residual_binding); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>( selected_rows.size()==expected.size()&&std::equal(selected_rows.reduced_dofs().begin(),selected_rows.reduced_dofs().end(),expected.reduced_dofs().begin()), "Aboundaryequationrequiresthecompleteselectiononitsdeclaredsupport."); } elseifconstexpr(requires{EquationT::reference_position;}) { constautoexpected=discretization::backend::mfem::select_point_dofs(residual_binding,EquationT::reference_position); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>( selected_rows.tracks_coordinates()&&selected_rows.size()==expected.size()&& std::equal(selected_rows.reduced_dofs().begin(),selected_rows.reduced_dofs().end(),expected.reduced_dofs().begin()), "Apointequationrequiresitscompletecoordinate-trackedpointselection."); } } template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> [[nodiscard]]automake_nodal_discretization(constdiscretization::backend::mfem::TermBinding<typenameEquationT::Test,SchemaT>&residual_binding, discretization::backend::mfem::DofSelectionselected_rows) { constNodalDiscretization<EquationT, SchemaT>discretization{ .residual_binding=residual_binding,.selected_rows=std::make_shared<constdiscretization::backend::mfem::DofSelection>(std::move(selected_rows))}; validate_nodal_discretization(discretization); returndiscretization; } template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> requiresrequires{EquationT::reference_position;} [[nodiscard]]automake_point_discretization(constdiscretization::backend::mfem::TermBinding<typenameEquationT::Test,SchemaT>&residual_binding) { returnmake_nodal_discretization<EquationT>(residual_binding,discretization::backend::mfem::select_point_dofs(residual_binding,EquationT::reference_position)); } template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> requires(discretization::domain::IsBoundary<equations::SupportOf<EquationT>>&&discretization::blocks::SpatialTermTraits<typename EquationT::Test>::rank==0) [[nodiscard]]automake_boundary_discretization(constdiscretization::backend::mfem::TermBinding<typenameEquationT::Test,SchemaT>&residual_binding) { returnmake_nodal_discretization<EquationT>(residual_binding,discretization::backend::mfem::select_boundary_dofs<equations::SupportOf<EquationT>>(residual_binding)); } template<AffinePointEquationEquationT,discretization::domain::schema::IsSchemaSchemaT> [[nodiscard]]automake_point_border_discretization(constdiscretization::backend::mfem::TermBinding<typenameEquationT::Test,SchemaT>&residual_binding, constdiscretization::backend::mfem::TermBinding<typenameEquationT::Border,SchemaT>&border_binding) { usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::MISMATCHED_MESHING_MAPS,std::invalid_argument>(&residual_binding.mesh()==&border_binding.mesh(), "Pointcarrierandbordermustshareamesh."); returnPointBorderDiscretization<EquationT, SchemaT>{.nodal=make_point_discretization<EquationT>(residual_binding),.border_binding=border_binding}; } structSelectedNodalValues { std::shared_ptr<constdiscretization::backend::mfem::DofSelection>selected_rows; ::mfem::Vectorvalues; }; structNodalValueTracking:discretization::backend::mfem::CoefficientTracking { [[nodiscard]]constvoid*identity(constSelectedNodalValues&input)const { returninput.selected_rows.get(); } }; template<NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]SelectedNodalValuesselect_nodal_values(constNodalDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::errors; validate_nodal_selection(discretization); constauto&input=term_coefficients.templateget<typenameEquationT::Test>(); serif_ensure<SERiFErrorCode::CACHE_FE_BINDING_ERROR,std::invalid_argument>(&input.binding==&discretization.residual_binding, "Nodalcoefficientsmustusetheequation'sresidualbinding."); discretization.residual_binding.validate_values(input.values); SelectedNodalValuesselected{.selected_rows=discretization.selected_rows,.values=::mfem::Vector(discretization.selected_rows->size())}; for(intindex=0;index<selected.values.Size();++index) { selected.values[index]=input.values[discretization.selected_rows->reduced_dofs()[index]]; } returnselected; } template<typenameScope=void,NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_nodal_dependency_context(constNodalDiscretization<EquationT,SchemaT>&discretization,constCoefficientsT&term_coefficients) { returnutils::dependencies::make_dependency_context( utils::dependencies::own<nodal_keys::SelectedInput<Scope, typename EquationT::Test>>(select_nodal_values(discretization,term_coefficients),NodalValueTracking{})); } template<typenameScope=void,AffinePointEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_point_border_dependency_context(constPointBorderDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::errors; usingnamespaceutils::dependencies; serif_ensure<SERiFErrorCode::MISMATCHED_MESHING_MAPS,std::invalid_argument>(&discretization.nodal.residual_binding.mesh()==&discretization.border_binding.mesh(), "Pointcarrierandbordermustshareamesh."); constauto&border=term_coefficients.templateget<typenameEquationT::Border>(); serif_ensure<SERiFErrorCode::CACHE_FE_BINDING_ERROR,std::invalid_argument>(&border.binding==&discretization.border_binding, "Pointbordercoefficientsmustusetheequation'sscalarbinding."); discretization.border_binding.validate_values(border.values); returnmake_dependency_context( own<nodal_keys::SelectedInput<Scope, typename EquationT::Test>>(select_nodal_values(discretization.nodal,term_coefficients),NodalValueTracking{}), own<typenameEquationT::Border>(border,discretization::backend::mfem::CoefficientTracking{})); } template<typenameScope=void,NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_nodal_binding_input(constNodalDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::dependencies; usingnamespaceutils::errors; validate_nodal_selection(discretization); constauto&input=term_coefficients.templateget<typenameEquationT::Test>(); serif_ensure<SERiFErrorCode::CACHE_FE_BINDING_ERROR,std::invalid_argument>(&input.binding==&discretization.residual_binding, "Nodalcoefficientsmustusetheequation'sresidualbinding."); discretization.residual_binding.validate_values(input.values); returnown<typenamenodal_keys::Scoped<Scope>::Bindings>( NodalBindings{.selection=discretization.selected_rows,.nodes_sequence=discretization.residual_binding.mesh().GetNodesSequence()},NodalBindingTracking{}); } template<typenameScope=void,NodalValueEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_nodal_inputs(constNodalDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::dependencies; returnmake_dependency_context(make_nodal_binding_input<Scope>(discretization,term_coefficients), own<typenameEquationT::Test>(term_coefficients.templateget<typenameEquationT::Test>(),discretization::backend::mfem::CoefficientTracking{})); } template<typenameScope=void,AffinePointEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_point_border_binding_input(constPointBorderDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::dependencies; usingnamespaceutils::errors; constauto&border=term_coefficients.templateget<typenameEquationT::Border>(); serif_ensure<SERiFErrorCode::MISMATCHED_MESHING_MAPS,std::invalid_argument>(&discretization.nodal.residual_binding.mesh()==&discretization.border_binding.mesh(), "Pointcarrierandbordermustshareamesh."); serif_ensure<SERiFErrorCode::CACHE_FE_BINDING_ERROR,std::invalid_argument>(&border.binding==&discretization.border_binding, "Pointbordercoefficientsmustusetheequation'sscalarbinding."); discretization.border_binding.validate_values(border.values); returnmake_nodal_binding_input<Scope>(discretization.nodal,term_coefficients); } template<typenameScope=void,AffinePointEquationEquationT,discretization::domain::schema::IsSchemaSchemaT,typenameCoefficientsT> [[nodiscard]]automake_point_border_inputs(constPointBorderDiscretization<EquationT, SchemaT>&discretization,constCoefficientsT&term_coefficients) { usingnamespaceutils::dependencies; returnmake_dependency_context(make_point_border_binding_input<Scope>(discretization,term_coefficients), own<typenameEquationT::Test>(term_coefficients.templateget<typenameEquationT::Test>(),discretization::backend::mfem::CoefficientTracking{}), own<typenameEquationT::Border>(term_coefficients.templateget<typenameEquationT::Border>(),discretization::backend::mfem::CoefficientTracking{})); } }//namespaceserif::operators::backend::mfem