use rexafs::rmc::*;
use rexafs::structure::{BuiltinLibrary, Edge};
use serde_json::json;
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let out = std::env::args()
.nth(1)
.ok_or("supply a new output JSON path")?;
let mut file = std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(out)?;
let library = BuiltinLibrary::get()?;
let c = Configuration::from_structure(&library.structure("cu2o_cuprite")?, [2, 2, 2])?;
let absorber = c.atoms.iter().position(|a| a.atomic_number == 29).unwrap();
let k: Vec<_> = (0..191).map(|i| 2.5 + i as f64 * 0.05).collect();
let options = RefeffOptions {
path_radius: 4.5,
path_criteria: [0., 0.],
..Default::default()
};
let acceleration = AccelerationSettings {
catalogue: PathCatalogueSettings {
radius: 4.5,
max_legs: 4,
displacement: 0.4,
..Default::default()
},
basis: ScatteringBasis::Frozen {
max_leg_change: 0.1,
max_angle_change: 0.2,
},
..Default::default()
};
let mut fast =
PreparedRefeffCalculator::new(options.clone(), vec![c.clone()], acceleration.clone())?;
let start = Instant::now();
let initial = fast.calculate(&c, absorber, Edge::K, &k)?;
let setup_seconds = start.elapsed().as_secs_f64();
let mut changed = c.clone();
let oxygen = fast
.catalogue(CalculationRequest {
structure: 0,
configuration: &c,
absorber,
edge: Edge::K,
k: &k,
options: None,
paths: false,
})?
.paths()
.iter()
.filter(|p| p.scatterers.len() == 1 && c.atoms[p.scatterers[0].atom].atomic_number == 8)
.min_by(|a, b| {
a.half_length(&c)
.unwrap()
.total_cmp(&b.half_length(&c).unwrap())
})
.unwrap()
.scatterers[0]
.atom;
changed.atoms[oxygen].position[0] += 0.025;
changed.atoms[oxygen].position[1] -= 0.012;
let start = Instant::now();
let updated = fast.calculate(&changed, absorber, Edge::K, &k)?;
let update_seconds = start.elapsed().as_secs_f64();
let fast_stats = fast.stats();
let start = Instant::now();
let agreement = fast.compare_reference(CalculationRequest {
structure: 0,
configuration: &changed,
absorber,
edge: Edge::K,
k: &k,
options: None,
paths: false,
})?;
let exact_seconds = start.elapsed().as_secs_f64();
let mut baseline =
RefeffCalculator::new(options.clone())?.with_frozen_potentials(vec![c.clone()])?;
let start = Instant::now();
let pipeline_initial = baseline.calculate(&c, absorber, Edge::K, &k)?;
let pipeline_setup_seconds = start.elapsed().as_secs_f64();
let start = Instant::now();
let pipeline_updated = baseline.calculate(&changed, absorber, Edge::K, &k)?;
let pipeline_update_seconds = start.elapsed().as_secs_f64();
let compare = |a: &[f64], b: &[f64]| {
(a.iter().zip(b).map(|(x, y)| (x - y).powi(2)).sum::<f64>()
/ b.iter().map(|x| x * x).sum::<f64>())
.sqrt()
};
let report = json!({"reference":c,"changed":changed,"absorber":absorber,"moved_atom":oxygen,"options":options,"acceleration":acceleration,
"k":k,"initial":initial,"updated":updated,"pipeline_initial":pipeline_initial,"pipeline_updated":pipeline_updated,
"basis_accuracy":agreement,"typed_vs_pipeline_relative_l2":compare(&agreement.reference,&pipeline_updated),
"initial_vs_pipeline_relative_l2":compare(&initial,&pipeline_initial),
"setup_seconds":setup_seconds,"update_seconds":update_seconds,"direct_typed_check_seconds":exact_seconds,
"pipeline_setup_seconds":pipeline_setup_seconds,"pipeline_update_seconds":pipeline_update_seconds,
"warm_speed_ratio":pipeline_update_seconds/update_seconds,"prepared_stats":fast_stats,"pipeline_stats":baseline.stats(),
"note":"One absorber, one local move; no EVAX timing and no inference of end-to-end RMC speed or experimental accuracy."});
serde_json::to_writer_pretty(&mut file, &report)?;
println!("prepared setup {setup_seconds:.3} s; update {update_seconds:.6} s; pinned pipeline update {pipeline_update_seconds:.6} s");
println!(
"basis relative L2 {:?}; typed vs pipeline {:.6}",
agreement.relative_l2,
compare(&agreement.reference, &pipeline_updated)
);
Ok(())
}