astronoby 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +145 -3
  4. data/README.md +59 -33
  5. data/UPGRADING.md +75 -21
  6. data/docs/README.md +224 -0
  7. data/docs/angles.md +137 -0
  8. data/docs/configuration.md +98 -0
  9. data/docs/coordinates.md +167 -0
  10. data/docs/deep_sky_bodies.md +101 -0
  11. data/docs/ephem.md +85 -0
  12. data/docs/equinoxes_solstices_times.md +31 -0
  13. data/docs/glossary.md +152 -0
  14. data/docs/instant.md +139 -0
  15. data/docs/moon_phases.md +79 -0
  16. data/docs/observer.md +65 -0
  17. data/docs/reference_frames.md +138 -0
  18. data/docs/rise_transit_set_times.md +119 -0
  19. data/docs/solar_system_bodies.md +107 -0
  20. data/docs/twilight_times.md +123 -0
  21. data/lib/astronoby/angle.rb +6 -2
  22. data/lib/astronoby/angular_velocity.rb +76 -0
  23. data/lib/astronoby/bodies/deep_sky_object.rb +44 -0
  24. data/lib/astronoby/bodies/deep_sky_object_position.rb +127 -0
  25. data/lib/astronoby/bodies/earth.rb +12 -2
  26. data/lib/astronoby/bodies/jupiter.rb +17 -0
  27. data/lib/astronoby/bodies/mars.rb +17 -0
  28. data/lib/astronoby/bodies/mercury.rb +21 -0
  29. data/lib/astronoby/bodies/moon.rb +50 -36
  30. data/lib/astronoby/bodies/neptune.rb +21 -0
  31. data/lib/astronoby/bodies/saturn.rb +26 -0
  32. data/lib/astronoby/bodies/solar_system_body.rb +162 -27
  33. data/lib/astronoby/bodies/sun.rb +25 -2
  34. data/lib/astronoby/bodies/uranus.rb +5 -0
  35. data/lib/astronoby/bodies/venus.rb +25 -0
  36. data/lib/astronoby/cache.rb +189 -0
  37. data/lib/astronoby/configuration.rb +92 -0
  38. data/lib/astronoby/constants.rb +11 -3
  39. data/lib/astronoby/constellation.rb +12 -0
  40. data/lib/astronoby/constellations/data.rb +42 -0
  41. data/lib/astronoby/constellations/finder.rb +35 -0
  42. data/lib/astronoby/constellations/repository.rb +20 -0
  43. data/lib/astronoby/coordinates/equatorial.rb +5 -8
  44. data/lib/astronoby/data/constellations/constellation_names.dat +88 -0
  45. data/lib/astronoby/data/constellations/indexed_abbreviations.dat +88 -0
  46. data/lib/astronoby/data/constellations/radec_to_index.dat +238 -0
  47. data/lib/astronoby/data/constellations/sorted_declinations.dat +202 -0
  48. data/lib/astronoby/data/constellations/sorted_right_ascensions.dat +237 -0
  49. data/lib/astronoby/distance.rb +6 -0
  50. data/lib/astronoby/equinox_solstice.rb +2 -2
  51. data/lib/astronoby/events/extremum_calculator.rb +233 -0
  52. data/lib/astronoby/events/extremum_event.rb +15 -0
  53. data/lib/astronoby/events/moon_phases.rb +15 -14
  54. data/lib/astronoby/events/rise_transit_set_calculator.rb +39 -12
  55. data/lib/astronoby/events/twilight_calculator.rb +116 -61
  56. data/lib/astronoby/events/twilight_events.rb +28 -0
  57. data/lib/astronoby/instant.rb +34 -6
  58. data/lib/astronoby/julian_date.rb +78 -0
  59. data/lib/astronoby/mean_obliquity.rb +8 -10
  60. data/lib/astronoby/nutation.rb +11 -3
  61. data/lib/astronoby/observer.rb +1 -1
  62. data/lib/astronoby/precession.rb +48 -38
  63. data/lib/astronoby/reference_frame.rb +2 -1
  64. data/lib/astronoby/reference_frames/apparent.rb +1 -11
  65. data/lib/astronoby/reference_frames/mean_of_date.rb +1 -1
  66. data/lib/astronoby/reference_frames/topocentric.rb +2 -12
  67. data/lib/astronoby/stellar_propagation.rb +162 -0
  68. data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +22 -0
  69. data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +64 -0
  70. data/lib/astronoby/time/greenwich_sidereal_time.rb +20 -58
  71. data/lib/astronoby/time/local_apparent_sidereal_time.rb +42 -0
  72. data/lib/astronoby/time/local_mean_sidereal_time.rb +42 -0
  73. data/lib/astronoby/time/local_sidereal_time.rb +35 -26
  74. data/lib/astronoby/time/sidereal_time.rb +42 -0
  75. data/lib/astronoby/true_obliquity.rb +2 -3
  76. data/lib/astronoby/util/time.rb +62 -44
  77. data/lib/astronoby/velocity.rb +5 -0
  78. data/lib/astronoby/version.rb +1 -1
  79. data/lib/astronoby.rb +19 -1
  80. metadata +71 -11
  81. data/Gemfile +0 -5
  82. data/Gemfile.lock +0 -102
  83. data/benchmark/README.md +0 -131
  84. data/benchmark/benchmark.rb +0 -259
  85. data/benchmark/data/imcce.csv.zip +0 -0
  86. data/benchmark/data/sun_calc.csv.zip +0 -0
  87. data/lib/astronoby/epoch.rb +0 -22
data/benchmark/README.md DELETED
@@ -1,131 +0,0 @@
1
- # Benchmark
2
-
3
- This is a first attempt to benchmark the accuracy of the library. It is not
4
- very scientific, but it gives a rough idea.
5
-
6
- ## Method
7
-
8
- The goal is to answer these two questions:
9
- - Is the library accurate enough compared to a source of truth?
10
- - Is the library accurate enough compared with other Ruby libraries?
11
-
12
- The source of truth is the <abbr title="Institut de Mécanique
13
- Céleste et de Calcul des Éphémérides">IMCCE</abbr>, a French public
14
- institude attached to the Paris Observatory. Their ephemerides are used by
15
- governements and public institutions in multiple European countries, their
16
- precesion is among the highest in the world.
17
- They also provide web services to easily access all their data. Many thanks
18
- for providing such high accuracy data for free.
19
-
20
- The other Ruby library is [sun_calc](https://github.com/fishbrain/sun_calc).
21
-
22
- 474,336 combinations of dates, latitudes and longitudes have been used to
23
- produce time predictions for the following events:
24
- - sunrise
25
- - sun's highest point
26
- - sunset
27
- - moonrise
28
- - moon's highest point
29
- - moonset
30
-
31
- For each combination, we first find out which of SunCalc or Astronoby is the
32
- closest to the IMCCE. Then we calculate the difference between Astronoby and
33
- the IMCCE, to discover if the difference is larger than the defined
34
- threshold of 5 minutes.
35
-
36
- ## Results
37
-
38
- The following output has been generated using what will be part of version 0.6.
39
-
40
- ```
41
- Unarchiving sun_calc.csv.zip...
42
- Done unarchiving sun_calc.csv.zip.
43
- Parsing sun_calc.csv...
44
- Done parsing sun_calc.csv.
45
- Unarchiving imcce.csv.zip...
46
- Done unarchiving imcce.csv.zip.
47
- Parsing imcce.csv...
48
- Done parsing imcce.csv.
49
- Comparing data...
50
- 2024-01-01: Done.
51
- 2024-01-02: Done.
52
- ...
53
- 2024-12-30: Done.
54
- 2024-12-31: Done.
55
- Done comparing data.
56
-
57
-
58
- Sun rising time:
59
- astronoby: 295395 (62.28%)
60
- sun_calc: 99710 (21.02%)
61
- n/a: 79231 (16.7%)
62
-
63
- Sun transit time:
64
- astronoby: 434495 (91.6%)
65
- sun_calc: 39769 (8.38%)
66
- n/a: 72 (0.02%)
67
-
68
- Sun setting time:
69
- astronoby: 358428 (75.56%)
70
- n/a: 79231 (16.7%)
71
- sun_calc: 36677 (7.73%)
72
-
73
- Moon rising time:
74
- astronoby: 290866 (61.32%)
75
- n/a: 113815 (23.99%)
76
- sun_calc: 69655 (14.68%)
77
-
78
- Moon transit time:
79
- astronoby: 341902 (72.08%)
80
- n/a: 101916 (21.49%)
81
- sun_calc: 30518 (6.43%)
82
-
83
- Moon setting time:
84
- astronoby: 327099 (68.96%)
85
- n/a: 114308 (24.1%)
86
- sun_calc: 32929 (6.94%)
87
-
88
- Moon illuminated fraction:
89
- astronoby: 474336 (100.0%)
90
-
91
- Sun rising time too far:
92
- false: 452887 (95.48%)
93
- true: 21449 (4.52%)
94
-
95
- Sun transit time too far:
96
- false: 396617 (83.62%)
97
- true: 77719 (16.38%)
98
-
99
- Sun setting time too far:
100
- false: 453208 (95.55%)
101
- true: 21128 (4.45%)
102
-
103
- Moon rising time too far:
104
- false: 459044 (96.78%)
105
- true: 15292 (3.22%)
106
-
107
- Moon transit time too far:
108
- false: 384516 (81.06%)
109
- true: 89820 (18.94%)
110
-
111
- Moon setting time too far:
112
- false: 459222 (96.81%)
113
- true: 15114 (3.19%)
114
- ```
115
-
116
- ## Conclusion
117
-
118
- As we can see, Astronoby is more accurate than SunCalc in a vast majority of
119
- cases. When it comes to the Moon's illuminated fraction, Astronoby is always
120
- more accurate than SunCalc.
121
-
122
- `n/a` values means that at least one of the three sources don't have a value
123
- for the combination of date, latitude and longitude. This happens because
124
- the Moon and the Sun cannot always rise, transit and set everywhere on Earth
125
- every day of the year. Latitudes close to the poles are more likely to miss
126
- data.
127
-
128
- Astronoby can be considered "good enough" for more around 90% of the cases,
129
- which means there is still work to do if we want to always be less than 5
130
- minutes away from the what the IMCCE provides. We can notice that transit
131
- times are those that experience the most significant differences.
@@ -1,259 +0,0 @@
1
- require "astronoby"
2
- require "csv"
3
- require "zip"
4
-
5
- class Source
6
- NAMES = [
7
- ASTRONOBY = "astronoby",
8
- IMCCE = "imcce",
9
- SUN_CALC = "sun_calc"
10
- ].freeze
11
-
12
- attr_accessor :name,
13
- :sun_rising_time,
14
- :sun_transit_time,
15
- :sun_setting_time,
16
- :moon_rising_time,
17
- :moon_transit_time,
18
- :moon_setting_time,
19
- :moon_illuminated_fraction
20
- end
21
-
22
- class Comparison
23
- SUN_CALC = "sun_calc"
24
- ASTRONOBY = "astronoby"
25
- NON_APPLICABLE = "n/a"
26
-
27
- TOO_FAR_THRESHOLD = 60 * 5 # 5 minutes
28
-
29
- attr_accessor :sources, :truth
30
-
31
- def initialize
32
- @sources = []
33
- end
34
-
35
- %i[
36
- sun_rising_time
37
- sun_transit_time
38
- sun_setting_time
39
- moon_rising_time
40
- moon_transit_time
41
- moon_setting_time
42
- ].each do |attribute|
43
- define_method(:"closest_#{attribute}") do
44
- compare(attribute)
45
- end
46
-
47
- define_method(:"#{attribute}_too_far?") do
48
- too_far?(attribute)
49
- end
50
- end
51
-
52
- def closest_moon_illuminated_fraction
53
- compare(:moon_illuminated_fraction)
54
- end
55
-
56
- private
57
-
58
- def compare(attribute)
59
- unless truth.public_send(attribute) && sources.all? { |source| source.public_send(attribute) }
60
- return NON_APPLICABLE
61
- end
62
-
63
- closest_source = sources.min_by do |source|
64
- (truth.public_send(attribute) - source.public_send(attribute)).abs
65
- end
66
-
67
- closest_source.name
68
- end
69
-
70
- def too_far?(attribute)
71
- truth_attribute = truth.public_send(attribute)
72
- astronoby_attribute = sources
73
- .find { _1.name == Source::ASTRONOBY }
74
- .public_send(attribute)
75
-
76
- return false unless truth_attribute && astronoby_attribute
77
-
78
- (truth_attribute - astronoby_attribute).abs > TOO_FAR_THRESHOLD
79
- end
80
- end
81
-
82
- class Result
83
- def initialize
84
- @sun_rising_time = []
85
- @sun_transit_time = []
86
- @sun_setting_time = []
87
- @moon_rising_time = []
88
- @moon_transit_time = []
89
- @moon_setting_time = []
90
- @illuminated_fraction = []
91
- @sun_rising_time_too_far = []
92
- @sun_transit_time_too_far = []
93
- @sun_setting_time_too_far = []
94
- @moon_rising_time_too_far = []
95
- @moon_transit_time_too_far = []
96
- @moon_setting_time_too_far = []
97
- end
98
-
99
- def add_comparison(comparison)
100
- @sun_rising_time << comparison.closest_sun_rising_time
101
- @sun_transit_time << comparison.closest_sun_transit_time
102
- @sun_setting_time << comparison.closest_sun_setting_time
103
- @moon_rising_time << comparison.closest_moon_rising_time
104
- @moon_transit_time << comparison.closest_moon_transit_time
105
- @moon_setting_time << comparison.closest_moon_setting_time
106
- @illuminated_fraction << comparison.closest_moon_illuminated_fraction
107
- @sun_rising_time_too_far << comparison.sun_rising_time_too_far?
108
- @sun_transit_time_too_far << comparison.sun_transit_time_too_far?
109
- @sun_setting_time_too_far << comparison.sun_setting_time_too_far?
110
- @moon_rising_time_too_far << comparison.moon_rising_time_too_far?
111
- @moon_transit_time_too_far << comparison.moon_transit_time_too_far?
112
- @moon_setting_time_too_far << comparison.moon_setting_time_too_far?
113
- end
114
-
115
- def display
116
- puts "Sun rising time:"
117
- tally(@sun_rising_time)
118
- puts "Sun transit time:"
119
- tally(@sun_transit_time)
120
- puts "Sun setting time:"
121
- tally(@sun_setting_time)
122
- puts "Moon rising time:"
123
- tally(@moon_rising_time)
124
- puts "Moon transit time:"
125
- tally(@moon_transit_time)
126
- puts "Moon setting time:"
127
- tally(@moon_setting_time)
128
- puts "Moon illuminated fraction:"
129
- tally(@illuminated_fraction)
130
- puts "Sun rising time too far:"
131
- tally(@sun_rising_time_too_far)
132
- puts "Sun transit time too far:"
133
- tally(@sun_transit_time_too_far)
134
- puts "Sun setting time too far:"
135
- tally(@sun_setting_time_too_far)
136
- puts "Moon rising time too far:"
137
- tally(@moon_rising_time_too_far)
138
- puts "Moon transit time too far:"
139
- tally(@moon_transit_time_too_far)
140
- puts "Moon setting time too far:"
141
- tally(@moon_setting_time_too_far)
142
- end
143
-
144
- private
145
-
146
- def tally(data)
147
- t = data.tally
148
- t.sort_by { |_key, value| -value }.each do |key, value|
149
- puts "#{key}: #{value} (#{(value.to_f / t.values.sum * 100).round(2)}%)"
150
- end
151
- puts "\n"
152
- end
153
- end
154
-
155
- data = {}
156
- result = Result.new
157
-
158
- sun_calc_zip_file = File.join(File.dirname(__FILE__), "data/sun_calc.csv.zip")
159
- imcce_zip_file = File.join(File.dirname(__FILE__), "data/imcce.csv.zip")
160
-
161
- puts "Unarchiving sun_calc.csv.zip..."
162
-
163
- Zip::File.open(sun_calc_zip_file) do |zip_file|
164
- puts "Done unarchiving sun_calc.csv.zip."
165
-
166
- csv_file = zip_file.find { |entry| entry.name.end_with?(".csv") }
167
- break unless csv_file
168
-
169
- puts "Parsing sun_calc.csv..."
170
-
171
- csv_content = csv_file.get_input_stream.read
172
- CSV.parse(csv_content, headers: true) do |row|
173
- data[row["date"]] ||= {}
174
- data[row["date"]][row["latitude"]] ||= {}
175
- data[row["date"]][row["latitude"]][row["longitude"]] = Comparison.new.tap do |comparison|
176
- source = Source.new.tap do |source|
177
- source.name = Source::SUN_CALC
178
- source.sun_rising_time = Time.new(row["sun_rising_time"]) if row["sun_rising_time"]
179
- source.sun_transit_time = Time.new(row["sun_transit_time"]) if row["sun_transit_time"]
180
- source.sun_setting_time = Time.new(row["sun_setting_time"]) if row["sun_setting_time"]
181
- source.moon_rising_time = Time.new(row["moon_rising_time"]) if row["moon_rising_time"]
182
- source.moon_transit_time = Time.new(row["moon_transit_time"]) if row["moon_transit_time"]
183
- source.moon_setting_time = Time.new(row["moon_setting_time"]) if row["moon_setting_time"]
184
- source.moon_illuminated_fraction = row["illuminated_fraction"].to_f
185
- end
186
- comparison.sources << source
187
- end
188
- end
189
-
190
- puts "Done parsing sun_calc.csv."
191
- end
192
-
193
- puts "Unarchiving imcce.csv.zip..."
194
-
195
- Zip::File.open(imcce_zip_file) do |zip_file|
196
- puts "Done unarchiving imcce.csv.zip."
197
-
198
- csv_file = zip_file.find { |entry| entry.name.end_with?(".csv") }
199
- break unless csv_file
200
-
201
- puts "Parsing imcce.csv..."
202
-
203
- csv_content = csv_file.get_input_stream.read
204
- CSV.parse(csv_content, headers: true) do |row|
205
- comparison = data[row["date"]][row["latitude"]][row["longitude"]]
206
- comparison.truth = Source.new.tap do |source|
207
- source.name = Source::IMCCE
208
- source.sun_rising_time = Time.new(row["sun_rising_time"] + " UTC") if row["sun_rising_time"]
209
- source.sun_transit_time = Time.new(row["sun_transit_time"] + " UTC") if row["sun_transit_time"]
210
- source.sun_setting_time = Time.new(row["sun_setting_time"] + " UTC") if row["sun_setting_time"]
211
- source.moon_rising_time = Time.new(row["moon_rising_time"] + " UTC") if row["moon_rising_time"]
212
- source.moon_transit_time = Time.new(row["moon_transit_time"] + " UTC") if row["moon_transit_time"]
213
- source.moon_setting_time = Time.new(row["moon_setting_time"] + " UTC") if row["moon_setting_time"]
214
- source.moon_illuminated_fraction = row["illuminated_fraction"].to_f
215
- end
216
- end
217
-
218
- puts "Done parsing imcce.csv."
219
- end
220
-
221
- puts "Comparing data..."
222
-
223
- data.each do |date, latitudes|
224
- latitudes.each do |latitude, longitudes|
225
- longitudes.each do |longitude, comparison|
226
- noon = Time.new("#{date}T12:00:00Z")
227
- observer = Astronoby::Observer.new(
228
- latitude: Astronoby::Angle.from_degrees(latitude.to_i),
229
- longitude: Astronoby::Angle.from_degrees(longitude.to_i)
230
- )
231
- sun = Astronoby::Sun.new(time: noon)
232
- sun_observation_events = sun.observation_events(observer: observer)
233
- moon = Astronoby::Moon.new(time: noon)
234
- moon_observation_events = moon.observation_events(observer: observer)
235
-
236
- source = Source.new.tap do |source|
237
- source.name = Source::ASTRONOBY
238
- source.sun_rising_time = sun_observation_events.rising_time
239
- source.sun_transit_time = sun_observation_events.transit_time
240
- source.sun_setting_time = sun_observation_events.setting_time
241
- source.moon_rising_time = moon_observation_events.rising_time
242
- source.moon_transit_time = moon_observation_events.transit_time
243
- source.moon_setting_time = moon_observation_events.setting_time
244
- source.moon_illuminated_fraction = moon.illuminated_fraction
245
- end
246
-
247
- comparison.sources << source
248
- result.add_comparison(comparison)
249
- end
250
- end
251
-
252
- puts "#{date}: Done."
253
- end
254
-
255
- puts "Done comparing data."
256
- puts
257
- puts
258
-
259
- puts result.display
Binary file
Binary file
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Astronoby
4
- class Epoch
5
- B1900 = 2415020.3135
6
- J1900 = 2415020.0
7
- B1950 = 2433282.4235
8
- J1950 = 2433282.5
9
- J2000 = 2451545.0
10
-
11
- DEFAULT_EPOCH = J2000
12
- JULIAN_DAY_NUMBER_OFFSET = 0.5
13
-
14
- def self.from_time(time)
15
- time.to_datetime.ajd
16
- end
17
-
18
- def self.to_utc(epoch)
19
- DateTime.jd(epoch + JULIAN_DAY_NUMBER_OFFSET).to_time.utc
20
- end
21
- end
22
- end