use crate::alpha16::{Adc32ChannelId, BoardId};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::f64::consts::PI;
use thiserror::Error;
pub const ANODE_WIRES_RADIUS: f64 = 0.182;
pub const INNER_CATHODE_RADIUS: f64 = 0.1092;
pub const TPC_ANODE_WIRES: usize = 256;
pub const ANODE_WIRE_PITCH_PHI: f64 = 2.0 * PI / (TPC_ANODE_WIRES as f64);
const PREAMPS_2941: [(&str, (usize, usize)); 8] = [
("09", (0, 1)),
("10", (2, 3)),
("11", (4, 5)),
("12", (6, 7)),
("13", (8, 9)),
("14", (10, 11)),
("18", (12, 13)),
("16", (14, 15)),
];
fn preamps_map(map: [(&str, (usize, usize)); 8]) -> HashMap<BoardId, (usize, usize)> {
let mut m = HashMap::new();
for (board_name, preamps) in map.iter() {
m.insert(BoardId::try_from(*board_name).unwrap(), *preamps);
}
m
}
lazy_static! {
static ref PREAMPS_MAP_2941: HashMap<BoardId, (usize, usize)> = preamps_map(PREAMPS_2941);
}
const INV_CHANNELS_2724: [usize; 32] = [
4, 2, 0, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15, 16, 18, 20, 22, 24, 26, 28, 30, 17, 19,
21, 23, 25, 27, 29, 31,
];
#[derive(Debug, Error)]
pub enum MapTpcWirePositionError {
#[error("no rTPC preamp mapping available for run number {run_number}")]
MissingPreampMap { run_number: u32 },
#[error("alpha16 `{}` not found in map for run number {run_number}", board_id.name())]
BoardIdNotFound { board_id: BoardId, run_number: u32 },
#[error("no rTPC wire mapping available for run number {run_number}")]
MissingWireMap { run_number: u32 },
}
#[derive(Debug, Error)]
#[error("unknown conversion from {input} to anode wire position")]
pub struct TryTpcWirePositionFromIndexError {
input: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(try_from = "usize", into = "usize")]
pub struct TpcWirePosition(usize);
impl TryFrom<usize> for TpcWirePosition {
type Error = TryTpcWirePositionFromIndexError;
fn try_from(input: usize) -> Result<Self, Self::Error> {
if input < TPC_ANODE_WIRES {
Ok(Self(input))
} else {
Err(Self::Error { input })
}
}
}
impl From<TpcWirePosition> for usize {
fn from(wire: TpcWirePosition) -> Self {
wire.0
}
}
impl TpcWirePosition {
pub fn try_new(
run_number: u32,
board_id: BoardId,
channel_id: Adc32ChannelId,
) -> Result<Self, MapTpcWirePositionError> {
let preamp_map = match run_number {
u32::MAX => &PREAMPS_MAP_2941,
2941.. => &PREAMPS_MAP_2941,
_ => return Err(MapTpcWirePositionError::MissingPreampMap { run_number }),
};
let channel_map = match run_number {
u32::MAX => &INV_CHANNELS_2724,
2724.. => &INV_CHANNELS_2724,
_ => return Err(MapTpcWirePositionError::MissingWireMap { run_number }),
};
let (preamp_1, preamp_2) =
preamp_map
.get(&board_id)
.ok_or(MapTpcWirePositionError::BoardIdNotFound {
board_id,
run_number,
})?;
let mapped_channel = channel_map[usize::from(channel_id.0)];
let wire_position = match mapped_channel {
0..=15 => preamp_1 * 16 + mapped_channel,
16..=31 => preamp_2 * 16 + (mapped_channel - 16),
_ => unreachable!(),
};
Ok(Self(wire_position))
}
pub fn phi(&self) -> f64 {
let shifted_index = self.0.wrapping_sub(8) & 0xff;
ANODE_WIRE_PITCH_PHI * (shifted_index as f64 + 0.5)
}
}
#[cfg(test)]
mod tests;