astronoby 0.5.0 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43ef390a6ab6a498edbf148b2af44c906daf73ff9ba61b5aafeadd828fb550e4
4
- data.tar.gz: b2cf0743676aa49f95f24c62b3d5d759553014bc52114260a71ecedfb9e6c1cb
3
+ metadata.gz: 15679e58775b5058f6a154502a3e94731effe12a9c90d0a28c642b96d07aa6b2
4
+ data.tar.gz: 00f9bcc5a4c0fa4111e33911ba3f1e3da4829edad54e4d1419c0d716f660ea69
5
5
  SHA512:
6
- metadata.gz: 052bfebf4ddaf6ef3f24883fec090a831d38a9e4124dd5f561d6b1dd7074b6385502396edddd5496ab6066ff93acab4f220ec3aaa244ad0638c0b65fbaace55f
7
- data.tar.gz: fe37ac2714328893b068ba958e37a3b057a76ddfa1b299a35f22be005687d3168d20e98ebe571db519bd6cf69227cc0f0dc4c0889dd9ca5bb9d1abb2b1ee550d
6
+ metadata.gz: b524b994952bfec402e42e69976c5f74d69d51e1d6fbf3b2f21327c9ed0e02011c32d897d09c216f7784c3c286ed69c11beee466207a64051aef536fbc8f5a64
7
+ data.tar.gz: 5ebbd92e2bb360d2d354800b7f05d35e4e74bce01cae06c8cf8176dae286e8ae70baa39c509c2c3466b05c676d624d4942a4a7cd08546ec895255785645e235b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 - 2024-12-10
4
+
5
+ _If you are upgrading: please see [UPGRADING.md]._
6
+
7
+ [UPGRADING.md]: https://github.com/rhannequin/astronoby/blob/main/UPGRADING.md
8
+
9
+ ### Bug fixes
10
+
11
+ * Fix `ObservationEvents` infinite loop in ([#110])
12
+ * Fix observation events times with local time dates in ([#105])
13
+ * Fix `IncompatibleArgumentsError` on Moon's observation events in ([#111])
14
+
15
+ ### Features
16
+
17
+ * Add `Astronoby::Moon#current_phase_fraction` in ([#115])
18
+ * Add sources and results for comparison in ([#114])
19
+
20
+ ### Improvements
21
+
22
+ * Bump standard from 1.36.0 to 1.39.2 by @dependabot in ([#95])
23
+ * Bump standard from 1.39.2 to 1.40.0 by @dependabot in ([#96])
24
+ * Bump dependencies in ([#100])
25
+ * Move dependencies to development ones in ([#99])
26
+ * Bump standard from 1.40.0 to 1.41.1 by @dependabot in ([#104])
27
+ * Bump standard from 1.41.1 to 1.42.0 by @dependabot in ([#107])
28
+ * Bump standard from 1.42.0 to 1.42.1 by @dependabot in ([#108])
29
+ * Bump dependencies in ([#116])
30
+ * Add supported Ruby versions in ([#117])
31
+
32
+ **Full Changelog**: https://github.com/rhannequin/astronoby/compare/v0.5.0...v0.6.0
33
+
34
+ [#95]: https://github\.com/rhannequin/astronoby/pull/95
35
+ [#96]: https://github\.com/rhannequin/astronoby/pull/96
36
+ [#99]: https://github\.com/rhannequin/astronoby/pull/99
37
+ [#100]: https://github\.com/rhannequin/astronoby/pull/100
38
+ [#104]: https://github\.com/rhannequin/astronoby/pull/104
39
+ [#105]: https://github\.com/rhannequin/astronoby/pull/105
40
+ [#107]: https://github\.com/rhannequin/astronoby/pull/107
41
+ [#108]: https://github\.com/rhannequin/astronoby/pull/108
42
+ [#110]: https://github\.com/rhannequin/astronoby/pull/110
43
+ [#111]: https://github\.com/rhannequin/astronoby/pull/111
44
+ [#114]: https://github\.com/rhannequin/astronoby/pull/114
45
+ [#115]: https://github\.com/rhannequin/astronoby/pull/115
46
+ [#116]: https://github\.com/rhannequin/astronoby/pull/116
47
+ [#117]: https://github\.com/rhannequin/astronoby/pull/117
48
+
3
49
  ## 0.5.0 - 2024-06-11
4
50
 
5
51
  _If you are upgrading: please see [UPGRADING.md]._
data/Gemfile.lock CHANGED
@@ -1,74 +1,69 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- astronoby (0.5.0)
4
+ astronoby (0.6.0)
5
5
  matrix (~> 0.4.2)
6
- rake (~> 13.0)
7
- rspec (~> 3.0)
8
6
 
9
7
  GEM
10
8
  remote: https://rubygems.org/
11
9
  specs:
12
10
  ast (2.4.2)
13
11
  diff-lcs (1.5.1)
14
- json (2.7.2)
12
+ json (2.9.0)
15
13
  language_server-protocol (3.17.0.3)
16
14
  lint_roller (1.1.0)
17
15
  matrix (0.4.2)
18
- parallel (1.24.0)
19
- parser (3.3.1.0)
16
+ parallel (1.26.3)
17
+ parser (3.3.6.0)
20
18
  ast (~> 2.4.1)
21
19
  racc
22
- racc (1.7.3)
20
+ racc (1.8.1)
23
21
  rainbow (3.1.1)
24
22
  rake (13.2.1)
25
- regexp_parser (2.9.1)
26
- rexml (3.2.8)
27
- strscan (>= 3.0.9)
23
+ regexp_parser (2.9.3)
28
24
  rspec (3.13.0)
29
25
  rspec-core (~> 3.13.0)
30
26
  rspec-expectations (~> 3.13.0)
31
27
  rspec-mocks (~> 3.13.0)
32
- rspec-core (3.13.0)
28
+ rspec-core (3.13.2)
33
29
  rspec-support (~> 3.13.0)
34
- rspec-expectations (3.13.0)
30
+ rspec-expectations (3.13.3)
35
31
  diff-lcs (>= 1.2.0, < 2.0)
36
32
  rspec-support (~> 3.13.0)
37
- rspec-mocks (3.13.0)
33
+ rspec-mocks (3.13.2)
38
34
  diff-lcs (>= 1.2.0, < 2.0)
39
35
  rspec-support (~> 3.13.0)
40
- rspec-support (3.13.1)
41
- rubocop (1.63.5)
36
+ rspec-support (3.13.2)
37
+ rubocop (1.68.0)
42
38
  json (~> 2.3)
43
39
  language_server-protocol (>= 3.17.0)
44
40
  parallel (~> 1.10)
45
41
  parser (>= 3.3.0.2)
46
42
  rainbow (>= 2.2.2, < 4.0)
47
- regexp_parser (>= 1.8, < 3.0)
48
- rexml (>= 3.2.5, < 4.0)
49
- rubocop-ast (>= 1.31.1, < 2.0)
43
+ regexp_parser (>= 2.4, < 3.0)
44
+ rubocop-ast (>= 1.32.2, < 2.0)
50
45
  ruby-progressbar (~> 1.7)
51
46
  unicode-display_width (>= 2.4.0, < 3.0)
52
- rubocop-ast (1.31.3)
47
+ rubocop-ast (1.36.2)
53
48
  parser (>= 3.3.1.0)
54
- rubocop-performance (1.21.0)
49
+ rubocop-performance (1.22.1)
55
50
  rubocop (>= 1.48.1, < 2.0)
56
51
  rubocop-ast (>= 1.31.1, < 2.0)
57
52
  ruby-progressbar (1.13.0)
58
- standard (1.36.0)
53
+ rubyzip (2.3.2)
54
+ standard (1.42.1)
59
55
  language_server-protocol (~> 3.17.0.2)
60
56
  lint_roller (~> 1.0)
61
- rubocop (~> 1.63.0)
57
+ rubocop (~> 1.68.0)
62
58
  standard-custom (~> 1.0.0)
63
- standard-performance (~> 1.4)
59
+ standard-performance (~> 1.5)
64
60
  standard-custom (1.0.2)
65
61
  lint_roller (~> 1.0)
66
62
  rubocop (~> 1.50)
67
- standard-performance (1.4.0)
63
+ standard-performance (1.5.0)
68
64
  lint_roller (~> 1.1)
69
- rubocop-performance (~> 1.21.0)
70
- strscan (3.1.0)
71
- unicode-display_width (2.5.0)
65
+ rubocop-performance (~> 1.22.0)
66
+ unicode-display_width (2.6.0)
72
67
 
73
68
  PLATFORMS
74
69
  ruby
@@ -76,6 +71,9 @@ PLATFORMS
76
71
 
77
72
  DEPENDENCIES
78
73
  astronoby!
74
+ rake (~> 13.0)
75
+ rspec (~> 3.0)
76
+ rubyzip (~> 2.3)
79
77
  standard (~> 1.3)
80
78
 
81
79
  BUNDLED WITH
data/README.md CHANGED
@@ -140,32 +140,37 @@ horizontal_coordinates.altitude.str(:dms)
140
140
 
141
141
  #### Sunrise and sunset times and azimuths
142
142
 
143
+ Only date part of the time is relevant for the calculation. The offset must
144
+ be provided to the observer.
145
+
143
146
  ```rb
144
- time = Time.new(2015, 2, 5)
147
+ utc_offset = "-05:00"
148
+ time = Time.new(2015, 2, 5, 0, 0, 0, utc_offset)
145
149
  observer = Astronoby::Observer.new(
146
150
  latitude: Astronoby::Angle.from_degrees(38),
147
- longitude: Astronoby::Angle.from_degrees(-78)
151
+ longitude: Astronoby::Angle.from_degrees(-78),
152
+ utc_offset: utc_offset
148
153
  )
149
154
  sun = Astronoby::Sun.new(time: time)
150
155
  observation_events = sun.observation_events(observer: observer)
151
156
 
152
- observation_events.rising_time
153
- # => 2015-02-05 12:12:59 UTC
157
+ observation_events.rising_time.getlocal(utc_offset)
158
+ # => 2015-02-05 07:12:59 -0500
154
159
 
155
160
  observation_events.rising_azimuth.str(:dms)
156
- # => "+109° 29′ 34.3674″"
161
+ # => "+109° 29′ 35.5069″"
157
162
 
158
- observation_events.transit_time
159
- # => 2015-02-05 17:25:59 UTC
163
+ observation_events.transit_time.getlocal(utc_offset)
164
+ # => 2015-02-05 12:25:59 -0500
160
165
 
161
166
  observation_events.transit_altitude.str(:dms)
162
- # => "+36° 8′ 15.8197″"
167
+ # => "+36° 8′ 14.9673″"
163
168
 
164
- observation_events.setting_time
165
- # => 2015-02-05 22:39:27 UTC
169
+ observation_events.setting_time.getlocal(utc_offset)
170
+ # => 2015-02-05 17:39:27 -0500
166
171
 
167
172
  observation_events.setting_azimuth.str(:dms)
168
- # => "+250° 40′ 42.8609″"
173
+ # => "+250° 40′ 41.7129″"
169
174
  ```
170
175
 
171
176
  #### Twilight times
@@ -244,6 +249,9 @@ moon = Astronoby::Moon.new(time: time)
244
249
  moon.illuminated_fraction.round(2)
245
250
  # => 0.31
246
251
 
252
+ moon.current_phase_fraction.round(2)
253
+ # => 0.82
254
+
247
255
  moon.distance.km.round
248
256
  # => 368409
249
257
 
@@ -268,32 +276,37 @@ june_phases.each { puts "#{_1.phase}: #{_1.time}" }
268
276
 
269
277
  #### Moonrise and moonset times and azimuths
270
278
 
279
+ Only date part of the time is relevant for the calculation. The offset must
280
+ be provided to the observer.
281
+
271
282
  ```rb
272
- time = Time.utc(2024, 6, 1, 10, 0, 0)
283
+ utc_offset = "-10:00"
284
+ time = Time.new(2024, 9, 1, 0, 0, 0, utc_offset)
273
285
  observer = Astronoby::Observer.new(
274
- latitude: Astronoby::Angle.from_degrees(48.8566),
275
- longitude: Astronoby::Angle.from_degrees(2.3522)
286
+ latitude: Astronoby::Angle.from_degrees(-17.5325),
287
+ longitude: Astronoby::Angle.from_degrees(-149.5677),
288
+ utc_offset: utc_offset
276
289
  )
277
290
  moon = Astronoby::Moon.new(time: time)
278
291
  observation_events = moon.observation_events(observer: observer)
279
292
 
280
- observation_events.rising_time
281
- # => 2024-06-01 00:35:36 UTC
293
+ observation_events.rising_time.getlocal(utc_offset)
294
+ # => 2024-09-01 05:24:55 -1000
282
295
 
283
296
  observation_events.rising_azimuth.str(:dms)
284
- # => "+93° 743.2347″"
297
+ # => "+72° 1519.1814″"
285
298
 
286
- observation_events.transit_time
287
- # => 2024-06-01 02:42:43 UTC
299
+ observation_events.transit_time.getlocal(utc_offset)
300
+ # => 2024-09-01 11:12:32 -1000
288
301
 
289
302
  observation_events.transit_altitude.str(:dms)
290
- # => "+26° 5930.9915″"
303
+ # => "+56° 3959.132″"
291
304
 
292
- observation_events.setting_time
293
- # => 2024-06-01 16:02:26 UTC
305
+ observation_events.setting_time.getlocal(utc_offset)
306
+ # => 2024-09-01 16:12:08 -1000
294
307
 
295
308
  observation_events.setting_azimuth.str(:dms)
296
- # => "+273° 2930.0954″"
309
+ # => "+290° 2542.5421″"
297
310
  ```
298
311
 
299
312
  ## Precision
@@ -0,0 +1,131 @@
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.
@@ -0,0 +1,259 @@
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
@@ -167,6 +167,11 @@ module Astronoby
167
167
  @illuminated_fraction ||= (1 + phase_angle.cos) / 2
168
168
  end
169
169
 
170
+ # @return [Float] Phase fraction, from 0 to 1
171
+ def current_phase_fraction
172
+ mean_elongation.degrees / Constants::DEGREES_PER_CIRCLE
173
+ end
174
+
170
175
  # @param observer [Astronoby::Observer] Observer of the event
171
176
  # @return [Astronoby::Events::ObservationEvents] Moon's observation events
172
177
  def observation_events(observer:)
@@ -7,6 +7,7 @@ module Astronoby
7
7
  RISING_SETTING_HOUR_ANGLE_RATIO_RANGE = (-1..1)
8
8
  EARTH_SIDEREAL_ROTATION_RATE = 360.98564736629
9
9
  ITERATION_PRECISION = 0.0001
10
+ ITERATION_LIMIT = 5
10
11
 
11
12
  attr_reader :rising_time,
12
13
  :rising_azimuth,
@@ -53,7 +54,11 @@ module Astronoby
53
54
 
54
55
  def compute
55
56
  @initial_transit = initial_transit
56
- @transit_time = Util::Time.decimal_hour_to_time(@date, @initial_transit)
57
+ @transit_time = Util::Time.decimal_hour_to_time(
58
+ @date,
59
+ @observer.utc_offset,
60
+ @initial_transit
61
+ )
57
62
  @transit_altitude = local_horizontal_altitude_transit
58
63
 
59
64
  return if h0.nil?
@@ -79,20 +84,33 @@ module Astronoby
79
84
  Constants::HOURS_PER_DAY * @final_setting
80
85
  )
81
86
 
82
- @rising_time = Util::Time.decimal_hour_to_time(@date, rationalized_corrected_rising)
87
+ @rising_time = Util::Time.decimal_hour_to_time(
88
+ @date,
89
+ @observer.utc_offset,
90
+ rationalized_corrected_rising
91
+ )
83
92
  @rising_azimuth = local_horizontal_azimuth_rising
84
- @transit_time = Util::Time.decimal_hour_to_time(@date, rationalized_corrected_transit)
93
+ @transit_time = Util::Time.decimal_hour_to_time(
94
+ @date,
95
+ @observer.utc_offset,
96
+ rationalized_corrected_transit
97
+ )
85
98
  @transit_altitude = local_horizontal_altitude_transit
86
- @setting_time = Util::Time.decimal_hour_to_time(@date, rationalized_corrected_setting)
99
+ @setting_time = Util::Time.decimal_hour_to_time(
100
+ @date,
101
+ @observer.utc_offset,
102
+ rationalized_corrected_setting
103
+ )
87
104
  @setting_azimuth = local_horizontal_azimuth_setting
88
105
  end
89
106
 
90
107
  def iterate(initial_rising, initial_transit, initial_setting)
91
108
  delta = 1
109
+ iteration = 1
92
110
  corrected_rising = initial_rising
93
111
  corrected_transit = initial_transit
94
112
  corrected_setting = initial_setting
95
- until delta < ITERATION_PRECISION
113
+ until delta < ITERATION_PRECISION || iteration > ITERATION_LIMIT
96
114
  iterate = RiseTransitSetIteration.new(
97
115
  observer: @observer,
98
116
  date: @date,
@@ -108,6 +126,7 @@ module Astronoby
108
126
  corrected_rising = rationalize_decimal_time corrected_rising + iterate[0]
109
127
  corrected_transit = rationalize_decimal_time corrected_transit + iterate[1]
110
128
  corrected_setting = rationalize_decimal_time corrected_setting + iterate[2]
129
+ iteration += 1
111
130
  end
112
131
  [corrected_rising, corrected_transit, corrected_setting]
113
132
  end
@@ -155,11 +174,6 @@ module Astronoby
155
174
  )
156
175
  end
157
176
 
158
- def leap_day_portion
159
- leap_seconds = Util::Time.terrestrial_universal_time_delta(@date)
160
- leap_seconds / Constants::SECONDS_PER_DAY
161
- end
162
-
163
177
  def local_hour_angle_transit
164
178
  gst_transit - observer_longitude - right_ascension_transit
165
179
  end
@@ -168,6 +182,8 @@ module Astronoby
168
182
  term1 = declination_rising.sin + (-shift).sin * @observer.latitude.cos
169
183
  term2 = (-shift).cos * @observer.latitude.cos
170
184
  angle = term1 / term2
185
+ return nil if angle.abs > 1
186
+
171
187
  Angle.acos(angle)
172
188
  end
173
189
 
@@ -182,14 +198,16 @@ module Astronoby
182
198
  term1 = declination_setting.sin + (-shift).sin * @observer.latitude.cos
183
199
  term2 = (-shift).cos * @observer.latitude.cos
184
200
  angle = term1 / term2
201
+ return nil if angle.abs > 1
202
+
185
203
  Angle.from_degrees(
186
204
  Constants::DEGREES_PER_CIRCLE - Angle.acos(angle).degrees
187
205
  )
188
206
  end
189
207
 
190
208
  def rationalize_decimal_time(decimal_time)
191
- decimal_time += 1 if decimal_time.negative?
192
- decimal_time -= 1 if decimal_time > 1
209
+ decimal_time += 1 while decimal_time.negative?
210
+ decimal_time -= 1 while decimal_time > 1
193
211
  decimal_time
194
212
  end
195
213
 
@@ -202,12 +220,14 @@ module Astronoby
202
220
  def right_ascension_transit
203
221
  Angle.from_degrees(
204
222
  Util::Maths.interpolate(
205
- [
206
- @coordinates_of_the_previous_day.right_ascension.degrees,
207
- @coordinates_of_the_day.right_ascension.degrees,
208
- @coordinates_of_the_next_day.right_ascension.degrees
209
- ],
210
- (@final_transit || @initial_transit) + leap_day_portion
223
+ Util::Maths.normalize_angles_for_interpolation(
224
+ [
225
+ @coordinates_of_the_previous_day.right_ascension.degrees,
226
+ @coordinates_of_the_day.right_ascension.degrees,
227
+ @coordinates_of_the_next_day.right_ascension.degrees
228
+ ]
229
+ ),
230
+ @final_transit || @initial_transit
211
231
  )
212
232
  )
213
233
  end
@@ -215,12 +235,14 @@ module Astronoby
215
235
  def declination_rising
216
236
  Angle.from_degrees(
217
237
  Util::Maths.interpolate(
218
- [
219
- @coordinates_of_the_previous_day.declination.degrees,
220
- @coordinates_of_the_day.declination.degrees,
221
- @coordinates_of_the_next_day.declination.degrees
222
- ],
223
- @final_rising + leap_day_portion
238
+ Util::Maths.normalize_angles_for_interpolation(
239
+ [
240
+ @coordinates_of_the_previous_day.declination.degrees,
241
+ @coordinates_of_the_day.declination.degrees,
242
+ @coordinates_of_the_next_day.declination.degrees
243
+ ]
244
+ ),
245
+ @final_rising
224
246
  )
225
247
  )
226
248
  end
@@ -228,12 +250,14 @@ module Astronoby
228
250
  def declination_transit
229
251
  Angle.from_degrees(
230
252
  Util::Maths.interpolate(
231
- [
232
- @coordinates_of_the_previous_day.declination.degrees,
233
- @coordinates_of_the_day.declination.degrees,
234
- @coordinates_of_the_next_day.declination.degrees
235
- ],
236
- (@final_transit || @initial_transit) + leap_day_portion
253
+ Util::Maths.normalize_angles_for_interpolation(
254
+ [
255
+ @coordinates_of_the_previous_day.declination.degrees,
256
+ @coordinates_of_the_day.declination.degrees,
257
+ @coordinates_of_the_next_day.declination.degrees
258
+ ]
259
+ ),
260
+ @final_transit || @initial_transit
237
261
  )
238
262
  )
239
263
  end
@@ -241,12 +265,14 @@ module Astronoby
241
265
  def declination_setting
242
266
  Angle.from_degrees(
243
267
  Util::Maths.interpolate(
244
- [
245
- @coordinates_of_the_previous_day.declination.degrees,
246
- @coordinates_of_the_day.declination.degrees,
247
- @coordinates_of_the_next_day.declination.degrees
248
- ],
249
- @final_setting + leap_day_portion
268
+ Util::Maths.normalize_angles_for_interpolation(
269
+ [
270
+ @coordinates_of_the_previous_day.declination.degrees,
271
+ @coordinates_of_the_day.declination.degrees,
272
+ @coordinates_of_the_next_day.declination.degrees
273
+ ]
274
+ ),
275
+ @final_setting
250
276
  )
251
277
  )
252
278
  end
@@ -112,13 +112,6 @@ module Astronoby
112
112
  )
113
113
  end
114
114
 
115
- def leap_day_portion
116
- @leap_day_portion ||= begin
117
- leap_seconds = Util::Time.terrestrial_universal_time_delta(@date)
118
- leap_seconds / Constants::SECONDS_PER_DAY
119
- end
120
- end
121
-
122
115
  def local_hour_angle_rising
123
116
  @local_hour_angle_rising ||=
124
117
  gst_rising - observer_longitude - right_ascension_rising
@@ -150,12 +143,14 @@ module Astronoby
150
143
  def right_ascension_rising
151
144
  Angle.from_degrees(
152
145
  Util::Maths.interpolate(
153
- [
154
- @coordinates_of_the_previous_day.right_ascension.degrees,
155
- @coordinates_of_the_day.right_ascension.degrees,
156
- @coordinates_of_the_next_day.right_ascension.degrees
157
- ],
158
- @initial_rising + leap_day_portion
146
+ Util::Maths.normalize_angles_for_interpolation(
147
+ [
148
+ @coordinates_of_the_previous_day.right_ascension.degrees,
149
+ @coordinates_of_the_day.right_ascension.degrees,
150
+ @coordinates_of_the_next_day.right_ascension.degrees
151
+ ]
152
+ ),
153
+ @initial_rising
159
154
  )
160
155
  )
161
156
  end
@@ -163,12 +158,14 @@ module Astronoby
163
158
  def right_ascension_transit
164
159
  Angle.from_degrees(
165
160
  Util::Maths.interpolate(
166
- [
167
- @coordinates_of_the_previous_day.right_ascension.degrees,
168
- @coordinates_of_the_day.right_ascension.degrees,
169
- @coordinates_of_the_next_day.right_ascension.degrees
170
- ],
171
- @initial_transit + leap_day_portion
161
+ Util::Maths.normalize_angles_for_interpolation(
162
+ [
163
+ @coordinates_of_the_previous_day.right_ascension.degrees,
164
+ @coordinates_of_the_day.right_ascension.degrees,
165
+ @coordinates_of_the_next_day.right_ascension.degrees
166
+ ]
167
+ ),
168
+ @initial_transit
172
169
  )
173
170
  )
174
171
  end
@@ -176,12 +173,14 @@ module Astronoby
176
173
  def right_ascension_setting
177
174
  Angle.from_degrees(
178
175
  Util::Maths.interpolate(
179
- [
180
- @coordinates_of_the_previous_day.right_ascension.degrees,
181
- @coordinates_of_the_day.right_ascension.degrees,
182
- @coordinates_of_the_next_day.right_ascension.degrees
183
- ],
184
- @initial_setting + leap_day_portion
176
+ Util::Maths.normalize_angles_for_interpolation(
177
+ [
178
+ @coordinates_of_the_previous_day.right_ascension.degrees,
179
+ @coordinates_of_the_day.right_ascension.degrees,
180
+ @coordinates_of_the_next_day.right_ascension.degrees
181
+ ]
182
+ ),
183
+ @initial_setting
185
184
  )
186
185
  )
187
186
  end
@@ -189,12 +188,14 @@ module Astronoby
189
188
  def declination_rising
190
189
  Angle.from_degrees(
191
190
  Util::Maths.interpolate(
192
- [
193
- @coordinates_of_the_previous_day.declination.degrees,
194
- @coordinates_of_the_day.declination.degrees,
195
- @coordinates_of_the_next_day.declination.degrees
196
- ],
197
- @initial_rising + leap_day_portion
191
+ Util::Maths.normalize_angles_for_interpolation(
192
+ [
193
+ @coordinates_of_the_previous_day.declination.degrees,
194
+ @coordinates_of_the_day.declination.degrees,
195
+ @coordinates_of_the_next_day.declination.degrees
196
+ ]
197
+ ),
198
+ @initial_rising
198
199
  )
199
200
  )
200
201
  end
@@ -202,12 +203,14 @@ module Astronoby
202
203
  def declination_setting
203
204
  Angle.from_degrees(
204
205
  Util::Maths.interpolate(
205
- [
206
- @coordinates_of_the_previous_day.declination.degrees,
207
- @coordinates_of_the_day.declination.degrees,
208
- @coordinates_of_the_next_day.declination.degrees
209
- ],
210
- @initial_setting + leap_day_portion
206
+ Util::Maths.normalize_angles_for_interpolation(
207
+ [
208
+ @coordinates_of_the_previous_day.declination.degrees,
209
+ @coordinates_of_the_day.declination.degrees,
210
+ @coordinates_of_the_next_day.declination.degrees
211
+ ]
212
+ ),
213
+ @initial_setting
211
214
  )
212
215
  )
213
216
  end
@@ -10,12 +10,18 @@ module Astronoby
10
10
  MOLAR_MASS_OF_AIR = 0.0289644
11
11
  UNIVERSAL_GAS_CONSTANT = 8.31432
12
12
 
13
- attr_reader :latitude, :longitude, :elevation, :temperature, :pressure
13
+ attr_reader :latitude,
14
+ :longitude,
15
+ :elevation,
16
+ :utc_offset,
17
+ :temperature,
18
+ :pressure
14
19
 
15
20
  # @param latitude [Angle] geographic latitude of the observer
16
21
  # @param longitude [Angle] geographic longitude of the observer
17
22
  # @param elevation [Astronoby::Distance] geographic elevation (or altitude)
18
23
  # of the observer above sea level
24
+ # @param utc_offset [Numeric, String] offset from Coordinated Universal Time
19
25
  # @param temperature [Numeric] temperature at the observer's location in
20
26
  # kelvins
21
27
  # @param pressure [Numeric] atmospheric pressure at the observer's
@@ -24,12 +30,14 @@ module Astronoby
24
30
  latitude:,
25
31
  longitude:,
26
32
  elevation: DEFAULT_ELEVATION,
33
+ utc_offset: 0,
27
34
  temperature: DEFAULT_TEMPERATURE,
28
35
  pressure: nil
29
36
  )
30
37
  @latitude = latitude
31
38
  @longitude = longitude
32
39
  @elevation = elevation
40
+ @utc_offset = utc_offset
33
41
  @temperature = temperature
34
42
  @pressure = pressure || compute_pressure
35
43
  end
@@ -40,6 +48,7 @@ module Astronoby
40
48
  @latitude == other.latitude &&
41
49
  @longitude == other.longitude &&
42
50
  @elevation == other.elevation &&
51
+ @utc_offset == other.utc_offset &&
43
52
  @temperature == other.temperature &&
44
53
  @pressure == other.pressure
45
54
  end
@@ -51,6 +60,7 @@ module Astronoby
51
60
  @latitude,
52
61
  @longitude,
53
62
  @elevation,
63
+ @utc_offset,
54
64
  @temperature,
55
65
  @pressure
56
66
  ].hash
@@ -65,7 +65,7 @@ module Astronoby
65
65
 
66
66
  utc = SIDEREAL_MINUTE_IN_UT_MINUTE * a
67
67
 
68
- Util::Time.decimal_hour_to_time(date, utc)
68
+ Util::Time.decimal_hour_to_time(date, 0, utc)
69
69
  end
70
70
 
71
71
  def to_lst(longitude:)
@@ -29,6 +29,28 @@ module Astronoby
29
29
  "Only 3 or 5 terms are supported for interpolation"
30
30
  end
31
31
 
32
+ # Fixes angles forced to be in range [0, 360] or other angle range, for
33
+ # interpolation use
34
+ # @param angles [Array<Integer|Float>] Angles values
35
+ # @param full_circle [Integer] Full circle value
36
+ # @return [Array<Interger|Float>] Normalized values
37
+ def normalize_angles_for_interpolation(angles, full_circle: 360)
38
+ normalized = angles.dup
39
+
40
+ (1...normalized.size).each do |i|
41
+ prev_angle = normalized[i - 1]
42
+
43
+ while normalized[i] - prev_angle > full_circle / 2
44
+ normalized[i] -= full_circle
45
+ end
46
+ while normalized[i] - prev_angle < -full_circle / 2
47
+ normalized[i] += full_circle
48
+ end
49
+ end
50
+
51
+ normalized
52
+ end
53
+
32
54
  private
33
55
 
34
56
  # @return [Float] Interpolated value
@@ -6,7 +6,7 @@ module Astronoby
6
6
  # @param date [Date]
7
7
  # @param decimal [Numeric] Hour of the day, in decimal hours
8
8
  # @return [::Time] Date and time
9
- def self.decimal_hour_to_time(date, decimal)
9
+ def self.decimal_hour_to_time(date, utc_offset, decimal)
10
10
  absolute_hour = decimal.abs
11
11
  hour = absolute_hour.floor
12
12
 
@@ -25,6 +25,17 @@ module Astronoby
25
25
  second = Constants::SECONDS_PER_MINUTE *
26
26
  (absolute_decimal_minute - absolute_decimal_minute.floor)
27
27
 
28
+ date_in_local_time = ::Time
29
+ .utc(date.year, date.month, date.day, hour, minute, second)
30
+ .getlocal(utc_offset)
31
+ .to_date
32
+
33
+ if date_in_local_time < date
34
+ date = date.next_day
35
+ elsif date_in_local_time > date
36
+ date = date.prev_day
37
+ end
38
+
28
39
  ::Time.utc(date.year, date.month, date.day, hour, minute, second).round
29
40
  end
30
41
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Astronoby
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: astronoby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémy Hannequin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-11 00:00:00.000000000 Z
11
+ date: 2024-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: matrix
@@ -31,7 +31,7 @@ dependencies:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '13.0'
34
- type: :runtime
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -45,13 +45,27 @@ dependencies:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.0'
48
- type: :runtime
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyzip
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: standard
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +100,10 @@ files:
86
100
  - README.md
87
101
  - Rakefile
88
102
  - UPGRADING.md
103
+ - benchmark/README.md
104
+ - benchmark/benchmark.rb
105
+ - benchmark/data/imcce.csv.zip
106
+ - benchmark/data/sun_calc.csv.zip
89
107
  - lib/astronoby.rb
90
108
  - lib/astronoby/aberration.rb
91
109
  - lib/astronoby/angle.rb