Skip to main content

sva_samples/physics/
mod.rs

1// Concern: names the six finite-difference models, opens one solver, and holds the ceiling and the drive each shared by two | Non-concern: a model's own grid (the siblings) | IO: (Params) -> a Solver
2
3pub mod botteldooren;
4pub mod bound;
5pub mod chaigne_askenfelt;
6pub mod chaigne_doutaut;
7pub mod darabundit_scavone;
8pub mod hammer;
9pub mod rhaouti_chaigne_joly;
10pub mod tonehole;
11pub mod willemsen_bilbao_serafin;
12
13use crate::error::SampleError;
14
15use botteldooren::{BotteldoorenParams, BotteldoorenSite};
16use chaigne_askenfelt::{ChaigneAskenfeltParams, ChaigneAskenfeltSite};
17use chaigne_doutaut::{ChaigneDoutautParams, ChaigneDoutautSite};
18use darabundit_scavone::{BoreParams, BoreSite};
19use rhaouti_chaigne_joly::{RhaoutiChaigneJolyParams, RhaoutiChaigneJolySite};
20use willemsen_bilbao_serafin::{WillemsenBilbaoSerafinParams, WillemsenBilbaoSerafinSite};
21
22/// One sample per call. The derivative half of the old pair died with the lanes.
23pub trait Solver {
24    fn step(&mut self) -> f64;
25}
26
27#[derive(Clone, Debug, PartialEq)]
28pub enum Params {
29    ChaigneAskenfelt(ChaigneAskenfeltParams),
30    WillemsenBilbaoSerafin(WillemsenBilbaoSerafinParams),
31    DarabunditScavone(BoreParams),
32    RhaoutiChaigneJoly(RhaoutiChaigneJolyParams),
33    ChaigneDoutaut(ChaigneDoutautParams),
34    Botteldooren(BotteldoorenParams),
35}
36
37impl Params {
38    pub fn name(&self) -> &'static str {
39        match self {
40            Params::ChaigneAskenfelt(_) => "chaigne_askenfelt",
41            Params::WillemsenBilbaoSerafin(_) => "willemsen_bilbao_serafin",
42            Params::DarabunditScavone(_) => "darabundit_scavone",
43            Params::RhaoutiChaigneJoly(_) => "rhaouti_chaigne_joly",
44            Params::ChaigneDoutaut(_) => "chaigne_doutaut",
45            Params::Botteldooren(_) => "botteldooren",
46        }
47    }
48
49    pub fn valid(&self) -> bool {
50        match self {
51            Params::ChaigneAskenfelt(p) => p.valid(),
52            Params::WillemsenBilbaoSerafin(p) => p.valid(),
53            Params::DarabunditScavone(p) => p.valid(),
54            Params::RhaoutiChaigneJoly(p) => p.valid(),
55            Params::ChaigneDoutaut(p) => p.valid(),
56            Params::Botteldooren(p) => p.valid(),
57        }
58    }
59}
60
61/// One grid, sized at the observation's rate; nothing here reads a sample back. A size only
62/// the rate decides is checked here, where the rate is known — `valid()` never sees one.
63pub fn site(p: &Params, rate: u32) -> Result<Box<dyn Solver>, SampleError> {
64    let sr = f64::from(rate);
65    Ok(match p {
66        Params::ChaigneAskenfelt(p) => Box::new(ChaigneAskenfeltSite::new(p, sr)?),
67        Params::WillemsenBilbaoSerafin(p) => Box::new(WillemsenBilbaoSerafinSite::new(p, sr)),
68        Params::DarabunditScavone(p) => Box::new(BoreSite::new(p, sr)),
69        Params::RhaoutiChaigneJoly(p) => {
70            under_ceiling(
71                "rhaouti_chaigne_joly",
72                rhaouti_chaigne_joly::node_count(p, sr),
73                rhaouti_chaigne_joly::NODE_COUNT_CEILING,
74            )?;
75            Box::new(RhaoutiChaigneJolySite::new(p, sr))
76        }
77        Params::ChaigneDoutaut(p) => Box::new(ChaigneDoutautSite::new(p, sr)),
78        Params::Botteldooren(p) => {
79            under_ceiling(
80                "botteldooren",
81                botteldooren::node_count(p.f0, p.aspect_y, p.aspect_z, sr),
82                botteldooren::NODE_COUNT_CEILING,
83            )?;
84            Box::new(BotteldoorenSite::new(p, sr))
85        }
86    })
87}
88
89fn under_ceiling(model: &'static str, nodes: f64, ceiling: usize) -> Result<(), SampleError> {
90    match nodes > ceiling as f64 {
91        true => Err(SampleError::GridTooLarge {
92            model,
93            nodes: nodes as usize,
94            ceiling,
95        }),
96        false => Ok(()),
97    }
98}
99
100/// The raised-cosine pressure pulse the room and the bore are driven by: one half-turn over
101/// `width` seconds and silence after, so the drive starts and ends at rest.
102pub(crate) fn raised_cosine_pulse(t: f64, amp: f64, width: f64) -> f64 {
103    match t < width {
104        true => amp * 0.5 * (1.0 - (std::f64::consts::TAU * t / width).cos()),
105        false => 0.0,
106    }
107}