1use super::{Agent, ForceBound, InteractionInf, PositionBound, VelocityBound};
2use cellular_raza_concepts::domain_old::*;
3use cellular_raza_concepts::reactions_old::*;
4use cellular_raza_concepts::*;
5
6use super::errors::*;
7use crate::storage::StorageManager;
8
9use std::collections::{BTreeMap, HashMap};
10
11use std::ops::AddAssign;
12use std::ops::{Add, Mul};
13
14use crossbeam_channel::{Receiver, SendError, Sender};
15use hurdles::Barrier;
16
17use num::Zero;
18use serde::{Deserialize, Serialize};
19
20use rand_chacha::ChaCha8Rng;
21
22#[cfg(feature = "tracing")]
23use tracing::instrument;
24
25#[derive(Clone, Serialize, Deserialize)]
27pub struct DomainBox<Dom> {
28 pub domain_raw: Dom,
30}
31
32impl<Dom> From<Dom> for DomainBox<Dom> {
33 fn from(domain: Dom) -> DomainBox<Dom> {
34 DomainBox { domain_raw: domain }
35 }
36}
37
38impl<Cel, Ind, Vox, Dom> cellular_raza_concepts::domain_old::Domain<CellBox<Cel>, Ind, Vox>
39 for DomainBox<Dom>
40where
41 Dom: cellular_raza_concepts::domain_old::Domain<Cel, Ind, Vox>,
42 Vox: Send + Sync,
43 Cel: Send + Sync,
44{
45 fn apply_boundary(&self, cbox: &mut CellBox<Cel>) -> Result<(), BoundaryError> {
46 self.domain_raw.apply_boundary(&mut cbox.cell)
47 }
48
49 fn get_neighbor_voxel_indices(&self, index: &Ind) -> Vec<Ind> {
50 self.domain_raw.get_neighbor_voxel_indices(index)
51 }
52
53 fn get_voxel_index(&self, cbox: &CellBox<Cel>) -> Ind {
54 self.domain_raw.get_voxel_index(&cbox.cell)
55 }
56
57 fn get_all_indices(&self) -> Vec<Ind> {
58 self.domain_raw.get_all_indices()
59 }
60
61 fn generate_contiguous_multi_voxel_regions(
62 &self,
63 n_regions: usize,
64 ) -> Result<Vec<Vec<(Ind, Vox)>>, CalcError> {
65 self.domain_raw
66 .generate_contiguous_multi_voxel_regions(n_regions)
67 }
68}
69
70pub type PlainIndex = usize;
72
73pub(crate) struct IndexBoundaryInformation<Ind> {
74 pub index_original_sender: PlainIndex,
75 pub index_original_sender_raw: Ind,
76 pub index_original_receiver: PlainIndex,
77}
78
79pub(crate) struct ConcentrationBoundaryInformation<ConcVecExtracellular, Ind> {
80 pub index_original_sender: PlainIndex,
81 pub concentration_boundary: BoundaryCondition<ConcVecExtracellular>,
82 pub index_original_receiver_raw: Ind,
83}
84
85pub(crate) struct PosInformation<Pos, Vel, Inf> {
86 pub pos: Pos,
87 pub vel: Vel,
88 pub info: Inf,
89 pub count: usize,
90 pub index_sender: PlainIndex,
91 pub index_receiver: PlainIndex,
92}
93
94pub(crate) struct ForceInformation<For> {
95 pub force: For,
96 pub count: usize,
97 pub index_sender: PlainIndex,
98}
99
100#[derive(Serialize, Deserialize, Clone)]
102pub struct VoxelBox<
103 Ind,
104 Pos,
105 Vel,
106 For,
107 Vox,
108 Cel,
109 ConcVecExtracellular,
110 ConcBoundaryExtracellular,
111 ConcVecIntracellular,
112> {
113 pub(crate) plain_index: PlainIndex,
114 pub(crate) index: Ind,
115 pub(crate) voxel: Vox,
116 pub(crate) neighbors: Vec<PlainIndex>,
117 pub(crate) cells: Vec<(
118 CellBox<Cel>,
119 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
120 )>,
121 pub(crate) new_cells: Vec<(Cel, Option<CellIdentifier>)>,
122 pub(crate) id_counter: u64,
123 pub(crate) rng: ChaCha8Rng,
124 pub(crate) extracellular_concentration_increments: Vec<(Pos, ConcVecExtracellular)>,
125 pub(crate) concentration_boundaries: Vec<(Ind, BoundaryCondition<ConcBoundaryExtracellular>)>,
126}
127
128impl<
129 Ind,
130 Vox,
131 Cel,
132 Pos,
133 Vel,
134 For,
135 ConcVecExtracellular,
136 ConcBoundaryExtracellular,
137 ConcVecIntracellular,
138> Id
139 for VoxelBox<
140 Ind,
141 Pos,
142 Vel,
143 For,
144 Vox,
145 Cel,
146 ConcVecExtracellular,
147 ConcBoundaryExtracellular,
148 ConcVecIntracellular,
149 >
150{
151 type Identifier = PlainIndex;
152
153 fn get_id(&self) -> PlainIndex {
154 self.plain_index
155 }
156
157 fn ref_id(&self) -> &Self::Identifier {
158 &self.plain_index
159 }
160}
161
162#[derive(Serialize, Deserialize, Clone)]
164pub struct AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular> {
165 force: For,
166 intracellular_concentration_increment: ConcVecIntracellular,
167 pub(crate) cycle_events: Vec<CycleEvent>,
168 neighbor_count: usize,
169
170 inc_pos_back_1: Option<Pos>,
171 inc_pos_back_2: Option<Pos>,
172 inc_vel_back_1: Option<Vel>,
173 inc_vel_back_2: Option<Vel>,
174}
175
176impl<Pos, Vel, For, ConcVecIntracellular> Default
177 for AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>
178where
179 For: Zero,
180 ConcVecIntracellular: Zero,
181{
182 fn default() -> AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular> {
183 AuxiliaryCellPropertyStorage {
184 force: For::zero(),
185 intracellular_concentration_increment: ConcVecIntracellular::zero(),
186 cycle_events: Vec::new(),
187 neighbor_count: 0,
188
189 inc_pos_back_1: None,
190 inc_pos_back_2: None,
191 inc_vel_back_1: None,
192 inc_vel_back_2: None,
193 }
194 }
195}
196
197impl<
198 Ind,
199 Vox,
200 Cel,
201 Pos,
202 Vel,
203 For,
204 ConcVecExtracellular,
205 ConcBoundaryExtracellular,
206 ConcVecIntracellular,
207>
208 VoxelBox<
209 Ind,
210 Pos,
211 Vel,
212 For,
213 Vox,
214 Cel,
215 ConcVecExtracellular,
216 ConcBoundaryExtracellular,
217 ConcVecIntracellular,
218 >
219where
220 Ind: Clone,
221 For: num::Zero,
222 ConcVecIntracellular: Zero,
223{
224 pub(crate) fn new(
225 plain_index: PlainIndex,
226 index: Ind,
227 voxel: Vox,
228 neighbors: Vec<PlainIndex>,
229 cells: Vec<CellBox<Cel>>,
230 rng_seed: u64,
231 ) -> VoxelBox<
232 Ind,
233 Pos,
234 Vel,
235 For,
236 Vox,
237 Cel,
238 ConcVecExtracellular,
239 ConcBoundaryExtracellular,
240 ConcVecIntracellular,
241 > {
242 use rand::SeedableRng;
243 let n_cells = cells.len() as u64;
244 VoxelBox {
245 plain_index,
246 index,
247 voxel,
248 neighbors,
249 cells: cells
250 .into_iter()
251 .map(|cell| (cell, AuxiliaryCellPropertyStorage::default()))
252 .collect(),
253 new_cells: Vec::new(),
254 id_counter: n_cells,
255 rng: ChaCha8Rng::seed_from_u64(rng_seed),
256 extracellular_concentration_increments: Vec::new(),
257 concentration_boundaries: Vec::new(),
258 }
259 }
260}
261
262impl<
263 Ind,
264 Vox,
265 Cel,
266 Pos,
267 Vel,
268 For,
269 ConcVecExtracellular,
270 ConcBoundaryExtracellular,
271 ConcVecIntracellular,
272>
273 VoxelBox<
274 Ind,
275 Pos,
276 Vel,
277 For,
278 Vox,
279 Cel,
280 ConcVecExtracellular,
281 ConcBoundaryExtracellular,
282 ConcVecIntracellular,
283 >
284where
285 Ind: Clone,
286 Pos: Serialize + for<'a> Deserialize<'a>,
287 Vel: Serialize + for<'a> Deserialize<'a>,
288 Cel: Serialize + for<'a> Deserialize<'a>,
289{
290 #[cfg_attr(feature = "tracing", instrument(skip_all))]
291 fn calculate_custom_force_on_cells(&mut self) -> Result<(), CalcError>
292 where
293 Vox: Voxel<Ind, Pos, Vel, For>,
294 Ind: Index,
295 Pos: PositionBound,
296 Vel: VelocityBound,
297 For: ForceBound,
298 Cel: Mechanics<Pos, Vel, For>,
299 Cel: Position<Pos>,
300 Cel: Velocity<Vel>,
301 {
302 for (cell, aux_storage) in self.cells.iter_mut() {
303 match self
304 .voxel
305 .custom_force_on_cell(&cell.pos(), &cell.velocity())
306 {
307 Some(Ok(force)) => Ok(aux_storage.force += force),
308 Some(Err(e)) => Err(e),
309 None => Ok(()),
310 }?;
311 }
312 Ok(())
313 }
314
315 #[cfg_attr(feature = "tracing", instrument(skip_all))]
335 fn calculate_force_between_cells_internally<Inf>(&mut self) -> Result<(), CalcError>
336 where
337 Vox: Voxel<Ind, Pos, Vel, For>,
338 Ind: Index,
339 Pos: PositionBound,
340 Vel: VelocityBound,
341 For: ForceBound,
342 Cel: Interaction<Pos, Vel, For, Inf> + Mechanics<Pos, Vel, For> + Clone,
343 Cel: Position<Pos>,
344 Cel: Velocity<Vel>,
345 {
346 use cellular_raza_concepts::InteractionInformation;
347
348 for n in 0..self.cells.len() {
349 for m in n + 1..self.cells.len() {
350 let mut cells_mut = self.cells.iter_mut();
351 let (c1, aux1) = cells_mut.nth(n).unwrap();
352 let (c2, aux2) = cells_mut.nth(m - n - 1).unwrap();
353
354 let p1 = c1.pos();
355 let v1 = c1.velocity();
356
357 let p2 = c2.pos();
358 let v2 = c2.velocity();
359 let i2 = c2.get_interaction_information();
360
361 let (force1, force2) = c1.calculate_force_between(&p1, &v1, &p2, &v2, &i2)?;
362 aux1.force += force1 * 0.5;
363 aux2.force += force2 * 0.5;
364 }
365 }
366 Ok(())
367 }
368
369 #[cfg_attr(feature = "tracing", instrument(skip_all))]
370 fn calculate_force_between_cells_external<Inf>(
371 &mut self,
372 ext_pos: &Pos,
373 ext_vel: &Vel,
374 ext_inf: &Inf,
375 ) -> Result<For, CalcError>
376 where
377 Vox: Voxel<Ind, Pos, Vel, For>,
378 Ind: Index,
379 Pos: PositionBound,
380 Vel: VelocityBound,
381 For: ForceBound,
382 Cel: Interaction<Pos, Vel, For, Inf> + Mechanics<Pos, Vel, For>,
383 Cel: Position<Pos>,
384 Cel: Velocity<Vel>,
385 {
386 let mut force = For::zero();
387 for (cell, aux_storage) in self.cells.iter_mut() {
388 let (f1, f2) = cell.calculate_force_between(
389 &cell.pos(),
390 &cell.velocity(),
391 &ext_pos,
392 &ext_vel,
393 &ext_inf,
394 )?;
395 aux_storage.force += f1;
396 force += f2;
397 }
398 Ok(force)
399 }
400
401 #[cfg_attr(feature = "tracing", instrument(skip_all))]
402 fn update_cell_cycle(&mut self, dt: &f64) -> Result<(), SimulationError>
403 where
404 Cel: Cycle<Cel>,
405 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>: Default,
406 {
407 self.cells
409 .iter_mut()
410 .map(|(cbox, aux_storage)| {
411 let mut remaining_events = Vec::new();
413 for event in aux_storage.cycle_events.drain(..) {
414 match event {
415 CycleEvent::Division => {
416 let new_cell = Cel::divide(&mut self.rng, &mut cbox.cell)?;
417 self.new_cells.push((new_cell, Some(cbox.get_id())));
418 }
419 CycleEvent::Remove => remaining_events.push(event),
420 CycleEvent::PhasedDeath => {
421 remaining_events.push(event);
422 }
423 };
424 }
425 aux_storage.cycle_events = remaining_events;
426 if aux_storage.cycle_events.contains(&CycleEvent::PhasedDeath) {
428 match Cel::update_conditional_phased_death(&mut self.rng, dt, &mut cbox.cell)? {
429 true => aux_storage.cycle_events.push(CycleEvent::Remove),
430 false => (),
431 }
432 } else {
433 match Cel::update_cycle(&mut self.rng, dt, &mut cbox.cell) {
434 Some(event) => aux_storage.cycle_events.push(event),
435 None => (),
436 }
437 }
438 Ok(())
439 })
440 .collect::<Result<(), SimulationError>>()?;
441
442 self.cells
444 .retain(|(_, aux_storage)| !aux_storage.cycle_events.contains(&CycleEvent::Remove));
445
446 self.cells
448 .extend(self.new_cells.drain(..).map(|(cell, parent_id)| {
449 self.id_counter += 1;
450 (
451 CellBox::new(
452 VoxelPlainIndex(self.plain_index),
453 self.id_counter,
454 cell,
455 parent_id,
456 ),
457 AuxiliaryCellPropertyStorage::default(),
458 )
459 }));
460 Ok(())
461 }
462}
463
464pub struct MultiVoxelContainer<
468 Ind,
469 Pos,
470 Vel,
471 For,
472 Inf,
473 Vox,
474 Dom,
475 Cel,
476 ConcVecExtracellular = (),
477 ConcBoundaryExtracellular = (),
478 ConcVecIntracellular = (),
479> where
480 Pos: Serialize + for<'a> Deserialize<'a>,
481 For: Serialize + for<'a> Deserialize<'a>,
482 Vel: Serialize + for<'a> Deserialize<'a>,
483 Cel: Serialize + for<'a> Deserialize<'a>,
484 Dom: Serialize + for<'a> Deserialize<'a>,
485 ConcVecExtracellular: Serialize + for<'a> Deserialize<'a> + 'static,
486 ConcBoundaryExtracellular: Serialize + for<'a> Deserialize<'a>,
487 ConcVecIntracellular: Serialize + for<'a> Deserialize<'a>,
488{
489 pub(crate) voxels: BTreeMap<
490 PlainIndex,
491 VoxelBox<
492 Ind,
493 Pos,
494 Vel,
495 For,
496 Vox,
497 Cel,
498 ConcVecExtracellular,
499 ConcBoundaryExtracellular,
500 ConcVecIntracellular,
501 >,
502 >,
503
504 pub(crate) domain: DomainBox<Dom>,
515 pub(crate) index_to_plain_index: BTreeMap<Ind, PlainIndex>,
516 pub(crate) plain_index_to_thread: BTreeMap<PlainIndex, usize>,
517 pub(crate) index_to_thread: BTreeMap<Ind, usize>,
518
519 pub(crate) senders_cell: HashMap<
520 usize,
521 Sender<(
522 CellBox<Cel>,
523 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
524 )>,
525 >,
526 pub(crate) senders_pos: HashMap<usize, Sender<PosInformation<Pos, Vel, Inf>>>,
527 pub(crate) senders_force: HashMap<usize, Sender<ForceInformation<For>>>,
528
529 pub(crate) senders_boundary_index: HashMap<usize, Sender<IndexBoundaryInformation<Ind>>>,
530 pub(crate) senders_boundary_concentrations:
531 HashMap<usize, Sender<ConcentrationBoundaryInformation<ConcBoundaryExtracellular, Ind>>>,
532
533 pub(crate) receiver_cell: Receiver<(
535 CellBox<Cel>,
536 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
537 )>,
538 pub(crate) receiver_pos: Receiver<PosInformation<Pos, Vel, Inf>>,
539 pub(crate) receiver_force: Receiver<ForceInformation<For>>,
540
541 pub(crate) receiver_index: Receiver<IndexBoundaryInformation<Ind>>,
542 pub(crate) receiver_concentrations:
543 Receiver<ConcentrationBoundaryInformation<ConcBoundaryExtracellular, Ind>>,
544
545 pub(crate) barrier: Barrier,
548
549 pub(crate) storage_cells: StorageManager<CellIdentifier, CellBox<Cel>>,
550 pub(crate) storage_voxels: StorageManager<
551 PlainIndex,
552 VoxelBox<
553 Ind,
554 Pos,
555 Vel,
556 For,
557 Vox,
558 Cel,
559 ConcVecExtracellular,
560 ConcBoundaryExtracellular,
561 ConcVecIntracellular,
562 >,
563 >,
564
565 pub(crate) mvc_id: u32,
566}
567
568impl<
569 Ind,
570 Pos,
571 Vel,
572 For,
573 Inf,
574 ConcVecExtracellular,
575 ConcBoundaryExtracellular,
576 ConcVecIntracellular,
577 Vox,
578 Dom,
579 Cel,
580>
581 MultiVoxelContainer<
582 Ind,
583 Pos,
584 Vel,
585 For,
586 Inf,
587 Vox,
588 Dom,
589 Cel,
590 ConcVecExtracellular,
591 ConcBoundaryExtracellular,
592 ConcVecIntracellular,
593 >
594where
595 Ind: Index + Serialize + for<'a> Deserialize<'a>,
599 Vox: Voxel<Ind, Pos, Vel, For>,
600 Dom: cellular_raza_concepts::domain_old::Domain<Cel, Ind, Vox>,
601 Pos: Serialize + for<'a> Deserialize<'a>,
602 Vel: Serialize + for<'a> Deserialize<'a>,
603 For: ForceBound + Serialize + for<'a> Deserialize<'a>,
604 Inf: Clone,
605 Cel: Serialize + for<'a> Deserialize<'a> + Send + Sync,
606 ConcVecExtracellular: Serialize + for<'a> Deserialize<'a>,
607 ConcBoundaryExtracellular: Serialize + for<'a> Deserialize<'a>,
608 ConcVecIntracellular: Serialize + for<'a> Deserialize<'a> + Zero,
609{
610 #[cfg_attr(feature = "tracing", instrument(skip_all))]
611 fn update_local_functions<ConcGradientExtracellular, ConcTotalExtracellular>(
612 &mut self,
613 dt: &f64,
614 ) -> Result<(), SimulationError>
615 where
616 Pos: PositionBound,
617 Vel: VelocityBound,
618 For: ForceBound,
619 Inf: InteractionInf,
620 Cel: Agent<Pos, Vel, For, Inf>
621 + InteractionExtracellularGradient<Cel, ConcGradientExtracellular>,
622 Vox: ExtracellularMechanics<
623 Ind,
624 Pos,
625 ConcVecExtracellular,
626 ConcGradientExtracellular,
627 ConcTotalExtracellular,
628 ConcBoundaryExtracellular,
629 >,
630 {
631 self.voxels
632 .iter_mut()
633 .map(|(_, vox)| {
634 use cellular_raza_concepts::domain_old::Domain;
635 vox.update_cell_cycle(dt)?;
637
638 vox.cells
643 .iter_mut()
644 .map(|(cell, _)| self.domain.apply_boundary(cell))
645 .collect::<Result<(), BoundaryError>>()?;
646
647 #[cfg(feature = "gradients")]
648 vox.cells
649 .iter_mut()
650 .map(|(cell, _)| {
651 let gradient = vox
652 .voxel
653 .get_extracellular_gradient_at_point(&cell.cell.pos())?;
654 Cel::sense_gradient(&mut cell.cell, &gradient)?;
655 Ok(())
656 })
657 .collect::<Result<(), SimulationError>>()?;
658 Ok(())
659 })
660 .collect::<Result<(), SimulationError>>()
661 }
662
663 #[cfg_attr(feature = "tracing", instrument(skip_all))]
666 fn update_cellular_reactions<ConcGradientExtracellular, ConcTotalExtracellular>(
667 &mut self,
668 dt: &f64,
669 ) -> Result<(), SimulationError>
670 where
671 ConcVecIntracellular: std::ops::AddAssign + Mul<f64, Output = ConcVecIntracellular>,
672 Cel: Mechanics<Pos, Vel, For>
673 + CellularReactions<ConcVecIntracellular, ConcVecExtracellular>
674 + Volume,
675 Cel: Position<Pos>,
676 Cel: Velocity<Vel>,
677 Vox: ExtracellularMechanics<
678 Ind,
679 Pos,
680 ConcVecExtracellular,
681 ConcGradientExtracellular,
682 ConcTotalExtracellular,
683 ConcBoundaryExtracellular,
684 > + Volume,
685 ConcVecExtracellular: core::ops::Mul<f64, Output = ConcVecExtracellular>,
686 {
687 self.voxels
688 .iter_mut()
689 .map(|(_, voxelbox)| {
690 voxelbox.cells.iter_mut().map(
691 |(cellbox, _aux_storage)| -> Result<(), SimulationError> {
692 let internal_concentration_vector = cellbox.cell.get_intracellular();
693
694 let external_concentration_vector = voxelbox
695 .voxel
696 .get_extracellular_at_point(&cellbox.cell.pos())?;
697 let (increment_intracellular, increment_extracellular) = cellbox
698 .cell
699 .calculate_intra_and_extracellular_reaction_increment(
700 &internal_concentration_vector,
701 &external_concentration_vector,
702 )?;
703
704 let cell_volume = cellbox.cell.get_volume();
705 let voxel_volume = voxelbox.voxel.get_volume();
706 let cell_to_voxel_volume = cell_volume / voxel_volume;
707
708 voxelbox.extracellular_concentration_increments.push((
709 cellbox.cell.pos(),
710 increment_extracellular * cell_to_voxel_volume,
711 ));
712 cellbox.cell.set_intracellular(
719 internal_concentration_vector + increment_intracellular * *dt,
720 );
721 Ok(())
722 },
723 )
724 })
725 .flatten()
726 .collect::<Result<(), SimulationError>>()
727 }
728
729 #[cfg_attr(feature = "tracing", instrument(skip_all))]
730 fn sort_cell_in_voxel(
731 &mut self,
732 cell: CellBox<Cel>,
733 aux_storage: AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
734 ) -> Result<(), SimulationError> {
735 use cellular_raza_concepts::domain_old::Domain;
736 let index = self.index_to_plain_index[&self.domain.get_voxel_index(&cell)];
737
738 match self.voxels.get_mut(&index) {
739 Some(vox) => vox.cells.push((cell, aux_storage)),
740 None => {
741 let thread_index = self.plain_index_to_thread[&index];
742 match self.senders_cell.get(&thread_index) {
743 Some(sender) => sender.send((cell, aux_storage)),
744 None => Err(SendError((cell, aux_storage))),
745 }?;
746 }
747 }
748 Ok(())
749 }
750
751 #[cfg_attr(feature = "tracing", instrument(skip_all))]
752 fn update_fluid_mechanics_step_1<ConcGradientExtracellular, ConcTotalExtracellular>(
753 &mut self,
754 ) -> Result<(), SimulationError>
755 where
756 Vox: ExtracellularMechanics<
757 Ind,
758 Pos,
759 ConcVecExtracellular,
760 ConcGradientExtracellular,
761 ConcTotalExtracellular,
762 ConcBoundaryExtracellular,
763 >,
764 {
765 let indices_iterator = self
766 .voxels
767 .iter()
768 .map(|(ind, vox)| (ind.clone(), vox.index.clone(), vox.neighbors.clone()))
769 .collect::<Vec<_>>();
770 for (voxel_plain_index, voxel_index, neighbor_indices) in indices_iterator.into_iter() {
771 for neighbor_index in neighbor_indices {
772 match self.voxels.get(&neighbor_index) {
773 Some(neighbor_voxel) => {
774 let neighbor_voxel_index_raw = neighbor_voxel.index.clone();
775 let bc = neighbor_voxel
776 .voxel
777 .boundary_condition_to_neighbor_voxel(&voxel_index)?;
778 let vox = self.voxels.get_mut(&voxel_plain_index).unwrap();
779 vox.concentration_boundaries
780 .push((neighbor_voxel_index_raw, bc));
781 Ok(())
782 }
783 None => self.senders_boundary_index
784 [&self.plain_index_to_thread[&neighbor_index]]
785 .send(IndexBoundaryInformation {
786 index_original_sender: voxel_plain_index,
787 index_original_receiver: neighbor_index,
788 index_original_sender_raw: voxel_index.clone(),
789 }),
790 }?;
791 }
792 }
793 Ok(())
794 }
795
796 #[cfg_attr(feature = "tracing", instrument(skip_all))]
797 fn update_fluid_mechanics_step_2<ConcGradientExtracellular, ConcTotalExtracellular>(
798 &mut self,
799 ) -> Result<(), SimulationError>
800 where
801 Vox: ExtracellularMechanics<
802 Ind,
803 Pos,
804 ConcVecExtracellular,
805 ConcGradientExtracellular,
806 ConcTotalExtracellular,
807 ConcBoundaryExtracellular,
808 >,
809 {
810 for index_boundary_information in self.receiver_index.try_iter() {
812 let voxel_box = self
813 .voxels
814 .get(&index_boundary_information.index_original_receiver)
815 .ok_or(IndexError(format!("")))?;
816
817 let concentration_boundary = voxel_box.voxel.boundary_condition_to_neighbor_voxel(
819 &index_boundary_information.index_original_sender_raw,
820 )?;
821
822 let thread_index =
824 self.plain_index_to_thread[&index_boundary_information.index_original_sender];
825 self.senders_boundary_concentrations[&thread_index].send(
826 ConcentrationBoundaryInformation {
827 index_original_sender: index_boundary_information.index_original_sender,
828 index_original_receiver_raw: voxel_box.voxel.get_index(),
829 concentration_boundary,
830 },
831 )?;
832 }
833
834 Ok(())
835 }
836
837 #[cfg_attr(feature = "tracing", instrument(skip_all))]
838 fn update_fluid_mechanics_step_3<ConcGradientExtracellular, ConcTotalExtracellular>(
839 &mut self,
840 dt: &f64,
841 ) -> Result<(), SimulationError>
842 where
843 ConcVecExtracellular: cellular_raza_concepts::domain_old::Concentration,
844 ConcTotalExtracellular: cellular_raza_concepts::domain_old::Concentration,
845 Vox: ExtracellularMechanics<
846 Ind,
847 Pos,
848 ConcVecExtracellular,
849 ConcGradientExtracellular,
850 ConcTotalExtracellular,
851 ConcBoundaryExtracellular,
852 >,
853 {
854 for concentration_boundary_information in self.receiver_concentrations.try_iter() {
856 let vox = self
857 .voxels
858 .get_mut(&concentration_boundary_information.index_original_sender)
859 .ok_or(IndexError(format!(
860 "EngineError: Sender with plain index {} was ended up in location where index is\
861 not present anymore",
862 concentration_boundary_information.index_original_sender)))?;
863 vox.concentration_boundaries.push((
864 concentration_boundary_information.index_original_receiver_raw,
865 concentration_boundary_information.concentration_boundary,
866 ));
867 }
868
869 self.voxels
870 .iter_mut()
871 .map(|(_, voxel_box)| -> Result<(), SimulationError> {
872 let total_extracellular = voxel_box.voxel.get_total_extracellular();
873 let concentration_increment = voxel_box.voxel.calculate_increment(
874 &total_extracellular,
875 &voxel_box.extracellular_concentration_increments,
876 &voxel_box.concentration_boundaries[..],
877 )?;
878 #[cfg(feature = "gradients")]
882 voxel_box
883 .voxel
884 .update_extracellular_gradient(&voxel_box.concentration_boundaries[..])?;
885 voxel_box.voxel.set_total_extracellular(
886 &(total_extracellular + concentration_increment * *dt),
887 )?;
888 voxel_box.extracellular_concentration_increments.drain(..);
889 voxel_box.concentration_boundaries.drain(..);
890 Ok(())
891 })
892 .collect::<Result<(), SimulationError>>()?;
893 Ok(())
894 }
895
896 #[cfg_attr(feature = "tracing", instrument(skip_all))]
899 fn update_cellular_mechanics_step_1(&mut self) -> Result<(), SimulationError>
900 where
901 Pos: PositionBound,
902 Vel: VelocityBound,
903 Inf: Clone,
904 For: std::fmt::Debug,
905 Cel: Interaction<Pos, Vel, For, Inf> + Mechanics<Pos, Vel, For> + Clone,
906 Cel: Position<Pos>,
907 Cel: Velocity<Vel>,
908 {
909 use cellular_raza_concepts::InteractionInformation;
910 self.voxels
931 .iter_mut()
932 .map(|(_, vox)| vox.calculate_force_between_cells_internally())
933 .collect::<Result<(), CalcError>>()?;
934
935 let key_iterator: Vec<_> = self.voxels.keys().map(|k| *k).collect();
938
939 for voxel_index in key_iterator {
940 for cell_count in 0..self.voxels[&voxel_index].cells.len() {
941 let cell_pos = self.voxels[&voxel_index].cells[cell_count].0.pos();
942 let cell_vel = self.voxels[&voxel_index].cells[cell_count].0.velocity();
943 let cell_inf = self.voxels[&voxel_index].cells[cell_count]
944 .0
945 .get_interaction_information();
946 let mut force = For::zero();
947 let neighbors = self.voxels[&voxel_index].neighbors.clone();
948 for neighbor_index in neighbors {
949 match self.voxels.get_mut(&neighbor_index) {
950 Some(vox) => Ok::<(), CalcError>(
951 force += vox.calculate_force_between_cells_external(
952 &cell_pos, &cell_vel, &cell_inf,
953 )?,
954 ),
955 None => Ok(
956 self.senders_pos[&self.plain_index_to_thread[&neighbor_index]].send(
957 PosInformation {
958 index_sender: voxel_index,
959 index_receiver: neighbor_index.clone(),
960 pos: cell_pos.clone(),
961 vel: cell_vel.clone(),
962 info: cell_inf.clone(),
963 count: cell_count,
964 },
965 )?,
966 ),
967 }?;
968 }
969 self.voxels.get_mut(&voxel_index).unwrap().cells[cell_count]
970 .1
971 .force += force;
972 }
973 }
974
975 self.voxels
977 .iter_mut()
978 .map(|(_, vox)| vox.calculate_custom_force_on_cells())
979 .collect::<Result<(), CalcError>>()?;
980 Ok(())
981 }
982
983 #[cfg_attr(feature = "tracing", instrument(skip_all))]
984 fn update_cellular_mechanics_step_2(&mut self) -> Result<(), SimulationError>
985 where
986 Pos: PositionBound,
987 Vel: VelocityBound,
988 Cel: Interaction<Pos, Vel, For, Inf> + Mechanics<Pos, Vel, For> + Clone,
989 Cel: Position<Pos>,
990 Cel: Velocity<Vel>,
991 {
992 for pos_info in self.receiver_pos.try_iter() {
994 let vox = self
995 .voxels
996 .get_mut(&pos_info.index_receiver)
997 .ok_or(IndexError(format!(
998 "EngineError: Voxel with index {:?} of PosInformation can not be found in this\
999 thread.",
1000 pos_info.index_receiver
1001 )))?;
1002 let force = vox.calculate_force_between_cells_external(
1004 &pos_info.pos,
1005 &pos_info.vel,
1006 &pos_info.info,
1007 )?;
1008
1009 let thread_index = self.plain_index_to_thread[&pos_info.index_sender];
1011 self.senders_force[&thread_index].send(ForceInformation {
1012 force,
1013 count: pos_info.count,
1014 index_sender: pos_info.index_sender,
1015 })?;
1016 }
1017 Ok(())
1018 }
1019
1020 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1021 fn update_cellular_mechanics_step_3(&mut self, dt: &f64) -> Result<(), SimulationError>
1022 where
1023 Pos: PositionBound,
1024 Vel: VelocityBound,
1025 Cel: Interaction<Pos, Vel, For, Inf> + Mechanics<Pos, Vel, For> + Clone,
1026 Cel: Position<Pos>,
1027 Cel: Velocity<Vel>,
1028 {
1029 for obt_forces in self.receiver_force.try_iter() {
1031 let vox = self
1032 .voxels
1033 .get_mut(&obt_forces.index_sender)
1034 .ok_or(IndexError(format!(
1035 "EngineError: Sender with plain index {} was ended up in location where index is\
1036 not present anymore",
1037 obt_forces.index_sender)))?;
1038 match vox.cells.get_mut(obt_forces.count) {
1039 Some((_, aux_storage)) => Ok(aux_storage.force += obt_forces.force),
1040 None => Err(IndexError(format!(
1041 "EngineError: Force Information with sender index {:?} and cell at vector\
1042 position {} could not be matched",
1043 obt_forces.index_sender, obt_forces.count
1044 ))),
1045 }?;
1046 }
1047
1048 for (_, vox) in self.voxels.iter_mut() {
1050 for (cell, aux_storage) in vox.cells.iter_mut() {
1051 let (dx, dv) = cell.calculate_increment(aux_storage.force.clone())?;
1053 let (dx_rand, dv_rand) = cell.get_random_contribution(&mut vox.rng, *dt)?;
1054
1055 match (
1056 aux_storage.inc_pos_back_1.clone(),
1057 aux_storage.inc_pos_back_2.clone(),
1058 aux_storage.inc_vel_back_1.clone(),
1059 aux_storage.inc_vel_back_2.clone(),
1060 ) {
1061 (
1063 Some(inc_pos_back_1),
1064 Some(inc_pos_back_2),
1065 Some(inc_vel_back_1),
1066 Some(inc_vel_back_2),
1067 ) => {
1068 cell.set_pos(
1069 &(cell.pos() + dx.clone() * (23.0 / 12.0) * *dt
1070 - inc_pos_back_1 * (16.0 / 12.0) * *dt
1071 + inc_pos_back_2 * (5.0 / 12.0) * *dt
1072 + dx_rand.clone()),
1073 );
1074 cell.set_velocity(
1075 &(cell.velocity() + dv.clone() * (23.0 / 12.0) * *dt
1076 - inc_vel_back_1 * (16.0 / 12.0) * *dt
1077 + inc_vel_back_2 * (5.0 / 12.0) * *dt
1078 + dv_rand.clone()),
1079 );
1080 }
1081 (Some(inc_pos_back_1), None, Some(inc_vel_back_1), None) => {
1083 cell.set_pos(
1084 &(cell.pos() + dx.clone() * (3.0 / 2.0) * *dt
1085 - inc_pos_back_1 * (1.0 / 2.0) * *dt
1086 + dx_rand.clone()),
1087 );
1088 cell.set_velocity(
1089 &(cell.velocity() + dv.clone() * (3.0 / 2.0) * *dt
1090 - inc_vel_back_1 * (1.0 / 2.0) * *dt
1091 + dv_rand.clone()),
1092 );
1093 }
1094 _ => {
1097 cell.set_pos(&(cell.pos() + dx.clone() * *dt + dx_rand.clone()));
1098 cell.set_velocity(&(cell.velocity() + dv.clone() * *dt + dv_rand.clone()));
1099 }
1100 }
1101
1102 aux_storage.force = For::zero();
1104 aux_storage.inc_pos_back_1 = Some(dx + dx_rand);
1105 aux_storage.inc_vel_back_1 = Some(dv + dv_rand);
1106 }
1107 }
1108 Ok(())
1109 }
1110
1111 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1112 fn sort_cells_in_voxels_step_1(&mut self) -> Result<(), SimulationError>
1113 where
1114 Pos: PositionBound,
1115 Vel: VelocityBound,
1116 Cel: Mechanics<Pos, Vel, For>,
1117 Cel: Position<Pos>,
1118 Cel: Velocity<Vel>,
1119 {
1120 let mut find_new_home_cells = Vec::<_>::new();
1122
1123 for (voxel_index, vox) in self.voxels.iter_mut() {
1124 let (new_voxel_cells, old_voxel_cells): (Vec<_>, Vec<_>) =
1127 vox.cells.drain(..).partition(|(c, _)| {
1128 use cellular_raza_concepts::domain_old::Domain;
1129 match self
1130 .index_to_plain_index
1131 .get(&self.domain.get_voxel_index(&c))
1132 {
1133 Some(ind) => ind != voxel_index,
1134 None => panic!("Cannot find index {:?}", self.domain.get_voxel_index(&c)),
1135 }
1136 });
1137 find_new_home_cells.extend(new_voxel_cells);
1138 vox.cells = old_voxel_cells;
1139 }
1140
1141 for (cell, aux_storage) in find_new_home_cells {
1143 use cellular_raza_concepts::domain_old::Domain;
1144 let ind = self.domain.get_voxel_index(&cell);
1145 let new_thread_index = self.index_to_thread[&ind];
1146 let cell_index = self.index_to_plain_index[&ind];
1147 match self.voxels.get_mut(&cell_index) {
1148 Some(vox) => {
1150 vox.cells.push((cell, aux_storage));
1151 Ok(())
1152 }
1153 None => match self.senders_cell.get(&new_thread_index) {
1155 Some(sender) => {
1156 sender.send((cell, aux_storage))?;
1157 Ok(())
1158 }
1159 None => Err(IndexError(format!(
1160 "Could not correctly send cell with id {:?}",
1161 cell.get_id()
1162 ))),
1163 },
1164 }?;
1165 }
1166 Ok(())
1167 }
1168
1169 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1170 fn sort_cells_in_voxels_step_2(&mut self) -> Result<(), SimulationError> {
1171 let mut new_cells = self.receiver_cell.try_iter().collect::<Vec<_>>();
1173 for (cell, aux_storage) in new_cells.drain(..) {
1174 self.sort_cell_in_voxel(cell, aux_storage)?;
1175 }
1176 Ok(())
1177 }
1178
1179 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1180 pub(crate) fn save_cells_to_database(
1181 &mut self,
1182 iteration: &u64,
1183 ) -> Result<(), crate::storage::StorageError>
1184 where
1185 Cel: 'static,
1186 CellBox<Cel>: Clone,
1187 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>: Clone,
1188 {
1189 use crate::storage::StorageInterfaceStore;
1190 let cells = self
1191 .voxels
1192 .iter()
1193 .map(|(_, vox)| vox.cells.iter().map(|(c, _)| (c.ref_id(), c)))
1194 .flatten();
1195
1196 self.storage_cells.store_batch_elements(*iteration, cells)
1197 }
1198
1199 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1200 pub(crate) fn save_voxels_to_database(
1201 &mut self,
1202 iteration: &u64,
1203 ) -> Result<(), crate::storage::StorageError>
1204 where
1205 VoxelBox<
1206 Ind,
1207 Pos,
1208 Vel,
1209 For,
1210 Vox,
1211 Cel,
1212 ConcVecExtracellular,
1213 ConcBoundaryExtracellular,
1214 ConcVecIntracellular,
1215 >: Clone + Send + Sync + 'static,
1216 {
1217 use crate::storage::StorageInterfaceStore;
1218 let voxels = self.voxels.iter().map(|(_, voxel)| (voxel.ref_id(), voxel));
1219
1220 self.storage_voxels.store_batch_elements(*iteration, voxels)
1221 }
1222
1223 #[cfg_attr(feature = "tracing", instrument(skip_all))]
1230 pub fn run_full_update<ConcGradientExtracellular, ConcTotalExtracellular>(
1231 &mut self,
1232 dt: &f64,
1233 ) -> Result<(), SimulationError>
1234 where
1235 Inf: Send + Sync + core::fmt::Debug,
1236 Pos: PositionBound,
1237 Vel: VelocityBound,
1238 ConcVecExtracellular: cellular_raza_concepts::domain_old::Concentration,
1239 ConcTotalExtracellular: cellular_raza_concepts::domain_old::Concentration,
1240 ConcVecIntracellular: Mul<f64, Output = ConcVecIntracellular>
1241 + Add<ConcVecIntracellular, Output = ConcVecIntracellular>
1242 + AddAssign<ConcVecIntracellular>,
1243 Cel: Cycle<Cel>
1244 + Mechanics<Pos, Vel, For>
1245 + Position<Pos>
1246 + Velocity<Vel>
1247 + Interaction<Pos, Vel, For, Inf>
1248 + CellularReactions<ConcVecIntracellular, ConcVecExtracellular>
1249 + InteractionExtracellularGradient<Cel, ConcGradientExtracellular>
1250 + Volume
1251 + Clone,
1252 Vox: ExtracellularMechanics<
1253 Ind,
1254 Pos,
1255 ConcVecExtracellular,
1256 ConcGradientExtracellular,
1257 ConcTotalExtracellular,
1258 ConcBoundaryExtracellular,
1259 > + Volume,
1260 {
1261 self.update_fluid_mechanics_step_1()?;
1265
1266 self.update_cellular_mechanics_step_1()?;
1268
1269 self.barrier.wait();
1272
1273 self.update_fluid_mechanics_step_2()?;
1274
1275 self.update_cellular_mechanics_step_2()?;
1276
1277 self.barrier.wait();
1278
1279 self.update_cellular_reactions(dt)?;
1280
1281 self.update_fluid_mechanics_step_3(dt)?;
1285
1286 self.update_cellular_mechanics_step_3(dt)?;
1287
1288 self.update_local_functions(dt)?;
1291
1292 self.sort_cells_in_voxels_step_1()?;
1295
1296 self.barrier.wait();
1297
1298 self.sort_cells_in_voxels_step_2()?;
1299 Ok(())
1300 }
1301}