1use super::{Agent, ForceBound, PositionBound, VelocityBound};
2use crate::backend::cpu_os_threads::domain_decomposition::AuxiliaryCellPropertyStorage;
3use crate::storage::StorageManager;
4use cellular_raza_concepts::domain_old::*;
5use cellular_raza_concepts::{CellBox, VoxelPlainIndex};
6
7use super::domain_decomposition::{
8 ConcentrationBoundaryInformation, DomainBox, ForceInformation, IndexBoundaryInformation,
9 MultiVoxelContainer, PlainIndex, PosInformation, VoxelBox,
10};
11use super::supervisor::ControllerBox;
12use super::supervisor::SimulationSupervisor;
13use cellular_raza_concepts::CellIdentifier;
14
15use std::collections::{BTreeMap, HashMap};
16use std::marker::PhantomData;
17
18use crossbeam_channel::{Receiver, Sender, unbounded};
19use hurdles::Barrier;
20
21use serde::{Deserialize, Serialize};
22
23use rayon::prelude::*;
24
25#[derive(Serialize, Deserialize, Clone, Debug)]
27pub struct SimulationConfig {
28 pub progressbar: Option<String>,
30}
31
32impl Default for SimulationConfig {
33 fn default() -> Self {
34 SimulationConfig { progressbar: None }
35 }
36}
37
38#[derive(Clone, Serialize, Deserialize)]
40pub struct SimulationMetaParams {
41 pub n_threads: usize,
44 pub rng_seed: u64,
46}
47
48impl Default for SimulationMetaParams {
49 fn default() -> Self {
50 Self {
51 n_threads: 1,
52 rng_seed: 0,
53 }
54 }
55}
56
57#[derive(Clone, Serialize, Deserialize)]
62pub struct TimeSetup {
63 pub t_start: f64,
65 pub t_eval: Vec<(f64, bool)>,
68}
69
70#[derive(Clone, Serialize, Deserialize)]
72pub struct SimulationSetup<Dom, Cel, Cont = ()> {
73 pub(crate) domain: Dom,
74 pub(crate) cells: Vec<Cel>,
76 pub(crate) time: TimeSetup,
77 pub(crate) meta_params: SimulationMetaParams,
78 pub(crate) storage: crate::storage::StorageBuilder<true>,
79 pub(crate) controller: Cont,
80}
81
82#[macro_export]
83#[doc(hidden)]
84macro_rules! create_simulation_setup (
85 (
86 Domain: $domain:expr,
87 Cells: $cells:expr,
88 Time: $time:expr,
89 MetaParams: $meta_params:expr,
90 Storage: $storage:expr,
91 Controller: $controller:expr$(,)?
92 ) => {
93 SimulationSetup::new(
94 $domain,
95 $cells,
96 $time,
97 $meta_params,
98 $storage,
99 $controller,
100 )
101 };
102
103 (
104 Domain: $domain:expr,
105 Cells: $cells:expr,
106 Time: $time:expr,
107 MetaParams: $meta_params:expr,
108 Storage: $storage:expr$(,)?
109 ) => {
110 create_simulation_setup!(
111 Domain: $domain,
112 Cells: $cells,
113 Time: $time,
114 MetaParams: $meta_params,
115 Storage: $storage,
116 Controller: (),
117 )
118 };
119);
120#[doc(inline)]
121pub use crate::create_simulation_setup;
122
123impl<Dom, Cel, Cont> SimulationSetup<Dom, Cel, Cont> {
124 pub fn new<V>(
126 domain: Dom,
127 cells: V,
128 time: TimeSetup,
129 meta_params: SimulationMetaParams,
130 storage: crate::storage::StorageBuilder<true>,
131 controller: Cont,
132 ) -> SimulationSetup<Dom, Cel, Cont>
133 where
134 V: IntoIterator<Item = Cel>,
135 {
136 SimulationSetup {
137 domain,
138 cells: cells.into_iter().collect(),
139 time,
140 meta_params,
141 storage,
142 controller,
143 }
144 }
145}
146
147#[derive(Clone, Debug, Deserialize, Serialize)]
149pub enum ImageType {
150 BitMap,
152 }
155
156#[derive(Serialize, Deserialize, Clone, Debug)]
158pub struct PlottingConfig {
159 pub image_size: u32,
162 pub n_threads: Option<usize>,
165 pub image_type: ImageType,
167 pub show_progressbar: bool,
169}
170
171impl Default for PlottingConfig {
172 fn default() -> Self {
173 PlottingConfig {
174 image_size: 1000,
175 n_threads: None,
176 image_type: ImageType::BitMap,
177 show_progressbar: true,
178 }
179 }
180}
181
182#[derive(Clone)]
184pub struct Strategies<'a, Vox>
185where
186 Vox: 'a + Clone,
187{
188 pub voxel_definition_strategies: &'a dyn Fn(&mut Vox),
190}
191
192impl<
193 Pos,
194 For,
195 Inf,
196 Vel,
197 ConcVecExtracellular,
198 ConcBoundaryExtracellular,
199 ConcVecIntracellular,
200 Cel,
201 Ind,
202 Vox,
203 Dom,
204 Cont,
205 Obs,
206>
207 SimulationSupervisor<
208 MultiVoxelContainer<
209 Ind,
210 Pos,
211 Vel,
212 For,
213 Inf,
214 Vox,
215 Dom,
216 Cel,
217 ConcVecExtracellular,
218 ConcBoundaryExtracellular,
219 ConcVecIntracellular,
220 >,
221 Dom,
222 Cel,
223 Cont,
224 Obs,
225 >
226where
227 Dom: Domain<Cel, Ind, Vox> + Clone + 'static,
228 Ind: Index + 'static,
229 Pos: Serialize + for<'a> Deserialize<'a> + PositionBound + 'static + std::fmt::Debug,
230 For: Serialize + for<'a> Deserialize<'a> + ForceBound + 'static,
231 Vel: Serialize + for<'a> Deserialize<'a> + VelocityBound + 'static,
232 ConcVecExtracellular: Serialize + for<'a> Deserialize<'a>,
233 ConcBoundaryExtracellular: Serialize + for<'a> Deserialize<'a>,
234 ConcVecIntracellular: Serialize + for<'a> Deserialize<'a> + num::Zero,
235 Vox: Voxel<Ind, Pos, Vel, For> + Clone + 'static,
236 Cel: Agent<Pos, Vel, For, Inf> + 'static,
237 VoxelBox<
238 Ind,
239 Pos,
240 Vel,
241 For,
242 Vox,
243 Cel,
244 ConcVecExtracellular,
245 ConcBoundaryExtracellular,
246 ConcVecIntracellular,
247 >: Clone,
248 Cont: Serialize + for<'a> Deserialize<'a>,
249{
250 pub fn initialize_from_setup(
252 setup: SimulationSetup<Dom, Cel, Cont>,
253 ) -> SimulationSupervisor<
254 MultiVoxelContainer<
255 Ind,
256 Pos,
257 Vel,
258 For,
259 Inf,
260 Vox,
261 Dom,
262 Cel,
263 ConcVecExtracellular,
264 ConcBoundaryExtracellular,
265 ConcVecIntracellular,
266 >,
267 Dom,
268 Cel,
269 Cont,
270 Obs,
271 >
272 where
273 Cel: Sized,
274 {
275 let no_strategy = |_: &mut Vox| {};
276 Self::initialize_with_strategies(
277 setup,
278 Strategies {
279 voxel_definition_strategies: &no_strategy,
280 },
281 )
282 }
283
284 pub fn initialize_with_strategies(
286 setup: SimulationSetup<Dom, Cel, Cont>,
287 strategies: Strategies<Vox>,
288 ) -> SimulationSupervisor<
289 MultiVoxelContainer<
290 Ind,
291 Pos,
292 Vel,
293 For,
294 Inf,
295 Vox,
296 Dom,
297 Cel,
298 ConcVecExtracellular,
299 ConcBoundaryExtracellular,
300 ConcVecIntracellular,
301 >,
302 Dom,
303 Cel,
304 Cont,
305 Obs,
306 >
307 where
308 Cel: Sized,
309 {
310 let voxel_chunks = <Dom>::generate_contiguous_multi_voxel_regions(
312 &setup.domain,
313 setup.meta_params.n_threads,
314 )
315 .unwrap();
316 let n_threads = voxel_chunks.len();
317
318 let convert_to_plain_index: BTreeMap<Ind, PlainIndex> = setup
319 .domain
320 .get_all_indices()
321 .into_iter()
322 .enumerate()
323 .map(|(count, ind)| (ind, count as PlainIndex))
324 .collect();
325 let convert_to_index: BTreeMap<PlainIndex, Ind> = convert_to_plain_index
326 .iter()
327 .map(|(i, j)| (j.clone(), i.clone()))
328 .collect();
329
330 let mut index_to_thread = BTreeMap::<Ind, usize>::new();
331 let mut plain_index_to_thread = BTreeMap::<PlainIndex, usize>::new();
332 for (n_thread, chunk) in voxel_chunks.iter().enumerate() {
333 for (ind, _) in chunk.iter() {
334 index_to_thread.insert(ind.clone(), n_thread);
335 plain_index_to_thread.insert(convert_to_plain_index[&ind], n_thread);
336 }
337 }
338
339 let multivoxelcontainers;
341
342 let sender_receiver_pairs_cell: Vec<(
344 Sender<(
345 CellBox<Cel>,
346 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
347 )>,
348 Receiver<(
349 CellBox<Cel>,
350 AuxiliaryCellPropertyStorage<Pos, Vel, For, ConcVecIntracellular>,
351 )>,
352 )> = (0..n_threads).map(|_| unbounded()).collect();
353 let sender_receiver_pairs_pos: Vec<(
354 Sender<PosInformation<Pos, Vel, Inf>>,
355 Receiver<PosInformation<Pos, Vel, Inf>>,
356 )> = (0..n_threads).map(|_| unbounded()).collect();
357 let sender_receiver_pairs_force: Vec<(
358 Sender<ForceInformation<For>>,
359 Receiver<ForceInformation<For>>,
360 )> = (0..n_threads).map(|_| unbounded()).collect();
361
362 let sender_receiver_pairs_boundary_concentrations: Vec<(
363 Sender<ConcentrationBoundaryInformation<ConcBoundaryExtracellular, Ind>>,
364 Receiver<ConcentrationBoundaryInformation<ConcBoundaryExtracellular, Ind>>,
365 )> = (0..n_threads).map(|_| unbounded()).collect();
366 let sender_receiver_pairs_boundary_index: Vec<(
367 Sender<IndexBoundaryInformation<Ind>>,
368 Receiver<IndexBoundaryInformation<Ind>>,
369 )> = (0..n_threads).map(|_| unbounded()).collect();
370
371 let barrier = Barrier::new(n_threads);
373
374 let mut plain_index_to_thread: BTreeMap<PlainIndex, usize> = BTreeMap::new();
377 for (i, chunk) in voxel_chunks.iter().enumerate() {
378 for (index, _) in chunk {
379 plain_index_to_thread.insert(convert_to_plain_index[&index], i);
380 }
381 }
382
383 let n_chunks = voxel_chunks.len();
385 let chunk_size = (setup.cells.len() as f64 / n_threads as f64).ceil() as usize;
386
387 let mut sorted_cells = setup
388 .cells
389 .into_par_iter()
390 .enumerate()
391 .chunks(chunk_size)
392 .map(|cell_chunk| {
393 let mut cs = BTreeMap::<usize, BTreeMap<PlainIndex, Vec<(usize, Cel)>>>::new();
394 for cell in cell_chunk.into_iter() {
395 let index = setup.domain.get_voxel_index(&cell.1);
396 let plain_index = convert_to_plain_index[&index];
397 let id_thread = plain_index_to_thread[&plain_index];
398 match cs.get_mut(&id_thread) {
399 Some(index_to_cells) => match index_to_cells.get_mut(&plain_index) {
400 Some(cs) => cs.push(cell),
401 None => {
402 index_to_cells.insert(plain_index, vec![cell]);
403 }
404 },
405 None => {
406 cs.insert(id_thread, BTreeMap::from([(plain_index, vec![cell])]));
407 }
408 }
409 }
410 cs
411 })
412 .reduce(
413 || {
414 (0..n_chunks)
415 .map(|i| (i, BTreeMap::new()))
416 .collect::<BTreeMap<usize, BTreeMap<PlainIndex, Vec<(usize, Cel)>>>>()
417 },
418 |mut acc, x| {
419 for (id_thread, idc) in x.into_iter() {
420 for (index, mut cells) in idc.into_iter() {
421 match acc.get_mut(&id_thread) {
422 Some(index_to_cells) => match index_to_cells.get_mut(&index) {
423 Some(cs) => cs.append(&mut cells),
424 None => {
425 index_to_cells.insert(index, cells);
426 }
427 },
428 None => {
429 acc.insert(id_thread, BTreeMap::from([(index, cells)]));
430 }
431 }
432 }
433 }
434 return acc;
435 },
436 );
437
438 let voxel_and_raw_cells: Vec<(
439 Vec<(PlainIndex, Vox)>,
440 BTreeMap<PlainIndex, Vec<(usize, Cel)>>,
441 )> = voxel_chunks
442 .into_iter()
443 .enumerate()
444 .map(|(i, chunk)| {
445 (
446 chunk
447 .into_iter()
448 .map(|(ind, vox)| (convert_to_plain_index[&ind], vox))
449 .collect(),
450 sorted_cells.remove(&i).unwrap(),
451 )
452 })
453 .collect();
454
455 let voxel_and_cell_boxes: Vec<(
456 Vec<(PlainIndex, Vox)>,
457 BTreeMap<PlainIndex, Vec<CellBox<Cel>>>,
458 )> = voxel_and_raw_cells
459 .into_iter()
460 .map(|(chunk, sorted_cells)| {
461 let res = (
462 chunk,
463 sorted_cells
464 .into_iter()
465 .map(|(ind, mut cells)| {
466 cells.sort_by(|(i, _), (j, _)| i.cmp(&j));
467 (
468 ind,
469 cells
470 .into_iter()
471 .enumerate()
472 .map(|(n_cell, (_, cell))| {
473 CellBox::new(
474 VoxelPlainIndex(ind),
475 n_cell as u64,
476 cell,
477 None,
478 )
479 })
480 .collect(),
481 )
482 })
483 .collect(),
484 );
485 res
486 })
487 .collect();
488
489 let builder = setup.storage.init();
492 let meta_infos_builder = builder
493 .clone()
494 .suffix(builder.get_suffix().join("meta_infos"));
495 let meta_infos =
496 StorageManager::<(), SimulationSetup<DomainBox<Dom>, Cel, Cont>>::open_or_create(
497 meta_infos_builder,
498 0,
499 )
500 .unwrap();
501
502 use rand::{RngCore, SeedableRng};
504 use rand_chacha::ChaCha8Rng;
505 let mut rng_generator = ChaCha8Rng::seed_from_u64(setup.meta_params.rng_seed.clone());
506 multivoxelcontainers = voxel_and_cell_boxes
507 .into_iter()
508 .enumerate()
509 .map(|(i, (chunk, mut index_to_cells))| {
510 let mut voxels: BTreeMap<
511 PlainIndex,
512 VoxelBox<
513 Ind,
514 Pos,
515 Vel,
516 For,
517 Vox,
518 Cel,
519 ConcVecExtracellular,
520 ConcBoundaryExtracellular,
521 ConcVecIntracellular,
522 >,
523 > = chunk
524 .clone()
525 .into_iter()
526 .map(|(plain_index, voxel)| {
527 let cells = match index_to_cells.remove(&plain_index) {
528 Some(cs) => cs,
529 None => Vec::new(),
530 };
531 let neighbors = setup
532 .domain
533 .get_neighbor_voxel_indices(&convert_to_index[&plain_index])
534 .into_iter()
535 .map(|i| convert_to_plain_index[&i])
536 .collect::<Vec<_>>();
537 let vbox = VoxelBox::<
538 Ind,
539 Pos,
540 Vel,
541 For,
542 Vox,
543 Cel,
544 ConcVecExtracellular,
545 ConcBoundaryExtracellular,
546 ConcVecIntracellular,
547 >::new(
548 plain_index,
549 convert_to_index[&plain_index].clone(),
550 voxel,
551 neighbors,
552 cells,
553 rng_generator.next_u64(),
554 );
555 (plain_index, vbox)
556 })
557 .collect();
558
559 for (ind, _) in voxels.iter() {
561 match index_to_cells.get(&ind) {
562 Some(_) => (),
563 None => {
564 index_to_cells.insert(ind.clone(), Vec::new());
565 }
566 }
567 }
568
569 macro_rules! create_senders {
571 ($sr_pairs: expr) => {
572 chunk
573 .clone()
574 .into_iter()
575 .map(|(plain_index, _)| {
576 setup
577 .domain
578 .get_neighbor_voxel_indices(&convert_to_index[&plain_index])
579 .into_iter()
580 .map(|ind| {
581 (
582 index_to_thread[&ind],
583 $sr_pairs[index_to_thread[&ind]].0.clone(),
584 )
585 })
586 })
587 .flatten()
588 .collect::<HashMap<usize, _>>()
589 };
590 }
591
592 let senders_cell = create_senders!(sender_receiver_pairs_cell);
593 let senders_pos = create_senders!(sender_receiver_pairs_pos);
594 let senders_force = create_senders!(sender_receiver_pairs_force);
595 let senders_boundary_index = create_senders!(sender_receiver_pairs_boundary_index);
596 let senders_boundary_concentrations =
597 create_senders!(sender_receiver_pairs_boundary_concentrations);
598
599 let storage_cells_builder = builder
601 .clone()
602 .suffix(builder.get_suffix().join("cell_storage"));
603
604 let storage_cells = StorageManager::<CellIdentifier, CellBox<Cel>>::open_or_create(
605 storage_cells_builder,
606 i as u64,
607 )
608 .unwrap();
609 let storage_voxels_builder = builder
610 .clone()
611 .suffix(builder.get_suffix().join("voxel_storage"));
612 let storage_voxels =
613 StorageManager::<
614 PlainIndex,
615 VoxelBox<
616 Ind,
617 Pos,
618 Vel,
619 For,
620 Vox,
621 Cel,
622 ConcVecExtracellular,
623 ConcBoundaryExtracellular,
624 ConcVecIntracellular,
625 >,
626 >::open_or_create(storage_voxels_builder, i as u64)
627 .unwrap();
628
629 voxels.iter_mut().for_each(|(_, voxelbox)| {
630 (strategies.voxel_definition_strategies)(&mut voxelbox.voxel)
631 });
632
633 let cont = MultiVoxelContainer {
635 voxels,
636 index_to_plain_index: convert_to_plain_index.clone(),
637
638 domain: DomainBox::from(setup.domain.clone()),
639
640 index_to_thread: index_to_thread.clone(),
641 plain_index_to_thread: plain_index_to_thread.clone(),
642
643 senders_cell,
644 senders_pos,
645 senders_force,
646
647 senders_boundary_index,
648 senders_boundary_concentrations,
649
650 receiver_cell: sender_receiver_pairs_cell[i].1.clone(),
651 receiver_pos: sender_receiver_pairs_pos[i].1.clone(),
652 receiver_force: sender_receiver_pairs_force[i].1.clone(),
653
654 receiver_index: sender_receiver_pairs_boundary_index[i].1.clone(),
655 receiver_concentrations: sender_receiver_pairs_boundary_concentrations[i]
656 .1
657 .clone(),
658
659 barrier: barrier.clone(),
660
661 storage_cells,
662 storage_voxels,
663
664 mvc_id: i as u32,
665 };
666
667 return cont;
668 })
669 .collect();
670
671 SimulationSupervisor {
672 worker_threads: Vec::new(),
673 multivoxelcontainers,
674
675 time: setup.time,
676 meta_params: setup.meta_params,
677 storage: builder,
678
679 domain: setup.domain.into(),
680
681 config: SimulationConfig {
682 progressbar: Some("".to_string()),
683 },
684
685 meta_infos,
686
687 controller_box: std::sync::Arc::new(std::sync::Mutex::new(ControllerBox {
688 controller: setup.controller,
689 measurements: BTreeMap::new(),
690 })),
691 phantom_cont: PhantomData,
692 phantom_obs: PhantomData,
693 }
694 }
695}