Hello,
I wrote code that I now need to make differentiable. I’ve read the best practice docs, and my code is differentiating (REPL compile times are seriously painful though). I use AI to read my code to help me improve quality, catch errors, fix style issues. GPT 5 recommends treating “1.0” and “0.0” like this (my code is below to give context of state and the whole function).
T = eltype(state)
oneT = one(T)
zeroT = zero(T)
I understand why this is necessary if I am using arrays that may end up having elements that are not constant and need to be differentiable. But, is this really necessary for constants? It reduces code readability, for something that is obviously not differentiable anyway. I want to avoid this if possible, but don’t want to create subtle type issues if this nasty type side-effect is truly a thing.
Thanks for any help here.
BTW, general comments on the code are appreciated as I am about to finalize a style guide for functions in my library and this is a good example of where I am going.
using LinearAlgebra
“”"
kep_to_cart(state::Vector, μ; tol=1e-12)Convert a Keplerian state vector to a Cartesian state vector.
Arguments
state::Vector
: Keplerian elements[a, e, i, Ω, ω, ν]
μ
: Gravitational parametertol
: Tolerance for singularities like p ≈ 0 (default: 1e-12)a
: semi-major axise
: eccentricityi
: inclinationΩ
: right ascension of ascending nodeω
: argument of periapsisν
: true anomalyReturns
A 6-element vector
[x, y, z, vx, vy, vz]
representing Cartesian position and velocity.Notes
- Angles must be in radians.
- Dimensional quantities must be consistent units with μ.
- Returns a vector of
NaN
s if conversion is undefined (e.g., p ≈ 0).
“”"function kep_to_cart(state::Vector, μ; tol=1e-12)
if length(state) != 6
error(“Input vector must have exactly six elements: a, e, i, Ω, ω, ν.”)
endif μ < tol @warn "Conversion Failed: μ < tolerance." return fill(NaN, 6) end # Unpack the elements a, e, i, Ω, ω, ν = state # Compute semi-latus rectum: p = a * (1 - e²) p = a * (1.0 - e^2) # Check for degenerate orbit (e.g., parabolic or collapsed) if p < tol || abs(1-e) < tol @warn "Conversion Failed: Orbit is parabolic or singular." return fill(NaN, 6) end # Compute radial distance: r = p / (1 + e * cos(ν)) r = p / (1.0 + e * cos(ν)) # Position and velocity in perifocal frame factor = sqrt(μ / p) r̄ₚ = [r * cos(ν), r * sin(ν), 0.0] v̄ₚ = [-factor * sin(ν), factor * (e + cos(ν)), 0.0] # Precompute sines and cosines for rotation matrix cos_Ω, sin_Ω = cos(Ω), sin(Ω) cos_ω, sin_ω = cos(ω), sin(ω) cos_i, sin_i = cos(i), sin(i) # Rotation matrix from perifocal to inertial R = [ cos_ω * cos_Ω - sin_ω * cos_i * sin_Ω -sin_ω * cos_Ω - cos_ω * cos_i * sin_Ω sin_i * sin_Ω; cos_ω * sin_Ω + sin_ω * cos_i * cos_Ω -sin_ω * sin_Ω + cos_ω * cos_i * cos_Ω -sin_i * cos_Ω; sin_ω * sin_i cos_ω * sin_i cos_i ] # Rotate position and velocity to inertial frame pos = R * r̄ₚ vel = R * v̄ₚ return vcat(pos, vel)
end