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    fn is_neighbor(&self, own_pos: &Pos, ext_pos: &Pos, ext_inf: &Inf) -> Result<bool, CalcError> {
185        self.cell.is_neighbor(own_pos, ext_pos, ext_inf)
186    }
187
188    fn react_to_neighbors(&mut self, neighbors: usize) -> Result<(), CalcError> {
189        self.cell.react_to_neighbors(neighbors)
190    }
191}
192
193impl<A, Pos> Position<Pos> for CellBox<A>
194where
195    A: Position<Pos>,
196{
197    fn pos(&self) -> Pos {
198        self.cell.pos()
199    }
200
201    fn set_pos(&mut self, pos: &Pos) {
202        self.cell.set_pos(pos)
203    }
204}
205
206impl<A, Vel> Velocity<Vel> for CellBox<A>
207where
208    A: Velocity<Vel>,
209{
210    fn velocity(&self) -> Vel {
211        self.cell.velocity()
212    }
213
214    fn set_velocity(&mut self, velocity: &Vel) {
215        self.cell.set_velocity(velocity)
216    }
217}
218
219impl<Pos, Vel, For, Float, A> Mechanics<Pos, Vel, For, Float> for CellBox<A>
220where
221    A: Mechanics<Pos, Vel, For, Float>,
222{
223    fn get_random_contribution(
224        &self,
225        rng: &mut rand_chacha::ChaCha8Rng,
226        dt: Float,
227    ) -> Result<(Pos, Vel), RngError> {
228        self.cell.get_random_contribution(rng, dt)
229    }
230
231    fn calculate_increment(&self, force: For) -> Result<(Pos, Vel), CalcError> {
232        self.cell.calculate_increment(force)
233    }
234}
235
236impl<C> core::ops::Deref for CellBox<C> {
237    type Target = C;
238
239    fn deref(&self) -> &Self::Target {
240        &self.cell
241    }
242}
243
244impl<C> core::ops::DerefMut for CellBox<C> {
245    fn deref_mut(&mut self) -> &mut Self::Target {
246        &mut self.cell
247    }
248}
249
250impl<C> CellBox<C> {
251    /// Create a new [CellBox] for a cell present initially in the simulation.
252    pub fn new_initial(n_cell: usize, cell: C) -> CellBox<C> {
253        CellBox::<C> {
254            identifier: CellIdentifier::Initial(n_cell),
255            parent: None,
256            cell,
257        }
258    }
259
260    /// Create a new [CellBox] at a specific voxel with a voxel-unique number
261    /// of cells that has already been created at this position.
262    pub fn new(
263        voxel_index: VoxelPlainIndex,
264        n_cell: u64,
265        cell: C,
266        parent: Option<CellIdentifier>,
267    ) -> CellBox<C> {
268        CellBox::<C> {
269            identifier: CellIdentifier::Division(voxel_index, n_cell),
270            parent,
271            cell,
272        }
273    }
274}
275
276#[doc(inline)]
277pub use cellular_raza_concepts_derive::CellAgent;