-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ported Tdbtt #14
Ported Tdbtt #14
Conversation
src/conversions.jl
Outdated
# Combine time argument (millennia) with deg/arcsec factor. | ||
w = t / 3600.0 | ||
# Sun Mean Longitude. | ||
elsun = mod(280.46645683 + 1296027711.03429 * w, 360.0) * DEG_2R |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use deg2rad
to convert degrees to radians and remove the DEG_2R
constant. Here and below
test/runtests.jl
Outdated
@test ref == TDBEpoch(TTEpoch("2013-03-18T11:59:59.998")) | ||
@test ref == TDBEpoch(TCBEpoch("2013-03-18T12:00:17.718")) | ||
@test ref == TDBEpoch(TCGEpoch("2013-03-18T12:00:00.795")) | ||
@test UT1Epoch(ref) ≈ UT1Epoch("2013-03-18T11:58:52.994") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why approximated equality?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See below ;-)
The discrepancy seems too high to me. |
src/conversions.jl
Outdated
end | ||
# T**1 | ||
w1 = 0 | ||
for j in 679:-1:1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lower bound of this loop and of the following ones are wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The loops all work on non-overlapping segements of the coefficients (or would if they were correct 😉). Thus, the first step to simplify this would be to split coefficients into five separate arrays.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a side note, the fairhd
array is quite big and is just a container of numbers. @helgee would be a StaticArray
an option? I don't know how it'd perform in this case.
Codecov Report
@@ Coverage Diff @@
## master #14 +/- ##
==========================================
+ Coverage 96.82% 97.28% +0.46%
==========================================
Files 6 6
Lines 252 295 +43
==========================================
+ Hits 244 287 +43
Misses 8 8
Continue to review full report at Codecov.
|
@giordano If I am not mistaken, a mutable array is better in this case since it will be heap-allocated and there are no copies when it is passed around. |
src/conversions.jl
Outdated
w4 = 0 | ||
for j in 787:-1:1 | ||
w4 += fairhd[j][1] * sin(fairhd[j][2] * t + fairhd[j][3]) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there might be a more straight-forward way to compute this. These countdown-loops are bit confusing too me 😜
src/conversions.jl
Outdated
w4 += fairhd[j][1] * sin(fairhd[j][2] * t + fairhd[j][3]) | ||
end | ||
# Multiply by powers of T and combine. | ||
wf = t * (t * (t * (t * w4 + w3) + w2) + w1) + w0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. This is awful! Not your fault, of course @prakharcode .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evalpoly t w0 w1 w2 w3 w4
src/conversions.jl
Outdated
function dtdb(jd1, jd2, ut, elong, u, v) | ||
|
||
t = ((jd1 - DJ00) + jd2) / DJM | ||
# Convert UT to local solar time in radians. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is off.
src/constants.jl
Outdated
|
||
const DEG_2R = 1.745329251994329576923691e-2 | ||
|
||
const fairhd = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move this to a separate file?
The array should probably not be accessed in row-major order. |
test/runtests.jl
Outdated
@@ -170,6 +172,9 @@ AstronomicalTime.update() | |||
@test AstronomicalTime.Epochs.tttcg(julian2(tt), julian1(tt)) == ERFA.tttcg(julian2(tt), julian1(tt)) | |||
@test AstronomicalTime.Epochs.taiutc(julian1(tai), julian2(tai)) == ERFA.taiutc(julian1(tai), julian2(tai)) | |||
@test AstronomicalTime.Epochs.taiutc(julian2(tai), julian1(tai)) == ERFA.taiutc(julian2(tai), julian1(tai)) | |||
@test AstronomicalTime.Epochs.dtdb(julian1(tdb), julian2(tdb), 0.0, 0.0, 0.0, 0.0) ≈ ERFA.dtdb(julian1(tdb), julian2(tdb), 0.0, 0.0, 0.0, 0.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
==
?
src/constants.jl
Outdated
@@ -4,7 +4,7 @@ export MJD, J2000, J1950, | |||
HOURS_PER_DAY, HOURS_PER_YEAR, HOURS_PER_CENTURY, | |||
DAYS_PER_YEAR, DAYS_PER_CENTURY, | |||
YEARS_PER_CENTURY, | |||
OFFSET_TT_TAI, MOD_JD_77, ELG | |||
OFFSET_TT_TAI, MOD_JD_77, ELG, fairhd, DJM, DJ00 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The coefficients should not be exported.
I really want to get rid of these funky backwards counting loops. Does anyone have a theory why the original code is written this way? |
src/constants.jl
Outdated
@@ -34,3 +34,8 @@ const OFFSET_TT_TAI = 32.184 | |||
|
|||
const MOD_JD_77 = 43144.0 | |||
const ELG = 6.969290134e-10 | |||
const DJM = 365250.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be defined in terms of DAYS_PER_YEAR
? I guess these are days per millennium, maybe the constant can be given a more meaningful name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I assume the backward counting loops are for numerical stability in the summation, the coefficients are (mostly) decreasing in magnitude. The alternative is rewriting it to use a kbn summation or something alike. |
Since Julia uses pairwise summation this might not be needed (see JuliaLang/julia#4039). |
But |
w0 = sum(fairhd0[:,1] .* sin(fairhd0[:,2] .* t .+ fairhd0[:,3])) |
Before merging this, we may want to check its performance. Currently it's slower than the julia> tdb = TDBEpoch(2000, 1, 1, 12, 0, 0.0)
2000-01-01T12:00:00.000 TDB
julia> a = julian1(tdb)
2.4515445e6
julia> b = julian2(tdb)
0.5
julia> @benchmark ERFA.dtdb($a, $b, 0.0, 0.0, 0.0, 0.0)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 16.025 μs (0.00% GC)
median time: 16.182 μs (0.00% GC)
mean time: 16.353 μs (0.00% GC)
maximum time: 46.679 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark AstronomicalTime.Epochs.dtdb($a, $b, 0.0, 0.0, 0.0, 0.0)
BenchmarkTools.Trial:
memory estimate: 37.05 KiB
allocs estimate: 2371
--------------
minimum time: 36.573 μs (0.00% GC)
median time: 37.647 μs (0.00% GC)
mean time: 40.081 μs (3.31% GC)
maximum time: 974.220 μs (89.31% GC)
--------------
samples: 10000
evals/sample: 1 |
src/conversions.jl
Outdated
# ===================== | ||
|
||
# T**0 | ||
w0 = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
w0
… w4
are first assigned an Int64 (w0 = 0
) and then reassigned a Float64 (w0 +=
) two lines later.
Using w0 = 0.0
(same for w1
… w4
) one can prevent a costly type-instability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! 10% of improvement is very nice
This is due to a type-instability in the variables used for summation, once those are initialized as floats the allocations are gone and the performance is better. julia> b1 = @benchmark AstronomicalTime.Epochs.dtdb($a, $b, 0.123, 0.234, 0.456, 0.789)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 10.916 μs (0.00% GC)
median time: 11.054 μs (0.00% GC)
mean time: 11.063 μs (0.00% GC)
maximum time: 27.996 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
julia> b2 = @benchmark ERFA.dtdb($a, $b, 0.123, 0.234, 0.456, 0.789)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 12.242 μs (0.00% GC)
median time: 12.295 μs (0.00% GC)
mean time: 12.302 μs (0.00% GC)
maximum time: 21.806 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
julia> judge(median(b1), median(b2))
BenchmarkTools.TrialJudgement:
time: -10.09% => improvement (5.00% tolerance)
memory: +0.00% => invariant (1.00% tolerance)
|
src/conversions.jl
Outdated
w4 += fairhd[j][1] * sin(fairhd[j][2] * t + fairhd[j][3]) | ||
end | ||
# Multiply by powers of T and combine. | ||
wf = t * (t * (t * (t * w4 + w3) + w2) + w1) + w0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already wrote this before but got lost: replace this line with
wf = @evalpoly t w0 w1 w2 w3 w4
I did a few experiments. The fastest version I was able to come up with is very close to ERFA in terms of performance (consistently within 10%). It uses StaticArrays.jl after all. Originally I did not realize that the algorithm does not work on a matrix of coefficients but actually iterates over an array of small vectors. w0 = 0.0
for j in reverse(eachindex(fairhd0))
w0 += fairhd0[j][1] * sin(fairhd0[j][2] * t + fairhd0[j][3])
end Which is much nicer IMHO. |
The vector themselves can be written in the reverse order (or reversed at compile time), rather than using |
Does not make a significant difference. |
Final version, with tuples of tuples instead of StaticArrays.jl: function dtdb_tuples2(jd1, jd2, ut, elong, u, v)
t = ((jd1 - DJ00) + jd2) / DJM
# Convert UT to local solar time in radians.
tsol = mod(ut, 1.0) * 2π + elong
# FUNDAMENTAL ARGUMENTS: Simon et al. 1994.
# Combine time argument (millennia) with deg/arcsec factor.
w = t / 3600.0
# Sun Mean Longitude.
elsun = deg2rad(mod(280.46645683 + 1296027711.03429 * w, 360.0))
# Sun Mean Anomaly.
emsun = deg2rad(mod(357.52910918 + 1295965810.481 * w, 360.0))
# Mean Elongation of Moon from Sun.
d = deg2rad(mod(297.85019547 + 16029616012.090 * w, 360.0))
# Mean Longitude of Jupiter.
elj = deg2rad(mod(34.35151874 + 109306899.89453 * w, 360.0))
# Mean Longitude of Saturn.
els = deg2rad(mod(50.07744430 + 44046398.47038 * w, 360.0))
# TOPOCENTRIC TERMS: Moyer 1981 and Murray 1983.
wt = + 0.00029e-10 * u * sin(tsol + elsun - els)
+ 0.00100e-10 * u * sin(tsol - 2.0 * emsun)
+ 0.00133e-10 * u * sin(tsol - d)
+ 0.00133e-10 * u * sin(tsol + elsun - elj)
- 0.00229e-10 * u * sin(tsol + 2.0 * elsun + emsun)
- 0.02200e-10 * v * cos(elsun + emsun)
+ 0.05312e-10 * u * sin(tsol - emsun)
- 0.13677e-10 * u * sin(tsol + 2.0 * elsun)
- 1.31840e-10 * v * cos(elsun)
+ 3.17679e-10 * u * sin(tsol)
# =====================
# Fairhead et al. model
# =====================
# T**0
w0 = 0.0
for j in eachindex(fairhd0_4)
@muladd w0 += fairhd0_4[j][1] * sin(fairhd0_4[j][2] * t + fairhd0_4[j][3])
end
# T**1
w1 = 0.0
for j in eachindex(fairhd1_4)
@muladd w1 += fairhd1_4[j][1] * sin(fairhd1_4[j][2] * t + fairhd1_4[j][3])
end
# T**2
w2 = 0.0
for j in eachindex(fairhd2_4)
@muladd w2 += fairhd2_4[j][1] * sin(fairhd2_4[j][2] * t + fairhd2_4[j][3])
end
# T**3
w3 = 0.0
for j in eachindex(fairhd3_4)
@muladd w3 += fairhd3_4[j][1] * sin(fairhd3_4[j][2] * t + fairhd3_4[j][3])
end
# T**4
w4 = 0.0
for j in eachindex(fairhd4_4)
@muladd w4 += fairhd4_4[j][1] * sin(fairhd4_4[j][2] * t + fairhd4_4[j][3])
end
# Multiply by powers of T and combine.
#= wf = t * (t * (t * (t * w4 + w3) + w2) + w1) + w0 =#
wf = @evalpoly t w0 w1 w2 w3 w4
# Adjustments to use JPL planetary masses instead of IAU.
wj = 0.00065e-6 * sin(6069.776754 * t + 4.021194) +
0.00033e-6 * sin( 213.299095 * t + 5.543132) +
(-0.00196e-6 * sin(6208.294251 * t + 5.696701)) +
(-0.00173e-6 * sin( 74.781599 * t + 2.435900)) +
0.03638e-6 * t * t
# ============
# Final result
# ============
# TDB-TT in seconds.
w = wt + wf + wj
end 0.6: 10.504 μs |
Good! I'm surprised long tuples (more than 16 elements) don't have some overhead. What's performance of the function from ERFA on your machine? |
~9 μs
… Am 31.03.2018 um 19:25 schrieb Mosè Giordano ***@***.***>:
Good! I'm surprised long tuples (more than 16 elements) don't have some overhead. What's performance of the function from ERFA on your machine?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
AFAIR StaticArrays are basically NTuples with added sugar. |
@helgee is this error tolerable: |
@giordano the edits suggested by you, @helgee and @benelsen helped a lot in making the function efficient. Now the function benchmarks as follows:
|
There is no error on my machine. Did you change the direction of the loops? |
Yes @helgee, I resolved it! |
src/constants.jl
Outdated
@@ -34,3 +34,8 @@ const OFFSET_TT_TAI = 32.184 | |||
|
|||
const MOD_JD_77 = 43144.0 | |||
const ELG = 6.969290134e-10 | |||
const DAYS_PER_MILLENNIUM = 365250.0 | |||
const DJ00 = 2451545.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as J2000
You need to add the new dependency to |
Nice work everybody 🎉 |
) * Use legal generated functions for conversions * Enable precompilation * Minor refactor of Period type and whitespace cleanup * Revert "Minor refactor of Period type and whitespace cleanup" This reverts commit b375073. * Make parameter for transform macro explicit * Replacing the calls to ERFA by pure Julia functions for eraTaiutc (#13) * Replacing the calls to ERFA by pure Julia functions for eraUtctai (#15) * Ported Tdbtt (#14) * Use legal generated functions for conversions * Allow additional arguments in transform macro * Fix transform and various cleanups * Cleanup
Ported
eraTdbtt
to pure Julia.Ported dependency
eraDtdb
to pure Julia.Used approximation due to precision error.
julia> ref = TDBEpoch(2013, 3, 18, 12)
2013-03-18T12:00:00.000 TDB
julia> ifu = AstronomicalTime.Epochs.dtdb(ref.jd1, ref.jd2, 0.0, 0.0, 0.0, 0.0)
0.0015985185850907002
julia> ou = ERFA.dtdb(ref.jd1, ref.jd2, 0.0, 0.0, 0.0, 0.0)
0.0015774019690913835