pmcore/bestdose/
predictions.rs1use pharmsol::prelude::*;
11
12pub fn find_last_dose_time_before(subject: &Subject, obs_time: f64) -> f64 {
15 let mut last_dose_time = 0.0;
16
17 for occasion in subject.occasions() {
18 for event in occasion.events() {
19 let event_time = match event {
20 Event::Bolus(b) => Some(b.time()),
21 Event::Infusion(i) => Some(i.time()),
22 Event::Observation(_) => None,
23 };
24
25 if let Some(t) = event_time {
26 if t < obs_time && t > last_dose_time {
27 last_dose_time = t;
28 }
29 }
30 }
31 }
32
33 last_dose_time
34}
35
36pub fn calculate_dense_times(
42 start_time: f64,
43 end_time: f64,
44 obs_times: &[f64],
45 idelta: f64,
46) -> Vec<f64> {
47 let mut times = Vec::new();
48
49 times.extend_from_slice(obs_times);
50
51 if idelta > 0.0 {
52 let mut t = start_time;
53 while t <= end_time {
54 times.push(t);
55 t += idelta;
56 }
57 }
58
59 if !times.contains(&end_time) {
60 times.push(end_time);
61 }
62
63 times.sort_by(|a, b| a.partial_cmp(b).unwrap());
64
65 let tolerance = 1e-10;
66 let mut unique_times = Vec::new();
67 let mut last_time = f64::NEG_INFINITY;
68
69 for &t in × {
70 if (t - last_time).abs() > tolerance {
71 unique_times.push(t);
72 last_time = t;
73 }
74 }
75
76 unique_times
77}
78
79pub fn calculate_auc_at_times(
84 dense_times: &[f64],
85 dense_predictions: &[f64],
86 target_times: &[f64],
87) -> Vec<f64> {
88 assert_eq!(dense_times.len(), dense_predictions.len());
89
90 let mut target_aucs = Vec::with_capacity(target_times.len());
91 let mut auc = 0.0;
92 let mut target_idx = 0;
93 let tolerance = 1e-10;
94
95 for i in 1..dense_times.len() {
96 let dt = dense_times[i] - dense_times[i - 1];
97 let avg_conc = (dense_predictions[i] + dense_predictions[i - 1]) / 2.0;
98 auc += avg_conc * dt;
99
100 if target_idx < target_times.len()
101 && (dense_times[i] - target_times[target_idx]).abs() < tolerance
102 {
103 target_aucs.push(auc);
104 target_idx += 1;
105 }
106 }
107
108 target_aucs
109}
110
111pub fn calculate_interval_auc_per_observation(
116 subject: &Subject,
117 dense_times: &[f64],
118 dense_predictions: &[f64],
119 obs_times: &[f64],
120) -> Vec<f64> {
121 assert_eq!(dense_times.len(), dense_predictions.len());
122
123 let mut interval_aucs = Vec::with_capacity(obs_times.len());
124 let tolerance = 1e-10;
125
126 for &obs_time in obs_times {
127 let last_dose_time = find_last_dose_time_before(subject, obs_time);
128
129 let start_idx = dense_times
130 .iter()
131 .position(|&t| (t - last_dose_time).abs() < tolerance || t > last_dose_time)
132 .unwrap_or(0);
133
134 let end_idx = dense_times
135 .iter()
136 .position(|&t| (t - obs_time).abs() < tolerance || t > obs_time)
137 .unwrap_or(dense_times.len() - 1);
138
139 let mut auc = 0.0;
140 for i in (start_idx + 1)..=end_idx.min(dense_times.len() - 1) {
141 let dt = dense_times[i] - dense_times[i - 1];
142 let avg_conc = (dense_predictions[i] + dense_predictions[i - 1]) / 2.0;
143 auc += avg_conc * dt;
144 }
145
146 interval_aucs.push(auc);
147 }
148
149 interval_aucs
150}