term_binding.hpp algorithm serif/discretization/blocks/traits.hpp serif/discretization/domain/schema/concepts.hpp serif/backend/mfem/discretization/dof_map.hpp serif/utils/error/errors.hpp src/include/serif/backend/mfem/discretization/dof_selection.hpp src/include/serif/backend/mfem/discretization/mass_diagonal.hpp src/include/serif/backend/mfem/discretization/term_coefficients.hpp src/include/serif/backend/mfem/model/finite_elements.hpp serif::discretization::backend::mfem::TermBinding serif serif::discretization serif::discretization::backend serif::discretization::backend::mfem A runtime binding between some term descriptor and its MFEM finite-element space. This is used to project down the compile time term descriptors into runtime reinterpretations which can then be used to extract out things like the list of dofs, the element support, and the mesh. Emily M. Boudreaux #pragmaonce #include<algorithm> #include"serif/discretization/blocks/traits.hpp" #include"serif/discretization/domain/schema/concepts.hpp" #include"serif/backend/mfem/discretization/dof_map.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::discretization::backend::mfem{ template<typenameTermT,domain::schema::IsSchemaSchemaT> requires(blocks::SpatialTerm<TermT>||blocks::GlobalScalarTerm<TermT>) classTermBindingfinal:publicDofMap{ public: usingTerm=TermT; usingSchema=SchemaT; explicitTermBinding( ::mfem::FiniteElementSpace&space,std::shared_ptr<constReconstructionPlan>reconstruction={} )requiresblocks::SpatialTerm<Term>: DofMap(space,element_support(checked_mesh(space)),std::move(reconstruction)){ usingTraits=blocks::SpatialTermTraits<Term>; usingnamespaceutils::errors; static_assert(Traits::family==functional_space::Family::h1||Traits::family==functional_space::Family::l2,"TheMFEMbackendcurrentlyonlysupportsH1andL2spaces."); static_assert(Traits::rank<=1,"Tensortermsarenotsupportedbythisbackend."); if(this->reconstruction()){ serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(Traits::family==functional_space::Family::h1&&Traits::rank==0, "RadialreconstructioncurrentlysupportsonlyscalarH1fields."); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(std::same_as<Term,blocks::density::mass>|| dynamic_cast<constreconstruction::SurfacePowerProfile*>(&this->reconstruction()->profile())==nullptr, "SurfacePowerhasbeenvalidatedonlyformassdensity;selectthatfieldorimplementacompatiblereconstructionform."); } constintvector_dimension=Traits::rank==0?1:3; constintcontinuity=Traits::family==functional_space::Family::h1?::mfem::FiniteElementCollection::CONTINUOUS:::mfem::FiniteElementCollection::DISCONTINUOUS; serif_ensure<SERiFErrorCode::INVALID_DIMENSION,std::invalid_argument>(space.GetVDim()==vector_dimension,"Termvectordimensiondisagreeswithitsscalar-copyrepresentation."); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>(space.FEColl()->GetContType()==continuity,"Termcontinuitydisagreeswithitsdescriptor."); for(intelement=0;element<space.GetNE();++element){ constauto*finite_element=space.GetFE(element); serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>( finite_element!=nullptr&&finite_element->GetOrder()==Traits::order&& finite_element->GetRangeType()==::mfem::FiniteElement::SCALAR&& finite_element->GetMapType()==::mfem::FiniteElement::VALUE, "Termelementsmustmatchtheregisteredfamilyorder,range,andmapping."); } } explicitTermBinding( ::mfem::Mesh&mesh )requiresdiscretization::blocks::GlobalScalarTerm<Term>: DofMap(mesh,element_support(mesh)){} private: static::mfem::Mesh&checked_mesh(const::mfem::FiniteElementSpace&space){ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::CACHE_FE_BINDING_ERROR>(space.GetMesh()!=nullptr&&space.FEColl()!=nullptr,"Termbindingsrequireaninitializedfinite-elementspace."); return*space.GetMesh(); } static::mfem::Array<int>element_support(const::mfem::Mesh&mesh){ usingnamespaceutils::errors; constexprautodomains=Schema::domain_descriptors(); ::mfem::Array<int>result(mesh.GetNE()); autoID_matches=[](constauto&domain,constintattribute)->bool{ returndomain.ID==attribute; }; for(intelement=0;element<mesh.GetNE();++element){ constintattribute=mesh.GetAttribute(element); serif_ensure<SERiFErrorCode::INVALID_DOMAIN_ERROR>(std::ranges::any_of(domains,[&](constauto&domain){returnID_matches(domain,attribute);}),"Elementattributedoesnotmatchtheregistereddomain."); result[element]=Schema::templatedomain_id_belongs_to<typenameTerm::Support>(attribute); } returnresult; } }; }