Files
nrlmsise00/benches/density.rs
T

94 lines
3.5 KiB
Rust

//! What an evaluation costs.
//!
//! The altitudes are chosen for the paths they take, not for being round: above 72.5 km
//! the model is the thermosphere alone, below it the mesosphere splines are built on top of
//! a thermosphere evaluation at 72.5 km, and below 32.5 km a second set of splines is built
//! on top of that. The three cost noticeably different amounts.
//!
//! The dual-number cases are the reason the crate exists, so they are measured alongside:
//! one seeded input gives the altitude partial, three give the position gradient a drag
//! calculation wants.
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use nrlmsise00::{Input, MagneticActivity, Model, Scalar};
use num_dual::{Dual64, DualSVec64};
use std::hint::black_box;
/// The baseline of the reference's published cases, at an altitude of the caller's choice.
fn input<T: Scalar>(altitude_km: T) -> Input<T> {
Input {
day_of_year: 172,
seconds_of_day: T::lift(29000.0),
altitude_km,
latitude_deg: T::lift(60.0),
longitude_deg: T::lift(-70.0),
local_solar_time_h: T::lift(16.0),
f107_average: T::lift(150.0),
f107: T::lift(150.0),
magnetic: MagneticActivity::History {
ap: [100.0; 7].map(T::lift),
},
}
}
/// An altitude in each of the model's three vertical regions, and one in the exosphere.
const ALTITUDES: [(&str, f64); 4] = [
("20 km, three splines", 20.0),
("50 km, two splines", 50.0),
("400 km, thermosphere", 400.0),
("1000 km, exosphere", 1000.0),
];
fn gtd7d(c: &mut Criterion) {
let model = Model::new();
let mut group = c.benchmark_group("gtd7d");
for (name, altitude) in ALTITUDES {
group.bench_with_input(BenchmarkId::new("f64", name), &altitude, |b, altitude| {
b.iter(|| model.gtd7d(black_box(&input(*altitude))));
});
}
group.finish();
}
fn derivatives(c: &mut Criterion) {
let model = Model::new();
let mut group = c.benchmark_group("gtd7d with derivatives");
for (name, altitude) in ALTITUDES {
// One partial: the altitude derivative a scale height comes from.
group.bench_with_input(
BenchmarkId::new("one partial", name),
&altitude,
|b, altitude| {
let seeded = Dual64::from(*altitude).derivative();
b.iter(|| model.gtd7d(black_box(&input(seeded))));
},
);
// Three at once: the position gradient, which is what a drag partial needs.
group.bench_with_input(
BenchmarkId::new("three partials", name),
&altitude,
|b, altitude| {
// Seeded in the first of three slots, as a position gradient would be.
let seeded = DualSVec64::<3>::from(*altitude).derivative(0);
b.iter(|| model.gtd7d(black_box(&input(seeded))));
},
);
}
group.finish();
}
/// The two entry points, to show that the drag total costs nothing extra.
fn entry_points(c: &mut Criterion) {
let model = Model::new();
let mut group = c.benchmark_group("entry points at 400 km");
group.bench_function("gtd7", |b| b.iter(|| model.gtd7(black_box(&input(400.0)))));
group.bench_function("gtd7d", |b| {
b.iter(|| model.gtd7d(black_box(&input(400.0))))
});
group.bench_function("gts7", |b| b.iter(|| model.gts7(black_box(&input(400.0)))));
group.finish();
}
criterion_group!(benches, gtd7d, derivatives, entry_points);
criterion_main!(benches);