Skip to content

Commit 903edfb

Browse files
feat: accept AbstractRange as times in *Ephemerides constructors (#215)
* feat: accept AbstractRange as times in *Ephemerides constructors Allow any AbstractRange (e.g. range(et_begin, et_end; length=n)) to be passed as the times argument. The inner constructor now calls convert(Vector{Float64}, times) so the stored field is always a Vector{Float64}. For an existing Vector{Float64} input, convert is a no-op and returns the same object, so callers do not need to change. This eliminates the boilerplate `times = collect(et_range)` line that appeared in every integration test and user script. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: pass et_range directly to *Ephemerides in integration tests Remove the `times = collect(et_range)` boilerplate now that constructors accept AbstractRange directly. et_range is passed to the constructor and the stored ephem.times is used for subsequent output spec setup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6c40271 commit 903edfb

6 files changed

Lines changed: 24 additions & 10 deletions

File tree

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Redesign the API around a Problem-Solver pattern inspired by `DifferentialEquati
8787
Non-breaking fixes and convenience improvements before the v0.3.0 surface roughness work.
8888

8989
- [ ] **Rename internal `energy_in` / `energy_out`** to `absorbed_power` / `emitted_power` — current names are physically inaccurate (units are W, not J); not exported so no breaking change
90-
- [ ] **`*Ephemerides` convenience constructors**accept `et_begin`, `et_end`, step count to assemble `times` and `r_sun` in one call, reducing user boilerplate; purely additive
90+
- [x] **`*Ephemerides` convenience constructors**`times` accepts any `AbstractRange` (e.g. `range(et_begin, et_end; length=n)`) and is automatically collected to `Vector{Float64}`, eliminating the separate `collect` call; purely additive
9191
- [ ] **Test prefix cleanup** — remove unnecessary `AsteroidThermoPhysicalModels.` prefixes from exported symbols in test files
9292

9393
## v0.3.0 - Surface Roughness Support (Target: 2026)

src/ephem_types.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ The type parameter `R` controls whether force and torque are computed:
8989
SingleAsteroidEphemerides(times, r_sun, R_body_to_inertial)
9090
-> SingleAsteroidEphemerides{Vector{SMatrix{3,3,Float64,9}}}
9191
92+
An `AbstractRange` (e.g. `range(et_begin, et_end; length=n)`) may be passed
93+
as `times` and is automatically collected to `Vector{Float64}`.
9294
Plain `AbstractVector` / `AbstractMatrix` elements in `r_sun` and
9395
`R_body_to_inertial` are automatically converted to the corresponding
9496
`SVector{3,Float64}` / `SMatrix{3,3,Float64,9}` types, so importing
@@ -111,7 +113,7 @@ struct SingleAsteroidEphemerides{R <: Union{Nothing, AbstractVector}} <: Abstrac
111113
R_body_to_inertial === nothing || length(R_body_to_inertial) == n || throw(DimensionMismatch(
112114
"R_body_to_inertial ($(length(R_body_to_inertial))) and times ($n) must have the same length"
113115
))
114-
new{R}(times, _to_svec3_vec(r_sun), R_body_to_inertial)
116+
new{R}(convert(Vector{Float64}, times), _to_svec3_vec(r_sun), R_body_to_inertial)
115117
end
116118
end
117119

@@ -165,6 +167,8 @@ R_{s2i} = R_{p2i} \\cdot R_{p2s}^{\\top}
165167
BinaryAsteroidEphemerides(times, r_sun, r_secondary, R_primary_to_secondary, R_primary_to_inertial)
166168
-> BinaryAsteroidEphemerides{Vector{SMatrix{3,3,Float64,9}}}
167169
170+
An `AbstractRange` (e.g. `range(et_begin, et_end; length=n)`) may be passed
171+
as `times` and is automatically collected to `Vector{Float64}`.
168172
Plain `AbstractVector` / `AbstractMatrix` elements are automatically converted
169173
to `SVector{3,Float64}` / `SMatrix{3,3,Float64,9}` types in all fields.
170174
"""
@@ -196,7 +200,7 @@ struct BinaryAsteroidEphemerides{R <: Union{Nothing, AbstractVector}} <: Abstrac
196200
"R_primary_to_inertial ($(length(R_primary_to_inertial))) and times ($n) must have the same length"
197201
))
198202
new{R}(
199-
times,
203+
convert(Vector{Float64}, times),
200204
_to_svec3_vec(r_sun),
201205
_to_svec3_vec(r_secondary),
202206
_to_smat33_vec(R_primary_to_secondary),

test/TPM_Didymos/TPM_Didymos.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,14 @@ See https://github.com/Astroshaper/Astroshaper-examples/tree/main/TPM_Didymos fo
7070
et_end = et_begin + P₂ * n_cycle # End time of TPM
7171
et_range = range(et_begin, et_end; length=n_step_in_cycle*n_cycle+1)
7272

73-
times = collect(et_range)
7473
r_sun = [SPICE.spkpos("SUN" , et, "DIDYMOS_FIXED", "None", "DIDYMOS")[1] for et in et_range] # Sun's position in DIDYMOS_FIXED [km]
7574
r_secondary = [SPICE.spkpos("DIMORPHOS", et, "DIDYMOS_FIXED", "None", "DIDYMOS")[1] for et in et_range] # Dimorphos position in DIDYMOS_FIXED [km]
7675
R_primary_to_secondary = [SPICE.pxform("DIDYMOS_FIXED", "DIMORPHOS_FIXED", et) for et in et_range]
7776

7877
r_sun .*= 1000 # Convert [km] to [m]
7978
r_secondary .*= 1000 # Convert [km] to [m]
8079

81-
ephem = BinaryAsteroidEphemerides(times, r_sun, r_secondary, R_primary_to_secondary)
80+
ephem = BinaryAsteroidEphemerides(et_range, r_sun, r_secondary, R_primary_to_secondary)
8281

8382
SPICE.kclear()
8483

test/TPM_Ryugu/TPM_Ryugu.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,10 @@ See https://github.com/Astroshaper/Astroshaper-examples/tree/main/TPM_Ryugu for
6262
et_end = et_begin + P * n_cycle # End time of TPM
6363
et_range = range(et_begin, et_end; length=n_step_in_cycle*n_cycle+1)
6464

65-
times = collect(et_range)
6665
r_sun = [SPICE.spkpos("SUN", et, "RYUGU_FIXED", "None", "RYUGU")[1] for et in et_range] # Sun's position in RYUGU_FIXED [km]
6766
r_sun .*= 1000 # Convert [km] to [m]
6867

69-
70-
ephem = SingleAsteroidEphemerides(times, r_sun)
68+
ephem = SingleAsteroidEphemerides(et_range, r_sun)
7169

7270
SPICE.kclear()
7371

test/TPM_non-uniform_thermoparams/TPM_non-uniform_thermoparams.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,10 @@ Based on TPM_Ryugu test but with varying thermophysical properties.
6262
et_end = et_begin + P * n_cycle # End time of TPM
6363
et_range = range(et_begin, et_end; length=n_step_in_cycle*n_cycle+1)
6464

65-
times = collect(et_range)
6665
r_sun = [SPICE.spkpos("SUN", et, "RYUGU_FIXED", "None", "RYUGU")[1] for et in et_range] # Sun's position in RYUGU_FIXED [km]
6766
r_sun .*= 1000 # Convert [km] to [m]
6867

69-
ephem = SingleAsteroidEphemerides(times, r_sun)
68+
ephem = SingleAsteroidEphemerides(et_range, r_sun)
7069

7170
SPICE.kclear()
7271

test/test_ephem_types.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,18 @@ Unit tests for parametric *Ephemerides{R} types introduced in v0.2.0:
145145
@test_throws DimensionMismatch BinaryAsteroidEphemerides(times, r_sun, r_secondary, R_primary_to_secondary[1:end-1], R_primary_to_inertial)
146146
@test_throws DimensionMismatch BinaryAsteroidEphemerides(times, r_sun, r_secondary, R_primary_to_secondary, R_primary_to_inertial[1:end-1])
147147
end
148+
149+
@testset "AbstractRange as times" begin
150+
et_range = range(0.0, 100.0; length=n)
151+
152+
ephem_s = SingleAsteroidEphemerides(et_range, r_sun)
153+
@test ephem_s.times isa Vector{Float64}
154+
@test ephem_s.times == collect(et_range)
155+
@test length(ephem_s) == n
156+
157+
ephem_b = BinaryAsteroidEphemerides(et_range, r_sun, r_secondary, R_primary_to_secondary)
158+
@test ephem_b.times isa Vector{Float64}
159+
@test ephem_b.times == collect(et_range)
160+
@test length(ephem_b) == n
161+
end
148162
end

0 commit comments

Comments
 (0)