Introduce a better rise/transit/set calculator#168
Conversation
There was a problem hiding this comment.
Pull Request Overview
The PR replaces the previous rising/transit/setting events calculator with a new, faster algorithm while updating tests and related integrations.
- Renames and refactors the calculator to use array-based event times (rising_times, transit_times, setting_times).
- Removes the old RisingTransitSettingEventsCalculator and adds a new RiseTransitSetCalculator.
- Updates supporting files and tests (including twilight events and maths helpers) to integrate the new event calculations.
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| spec/astronoby/events/rise_transit_set_calculator_spec.rb | Renamed spec and updated expectations to use array-based event times. |
| lib/astronoby/util/maths.rb | Added a new linspace helper for array generation in interpolation. |
| lib/astronoby/events/twilight_events.rb | Updated event access and passed utc_offset to align with new API. |
| lib/astronoby/events/rise_transit_set_calculator.rb | Introduced the new calculator with a more performant interpolation logic. |
| lib/astronoby/events/rise_transit_set_events.rb | Added a new events container class reflecting the new API. |
| lib/astronoby/constants.rb | Added MICROSECOND_IN_DAYS constant used in time adjustments. |
| lib/astronoby.rb | Updated requires to load the new calculator and events class. |
Comments suppressed due to low confidence (1)
spec/astronoby/events/rise_transit_set_calculator_spec.rb:29
- [nitpick] It would improve clarity to document that the first element in the array is assumed to be the primary event, given that a day may yield multiple events.
expect(events.rising_times.first)
e2fd7d3 to
3f10c79
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a new, more performant and streamlined rise/transit/set calculator along with a corresponding twilight calculator while deprecating the old rising/transit/setting events calculator. Key changes include replacing the old calculator with the new RiseTransitSetCalculator, updating related test specs, and adding a utility method (linspace) for numerical interpolation across the codebase.
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| spec/astronoby/util/maths_spec.rb | Added tests for the new linspace method. |
| spec/astronoby/events/twilight_calculator_spec.rb | Updated specs to use the new TwilightCalculator API. |
| spec/astronoby/events/rise_transit_set_calculator_spec.rb | Updated tests to match renaming of calculator and event attribute changes. |
| lib/astronoby/util/maths.rb | Introduced the linspace method. |
| lib/astronoby/events/* | Refactored calculator-related implementations and removed deprecated modules. |
Comments suppressed due to low confidence (1)
spec/astronoby/events/twilight_calculator_spec.rb:355
- The variable name 'calulator' appears to be a typo. It should be renamed to 'calculator' to maintain clarity and consistency.
calulator = described_class.new(
## 0.7.0 - 2025-05-12 _If you are upgrading: please see [UPGRADING.md]._ ### Bug fixes * Fix Moon monthly phase events calculation by @valeriy-sokoloff in ([#124]) ### Features * Add `Instant` value object ([#121]) * Introduce barycentric position of Solar System major bodies ([#127]) * Introduce Astrometric position for planets ([#129]) * Rename Barycentric into Geometric ([#130]) * Rename IRCF and remove module Position ([#131]) * Geometric and Astrometric reference frames with coordinates ([#132]) * Ecliptic coordinates for Geometric and Astrometric reference frames ([#134]) * Add Geometric and Astrometric positions for `Sun` and `Moon` ([#135]) * Implement new aberration correction ([#136]) * Precession matrix for 2006 P03 model ([#137]) * Introduce `MeanOfDate` reference frame ([#138]) * New nutation model ([#141]) * Light deflection correction ([#142]) * Introduce `Apparent` reference frame ([#143]) * Introduce `Topocentric` reference frame ([#145]) * Improve Vector integration with value objects ([#146]) * Handle refracted topocentric horizontal coordinates ([#147]) * Add `#angular_diameter` to apparent and topocentric reference frames ([#149]) * Introduce new calculator for rising, transit and setting times ([#148]) * Clean code after Ephem refactoring ([#152]) * Improve `RisingTransitSettingEventsCalculator` ([#155]) * Simplify `RisingTransitSettingEventsCalculator` ([#156]) * Lazy-load reference frames ([#157]) * Overall performance improvements ([#163]) * Add support for IMCCE INPOP by @JoelQ and @rhannequin ([#166]) * Update INPOP excerpt in spec data ([#167]) * Introduce a better rise/transit/set calculator ([#168]) * Drop `Astronoby::Observer#observe` ([#174]) ### Improvements * Bump standard from 1.42.1 to 1.49.0 by @dependabot ([#123], [#128], [#150], [#165]) * Bump rubyzip from 2.3.2 to 2.4.1 by @dependabot ([#120]) * Add more tests for Julian Date conversion ([#122]) * Upgrade main Ruby version and supported ones ([#125]) * Update email address and gem description ([#126]) * Increase precision of mean obliquity ([#133]) * Add supported Rubies ([#139]) * Set Ruby 3.4.2 as default version ([#140]) * Fix dependency secutiry patch ([#151]) * Improve HMS/DMS formats ([#153]) * Use excerpts ephemerides for specs of Sun and Moon ([#154]) * Add link to deprecated documentation ([#160]) * Default Ruby 3.4.3 and support recent rubies ([#169]) * Better Moon phases test coverage ([#172]) * Optimize Observer with GMST from Instant ([#173]) * Update README about documentation location ([#175]) * Add GitHub Actions permissions ([#176]) ### New Contributors * @valeriy-sokoloff made their first contribution in #124 * @JoelQ made their first contribution in #166 **Full Changelog**: v0.6.0...v0.7.0 [#120]: #120 [#121]: #121 [#122]: #122 [#123]: #123 [#124]: #124 [#125]: #125 [#126]: #126 [#127]: #127 [#128]: #128 [#129]: #129 [#130]: #130 [#131]: #131 [#132]: #132 [#133]: #133 [#134]: #134 [#135]: #135 [#136]: #136 [#137]: #137 [#138]: #138 [#139]: #139 [#140]: #140 [#141]: #141 [#142]: #142 [#143]: #143 [#145]: #145 [#146]: #146 [#147]: #147 [#148]: #148 [#149]: #149 [#150]: #150 [#151]: #151 [#152]: #152 [#153]: #153 [#154]: #154 [#155]: #155 [#156]: #156 [#157]: #157 [#160]: #160 [#163]: #163 [#165]: #165 [#166]: #166 [#167]: #167 [#168]: #168 [#169]: #169 [#172]: #172 [#173]: #173 [#174]: #174 [#175]: #175 [#176]: #176 [UPGRADING.md]: https://github.com/rhannequin/astronoby/blob/main/UPGRADING.md
Yes, I know, it must be the third calculator I introduce between two versions, I just never feel completely satisfied.
The previous calculator was accurate and provided many different attribute, but it was way too slow (see comparison below).
There are two common use cases I identified:
Another thing, because of time zones and the motion of celestial bodies in space, there are occurrences with several events the same day, or no event at all.
I realised it might be foolish to try to apply a strict definition (and a strict API) to phenomenons that don't happen the same way. At the end of the day, Astronoby is here to provide astronomical data, it is not an integrated tool with a specific use-case in mind.
This PR introduces
Astronoby::RiseTransitSetCalculator(yes the name changed slightly, mostly because it's shorter), a calculator of rising, transit and setting times (and only times) with a more performant and readable algorithm. It is inspired by Skyfield's almanac algorithm, but behaves slightly different.Initialization
It takes 3 key arguments:
observer(Astronoby::Observer)body(Astronoby::SolarSystemBody, i.e.Astronoby::Sun)ephem(Astronoby::Ephem)Calculation
The calculator enables to compute times for a given date, of that would happen in a time range.
Please note that the rising and setting's azimuth angles, and the transit's elevation angle are not computed anymore. The new algorithm focuses on performance and computing events (times). If one is interested in having these angles, they can be computed individually from the topocentric position.
Depending on the method used, it will return either a
RiseTransitSetEventor aRiseTransitSetEventsobject.Astronoby::RiseTransitSetEventexposes 3 attributes:#rising_time(Time)#transit_time(Time)#setting_time(Time)Astronoby::RiseTransitSetEventsexposes 3 attributes:#rising_times(Array)#transit_times(Array)#setting_times(Array)As you can see,
RiseTransitSetEventsexposes arrays. While in 99+% of cases a celestial body will rise, transit and set only once in a day, it is possible to have no or several values, especially for rising and setting times.One common example relates to the Moon. Because of its rotation around the Earth, its rising, transit and setting times are very different each day. When one of the happens very close to the beginning or the end of a day, the next one might "skip" a day.
Another example relates to the Sun and time zones. When dealing with UTC times, it might look like the Sun rises or sets twice in the same date, which is not true from the observer's point of view, but a "UTC day" is not the same defined period of time as the day from an observer at a longitude far from the Greenwich meridian.
Single date, support for only one event:
#event_onSingle date, support for multiple events:
#events_onTime range:
#events_betweenPerformance improvements
This was the main reason for implementing a new algorithm. Here is an example of code meant to compute the events for the whole year of 2025 using the previous algorithm which was only able to compute one day at a time:
Now, the same experiment but using the new algorithm:
The new algorithm is more than 4.7 times faster over a large range of dates.
Twilight events adaptation
This was the opportunity to adapt the twilght events into a similar behaviour. Now, it also uses a calculator:
It also still supports the
time_for_zenith_anglemethod: