reference_geometry.cpp algorithm cmath mfem/fem/fespace.hpp serif/backend/mfem/geometry/deformation/reference_geometry.hpp serif serif::geometry serif::geometry::deformation serif::geometry::deformation::backend serif::geometry::deformation::backend::mfem #include<algorithm> #include<cmath> #include"mfem/fem/fespace.hpp" #ifdefMFEM_USE_MPI #include"mfem/fem/pfespace.hpp" #endif #include"serif/backend/mfem/geometry/deformation/reference_geometry.hpp" namespaceserif::geometry::deformation::backend::mfem { DeformationStatusvalidate_scalar_reference_space(const::mfem::FiniteElementSpace&scalar_space) { #ifdefMFEM_USE_MPI if(dynamic_cast<const::mfem::ParFiniteElementSpace*>(&scalar_space)!=nullptr) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Referencedeformationcompilationrequiresaserialfinite-elementspace;distributedinterpolationownershipisnotimplemented."}); } #endif const::mfem::Mesh*mesh=scalar_space.GetMesh(); if(mesh==nullptr||mesh->Dimension()!=3||mesh->SpaceDimension()!=3||(scalar_space.GetConformingProlongation()!=nullptr&&scalar_space.IsVariableOrder())) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Referencedeformationcompilationrequiresthree-dimensionalserialnodalspaces;constrainedspacesmusthavefixedorder."}); } if(scalar_space.GetVDim()!=1||scalar_space.FEColl()==nullptr||scalar_space.FEColl()->GetContType()!=::mfem::FiniteElementCollection::CONTINUOUS) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Referencedeformationrequiresascalarcontinuousnodalcompanionspace."}); } for(intelement=0;element<mesh->GetNE();++element) { const::mfem::FiniteElement*finite_element=scalar_space.GetFE(element); if(dynamic_cast<const::mfem::NodalFiniteElement*>(finite_element)==nullptr||finite_element->GetRangeType()!=::mfem::FiniteElement::SCALAR||finite_element->GetMapType()!=::mfem::FiniteElement::VALUE) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Deformationcoordinatesrequirescalarnodalvalueelements.",.element=element}); } } return{}; } DeformationStatusvalidate_companion_numbering(const::mfem::FiniteElementSpace&reference_space,const::mfem::FiniteElementSpace&companion_space) { if(reference_space.GetMesh()==nullptr||reference_space.GetMesh()!=companion_space.GetMesh()||reference_space.FEColl()==nullptr||reference_space.FEColl()!=companion_space.FEColl()||reference_space.GetNDofs()!=companion_space.GetNDofs()) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Deformationcompanionsrequirethesamereferencemesh,nodalcollectionandscalar-nodecount."}); } if(&reference_space==&companion_space) { return{}; } ::mfem::Array<int>reference_dofs,companion_dofs; for(intelement=0;element<reference_space.GetNE();++element) { reference_space.GetElementDofs(element,reference_dofs); companion_space.GetElementDofs(element,companion_dofs); if(reference_space.GetFE(element)!=companion_space.GetFE(element)||reference_dofs.Size()!=companion_dofs.Size()||!std::equal(reference_dofs.begin(),reference_dofs.end(),companion_dofs.begin())) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Deformationcompanionsmustusethesameelementbasisandcanonicalscalar-nodenumbering.",.element=element}); } } return{}; } std::expected<std::vector<std::array<double,3>>,DeformationFailure>detail::sample_reference_positions( const::mfem::FiniteElementSpace&scalar_space, ::mfem::Mesh&reference_mesh) { const::mfem::Mesh&physical_mesh=*scalar_space.GetMesh(); if(reference_mesh.Dimension()!=3||reference_mesh.SpaceDimension()!=3||reference_mesh.Nonconforming()!=physical_mesh.Nonconforming()||physical_mesh.GetNE()!=reference_mesh.GetNE()) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Referencepositionsrequirepairedthree-dimensionalelementswithmatchingrefinementtopology."}); } std::vector<std::array<double,3>>positions(scalar_space.GetNDofs()); std::vector<bool>processed(positions.size(),false); ::mfem::Array<int>dofs,physical_vertices,reference_vertices; ::mfem::Vectorposition(3); for(intelement=0;element<physical_mesh.GetNE();++element) { physical_mesh.GetElementVertices(element,physical_vertices); reference_mesh.GetElementVertices(element,reference_vertices); if(physical_mesh.GetElementGeometry(element)!=reference_mesh.GetElementGeometry(element)||physical_mesh.GetAttribute(element)!=reference_mesh.GetAttribute(element)||physical_vertices.Size()!=reference_vertices.Size()||!std::equal(physical_vertices.begin(),physical_vertices.end(),reference_vertices.begin())) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Physicalandlogicalelementsmusthaveidenticalattributes,vertexcorrespondenceandlocalorientation.",.element=element}); } const::mfem::FiniteElement&finite_element=*scalar_space.GetFE(element); const::mfem::IntegrationRule&nodes=finite_element.GetNodes(); scalar_space.GetElementDofs(element,dofs); if(nodes.GetNPoints()!=dofs.Size()) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="ThescalarcompanionnodesdonotmatchtheelementDOFs.",.element=element}); } ::mfem::ElementTransformation*transformation=reference_mesh.GetElementTransformation(element); if(transformation==nullptr) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::invalid_geometry,.message="Areferenceelementhasnocoordinatetransformation.",.element=element}); } for(intnode=0;node<dofs.Size();++node) { constintdof=::mfem::FiniteElementSpace::DecodeDof(dofs[node]); transformation->Transform(nodes.IntPoint(node),position); doublescale=1.0; doublesquared_difference=0.0; for(intcomponent=0;component<3;++component) { if(!std::isfinite(position[component])) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::non_finite,.message="Areferencenodehasanon-finiteposition.",.element=element,.point=node}); } scale=std::max(scale,std::abs(position[component])); constdoubledifference=position[component]-positions[dof][component]; squared_difference+=difference*difference; } if(processed[dof]&&std::sqrt(squared_difference)>1.0e-12*scale) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Asharedscalarnodehasinconsistentreferencecoordinates.",.element=element,.point=node}); } if(processed[dof]) { continue; } for(intcomponent=0;component<3;++component) { positions[dof][component]=position[component]; } processed[dof]=true; } } if(std::find(processed.begin(),processed.end(),false)!=processed.end()) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Ascalarnodehasnoreferencecoordinate."}); } returnpositions; } std::expected<std::vector<int>,DeformationFailure>select_surface_scalar_dofs(const::mfem::FiniteElementSpace&scalar_space,intsurface_attribute) { constDeformationStatusstatus=validate_scalar_reference_space(scalar_space); if(!status) { returnstd::unexpected(status.error()); } std::vector<bool>selected(scalar_space.GetNDofs(),false); ::mfem::Array<int>dofs; for(intboundary=0;boundary<scalar_space.GetMesh()->GetNBE();++boundary) { if(scalar_space.GetMesh()->GetBdrAttribute(boundary)!=surface_attribute) { continue; } scalar_space.GetBdrElementDofs(boundary,dofs); for(constintdof:dofs) { selected[::mfem::FiniteElementSpace::DecodeDof(dof)]=true; } } std::vector<int>result; const::mfem::SparseMatrix*prolongation=scalar_space.GetConformingProlongation(); for(intdof=0;dof<scalar_space.GetNDofs();++dof) { if(selected[dof]) { if(prolongation!=nullptr) { constintbegin=prolongation->GetI()[dof]; constintend=prolongation->GetI()[dof+1]; if(end!=begin+1||prolongation->GetData()[begin]!=1.0) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Radialsurfacedeformationrequiresaconformingstellartrace.GeneratethemeshwithSTROIDinterfaceclosure.",.point=dof}); } } result.push_back(dof); } } if(result.empty()) { returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::unresolved_surface,.message="Therequestedsurfaceattributehasnoscalarnodes."}); } returnresult; } std::expected<std::vector<std::array<double,3>>,DeformationFailure>sample_reference_positions(const::mfem::FiniteElementSpace&scalar_space,::mfem::Mesh&reference_mesh) { if(constDeformationStatusstatus=validate_scalar_reference_space(scalar_space);!status) { returnstd::unexpected(status.error()); } returndetail::sample_reference_positions(scalar_space,reference_mesh); } std::expected<ReferenceSurface,DeformationFailure>detail::sample_reference_surface(const::mfem::FiniteElementSpace&scalar_space,conststd::vector<int>&selected) { constautopositions=detail::sample_reference_positions(scalar_space,*scalar_space.GetMesh()); if(!positions) { returnstd::unexpected(positions.error()); } ReferenceSurfaceresult{.scalar_dofs=selected}; result.positions.reserve(selected.size()); for(constintdof:selected) { result.positions.push_back((*positions)[dof]); } returnresult; } std::expected<ReferenceSurface,DeformationFailure>sample_reference_surface(const::mfem::FiniteElementSpace&scalar_space,intsurface_attribute) { returnselect_surface_scalar_dofs(scalar_space,surface_attribute).and_then([&](conststd::vector<int>&selected) { returndetail::sample_reference_surface(scalar_space,selected); }); } DeformationStatusvalidate_surface_trace(const::mfem::FiniteElementSpace&scalar_space,intsurface_attribute,constReferenceSurface&reference_surface,constSurfaceEmbedding&embedding){ constautocurrent=sample_reference_surface(scalar_space,surface_attribute); if(!current){ returnstd::unexpected(current.error()); } if(reference_surface.scalar_dofs!=current->scalar_dofs||reference_surface.positions!=current->positions||!std::ranges::equal(reference_surface.positions,embedding.reference_positions())){ returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Surfaceassemblyrequiresthesameorderedreferencetraceasitssurfaceembedding.Rebuildthereferencesurfaceandembeddingtogether."}); } return{}; } }//namespaceserif::geometry::deformation::backend::mfem