radial_locator.cpp algorithm cmath limits mfem/mesh/mesh.hpp serif/backend/mfem/geometry/deformation/detail/radial_locator.hpp serif serif::geometry serif::geometry::deformation serif::geometry::deformation::backend serif::geometry::deformation::backend::mfem serif::geometry::deformation::backend::mfem::detail #include<algorithm> #include<cmath> #include<limits> #include"mfem/mesh/mesh.hpp" #include"serif/backend/mfem/geometry/deformation/detail/radial_locator.hpp" namespaceserif::geometry::deformation::backend::mfem::detail{ doublelogical_radius(const::mfem::Vector&position){ doubleradius=0.0; for(intcomponent=0;component<position.Size();++component){ radius=std::max(radius,std::abs(position[component])); } returnradius; } std::expected<double,DeformationFailure>boundary_logical_radius(::mfem::Mesh&mesh,constintattribute){ doubleminimum=std::numeric_limits<double>::infinity(); doublemaximum=0.0; intsamples=0; ::mfem::Vectorposition(3); for(intboundary=0;boundary<mesh.GetNBE();++boundary){ if(mesh.GetBdrAttribute(boundary)!=attribute){ continue; } ::mfem::ElementTransformation*transformation=mesh.GetBdrElementTransformation(boundary); constintgeometry=mesh.GetBdrElementGeometry(boundary); if(geometry!=::mfem::Geometry::SQUARE||transformation==nullptr){ returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::incompatible_discretization,.message="Thelogicalradialfoliationrequiresquadrilateralshellelements.",.element=boundary}); } const::mfem::IntegrationRule*vertices=::mfem::Geometries.GetVertices(geometry); for(intvertex=0;vertex<vertices->GetNPoints();++vertex){ transformation->Transform(vertices->IntPoint(vertex),position); for(intcomponent=0;component<3;++component){ if(!std::isfinite(position[component])){ returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::non_finite,.message="Alogicalboundaryvertexisnon-finite.",.element=boundary,.point=vertex}); } } constdoubleradius=logical_radius(position); minimum=std::min(minimum,radius); maximum=std::max(maximum,radius); ++samples; } } if(samples==0||!(minimum>0.0)||maximum-minimum>1.0e-12*std::max(1.0,maximum)){ returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::invalid_geometry,.message="ArequiredlogicalboundaryisabsentorisnotapositiveconstantL-infinity-radiusshell."}); } return0.5*(minimum+maximum); } std::expected<LocatedBoundaryPoint,DeformationFailure>locate_boundary_point(::mfem::Mesh&mesh,constintattribute,const::mfem::Vector&target){ LocatedBoundaryPointbest{.boundary_element=-1,.point={}}; doublebest_residual=std::numeric_limits<double>::infinity(); constdoubletolerance=2.0e-11*std::max(1.0,logical_radius(target)); ::mfem::Vectortransformed(3),residual(3); for(intboundary=0;boundary<mesh.GetNBE();++boundary){ if(mesh.GetBdrAttribute(boundary)!=attribute){ continue; } ::mfem::ElementTransformation*transformation=mesh.GetBdrElementTransformation(boundary); ::mfem::IntegrationPointpoint=::mfem::Geometries.GetCenter(::mfem::Geometry::SQUARE); boolnonsingular=true; for(intiteration=0;iteration<8;++iteration){ transformation->Transform(point,transformed); residual=target; residual-=transformed; if(residual.Norml2()<=tolerance){ break; } transformation->SetIntPoint(&point); const::mfem::DenseMatrix&jacobian=transformation->Jacobian(); doublenormal00=0.0,normal01=0.0,normal11=0.0; doubleright0=0.0,right1=0.0; for(intcomponent=0;component<3;++component){ normal00+=jacobian(component,0)*jacobian(component,0); normal01+=jacobian(component,0)*jacobian(component,1); normal11+=jacobian(component,1)*jacobian(component,1); right0+=jacobian(component,0)*residual(component); right1+=jacobian(component,1)*residual(component); } constdoubledeterminant=normal00*normal11-normal01*normal01; if(!(std::abs(determinant)>std::numeric_limits<double>::epsilon())){ nonsingular=false; break; } point.x+=(normal11*right0-normal01*right1)/determinant; point.y+=(normal00*right1-normal01*right0)/determinant; } if(!nonsingular||!::mfem::Geometry::CheckPoint(::mfem::Geometry::SQUARE,point,1.0e-10)){ continue; } transformation->Transform(point,transformed); transformed-=target; constdoublenorm=transformed.Norml2(); if(norm<=tolerance&&norm<best_residual){ best={.boundary_element=boundary,.point=point}; best_residual=norm; } } if(best.boundary_element<0){ returnstd::unexpected(DeformationFailure{.reason=DeformationFailureReason::unresolved_surface,.message="Nologicalquadrilateralcontainsaradialprojectionontotherequiredshell."}); } returnbest; } }