kelvin.cpp cmath serif/backend/mfem/shared/finite.hpp serif/backend/mfem/mapping/compactification/kelvin.hpp serif/utils/user_options/mapping/compactification/kelvin.hpp serif/utils/error/errors.hpp serif serif::mapping serif::mapping::compactification #include<cmath> #include"serif/backend/mfem/shared/finite.hpp" #include"serif/backend/mfem/mapping/compactification/kelvin.hpp" #include"serif/utils/user_options/mapping/compactification/kelvin.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::mapping::compactification{ usingnamespaceserif::utils::user_options; usingnamespaceserif::utils::errors; usingnamespaceserif::utils::checks; KelvinCompactification::KelvinCompactification(constKelvinCompactificationOptions&options):m_options(options){ if(!std::isfinite(m_options.r_star_ref)){ serif_error<std::invalid_argument,SERiFErrorCode::NON_FINITE_MAPPING_INPUT>("Kelvincompactificationrequiresafinitereferencestellarradius.Received{}",m_options.r_star_ref); } if(!std::isfinite(m_options.r_inf_ref)){ serif_error<std::invalid_argument,SERiFErrorCode::NON_FINITE_MAPPING_INPUT>("Kelvincompactificationrequiresafinitereferenceinfinityradius.Received{}",m_options.r_star_ref); } if(m_options.r_star_ref<=0||m_options.r_inf_ref<=m_options.r_star_ref) { serif_error<std::invalid_argument,SERiFErrorCode::IMPROPERLY_ORDERED_REFERENCE_RADII>("Kelvincompactificationrequires0<r_star_ref<r_inf_ref.Gotr_star_ref={}andr_inf_ref={}",m_options.r_star_ref,m_options.r_inf_ref); } if(!std::isfinite(m_options.coordinate_tolerance)||m_options.coordinate_tolerance<0.0||m_options.coordinate_tolerance>=1.0) { serif_error<std::invalid_argument,SERiFErrorCode::INVALID_COORDINATE_TOLERANCE>("Kelvincompactificationcoordinatetolerancemustbefiniteandon[0,1).Received:{}",m_options.coordinate_tolerance); } } boolKelvinCompactification::is_affine_in_displacement()constnoexcept{ returntrue;//Alwaystrueforkelvincompactification } MappingStatusKelvinCompactification::evaluate(constExteriorMapInput&input,ExteriorMapResult&result)const{ constintdimension=input.reference_position.Size(); if(dimension<=0||input.displaced_position.Size()!=dimension||input.compactification_coordinate_gradient.Size()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } if(input.displacement_jacobian.Height()!=dimension||input.displacement_jacobian.Width()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } constboolreference_pos_is_finite=is_finite(input.reference_position); constbooldisplaced_pos_is_finite=is_finite(input.displaced_position); constboolcoord_grad_is_finite=is_finite(input.compactification_coordinate_gradient); constbooldisplacement_jacobian_is_finite=is_finite(input.displacement_jacobian); if(!(reference_pos_is_finite&&displaced_pos_is_finite&&coord_grad_is_finite&&displacement_jacobian_is_finite)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } RadialFactorsfactors{}; //Thekeyradialfactorsweusearethescale(whichstretchesthefinitecomputationaldomainintotheinfinitephysicaldomain)andthescalederivative(whichisusedtocomputethemappingjacobian) constMappingStatusfactor_status=compute_radial_factors(input.compactification_coordinate,factors); if(factor_status!=MappingStatus::VALID){ returnfactor_status; } result.physical_position.SetSize(dimension); result.mapping_jacobian.SetSize(dimension,dimension); for(inti=0;i<dimension;++i){ //Notehowthephysicalpositionisjusttheproductofthedisplacedpositionandthescalefactor. result.physical_position(i)=factors.scale*input.displaced_position(i); //Themappingjacobiancomesfromtrivialapplicationoftheproductrule //recall:r_i=scale*x_iwhereristhephysicalpositionandxisthedisplacedposition. //thenwecandifferentiatewrt.X_jholdingnothingfixed.NotethecapitalXhere,thisisthemeshcoordinatenotthedisplacedposition. //LetscallthisjacobianF //F=\frac{\partialr_i}{\partialX_{j}} //Fthentellsushowthephysicalpositionchangesaswemovealongmeshcoordinates //Letsthenapplythistothefunctionwehaveforthekelvincompactification //F=scale*\frac{\partialx_i}{\partialX_j}+x_i*\frac{\partialscale}{\partialX_j} //Belowyoucanseethedisplacementjacobian(\frac{\partialx_i}{\partialX_j})andthescalederivative(\frac{\partialscale}{\partialX_j})beingappliedtocomputethemappingjacobian. for(intj=0;j<dimension;++j){ constdoublescale_gradient=factors.scale_derivative*input.compactification_coordinate_gradient(j); result.mapping_jacobian(i,j)=factors.scale*input.displacement_jacobian(i,j)+input.displaced_position(i)*scale_gradient; } } if(!is_finite(result.physical_position)||!is_finite(result.mapping_jacobian)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } constdoublemapping_determinant=result.mapping_jacobian.Det(); if(!std::isfinite(mapping_determinant)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } if(mapping_determinant<=0.0){ returnMappingStatus::NON_POSITIVE_DETERMINATE; } returnMappingStatus::VALID; } MappingStatusKelvinCompactification::evaluate_variation(constExteriorMapInput&input,constExteriorMapResult&result,constExteriorMapDirection&direction,ExteriorMapVariation&variation)const{ constintdimension=input.reference_position.Size(); if(dimension<=0||input.displaced_position.Size()!=dimension||input.compactification_coordinate_gradient.Size()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } if(input.displacement_jacobian.Height()!=dimension||input.displacement_jacobian.Width()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } if(result.physical_position.Size()!=dimension||result.mapping_jacobian.Height()!=dimension||result.mapping_jacobian.Width()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } if(direction.displaced_position_variation.Size()!=dimension||direction.displacement_jacobian_variation.Height()!=dimension||direction.displacement_jacobian_variation.Width()!=dimension){ returnMappingStatus::INVALID_DIMENSION; } constboolreference_position_is_finite=is_finite(input.reference_position); constbooldisplaced_position_is_finite=is_finite(input.displaced_position); constboolcompactification_coord_grad_is_finite=is_finite(input.compactification_coordinate_gradient); constbooldisplacement_jacobian_is_finite=is_finite(input.displacement_jacobian); if(!(reference_position_is_finite&&displaced_position_is_finite&&compactification_coord_grad_is_finite&&displacement_jacobian_is_finite)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } constboolresult_physical_position_is_finite=is_finite(result.physical_position); constboolresult_mapping_jacobian_is_finite=is_finite(result.mapping_jacobian); constbooldirection_displaced_position_is_finite=is_finite(direction.displaced_position_variation); constbooldirection_displacement_jacobian_is_finite=is_finite(direction.displacement_jacobian_variation); if(!(result_physical_position_is_finite&&result_mapping_jacobian_is_finite&&direction_displaced_position_is_finite&&direction_displacement_jacobian_is_finite)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT;//Notewearecheckingaparametercalledresulthere;however,thisistheresultfromanevaluatecall,itisaninputtothisfunction. } RadialFactorsfactors{}; constMappingStatusfactor_status=compute_radial_factors(input.compactification_coordinate,factors); if(factor_status!=MappingStatus::VALID){ returnfactor_status; } variation.physical_position_variation.SetSize(dimension); variation.mapping_jacobian_variation.SetSize(dimension,dimension); for(inti=0;i<dimension;++i){ variation.physical_position_variation(i)=factors.scale*direction.displaced_position_variation(i); for(intj=0;j<dimension;++j){ constdoublescale_gradient=factors.scale_derivative*input.compactification_coordinate_gradient(j); variation.mapping_jacobian_variation(i,j)=factors.scale*direction.displacement_jacobian_variation(i,j)+direction.displaced_position_variation(i)*scale_gradient; } } if(!is_finite(variation.physical_position_variation)||!is_finite(variation.mapping_jacobian_variation)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } [[nodiscard]]std::string_viewKelvinCompactification::get_name()constnoexcept{ returnm_name; } [[nodiscard]]doubleKelvinCompactification::get_reference_stellar_radius()constnoexcept{ returnm_options.r_star_ref; } [[nodiscard]]doubleKelvinCompactification::get_reference_infinity_radius()constnoexcept{ returnm_options.r_inf_ref; } [[nodiscard]]doubleKelvinCompactification::get_coordinate_tolerance()constnoexcept{ returnm_options.coordinate_tolerance; } [[nodiscard]]MappingStatusKelvinCompactification::evaluate_jacobian_variation_factors(doublecompactification_coordinate,constmfem::Vector&coordinateGradient,double&scale,mfem::Vector&scaleGradient)const{ if(coordinateGradient.Size()<=0){ returnMappingStatus::INVALID_DIMENSION; } if(!is_finite(coordinateGradient)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } RadialFactorsfactors{}; constMappingStatusstatus=compute_radial_factors(compactification_coordinate,factors); if(status!=MappingStatus::VALID){ returnstatus; } scale=factors.scale; scaleGradient=coordinateGradient; scaleGradient*=factors.scale_derivative; if(!is_finite(scaleGradient)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } returnMappingStatus::VALID; } MappingStatusKelvinCompactification::compute_radial_factors(doublecompactification_coordinate,RadialFactors&radial_factors)const{ if(!std::isfinite(compactification_coordinate)){ returnMappingStatus::NON_FINITE_MAPPING_INPUT; } constdoubletolerance=m_options.coordinate_tolerance; if(compactification_coordinate<-tolerance||compactification_coordinate>1.0+tolerance){ returnMappingStatus::OUTSIDE_REFERENCE_DOMAIN; } doublecoordinate=compactification_coordinate; if(coordinate<0.0){ coordinate=0.0;//Notsurethisisthebestbehaviorhere... } if(coordinate>=1.0-tolerance){ returnMappingStatus::AT_COMPACTIFIED_INFINITY; } //Hereweneedtodosometransformationsfromtheoptionsdefinedonthemeshtousefulcomputationalcoordinates //r_inf_refisthecomputational/referenceradiusoftheinfinitysurface(theedgeoftheentiredomain)andr_star_refistheradiusofthespherical //stellarmodelinscribedwithin.Thereforeradialextentisthecomputationalradialdistancebetweenthestellarsurfaceandtheinfinitysurface. //Notethatthisisseparatefromtheparameterizecompactificationcoordinate. constdoubleradial_extent=m_options.r_inf_ref-m_options.r_star_ref; //Thisplacesusatthecorrectspotincomputationalspacegiventhecurrentcompactificationcoordinate.Sayyouhavecompactification=0.5, //anr_star_refof2andaradialextentof3,thisthiswillplaceyouat2+0.5*3=3.5incomputationalspace,whichishalfwaybetweenthestellarsurfaceandtheinfinitysurface. constdoublecomputational_radius=m_options.r_star_ref+coordinate*radial_extent; if(!std::isfinite(computational_radius)||computational_radius<=0.0){ returnMappingStatus::INVALID_REFERENCE_RADIUS; } //Inverttheexteriorcoordinatesoitrunsfrom0atthestarto1atcompactifiedinfinity constdoubleone_minus_coordinate=1.0-coordinate; constdoubledenominator=computational_radius*one_minus_coordinate; if(!std::isfinite(denominator)||denominator<=0.0){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } //Thescalehereisthefactorwhichstretchesthefinitecomputationaldomainintotheinfinitephysicaldomain.Propertiesweneedthistohave //includethatitshouldgoto1atthestellarsurfaceandgotoinfinityatthecompactifiedinfinity. //Mathematicallythisisscale=|r|/|x|whereristhephysicalradiusandxisthecomputationalradius. //Putanotherway,scaleistheratioofthetargetphysicalradiusforthecurrentcompactificationcoordinate //tothecurrentmeshradius. constdoublescale=m_options.r_star_ref/denominator; constdoublescale_derivative=scale*(1.0/one_minus_coordinate-radial_extent/computational_radius); if(!std::isfinite(scale)||!std::isfinite(scale_derivative)){ returnMappingStatus::NON_FINITE_MAPPING_RESULT; } radial_factors.compactification_coordinate=coordinate; radial_factors.computational_radius=computational_radius; radial_factors.scale=scale; radial_factors.scale_derivative=scale_derivative; returnMappingStatus::VALID; } }