blackholesfactory 0.0.2

Black hole factory — create and simulate stellar, intermediate-mass, and supermassive black holes with full Kerr physics
Documentation
use std::fs;
use std::path::Path;

pub fn write_csv(path: &str, headers: &[&str], rows: &[Vec<f64>]) -> std::io::Result<()> {
    let mut content = headers.join(",") + "\n";
    for row in rows {
        let line: Vec<String> = row.iter().map(|v| format!("{:.6e}", v)).collect();
        content += &(line.join(",") + "\n");
    }
    if let Some(parent) = Path::new(path).parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(path, content)
}

pub fn write_dat(path: &str, data: &[(f64, f64)]) -> std::io::Result<()> {
    let content: String = data
        .iter()
        .map(|(x, y)| format!("{:.6e}\t{:.6e}\n", x, y))
        .collect();
    if let Some(parent) = Path::new(path).parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(path, content)
}

pub fn ensure_dir(path: &str) -> std::io::Result<()> {
    fs::create_dir_all(path)
}

pub fn format_si(value: f64) -> String {
    let prefixes = [
        (1e24, "Y"),
        (1e21, "Z"),
        (1e18, "E"),
        (1e15, "P"),
        (1e12, "T"),
        (1e9, "G"),
        (1e6, "M"),
        (1e3, "k"),
        (1.0, ""),
        (1e-3, "m"),
        (1e-6, "µ"),
        (1e-9, "n"),
        (1e-12, "p"),
    ];
    let abs = value.abs();
    for (threshold, prefix) in prefixes {
        if abs >= threshold {
            return format!("{:.3}{}", value / threshold, prefix);
        }
    }
    format!("{:.3e}", value)
}