fitted.cpp serif/solver/seed/fitted.hpp cmath serif serif::solver serif::solver::seed #include"serif/solver/seed/fitted.hpp" #include<cmath> namespaceserif::solver::seed{ std::expected<FittedRadialSeed,std::string>fit_radial_seed(constRadialSeed&seed,dimensions::LengthValueradius){ constauto&samples=seed.solution.samples; if(samples.size()<2||samples.front().xi!=0.0||samples.front().theta!=1.0||samples.front().derivative!=0.0|| !seed.solution.surface||samples.back().xi!=seed.solution.surface->xi||samples.back().theta!=0.0|| samples.back().derivative!=seed.solution.surface->derivative){ returnstd::unexpected("FittingaradialguessrequiresacompleteregularLane–Emdenprofileendingatitsfinitesurface."); } doubleprevious_radius=-1.0; for(constauto&sample:samples){ if(!std::isfinite(sample.xi)||sample.xi<=previous_radius||!std::isfinite(sample.theta)||sample.theta<0.0||!std::isfinite(sample.derivative)){ returnstd::unexpected("Fittingaradialguessrequiresfinitenonnegativesamplesatstrictlyincreasingdimensionlessradii."); } previous_radius=sample.xi; } constautocenter=evaluate_radial_seed(seed,dimensions::LengthValue{0.0}); if(!center){ returnstd::unexpected(center.error()); } if(!std::isfinite(radius.value())||radius.value()<=0.0||!std::isfinite(seed.moment_of_inertia)|| seed.moment_of_inertia<=0.0||!std::isfinite(seed.angular_velocity)){ returnstd::unexpected("Fittingaradialguessrequiresafinitepositiveradiusandinertiaandafiniteangularvelocity."); } for(constdoublecoordinate:seed.center){ if(!std::isfinite(coordinate)){ returnstd::unexpected("Fittingaradialguessrequiresafinitephysicalcenter."); } } constlongdoublestretch=static_cast<longdouble>(radius.value())/seed.scales.radius.value(); //Applyeachlengthfactortoitsphysicalquantity:s^5alonecanoverflowwhileI*s^5remainsrepresentable. constdoublemass=static_cast<double>(seed.scales.mass.value()*stretch*stretch*stretch); constdoubleinertia=static_cast<double>(seed.moment_of_inertia*stretch*stretch*stretch*stretch*stretch); constdoublerotation=static_cast<double>(seed.angular_velocity/stretch/stretch/stretch/stretch/stretch); constdoublepotential=static_cast<double>(center->potential.value()*stretch*stretch); if(!std::isfinite(mass)||mass<=0.0||!std::isfinite(inertia)||inertia<=0.0|| !std::isfinite(rotation)||(seed.angular_velocity!=0.0&&rotation==0.0)||!std::isfinite(potential)){ returnstd::unexpected("Fittingtheradialguessexceedsrepresentablemass,gravityorrotationscales.Useconsistentphysicalunitsandalessextremeradiusratio."); } returnFittedRadialSeed{.source=seed,.radius=radius,.mass=dimensions::MassValue{mass}, .moment_of_inertia=inertia,.angular_velocity=rotation}; } std::expected<utils::laneemden::PhysicalSample,std::string>evaluate_radial_seed( constFittedRadialSeed&seed,dimensions::LengthValueradius){ if(!std::isfinite(radius.value())||radius.value()<0.0||!std::isfinite(seed.radius.value())||seed.radius.value()<=0.0|| !std::isfinite(seed.mass.value())||seed.mass.value()<=0.0||!std::isfinite(seed.source.scales.radius.value())||seed.source.scales.radius.value()<=0.0|| !std::isfinite(seed.source.scales.gravitational_constant.value())||seed.source.scales.gravitational_constant.value()<=0.0){ returnstd::unexpected("Afittedradialguessrequiresafinitenonnegativeevaluationradiusandfinitepositivesourceradius,fittedradius,massandG."); } if(radius.value()>=seed.radius.value()){ constlongdoublegravitational_mass=static_cast<longdouble>(seed.source.scales.gravitational_constant.value())*seed.mass.value(); constdoublepotential=static_cast<double>(-gravitational_mass/radius.value()); constdoublegravity=static_cast<double>(gravitational_mass/radius.value()/radius.value()); if(!std::isfinite(potential)||!std::isfinite(gravity)){ returnstd::unexpected("Thefittedexteriorgravityfieldsoverflowinthesuppliedphysicalunits."); } returnutils::laneemden::PhysicalSample{ .density=dimensions::DensityValue{0.0},.pressure=dimensions::PressureValue{0.0}, .enthalpy=dimensions::QuantityValue<dimensions::SpecificEnthalpy>{0.0}, .potential=dimensions::QuantityValue<dimensions::GravitationalPotential>{potential}, .enclosed_mass=seed.mass,.gravity=dimensions::QuantityValue<dimensions::Acceleration>{gravity} }; } constlongdoublestretch=static_cast<longdouble>(seed.radius.value())/seed.source.scales.radius.value(); constdoublesource_radius=static_cast<double>((static_cast<longdouble>(radius.value())/seed.radius.value())*seed.source.scales.radius.value()); autosample=evaluate_radial_seed(seed.source,dimensions::LengthValue{source_radius}); if(!sample){ returnsample; } constdoublemass=static_cast<double>(sample->enclosed_mass.value()*stretch*stretch*stretch); constdoublepotential=static_cast<double>(sample->potential.value()*stretch*stretch); constdoublegravity=static_cast<double>(sample->gravity.value()*stretch); if(!std::isfinite(mass)||!std::isfinite(potential)||!std::isfinite(gravity)){ returnstd::unexpected("Thefittedradialgravityfieldsoverflowinthesuppliedphysicalunits."); } sample->enclosed_mass=dimensions::MassValue{mass}; sample->potential=dimensions::QuantityValue<dimensions::GravitationalPotential>{potential}; sample->gravity=dimensions::QuantityValue<dimensions::Acceleration>{gravity}; returnsample; } }