| Crates.io | flare |
| lib.rs | flare |
| version | 0.2.0 |
| created_at | 2024-09-27 10:43:33.979863+00 |
| updated_at | 2025-04-24 16:36:34.383609+00 |
| description | A lightweight library to perform basic astronomical calculations, inspired by Python's Astropy syntax. |
| homepage | |
| repository | https://github.com/boom-astro/flare |
| max_upload_size | |
| id | 1388551 |
| size | 93,079 |
flare is a lightweight library designed to perform basic astronomical calculations, inspired by Python's Astropy syntax.
To include flare in your project, add the following to your Cargo.toml:
[dependencies]
flare = "0.1.0"
You can do a couple of different things with flare. We recommend reading the documentation that you can find here.
Here are some examples of what you can do with flare:
Handle dates in multiple standard & astronomical formats:
use chrono::{Utc, TimeZone};
use flare::Time;
fn main() {
let time = Time::new(2021, 6, 21, 12, 0, 0);
// You can convert a time (which is timezone-agnostic, in UTC)
// to a variety of formats:
let time_jd = time.to_jd();
println!("The Julian Date of the time is: {}", time_jd);
// and, you can do the exact opposite, create a `Time` object
// from a JD, MJD, GST, UTC, or ISO string:
let time_from_jd = Time::from_jd(2459376.0);
println!("The time from the Julian Date is: {}", time_from_jd);
// you can also get the current time:
let current_time = Time::now();
println!("{}", current_time);
// we rely on the fantastic `chrono` library for date-time handling
// so you can convert a chrono::DateTime<Utc> object to a `Time` object
let chrono_utc = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
let time = Time::from_utc(chrono_utc);
// you can print a date in any of the supported formats:
println!("{}", time.to_string(Some("mjd")));
}
Calculate the angular separation between two targets/objects in the sky:
use flare::Target;
fn main() {
let target1 = Target::new(6.374817, 20.242942, Some("A"));
let target2 = Target::new(6.374817, 21.242942, Some("B"));
let separation = target1.separation(&target2);
println!("The angular separation between the two targets is: {}", separation);
}
Given an observer on earth, find the airmass of a target (at a given time):
use flare::{Target, Observer, Time};
fn main() {
let observer = Observer::new(30.0, 45.0, 1800.0, Some("A"));
println!("{}", observer);
let target = Target::new(6.374817, 20.242942, Some("B"));
println!("{}", target);
let time = Time::new(2020, 12, 21, 12, 0, 0);
println!("{}", time);
let airmass = target.airmass(&observer, &time);
println!("Airmass at {} is: {}", time, airmass);
}
For an observer, find the next sunrise & sunset times (after a given time):
use flare::{Observer, Time};
fn main() {
let observer = Observer::new(33.3633675, -116.8361345, 1870.0, None);
println!("{}", observer);
let time = Time::new(2024, 9, 10, 3, 0, 0);
println!("{}", time);
let (sunrise, sunset) = observer.sun_set_time(Some(&time), None);
println!("Next sunrise: {}", sunrise);
println!("Next sunset: {}", sunset);
// the time is optional, in which case the current time is used
let (sunrise, sunset) = observer.sun_set_time(None, None);
println!("Sunrise: {}, Sunset: {}", sunrise, sunset);
// You can also specify at what altitude the sun should be considered to have risen/set, as an angle in degrees
let (sunrise, sunset) = observer.sun_set_time(Some(&time), Some(0.0));
println!("Sunrise: {}, Sunset: {} (at 0.0 deg)", sunrise, sunset);
// Otherwise, you can get astronomical, nautical, and civil twilight times:
let (sunrise, sunset) = observer.twilight_astronomical(Some(&time));
println!("Sunrise: {}, Sunset: {} (astronomical)", sunrise, sunset);
let (sunrise, sunset) = observer.twilight_nautical(Some(&time));
println!("Sunrise: {}, Sunset: {} (nautical)", sunrise, sunset);
let (sunrise, sunset) = observer.twilight_civil(Some(&time));
println!("Sunrise: {}, Sunset: {} (civil)", sunrise, sunset);
}
Work with photometry, in mag and flux space:
use flare::phot::{mag_to_flux, flux_to_mag, limmag_to_fluxerr, fluxerr_to_limmag, ZP};
fn main() {
let mag = 20.0;
let magerr = 0.1;
let limmag = 21.0;
// mag to flux
let (flux, fluxerr) = mag_to_flux(mag, magerr, ZP);
println!("flux: {}, fluxerr: {}", flux, fluxerr);
// flux to mag
let (mag, magerr) = flux_to_mag(flux, fluxerr, ZP);
println!("mag: {}, mag: {}", mag, magerr);
// limiting mag to fluxerr, at 5-sigma
let fluxerr = limmag_to_fluxerr(limmag, ZP, 5.0);
println!("fluxerr (from limmag): {}", fluxerr);
// fluxerr to limiting mag at 5-sigma
let limmag = fluxerr_to_limmag(fluxerr, ZP, 5.0);
println!("limmag (from fluxerr, at 5-sigma): {}", limmag);
// ZP = 23.9, but you can specify your own zero point for any of the above,
// just like you can specify a different sigma value
let limmag = limmag_to_fluxerr(limmag, 25.0, 3.0);
println!("fluxerr (from limmag, 3-sigma & ZP=25.0): {}", limmag);
}
Use a cosmology (custom, or one of the built-in ones) to compute distances:
use flare::Cosmo;
fn main() {
let z = 0.1;
// you can use one of the built-in cosmologies
let cosmo = Cosmo::planck18();
let luminosity_distance = cosmo.luminosity_distance(z);
println!("Luminosity distance: {}", luminosity_distance);
let dm = cosmo.dm(z);
println!("Distance modulus: {}", dm);
let angular_diameter_distance = cosmo.angular_diameter_distance(z);
println!("Angular diameter distance: {}", angular_diameter_distance);
// for example, you could this to get the absolute magnitude of a target
let apparent_mag = 20.0;
let abs_mag = apparent_mag - dm;
println!("{} mag at z={} is {}", apparent_mag, z, abs_mag);
// You can also create your own cosmology
let cosmology = Cosmo::new(67.66, 0.3103, 0.6897, Some("mycosmo"));
let z = 0.0246;
let dm = cosmology.dm(z);
println!("Distance modulus at z={} (using custom cosmology {}) is {}", z, cosmology.name.unwrap(), dm);
}
Look for a periodic in a lightcurve:
use flare::period::{fpw, freq_grid, get_best_freq};
use rand::Rng;
fn main() {
// let's simulate a sinusoidal with a period of 6 hours, with some noise
// measured at N random times over a 6 years period.
let n_points = 1000;
let period = 0.25; // in days
// we don't want evenly spaced data, so let's randomly sample times over 6 years
// so we grab random floats between 0 and 6*365 days (6 years)
let mut rng = rand::rng();
let mut t: Vec<f64> = Vec::with_capacity(n_points);
for _ in 0..n_points {
// generate a random time between 0 and 6*365 days
let random_time = rng.random_range(0.0..(6.0 * 365.0));
t.push(random_time);
}
// Sort the time array to ensure it's in ascending order
t.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
// Now generate the sinusoidal light curve with some noise
let noise_level = 0.1; // noise in magnitude
let y: Vec<f64> = t
.iter()
.map(|&time| {
// Simulate a sinusoidal light curve with some noise
let true_value = (2.0 * std::f64::consts::PI * time / period).sin();
let noise = rng.random_range(-noise_level..noise_level);
true_value + noise
})
.collect();
// Define frequency grid, with a min freq of 10 days
// and a maximum frequency of 5 minutes
let f_min = 1.0 / (10.0 * 24.0 * 60.0);
let f_max = 1.0 / (5.0 / 60.0);
let freqs = freq_grid(&t, Some(f_min), Some(f_max), 3);
println!("Using {} frequencies", freqs.len());
// the FPW algorithm requires a number of bins, typically between 5 and 20
// in this crate, we've set a maximum of 20 bins. This is enough for most
// applications, and using a set number of bins let's us allocated memory to the stack
// which is much faster than heap allocation.
let n_bins = 10; // choose a number of bins between 5 and 20
let fpw_stats = fpw(&t, &y, &vec![0.1; n_points], &freqs, n_bins);
// Find the best period using the FPW statistic
let (best_freq, best_stat) = get_best_freq(&freqs, &fpw_stats);
let period = 1.0 / best_freq * 24.0; // convert from frequency in days to a period in hours
println!("Period: {:.2} hours, statistic: {:.2}", period, best_stat);
}
We welcome contributions! No specific guidelines yet, but feel free to open an issue or a PR. Keep in mind that the goal is to keep this library lightweight and focused on basic astronomical calculations. We are not trying to replicate the functionality of Astropy in Rust.
This project is licensed under the MIT License - see the LICENSE file for details.