dvcompute 2.0.0

Discrete event simulation library (sequential simulation)
Documentation
// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::simulation::specs::*;
use crate::simulation::point::Point;
use crate::simulation::internal::event_queue::*;
use crate::simulation::generator::Generator;

#[cfg(feature="cons_mode")]
use crate::simulation::comm::context::LogicalProcessContext;

#[cfg(feature="cons_mode")]
use crate::simulation::internal::input_message_queue::*;

#[cfg(feature="cons_mode")]
use crate::simulation::internal::output_message_queue::*;

/// It represents the simulation run.
#[cfg(feature="cons_mode")]
#[repr(C)]
pub struct Run<'a> {

    /// The event queue.
    #[doc(hidden)]
    pub event_queue: *mut EventQueue,

    /// The simulation specs.
    pub specs: SpecsRepr,

    /// The current simulation run index starting from zero.
    pub run_index: usize,

    /// The number of simulation runs in the Monte Carlo experiment.
    pub run_count: usize,

    /// The random number generator.
    pub generator: Generator,

    /// The logical process context.
    #[doc(hidden)]
    pub lp_context: &'a LogicalProcessContext,

    /// The input message queue.
    #[doc(hidden)]
    pub input_messages: *mut InputMessageQueue,

    /// The output message queue.
    #[doc(hidden)]
    pub output_messages: *mut OutputMessageQueue
}

#[cfg(feature="cons_mode")]
impl<'a> Drop for Run<'a> {

    fn drop(&mut self) {
        unsafe {
            delete_extern_event_queue(self.event_queue);
            delete_extern_input_message_queue(self.input_messages);
            delete_extern_output_message_queue(self.output_messages);
        }
    }
}

#[cfg(feature="cons_mode")]
impl<'a> Run<'a> {

    /// Create a new run instance.
    pub fn new(specs: Specs, ctx: &'a LogicalProcessContext) -> Run<'a> {
        Self::by_index(specs, ctx, 0, 1)
    }

    /// Create a new run instance by the specified index.
    pub fn by_index(specs: Specs, ctx: &'a LogicalProcessContext, run_index: usize, run_count: usize) -> Run<'a> {
        let generator = Generator::new(&specs.generator_type);
        let specs = specs.into();
        let event_queue = unsafe {
            create_extern_event_queue(&specs)
        };
        let input_messages = unsafe {
            create_extern_input_message_queue()
        };
        let output_messages = unsafe {
            create_extern_output_message_queue()
        };
        Run {
            specs: specs,
            event_queue: event_queue,
            run_index: run_index,
            run_count: run_count,
            generator: generator,
            lp_context: ctx,
            input_messages: input_messages,
            output_messages: output_messages
        }
    }

    /// Return the point in the start simulation time.
    #[inline]
    pub fn point_in_start_time(&self) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        Point {
            run: self,
            time: t0,
            priority: 0,
            minimal_priority: isize::MIN,
            iteration: 0,
            phase: 0
        }
    }

    /// Return the point in the final simulation time.
    #[inline]
    pub fn point_in_stop_time(&self) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        let t2 = specs.stop_time;
        let dt = specs.dt;
        let n2 = ((t2 - t0) / dt).floor() as usize;
        Point {
            run: self,
            time: t2,
            priority: 0,
            minimal_priority: isize::MIN,
            iteration: n2,
            phase: 0
        }
    }

    /// Return the point at the specified modeling time.
    #[inline]
    pub fn point_at(&self, t: f64, priority: isize, minimal_priority: isize) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        let dt = specs.dt;
        let n2 = ((t - t0) / dt).floor() as usize;
        Point {
            run: self,
            time: t,
            priority: priority,
            minimal_priority: minimal_priority,
            iteration: n2,
            phase: -1
        }
    }
}

/// It represents the simulation run.
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
#[repr(C)]
pub struct Run {

    /// The event queue.
    #[doc(hidden)]
    pub event_queue: Box<EventQueue>,

    /// The simulation specs.
    pub specs: SpecsRepr,

    /// The current simulation run index starting from zero.
    pub run_index: usize,

    /// The number of simulation runs in the Monte Carlo experiment.
    pub run_count: usize,

    /// The random number generator.
    pub generator: Generator
}

#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
impl Run {

    /// Create a new run instance.
    pub fn new(specs: Specs) -> Run {
        Self::by_index(specs, 0, 1)
    }

    /// Create a new run instance by the specified index.
    pub fn by_index(specs: Specs, run_index: usize, run_count: usize) -> Run {
        let generator = Generator::new(&specs.generator_type);
        let specs = specs.into();
        let event_queue = Box::new(EventQueue::new(&specs));
        Run {
            specs: specs,
            event_queue: event_queue,
            run_index: run_index,
            run_count: run_count,
            generator: generator
        }
    }

    /// Return the point in the start simulation time.
    #[inline]
    pub fn point_in_start_time(&self) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        Point {
            run: self,
            time: t0,
            priority: 0,
            minimal_priority: isize::MIN,
            iteration: 0,
            phase: 0
        }
    }

    /// Return the point in the final simulation time.
    #[inline]
    pub fn point_in_stop_time(&self) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        let t2 = specs.stop_time;
        let dt = specs.dt;
        let n2 = ((t2 - t0) / dt).floor() as usize;
        Point {
            run: self,
            time: t2,
            priority: 0,
            minimal_priority: isize::MIN,
            iteration: n2,
            phase: 0
        }
    }

    /// Return the point at the specified modeling time.
    #[inline]
    pub fn point_at(&self, t: f64, priority: isize, minimal_priority: isize) -> Point {
        let specs = &self.specs;
        let t0 = specs.start_time;
        let dt = specs.dt;
        let n2 = ((t - t0) / dt).floor() as usize;
        Point {
            run: self,
            time: t,
            priority: priority,
            minimal_priority: minimal_priority,
            iteration: n2,
            phase: -1
        }
    }
}