sciforge 0.0.3

A comprehensive scientific computing library in pure Rust with zero dependencies
Documentation
pub fn bcf_ratio(c_organism: f64, c_water: f64) -> f64 {
    c_organism / c_water.max(1e-30)
}

pub fn bioaccumulation_factor(c_organism: f64, c_environment: f64) -> f64 {
    c_organism / c_environment.max(1e-30)
}

pub fn biomagnification_factor(c_predator: f64, c_prey: f64) -> f64 {
    c_predator / c_prey.max(1e-30)
}

pub fn one_compartment_toxicokinetics(
    c0: f64,
    k_uptake: f64,
    k_elim: f64,
    c_exposure: f64,
    dt: f64,
    steps: usize,
) -> Vec<f64> {
    let mut result = Vec::with_capacity(steps + 1);
    let mut c = c0;
    result.push(c);
    for _ in 0..steps {
        let dc = k_uptake * c_exposure - k_elim * c;
        c = (c + dc * dt).max(0.0);
        result.push(c);
    }
    result
}

pub fn depuration_half_life(k_elim: f64) -> f64 {
    (2.0_f64).ln() / k_elim
}

pub fn toxic_units(concentration: f64, ec50: f64) -> f64 {
    concentration / ec50
}

pub fn mixture_toxicity_concentration_addition(concentrations: &[f64], ec50s: &[f64]) -> f64 {
    let n = concentrations.len().min(ec50s.len());
    let mut sum_tu = 0.0;
    for i in 0..n {
        sum_tu += concentrations[i] / ec50s[i].max(1e-30);
    }
    sum_tu
}

pub fn haber_ct_product(concentration: f64, time: f64) -> f64 {
    concentration * time
}

pub fn risk_quotient(
    predicted_environmental_concentration: f64,
    predicted_no_effect_concentration: f64,
) -> f64 {
    predicted_environmental_concentration / predicted_no_effect_concentration.max(1e-30)
}

pub fn trophic_magnification_factor(concentrations: &[f64], trophic_levels: &[f64]) -> f64 {
    let n = concentrations.len().min(trophic_levels.len());
    if n < 2 {
        return 1.0;
    }
    let log_c: Vec<f64> = concentrations.iter().map(|&c| c.max(1e-30).ln()).collect();
    let x_mean = trophic_levels.iter().take(n).sum::<f64>() / n as f64;
    let y_mean = log_c.iter().take(n).sum::<f64>() / n as f64;
    let mut num = 0.0;
    let mut den = 0.0;
    for i in 0..n {
        let dx = trophic_levels[i] - x_mean;
        num += dx * (log_c[i] - y_mean);
        den += dx * dx;
    }
    if den < 1e-30 {
        return 1.0;
    }
    (num / den).exp()
}

pub fn two_compartment_toxicokinetics(
    c_fast: f64,
    c_slow: f64,
    k12: f64,
    k21: f64,
    k_elim: f64,
    k_uptake: f64,
    c_exposure: f64,
    dt: f64,
) -> (f64, f64) {
    let dc_fast = k_uptake * c_exposure - k_elim * c_fast - k12 * c_fast + k21 * c_slow;
    let dc_slow = k12 * c_fast - k21 * c_slow;
    (
        (c_fast + dc_fast * dt).max(0.0),
        (c_slow + dc_slow * dt).max(0.0),
    )
}

pub fn steady_state_body_burden(k_uptake: f64, c_exposure: f64, k_elim: f64) -> f64 {
    k_uptake * c_exposure / k_elim
}

pub fn biota_sediment_accumulation_factor(c_organism: f64, c_sediment: f64) -> f64 {
    c_organism / c_sediment.max(1e-30)
}

pub fn lipid_normalized_concentration(c_tissue: f64, lipid_fraction: f64) -> f64 {
    c_tissue / lipid_fraction.max(1e-30)
}

pub fn fugacity_ratio(c_organism: f64, c_environment: f64, k_ow: f64) -> f64 {
    c_organism / (k_ow * c_environment).max(1e-30)
}

pub fn elimination_rate_from_depuration(c_start: f64, c_end: f64, time: f64) -> f64 {
    if time <= 0.0 {
        return 0.0;
    }
    (c_start / c_end.max(1e-30)).ln() / time
}

pub fn critical_body_residue(lc50: f64, bcf: f64) -> f64 {
    lc50 * bcf
}

pub fn dietary_uptake_efficiency(assimilation: f64, feeding_rate: f64, body_weight: f64) -> f64 {
    assimilation * feeding_rate / body_weight.max(1e-30)
}