1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
use crate::errors::{DeathError, DivisionError};

use serde::{Deserialize, Serialize};

/// Contains all events which can arise during the cell cycle and need to be communciated to
/// the simulation engine (see also [Cycle]).
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum CycleEvent {
    /// A cell-event which calls the [Cycle::divide] method which will
    /// spawn an additional cell and modify the existing one.
    Division,
    /// Immediately removes the cell from the simulation domain. No function will be called.
    Remove,
    /// The cell enters a dying mode.
    /// It is still continuously updating via the [Cycle::update_conditional_phased_death] its
    /// properties but now checking if the death phase is completed.
    /// [CycleEvent::Remove] will be carried out when the condition reaches true.
    PhasedDeath,
}

/// This trait represents all cycles of a cell and works in tandem with the [CycleEvent] enum.
///
/// The `update_cycle` function is designed to be called frequently and return only something if a
/// specific cycle event is supposed to be occuring. Backends should implement
/// the functionality to call the corresponding functions as needed.
///
/// ## Stochasticity
/// In order to make sure that results are reproducible, the provided rng parameter should be used.
/// Should a user fall back to the option to use the threaded rng, this simulation cannot guarantee
/// deterministic results anymore.
/// We plan to include the stochastic aspect into individual [`Event`](CycleEvent) variants such
/// that the correct handling of integrating the underlying stochastic process can be
/// carried out by the [backend](https://docs.rs/cellular_raza-core/backend).
///
/// ## Example implementation
/// This could be an example of a very simplified cell-agent.
/// The user is free to do anything with this function that is desired but is also responsible for
/// keeping track of all the variables. This means for example that intracellular values might need
/// to be adjusted (most often halfed) and new positions need to be assigned to the cells such that
/// the cells are not overlapping ...
///
/// ```
/// use rand::Rng;
/// use rand_chacha::ChaCha8Rng;
/// use cellular_raza_concepts::{Cycle, CycleEvent, DivisionError};
///
/// // We define our cell struct with all parameters needed for this cell-agent.
/// #[derive(Clone)]
/// struct Cell {
///     // Size of the cell (spherical)
///     radius: f64,
///     // Track the age of the cell
///     current_age: f64,
///     // Used in cycle later. Divide cell if older than maximum age.
///     maximum_age: f64,
///     // The position of the cell. We cannot have two positions which are the same. Thus we need
///     // to update the position as well.
///     position: [f64; 2],
/// }
///
/// impl Cycle<Cell> for Cell {
///     fn update_cycle(rng: &mut ChaCha8Rng, dt: &f64, cell: &mut Cell) -> Option<CycleEvent> {
///         // Increase the current age of the cell
///         cell.current_age += dt;
///
///         // If the cell is older than the current age, return a division event
///         if cell.current_age > cell.maximum_age {
///             return Some(CycleEvent::Division)
///         }
///         None
///     }
///
///     fn divide(rng: &mut ChaCha8Rng, cell: &mut Cell) -> Result<Cell, DivisionError> {
///         // Prepare the original cell for division.
///         // Set the radius of both cells to half of the original radius.
///         cell.radius *= 0.5;
///
///         // Also set the current age of the cell to zero again
///         cell.current_age = 0.0;
///
///         // Clone the existing cell
///         let mut new_cell = (*cell).clone();
///
///         // Define a new position for both cells
///         // To do this: Pick a random number as an angle.
///         let angle = rng.gen_range(0.0..2.0*std::f64::consts::PI);
///
///         // Calculate the new position of the original and new cell with this angle
///         let pos = [
///             cell.radius * angle.cos(),
///             cell.radius * angle.sin()
///         ];
///         let new_pos = [
///             cell.radius * (angle+std::f64::consts::FRAC_PI_2).cos(),
///             cell.radius * (angle+std::f64::consts::FRAC_PI_2).sin()
///         ];
///
///         // Set new positions
///         cell.position = pos;
///         new_cell.position = new_pos;
///
///         // Finally return the new cell
///         return Ok(new_cell);
///     }
/// }
/// ```
pub trait Cycle<Cell = Self, Float = f64> {
    /// Continuously updates cellular properties and may spawn a [CycleEvent] which
    /// then calls the corresponding functions (see also [CycleEvent]).
    #[must_use]
    fn update_cycle(
        rng: &mut rand_chacha::ChaCha8Rng,
        dt: &Float,
        cell: &mut Cell,
    ) -> Option<CycleEvent>;

    /// Performs division of the cell by modifying the existing one and spawning an additional cell.
    /// The user is responsible for correctly adjusting cell-specific values such as intracellular
    /// concentrations or position of the two resulting cells.
    /// Corresponds to [CycleEvent::Division].
    #[must_use]
    fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut Cell) -> Result<Cell, DivisionError>;

    /// Method corresponding to the [CycleEvent::PhasedDeath] event.
    /// Update the cell while returning a boolean which indicates if the updating procedure has
    /// finished. As soon as the return value is `true` the cell is removed.
    #[allow(unused)]
    #[must_use]
    fn update_conditional_phased_death(
        rng: &mut rand_chacha::ChaCha8Rng,
        dt: &Float,
        cell: &mut Cell,
    ) -> Result<bool, DeathError> {
        Ok(true)
    }
}

#[allow(unused)]
#[doc(hidden)]
mod test_derive {
    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle;
    ///
    /// impl Cycle<MyAgent> for MyCycle {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent) -> Result<MyAgent, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f64,
    ///             cell: &mut MyAgent,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent {
    ///     #[Cycle]
    ///     cycle: MyCycle
    /// }
    /// ```
    fn derive_cycle_default() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle;
    ///
    /// impl Cycle<MyAgent, f32> for MyCycle {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent) -> Result<MyAgent, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f32,
    ///             cell: &mut MyAgent,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent {
    ///     #[Cycle]
    ///     cycle: MyCycle
    /// }
    /// ```
    fn derive_cycle_f32() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle<F> {
    ///     some_property: F,
    /// }
    ///
    /// impl<F> Cycle<MyAgent<F>, F> for MyCycle<F> {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent<F>) -> Result<MyAgent<F>, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &F,
    ///             cell: &mut MyAgent<F>,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent<F> {
    ///     #[Cycle]
    ///     cycle: MyCycle<F>
    /// }
    /// ```
    fn derive_cycle_generic_float() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle<G> {
    ///     some_property: G,
    /// }
    ///
    /// impl<G> Cycle<MyAgent<G>> for MyCycle<G>
    /// where
    ///     G: Clone
    /// {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent<G>) -> Result<MyAgent<G>, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f64,
    ///             cell: &mut MyAgent<G>,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent<G>
    /// where
    ///     G: Clone
    /// {
    ///     #[Cycle]
    ///     cycle: MyCycle<G>
    /// }
    /// ```
    fn derive_cycle_generic_float_where_clause() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle;
    ///
    /// impl Cycle<MyAgent> for MyCycle {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent) -> Result<MyAgent, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f64,
    ///             cell: &mut MyAgent,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent(
    ///     #[Cycle]
    ///     MyCycle
    /// );
    /// ```
    fn derive_cycle_unnamed() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle;
    ///
    /// impl Cycle<MyAgent, f32> for MyCycle {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent) -> Result<MyAgent, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f32,
    ///             cell: &mut MyAgent,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent(
    ///     #[Cycle]
    ///     MyCycle
    /// );
    /// ```
    fn derive_cycle_f32_unnamed() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle<F> {
    ///     some_property: F,
    /// }
    ///
    /// impl<F> Cycle<MyAgent<F>, F> for MyCycle<F> {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent<F>) -> Result<MyAgent<F>, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &F,
    ///             cell: &mut MyAgent<F>,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent<F>(
    ///     #[Cycle]
    ///     MyCycle<F>
    /// );
    /// ```
    fn derive_cycle_generic_float_unnamed() {}

    /// ```
    /// use cellular_raza_concepts::{Cycle, CycleEvent, DeathError, DivisionError, CellAgent};
    /// struct MyCycle<G> {
    ///     some_property: G,
    /// }
    ///
    /// impl<G> Cycle<MyAgent<G>> for MyCycle<G>
    /// where
    ///     G: Clone
    /// {
    ///     fn divide(rng: &mut rand_chacha::ChaCha8Rng, cell: &mut MyAgent<G>) -> Result<MyAgent<G>, DivisionError> {
    ///         panic!("This should never be called")
    ///     }
    ///
    ///     fn update_cycle(
    ///             rng: &mut rand_chacha::ChaCha8Rng,
    ///             dt: &f64,
    ///             cell: &mut MyAgent<G>,
    ///         ) -> Option<CycleEvent> {
    ///         panic!("This should never be called")
    ///     }
    /// }
    ///
    /// #[derive(CellAgent)]
    /// struct MyAgent<G>
    /// (
    ///     #[Cycle]
    ///     MyCycle<G>
    /// )
    /// where
    ///     G: Clone;
    /// ```
    fn derive_cycle_generic_float_where_clause_unnamed() {}
}