sim-lib-interference-core 0.1.0

Validated physical boundary types for coherent scalar wave-field studies.
Documentation
use sim_lib_interference_core::{
    Emitter, FieldAmplitude, Hertz, InterferenceError, InterferenceProblem, MetresPerSecond,
    NepersPerMetre, Point3M, PositiveMetres, Radians, RequestPreflight, SamplingPlane,
    SamplingPolicy, SamplingThresholds, ScalarMedium, SourceSet, UnitVector3, WorkBudget,
    WorkEstimate, WorkMetric,
};

fn problem() -> InterferenceProblem {
    let emitter = Emitter::ForwardPlane {
        id: "plane".to_owned(),
        through: Point3M::from_metres(0.0, 0.0, 0.0).unwrap(),
        direction: UnitVector3::new(0.0, 0.0, 1.0).unwrap(),
        amplitude: FieldAmplitude::new(1.0).unwrap(),
        phase: Radians::new(0.0).unwrap(),
    };
    InterferenceProblem::new(
        Hertz::new(1_000.0).unwrap(),
        ScalarMedium::new(
            MetresPerSecond::new(343.0).unwrap(),
            NepersPerMetre::new(0.0).unwrap(),
        ),
        SourceSet::new(vec![emitter]).unwrap(),
        PositiveMetres::new(0.001).unwrap(),
    )
}

fn plane(cells_per_axis: usize) -> SamplingPlane {
    SamplingPlane::new(
        Point3M::from_metres(0.0, 0.0, 0.0).unwrap(),
        UnitVector3::new(1.0, 0.0, 0.0).unwrap(),
        UnitVector3::new(0.0, 1.0, 0.0).unwrap(),
        PositiveMetres::new(1.0).unwrap(),
        PositiveMetres::new(1.0).unwrap(),
        cells_per_axis,
        cells_per_axis,
    )
    .unwrap()
}

#[test]
fn estimate_accounts_for_all_required_work_dimensions() {
    assert_eq!(
        WorkEstimate::new(4, 2).unwrap(),
        WorkEstimate {
            cells: 4,
            emitters: 2,
            emitter_evaluations: 8,
            host_bytes: 64,
            result_bytes: 64,
            certificate_stencil_work: 28,
        }
    );
}

#[test]
fn every_budget_field_is_enforced_with_estimate_and_limit() {
    let estimate = WorkEstimate::new(4, 2).unwrap();
    let mut budget = WorkBudget {
        max_cells: estimate.cells,
        max_emitter_evaluations: estimate.emitter_evaluations,
        max_host_bytes: estimate.host_bytes,
        max_result_bytes: estimate.result_bytes,
        max_certificate_stencil_work: estimate.certificate_stencil_work,
    };
    assert_eq!(budget.admit(&estimate), Ok(()));

    budget.max_certificate_stencil_work -= 1;
    assert_eq!(
        budget.admit(&estimate),
        Err(InterferenceError::WorkBudgetExceeded {
            metric: WorkMetric::CertificateStencilWork,
            estimate: 28,
            limit: 27,
        })
    );
}

#[test]
fn preflight_returns_sampling_and_work_evidence_before_solver_storage_exists() {
    let preflight = RequestPreflight::admit(
        &problem(),
        &plane(64),
        SamplingPolicy::Strict,
        SamplingThresholds::default(),
        WorkBudget::default(),
    )
    .unwrap();

    assert_eq!(preflight.work_estimate.cells, 4_096);
    assert_eq!(preflight.work_estimate.emitter_evaluations, 4_096);
    assert_eq!(preflight.work_estimate.result_bytes, 65_536);
}

#[test]
fn checked_estimation_rejects_arithmetic_overflow() {
    assert_eq!(
        WorkEstimate::new(u64::MAX, 2),
        Err(InterferenceError::WorkEstimateOverflow {
            metric: WorkMetric::EmitterEvaluations,
        })
    );
}