boundary_elements.hpp expected span string vector mfem/fem/fespace.hpp src/lib/serif/backend/mfem/geometry/deformation/surface_metric.cpp src/lib/serif/backend/mfem/model/surface_potential.cpp serif::backend::mfem::shared::BoundaryFailure serif::backend::mfem::shared::BoundaryElement serif serif::backend serif::backend::mfem serif::backend::mfem::shared #pragmaonce #include<expected> #include<span> #include<string> #include<vector> #include"mfem/fem/fespace.hpp" namespaceserif::backend::mfem::shared{ structBoundaryFailure{ std::stringmessage; intelement{-1}; boolincompatible_coordinates{true}; }; usingBoundaryStatus=std::expected<void,BoundaryFailure>; structBoundaryElement{ const::mfem::FiniteElement&finite_element; ::mfem::ElementTransformation&transformation; std::span<constint>encoded_dofs; std::span<constint>selected_nodes; }; template<typenameVisitor> [[nodiscard]]BoundaryStatusfor_each_boundary_element(const::mfem::FiniteElementSpace&space,intattribute,std::span<constint>selected_dofs,Visitor&&visit){ if(space.GetMesh()==nullptr){ returnstd::unexpected(BoundaryFailure{.message="Boundaryassemblyrequiresafinite-elementspaceattachedtoamesh."}); } std::vector<int>selected_index(space.GetNDofs(),-1); for(std::size_tnode=0;node<selected_dofs.size();++node){ constintdof=selected_dofs[node]; if(dof<0||dof>=space.GetNDofs()||selected_index[dof]>=0){ returnstd::unexpected(BoundaryFailure{.message="Boundaryassemblyrequiresdistinctscalarnodesbelongingtoitsfinite-elementspace."}); } selected_index[dof]=static_cast<int>(node); } ::mfem::Array<int>dofs; std::vector<int>nodes; for(intboundary=0;boundary<space.GetMesh()->GetNBE();++boundary){ if(space.GetMesh()->GetBdrAttribute(boundary)!=attribute){ continue; } if(space.GetBdrElementDofs(boundary,dofs)!=nullptr||space.GetBE(boundary)->GetDof()!=dofs.Size()){ returnstd::unexpected(BoundaryFailure{.message="BoundaryassemblyrequiresacanonicalscalarnodaltracewithoutadditionalDOFtransformations.",.element=boundary}); } nodes.resize(dofs.Size()); for(intlocal=0;local<dofs.Size();++local){ constintdof=::mfem::FiniteElementSpace::DecodeDof(dofs[local]); if(dof<0||dof>=space.GetNDofs()||selected_index[dof]<0){ returnstd::unexpected(BoundaryFailure{.message="Aboundarytracenodeismissingfromtheselectedscalarcoordinates.",.element=boundary}); } nodes[local]=selected_index[dof]; } constBoundaryElementelement{.finite_element=*space.GetBE(boundary),.transformation=*space.GetBdrElementTransformation(boundary),.encoded_dofs={dofs.GetData(),static_cast<std::size_t>(dofs.Size())},.selected_nodes=nodes}; if(BoundaryStatusstatus=visit(element);!status){ status.error().element=boundary; returnstatus; } } return{}; } }