1use super::{
2 Communicator, ReactionsRungeKuttaSolver, RungeKutta, SimulationError, SubDomainBox,
3 SubDomainPlainIndex, UpdateReactions, UpdateReactionsContact, Voxel, VoxelPlainIndex,
4 reactions_contact_adams_bashforth_3rd,
5};
6use cellular_raza_concepts::*;
7
8use num::FromPrimitive;
9#[cfg(feature = "tracing")]
10use tracing::instrument;
11
12pub struct ReactionsExtraBorderInfo<Binfo>(pub SubDomainPlainIndex, pub Binfo);
14
15pub struct ReactionsExtraBorderReturn<Bvalue>(pub SubDomainPlainIndex, pub Bvalue);
17
18impl<I, S, C, A, Com, Sy> SubDomainBox<I, S, C, A, Com, Sy>
19where
20 S: SubDomain,
21{
22 #[cfg_attr(feature = "tracing", instrument(skip_all))]
24 pub fn update_reactions_extra_step_1<Pos, Ri, Re, Float>(
25 &mut self,
26 ) -> Result<(), SimulationError>
27 where
28 C: ReactionsExtra<Ri, Re>,
29 S: SubDomainReactions<Pos, Re, Float>,
30 Com: Communicator<
31 SubDomainPlainIndex,
32 ReactionsExtraBorderInfo<<S as SubDomainReactions<Pos, Re, Float>>::BorderInfo>,
33 >,
34 {
35 for neighbor_index in self.neighbors.iter() {
36 let border_info = self.subdomain.get_border_info();
37 self.communicator.send(
38 neighbor_index,
39 ReactionsExtraBorderInfo(self.subdomain_plain_index, border_info),
40 )?;
41 }
42 Ok(())
43 }
44
45 #[cfg_attr(feature = "tracing", instrument(skip_all))]
48 pub fn update_reactions_extra_step_2<Pos, Ri, Re, Float>(
49 &mut self,
50 determinism: bool,
51 ) -> Result<(), SimulationError>
52 where
53 C: ReactionsExtra<Ri, Re>,
54 S: SubDomainReactions<Pos, Re, Float>,
55 Com: Communicator<
56 SubDomainPlainIndex,
57 ReactionsExtraBorderReturn<
58 <S as SubDomainReactions<Pos, Re, Float>>::NeighborValue,
59 >,
60 >,
61 Com: Communicator<
62 SubDomainPlainIndex,
63 ReactionsExtraBorderInfo<<S as SubDomainReactions<Pos, Re, Float>>::BorderInfo>,
64 >,
65 {
66 let mut received_infos = <Com as Communicator<
67 SubDomainPlainIndex,
68 ReactionsExtraBorderInfo<<S as SubDomainReactions<Pos, Re, Float>>::BorderInfo>,
69 >>::receive(&mut self.communicator);
70 if determinism {
71 received_infos.sort_by_key(|info| info.0);
72 }
73 for border_info in received_infos {
74 let boundary_value = self.subdomain.get_neighbor_value(border_info.1);
75 self.communicator.send(
77 &border_info.0,
78 ReactionsExtraBorderReturn(self.subdomain_plain_index, boundary_value),
79 )?;
80 }
81 Ok(())
82 }
83
84 #[cfg_attr(feature = "tracing", instrument(skip_all))]
86 pub fn update_reactions_extra_step_3<Pos, Ri, Re, Float>(
87 &mut self,
88 determinism: bool,
89 ) -> Result<(), SimulationError>
90 where
91 C: ReactionsExtra<Ri, Re>,
92 C: Intracellular<Ri>,
93 A: UpdateReactions<Ri>,
94 C: Position<Pos>,
95 S: SubDomainReactions<Pos, Re, Float>,
96 Com: Communicator<
97 SubDomainPlainIndex,
98 ReactionsExtraBorderReturn<
99 <S as SubDomainReactions<Pos, Re, Float>>::NeighborValue,
100 >,
101 >,
102 {
103 let mut errors: Vec<CalcError> = vec![];
104 let sources = self
109 .voxels
110 .iter_mut()
111 .map(|(_, vox)| {
112 vox.cells.iter_mut().map(|(cbox, aux_storage)| {
113 let intracellular = cbox.get_intracellular();
114 let pos = cbox.pos();
115 let extracellular = self.subdomain.get_extracellular_at_pos(&pos)?;
116 let (dintra, dextra) =
117 cbox.calculate_combined_increment(&intracellular, &extracellular)?;
118 aux_storage.incr_conc(dintra);
119 Result::<_, CalcError>::Ok((pos, dextra))
120 })
121 })
122 .flatten()
123 .collect::<Result<Vec<_>, CalcError>>()?;
124 match errors.len() {
125 1 => return Err(errors.pop().unwrap().into()),
126 _ => (),
127 }
128 let mut neighbors = <Com as Communicator<
129 SubDomainPlainIndex,
130 ReactionsExtraBorderReturn<<S as SubDomainReactions<Pos, Re, Float>>::NeighborValue>,
131 >>::receive(&mut self.communicator);
132 if determinism {
133 neighbors.sort_by_key(|v| v.0);
134 }
135 self.subdomain
136 .treat_increments(neighbors.into_iter().map(|n| n.1), sources.into_iter())?;
137 Ok(())
138 }
139}
140
141pub struct ReactionsContactInformation<Pos, Ri, RInf> {
143 pub pos: Pos,
145 pub intracellular: Ri,
147 pub info: RInf,
149 pub cell_index_in_vector: usize,
154 pub index_sender: VoxelPlainIndex,
157 pub index_receiver: VoxelPlainIndex,
160}
161
162pub struct ReactionsContactReturn<Ri> {
165 pub intracellular: Ri,
167 pub cell_index_in_vector: usize,
172 pub index_sender: VoxelPlainIndex,
174}
175
176impl<C, A> Voxel<C, A> {
177 #[cfg_attr(feature = "tracing", instrument(skip_all))]
178 pub(crate) fn calculate_contact_reactions_between_cells_internally<
179 Ri,
180 Pos,
181 RInf,
182 Float,
183 const N: usize,
184 >(
185 &mut self,
186 ) -> Result<(), CalcError>
187 where
188 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
189 C: cellular_raza_concepts::Intracellular<Ri>,
190 C: Position<Pos>,
191 Ri: cellular_raza_concepts::Xapy<Float>,
192 A: UpdateReactionsContact<Ri, N>,
193 A: UpdateReactions<Ri>,
194 Float: num::Float,
195 {
196 let one_half: Float = Float::one() / (Float::one() + Float::one());
197
198 for n in 0..self.cells.len() {
199 for m in n + 1..self.cells.len() {
200 let mut cells_mut = self.cells.iter_mut();
201 let (c1, aux1) = cells_mut.nth(n).unwrap();
202 let (c2, aux2) = cells_mut.nth(m - n - 1).unwrap();
203
204 let p1 = c1.pos();
205 let intra1 = c1.get_intracellular();
206 let rinf1 = c1.get_contact_information();
207 let p2 = c2.pos();
208 let intra2 = c2.get_intracellular();
209 let rinf2 = c2.get_contact_information();
210
211 let (dintra11, dintra12) =
212 c1.calculate_contact_increment(&intra1, &intra2, &p1, &p2, &rinf2)?;
213 let (dintra22, dintra21) =
214 c2.calculate_contact_increment(&intra2, &intra1, &p2, &p1, &rinf1)?;
215
216 aux1.incr_conc(dintra11.xapy(one_half, &dintra21.xa(one_half)));
217 aux2.incr_conc(dintra22.xapy(one_half, &dintra12.xa(one_half)));
218 }
219 }
220 Ok(())
221 }
222
223 #[cfg_attr(feature = "tracing", instrument(skip_all))]
224 pub(crate) fn calculate_contact_reactions_between_cells_external<
225 Ri,
226 Pos,
227 RInf,
228 Float,
229 const N: usize,
230 >(
231 &mut self,
232 ext_pos: &Pos,
233 ext_intra: &Ri,
234 ext_rinf: &RInf,
235 ) -> Result<Ri, CalcError>
236 where
237 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
238 C: cellular_raza_concepts::Intracellular<Ri>,
239 C: Position<Pos>,
240 Ri: Xapy<Float>,
241 A: UpdateReactions<Ri>,
242 A: UpdateReactionsContact<Ri, N>,
243 Float: num::Float,
244 {
245 let one_half = Float::one() / (Float::one() + Float::one());
246 let mut dextra_total = ext_intra.xa(Float::zero());
247 for (cell, aux_storage) in self.cells.iter_mut() {
248 let own_intra = cell.get_intracellular();
249 let own_pos = cell.pos();
250
251 let (dintra, dextra) = cell.calculate_contact_increment(
252 &own_intra, &ext_intra, &own_pos, &ext_pos, &ext_rinf,
253 )?;
254 aux_storage.incr_conc(dintra.xa(one_half));
255 dextra_total = dextra.xapy(one_half, &dextra_total);
256 }
257 Ok(dextra_total)
258 }
259}
260
261impl<I, S, C, A, Com, Sy> SubDomainBox<I, S, C, A, Com, Sy>
262where
263 S: SubDomain,
264{
265 #[cfg_attr(feature = "tracing", instrument(skip_all))]
267 pub fn update_contact_reactions_step_1<Ri, Pos, RInf, Float, const N: usize>(
268 &mut self,
269 ) -> Result<(), SimulationError>
270 where
271 Pos: Clone,
272 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
273 C: cellular_raza_concepts::Intracellular<Ri>,
274 C: cellular_raza_concepts::Position<Pos>,
275 A: UpdateReactions<Ri>,
276 A: UpdateReactionsContact<Ri, N>,
277 Ri: Xapy<Float> + Clone,
278 RInf: Clone,
279 Float: num::Float,
280 Com: Communicator<SubDomainPlainIndex, ReactionsContactInformation<Pos, Ri, RInf>>,
282 {
283 for (_, vox) in self.voxels.iter_mut() {
284 vox.calculate_contact_reactions_between_cells_internally::<Ri, Pos, RInf, Float, N>()?;
285 }
286
287 let key_iterator: Vec<_> = self.voxels.keys().map(|k| *k).collect();
290
291 for voxel_index in key_iterator {
292 for cell_index_in_vector in 0..self.voxels[&voxel_index].cells.len() {
293 let cell_pos = self.voxels[&voxel_index].cells[cell_index_in_vector]
294 .0
295 .pos();
296 let cell_intra = self.voxels[&voxel_index].cells[cell_index_in_vector]
297 .0
298 .get_intracellular();
299 let cell_contact_inf = self.voxels[&voxel_index].cells[cell_index_in_vector]
300 .0
301 .get_contact_information();
302 let mut incr = cell_intra.xa(Float::zero());
303 let neighbors = self.voxels[&voxel_index].neighbors.clone();
305 for neighbor_index in neighbors {
306 match self.voxels.get_mut(&neighbor_index) {
307 Some(vox) => Ok::<(), CalcError>(
308 incr = incr.xapy(
309 Float::one(),
310 &vox.calculate_contact_reactions_between_cells_external(
311 &cell_pos,
312 &cell_intra,
313 &cell_contact_inf,
314 )?,
315 ),
316 ),
318 None => Ok(self.communicator.send(
319 &self.plain_index_to_subdomain[&neighbor_index],
320 ReactionsContactInformation {
321 pos: cell_pos.clone(),
322 intracellular: cell_intra.clone(),
323 info: cell_contact_inf.clone(),
324 cell_index_in_vector,
325 index_sender: voxel_index,
326 index_receiver: neighbor_index.clone(),
327 },
328 )?),
329 }?;
330 }
331 self.voxels.get_mut(&voxel_index).unwrap().cells[cell_index_in_vector]
332 .1
333 .incr_conc(incr);
334 }
335 }
336 Ok(())
337 }
338
339 #[cfg_attr(feature = "tracing", instrument(skip_all))]
342 pub fn update_contact_reactions_step_2<Ri, Pos, RInf, Float, const N: usize>(
343 &mut self,
344 determinism: bool,
345 ) -> Result<(), SimulationError>
346 where
347 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf> + Position<Pos>,
348 C: cellular_raza_concepts::Intracellular<Ri>,
349 A: UpdateReactions<Ri> + UpdateReactionsContact<Ri, N>,
350 Ri: Xapy<Float>,
351 Float: num::Float,
352 Pos: Clone,
353 Com: Communicator<SubDomainPlainIndex, ReactionsContactInformation<Pos, Ri, RInf>>,
354 Com: Communicator<SubDomainPlainIndex, ReactionsContactReturn<Ri>>,
355 {
356 let mut received_infos = <Com as Communicator<
358 SubDomainPlainIndex,
359 ReactionsContactInformation<Pos, Ri, RInf>,
360 >>::receive(&mut self.communicator);
361 if determinism {
362 received_infos.sort_by_key(|info| info.index_sender);
363 }
364 for contact_info in received_infos {
365 let vox = self.voxels.get_mut(&contact_info.index_receiver).ok_or(
366 cellular_raza_concepts::IndexError(format!(
367 "EngineError: Voxel with index {:?} of ReactionsContactInformation can not be\
368 found in this threads.",
369 contact_info.index_receiver
370 )),
371 )?;
372 let incr = vox.calculate_contact_reactions_between_cells_external(
374 &contact_info.pos,
375 &contact_info.intracellular,
376 &contact_info.info,
377 )?;
378
379 self.communicator.send(
381 &self.plain_index_to_subdomain[&contact_info.index_sender],
382 ReactionsContactReturn {
383 intracellular: incr,
384 cell_index_in_vector: contact_info.cell_index_in_vector,
385 index_sender: contact_info.index_sender,
386 },
387 )?;
388 }
389 Ok(())
390 }
391
392 #[cfg_attr(feature = "tracing", instrument(skip(self)))]
394 pub fn update_contact_reactions_step_3<Ri>(
395 &mut self,
396 determinism: bool,
397 ) -> Result<(), SimulationError>
398 where
399 A: UpdateReactions<Ri>,
400 Com: Communicator<SubDomainPlainIndex, ReactionsContactReturn<Ri>>,
401 {
402 let mut received_infos = <Com as Communicator<
404 SubDomainPlainIndex,
405 ReactionsContactReturn<Ri>,
406 >>::receive(&mut self.communicator);
407 if determinism {
408 received_infos.sort_by_key(|info| info.index_sender);
409 }
410 for obt_intracellular in received_infos {
411 let error_1 = format!(
412 "EngineError: Sender with plain index {:?} was ended up in location\
413 where index is not present anymore",
414 obt_intracellular.index_sender
415 );
416 let vox = self
417 .voxels
418 .get_mut(&obt_intracellular.index_sender)
419 .ok_or(cellular_raza_concepts::IndexError(error_1))?;
420 let error_2 = format!(
421 "\
422 EngineError: Force Information with sender index {:?} and\
423 cell at vector position {} could not be matched",
424 obt_intracellular.index_sender, obt_intracellular.cell_index_in_vector
425 );
426 match vox.cells.get_mut(obt_intracellular.cell_index_in_vector) {
427 Some((_, aux_storage)) => {
428 Ok(aux_storage.incr_conc(obt_intracellular.intracellular))
429 }
430 None => Err(cellular_raza_concepts::IndexError(error_2)),
431 }?;
432 }
433 Ok(())
434 }
435}
436
437#[cfg_attr(feature = "tracing", instrument(skip_all))]
439pub fn local_update_contact_reactions<
440 C,
441 A,
442 Ri,
443 #[cfg(feature = "tracing")] F: core::fmt::Debug,
444 #[cfg(not(feature = "tracing"))] F,
445>(
446 cell: &mut C,
447 aux_storage: &mut A,
448 _dt: F,
449 _rng: &mut rand_chacha::ChaCha8Rng,
450) -> Result<(), SimulationError>
451where
452 A: UpdateReactions<Ri> + UpdateReactionsContact<Ri, 2>,
453 C: cellular_raza_concepts::Intracellular<Ri>,
454 F: num::Float + FromPrimitive,
455 Ri: Xapy<F> + Clone,
456{
457 reactions_contact_adams_bashforth_3rd(cell, aux_storage)?;
458 Ok(())
459}
460
461#[allow(private_bounds)]
463#[cfg_attr(feature = "tracing", instrument(skip_all))]
464pub fn local_reactions_intracellular<
465 C,
466 A,
467 Ri,
468 #[cfg(feature = "tracing")] F: core::fmt::Debug,
469 #[cfg(not(feature = "tracing"))] F,
470 const N: usize,
471>(
472 cell: &mut C,
473 aux_storage: &mut A,
474 dt: F,
475 _rng: &mut rand_chacha::ChaCha8Rng,
476) -> Result<(), SimulationError>
477where
478 A: UpdateReactions<Ri>,
479 C: cellular_raza_concepts::Reactions<Ri>,
480 F: num::Float,
481 Ri: Xapy<F>,
482 ReactionsRungeKuttaSolver<N>: RungeKutta<N>,
483{
484 ReactionsRungeKuttaSolver::<N>::update(cell, aux_storage, dt)?;
485 Ok(())
486}
487
488#[cfg_attr(feature = "tracing", instrument(skip_all))]
490pub fn local_reactions_use_increment<
491 C,
492 A,
493 Ri,
494 #[cfg(feature = "tracing")] F: core::fmt::Debug,
495 #[cfg(not(feature = "tracing"))] F,
496>(
497 cell: &mut C,
498 aux_storage: &mut A,
499 dt: F,
500 _rng: &mut rand_chacha::ChaCha8Rng,
501) -> Result<(), SimulationError>
502where
503 C: Intracellular<Ri>,
504 A: UpdateReactions<Ri>,
505 Ri: Xapy<F>,
506 F: num::Zero,
507{
508 let intra = cell.get_intracellular();
509 let dintra = aux_storage.get_conc();
510 cell.set_intracellular(dintra.xapy(dt, &intra));
511 aux_storage.set_conc(aux_storage.get_conc().xa(F::zero()));
512 Ok(())
513}
514
515#[cfg_attr(feature = "tracing", instrument(skip_all))]
520pub fn local_subdomain_update_reactions_extra<S, Ri, Re, Float>(
521 subdomain: &mut S,
522 dt: Float,
523) -> Result<(), SimulationError>
524where
525 S: SubDomainReactions<Ri, Re, Float>,
526{
527 subdomain.update_fluid_dynamics(dt)?;
528 Ok(())
529}