dvcompute_branch/simulation/branch/mod.rs
1// Copyright (c) 2020-2022 David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use crate::simulation;
8use crate::simulation::Run;
9use crate::simulation::Point;
10use crate::simulation::event::*;
11use crate::simulation::parameter::*;
12
13/// Some useful utilities.
14pub mod utils;
15
16/// Return the current nested level within `Parameter<usize>` computation,
17/// which is started from zero for the root computation and then increased by one
18/// for each next nested computation.
19#[inline]
20pub fn branch_level() -> BranchLevel {
21 BranchLevel {}
22}
23
24/// Branch a new nested computation and return its result within the current
25/// `Event` by leaving the current computation intact.
26///
27/// A new derivative branch with `branch_level` increased by 1 is created at
28/// the current modeling time. Then the result of the specified computation for
29/// derivative branch is returned to the current computation.
30///
31/// The state of the current computation including its event queue and mutable
32/// references `RefComp` remain intact. In some sense we copy the state of the model
33/// to derivative branch and then proceed with the derived simulation.
34/// Only this copying operation is relatively cheap.
35#[inline]
36pub fn branch_event<M>(comp: M) -> BranchEvent<M>
37 where M: Event
38{
39 BranchEvent { comp }
40}
41
42/// Branch a new nested computation and return its result at the desired
43/// time of the future within the current `Event` by leaving
44/// the current computation intact.
45///
46/// A new derivative branch with `branch_level` increased by 1 is created at
47/// the current modeling time. Then the result of the specified computation for
48/// derivative branch is returned to the current computation.
49///
50/// The state of the current computation including its event queue and mutable
51/// references `RefComp` remain intact. In some sense we copy the state of the model
52/// to derivative branch and then proceed with the derived simulation.
53/// Only this copying operation is relatively cheap.
54#[inline]
55pub fn future_event<M>(event_time: f64, comp: M, including_current: bool) -> FutureEvent<M>
56 where M: Event
57{
58 FutureEvent { event_time, comp, including_current }
59}
60
61/// Return the branch level.
62#[must_use = "computations are lazy and do nothing unless to be run"]
63#[derive(Clone)]
64pub struct BranchLevel {}
65
66impl Parameter for BranchLevel {
67
68 type Item = usize;
69
70 #[doc(hidden)]
71 #[inline]
72 fn call_parameter(self, r: &Run) -> simulation::Result<usize> {
73 Result::Ok(r.branch.level)
74 }
75}
76
77/// Allows branching the `Event` computation.
78#[must_use = "computations are lazy and do nothing unless to be run"]
79#[derive(Clone)]
80pub struct BranchEvent<M> {
81
82 /// The computation.
83 comp: M
84}
85
86impl<M: Event> Event for BranchEvent<M> {
87
88 type Item = M::Item;
89
90 #[doc(hidden)]
91 #[inline]
92 fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
93 let BranchEvent { comp } = self;
94 let r = p.run.new_child(p);
95 let p = Point {
96 run: &r,
97 time: p.time,
98 priority: p.priority,
99 minimal_priority: p.minimal_priority,
100 iteration: p.iteration,
101 phase: p.phase
102 };
103 comp.call_event(&p)
104 }
105}
106
107/// Allows running the `Event` computation in future.
108#[must_use = "computations are lazy and do nothing unless to be run"]
109#[derive(Clone)]
110pub struct FutureEvent<M> {
111
112 /// The event time.
113 event_time: f64,
114
115 /// The computation.
116 comp: M,
117
118 /// Whether to include the current events?
119 including_current: bool
120}
121
122impl<M: Event> Event for FutureEvent<M> {
123
124 type Item = M::Item;
125
126 #[doc(hidden)]
127 #[inline]
128 fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
129 let FutureEvent { event_time, comp, including_current } = self;
130 assert!(event_time >= p.time, "The event time cannot be less than the current modeling time");
131 let r = p.run.new_child(p);
132 let p = r.point_at(event_time, p.priority, p.minimal_priority);
133 r.event_queue.run_events(including_current, &p)?;
134 comp.call_event(&p)
135 }
136}