cellular_raza_concepts/
cell.rs

1use crate::domain::VoxelPlainIndex;
2use crate::errors::{CalcError, RngError};
3use crate::interaction::*;
4use crate::mechanics::{Mechanics, Position, Velocity};
5
6use serde::{Deserialize, Serialize};
7
8// TODO move this module to cpu_os_threads backend except for traits
9
10/// Unique identifier which is given to every cell in the simulation
11///
12/// The identifier is comprised of the [VoxelPlainIndex] in which the cell was first spawned.
13/// This can be due to initial setup or due to other methods such as division in a cell cycle.
14/// The second parameter is a counter which is unique for each voxel.
15/// This ensures that each cell obtains a unique identifier over the course of the simulation.
16#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
17#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize)]
18pub enum CellIdentifier {
19    /// Produced from a division process
20    Division(VoxelPlainIndex, u64),
21    /// Initially placed inside the simulation
22    Initial(usize),
23    /// Inserted manually by other processes
24    Inserted(VoxelPlainIndex, u64),
25}
26
27#[cfg(feature = "pyo3")]
28#[pyo3::pymethods]
29impl CellIdentifier {
30    /// Constructs a new [CellIdentifier::Division]
31    #[new]
32    pub fn new(voxel_plain_index: VoxelPlainIndex, counter: u64) -> Self {
33        CellIdentifier::Division(voxel_plain_index, counter)
34    }
35
36    /// Construct a new [CellIdentifier::Initial]
37    #[staticmethod]
38    pub fn new_initial(index: usize) -> Self {
39        CellIdentifier::Initial(index)
40    }
41
42    /// Construct a new [CellIdentifier::Inserted]
43    #[staticmethod]
44    pub fn new_inserted(voxel_plain_index: VoxelPlainIndex, counter: u64) -> Self {
45        Self::Inserted(voxel_plain_index, counter)
46    }
47
48    /// Returns an identical clone of the identifier
49    pub fn __deepcopy__(&self, _memo: pyo3::Bound<pyo3::types::PyDict>) -> Self {
50        *self
51    }
52
53    /// Returns an identical clone of the identifier
54    pub fn copy(&self) -> Self {
55        *self
56    }
57
58    /// Returns an identical clone of the identifier
59    pub fn __copy__(&self) -> Self {
60        *self
61    }
62
63    /// Formats the CellIdentifier
64    pub fn __repr__(&self) -> String {
65        format!("{:?}", self)
66    }
67
68    /// Performs the `==` operation.
69    pub fn __eq__(&self, other: &Self) -> bool {
70        self.eq(other)
71    }
72
73    /// Calculates a hash value of type `u64`
74    pub fn __hash__(&self) -> u64 {
75        use core::hash::{Hash, Hasher};
76        let mut hasher = std::collections::hash_map::DefaultHasher::new();
77        self.hash(&mut hasher);
78        hasher.finish()
79    }
80
81    ///  Performs the `<` operation
82    pub fn __lt__(&self, other: &Self) -> bool {
83        self.lt(other)
84    }
85
86    /// Implementes the `__getitem__` method. Since the [CellIdentifier] is built like a list this
87    /// only works for the entires 0 and 1 and will yield an error otherwise
88    pub fn __getitem__<'py>(
89        &self,
90        py: pyo3::Python<'py>,
91        key: usize,
92    ) -> pyo3::PyResult<pyo3::Bound<'py, pyo3::PyAny>> {
93        use pyo3::IntoPyObject;
94        let (key0, key1) = match self {
95            CellIdentifier::Initial(key0) => (*key0, None),
96            CellIdentifier::Division(key0, key1) => (key0.0, Some(*key1)),
97            CellIdentifier::Inserted(key0, key1) => (key0.0, Some(*key1)),
98        };
99        if key == 0 {
100            Ok(key0.into_pyobject(py)?.into_any())
101        } else if key == 1 {
102            Ok(key1.into_pyobject(py)?.into_any())
103        } else {
104            Err(pyo3::exceptions::PyValueError::new_err(
105                "CellIdentifier can only be indexed at 0 and 1",
106            ))
107        }
108    }
109}
110
111/// Specifies how to retrieve a unique identifier of an object.
112pub trait Id {
113    /// The identifier type is usually chosen to be completely unique and repeatable across
114    /// different simulations.
115    type Identifier;
116
117    /// Retrieves the Identifier from the object.
118    fn get_id(&self) -> Self::Identifier;
119    /// Returns a reference to the id of the object.
120    fn ref_id(&self) -> &Self::Identifier;
121}
122
123/// Wrapper around the user-defined CellAgent
124///
125/// This wrapper serves to provide a unique identifier and the option to specify
126/// the parent of the current cell.
127#[derive(Clone, Deserialize, Serialize)]
128pub struct CellBox<C> {
129    /// The identifier is composed of two values, one for the voxel index in which the
130    /// object was created and another one which counts how many elements have already
131    /// been created there.
132    pub identifier: CellIdentifier,
133    /// Identifier of the parent cell if this cell was created by cell-division
134    pub parent: Option<CellIdentifier>,
135    /// The cell which is encapsulated by this box.
136    pub cell: C,
137}
138
139impl<Cel> Id for CellBox<Cel> {
140    type Identifier = CellIdentifier;
141
142    fn get_id(&self) -> CellIdentifier {
143        self.identifier
144    }
145
146    fn ref_id(&self) -> &CellIdentifier {
147        &self.identifier
148    }
149}
150
151impl<Cel> CellBox<Cel> {
152    /// Simple method to retrieve the [CellularIdentifier] of the parent cell if existing.
153    pub fn get_parent_id(&self) -> Option<CellIdentifier> {
154        self.parent
155    }
156}
157
158impl<Inf, A> InteractionInformation<Inf> for CellBox<A>
159where
160    A: InteractionInformation<Inf>,
161{
162    fn get_interaction_information(&self) -> Inf {
163        self.cell.get_interaction_information()
164    }
165}
166
167// Auto-implement traits for CellAgentBox which where also implemented for Agent
168impl<Pos, Vel, For, Inf, A> Interaction<Pos, Vel, For, Inf> for CellBox<A>
169where
170    A: Interaction<Pos, Vel, For, Inf> + Serialize + for<'a> Deserialize<'a>,
171{
172    fn calculate_force_between(
173        &self,
174        own_pos: &Pos,
175        own_vel: &Vel,
176        ext_pos: &Pos,
177        ext_vel: &Vel,
178        ext_information: &Inf,
179    ) -> Result<(For, For), CalcError> {
180        self.cell
181            .calculate_force_between(own_pos, own_vel, ext_pos, ext_vel, ext_information)
182    }
183}
184
185impl<A, Pos> Position<Pos> for CellBox<A>
186where
187    A: Position<Pos>,
188{
189    fn pos(&self) -> Pos {
190        self.cell.pos()
191    }
192
193    fn set_pos(&mut self, pos: &Pos) {
194        self.cell.set_pos(pos)
195    }
196}
197
198impl<A, Vel> Velocity<Vel> for CellBox<A>
199where
200    A: Velocity<Vel>,
201{
202    fn velocity(&self) -> Vel {
203        self.cell.velocity()
204    }
205
206    fn set_velocity(&mut self, velocity: &Vel) {
207        self.cell.set_velocity(velocity)
208    }
209}
210
211impl<Pos, Vel, For, Float, A> Mechanics<Pos, Vel, For, Float> for CellBox<A>
212where
213    A: Mechanics<Pos, Vel, For, Float>,
214{
215    fn get_random_contribution(
216        &self,
217        rng: &mut rand_chacha::ChaCha8Rng,
218        dt: Float,
219    ) -> Result<(Pos, Vel), RngError> {
220        self.cell.get_random_contribution(rng, dt)
221    }
222
223    fn calculate_increment(&self, force: For) -> Result<(Pos, Vel), CalcError> {
224        self.cell.calculate_increment(force)
225    }
226}
227
228impl<C> core::ops::Deref for CellBox<C> {
229    type Target = C;
230
231    fn deref(&self) -> &Self::Target {
232        &self.cell
233    }
234}
235
236impl<C> core::ops::DerefMut for CellBox<C> {
237    fn deref_mut(&mut self) -> &mut Self::Target {
238        &mut self.cell
239    }
240}
241
242impl<C> CellBox<C> {
243    /// Create a new [CellBox] for a cell present initially in the simulation.
244    pub fn new_initial(n_cell: usize, cell: C) -> CellBox<C> {
245        CellBox::<C> {
246            identifier: CellIdentifier::Initial(n_cell),
247            parent: None,
248            cell,
249        }
250    }
251
252    /// Create a new [CellBox] at a specific voxel with a voxel-unique number
253    /// of cells that has already been created at this position.
254    pub fn new(
255        voxel_index: VoxelPlainIndex,
256        n_cell: u64,
257        cell: C,
258        parent: Option<CellIdentifier>,
259    ) -> CellBox<C> {
260        CellBox::<C> {
261            identifier: CellIdentifier::Division(voxel_index, n_cell),
262            parent,
263            cell,
264        }
265    }
266}
267
268#[doc(inline)]
269pub use cellular_raza_concepts_derive::CellAgent;