1mod drive;
2mod emit_intensity;
3mod error;
4mod phase;
5
6use std::collections::HashMap;
7
8pub use drive::Drive;
9pub use emit_intensity::Intensity;
10pub use error::GainError;
11pub use phase::Phase;
12
13use crate::{
14 datagram::{DeviceFilter, Segment, TransitionMode},
15 environment::Environment,
16 geometry::{Device, Geometry, Transducer},
17};
18
19#[derive(Debug)]
20pub struct TransducerFilter(Option<HashMap<usize, Option<bit_vec::BitVec<u32>>>>);
22
23impl TransducerFilter {
24 #[doc(hidden)]
25 pub const fn new(filter: HashMap<usize, Option<bit_vec::BitVec<u32>>>) -> Self {
26 Self(Some(filter))
27 }
28
29 pub const fn all_enabled() -> Self {
31 Self(None)
32 }
33
34 pub fn from_fn<FT: Fn(&Transducer) -> bool>(
36 geo: &Geometry,
37 f: impl Fn(&Device) -> Option<FT>,
38 ) -> Self {
39 Self(Some(HashMap::from_iter(geo.iter().filter_map(|dev| {
40 f(dev).map(|f| {
41 (
42 dev.idx(),
43 Some(bit_vec::BitVec::from_fn(dev.num_transducers(), |idx| {
44 f(&dev[idx])
45 })),
46 )
47 })
48 }))))
49 }
50
51 pub const fn is_all_enabled(&self) -> bool {
53 self.0.is_none()
54 }
55
56 pub fn is_enabled_device(&self, dev: &Device) -> bool {
58 self.0.as_ref().is_none_or(|f| f.contains_key(&dev.idx()))
59 }
60
61 pub fn is_enabled(&self, tr: &Transducer) -> bool {
63 self.0.as_ref().is_none_or(|f| {
64 f.get(&tr.dev_idx())
65 .map(|f| f.as_ref().map(|f| f[tr.idx()]).unwrap_or(true))
66 .unwrap_or(false)
67 })
68 }
69
70 pub fn num_enabled_devices(&self, geometry: &Geometry) -> usize {
72 self.0.as_ref().map_or(geometry.num_devices(), |f| {
73 geometry
74 .iter()
75 .filter(|dev| f.contains_key(&dev.idx()))
76 .count()
77 })
78 }
79
80 pub fn num_enabled_transducers(&self, dev: &Device) -> usize {
82 self.0.as_ref().map_or(dev.num_transducers(), |f| {
83 f.get(&dev.idx()).map_or(0, |filter| {
84 filter
85 .as_ref()
86 .map_or(dev.num_transducers(), |f| f.count_ones() as usize)
87 })
88 })
89 }
90}
91
92impl From<&DeviceFilter> for TransducerFilter {
93 fn from(filter: &DeviceFilter) -> Self {
94 if let Some(filter) = filter.0.as_ref() {
95 Self(Some(
96 filter
97 .iter()
98 .enumerate()
99 .filter_map(|(idx, enable)| enable.then_some((idx, None)))
100 .collect(),
101 ))
102 } else {
103 Self(None)
104 }
105 }
106}
107
108pub trait GainCalculator: Send + Sync {
112 #[must_use]
114 fn calc(&self, tr: &Transducer) -> Drive;
115}
116
117impl GainCalculator for Box<dyn GainCalculator> {
118 fn calc(&self, tr: &Transducer) -> Drive {
119 self.as_ref().calc(tr)
120 }
121}
122
123pub trait GainCalculatorGenerator {
125 type Calculator: GainCalculator;
127
128 #[must_use]
130 fn generate(&mut self, device: &Device) -> Self::Calculator;
131}
132
133pub trait Gain: std::fmt::Debug + Sized {
139 type G: GainCalculatorGenerator;
141
142 fn init(
147 self,
148 geometry: &Geometry,
149 env: &Environment,
150 filter: &TransducerFilter,
151 ) -> Result<Self::G, GainError>;
152}
153
154#[doc(hidden)]
155pub struct GainOperationGenerator<G> {
156 pub generator: G,
157 pub segment: Segment,
158 pub transition: Option<TransitionMode>,
159}
160
161impl<G: GainCalculatorGenerator> GainOperationGenerator<G> {
162 pub fn new<T: Gain<G = G>>(
163 gain: T,
164 geometry: &Geometry,
165 env: &Environment,
166 filter: &DeviceFilter,
167 segment: Segment,
168 transition: Option<TransitionMode>,
169 ) -> Result<Self, GainError> {
170 Ok(Self {
171 generator: gain.init(geometry, env, &TransducerFilter::from(filter))?,
172 segment,
173 transition,
174 })
175 }
176}
177
178#[derive(Debug, Clone, PartialEq)]
179pub struct GainInspectionResult {
181 pub name: String,
183 pub data: Vec<Drive>,
185 pub segment: Segment,
187 pub transition_mode: Option<TransitionMode>,
189}