Usage
julia> using SatelliteToolboxGravityModelsInitialization
We can initialize a gravity model using the function:
GravityModels.load(::Type{T}, args...; kwargs...) where {T <: AbstractGravityModel} -> Twhere the arguments and keywords depend on the gravity model type T. For ICGEM files, we must use T = IcgemFile and the following signature:
GravityModels.load(::Type{IcgemFile}, filename::AbstractString, T::Type = Float64; kwargs...)where it loads the ICGEM file in the path filename converting the coefficients to the type T. The ICGEM format does not define the angular speed of the central body, which is required to compute the gravity acceleration. Hence, it must be provided using the keyword angular_speed [rad/s] for bodies other than Earth (Default: EARTH_ANGULAR_SPEED). Both the ICGEM formats 1.0 and 2.0 are supported, including time-variable coefficients with validity intervals.
We also provide a function to help downloading the ICGEM files:
fetch_icgem_file(url::AbstractString; kwargs...)
fetch_icgem_file(model::Symbol; kwargs...)It fetches an ICGEM file from the url and returns its file path to be parsed with the function GravityModels.load. If the file already exists, it will not be re-downloaded unless the keyword force = true is passed.
Notice that the function downloads the files to a scratch space.
A symbol can be passed instead of the URL to fetch pre-configured gravity field models. The supported values are:
:EGM96: Earth Gravitational Model from 1996.:EGM2008: Earth Gravitational Model from 2008.:JGM2: Joint Gravity Model 2.:JGM3: Joint Gravity Model 3.
Finally, we can initialize, for example, the EGM96 model using:
julia> egm96 = GravityModels.load(IcgemFile, fetch_icgem_file(:EGM96))IcgemFile{Float64, Val{:full}}: Product Type : gravity_field Model Name : EGM96 Gravity Constant : 3.986004415e14 m³/s² Radius : 6.3781363e6 m Angular Speed : 7.292115147e-5 rad/s Maximum Degree : 360 Errors : formal Tide System : tide_free Normalization : full Time-Variable Coefficients : none
Workspace
All the functions that evaluate a model accept the keyword workspace, which receives an object created by:
GravityModels.Workspace(model::AbstractGravityModel; kwargs...) -> WorkspaceThe workspace holds the buffers used to compute the associated Legendre functions and their derivatives, together with precomputed recursion coefficients. Hence, when the functions are called many times for the same model, e.g. in a numerical orbit propagator, the workspace avoids allocations and largely improves the performance. The following keywords are available:
max_degree::Int: Maximum degree supported by the workspace. If it is higher than the maximum degree of the model, it will be clamped. If it is lower than 0, it will be set to the maximum degree of the model. (Default: -1)max_order::Int: Maximum order supported by the workspace. If it is higher thanmax_degree, it will be clamped. If it is lower than 0, it will be set to the same value asmax_degree. (Default: -1)T::Type{<:AbstractFloat}: Element type of the workspace, which must be the type obtained by promoting the type of the model coefficients, the element type of the position, and the type of the time used in the evaluations. (Default: type of the model coefficients)
The evaluation functions throw an ArgumentError if the workspace element type or the supported degree and order do not match the computation.
The workspace holds mutable buffers. Hence, it must not be shared among threads that evaluate the model concurrently. Create one workspace per thread instead.
julia> workspace = GravityModels.Workspace(egm96)Workspace{:full, Float64}(360, 360)
Common Keywords
The functions described in the following sections accept the keywords:
max_degree::Int: Maximum degree used in the spherical harmonics. If it is higher than the available number of coefficients in the model, it will be clamped. If it is lower than 0, it will be set to the maximum degree available. (Default: -1)max_order::Int: Maximum order used in the spherical harmonics. If it is higher thanmax_degree, it will be clamped. If it is lower than 0, it will be set to the same value asmax_degree. (Default: -1)workspace::Union{Nothing, Workspace}: Workspace created for the model as described in the previous section. If it isnothing, the buffers are allocated at every call. (Default:nothing)
The time can be passed as a DateTime object or as the number of elapsed seconds [s] from the J2000.0 epoch (2000-01-01T12:00:00). If it is omitted, the J2000.0 epoch is used.
Gravitational Potential
The following function:
GravityModels.gravitational_potential(model::AbstractGravityModel, r::AbstractVector, time = 0; kwargs...) -> RTcomputes the gravitational potential [m²/s²] using the model in the position r [m], represented in the body-fixed frame (ITRF for Earth), at instant time. The gravitational potential is the potential caused by the central body mass only, i.e., without considering the centrifugal potential.
julia> GravityModels.gravitational_potential(egm96, [6378.137e3, 0, 0]; workspace)6.25288651701736e7
Gravitational Field Derivative
The following function:
GravityModels.gravitational_field_derivative(model::AbstractGravityModel, r::AbstractVector, time = 0; kwargs...) -> RT, RT, RTcomputes the gravitational field derivative with respect to the spherical coordinates:
\[\frac{\partial U}{\partial r},~ \frac{\partial U}{\partial \phi},~ \frac{\partial U}{\partial \lambda},~\]
using the model in the position r [m], represented in the body-fixed frame (ITRF for Earth), at instant time. The derivatives have units [m/s²], [m²/s²], and [m²/s²], respectively.
julia> GravityModels.gravitational_field_derivative(egm96, [6378.137e3, 0, 0]; workspace)(-9.814284376497435, 49.45906319416966, -115.71285105900408)
Gravitational Acceleration
The gravitational acceleration is the acceleration caused by the central body mass only, i.e., without considering the centrifugal potential. We can compute it using the function:
GravityModels.gravitational_acceleration(model::AbstractGravityModel, r::AbstractVector, time = 0; kwargs...) -> SVector{3, RT}where it returns the gravitational acceleration [m/s²] represented in the body-fixed frame (ITRF for Earth) using the model in the position r [m], also represented in the body-fixed frame, at instant time.
julia> GravityModels.gravitational_acceleration(egm96, [6378.137e3, 0, 0]; workspace)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): -9.814284376497435 -1.814210812013039e-5 7.754468615862227e-6
The algorithm is accurate at the poles, including positions exactly on the polar axis:
julia> GravityModels.gravitational_acceleration(egm96, [0, 0, 6356.7523e3]; workspace)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): 6.121527859294718e-5 -7.274272056974707e-5 -9.83208158872835
Gravity Acceleration
The gravity acceleration is the compound acceleration caused by the central body mass and the centrifugal force due to the body's rotation. We can compute it using the function:
GravityModels.gravity_acceleration(model::AbstractGravityModel, r::AbstractVector, time = 0; kwargs...) -> SVector{3, RT}where it computes the gravity acceleration [m/s²] represented in the body-fixed frame (ITRF for Earth) using the model in the position r [m], also represented in the body-fixed frame, at instant time. Besides the common keywords, this function accepts:
ω::Number: Angular speed of the body [rad/s], which defaults to the value stored in the model (seeGravityModels.angular_speed). (Default:GravityModels.angular_speed(model))
Thus, we can compute the gravity acceleration in the Equator using the EGM96 model by:
julia> GravityModels.gravity_acceleration(egm96, [6378.137e3, 0, 0]; workspace)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): -9.780368669155786 -1.814210812013039e-5 7.754468615862227e-6
Whereas we can obtain the gravity acceleration at the North pole by:
julia> GravityModels.gravity_acceleration(egm96, [0, 0, 6356.7523e3]; workspace)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): 6.121527859294718e-5 -7.274272056974707e-5 -9.83208158872835
Automatic Differentiation
The evaluation functions can be differentiated with respect to the position and the time using ForwardDiff.jl. If both ForwardDiff.jl and Zygote.jl are loaded, a package extension provides the reverse rules required by Zygote.jl, whose pullbacks compute the Jacobians with ForwardDiff.jl. Notice that the workspace cannot be used in this case because its buffers cannot store the dual numbers.