astronoby 0.7.0 → 0.8.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/.ruby-version +1 -1
- data/CHANGELOG.md +87 -3
- data/README.md +56 -32
- data/UPGRADING.md +50 -21
- data/docs/README.md +196 -0
- data/docs/angles.md +137 -0
- data/docs/celestial_bodies.md +107 -0
- data/docs/configuration.md +98 -0
- data/docs/coordinates.md +167 -0
- data/docs/ephem.md +85 -0
- data/docs/equinoxes_solstices_times.md +31 -0
- data/docs/glossary.md +152 -0
- data/docs/instant.md +139 -0
- data/docs/moon_phases.md +79 -0
- data/docs/observer.md +65 -0
- data/docs/reference_frames.md +138 -0
- data/docs/rise_transit_set_times.md +119 -0
- data/docs/twilight_times.md +123 -0
- data/lib/astronoby/bodies/earth.rb +8 -2
- data/lib/astronoby/bodies/jupiter.rb +17 -0
- data/lib/astronoby/bodies/mars.rb +17 -0
- data/lib/astronoby/bodies/mercury.rb +21 -0
- data/lib/astronoby/bodies/moon.rb +29 -36
- data/lib/astronoby/bodies/neptune.rb +21 -0
- data/lib/astronoby/bodies/saturn.rb +26 -0
- data/lib/astronoby/bodies/solar_system_body.rb +139 -29
- data/lib/astronoby/bodies/sun.rb +25 -2
- data/lib/astronoby/bodies/uranus.rb +5 -0
- data/lib/astronoby/bodies/venus.rb +25 -0
- data/lib/astronoby/cache.rb +188 -0
- data/lib/astronoby/configuration.rb +92 -0
- data/lib/astronoby/constants.rb +4 -1
- data/lib/astronoby/constellation.rb +12 -0
- data/lib/astronoby/constellations/data.rb +42 -0
- data/lib/astronoby/constellations/finder.rb +35 -0
- data/lib/astronoby/constellations/repository.rb +20 -0
- data/lib/astronoby/coordinates/equatorial.rb +3 -3
- data/lib/astronoby/data/constellations/constellation_names.dat +88 -0
- data/lib/astronoby/data/constellations/indexed_abbreviations.dat +88 -0
- data/lib/astronoby/data/constellations/radec_to_index.dat +238 -0
- data/lib/astronoby/data/constellations/sorted_declinations.dat +202 -0
- data/lib/astronoby/data/constellations/sorted_right_ascensions.dat +237 -0
- data/lib/astronoby/equinox_solstice.rb +2 -2
- data/lib/astronoby/events/moon_phases.rb +15 -14
- data/lib/astronoby/events/rise_transit_set_calculator.rb +32 -8
- data/lib/astronoby/events/twilight_calculator.rb +115 -60
- data/lib/astronoby/events/twilight_events.rb +28 -0
- data/lib/astronoby/instant.rb +7 -2
- data/lib/astronoby/julian_date.rb +78 -0
- data/lib/astronoby/mean_obliquity.rb +8 -10
- data/lib/astronoby/nutation.rb +11 -3
- data/lib/astronoby/observer.rb +1 -1
- data/lib/astronoby/precession.rb +48 -38
- data/lib/astronoby/reference_frame.rb +2 -1
- data/lib/astronoby/reference_frames/apparent.rb +1 -1
- data/lib/astronoby/reference_frames/mean_of_date.rb +1 -1
- data/lib/astronoby/reference_frames/topocentric.rb +1 -11
- data/lib/astronoby/time/greenwich_sidereal_time.rb +2 -2
- data/lib/astronoby/true_obliquity.rb +2 -3
- data/lib/astronoby/util/time.rb +1 -1
- data/lib/astronoby/version.rb +1 -1
- data/lib/astronoby.rb +8 -1
- metadata +59 -11
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -102
- data/benchmark/README.md +0 -131
- data/benchmark/benchmark.rb +0 -259
- data/benchmark/data/imcce.csv.zip +0 -0
- data/benchmark/data/sun_calc.csv.zip +0 -0
- data/lib/astronoby/epoch.rb +0 -22
@@ -0,0 +1,123 @@
|
|
1
|
+
# Twilight times
|
2
|
+
|
3
|
+
In astronomy, twilight is a period of time when the Sun is already set but
|
4
|
+
some of its light still illuminates the atmosphere, making the sky brighter than
|
5
|
+
during full night.
|
6
|
+
|
7
|
+
We usually define 4 moments when talking about twilight:
|
8
|
+
* sunrise/sunset: right when the Sun goes above the horizon or right after it
|
9
|
+
goes below the horizon. The Sun's horizon angle is 0°.
|
10
|
+
* civil twilight: when the horizon angle is between 0° and -6°. Usually, during
|
11
|
+
this time, artificial light is not needed yet.
|
12
|
+
* nautical twilight: when the horizon angle is between -6° and -12°. When the
|
13
|
+
nautical twilight starts, the difference between the horizon at sea and the
|
14
|
+
sky cannot be seen clearly anymore.
|
15
|
+
* astronomical twilight: when the horizon angle is between -12° and -18°. Some
|
16
|
+
stars can be seen during this time.
|
17
|
+
|
18
|
+
These moments change every day and depend on the observer's location. They can
|
19
|
+
be computed using `Astronoby::TwilightCalculator`.
|
20
|
+
|
21
|
+
## Initialization
|
22
|
+
|
23
|
+
Once instantiated, the calculator doesn't do anything yet, it waits for your
|
24
|
+
instruction.
|
25
|
+
|
26
|
+
It takes as key arguments:
|
27
|
+
* `observer` (`Astronoby::Observer`): location on Earth of the observer
|
28
|
+
* `ephem`: ephemeris to provide the initial raw data
|
29
|
+
|
30
|
+
You can learn more about ephemerides on the [Ephem page].
|
31
|
+
|
32
|
+
```rb
|
33
|
+
ephem = Astronoby::Ephem.load("inpop19a.bsp")
|
34
|
+
|
35
|
+
observer = Astronoby::Observer.new(
|
36
|
+
latitude: Astronoby::Angle.from_degrees(41.0082),
|
37
|
+
longitude: Astronoby::Angle.from_degrees(28.9784),
|
38
|
+
elevation: Astronoby::Distance.from_meters(40)
|
39
|
+
)
|
40
|
+
|
41
|
+
calculator = Astronoby::TwilightCalculator.new(
|
42
|
+
observer: observer,
|
43
|
+
ephem: ephem
|
44
|
+
)
|
45
|
+
```
|
46
|
+
|
47
|
+
You can learn more about observers on the [Observer page].
|
48
|
+
|
49
|
+
## `events_between`
|
50
|
+
|
51
|
+
This is the main method of the calculator. It provides all the twilight times
|
52
|
+
that will happen between two dates.
|
53
|
+
|
54
|
+
It returns a `Astronoby::TwilightEvents` object which exposes the 6 following
|
55
|
+
instance methods:
|
56
|
+
* `#morning_astronomical_twilight_times`: when the rising Sun reaches 18° below
|
57
|
+
the horizon
|
58
|
+
* `#morning_nautical_twilight_times`: when the rising Sun reaches 12° below the
|
59
|
+
horizon
|
60
|
+
* `#morning_civil_twilight_times`: when the rising Sun reaches 6° below the
|
61
|
+
horizon
|
62
|
+
* `#evening_civil_twilight_times`: when the setting Sun reaches 6° below the
|
63
|
+
horizon
|
64
|
+
* `#evening_nautical_twilight_times`: when the setting Sun reaches 12° below the
|
65
|
+
horizon
|
66
|
+
* `#evening_astronomical_twilight_times`: when the setting Sun reaches 18° below
|
67
|
+
the horizon
|
68
|
+
|
69
|
+
```rb
|
70
|
+
events = calculator.events_between(
|
71
|
+
Time.utc(2025, 8, 1),
|
72
|
+
Time.utc(2025, 8, 8)
|
73
|
+
)
|
74
|
+
|
75
|
+
events.morning_civil_twilight_times
|
76
|
+
# =>
|
77
|
+
# [2025-08-01 02:29:17 UTC,
|
78
|
+
# 2025-08-02 02:30:21 UTC,
|
79
|
+
# 2025-08-03 02:31:26 UTC,
|
80
|
+
# 2025-08-04 02:32:30 UTC,
|
81
|
+
# 2025-08-05 02:33:35 UTC,
|
82
|
+
# 2025-08-06 02:34:40 UTC,
|
83
|
+
# 2025-08-07 02:35:45 UTC]
|
84
|
+
```
|
85
|
+
|
86
|
+
## `#event_on`
|
87
|
+
|
88
|
+
The calculator exposes the instance method `#event_on` to compute the twilight
|
89
|
+
times for a given `date` (`Date`) parameter.
|
90
|
+
|
91
|
+
It returns a `Astronoby::TwilightEvent` object which exposes the 6 following
|
92
|
+
instance methods: `#morning_astronomical_twilight_time`,
|
93
|
+
`#morning_nautical_twilight_time`, `#morning_civil_twilight_time`,
|
94
|
+
`#evening_civil_twilight_time`, `#evening_nautical_twilight_time` and
|
95
|
+
`#evening_astronomical_twilight_time`.
|
96
|
+
|
97
|
+
```rb
|
98
|
+
event = calculator.event_on(Date.new(2025, 5, 1))
|
99
|
+
|
100
|
+
event.morning_astronomical_twilight_time
|
101
|
+
# => 2025-05-01 01:17:18 UTC
|
102
|
+
|
103
|
+
event.morning_nautical_twilight_time
|
104
|
+
# => 2025-05-01 01:56:48 UTC
|
105
|
+
|
106
|
+
event.evening_civil_twilight_time
|
107
|
+
# => 2025-05-01 17:29:41 UTC
|
108
|
+
|
109
|
+
event.evening_nautical_twilight_time
|
110
|
+
# => 2025-05-01 18:06:08 UTC
|
111
|
+
|
112
|
+
event.evening_astronomical_twilight_time
|
113
|
+
# => 2025-05-01 18:45:38 UTC
|
114
|
+
```
|
115
|
+
|
116
|
+
[Ephem page]: ephem.md
|
117
|
+
[Observer page]: observer.md
|
118
|
+
|
119
|
+
## See also
|
120
|
+
- [Rise, Transit and Set Times](rise_transit_set_times.md) - for sun and moon events
|
121
|
+
- [Observer](observer.md) - for location setup
|
122
|
+
- [Ephemerides](ephem.md) - for data sources
|
123
|
+
- [Moon Phases](moon_phases.md) - for lunar events
|
@@ -17,7 +17,13 @@ module Astronoby
|
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
|
20
|
+
# Attributes that require Sun data like phase angle or magnitude are not
|
21
|
+
# applicable for Earth.
|
22
|
+
def requires_sun_data?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def compute_astrometric(_ephem)
|
21
27
|
Astrometric.new(
|
22
28
|
position: Vector[
|
23
29
|
Distance.zero,
|
@@ -35,7 +41,7 @@ module Astronoby
|
|
35
41
|
)
|
36
42
|
end
|
37
43
|
|
38
|
-
def compute_mean_of_date(
|
44
|
+
def compute_mean_of_date(_ephem)
|
39
45
|
MeanOfDate.new(
|
40
46
|
position: Vector[
|
41
47
|
Distance.zero,
|
@@ -3,9 +3,26 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Jupiter < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(71_492_000)
|
6
|
+
ABSOLUTE_MAGNITUDE = -9.395
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, JUPITER_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
-3.7 * 10**-4 * phase_angle_degrees +
|
25
|
+
6.16 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
26
|
+
end
|
10
27
|
end
|
11
28
|
end
|
@@ -3,9 +3,26 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Mars < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(3_396_200)
|
6
|
+
ABSOLUTE_MAGNITUDE = -1.601
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, MARS_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
2.267 * 10**-2 * phase_angle_degrees -
|
25
|
+
1.302 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
26
|
+
end
|
10
27
|
end
|
11
28
|
end
|
@@ -3,9 +3,30 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Mercury < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(2_439_700)
|
6
|
+
ABSOLUTE_MAGNITUDE = -0.613
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, MERCURY_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
6.328 * 10**-2 * phase_angle_degrees -
|
25
|
+
1.6336 * 10**-3 * phase_angle_degrees * phase_angle_degrees +
|
26
|
+
3.3634 * 10**-5 * phase_angle_degrees**3 -
|
27
|
+
3.4265 * 10**-7 * phase_angle_degrees**4 +
|
28
|
+
1.6893 * 10**-9 * phase_angle_degrees**5 -
|
29
|
+
3.0334 * 10**-12 * phase_angle_degrees**6
|
30
|
+
end
|
10
31
|
end
|
11
32
|
end
|
@@ -4,6 +4,7 @@ module Astronoby
|
|
4
4
|
class Moon < SolarSystemBody
|
5
5
|
SEMIDIAMETER_VARIATION = 0.7275
|
6
6
|
EQUATORIAL_RADIUS = Distance.from_meters(1_737_400)
|
7
|
+
ABSOLUTE_MAGNITUDE = 0.28
|
7
8
|
|
8
9
|
def self.ephemeris_segments(ephem_source)
|
9
10
|
if ephem_source == ::Ephem::SPK::JPL_DE
|
@@ -32,16 +33,8 @@ module Astronoby
|
|
32
33
|
Events::MoonPhases.phases_for(year: year, month: month)
|
33
34
|
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
def initialize(instant:, ephem:)
|
38
|
-
super
|
39
|
-
@phase_angle = compute_phase_angle(ephem)
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [Float] Moon's illuminated fraction
|
43
|
-
def illuminated_fraction
|
44
|
-
@illuminated_fraction ||= (1 + phase_angle.cos) / 2.0
|
36
|
+
def self.absolute_magnitude
|
37
|
+
ABSOLUTE_MAGNITUDE
|
45
38
|
end
|
46
39
|
|
47
40
|
# @return [Float] Phase fraction, from 0 to 1
|
@@ -56,31 +49,6 @@ module Astronoby
|
|
56
49
|
# Author: Jean Meeus
|
57
50
|
# Edition: 2nd edition
|
58
51
|
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
59
|
-
|
60
|
-
# @return [Angle] Moon's phase angle
|
61
|
-
def compute_phase_angle(ephem)
|
62
|
-
@phase_angle ||= begin
|
63
|
-
sun = Sun.new(instant: @instant, ephem: ephem)
|
64
|
-
geocentric_elongation = Angle.acos(
|
65
|
-
sun.apparent.equatorial.declination.sin *
|
66
|
-
apparent.equatorial.declination.sin +
|
67
|
-
sun.apparent.equatorial.declination.cos *
|
68
|
-
apparent.equatorial.declination.cos *
|
69
|
-
(
|
70
|
-
sun.apparent.equatorial.right_ascension -
|
71
|
-
apparent.equatorial.right_ascension
|
72
|
-
).cos
|
73
|
-
)
|
74
|
-
|
75
|
-
term1 = sun.astrometric.distance.km * geocentric_elongation.sin
|
76
|
-
term2 = astrometric.distance.km -
|
77
|
-
sun.astrometric.distance.km * geocentric_elongation.cos
|
78
|
-
angle = Angle.atan(term1 / term2)
|
79
|
-
Astronoby::Util::Trigonometry
|
80
|
-
.adjustement_for_arctangent(term1, term2, angle)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
52
|
def mean_elongation
|
85
53
|
@mean_elongation ||= Angle.from_degrees(
|
86
54
|
(
|
@@ -94,7 +62,32 @@ module Astronoby
|
|
94
62
|
end
|
95
63
|
|
96
64
|
def elapsed_centuries
|
97
|
-
(@instant.tt -
|
65
|
+
(@instant.tt - JulianDate::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Source:
|
71
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
72
|
+
# Almanac (2018)
|
73
|
+
# Authors: Anthony Mallama and James L. Hilton
|
74
|
+
def magnitude_correction_term
|
75
|
+
phase_angle_degrees = phase_angle.degrees
|
76
|
+
if phase_angle_degrees <= 150 && current_phase_fraction <= 0.5
|
77
|
+
2.9994 * 10**-2 * phase_angle_degrees -
|
78
|
+
1.6057 * 10**-4 * phase_angle_degrees**2 +
|
79
|
+
3.1543 * 10**-6 * phase_angle_degrees**3 -
|
80
|
+
2.0667 * 10**-8 * phase_angle_degrees**4 +
|
81
|
+
6.2553 * 10**-11 * phase_angle_degrees**5
|
82
|
+
elsif phase_angle_degrees <= 150 && current_phase_fraction > 0.5
|
83
|
+
3.3234 * 10**-2 * phase_angle_degrees -
|
84
|
+
3.0725 * 10**-4 * phase_angle_degrees**2 +
|
85
|
+
6.1575 * 10**-6 * phase_angle_degrees**3 -
|
86
|
+
4.7723 * 10**-8 * phase_angle_degrees**4 +
|
87
|
+
1.4681 * 10**-10 * phase_angle_degrees**5
|
88
|
+
else
|
89
|
+
super
|
90
|
+
end
|
98
91
|
end
|
99
92
|
end
|
100
93
|
end
|
@@ -3,9 +3,30 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Neptune < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(24_764_000)
|
6
|
+
ABSOLUTE_MAGNITUDE = -7.0
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, NEPTUNE_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
if phase_angle_degrees < 133 && @instant.tt > JulianDate::J2000
|
25
|
+
7.944 * 10**-3 * phase_angle_degrees +
|
26
|
+
9.617 * 10**-5 * phase_angle_degrees * phase_angle_degrees
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
10
31
|
end
|
11
32
|
end
|
@@ -3,9 +3,35 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Saturn < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(60_268_000)
|
6
|
+
ABSOLUTE_MAGNITUDE = -8.914
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, SATURN_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
if phase_angle_degrees <= 6
|
25
|
+
-0.036 -
|
26
|
+
3.7 * 10**-4 * phase_angle_degrees +
|
27
|
+
6.16 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
28
|
+
else
|
29
|
+
0.026 +
|
30
|
+
2.446 * 10**-4 * phase_angle_degrees +
|
31
|
+
2.672 * 10**-4 * phase_angle_degrees * phase_angle_degrees -
|
32
|
+
1.505 * 10**-6 * phase_angle_degrees**3 +
|
33
|
+
4.767 * 10**-9 * phase_angle_degrees**4
|
34
|
+
end
|
35
|
+
end
|
10
36
|
end
|
11
37
|
end
|
@@ -27,42 +27,49 @@ module Astronoby
|
|
27
27
|
segments = ephemeris_segments(ephem.type)
|
28
28
|
segment1 = segments[0]
|
29
29
|
segment2 = segments[1] if segments.size == 2
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
cache_key = CacheKey.generate(:geometric, instant, segment1, segment2)
|
31
|
+
|
32
|
+
Astronoby.cache.fetch(cache_key) do
|
33
|
+
state1 = ephem[*segment1].state_at(instant.tt)
|
34
|
+
|
35
|
+
if segment2
|
36
|
+
state2 = ephem[*segment2].state_at(instant.tt)
|
37
|
+
position = state1.position + state2.position
|
38
|
+
velocity = state1.velocity + state2.velocity
|
39
|
+
else
|
40
|
+
position = state1.position
|
41
|
+
velocity = state1.velocity
|
42
|
+
end
|
43
|
+
|
44
|
+
position_vector = Vector[
|
45
|
+
Distance.from_kilometers(position.x),
|
46
|
+
Distance.from_kilometers(position.y),
|
47
|
+
Distance.from_kilometers(position.z)
|
48
|
+
]
|
49
|
+
|
50
|
+
velocity_vector = Vector[
|
51
|
+
Velocity.from_kilometers_per_day(velocity.x),
|
52
|
+
Velocity.from_kilometers_per_day(velocity.y),
|
53
|
+
Velocity.from_kilometers_per_day(velocity.z)
|
54
|
+
]
|
55
|
+
|
56
|
+
Geometric.new(
|
57
|
+
position: position_vector,
|
58
|
+
velocity: velocity_vector,
|
59
|
+
instant: instant,
|
60
|
+
target_body: self
|
61
|
+
)
|
40
62
|
end
|
41
|
-
|
42
|
-
position_vector = Vector[
|
43
|
-
Distance.from_kilometers(position.x),
|
44
|
-
Distance.from_kilometers(position.y),
|
45
|
-
Distance.from_kilometers(position.z)
|
46
|
-
]
|
47
|
-
|
48
|
-
velocity_vector = Vector[
|
49
|
-
Velocity.from_kilometers_per_day(velocity.x),
|
50
|
-
Velocity.from_kilometers_per_day(velocity.y),
|
51
|
-
Velocity.from_kilometers_per_day(velocity.z)
|
52
|
-
]
|
53
|
-
|
54
|
-
Geometric.new(
|
55
|
-
position: position_vector,
|
56
|
-
velocity: velocity_vector,
|
57
|
-
instant: instant,
|
58
|
-
target_body: self
|
59
|
-
)
|
60
63
|
end
|
61
64
|
|
62
65
|
def self.ephemeris_segments(_ephem_source)
|
63
66
|
raise NotImplementedError
|
64
67
|
end
|
65
68
|
|
69
|
+
def self.absolute_magnitude
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
66
73
|
def initialize(ephem:, instant:)
|
67
74
|
@instant = instant
|
68
75
|
@geometric = compute_geometric(ephem)
|
@@ -74,6 +81,7 @@ module Astronoby
|
|
74
81
|
target: @geometric,
|
75
82
|
ephem: ephem
|
76
83
|
)
|
84
|
+
compute_sun(ephem) if requires_sun_data?
|
77
85
|
end
|
78
86
|
|
79
87
|
def astrometric
|
@@ -113,10 +121,112 @@ module Astronoby
|
|
113
121
|
)
|
114
122
|
end
|
115
123
|
|
124
|
+
# Returns the constellation of the body
|
125
|
+
# @return [Astronoby::Constellation, nil]
|
126
|
+
def constellation
|
127
|
+
@constellation ||= Constellations::Finder.find(
|
128
|
+
Precession.for_equatorial_coordinates(
|
129
|
+
coordinates: astrometric.equatorial,
|
130
|
+
epoch: JulianDate::B1875
|
131
|
+
)
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Source:
|
136
|
+
# Title: Astronomical Algorithms
|
137
|
+
# Author: Jean Meeus
|
138
|
+
# Edition: 2nd edition
|
139
|
+
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
140
|
+
# @return [Astronoby::Angle, nil] Phase angle of the body
|
141
|
+
def phase_angle
|
142
|
+
return unless @sun
|
143
|
+
|
144
|
+
@phase_angle ||= begin
|
145
|
+
geocentric_elongation = Angle.acos(
|
146
|
+
@sun.apparent.equatorial.declination.sin *
|
147
|
+
apparent.equatorial.declination.sin +
|
148
|
+
@sun.apparent.equatorial.declination.cos *
|
149
|
+
apparent.equatorial.declination.cos *
|
150
|
+
(
|
151
|
+
@sun.apparent.equatorial.right_ascension -
|
152
|
+
apparent.equatorial.right_ascension
|
153
|
+
).cos
|
154
|
+
)
|
155
|
+
|
156
|
+
term1 = @sun.astrometric.distance.km * geocentric_elongation.sin
|
157
|
+
term2 = astrometric.distance.km -
|
158
|
+
@sun.astrometric.distance.km * geocentric_elongation.cos
|
159
|
+
angle = Angle.atan(term1 / term2)
|
160
|
+
Astronoby::Util::Trigonometry
|
161
|
+
.adjustement_for_arctangent(term1, term2, angle)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Fraction between 0 and 1 of the body's disk that is illuminated.
|
166
|
+
# @return [Float, nil] Body's illuminated fraction, between 0 and 1.
|
167
|
+
def illuminated_fraction
|
168
|
+
return unless phase_angle
|
169
|
+
|
170
|
+
@illuminated_fraction ||= (1 + phase_angle.cos) / 2.0
|
171
|
+
end
|
172
|
+
|
173
|
+
# Source:
|
174
|
+
# Title: Astronomical Algorithms
|
175
|
+
# Author: Jean Meeus
|
176
|
+
# Edition: 2nd edition
|
177
|
+
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
178
|
+
# Apparent magnitude of the body, as seen from Earth.
|
179
|
+
# @return [Float, nil] Apparent magnitude of the body.
|
180
|
+
def apparent_magnitude
|
181
|
+
return unless self.class.absolute_magnitude
|
182
|
+
|
183
|
+
@apparent_magnitude ||= begin
|
184
|
+
body_sun_distance =
|
185
|
+
(astrometric.position - @sun.astrometric.position).magnitude
|
186
|
+
self.class.absolute_magnitude +
|
187
|
+
5 * Math.log10(body_sun_distance.au * astrometric.distance.au) +
|
188
|
+
magnitude_correction_term
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Angular diameter of the body, as seen from Earth. Based on the apparent
|
193
|
+
# position of the body.
|
194
|
+
# @return [Astronoby::Angle] Angular diameter of the body
|
195
|
+
def angular_diameter
|
196
|
+
@angular_radius ||= begin
|
197
|
+
return if apparent.position.zero?
|
198
|
+
|
199
|
+
Angle.from_radians(
|
200
|
+
Math.asin(self.class::EQUATORIAL_RADIUS.m / apparent.distance.m) * 2
|
201
|
+
)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
116
205
|
private
|
117
206
|
|
207
|
+
# By default, Solar System bodies expose attributes that are dependent on
|
208
|
+
# the Sun's position, such as phase angle and illuminated fraction.
|
209
|
+
# If a body does not require Sun data, it should override this method to
|
210
|
+
# return false.
|
211
|
+
def requires_sun_data?
|
212
|
+
true
|
213
|
+
end
|
214
|
+
|
118
215
|
def compute_geometric(ephem)
|
119
216
|
self.class.compute_geometric(ephem: ephem, instant: @instant)
|
120
217
|
end
|
218
|
+
|
219
|
+
def compute_sun(ephem)
|
220
|
+
@sun ||= Sun.new(instant: @instant, ephem: ephem)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Source:
|
224
|
+
# Title: Explanatory Supplement to the Astronomical Almanac
|
225
|
+
# Authors: Sean E. Urban and P. Kenneth Seidelmann
|
226
|
+
# Edition: University Science Books
|
227
|
+
# Chapter: 10.3 - Phases and Magnitudes
|
228
|
+
def magnitude_correction_term
|
229
|
+
-2.5 * Math.log10(illuminated_fraction)
|
230
|
+
end
|
121
231
|
end
|
122
232
|
end
|
data/lib/astronoby/bodies/sun.rb
CHANGED
@@ -3,11 +3,28 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Sun < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(695_700_000)
|
6
|
+
ABSOLUTE_MAGNITUDE = -26.74
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, SUN]]
|
9
10
|
end
|
10
11
|
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
# Source:
|
17
|
+
# Title: Explanatory Supplement to the Astronomical Almanac
|
18
|
+
# Authors: Sean E. Urban and P. Kenneth Seidelmann
|
19
|
+
# Edition: University Science Books
|
20
|
+
# Chapter: 10.3 - Phases and Magnitudes
|
21
|
+
# Apparent magnitude of the body, as seen from Earth.
|
22
|
+
# @return [Float] Apparent magnitude of the body.
|
23
|
+
def apparent_magnitude
|
24
|
+
@apparent_magnitude ||=
|
25
|
+
self.class.absolute_magnitude + 5 * Math.log10(astrometric.distance.au)
|
26
|
+
end
|
27
|
+
|
11
28
|
# Source:
|
12
29
|
# Title: Astronomical Algorithms
|
13
30
|
# Author: Jean Meeus
|
@@ -17,7 +34,7 @@ module Astronoby
|
|
17
34
|
# @return [Integer] Equation of time in seconds
|
18
35
|
def equation_of_time
|
19
36
|
right_ascension = apparent.equatorial.right_ascension
|
20
|
-
t = (@instant.julian_date -
|
37
|
+
t = (@instant.julian_date - JulianDate::J2000) / Constants::DAYS_PER_JULIAN_MILLENIA
|
21
38
|
l0 = (280.4664567 +
|
22
39
|
360_007.6982779 * t +
|
23
40
|
0.03032028 * t**2 +
|
@@ -25,7 +42,7 @@ module Astronoby
|
|
25
42
|
t**4 / 15_300 -
|
26
43
|
t**5 / 2_000_000) % Constants::DEGREES_PER_CIRCLE
|
27
44
|
nutation = Nutation.new(instant: instant).nutation_in_longitude
|
28
|
-
obliquity = TrueObliquity.
|
45
|
+
obliquity = TrueObliquity.at(@instant)
|
29
46
|
|
30
47
|
(
|
31
48
|
Angle
|
@@ -37,5 +54,11 @@ module Astronoby
|
|
37
54
|
).hours * Constants::SECONDS_PER_HOUR
|
38
55
|
).round
|
39
56
|
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def requires_sun_data?
|
61
|
+
false
|
62
|
+
end
|
40
63
|
end
|
41
64
|
end
|
@@ -3,9 +3,14 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Uranus < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(25_559_000)
|
6
|
+
ABSOLUTE_MAGNITUDE = -7.11
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, URANUS_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
10
15
|
end
|
11
16
|
end
|
@@ -3,9 +3,34 @@
|
|
3
3
|
module Astronoby
|
4
4
|
class Venus < SolarSystemBody
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(6_051_800)
|
6
|
+
ABSOLUTE_MAGNITUDE = -4.384
|
6
7
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, VENUS_BARYCENTER]]
|
9
10
|
end
|
11
|
+
|
12
|
+
def self.absolute_magnitude
|
13
|
+
ABSOLUTE_MAGNITUDE
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Source:
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
20
|
+
# Almanac (2018)
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
22
|
+
def magnitude_correction_term
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
24
|
+
if phase_angle_degrees < 163.7
|
25
|
+
-1.044 * 10**-3 * phase_angle_degrees +
|
26
|
+
3.687 * 10**-4 * phase_angle_degrees * phase_angle_degrees -
|
27
|
+
2.814 * 10**-6 * phase_angle_degrees**3 +
|
28
|
+
8.938 * 10**-9 * phase_angle_degrees**4
|
29
|
+
|
30
|
+
else
|
31
|
+
240.44228 - 2.81914 * phase_angle_degrees +
|
32
|
+
8.39034 * 10**-3 * phase_angle_degrees * phase_angle_degrees
|
33
|
+
end
|
34
|
+
end
|
10
35
|
end
|
11
36
|
end
|