iers 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +64 -0
- data/README.md +4 -3
- data/Rakefile +0 -1
- data/data/Leap_Second.dat +2 -2
- data/data/finals2000A.all +860 -797
- data/lib/iers/configuration.rb +13 -0
- data/lib/iers/data.rb +25 -4
- data/lib/iers/delta_t.rb +61 -18
- data/lib/iers/version.rb +1 -1
- data/lib/iers.rb +7 -1
- metadata +1 -1
data/lib/iers/configuration.rb
CHANGED
|
@@ -39,6 +39,7 @@ module IERS
|
|
|
39
39
|
|
|
40
40
|
def cache_dir=(value)
|
|
41
41
|
@cache_dir = Pathname(value)
|
|
42
|
+
invalidate
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def sources=(value)
|
|
@@ -59,10 +60,12 @@ module IERS
|
|
|
59
60
|
|
|
60
61
|
def finals_path=(value)
|
|
61
62
|
@finals_path = value && Pathname(value)
|
|
63
|
+
invalidate(:finals)
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def leap_second_path=(value)
|
|
65
67
|
@leap_second_path = value && Pathname(value)
|
|
68
|
+
invalidate(:leap_seconds)
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def interpolation=(value)
|
|
@@ -82,5 +85,15 @@ module IERS
|
|
|
82
85
|
|
|
83
86
|
@lagrange_order = value
|
|
84
87
|
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Settings staged on a detached Configuration govern nothing, so they must
|
|
92
|
+
# not reach into the parse the gem is actually serving.
|
|
93
|
+
def invalidate(*sources)
|
|
94
|
+
return unless IERS.active_configuration?(self)
|
|
95
|
+
|
|
96
|
+
Data.clear_loaded!(*sources)
|
|
97
|
+
end
|
|
85
98
|
end
|
|
86
99
|
end
|
data/lib/iers/data.rb
CHANGED
|
@@ -37,6 +37,7 @@ module IERS
|
|
|
37
37
|
begin
|
|
38
38
|
Downloader.new(timeout: config.download_timeout).fetch(url, dest)
|
|
39
39
|
updated << source
|
|
40
|
+
clear_loaded!(source)
|
|
40
41
|
rescue DownloadError => e
|
|
41
42
|
errors[source] = e
|
|
42
43
|
end
|
|
@@ -67,6 +68,8 @@ module IERS
|
|
|
67
68
|
path = config.cache_dir.join(filename)
|
|
68
69
|
path.delete if path.exist?
|
|
69
70
|
end
|
|
71
|
+
|
|
72
|
+
clear_loaded!
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
# @param coverage_days_ahead [Integer, nil]
|
|
@@ -161,15 +164,33 @@ module IERS
|
|
|
161
164
|
(Time.now - mtimes.min).to_i
|
|
162
165
|
end
|
|
163
166
|
|
|
167
|
+
# @param sources [Array<Symbol>] data sources to drop (default: all)
|
|
164
168
|
# @return [void]
|
|
165
|
-
def clear_loaded!
|
|
169
|
+
def clear_loaded!(*sources)
|
|
170
|
+
sources = FILENAMES.keys if sources.empty?
|
|
171
|
+
validate_sources!(sources)
|
|
172
|
+
|
|
166
173
|
@mutex.synchronize do
|
|
167
|
-
@finals = nil
|
|
168
|
-
@leap_second_table = nil
|
|
174
|
+
@finals = nil if sources.include?(:finals)
|
|
175
|
+
@leap_second_table = nil if sources.include?(:leap_seconds)
|
|
169
176
|
end
|
|
177
|
+
|
|
178
|
+
# Outside the mutex above: LeapSecond takes its own lock before calling
|
|
179
|
+
# back into Data, so taking them in that order here would invert it.
|
|
180
|
+
LeapSecond.clear_cached! if sources.include?(:leap_seconds)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def validate_sources!(sources)
|
|
184
|
+
unknown = sources - FILENAMES.keys
|
|
185
|
+
return if unknown.empty?
|
|
186
|
+
|
|
187
|
+
raise ConfigurationError,
|
|
188
|
+
"Unknown data source: #{unknown.map(&:inspect).join(", ")}. " \
|
|
189
|
+
"Valid sources: #{FILENAMES.keys.inspect}"
|
|
170
190
|
end
|
|
171
191
|
|
|
172
|
-
private_class_method :
|
|
192
|
+
private_class_method :validate_sources!,
|
|
193
|
+
:resolve_path,
|
|
173
194
|
:resolve_read_path,
|
|
174
195
|
:validate_source!,
|
|
175
196
|
:custom_paths_configured?,
|
data/lib/iers/delta_t.rb
CHANGED
|
@@ -14,11 +14,11 @@ module IERS
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
EARLIEST_YEAR = 1800.0
|
|
17
|
-
|
|
17
|
+
LATEST_POLYNOMIAL_YEAR = 1986.0
|
|
18
18
|
DAYS_PER_JULIAN_YEAR = 365.25
|
|
19
19
|
YEAR_J2000 = 2000.0
|
|
20
20
|
|
|
21
|
-
# Espenak & Meeus (2014) polynomial segments for 1800–
|
|
21
|
+
# Espenak & Meeus (2014) polynomial segments for 1800–1986.
|
|
22
22
|
# Each segment: [year_start, year_end, epoch, coefficients]
|
|
23
23
|
# ΔT = c₀ + c₁·t + c₂·t² + ... where t = y − epoch
|
|
24
24
|
# Reference: https://eclipsewise.com/help/deltatpoly2014.html
|
|
@@ -46,7 +46,7 @@ module IERS
|
|
|
46
46
|
].freeze
|
|
47
47
|
|
|
48
48
|
private_constant :EARLIEST_YEAR,
|
|
49
|
-
:
|
|
49
|
+
:LATEST_POLYNOMIAL_YEAR,
|
|
50
50
|
:DAYS_PER_JULIAN_YEAR,
|
|
51
51
|
:YEAR_J2000,
|
|
52
52
|
:POLYNOMIALS
|
|
@@ -69,24 +69,62 @@ module IERS
|
|
|
69
69
|
)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
if query_mjd
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
source: :estimated
|
|
77
|
-
)
|
|
72
|
+
if series_covers?(query_mjd)
|
|
73
|
+
measured_entry(query_mjd)
|
|
74
|
+
elsif y <= LATEST_POLYNOMIAL_YEAR
|
|
75
|
+
estimated_entry(query_mjd, y)
|
|
78
76
|
else
|
|
79
|
-
|
|
80
|
-
ut1_utc = UT1.at(mjd: query_mjd).ut1_utc
|
|
81
|
-
|
|
82
|
-
Entry.new(
|
|
83
|
-
delta_t: tai_utc + TimeScale::TT_TAI - ut1_utc,
|
|
84
|
-
mjd: query_mjd,
|
|
85
|
-
source: :measured
|
|
86
|
-
)
|
|
77
|
+
raise_uncovered!(query_mjd)
|
|
87
78
|
end
|
|
88
79
|
end
|
|
89
80
|
|
|
81
|
+
# The EOP series is the better source wherever it reaches, so it is asked
|
|
82
|
+
# first; the polynomial covers whatever is left within its own validity.
|
|
83
|
+
def series_covers?(mjd)
|
|
84
|
+
entries = Data.finals_entries
|
|
85
|
+
return false if entries.empty?
|
|
86
|
+
|
|
87
|
+
mjd.between?(entries.first.mjd, entries.last.mjd)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def estimated_entry(query_mjd, y)
|
|
91
|
+
Entry.new(
|
|
92
|
+
delta_t: polynomial_delta_t(y),
|
|
93
|
+
mjd: query_mjd,
|
|
94
|
+
source: :estimated
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def raise_uncovered!(query_mjd)
|
|
99
|
+
entries = Data.finals_entries
|
|
100
|
+
series =
|
|
101
|
+
if entries.empty?
|
|
102
|
+
"is empty"
|
|
103
|
+
else
|
|
104
|
+
"covers #{entries.first.mjd}..#{entries.last.mjd}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# No `available_range`: what DeltaT can answer is two disjoint spans, and
|
|
108
|
+
# naming either one alone is what made the old message misleading.
|
|
109
|
+
raise OutOfRangeError.new(
|
|
110
|
+
"No DeltaT available for MJD #{query_mjd}: the polynomial covers " \
|
|
111
|
+
"#{EARLIEST_YEAR.to_i}–#{LATEST_POLYNOMIAL_YEAR.to_i} and the EOP " \
|
|
112
|
+
"series #{series}",
|
|
113
|
+
requested_mjd: query_mjd
|
|
114
|
+
)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def measured_entry(query_mjd)
|
|
118
|
+
tai_utc = LeapSecond.at(mjd: query_mjd)
|
|
119
|
+
ut1_utc = UT1.at(mjd: query_mjd).ut1_utc
|
|
120
|
+
|
|
121
|
+
Entry.new(
|
|
122
|
+
delta_t: tai_utc + TimeScale::TT_TAI - ut1_utc,
|
|
123
|
+
mjd: query_mjd,
|
|
124
|
+
source: :measured
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
90
128
|
def polynomial_delta_t(y)
|
|
91
129
|
segment = POLYNOMIALS.find { |s| y < s[1] } || POLYNOMIALS.last
|
|
92
130
|
t = y - segment[2]
|
|
@@ -97,6 +135,11 @@ module IERS
|
|
|
97
135
|
YEAR_J2000 + (mjd - TimeScale::MJD_J2000) / DAYS_PER_JULIAN_YEAR
|
|
98
136
|
end
|
|
99
137
|
|
|
100
|
-
private_class_method :
|
|
138
|
+
private_class_method :series_covers?,
|
|
139
|
+
:estimated_entry,
|
|
140
|
+
:raise_uncovered!,
|
|
141
|
+
:measured_entry,
|
|
142
|
+
:polynomial_delta_t,
|
|
143
|
+
:mjd_to_decimal_year
|
|
101
144
|
end
|
|
102
145
|
end
|
data/lib/iers/version.rb
CHANGED
data/lib/iers.rb
CHANGED
|
@@ -40,11 +40,17 @@ module IERS
|
|
|
40
40
|
yield configuration
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# @api private
|
|
44
|
+
# @param candidate [Configuration]
|
|
45
|
+
# @return [Boolean] whether the gem reads its data through this object
|
|
46
|
+
def active_configuration?(candidate)
|
|
47
|
+
@configuration.equal?(candidate)
|
|
48
|
+
end
|
|
49
|
+
|
|
43
50
|
# @return [void]
|
|
44
51
|
def reset_configuration!
|
|
45
52
|
@configuration = nil
|
|
46
53
|
Data.clear_loaded!
|
|
47
|
-
LeapSecond.clear_cached!
|
|
48
54
|
end
|
|
49
55
|
|
|
50
56
|
# @return [void]
|