cellular_raza_core/backend/chili/mod.rs
1//! 🌶️ A modular, reusable, general-purpose backend
2//!
3//! # Usage
4//!
5//! In the following example, we provide an extremely short basic usage of the [run_simulation]
6//! macro.
7//! It performs the numerical integration of a well-defined problem.
8//! We assume that the `MyAgent` struct and `MyDomain` have already been defined and implement the
9//! [Mechanics](cellular_raza_concepts::Mechanics) concept.
10//! More details about how to use pre-existing building blocks or derive their functionality is
11//! provided by the
12//! [cellular_raza_building_blocks](https://cellular-raza.com/docs/cellular_raza_building_blocks)
13//! crate.
14//! We will then solve our system for the
15//! [`Mechanics`](https://cellular-raza.com/internals/concepts/cell/mechanics) aspect.
16//!
17//! ```
18//! # use cellular_raza_core::backend::chili::*;
19//! # use cellular_raza_core::{storage::*, time::*};
20//! # use cellular_raza_concepts::*;
21//! # use rand_chacha::ChaCha8Rng;
22//! # use serde::{Deserialize, Serialize};
23//! # use std::collections::{BTreeMap, BTreeSet};
24//! # // Define agents and domain
25//! # #[derive(Clone, Debug, Deserialize, Serialize)]
26//! # struct MyAgent {
27//! # pos: f64,
28//! # vel: f64
29//! # }
30//! # impl Position<f64> for MyAgent {
31//! # fn pos(&self) -> f64 {
32//! # self.pos
33//! # }
34//! # fn set_pos(&mut self, pos: &f64) {
35//! # self.pos = *pos
36//! # }
37//! # }
38//! # impl Velocity<f64> for MyAgent {
39//! # fn velocity(&self) -> f64 {
40//! # self.vel
41//! # }
42//! # fn set_velocity(&mut self, vel: &f64) {
43//! # self.vel = *vel
44//! # }
45//! # }
46//! # impl Mechanics<f64, f64, f64> for MyAgent {
47//! # fn get_random_contribution(
48//! # &self,
49//! # _rng: &mut ChaCha8Rng,
50//! # _dt: f64,
51//! # ) -> Result<(f64, f64), RngError> {
52//! # Ok((0.0, 0.0))
53//! # }
54//! # fn calculate_increment(&self, force: f64) -> Result<(f64, f64), CalcError> {
55//! # Ok((self.vel, force))
56//! # }
57//! # }
58//! # #[derive(Clone, Debug, Deserialize, Serialize)]
59//! # struct MyDomain {};
60//! # impl<Ci> Domain<MyAgent, MyDomain, Ci> for MyDomain
61//! # where
62//! # Ci: IntoIterator<Item = MyAgent>
63//! # {
64//! # type VoxelIndex = usize;
65//! # type SubDomainIndex = usize;
66//! # fn decompose(
67//! # self,
68//! # _: core::num::NonZeroUsize,
69//! # cells: Ci,
70//! # ) -> Result<
71//! # DecomposedDomain<Self::SubDomainIndex, MyDomain, MyAgent>,
72//! # cellular_raza_concepts::DecomposeError,
73//! # > {
74//! # Ok(DecomposedDomain {
75//! # n_subdomains: 1.try_into().unwrap(),
76//! # index_subdomain_cells: vec![(1, MyDomain {}, cells.into_iter().collect())],
77//! # neighbor_map: BTreeMap::from([(1, BTreeSet::new())]),
78//! # rng_seed: 1,
79//! # })
80//! # }
81//! # }
82//! # impl SubDomain for MyDomain {
83//! # type VoxelIndex = usize;
84//! # fn get_neighbor_voxel_indices(&self, _: &Self::VoxelIndex) -> Vec<Self::VoxelIndex> {
85//! # Vec::new()
86//! # }
87//! # fn get_all_indices(&self) -> Vec<Self::VoxelIndex> {
88//! # vec![1]
89//! # }
90//! # }
91//! # impl SortCells<MyAgent> for MyDomain {
92//! # type VoxelIndex = usize;
93//! # fn get_voxel_index_of(
94//! # &self,
95//! # _: &MyAgent,
96//! # ) -> Result<Self::VoxelIndex, cellular_raza_concepts::BoundaryError> {
97//! # Ok(1)
98//! # }
99//! # }
100//! # impl SubDomainMechanics<f64, f64> for MyDomain {
101//! # fn apply_boundary(
102//! # &self,
103//! # _: &mut f64,
104//! # _: &mut f64,
105//! # ) -> Result<(), cellular_raza_concepts::BoundaryError> {
106//! # Ok(())
107//! # }
108//! # }
109//! # let t0 = 0.0;
110//! # let dt = 0.1;
111//! # let tmax = 20.0;
112//! # let save_interval = 2.0;
113//! # let initial_vel = 0.1;
114//! # let n_threads = 1.try_into().unwrap();
115//! // Initialize agents, domain, solving time and how to store results
116//! let agents = (0..10).map(|n| MyAgent {
117//! /* Define the agent's properties */
118//! # pos: n as f64,
119//! # vel: initial_vel,
120//! });
121//! let domain = MyDomain {/* Define the domain*/};
122//! let time = FixedStepsize::from_partial_save_interval(t0, dt, tmax, save_interval)?;
123//! let storage = StorageBuilder::new().priority([StorageOption::Memory]);
124//!
125//! // Group them together
126//! let settings = Settings {
127//! n_threads,
128//! time,
129//! storage,
130//! progressbar: None,
131//! };
132//!
133//! // This will perform the numerical simulation
134//! let storage_access = run_simulation!(
135//! agents: agents,
136//! domain: domain,
137//! settings: settings,
138//! aspects: [Mechanics],
139//! core_path: cellular_raza_core,
140//! )?;
141//!
142//! // Use calculated results
143//! let history = storage_access.cells.load_all_elements()?;
144//! for (iteration, cells) in history {
145//! // ...
146//! # assert!(iteration >= 0);
147//! # assert_eq!(cells.len(), 10);
148//! # for (_, (cbox, _)) in cells {
149//! # if let CellIdentifier::Initial(key) = cbox.get_id() {
150//! # let calculated = key as f64 + iteration as f64 * 0.1 * initial_vel;
151//! # let cr = cbox.cell.pos;
152//! # assert!((calculated - cr).abs() < 1e-5);
153//! # } else {
154//! # panic!("This should only contain initial identifiers");
155//! # }
156//! # }
157//! }
158//! # Ok::<(), SimulationError>(())
159//! ```
160//!
161//! This example cannot contain all the functionality which the [chili](self) backend provides.
162//! We encourage the user to look at the
163//! [cellular-raza.com/guides](https://cellular-raza.com/guides) and
164//! [cellular-raza.com/showcase](https://cellular-raza.com/showcase) sections to get started.
165//!
166//! # Internals
167//! The [chili](self) backend uses procedural macros to generate code which
168//! results in a fully working simulation.
169//! The methods, functions and objects used in this way are formualted with generics.
170//! This enables us to write general-purpose solvers for a wide range of problems.
171//! The most important macro is the [run_simulation] macro which can be solely used to run
172//! simulations.
173//! This macro itself can be broken down into smaller pieces.
174//! - [prepare_types] Defines types used in simulation
175//! - [build_aux_storage] AuxStorage struct used to store intermediate
176//! values for update steps of aspects
177//! - [build_communicator] Type which handles communication between
178//! threads
179//! - [test_compatibility] Test compatibility of all types involved
180//! - [run_main] Defines main loop and performs the simulation
181//!
182//! These macros take a subset of keyword arguments of the [run_simulation] macro.
183//! The arguments are documented under the [run_simulation] macro.
184//!
185//! # Main Loop
186//! The [run_main] macro constructs the main loop of the simulation.
187//! It inserts functions depending on the given simulation aspects.
188//! They can be grouped into 6 steps
189//! Below, we show a list of all these functions and their corresponding aspects.
190//!
191//! #### Step 1 - Send Information
192//!
193//! In this step, each sub
194//!
195//! <style>
196//! div table {
197//! width: 100%;
198//! }
199//! table th:first-of-type {
200//! width: 20%;
201//! }
202//! table th:nth-of-type(2) {
203//! width: 35%;
204//! }
205//! table th:nth-of-type(3) {
206//! width: 45%;
207//! }
208//! </style>
209//!
210//! | Aspects | Function | Purpose |
211//! | --- | --- | --- |
212#\
215 | Send [PosInformation](PosInformation) between threads to get back \
216 [ForceInformation](ForceInformation) |"]
217#\
220 | Uses the [SubDomainForce](cellular_raza_concepts::SubDomainForce) trait to add \
221 custom external force. |"]
222#![doc = "\
223 | `ReactionsContact`\
224 | [update_contact_reactions_step_1]\
225 (SubDomainBox::update_contact_reactions_step_1) \
226 | Sends [ReactionsContactInformation](ReactionsContactInformation) between threads. |"]
227# \
230 | Sends [ReactionsExtraBorderInfo](ReactionsExtraBorderInfo) between threads. |"]
231# | Wait for threads to have finished until proceeding. |"]
233//!
234//! #### Step 2 - Calculate and Return
235//! | Aspects | Function | Purpose |
236//! | --- | --- | --- |
237# \
240 | Calculate forces and return [ForceInformation](ForceInformation) to the original \
241 sender. |"]
242# \
245 | Calculates the combined increment and returns \
246 [ReactionsContactReturn](ReactionsContactReturn) |"]
247# \
250 | Returns [ReactionsExtraBorderReturn](ReactionsExtraBorderReturn) |"]
251//!
252//! #### Step 3 - Receive and Apply
253//! | Aspects | Function | Purpose |
254//! | --- | --- | --- |
255# \
258 | Receives the [ForceInformation](ForceInformation) and adds within the \
259 `aux_storage`. |"]
260# \
263 | Receives the [ReactionsContactReturn](ReactionsContactReturn) and adds within the `aux_storage`. |"]
264# \
267 | Receives the [ReactionsExtraBorderReturn](ReactionsExtraBorderReturn). |"]
268//!
269//! #### Pure Local Functions - Perform Update
270//! | Aspects | Function | Purpose |
271//! | --- | --- | --- |
272# \
275 | Performs numerical integration of the position and velocity. |"]
276# \
279 | Performs changes due to neighbor counting. |"]
280# \
283 | Advances the cycle of the cell. This may introduce a\
284 [CycleEvent](cellular_raza_concepts::CycleEvent) |"]
285# \
288 | Calculates increment from purely intracellular reactions. |"]
289# \
292 | Performs the update of the contact reactions. |"]
293# \
296 | Performs the update of the extracellular reactions. |"]
297# \
300 | Calculates increment from purely intracellular reactions. |"]
301//!
302//! #### Step 4 - Treat Cell Positions
303//! | Aspects | Function | Purpose |
304//! | --- | --- | --- |
305# \
308 | Apply a boundary condition. |"]
309# \
312 | Performs cell-division and other cycle events. |"]
313# \
316 | Checks if cells need to be sent to different subdomain and sends them. |"]
317//!
318//! #### Step 5 - Include new Cells
319//! | Aspects | Function | Purpose |
320//! | --- | --- | --- |
321# \
324 | Include newly received cells into correct subdomains. |"]
325//!
326//! # Return Type
327//! After the simulation is done, we return a [StorageAccess] struct to interoperate with stored
328//! results.
329
330pub use cellular_raza_concepts::{CellBox, CellIdentifier, SubDomainPlainIndex, VoxelPlainIndex};
331
332/// Contains structs to store aspects of the simulation and macros to construct them.
333mod aux_storage;
334#[doc(hidden)]
335pub mod compatibility_tests;
336mod datastructures;
337mod errors;
338mod proc_macro;
339mod result;
340mod setup;
341mod simulation_flow;
342mod solvers;
343mod update_cycle;
344mod update_mechanics;
345mod update_reactions;
346
347pub use aux_storage::*;
348pub use datastructures::*;
349pub use errors::*;
350pub use proc_macro::*;
351pub use result::*;
352pub use setup::*;
353pub use simulation_flow::*;
354pub use solvers::*;
355pub use update_cycle::*;
356pub use update_mechanics::*;
357pub use update_reactions::*;