Skip to content

Instantly share code, notes, and snippets.

@rhannequin
Created July 16, 2023 23:18
Show Gist options
  • Save rhannequin/5845833a59194f7fcc3e1a13e5cc7a8d to your computer and use it in GitHub Desktop.
Save rhannequin/5845833a59194f7fcc3e1a13e5cc7a8d to your computer and use it in GitHub Desktop.
Ruby script to compute the best days to observe a celestial body, based on its elevation on the celestial sphere and its angular diamater, based on the IMCCE Opale API.
require "date"
require "faraday"
host = "https://opale.imcce.fr"
observer_longitude = 2.3522
observer_latitude = 48.8566
body = 699 # https://www.imcce.fr/content/medias/recherche/equipes/asd/calceph/html/c/calceph.naifid.html
year = 2023
first_date = Date.new(year, 1, 1)
last_date = Date.new(year, 12, 31)
number_of_dates = (last_date - first_date).to_i + 1
number_of_hours = number_of_dates * 24
conn = Faraday.new(url: host) do |builder|
builder.response :json
builder.response :logger
end
url = "/api/v1/phenomena/rts/10/#{first_date}/#{observer_latitude},#{observer_longitude}"
response = conn.get(url) do |req|
req.params["nbd"] = number_of_dates
req.params["twilight"] = true
end
rts = response.body["response"]["data"].first["10"]
# This doesn't work for latitudes above ~60° (north of Oslo, Norway),
# or below ~-60° (south of Ushuaia, Argentina), because there is no civil
# twilight at those latitudes close to the solstices.
sunlight_periods = rts.map do |el|
[
Date.parse(el["calendarDate"]),
(
DateTime.parse(el["civilDawn"].first["date"]).to_time..
DateTime.parse(el["civilDusk"].first["date"]).to_time
)
]
end.to_h
response = conn.get("/api/v1/positions/#{body}") do |req|
req.params["observer"] = "#{observer_latitude},#{observer_longitude}"
req.params["date"] = first_date.strftime("%FT%T")
req.params["step"] = "1H"
req.params["nbd"] = number_of_hours
req.params["frame"] = "TrueOfDate"
req.params["reference"] = "origin"
req.params["places"] = "apparent"
req.params["quantities"] = "radec,azel,dist,mag,phase,angdiam"
end
positions = response.body["response"]["data"].reject do |el|
sunlight_periods[DateTime.parse(el["date"]).to_date].cover?(
DateTime.parse(el["date"]).to_time
) || el["elevation"] < 0
end
elevations = positions.sort_by { |el| el["elevation"] }.reverse
angular_diameter = positions.sort_by { |el| el["angDiameter"] }.reverse
best_of_all_hour = positions
.map do |el|
[
el["date"],
angular_diameter.index(el) + elevations.index(el)
]
end.min_by { |rank| rank.last }.first
best_of_all = positions.find { |el| el["date"] == best_of_all_hour }
best_of = [
["Best moment for elevation", elevations.first],
["Best moment for angular diameter", angular_diameter.first],
["Best moment for all", best_of_all]
].to_h
best_of.each do |title, el|
elevation_ranking = elevations.index(el) + 1
ad_ranking = angular_diameter.index(el) + 1
puts "---------------------------------"
puts title
puts "Date: #{DateTime.parse(el["date"]).to_time.utc}"
puts "Elevation: #{el["elevation"]} (##{elevation_ranking} of elevations)"
puts "Angular diameter: #{el["angDiameter"]} (##{ad_ranking} of angular diameters)"
puts "Magnitude: #{el["magnitude"]}"
puts "Distance: #{el["distance"]}"
end
# Output
# ---------------------------------
# Best moment for elevation
# Date: 2023-07-13 03:00:00 UTC
# Elevation: 30.52802388263536 (#1 of elevations)
# Angular diameter: 0.005098776354 (#735 of angular diameters)
# Magnitude: 0.66
# Distance: 1354482644.95111
# ---------------------------------
# Best moment for angular diameter
# Date: 2023-08-27 03:00:00 UTC
# Elevation: 17.082071830366313 (#960 of elevations)
# Angular diameter: 0.005268176823 (#1 of angular diameters)
# Magnitude: 0.43
# Distance: 1310928678.75692
# ---------------------------------
# Best moment for all
# Date: 2023-08-27 00:00:00 UTC
# Elevation: 29.387024727459007 (#70 of elevations)
# Angular diameter: 0.005268172202 (#9 of angular diameters)
# Magnitude: 0.43
# Distance: 1310929828.67324
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment