use std::path::PathBuf;
use std::time::Instant;
use anyhow::{Context, Result};
use crate::ForceModel;
use crate::io::output::OutputFormat;
use crate::io::{orbit_input, output};
#[derive(clap::Args)]
pub struct EphemerisArgs {
#[arg(long = "object-id", num_args = 1..)]
pub object_ids: Option<Vec<String>>,
#[arg(long, conflicts_with = "object_ids")]
pub input: Option<PathBuf>,
#[arg(long, value_delimiter = ',')]
pub observers: Vec<String>,
#[arg(long)]
pub epoch: f64,
#[arg(long, default_value = "standard")]
pub force_model: ForceModel,
#[arg(long, default_value = ".")]
pub out_dir: PathBuf,
#[arg(long, value_enum, default_value_t = OutputFormat::Parquet)]
pub format: OutputFormat,
}
pub fn run(data_dir: Option<PathBuf>, args: EphemerisArgs) -> Result<()> {
let request = crate::daemon::protocol::Request::Ephemeris {
object_ids: args.object_ids.clone(),
input_path: args.input.as_ref().map(|p| p.display().to_string()),
observers: args.observers.clone(),
epoch: args.epoch,
force_model: args.force_model.as_str().to_string(),
out_dir: args.out_dir.display().to_string(),
format: super::propagate::format_to_str(args.format).into(),
};
if let Some(resp) = crate::daemon::client::try_request(&request) {
if resp.success {
eprintln!("{}", resp.message);
return Ok(());
} else {
anyhow::bail!("daemon error: {}", resp.error.unwrap_or_default());
}
}
let t0 = Instant::now();
let ctx =
empyrean::Context::from_data_dir(data_dir.as_deref()).context("failed to load context")?;
eprintln!("Loaded context ({:.1}s)", t0.elapsed().as_secs_f64());
let batch = orbit_input::load_orbits(&args.object_ids, &args.input)?;
let obs_refs: Vec<&str> = args.observers.iter().map(|s| s.as_str()).collect();
let observers = ctx
.get_observers(&obs_refs, &[empyrean::Epoch::from_mjd_tdb(args.epoch)])
.context("failed to get observer states")?;
eprintln!(
"Observers: {} code(s) x 1 epoch(s) = {} state(s)",
args.observers.len(),
observers.len()
);
eprintln!("Generating ephemeris for {} orbit(s)...", batch.len());
let t1 = Instant::now();
let config = empyrean::EphemerisConfig::with_force_model(args.force_model.to_empyrean());
let entries = ctx
.generate_ephemeris(&batch.orbits, &observers, &config)
.context("ephemeris generation failed")?
.entries;
eprintln!("Ephemeris complete ({:.1}s)", t1.elapsed().as_secs_f64());
eprintln!("\n Output: {}/", args.out_dir.display());
output::write_ephemeris(&args.out_dir, "ephemeris", &entries, args.format)?;
eprintln!(
"\n Summary: {} orbit(s), {} observer(s), {} row(s)",
batch.len(),
args.observers.len(),
entries.len()
);
Ok(())
}