use crate::data::error_model::ErrorPoly;
use crate::prelude::simulator::Prediction;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum Route {
IVBolus,
IVInfusion,
#[default]
Extravascular,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum AUCMethod {
Linear,
#[default]
LinUpLogDown,
LinLog,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub enum BLQRule {
Zero,
LoqOver2,
#[default]
Exclude,
Positional,
TmaxRelative {
before_tmax_keep: bool,
after_tmax_keep: bool,
},
}
#[derive(Serialize, Debug, Clone, Deserialize)]
pub enum Event {
Bolus(Bolus),
Infusion(Infusion),
Observation(Observation),
}
impl Event {
pub fn time(&self) -> f64 {
match self {
Event::Bolus(bolus) => bolus.time,
Event::Infusion(infusion) => infusion.time,
Event::Observation(observation) => observation.time,
}
}
pub(crate) fn inc_time(&mut self, dt: f64) {
match self {
Event::Bolus(bolus) => bolus.time += dt,
Event::Infusion(infusion) => infusion.time += dt,
Event::Observation(observation) => observation.time += dt,
}
}
pub fn occasion(&self) -> usize {
match self {
Event::Bolus(bolus) => bolus.occasion,
Event::Infusion(infusion) => infusion.occasion,
Event::Observation(observation) => observation.occasion,
}
}
pub fn mut_occasion(&mut self) -> &mut usize {
match self {
Event::Bolus(bolus) => bolus.mut_occasion(),
Event::Infusion(infusion) => infusion.mut_occasion(),
Event::Observation(observation) => observation.mut_occasion(),
}
}
pub fn set_occasion(&mut self, occasion: usize) {
match self {
Event::Bolus(_) => {
*self.mut_occasion() = occasion;
}
Event::Infusion(_) => {
*self.mut_occasion() = occasion;
}
Event::Observation(_) => {
*self.mut_occasion() = occasion;
}
}
}
}
#[derive(Serialize, Debug, Clone, Deserialize)]
pub struct Bolus {
time: f64,
amount: f64,
input: usize,
occasion: usize,
}
impl Bolus {
pub fn new(time: f64, amount: f64, input: usize, occasion: usize) -> Self {
Bolus {
time,
amount,
input,
occasion,
}
}
pub fn amount(&self) -> f64 {
self.amount
}
pub fn input(&self) -> usize {
self.input
}
pub fn time(&self) -> f64 {
self.time
}
pub fn set_amount(&mut self, amount: f64) {
self.amount = amount;
}
pub fn set_input(&mut self, input: usize) {
self.input = input;
}
pub fn set_time(&mut self, time: f64) {
self.time = time;
}
pub fn mut_amount(&mut self) -> &mut f64 {
&mut self.amount
}
pub fn mut_input(&mut self) -> &mut usize {
&mut self.input
}
pub fn mut_time(&mut self) -> &mut f64 {
&mut self.time
}
pub fn occasion(&self) -> usize {
self.occasion
}
pub fn mut_occasion(&mut self) -> &mut usize {
&mut self.occasion
}
}
#[derive(Serialize, Debug, Clone, Deserialize)]
pub struct Infusion {
time: f64,
amount: f64,
input: usize,
duration: f64,
occasion: usize,
}
impl Infusion {
pub fn new(time: f64, amount: f64, input: usize, duration: f64, occasion: usize) -> Self {
Infusion {
time,
amount,
input,
duration,
occasion,
}
}
pub fn amount(&self) -> f64 {
self.amount
}
pub fn input(&self) -> usize {
self.input
}
pub fn duration(&self) -> f64 {
self.duration
}
pub fn time(&self) -> f64 {
self.time
}
pub fn set_amount(&mut self, amount: f64) {
self.amount = amount;
}
pub fn set_input(&mut self, input: usize) {
self.input = input;
}
pub fn set_time(&mut self, time: f64) {
self.time = time;
}
pub fn set_duration(&mut self, duration: f64) {
self.duration = duration;
}
pub fn mut_amount(&mut self) -> &mut f64 {
&mut self.amount
}
pub fn mut_input(&mut self) -> &mut usize {
&mut self.input
}
pub fn mut_time(&mut self) -> &mut f64 {
&mut self.time
}
pub fn mut_duration(&mut self) -> &mut f64 {
&mut self.duration
}
pub fn occasion(&self) -> usize {
self.occasion
}
pub fn mut_occasion(&mut self) -> &mut usize {
&mut self.occasion
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Censor {
#[default]
None,
BLOQ,
ALOQ,
}
#[derive(Serialize, Debug, Clone, Deserialize)]
pub struct Observation {
time: f64,
value: Option<f64>,
outeq: usize,
errorpoly: Option<ErrorPoly>,
occasion: usize,
censoring: Censor,
}
impl Observation {
pub(crate) fn new(
time: f64,
value: Option<f64>,
outeq: usize,
errorpoly: Option<ErrorPoly>,
occasion: usize,
censoring: Censor,
) -> Self {
Observation {
time,
value,
outeq,
errorpoly,
occasion,
censoring,
}
}
pub fn time(&self) -> f64 {
self.time
}
pub fn value(&self) -> Option<f64> {
self.value
}
pub fn outeq(&self) -> usize {
self.outeq
}
pub fn errorpoly(&self) -> Option<ErrorPoly> {
self.errorpoly
}
pub fn set_time(&mut self, time: f64) {
self.time = time;
}
pub fn set_value(&mut self, value: Option<f64>) {
self.value = value;
}
pub fn set_outeq(&mut self, outeq: usize) {
self.outeq = outeq;
}
pub fn set_errorpoly(&mut self, errorpoly: Option<ErrorPoly>) {
self.errorpoly = errorpoly;
}
pub fn mut_time(&mut self) -> &mut f64 {
&mut self.time
}
pub fn mut_value(&mut self) -> &mut Option<f64> {
&mut self.value
}
pub fn mut_outeq(&mut self) -> &mut usize {
&mut self.outeq
}
pub fn mut_errorpoly(&mut self) -> &mut Option<ErrorPoly> {
&mut self.errorpoly
}
pub fn occasion(&self) -> usize {
self.occasion
}
pub fn mut_occasion(&mut self) -> &mut usize {
&mut self.occasion
}
pub fn to_prediction(&self, pred: f64, state: Vec<f64>) -> Prediction {
Prediction {
time: self.time(),
observation: self.value(),
prediction: pred,
outeq: self.outeq(),
errorpoly: self.errorpoly(),
state,
occasion: self.occasion(),
censoring: self.censoring(),
}
}
pub fn censored(&self) -> bool {
match self.censoring {
Censor::None => false,
Censor::ALOQ => true,
Censor::BLOQ => true,
}
}
pub fn censoring(&self) -> Censor {
self.censoring
}
pub fn censor(&mut self, censor: Censor) {
self.censoring = censor;
}
pub fn mut_censoring(&mut self) -> &mut Censor {
&mut self.censoring
}
}
impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Event::Bolus(bolus) => write!(
f,
"Bolus at time {:.2} with amount {:.2} in compartment {}",
bolus.time, bolus.amount, bolus.input
),
Event::Infusion(infusion) => write!(
f,
"Infusion starting at {:.2} with amount {:.2} over {:.2} hours in compartment {}",
infusion.time, infusion.amount, infusion.duration, infusion.input
),
Event::Observation(observation) => {
let errpoly_desc = match observation.errorpoly {
Some(errorpoly) => {
format!(
"with error poly {} {} {} {}",
errorpoly.coefficients().0,
errorpoly.coefficients().1,
errorpoly.coefficients().2,
errorpoly.coefficients().3
)
}
None => "".to_string(),
};
write!(
f,
"Observation at time {:.2}: {:#?} (outeq {}) {}",
observation.time, observation.value, observation.outeq, errpoly_desc
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bolus_creation() {
let bolus = Bolus::new(2.5, 100.0, 1, 0);
assert_eq!(bolus.time(), 2.5);
assert_eq!(bolus.amount(), 100.0);
assert_eq!(bolus.input(), 1);
}
#[test]
fn test_bolus_setters() {
let mut bolus = Bolus::new(2.5, 100.0, 1, 0);
bolus.set_time(3.0);
assert_eq!(bolus.time(), 3.0);
bolus.set_amount(150.0);
assert_eq!(bolus.amount(), 150.0);
bolus.set_input(2);
assert_eq!(bolus.input(), 2);
}
#[test]
fn test_infusion_creation() {
let infusion = Infusion::new(1.0, 200.0, 1, 2.5, 0);
assert_eq!(infusion.time(), 1.0);
assert_eq!(infusion.amount(), 200.0);
assert_eq!(infusion.input(), 1);
assert_eq!(infusion.duration(), 2.5);
}
#[test]
fn test_infusion_setters() {
let mut infusion = Infusion::new(1.0, 200.0, 1, 2.5, 0);
infusion.set_time(1.5);
assert_eq!(infusion.time(), 1.5);
infusion.set_amount(250.0);
assert_eq!(infusion.amount(), 250.0);
infusion.set_input(2);
assert_eq!(infusion.input(), 2);
infusion.set_duration(3.0);
assert_eq!(infusion.duration(), 3.0);
}
#[test]
fn test_observation_creation() {
let error_poly = Some(ErrorPoly::new(0.1, 0.2, 0.3, 0.4));
let observation = Observation::new(5.0, Some(75.5), 2, error_poly, 0, Censor::None);
assert_eq!(observation.time(), 5.0);
assert_eq!(observation.value(), Some(75.5));
assert_eq!(observation.outeq(), 2);
assert_eq!(observation.errorpoly(), error_poly);
}
#[test]
fn test_observation_setters() {
let mut observation = Observation::new(
5.0,
Some(75.5),
2,
Some(ErrorPoly::new(0.1, 0.2, 0.3, 0.4)),
0,
Censor::None,
);
observation.set_time(6.0);
assert_eq!(observation.time(), 6.0);
observation.set_value(Some(80.0));
assert_eq!(observation.value(), Some(80.0));
observation.set_outeq(3);
assert_eq!(observation.outeq(), 3);
let new_error_poly = Some(ErrorPoly::new(0.2, 0.3, 0.4, 0.5));
observation.set_errorpoly(new_error_poly);
assert_eq!(observation.errorpoly(), new_error_poly);
}
#[test]
fn test_event_time_operations() {
let mut bolus_event = Event::Bolus(Bolus::new(1.0, 100.0, 1, 0));
let mut infusion_event = Event::Infusion(Infusion::new(2.0, 200.0, 1, 2.5, 0));
let mut observation_event =
Event::Observation(Observation::new(3.0, Some(75.5), 2, None, 0, Censor::None));
assert_eq!(bolus_event.time(), 1.0);
assert_eq!(infusion_event.time(), 2.0);
assert_eq!(observation_event.time(), 3.0);
bolus_event.inc_time(0.5);
infusion_event.inc_time(0.5);
observation_event.inc_time(0.5);
assert_eq!(bolus_event.time(), 1.5);
assert_eq!(infusion_event.time(), 2.5);
assert_eq!(observation_event.time(), 3.5);
}
}