top.hpp array cmath filesystem memory numbers span string type_traits serif/backend/mfem/discretization/dof_map.hpp serif/backend/mfem/geometry/deformation/computations.hpp serif/eos/models/polytropic.hpp serif/equations/barotropic_density.hpp serif/equations/primal_gravity.hpp serif/geometry/surface/isobaric.hpp serif/model/description.hpp serif/utils/dependencies/computation_cache.hpp serif/utils/serialize/top.hpp src/lib/serif/backend/mfem/serialize/top.cpp serif::backend::mfem::serialize::detail::TopModelSampler serif serif::backend serif::backend::mfem serif::backend::mfem::serialize serif::backend::mfem::serialize::detail serif::utils serif::utils::serialize #pragmaonce #include<array> #include<cmath> #include<filesystem> #include<memory> #include<numbers> #include<span> #include<string> #include<type_traits> #include"serif/backend/mfem/discretization/dof_map.hpp" #include"serif/backend/mfem/geometry/deformation/computations.hpp" #include"serif/eos/models/polytropic.hpp" #include"serif/equations/barotropic_density.hpp" #include"serif/equations/primal_gravity.hpp" #include"serif/geometry/surface/isobaric.hpp" #include"serif/model/description.hpp" #include"serif/utils/dependencies/computation_cache.hpp" #include"serif/utils/serialize/top.hpp" namespaceserif::backend::mfem::serialize::detail{ classTopModelSamplerfinal{ public: TopModelSampler(constdiscretization::backend::mfem::DofMap&density_binding, std::span<constdouble>density, constgeometry::deformation::backend::mfem::ReferenceDiscretization&reference, std::span<constdouble>component_displacement, conststd::array<double,3>&axis,conststd::array<double,3>&center); ~TopModelSampler(); TopModelSampler(constTopModelSampler&)=delete; TopModelSampler&operator=(constTopModelSampler&)=delete; [[nodiscard]]utils::serialize::Result<double>surface_radius(doublemu,doublephi); [[nodiscard]]utils::serialize::Result<double>density(doubleradius,doublemu,doublephi); [[nodiscard]]doublemass()constnoexcept; [[nodiscard]]std::size_troundoff_density_clamps()constnoexcept; private: structImpl; std::unique_ptr<Impl>m_impl; }; template<typenameEOS> [[nodiscard]]booltop_matching_polytrope(constEOS&candidate,consteos::models::Polytrope&physical){ ifconstexpr(std::same_as<std::remove_cvref_t<EOS>,eos::models::Polytrope>){ returncandidate.polytropic_index()==physical.polytropic_index()&& candidate.polytropic_constant()==physical.polytropic_constant(); }elseifconstexpr(requires{candidate.get();}){ returntop_matching_polytrope(candidate.get(),physical); }else{ returnfalse; } } template<typenameT>inlineconstexprbooltop_rigid_barotrope=false; template<typenameEOS>inlineconstexprbooltop_rigid_barotrope<equations::BarotropicDensityBalance<EOS>>=true; } namespaceserif::utils::serialize{ template<model::StellarModelTypeModel,typenameFiniteElements,typenameState> [[nodiscard]]Result<TopExportReport>export_top(conststd::filesystem::path&directory, constModel&stellar_model,constFiniteElements&finite_elements,constState&state, constTopExportOptions&options={}){ usingDensity=discretization::blocks::density::mass; usingShape=discretization::blocks::surface_deformation::coefficients; usingOmega=discretization::blocks::rotation::angular_velocity; namespacedeformation=geometry::deformation; namespacedeform_backend=deformation::backend::mfem; namespaceadapter=serif::backend::mfem::serialize::detail; ifconstexpr(!std::same_as<typenameModel::EquationOfState,eos::models::Polytrope>){ returnstd::unexpected(Error{"top/model/eos","TOP'srecoveredpolytropereaderrequiresthePolytropeEOS;ageneralstellarEOSneedsadifferentTOPreader."}); }elseifconstexpr(!Model::templatecontains_specification<model::FixedAngularMomentum>){ returnstd::unexpected(Error{"top/model/rotation","ThisTOPadapterrequiresFixedAngularMomentumwithasolveduniformangularvelocity."}); }elseifconstexpr(!requires{ state.templateget<Density>();state.templateget<Shape>();state.templateget<Omega>(); finite_elements.templatebinding<Density>();finite_elements.deformation.reference; finite_elements.deformation.model.surface; }){ returnstd::unexpected(Error{"top/state","TOPexportrequiressolveddensity,angularvelocity,andamovingstellarsurfacewithmatchingfinite-elementbindings."}); }else{ try{ constautoequations=model::resolve_equilibrium_equations(stellar_model); ifconstexpr(!geometry::surface::IsobaricSurfaceType<decltype(equations.surface_condition)>){ returnstd::unexpected(Error{"top/model/surface","TOPpolytropeexportrequiresanexplicitlyprescribedzero-pressureisobar."}); }else{ if(equations.surface_condition.target_pressure().value()!=0.0){ returnstd::unexpected(Error{"top/model/surface","Finite-pressuresurfaceconditionsarenotsupportedbyTOP'srecoveredpolytropereader."}); } constauto&rotation=stellar_model.templatespecification<model::FixedAngularMomentum>(); doublefour_pi_G=0.0; intgravity_count=0,rigid_count=0; boolrigid_compatible=true; equations.interior_equations.for_each([&](constauto&equation){ usingEquation=std::remove_cvref_t<decltype(equation)>; ifconstexpr(std::same_as<Equation,serif::equations::PrimalPoissonBalance>){ four_pi_G=equation.four_pi_G(); ++gravity_count; } ifconstexpr(adapter::top_rigid_barotrope<Equation>){ ++rigid_count; rigid_compatible=rigid_compatible&&equation.surface_pressure().value()==0.0&& adapter::top_matching_polytrope(equation.equation_of_state(),stellar_model.equation_of_state()); for(intcomponent=0;component<3;++component){ rigid_compatible=rigid_compatible&& std::abs(equation.rotation().angular_velocity_vector()[component]-rotation.axis()[component])<1.0e-13&& equation.rotation().axis_origin()[component]==rotation.center()[component]; } } }); if(gravity_count!=1||rigid_count!=1||!rigid_compatible){ returnstd::unexpected(Error{"top/model/equations","TOPexportrequiresonePrimalPoissonBalanceandonezero-pressureBarotropicDensityBalanceusingthemodel'sEOS,uniformrotationaxis,andcenter."}); } constautoomega=state.templateget<Omega>(); if(omega.size()!=1||!std::isfinite(omega[0])){ returnstd::unexpected(Error{"top/state/rotation","Theuniformangularvelocitymustbeonefinitephysicalcoefficient."}); } constautoinputs=deform_backend::make_deformation_inputs(finite_elements.deformation.model, finite_elements.deformation.reference,state.templateget<Shape>()); usingSurface=std::remove_cvref_t<decltype(finite_elements.deformation.model.surface)>; autocache=utils::dependencies::make_computation_cache<deformation::DeformationFailure>( deform_backend::make_deformation_graph<Surface>(),inputs); constautoprepared=cache.try_prepare(inputs,utils::dependencies::KeyList<deformation::keys::VolumeDisplacement>{}); if(!prepared){ returnstd::unexpected(Error{"top/geometry",prepared.error().error.message}); } autosampler=std::make_shared<adapter::TopModelSampler>(finite_elements.templatebinding<Density>(), state.templateget<Density>(),finite_elements.deformation.reference, cache.templateget<deformation::keys::VolumeDisplacement>(),rotation.axis(),rotation.center()); constautocentral_density=sampler->density(0.0,1.0,0.0); if(!central_density){returnstd::unexpected(central_density.error());} if(!std::isfinite(*central_density)||*central_density<=0.0){ returnstd::unexpected(Error{"top/state/center","TOPnormalizationrequirespositivefinitedensityattherotationcenter."}); } constauto&eos=stellar_model.equation_of_state(); constdoublecentral_enthalpy=eos.evaluate(serif::eos::relations::SpecificEnthalpyFromDensity{}, dimensions::DensityValue{*central_density}).value(); TopPolytropeSourcesource{ .polytropic_index=eos.polytropic_index(), .gravitational_constant=four_pi_G/(4.0*std::numbers::pi), .mass=sampler->mass(),.angular_velocity=omega[0], .central_density=*central_density,.central_enthalpy=central_enthalpy, .surface_radius=[sampler](doublemu,doublephi){returnsampler->surface_radius(mu,phi);}, .enthalpy=[sampler,eos](doubleradius,doublemu,doublephi)->Result<double>{ autodensity=sampler->density(radius,mu,phi); if(!density){returnstd::unexpected(density.error());} returneos.evaluate(serif::eos::relations::SpecificEnthalpyFromDensity{},dimensions::DensityValue{*density}).value(); } }; source.roundoff_density_clamps=[sampler]{returnsampler->roundoff_density_clamps();}; returnexport_top(directory,source,options); } }catch(conststd::exception&error){ returnstd::unexpected(Error{"top/model",error.what()}); } } } template<typenameFiniteElements,typenameSolution> requiresrequires(constSolution&solution){solution.has_state();solution.model();solution.state();} [[nodiscard]]Result<TopExportReport>export_top(conststd::filesystem::path&directory, constFiniteElements&finite_elements,constSolution&solution,constTopExportOptions&options={}){ if(!solution.has_state()){ returnstd::unexpected(Error{"top/state","Thesolvehasnoacceptedstellarstatetoexport."}); } returnexport_top(directory,solution.model(),finite_elements,solution.state(),options); } }