surface_power.hpp cmath span string_view serif/discretization/domain/physical_domains.hpp serif/utils/error/errors.hpp src/include/serif/backend/mfem/discretization/reconstruction.hpp serif::discretization::reconstruction::SurfaceRegion serif::discretization::reconstruction::SurfaceAdjacent serif::discretization::reconstruction::SurfacePower serif::discretization::reconstruction::RadialProfile serif::discretization::reconstruction::SurfacePowerProfile serif serif::discretization serif::discretization::reconstruction #pragmaonce #include<cmath> #include<span> #include<string_view> #include"serif/discretization/domain/physical_domains.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::discretization::reconstruction{ structSurfaceRegion{ std::string_viewboundary_name; }; template<typenameBoundaryT=domain::StellarSurfaceBoundary> structSurfaceAdjacent:SurfaceRegion{ constexprSurfaceAdjacent():SurfaceRegion{BoundaryT::name}{} }; template<typenameTermT> structSurfacePower{ usingTerm=TermT; doubledensity_exponent{1.0}; SurfaceRegionregion{SurfaceAdjacent<>{}}; }; classRadialProfile{ public: virtual~RadialProfile()=default; [[nodiscard]]virtualstd::string_viewname()constnoexcept=0; virtualvoidevaluate(std::span<constdouble>nodes,doubleinward_coordinate, std::span<double>values,std::span<double>derivatives)const=0; }; classSurfacePowerProfilefinal:publicRadialProfile{ public: explicitSurfacePowerProfile(doubledensity_exponent):m_exponent(density_exponent){ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(std::isfinite(m_exponent)&&m_exponent>=1.0, "SurfacePowerrequiresafinitedensityexponent>=1;received{}.Choosethepolytropicindexofavacuummodelinthesupportedrange.",m_exponent); } [[nodiscard]]std::string_viewname()constnoexceptoverride{return"surface_power";} [[nodiscard]]doubledensity_exponent()constnoexcept{returnm_exponent;} voidevaluate(std::span<constdouble>nodes,doubleinward_coordinate, std::span<double>values,std::span<double>derivatives)constoverride{ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(nodes.size()>=2&&values.size()==nodes.size()&&derivatives.size()==nodes.size()&& nodes.front()==0.0&&nodes.back()==1.0&&std::isfinite(inward_coordinate)&&inward_coordinate>=0.0&&inward_coordinate<=1.0, "SurfacePowerevaluationrequiresclosedinwardnodeson[0,1]andmatchingoutputsizes;receivedcoordinate{}and{}nodes.",inward_coordinate,nodes.size()); for(std::size_tnode=1;node<nodes.size();++node){ serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(std::isfinite(nodes[node])&&nodes[node]>nodes[node-1], "SurfacePowerrequiresstrictlyincreasingradialnodes."); } values[0]=1.0; derivatives[0]=0.0; for(std::size_tnode=1;node<nodes.size();++node){ doublecardinal=1.0; doublecardinal_derivative=0.0; for(std::size_tother=1;other<nodes.size();++other){ if(other==node){continue;} constdoubledenominator=nodes[node]-nodes[other]; cardinal_derivative=cardinal_derivative*(inward_coordinate-nodes[other])/denominator+cardinal/denominator; cardinal*=(inward_coordinate-nodes[other])/denominator; } constdoubleratio=inward_coordinate/nodes[node]; constdoublepower=std::pow(ratio,m_exponent); constdoublepower_derivative=m_exponent/nodes[node]*std::pow(ratio,m_exponent-1.0); values[node]=power*cardinal; derivatives[node]=power_derivative*cardinal+power*cardinal_derivative; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT>(std::isfinite(values[node])&&std::isfinite(derivatives[node]), "SurfacePowerexponent{}cannotbeevaluatedfinitelyontheseradialnodes.",m_exponent); values[0]-=values[node]; derivatives[0]-=derivatives[node]; } } private: doublem_exponent; }; }