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 sources = self
108 .voxels
109 .iter_mut()
110 .map(|(_, vox)| {
111 vox.cells.iter_mut().map(|(cbox, aux_storage)| {
112 let intracellular = cbox.get_intracellular();
113 let pos = cbox.pos();
114 let extracellular = self.subdomain.get_extracellular_at_pos(&pos)?;
115 let (dintra, dextra) =
116 cbox.calculate_combined_increment(&intracellular, &extracellular)?;
117 aux_storage.incr_conc(dintra);
118 Result::<_, CalcError>::Ok((pos, dextra))
119 })
120 })
121 .flatten()
122 .collect::<Result<Vec<_>, CalcError>>()?;
123 let mut neighbors = <Com as Communicator<
124 SubDomainPlainIndex,
125 ReactionsExtraBorderReturn<<S as SubDomainReactions<Pos, Re, Float>>::NeighborValue>,
126 >>::receive(&mut self.communicator);
127 if determinism {
128 neighbors.sort_by_key(|v| v.0);
129 }
130 self.subdomain
131 .treat_increments(neighbors.into_iter().map(|n| n.1), sources.into_iter())?;
132 Ok(())
133 }
134}
135
136pub struct ReactionsContactInformation<Pos, Ri, RInf> {
138 pub pos: Pos,
140 pub intracellular: Ri,
142 pub info: RInf,
144 pub cell_index_in_vector: usize,
149 pub index_sender: VoxelPlainIndex,
152 pub index_receiver: VoxelPlainIndex,
155}
156
157pub struct ReactionsContactReturn<Ri> {
160 pub intracellular: Ri,
162 pub cell_index_in_vector: usize,
167 pub index_sender: VoxelPlainIndex,
169}
170
171impl<C, A> Voxel<C, A> {
172 #[cfg_attr(feature = "tracing", instrument(skip_all))]
173 pub(crate) fn calculate_contact_reactions_between_cells_internally<
174 Ri,
175 Pos,
176 RInf,
177 Float,
178 const N: usize,
179 >(
180 &mut self,
181 ) -> Result<(), CalcError>
182 where
183 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
184 C: cellular_raza_concepts::Intracellular<Ri>,
185 C: Position<Pos>,
186 Ri: cellular_raza_concepts::Xapy<Float>,
187 A: UpdateReactionsContact<Ri, N>,
188 A: UpdateReactions<Ri>,
189 Float: num::Float,
190 {
191 let one_half: Float = Float::one() / (Float::one() + Float::one());
192
193 for n in 0..self.cells.len() {
194 for m in n + 1..self.cells.len() {
195 let mut cells_mut = self.cells.iter_mut();
196 let (c1, aux1) = cells_mut.nth(n).unwrap();
197 let (c2, aux2) = cells_mut.nth(m - n - 1).unwrap();
198
199 let p1 = c1.pos();
200 let intra1 = c1.get_intracellular();
201 let rinf1 = c1.get_contact_information();
202 let p2 = c2.pos();
203 let intra2 = c2.get_intracellular();
204 let rinf2 = c2.get_contact_information();
205
206 let (dintra11, dintra12) =
207 c1.calculate_contact_increment(&intra1, &intra2, &p1, &p2, &rinf2)?;
208 let (dintra22, dintra21) =
209 c2.calculate_contact_increment(&intra2, &intra1, &p2, &p1, &rinf1)?;
210
211 aux1.incr_conc(dintra11.xapy(one_half, &dintra21.xa(one_half)));
212 aux2.incr_conc(dintra22.xapy(one_half, &dintra12.xa(one_half)));
213 }
214 }
215 Ok(())
216 }
217
218 #[cfg_attr(feature = "tracing", instrument(skip_all))]
219 pub(crate) fn calculate_contact_reactions_between_cells_external<
220 Ri,
221 Pos,
222 RInf,
223 Float,
224 const N: usize,
225 >(
226 &mut self,
227 ext_pos: &Pos,
228 ext_intra: &Ri,
229 ext_rinf: &RInf,
230 ) -> Result<Ri, CalcError>
231 where
232 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
233 C: cellular_raza_concepts::Intracellular<Ri>,
234 C: Position<Pos>,
235 Ri: Xapy<Float>,
236 A: UpdateReactions<Ri>,
237 A: UpdateReactionsContact<Ri, N>,
238 Float: num::Float,
239 {
240 let one_half = Float::one() / (Float::one() + Float::one());
241 let mut dextra_total = ext_intra.xa(Float::zero());
242 for (cell, aux_storage) in self.cells.iter_mut() {
243 let own_intra = cell.get_intracellular();
244 let own_pos = cell.pos();
245
246 let (dintra, dextra) = cell.calculate_contact_increment(
247 &own_intra, &ext_intra, &own_pos, &ext_pos, &ext_rinf,
248 )?;
249 aux_storage.incr_conc(dintra.xa(one_half));
250 dextra_total = dextra.xapy(one_half, &dextra_total);
251 }
252 Ok(dextra_total)
253 }
254}
255
256impl<I, S, C, A, Com, Sy> SubDomainBox<I, S, C, A, Com, Sy>
257where
258 S: SubDomain,
259{
260 #[cfg_attr(feature = "tracing", instrument(skip_all))]
262 pub fn update_contact_reactions_step_1<Ri, Pos, RInf, Float, const N: usize>(
263 &mut self,
264 ) -> Result<(), SimulationError>
265 where
266 Pos: Clone,
267 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf>,
268 C: cellular_raza_concepts::Intracellular<Ri>,
269 C: cellular_raza_concepts::Position<Pos>,
270 A: UpdateReactions<Ri>,
271 A: UpdateReactionsContact<Ri, N>,
272 Ri: Xapy<Float> + Clone,
273 RInf: Clone,
274 Float: num::Float,
275 Com: Communicator<SubDomainPlainIndex, ReactionsContactInformation<Pos, Ri, RInf>>,
277 {
278 for (_, vox) in self.voxels.iter_mut() {
279 vox.calculate_contact_reactions_between_cells_internally::<Ri, Pos, RInf, Float, N>()?;
280 }
281
282 let key_iterator: Vec<_> = self.voxels.keys().map(|k| *k).collect();
285
286 for voxel_index in key_iterator {
287 for cell_index_in_vector in 0..self.voxels[&voxel_index].cells.len() {
288 let cell_pos = self.voxels[&voxel_index].cells[cell_index_in_vector]
289 .0
290 .pos();
291 let cell_intra = self.voxels[&voxel_index].cells[cell_index_in_vector]
292 .0
293 .get_intracellular();
294 let cell_contact_inf = self.voxels[&voxel_index].cells[cell_index_in_vector]
295 .0
296 .get_contact_information();
297 let mut incr = cell_intra.xa(Float::zero());
298 let neighbors = self.voxels[&voxel_index].neighbors.clone();
300 for neighbor_index in neighbors {
301 match self.voxels.get_mut(&neighbor_index) {
302 Some(vox) => Ok::<(), CalcError>(
303 incr = incr.xapy(
304 Float::one(),
305 &vox.calculate_contact_reactions_between_cells_external(
306 &cell_pos,
307 &cell_intra,
308 &cell_contact_inf,
309 )?,
310 ),
311 ),
313 None => Ok(self.communicator.send(
314 &self.plain_index_to_subdomain[&neighbor_index],
315 ReactionsContactInformation {
316 pos: cell_pos.clone(),
317 intracellular: cell_intra.clone(),
318 info: cell_contact_inf.clone(),
319 cell_index_in_vector,
320 index_sender: voxel_index,
321 index_receiver: neighbor_index.clone(),
322 },
323 )?),
324 }?;
325 }
326 self.voxels.get_mut(&voxel_index).unwrap().cells[cell_index_in_vector]
327 .1
328 .incr_conc(incr);
329 }
330 }
331 Ok(())
332 }
333
334 #[cfg_attr(feature = "tracing", instrument(skip_all))]
337 pub fn update_contact_reactions_step_2<Ri, Pos, RInf, Float, const N: usize>(
338 &mut self,
339 determinism: bool,
340 ) -> Result<(), SimulationError>
341 where
342 C: cellular_raza_concepts::ReactionsContact<Ri, Pos, Float, RInf> + Position<Pos>,
343 C: cellular_raza_concepts::Intracellular<Ri>,
344 A: UpdateReactions<Ri> + UpdateReactionsContact<Ri, N>,
345 Ri: Xapy<Float>,
346 Float: num::Float,
347 Pos: Clone,
348 Com: Communicator<SubDomainPlainIndex, ReactionsContactInformation<Pos, Ri, RInf>>,
349 Com: Communicator<SubDomainPlainIndex, ReactionsContactReturn<Ri>>,
350 {
351 let mut received_infos = <Com as Communicator<
353 SubDomainPlainIndex,
354 ReactionsContactInformation<Pos, Ri, RInf>,
355 >>::receive(&mut self.communicator);
356 if determinism {
357 received_infos.sort_by_key(|info| info.index_sender);
358 }
359 for contact_info in received_infos {
360 let vox = self.voxels.get_mut(&contact_info.index_receiver).ok_or(
361 cellular_raza_concepts::IndexError(format!(
362 "EngineError: Voxel with index {:?} of ReactionsContactInformation can not be\
363 found in this threads.",
364 contact_info.index_receiver
365 )),
366 )?;
367 let incr = vox.calculate_contact_reactions_between_cells_external(
369 &contact_info.pos,
370 &contact_info.intracellular,
371 &contact_info.info,
372 )?;
373
374 self.communicator.send(
376 &self.plain_index_to_subdomain[&contact_info.index_sender],
377 ReactionsContactReturn {
378 intracellular: incr,
379 cell_index_in_vector: contact_info.cell_index_in_vector,
380 index_sender: contact_info.index_sender,
381 },
382 )?;
383 }
384 Ok(())
385 }
386
387 #[cfg_attr(feature = "tracing", instrument(skip(self)))]
389 pub fn update_contact_reactions_step_3<Ri>(
390 &mut self,
391 determinism: bool,
392 ) -> Result<(), SimulationError>
393 where
394 A: UpdateReactions<Ri>,
395 Com: Communicator<SubDomainPlainIndex, ReactionsContactReturn<Ri>>,
396 {
397 let mut received_infos = <Com as Communicator<
399 SubDomainPlainIndex,
400 ReactionsContactReturn<Ri>,
401 >>::receive(&mut self.communicator);
402 if determinism {
403 received_infos.sort_by_key(|info| info.index_sender);
404 }
405 for obt_intracellular in received_infos {
406 let error_1 = format!(
407 "EngineError: Sender with plain index {:?} was ended up in location\
408 where index is not present anymore",
409 obt_intracellular.index_sender
410 );
411 let vox = self
412 .voxels
413 .get_mut(&obt_intracellular.index_sender)
414 .ok_or(cellular_raza_concepts::IndexError(error_1))?;
415 let error_2 = format!(
416 "\
417 EngineError: Force Information with sender index {:?} and\
418 cell at vector position {} could not be matched",
419 obt_intracellular.index_sender, obt_intracellular.cell_index_in_vector
420 );
421 match vox.cells.get_mut(obt_intracellular.cell_index_in_vector) {
422 Some((_, aux_storage)) => {
423 Ok(aux_storage.incr_conc(obt_intracellular.intracellular))
424 }
425 None => Err(cellular_raza_concepts::IndexError(error_2)),
426 }?;
427 }
428 Ok(())
429 }
430}
431
432#[cfg_attr(feature = "tracing", instrument(skip_all))]
434pub fn local_update_contact_reactions<
435 C,
436 A,
437 Ri,
438 #[cfg(feature = "tracing")] F: core::fmt::Debug,
439 #[cfg(not(feature = "tracing"))] F,
440>(
441 cell: &mut C,
442 aux_storage: &mut A,
443 _dt: F,
444 _rng: &mut rand_chacha::ChaCha8Rng,
445) -> Result<(), SimulationError>
446where
447 A: UpdateReactions<Ri> + UpdateReactionsContact<Ri, 2>,
448 C: cellular_raza_concepts::Intracellular<Ri>,
449 F: num::Float + FromPrimitive,
450 Ri: Xapy<F> + Clone,
451{
452 reactions_contact_adams_bashforth_3rd(cell, aux_storage)?;
453 Ok(())
454}
455
456#[allow(private_bounds)]
458#[cfg_attr(feature = "tracing", instrument(skip_all))]
459pub fn local_reactions_intracellular<
460 C,
461 A,
462 Ri,
463 #[cfg(feature = "tracing")] F: core::fmt::Debug,
464 #[cfg(not(feature = "tracing"))] F,
465 const N: usize,
466>(
467 cell: &mut C,
468 aux_storage: &mut A,
469 dt: F,
470 _rng: &mut rand_chacha::ChaCha8Rng,
471) -> Result<(), SimulationError>
472where
473 A: UpdateReactions<Ri>,
474 C: cellular_raza_concepts::Reactions<Ri>,
475 F: num::Float,
476 Ri: Xapy<F>,
477 ReactionsRungeKuttaSolver<N>: RungeKutta<N>,
478{
479 ReactionsRungeKuttaSolver::<N>::update(cell, aux_storage, dt)?;
480 Ok(())
481}
482
483#[cfg_attr(feature = "tracing", instrument(skip_all))]
485pub fn local_reactions_use_increment<
486 C,
487 A,
488 Ri,
489 #[cfg(feature = "tracing")] F: core::fmt::Debug,
490 #[cfg(not(feature = "tracing"))] F,
491>(
492 cell: &mut C,
493 aux_storage: &mut A,
494 dt: F,
495 _rng: &mut rand_chacha::ChaCha8Rng,
496) -> Result<(), SimulationError>
497where
498 C: Intracellular<Ri>,
499 A: UpdateReactions<Ri>,
500 Ri: Xapy<F>,
501 F: num::Zero,
502{
503 let intra = cell.get_intracellular();
504 let dintra = aux_storage.get_conc();
505 cell.set_intracellular(dintra.xapy(dt, &intra));
506 let intra_new = cell.get_intracellular();
507 aux_storage.set_conc(intra_new.xa(F::zero()));
508 Ok(())
509}
510
511#[cfg_attr(feature = "tracing", instrument(skip_all))]
516pub fn local_subdomain_update_reactions_extra<S, Ri, Re, Float>(
517 subdomain: &mut S,
518 dt: Float,
519) -> Result<(), SimulationError>
520where
521 S: SubDomainReactions<Ri, Re, Float>,
522{
523 subdomain.update_fluid_dynamics(dt)?;
524 Ok(())
525}