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}