use crate::data::acquisition::AcquisitionMode;
use crate::data::handle::{IndexConverter, TimsData, TimsDataLoader};
use crate::data::meta::{read_dda_precursor_meta, read_global_meta_sql, read_meta_data_sql, read_pasef_frame_ms_ms_info, DDAPrecursor, DDAPrecursorMeta, PasefMsMsMeta};
use mscore::timstof::frame::{ImsFrame, RawTimsFrame, TimsFrame};
use mscore::timstof::slice::TimsSlice;
use mscore::timstof::spectrum_processing::{
PASEFFragmentData, PreprocessedSpectrum, SpectrumProcessingConfig,
process_pasef_fragments_batch,
};
use rayon::prelude::*;
use rayon::ThreadPoolBuilder;
use std::collections::BTreeMap;
use rand::prelude::IteratorRandom;
use mscore::data::spectrum::MsType;
use std::collections::HashMap;
#[derive(Clone)]
pub struct PASEFDDAFragment {
pub frame_id: u32,
pub precursor_id: u32,
pub collision_energy: f64,
pub selected_fragment: TimsFrame,
}
#[derive(Clone, Debug, Default)]
pub struct SignalMoments {
pub mean: f64,
pub variance: f64,
pub skewness: f64,
pub apex: f64,
pub fwhm: f64,
pub total_intensity: f64,
}
impl SignalMoments {
pub fn from_signal(coords: &[f64], intensities: &[f64]) -> Self {
if coords.is_empty() || intensities.iter().sum::<f64>() == 0.0 {
return Self::default();
}
let total: f64 = intensities.iter().sum();
let mean: f64 = coords.iter()
.zip(intensities.iter())
.map(|(c, i)| c * i / total)
.sum();
let variance: f64 = coords.iter()
.zip(intensities.iter())
.map(|(c, i)| i / total * (c - mean).powi(2))
.sum();
let std = variance.sqrt().max(1e-10);
let skewness: f64 = coords.iter()
.zip(intensities.iter())
.map(|(c, i)| i / total * ((c - mean) / std).powi(3))
.sum();
let apex_idx = intensities.iter()
.enumerate()
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
.map(|(i, _)| i)
.unwrap_or(0);
let apex = coords.get(apex_idx).copied().unwrap_or(0.0);
let half_max = intensities.get(apex_idx).copied().unwrap_or(0.0) / 2.0;
let above_half: Vec<f64> = coords.iter()
.zip(intensities.iter())
.filter(|(_, i)| **i >= half_max)
.map(|(c, _)| *c)
.collect();
let fwhm = if above_half.len() >= 2 {
above_half.last().unwrap_or(&0.0) - above_half.first().unwrap_or(&0.0)
} else {
2.355 * std };
SignalMoments {
mean,
variance,
skewness,
apex,
fwhm,
total_intensity: total,
}
}
}
#[derive(Clone, Debug)]
pub struct PrecursorMS1Signal {
pub precursor_id: u32,
pub rt_coords: Vec<f64>, pub rt_intensities: Vec<f64>,
pub rt_moments: SignalMoments,
pub im_coords: Vec<f64>, pub im_intensities: Vec<f64>,
pub im_moments: SignalMoments,
pub isotope_mz: Vec<f64>,
pub isotope_intensity: Vec<f64>,
pub mz_moments: SignalMoments,
pub raw_rt: Vec<f64>, pub raw_mz: Vec<f64>, pub raw_mobility: Vec<f64>, pub raw_intensity: Vec<f64>, }
#[derive(Clone, Debug)]
pub struct PrecursorCoord {
pub precursor_id: u32,
pub mz: f64, pub mono_mz: f64, pub rt_seconds: f64,
pub mobility: f64, pub im_start: f64, pub im_end: f64, pub charge: i32,
}
pub struct TimsDatasetDDA {
pub loader: TimsDataLoader,
pub pasef_meta: Vec<PasefMsMsMeta>,
}
impl TimsDatasetDDA {
pub fn new(
bruker_lib_path: &str,
data_path: &str,
in_memory: bool,
use_bruker_sdk: bool,
) -> Self {
let global_meta_data = read_global_meta_sql(data_path).unwrap();
let meta_data = read_meta_data_sql(data_path).unwrap();
let scan_max_index = meta_data.iter().map(|x| x.num_scans).max().unwrap() as u32;
let im_lower = global_meta_data.one_over_k0_range_lower;
let im_upper = global_meta_data.one_over_k0_range_upper;
let tof_max_index = global_meta_data.tof_max_index;
let mz_lower = global_meta_data.mz_acquisition_range_lower;
let mz_upper = global_meta_data.mz_acquisition_range_upper;
let loader = match in_memory {
true => TimsDataLoader::new_in_memory(
bruker_lib_path,
data_path,
use_bruker_sdk,
scan_max_index,
im_lower,
im_upper,
tof_max_index,
mz_lower,
mz_upper,
),
false => TimsDataLoader::new_lazy(
bruker_lib_path,
data_path,
use_bruker_sdk,
scan_max_index,
im_lower,
im_upper,
tof_max_index,
mz_lower,
mz_upper,
),
};
let pasef_meta = read_pasef_frame_ms_ms_info(data_path).unwrap();
TimsDatasetDDA { loader, pasef_meta }
}
pub fn new_with_calibration(
data_path: &str,
in_memory: bool,
im_lookup: Vec<f64>,
) -> Self {
let global_meta_data = read_global_meta_sql(data_path).unwrap();
let tof_max_index = global_meta_data.tof_max_index;
let mz_lower = global_meta_data.mz_acquisition_range_lower;
let mz_upper = global_meta_data.mz_acquisition_range_upper;
let loader = match in_memory {
true => TimsDataLoader::new_in_memory_with_calibration(
data_path,
tof_max_index,
mz_lower,
mz_upper,
im_lookup,
),
false => TimsDataLoader::new_lazy_with_calibration(
data_path,
tof_max_index,
mz_lower,
mz_upper,
im_lookup,
),
};
let pasef_meta = read_pasef_frame_ms_ms_info(data_path).unwrap();
TimsDatasetDDA { loader, pasef_meta }
}
pub fn new_with_mz_calibration(
data_path: &str,
in_memory: bool,
tof_intercept: f64,
tof_slope: f64,
) -> Self {
let global_meta_data = read_global_meta_sql(data_path).unwrap();
let frame_meta = read_meta_data_sql(data_path).unwrap();
let scan_max_index = frame_meta.iter().map(|x| x.num_scans).max().unwrap() as u32;
let im_lower = global_meta_data.one_over_k0_range_lower;
let im_upper = global_meta_data.one_over_k0_range_upper;
let loader = match in_memory {
true => TimsDataLoader::new_in_memory_with_mz_calibration(
data_path,
tof_intercept,
tof_slope,
im_lower,
im_upper,
scan_max_index,
),
false => TimsDataLoader::new_lazy_with_mz_calibration(
data_path,
tof_intercept,
tof_slope,
im_lower,
im_upper,
scan_max_index,
),
};
let pasef_meta = read_pasef_frame_ms_ms_info(data_path).unwrap();
TimsDatasetDDA { loader, pasef_meta }
}
pub fn uses_bruker_sdk(&self) -> bool {
self.loader.uses_bruker_sdk()
}
pub fn get_selected_precursors(&self) -> Vec<DDAPrecursor> {
let precursor_meta = read_dda_precursor_meta(&self.loader.get_data_path()).unwrap();
let pasef_meta = &self.pasef_meta;
let precursor_id_to_pasef_meta: BTreeMap<i64, &PasefMsMsMeta> = pasef_meta
.iter()
.map(|x| (x.precursor_id as i64, x))
.collect();
let result: Vec<_> = precursor_meta
.iter()
.map(|precursor| {
let pasef_meta = precursor_id_to_pasef_meta
.get(&precursor.precursor_id)
.unwrap();
DDAPrecursor {
frame_id: precursor.precursor_frame_id,
precursor_id: precursor.precursor_id,
mono_mz: precursor.precursor_mz_monoisotopic,
highest_intensity_mz: precursor.precursor_mz_highest_intensity,
average_mz: precursor.precursor_mz_average,
charge: precursor.precursor_charge,
inverse_ion_mobility: self.scan_to_inverse_mobility(
precursor.precursor_frame_id as u32,
&vec![precursor.precursor_average_scan_number as u32],
)[0],
collision_energy: pasef_meta.collision_energy,
precuror_total_intensity: precursor.precursor_total_intensity,
isolation_mz: pasef_meta.isolation_mz,
isolation_width: pasef_meta.isolation_width,
}
})
.collect();
result
}
pub fn get_precursor_frames(
&self,
min_intensity: f64,
max_num_peaks: usize,
num_threads: usize,
) -> Vec<TimsFrame> {
let meta_data = read_meta_data_sql(&self.loader.get_data_path()).unwrap();
let precursor_frames = meta_data.iter().filter(|x| x.ms_ms_type == 0);
let tims_silce =
self.get_slice(precursor_frames.map(|x| x.id as u32).collect(), num_threads);
let result: Vec<_> = tims_silce
.frames
.par_iter()
.map(|frame| {
frame
.filter_ranged(0.0, 2000.0, 0, 2000, 0.0, 5.0, min_intensity, 1e9, 0, i32::MAX)
.top_n(max_num_peaks)
})
.collect();
result
}
pub fn extract_precursor_ms1_signals(
&self,
precursor_coords: Vec<PrecursorCoord>,
rt_window_sec: f64,
mz_tol_ppm: f64,
im_window: f64,
n_isotopes: usize,
num_threads: usize,
) -> Vec<PrecursorMS1Signal> {
if precursor_coords.is_empty() {
return Vec::new();
}
let meta_data = read_meta_data_sql(&self.loader.get_data_path()).unwrap();
let mut ms1_frame_info: Vec<(u32, f64)> = meta_data
.iter()
.filter(|f| f.ms_ms_type == 0)
.map(|f| (f.id as u32, f.time))
.collect();
ms1_frame_info.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
let ms1_times: Vec<f64> = ms1_frame_info.iter().map(|(_, t)| *t).collect();
let mut sorted_coords: Vec<(usize, &PrecursorCoord)> = precursor_coords
.iter()
.enumerate()
.collect();
sorted_coords.sort_by(|a, b| a.1.rt_seconds.partial_cmp(&b.1.rt_seconds).unwrap());
let batch_size_sec = 300.0;
let mut results: Vec<(usize, PrecursorMS1Signal)> = Vec::with_capacity(precursor_coords.len());
let mut batch_start = 0;
while batch_start < sorted_coords.len() {
let batch_rt_start = sorted_coords[batch_start].1.rt_seconds;
let batch_rt_end = batch_rt_start + batch_size_sec;
let mut batch_end = batch_start;
while batch_end < sorted_coords.len() && sorted_coords[batch_end].1.rt_seconds < batch_rt_end {
batch_end += 1;
}
let frame_rt_min = batch_rt_start - rt_window_sec;
let frame_rt_max = batch_rt_end + rt_window_sec;
let frame_start_idx = ms1_times.partition_point(|t| *t < frame_rt_min);
let frame_end_idx = ms1_times.partition_point(|t| *t <= frame_rt_max);
let batch_frame_ids: Vec<u32> = ms1_frame_info[frame_start_idx..frame_end_idx]
.iter()
.map(|(id, _)| *id)
.collect();
let batch_frames = if !batch_frame_ids.is_empty() {
self.loader.get_slice(batch_frame_ids, num_threads)
} else {
TimsSlice { frames: Vec::new() }
};
let batch_times: Vec<f64> = ms1_times[frame_start_idx..frame_end_idx].to_vec();
let batch_coords = &sorted_coords[batch_start..batch_end];
let pool = ThreadPoolBuilder::new()
.num_threads(num_threads)
.build()
.unwrap();
let batch_results: Vec<(usize, PrecursorMS1Signal)> = pool.install(|| {
batch_coords.par_iter().map(|(orig_idx, coord)| {
let signal = Self::extract_single_precursor(
coord,
&batch_frames.frames,
&batch_times,
rt_window_sec,
mz_tol_ppm,
im_window,
n_isotopes,
);
(*orig_idx, signal)
}).collect()
});
results.extend(batch_results);
batch_start = batch_end;
}
results.sort_by_key(|(idx, _)| *idx);
results.into_iter().map(|(_, signal)| signal).collect()
}
fn extract_single_precursor(
coord: &PrecursorCoord,
frames: &[TimsFrame],
frame_times: &[f64],
rt_window_sec: f64,
mz_tol_ppm: f64,
im_window: f64,
n_isotopes: usize,
) -> PrecursorMS1Signal {
let rt_sec = coord.rt_seconds;
let rt_min = rt_sec - rt_window_sec / 2.0;
let rt_max = rt_sec + rt_window_sec / 2.0;
let start_idx = frame_times.partition_point(|t| *t < rt_min);
let end_idx = frame_times.partition_point(|t| *t <= rt_max);
let isotope_spacing = 1.003355 / (coord.charge.max(1) as f64);
let n_isotopes_to_extract = 4.min(n_isotopes);
let has_mono_mz = coord.mono_mz > 0.0;
let base_mz = if has_mono_mz { coord.mono_mz } else { coord.mz };
let mz_tol = base_mz * mz_tol_ppm / 1e6;
let isotope_mz_values: Vec<f64> = (0..n_isotopes_to_extract)
.map(|i| base_mz + (i as f64) * isotope_spacing)
.collect();
let (xic_mz_min, xic_mz_max) = if has_mono_mz {
(base_mz - mz_tol, base_mz + ((n_isotopes_to_extract - 1) as f64) * isotope_spacing + mz_tol)
} else {
(coord.mz - mz_tol, coord.mz + mz_tol)
};
let im_min = coord.mobility - im_window / 2.0;
let im_max = coord.mobility + im_window / 2.0;
let n_frames = end_idx.saturating_sub(start_idx);
let mut rt_coords = Vec::with_capacity(n_frames);
let mut rt_intensities = Vec::with_capacity(n_frames);
let mut im_dict: HashMap<i64, f64> = HashMap::new();
let mut isotope_intensity = vec![0.0f64; n_isotopes];
let mut raw_rt = Vec::new();
let mut raw_mz = Vec::new();
let mut raw_mobility = Vec::new();
let mut raw_intensity = Vec::new();
for idx in start_idx..end_idx.min(frames.len()) {
let frame_time = frame_times[idx];
let frame = &frames[idx];
let xic_filtered = frame.filter_ranged(
xic_mz_min, xic_mz_max,
0, 1000,
im_min, im_max,
0.0, 1e9,
0, i32::MAX,
);
let xic_intensity: f64 = xic_filtered.ims_frame.intensity.iter().sum();
rt_coords.push(frame_time);
rt_intensities.push(xic_intensity);
for (mob, inten) in xic_filtered.ims_frame.mobility.iter().zip(xic_filtered.ims_frame.intensity.iter()) {
let mob_bin = (*mob * 1000.0).round() as i64;
*im_dict.entry(mob_bin).or_insert(0.0) += *inten;
}
for (iso_idx, iso_mz) in isotope_mz_values.iter().enumerate() {
let iso_peak_min = iso_mz - mz_tol;
let iso_peak_max = iso_mz + mz_tol;
let iso_intensity_sum: f64 = xic_filtered.ims_frame.mz.iter()
.zip(xic_filtered.ims_frame.intensity.iter())
.filter(|(mz, _)| **mz >= iso_peak_min && **mz <= iso_peak_max)
.map(|(_, i)| *i)
.sum();
isotope_intensity[iso_idx] += iso_intensity_sum;
}
let n_peaks = xic_filtered.ims_frame.mz.len();
for i in 0..n_peaks {
raw_rt.push(frame_time);
raw_mz.push(xic_filtered.ims_frame.mz[i]);
raw_mobility.push(xic_filtered.ims_frame.mobility[i]);
raw_intensity.push(xic_filtered.ims_frame.intensity[i]);
}
}
let mut im_entries: Vec<(i64, f64)> = im_dict.into_iter().collect();
im_entries.sort_by_key(|(k, _)| *k);
let im_coords: Vec<f64> = im_entries.iter().map(|(k, _)| *k as f64 / 1000.0).collect();
let im_intensities: Vec<f64> = im_entries.iter().map(|(_, v)| *v).collect();
let rt_moments = SignalMoments::from_signal(&rt_coords, &rt_intensities);
let im_moments = SignalMoments::from_signal(&im_coords, &im_intensities);
let mz_moments = SignalMoments::from_signal(&isotope_mz_values, &isotope_intensity);
PrecursorMS1Signal {
precursor_id: coord.precursor_id,
rt_coords,
rt_intensities,
rt_moments,
im_coords,
im_intensities,
im_moments,
isotope_mz: isotope_mz_values,
isotope_intensity,
mz_moments,
raw_rt,
raw_mz,
raw_mobility,
raw_intensity,
}
}
pub fn get_pasef_frame_ms_ms_info(&self) -> Vec<PasefMsMsMeta> {
read_pasef_frame_ms_ms_info(&self.loader.get_data_path()).unwrap()
}
pub fn get_pasef_fragments(&self, num_threads: usize) -> Vec<PASEFDDAFragment> {
self.get_pasef_fragments_for_precursors(None, num_threads)
}
pub fn get_pasef_fragments_for_precursors(
&self,
precursor_ids: Option<&[u32]>,
num_threads: usize,
) -> Vec<PASEFDDAFragment> {
let pasef_info = self.get_pasef_frame_ms_ms_info();
let filtered_pasef_info: Vec<&PasefMsMsMeta> = match precursor_ids {
Some(ids) => {
let id_set: std::collections::HashSet<u32> = ids.iter().copied().collect();
pasef_info.iter()
.filter(|info| id_set.contains(&(info.precursor_id as u32)))
.collect()
}
None => pasef_info.iter().collect(),
};
let uses_bruker_sdk = self.loader.uses_bruker_sdk();
let process_fragment = |pasef_info: &PasefMsMsMeta| -> PASEFDDAFragment {
let frame = self.loader.get_frame(pasef_info.frame_id as u32);
let scan_margin = (pasef_info.scan_num_end - pasef_info.scan_num_begin) / 20;
let filtered_frame = frame.filter_ranged(
0.0,
2000.0,
(pasef_info.scan_num_begin - scan_margin) as i32,
(pasef_info.scan_num_end + scan_margin) as i32,
0.0,
5.0,
0.0,
1e9,
0,
i32::MAX,
);
PASEFDDAFragment {
frame_id: pasef_info.frame_id as u32,
precursor_id: pasef_info.precursor_id as u32,
collision_energy: pasef_info.collision_energy,
selected_fragment: filtered_frame,
}
};
if uses_bruker_sdk {
filtered_pasef_info.iter().map(|info| process_fragment(info)).collect()
} else {
let pool = ThreadPoolBuilder::new()
.num_threads(num_threads)
.build()
.unwrap();
pool.install(|| {
filtered_pasef_info.par_iter().map(|info| process_fragment(info)).collect()
})
}
}
pub fn get_preprocessed_pasef_fragments(
&self,
dataset_name: &str,
config: SpectrumProcessingConfig,
num_threads: usize,
) -> Vec<PreprocessedSpectrum> {
let pasef_info = self.get_pasef_frame_ms_ms_info();
let precursor_meta = read_dda_precursor_meta(&self.loader.get_data_path()).unwrap_or_default();
let frame_meta = read_meta_data_sql(&self.loader.get_data_path()).unwrap_or_default();
let precursor_map: BTreeMap<i64, &DDAPrecursorMeta> = precursor_meta
.iter()
.map(|p| (p.precursor_id, p))
.collect();
let frame_time_map: BTreeMap<i64, f64> = frame_meta
.iter()
.map(|f| (f.id, f.time / 60.0)) .collect();
let mut pasef_by_precursor: BTreeMap<i64, Vec<&PasefMsMsMeta>> = BTreeMap::new();
for info in &pasef_info {
pasef_by_precursor
.entry(info.precursor_id)
.or_insert_with(Vec::new)
.push(info);
}
let uses_bruker_sdk = self.loader.uses_bruker_sdk();
let process_precursor = |(precursor_id, pasef_infos): (&i64, &Vec<&PasefMsMsMeta>)| -> Option<PASEFFragmentData> {
let precursor = precursor_map.get(precursor_id)?;
let first_pasef = pasef_infos.first()?;
let scan_start_time = frame_time_map.get(&first_pasef.frame_id).copied().unwrap_or(0.0);
let mut combined_scan = Vec::new();
let mut combined_mobility = Vec::new();
let mut combined_tof = Vec::new();
let mut combined_mz = Vec::new();
let mut combined_intensity = Vec::new();
for pasef_info in pasef_infos {
let frame = self.loader.get_frame(pasef_info.frame_id as u32);
let scan_margin = (pasef_info.scan_num_end - pasef_info.scan_num_begin) / 20;
let filtered_frame = frame.filter_ranged(
0.0,
2000.0,
(pasef_info.scan_num_begin - scan_margin) as i32,
(pasef_info.scan_num_end + scan_margin) as i32,
0.0,
5.0,
0.0,
1e9,
0,
i32::MAX,
);
combined_scan.extend(filtered_frame.scan.iter());
combined_mobility.extend(filtered_frame.ims_frame.mobility.iter());
combined_tof.extend(filtered_frame.tof.iter());
combined_mz.extend(filtered_frame.ims_frame.mz.iter());
combined_intensity.extend(filtered_frame.ims_frame.intensity.iter());
}
if combined_mz.is_empty() {
return None;
}
let precursor_mz = precursor.precursor_mz_monoisotopic
.unwrap_or(precursor.precursor_mz_highest_intensity);
Some(PASEFFragmentData {
frame_id: first_pasef.frame_id as u32,
precursor_id: *precursor_id as u32,
collision_energy: first_pasef.collision_energy,
scan_start_time,
scan: combined_scan,
mobility: combined_mobility,
tof: combined_tof,
mz: combined_mz,
intensity: combined_intensity,
precursor_mz,
precursor_charge: precursor.precursor_charge.map(|c| c as i32),
precursor_intensity: precursor.precursor_total_intensity,
isolation_mz: first_pasef.isolation_mz,
isolation_width: first_pasef.isolation_width,
})
};
let fragment_data: Vec<PASEFFragmentData> = if uses_bruker_sdk {
pasef_by_precursor
.iter()
.filter_map(process_precursor)
.collect()
} else {
let pool = ThreadPoolBuilder::new()
.num_threads(num_threads)
.build()
.unwrap();
pool.install(|| {
pasef_by_precursor
.par_iter()
.filter_map(|item| process_precursor(item))
.collect()
})
};
process_pasef_fragments_batch(fragment_data, dataset_name, &config, num_threads)
}
pub fn sample_pasef_fragment_random(
&self,
target_scan_apex: i32,
experiment_max_scan: i32,
) -> TimsFrame {
let pasef_meta = &self.pasef_meta;
let random_index = rand::random::<usize>() % pasef_meta.len();
let pasef_info = &pasef_meta[random_index];
let frame = self.loader.get_frame(pasef_info.frame_id as u32);
let scan_margin = (pasef_info.scan_num_end - pasef_info.scan_num_begin) / 20;
let mut filtered = frame.filter_ranged(
0.0,
2000.0,
(pasef_info.scan_num_begin - scan_margin) as i32,
(pasef_info.scan_num_end + scan_margin) as i32,
0.0,
5.0,
0.0,
1e9,
0,
i32::MAX,
);
if filtered.scan.is_empty() {
return filtered;
}
let mut scan_copy = filtered.scan.clone();
scan_copy.sort_unstable();
let median_scan = scan_copy[scan_copy.len() / 2];
let scan_shift = target_scan_apex - median_scan;
for s in filtered.scan.iter_mut() {
*s += scan_shift;
}
let re_filtered = filtered.filter_ranged(
0.0,
2000.0,
0,
experiment_max_scan,
0.0,
5.0,
0.0,
1e9,
0,
i32::MAX,
);
re_filtered
}
pub fn sample_pasef_fragments_random(
&self,
target_scan_apex_values: Vec<i32>,
experiment_max_scan: i32,
) -> TimsFrame {
if target_scan_apex_values.is_empty() {
return TimsFrame {
frame_id: 0, ms_type: MsType::FragmentDda,
scan: Vec::new(),
tof: Vec::new(),
ims_frame: ImsFrame::default(), }
}
let mut pasef_frames = Vec::new();
for target_scan_apex in target_scan_apex_values {
let pasef_frame = self.sample_pasef_fragment_random(target_scan_apex, experiment_max_scan);
pasef_frames.push(pasef_frame);
}
let mut combined_frame = pasef_frames[0].clone();
for frame in pasef_frames.iter().skip(1) {
combined_frame = combined_frame + frame.clone();
}
let im_values = self.scan_to_inverse_mobility(
combined_frame.frame_id as u32,
&combined_frame.scan.iter().map(|x| *x as u32).collect(),
);
combined_frame.ims_frame.mobility = std::sync::Arc::new(im_values);
combined_frame
}
pub fn sample_precursor_signal(
&self,
num_frames: usize,
max_intensity: f64,
take_probability: f64,
) -> TimsFrame {
let meta_data = read_meta_data_sql(&self.loader.get_data_path()).unwrap();
let precursor_frames = meta_data.iter().filter(|x| x.ms_ms_type == 0);
let mut rng = rand::thread_rng();
let mut sampled_frames: Vec<TimsFrame> = Vec::new();
for frame in precursor_frames.choose_multiple(&mut rng, num_frames) {
let frame_id = frame.id;
let frame_data = self
.loader
.get_frame(frame_id as u32)
.filter_ranged(0.0, 2000.0, 0, 1000, 0.0, 5.0, 1.0, max_intensity, 0, i32::MAX)
.generate_random_sample(take_probability);
sampled_frames.push(frame_data);
}
let mut sampled_frame = sampled_frames.remove(0);
for frame in sampled_frames {
sampled_frame = sampled_frame + frame;
}
sampled_frame
}
}
impl TimsData for TimsDatasetDDA {
fn get_frame(&self, frame_id: u32) -> TimsFrame {
self.loader.get_frame(frame_id)
}
fn get_raw_frame(&self, frame_id: u32) -> RawTimsFrame {
self.loader.get_raw_frame(frame_id)
}
fn get_slice(&self, frame_ids: Vec<u32>, num_threads: usize) -> TimsSlice {
self.loader.get_slice(frame_ids, num_threads)
}
fn get_acquisition_mode(&self) -> AcquisitionMode {
self.loader.get_acquisition_mode().clone()
}
fn get_frame_count(&self) -> i32 {
self.loader.get_frame_count()
}
fn get_data_path(&self) -> &str {
&self.loader.get_data_path()
}
}
impl IndexConverter for TimsDatasetDDA {
fn tof_to_mz(&self, frame_id: u32, tof_values: &Vec<u32>) -> Vec<f64> {
self.loader
.get_index_converter()
.tof_to_mz(frame_id, tof_values)
}
fn mz_to_tof(&self, frame_id: u32, mz_values: &Vec<f64>) -> Vec<u32> {
self.loader
.get_index_converter()
.mz_to_tof(frame_id, mz_values)
}
fn scan_to_inverse_mobility(&self, frame_id: u32, scan_values: &Vec<u32>) -> Vec<f64> {
self.loader
.get_index_converter()
.scan_to_inverse_mobility(frame_id, scan_values)
}
fn inverse_mobility_to_scan(
&self,
frame_id: u32,
inverse_mobility_values: &Vec<f64>,
) -> Vec<u32> {
self.loader
.get_index_converter()
.inverse_mobility_to_scan(frame_id, inverse_mobility_values)
}
}