ferritin_core/columns/
frame.rs1use super::buffer::{Column, ColumnData};
4use super::error::{BoundaryError, to_u32};
5use super::gpu::{GpuBuffer, PositionLayout};
6use crate::model::Model;
7
8#[derive(Clone, Copy)]
16pub struct FrameColumns<'a> {
17 model: &'a Model,
18 n_atoms: u32,
19}
20
21impl std::fmt::Debug for FrameColumns<'_> {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 f.debug_struct("FrameColumns")
24 .field("n_atoms", &self.n_atoms)
25 .finish_non_exhaustive()
26 }
27}
28
29impl<'a> FrameColumns<'a> {
30 pub fn new(model: &'a Model) -> Result<Self, BoundaryError> {
35 let n_atoms = model.n_atoms();
36 model.conformation.validate(n_atoms)?;
37 Ok(Self {
38 model,
39 n_atoms: to_u32("atom count", n_atoms)?,
40 })
41 }
42
43 pub fn n_atoms(&self) -> u32 {
45 self.n_atoms
46 }
47
48 pub fn x(&self) -> &'a [f32] {
50 &self.model.conformation.x
51 }
52
53 pub fn y(&self) -> &'a [f32] {
55 &self.model.conformation.y
56 }
57
58 pub fn z(&self) -> &'a [f32] {
60 &self.model.conformation.z
61 }
62
63 pub fn occupancy(&self) -> Option<&'a [f32]> {
65 self.model.conformation.occupancy.as_deref()
66 }
67
68 pub fn b_iso(&self) -> Option<&'a [f32]> {
70 self.model.conformation.b_iso.as_deref()
71 }
72
73 pub fn confidence(&self) -> Option<&'a [f32]> {
75 self.model.conformation.confidence.as_deref()
76 }
77
78 pub fn columns(&self) -> Vec<Column<'a>> {
81 [
82 ("x", Some(self.x())),
83 ("y", Some(self.y())),
84 ("z", Some(self.z())),
85 ("occupancy", self.occupancy()),
86 ("b_iso", self.b_iso()),
87 ("confidence", self.confidence()),
88 ]
89 .into_iter()
90 .filter_map(|(name, values)| {
91 values.map(|values| Column {
92 name,
93 data: ColumnData::F32(values),
94 })
95 })
96 .collect()
97 }
98
99 pub fn positions(&self, layout: PositionLayout) -> GpuBuffer<'static> {
102 let components = layout.components();
103 let mut bytes = Vec::with_capacity(self.n_atoms as usize * layout.stride_bytes() as usize);
104 for ((&x, &y), &z) in self.x().iter().zip(self.y()).zip(self.z()) {
105 bytes.extend_from_slice(&x.to_le_bytes());
106 bytes.extend_from_slice(&y.to_le_bytes());
107 bytes.extend_from_slice(&z.to_le_bytes());
108 if components == 4 {
109 bytes.extend_from_slice(&1.0f32.to_le_bytes());
110 }
111 }
112 GpuBuffer {
113 label: "positions",
114 layout: layout.buffer_layout(self.n_atoms),
115 bytes: bytes.into(),
116 }
117 }
118}