mixed_gravity.hpp cmath tuple string_view stdexcept serif/equations/contributions.hpp serif/equations/point.hpp serif/utils/error/errors.hpp src/compile_time_checks/serif/model/execution_validation.cpp src/compile_time_checks/serif/model/normalization.cpp src/compile_time_checks/serif/operators/coordinate_identity_meanfield.cpp src/compile_time_checks/serif/operators/plan.cpp src/compile_time_checks/serif/solver/normalization/plan.cpp src/include/serif/equations/equations.hpp serif::equations::gravity_contributions::GradientValue serif::equations::gravity_contributions::PotentialValue serif::equations::gravity_contributions::GradientDivergence serif::equations::gravity_contributions::DensitySource serif::equations::GravityGradientRelation serif::equations::PoissonBalance serif serif::equations serif::equations::gravity_contributions File containing the mixed gravity equation and its contributions. Emily M. Boudreaux In SERiF we used a mixed formulation when solving for the gravitational potential and gravitational field. This is a pragmatic choice to try to avoid loss of accuracy when differentiating the potential to get the field. More specifically, if we were to just solve for the potential and then differentiate to get the field we would lose one order of accuracy in the field when compared to the potential. Due to the required accuracy in virialization (which is fundamentally related to the gravitational field) we cannot afford to loose that order and maintain the low-ish resolution mesh we use. I was already solving for potential when I went this route so I wanted to keep it. I suppose there is some world where you could solve for the field and then integrate it to get the potential; however, I have not thought deeply about the effects that would have on either the accuracy or run-time performance. As it stands we solve for the potential and the field separately but simultaneously and we weakly constrain them to agree. #pragmaonce #include<cmath> #include<tuple> #include<string_view> #include<stdexcept> #include"serif/equations/contributions.hpp" #include"serif/equations/point.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::equations{ //TODO:IknowthatthesedeeplynestednamespacesarereallyaC++no-no(orasweinthebizcallthemananit-pattern).Ithink //mybackgroundasapythondevmakesmelikethem,butperhapsatsomepointweshouldgothroughandflattenthisoutsowe //avoidhavingtheselongaliasdefinitionsatthestartsofclassesandnamespaces(whichisalsobadinaheadertobeginwith)? //Somethingtothinkabout namespacegravity_contributions{ usingGradient=discretization::blocks::gravity::gradient; usingPotential=discretization::blocks::gravity::potential; usingDensity=discretization::blocks::density::mass; usingValue=discretization::forms::Operation::Value; usingDivergence=discretization::forms::Operation::Divergence; template<typenameTerm,typenameOperation=Value> usingOperand=discretization::forms::Operand<Term, Operation>; structGradientValue:Contribution<Operand<Gradient>>{ usingOperands=utils::types::TypeList<Operand<Gradient>>; staticPointLinearization<Operands, discretization::forms::VectorValue>evaluate( constEquationPoint<Operands>&point ){ PointLinearization<Operands, discretization::forms::VectorValue>result; result.residual=point.fields.get<Gradient>(); for(intaxis=0;axis<3;++axis){ result.field_derivatives.get<Gradient>()[axis][axis]=1.0; } returnresult; } staticintadditional_order(Operand<Gradient>/*operand-type*/,int/*position-order*/){ return0; } }; structPotentialValue:Contribution<Operand<Gradient,Divergence>>{ usingOperands=utils::types::TypeList<Operand<Potential>>; staticPointLinearization<Operands>evaluate(constEquationPoint<Operands>&point){ PointLinearization<Operands>result; result.residual=point.fields.get<Potential>(); result.field_derivatives.get<Potential>()=1.0; returnresult; } staticintadditional_order(Operand<Potential>/*operand-type*/,int/*position-order*/){ return0; } }; structGradientDivergence:Contribution<Operand<Potential>>{ usingOperands=utils::types::TypeList<Operand<Gradient, Divergence>>; PointLinearization<Operands>evaluate( constEquationPoint<Operands>&point )const{ PointLinearization<Operands>result; result.residual=point.fields.get<Operand<Gradient, Divergence>>(); result.field_derivatives.get<Operand<Gradient, Divergence>>()=1.0; returnresult; } intadditional_order(Operand<Gradient, Divergence>,int)const{ return0; } }; structDensitySource:Contribution<Operand<Potential>,discretization::domain::StellarDomains>{ usingOperands=utils::types::TypeList<Operand<Density>>; doublefour_pi_G; explicitDensitySource(doublecoefficient):four_pi_G(coefficient){} PointLinearization<Operands>evaluate( constEquationPoint<Operands>&point )const{ PointLinearization<Operands>result; result.residual=-four_pi_G*point.fields.templateget<Density>(); result.field_derivatives.templateget<Density>()=-four_pi_G; returnresult; } intadditional_order(Operand<Density>,int)const{ return0; } }; }//namespacegravity_contributions structGravityGradientRelation{ usingTest=discretization::blocks::gravity::gradient; usingResidualQuantity=dimensions::Acceleration; staticconstexprstd::string_viewname="gravity-gradientrelation"; autocontributions()const{ returnstd::tuple{gravity_contributions::GradientValue{},gravity_contributions::PotentialValue{}}; } }; classPoissonBalance{ public: usingTest=discretization::blocks::gravity::potential; usingResidualQuantity=dimensions::InverseTimeSquared; staticconstexprstd::string_viewname="Poissonbalance"; explicitPoissonBalance(doublefour_pi_G):m_four_pi_G(four_pi_G){ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::INVALID_ARGUMENT,std::invalid_argument>(std::isfinite(four_pi_G)&&four_pi_G>0.0,"Poissonbalancerequirespositivefinite4piG."); } autocontributions()const{ returnstd::tuple{gravity_contributions::GradientDivergence{},gravity_contributions::DensitySource{m_four_pi_G}}; } private: doublem_four_pi_G; }; }//namespaceserif::equations