From a673946e24c05735fd49192b5804642e3f66b2d2 Mon Sep 17 00:00:00 2001 From: "J. Sebastian Paez" Date: Thu, 1 Aug 2024 06:51:26 -0700 Subject: [PATCH 1/3] (feature) reparametrized splitting to 1/k0 terms --- src/io/readers/precursor_reader/tdf/dia.rs | 3 +- src/io/readers/quad_settings_reader.rs | 74 +++++++++++++------ src/io/readers/spectrum_reader/tdf.rs | 1 + src/io/readers/spectrum_reader/tdf/dia.rs | 5 +- .../spectrum_reader/tdf/raw_spectra.rs | 4 +- tests/spectrum_readers.rs | 17 +++-- 6 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/io/readers/precursor_reader/tdf/dia.rs b/src/io/readers/precursor_reader/tdf/dia.rs index 9eacaa7..c0986de 100644 --- a/src/io/readers/precursor_reader/tdf/dia.rs +++ b/src/io/readers/precursor_reader/tdf/dia.rs @@ -34,8 +34,9 @@ impl DIATDFPrecursorReader { let im_converter: Scan2ImConverter = metadata.im_converter; let expanded_quadrupole_settings = QuadrupoleSettingsReader::from_splitting( - tdf_sql_reader.get_path(), + &tdf_sql_reader, splitting_strategy, + Some(&im_converter), )?; let reader = Self { expanded_quadrupole_settings, diff --git a/src/io/readers/quad_settings_reader.rs b/src/io/readers/quad_settings_reader.rs index 6f5f398..a18bce3 100644 --- a/src/io/readers/quad_settings_reader.rs +++ b/src/io/readers/quad_settings_reader.rs @@ -1,6 +1,10 @@ use std::path::Path; -use crate::{ms_data::QuadrupoleSettings, utils::vec_utils::argsort}; +use crate::{ + domain_converters::{ConvertableDomain, Scan2ImConverter}, + ms_data::QuadrupoleSettings, + utils::vec_utils::argsort, +}; use super::file_readers::sql_reader::{ frame_groups::SqlWindowGroup, quad_settings::SqlQuadSettings, @@ -48,11 +52,11 @@ impl QuadrupoleSettingsReader { } pub fn from_splitting( - path: impl AsRef, + tdf_sql_reader: &SqlReader, splitting_strat: FrameWindowSplittingStrategy, + scan_converter: Option<&Scan2ImConverter>, ) -> Result, QuadrupoleSettingsReaderError> { - let sql_path = path.as_ref(); - let tdf_sql_reader = SqlReader::open(&sql_path)?; + let sql_path = tdf_sql_reader.get_path(); let quadrupole_settings = Self::from_sql_settings(&tdf_sql_reader)?; let window_groups = SqlWindowGroup::from_sql_reader(&tdf_sql_reader)?; let expanded_quadrupole_settings = match splitting_strat { @@ -61,11 +65,15 @@ impl QuadrupoleSettingsReader { &window_groups, &quadrupole_settings, &x, + scan_converter, ) }, - FrameWindowSplittingStrategy::Window(x) => { - expand_window_settings(&window_groups, &quadrupole_settings, &x) - }, + FrameWindowSplittingStrategy::Window(x) => expand_window_settings( + &window_groups, + &quadrupole_settings, + &x, + scan_converter, + ), }; Ok(expanded_quadrupole_settings) } @@ -120,7 +128,7 @@ pub enum QuadrupoleSettingsReaderError { SqlError(#[from] SqlError), } -type SpanStep = (usize, usize); +type SpanStep = (f64, f64); /// Strategy for expanding quadrupole settings /// @@ -136,9 +144,9 @@ type SpanStep = (usize, usize); /// subwindows; e.g. if `usize` is 2, the window will be split into 2 subwindows /// of equal width. /// * `Uniform(SpanStep)` - Split the quadrupole settings into subwindows of -/// width `SpanStep.0` and step `SpanStep.1`; e.g. if `SpanStep` is (100, 50), -/// the window will be split into subwindows of width 100 and step 50 between their -/// scan start and end. +/// width `SpanStep.0` and step `SpanStep.1`; e.g. if `SpanStep` is (0.05, 0.02), +/// the window will be split into subwindows of width 0.05 and step 0.02 between their +/// in the mobility dimension. /// #[derive(Debug, Copy, Clone)] pub enum QuadWindowExpansionStrategy { @@ -163,8 +171,9 @@ fn scan_range_subsplit( start: usize, end: usize, strategy: &QuadWindowExpansionStrategy, + converter: Option<&Scan2ImConverter>, ) -> Vec<(usize, usize)> { - let out = match strategy { + let out: Vec<(usize, usize)> = match strategy { QuadWindowExpansionStrategy::None => { vec![(start, end)] }, @@ -182,16 +191,29 @@ fn scan_range_subsplit( out }, QuadWindowExpansionStrategy::Uniform((span, step)) => { - let mut curr_start = start.clone(); - let mut curr_end = start + span; + let converter = converter + .as_ref() + .expect("Uniform expansion requires a scan to IM converter"); + + // Since scan start < scan end but low scans are high IMs, we need to + // subtract instead of adding. + let mut curr_start_offset = start.clone(); + let mut curr_start_im = converter.convert(curr_start_offset as f64); + + let mut curr_end_im = curr_start_im - span; + let mut curr_end_offset = converter.invert(curr_end_im) as usize; let mut out = Vec::new(); - while curr_end < end { - out.push((curr_start, curr_end)); - curr_start += step; - curr_end += step; + while curr_end_offset < end { + out.push((curr_start_offset, curr_end_offset)); + + curr_start_im = curr_start_im - step; + curr_start_offset = converter.invert(curr_start_im) as usize; + + curr_end_im = curr_start_im - span; + curr_end_offset = converter.invert(curr_end_im) as usize; } - if curr_start < end { - out.push((curr_start, end)); + if curr_start_offset < end { + out.push((curr_start_offset, end)); } out }, @@ -214,6 +236,7 @@ fn expand_window_settings( window_groups: &[SqlWindowGroup], quadrupole_settings: &[QuadrupoleSettings], strategy: &QuadWindowExpansionStrategy, + converter: Option<&Scan2ImConverter>, ) -> Vec { let mut expanded_quadrupole_settings: Vec = vec![]; for window_group in window_groups { @@ -223,9 +246,12 @@ fn expand_window_settings( let window_group_start = group.scan_starts.iter().min().unwrap().clone(); // SqlReader cannot return empty vecs, so always succeeds let window_group_end = group.scan_ends.iter().max().unwrap().clone(); // SqlReader cannot return empty vecs, so always succeeds - for (sws, swe) in - scan_range_subsplit(window_group_start, window_group_end, &strategy) - { + for (sws, swe) in scan_range_subsplit( + window_group_start, + window_group_end, + &strategy, + converter, + ) { let mut mz_min = std::f64::MAX; let mut mz_max = std::f64::MIN; let mut nce_sum = 0.0; @@ -262,6 +288,7 @@ fn expand_quadrupole_settings( window_groups: &[SqlWindowGroup], quadrupole_settings: &[QuadrupoleSettings], strategy: &QuadWindowExpansionStrategy, + converter: Option<&Scan2ImConverter>, ) -> Vec { let mut expanded_quadrupole_settings: Vec = vec![]; for window_group in window_groups { @@ -275,6 +302,7 @@ fn expand_quadrupole_settings( subwindow_scan_start, subwindow_scan_end, &strategy, + converter, ) { let sub_quad_settings = QuadrupoleSettings { index: frame, diff --git a/src/io/readers/spectrum_reader/tdf.rs b/src/io/readers/spectrum_reader/tdf.rs index 7f29748..f3d0d8c 100644 --- a/src/io/readers/spectrum_reader/tdf.rs +++ b/src/io/readers/spectrum_reader/tdf.rs @@ -50,6 +50,7 @@ impl TDFSpectrumReader { frame_reader, acquisition_type, config.frame_splitting_params, + Some(&metadata.im_converter), )?; let reader = Self { path: path_name.as_ref().to_path_buf(), diff --git a/src/io/readers/spectrum_reader/tdf/dia.rs b/src/io/readers/spectrum_reader/tdf/dia.rs index 3313acf..1cb1e37 100644 --- a/src/io/readers/spectrum_reader/tdf/dia.rs +++ b/src/io/readers/spectrum_reader/tdf/dia.rs @@ -1,3 +1,4 @@ +use crate::domain_converters::Scan2ImConverter; use crate::io::readers::quad_settings_reader::FrameWindowSplittingStrategy; use crate::io::readers::FrameReaderError; use crate::{ @@ -24,11 +25,13 @@ impl DIARawSpectrumReader { tdf_sql_reader: &SqlReader, frame_reader: FrameReader, splitting_strategy: FrameWindowSplittingStrategy, + im_converter: Option<&Scan2ImConverter>, ) -> Result { let expanded_quadrupole_settings = QuadrupoleSettingsReader::from_splitting( - tdf_sql_reader.get_path(), + &tdf_sql_reader, splitting_strategy, + im_converter, )?; let reader = Self { expanded_quadrupole_settings, diff --git a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs index 95b4a46..40edfa1 100644 --- a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs +++ b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs @@ -1,7 +1,7 @@ use core::fmt; use crate::{ - domain_converters::{ConvertableDomain, Tof2MzConverter}, + domain_converters::{ConvertableDomain, Scan2ImConverter, Tof2MzConverter}, io::readers::{ file_readers::sql_reader::SqlReader, quad_settings_reader::FrameWindowSplittingStrategy, FrameReader, @@ -98,6 +98,7 @@ impl RawSpectrumReader { frame_reader: FrameReader, acquisition_type: AcquisitionType, splitting_strategy: FrameWindowSplittingStrategy, + converter: Option<&Scan2ImConverter>, ) -> Result { let raw_spectrum_reader: Box = match acquisition_type { @@ -109,6 +110,7 @@ impl RawSpectrumReader { tdf_sql_reader, frame_reader, splitting_strategy, + converter, )?) }, acquisition_type => { diff --git a/tests/spectrum_readers.rs b/tests/spectrum_readers.rs index 8f6f198..2c77759 100644 --- a/tests/spectrum_readers.rs +++ b/tests/spectrum_readers.rs @@ -172,7 +172,7 @@ fn test_dia_uniform() { .to_str() .unwrap() .to_string(); - for i in [100, 200, 300] { + for i in [0.02, 0.05, 0.1] { let spectra = SpectrumReader::build() .with_path(&file_path) .with_config(SpectrumReaderConfig { @@ -185,12 +185,17 @@ fn test_dia_uniform() { .unwrap() .get_all(); for f in spectra.iter() { - println!("{:?}", f.as_ref().unwrap().precursor); + println!("i={} -> {:?}", i, f.as_ref().unwrap().precursor); } - // Not all frames have scan windows from 0 to 709 ... so ... I need to think + // Not all frames have scan windows from 0.5 to 1.5 ... so ... I need to think // on how to express this in the test - // assert_eq!(frames.len(), 4 * ((709 / i) + 1)); - assert!(spectra.len() > (709 / i)); - assert!(spectra.len() < 3 * ((709 / i) + 1)); + assert!(spectra.len() >= (1.0 / i) as usize); + + // 4 frames, each split in 1.0/i chunks max, 1.0 is the IMS width of a frame + // but not all frames span windows in that range + assert!(spectra.len() < 4 * (1.0 / i) as usize,); + + // TODO make a more accurate test where we measure the differences in ion + // mobilities and see if they are within the expected range } } From 9b63805592d16dcdeee9eab11897122d59ab69c6 Mon Sep 17 00:00:00 2001 From: "J. Sebastian Paez" Date: Mon, 26 Aug 2024 17:20:22 -0700 Subject: [PATCH 2/3] (feat,wip) Adding back flat span and upstream query of spectrum converter --- src/io/readers/precursor_reader.rs | 9 +- src/io/readers/precursor_reader/tdf.rs | 4 +- src/io/readers/precursor_reader/tdf/dia.rs | 5 +- src/io/readers/quad_settings_reader.rs | 131 ++++++++++++++---- src/io/readers/spectrum_reader.rs | 4 +- src/io/readers/spectrum_reader/tdf.rs | 6 +- src/io/readers/spectrum_reader/tdf/dia.rs | 2 - .../spectrum_reader/tdf/raw_spectra.rs | 2 - tests/spectrum_readers.rs | 46 +++++- 9 files changed, 157 insertions(+), 52 deletions(-) diff --git a/src/io/readers/precursor_reader.rs b/src/io/readers/precursor_reader.rs index e4750c5..8f477d0 100644 --- a/src/io/readers/precursor_reader.rs +++ b/src/io/readers/precursor_reader.rs @@ -9,7 +9,7 @@ use tdf::{TDFPrecursorReader, TDFPrecursorReaderError}; use crate::ms_data::Precursor; -use super::quad_settings_reader::FrameWindowSplittingStrategy; +use super::FrameWindowSplittingConfiguration; pub struct PrecursorReader { precursor_reader: Box, @@ -42,7 +42,7 @@ impl PrecursorReader { #[derive(Debug, Default, Clone)] pub struct PrecursorReaderBuilder { path: PathBuf, - config: FrameWindowSplittingStrategy, + config: FrameWindowSplittingConfiguration, } impl PrecursorReaderBuilder { @@ -53,7 +53,10 @@ impl PrecursorReaderBuilder { } } - pub fn with_config(&self, config: FrameWindowSplittingStrategy) -> Self { + pub fn with_config( + &self, + config: FrameWindowSplittingConfiguration, + ) -> Self { Self { config: config, ..self.clone() diff --git a/src/io/readers/precursor_reader/tdf.rs b/src/io/readers/precursor_reader/tdf.rs index 34efef1..60d179d 100644 --- a/src/io/readers/precursor_reader/tdf.rs +++ b/src/io/readers/precursor_reader/tdf.rs @@ -9,7 +9,7 @@ use dia::{DIATDFPrecursorReader, DIATDFPrecursorReaderError}; use crate::{ io::readers::{ file_readers::sql_reader::{SqlError, SqlReader}, - quad_settings_reader::FrameWindowSplittingStrategy, + FrameWindowSplittingConfiguration, }, ms_data::{AcquisitionType, Precursor}, }; @@ -23,7 +23,7 @@ pub struct TDFPrecursorReader { impl TDFPrecursorReader { pub fn new( path: impl AsRef, - splitting_strategy: FrameWindowSplittingStrategy, + splitting_strategy: FrameWindowSplittingConfiguration, ) -> Result { let sql_path = path.as_ref(); let tdf_sql_reader = SqlReader::open(sql_path)?; diff --git a/src/io/readers/precursor_reader/tdf/dia.rs b/src/io/readers/precursor_reader/tdf/dia.rs index c0986de..b259f05 100644 --- a/src/io/readers/precursor_reader/tdf/dia.rs +++ b/src/io/readers/precursor_reader/tdf/dia.rs @@ -1,6 +1,7 @@ use std::path::Path; use crate::io::readers::quad_settings_reader::FrameWindowSplittingStrategy; +use crate::io::readers::FrameWindowSplittingConfiguration; use crate::{ domain_converters::{ ConvertableDomain, Frame2RtConverter, Scan2ImConverter, @@ -25,18 +26,18 @@ pub struct DIATDFPrecursorReader { impl DIATDFPrecursorReader { pub fn new( path: impl AsRef, - splitting_strategy: FrameWindowSplittingStrategy, + splitting_config: FrameWindowSplittingConfiguration, ) -> Result { let sql_path = path.as_ref(); let tdf_sql_reader = SqlReader::open(sql_path)?; let metadata = MetadataReader::new(&path)?; let rt_converter: Frame2RtConverter = metadata.rt_converter; let im_converter: Scan2ImConverter = metadata.im_converter; + let splitting_strategy = splitting_config.finalize(im_converter); let expanded_quadrupole_settings = QuadrupoleSettingsReader::from_splitting( &tdf_sql_reader, splitting_strategy, - Some(&im_converter), )?; let reader = Self { expanded_quadrupole_settings, diff --git a/src/io/readers/quad_settings_reader.rs b/src/io/readers/quad_settings_reader.rs index a18bce3..ffc22f9 100644 --- a/src/io/readers/quad_settings_reader.rs +++ b/src/io/readers/quad_settings_reader.rs @@ -54,9 +54,7 @@ impl QuadrupoleSettingsReader { pub fn from_splitting( tdf_sql_reader: &SqlReader, splitting_strat: FrameWindowSplittingStrategy, - scan_converter: Option<&Scan2ImConverter>, ) -> Result, QuadrupoleSettingsReaderError> { - let sql_path = tdf_sql_reader.get_path(); let quadrupole_settings = Self::from_sql_settings(&tdf_sql_reader)?; let window_groups = SqlWindowGroup::from_sql_reader(&tdf_sql_reader)?; let expanded_quadrupole_settings = match splitting_strat { @@ -65,15 +63,11 @@ impl QuadrupoleSettingsReader { &window_groups, &quadrupole_settings, &x, - scan_converter, ) }, - FrameWindowSplittingStrategy::Window(x) => expand_window_settings( - &window_groups, - &quadrupole_settings, - &x, - scan_converter, - ), + FrameWindowSplittingStrategy::Window(x) => { + expand_window_settings(&window_groups, &quadrupole_settings, &x) + }, }; Ok(expanded_quadrupole_settings) } @@ -128,7 +122,8 @@ pub enum QuadrupoleSettingsReaderError { SqlError(#[from] SqlError), } -type SpanStep = (f64, f64); +type MobilitySpanStep = (f64, f64); +type ScanSpanStep = (usize, usize); /// Strategy for expanding quadrupole settings /// @@ -143,16 +138,62 @@ type SpanStep = (f64, f64); /// * `Even(usize)` - Split the quadrupole settings into `usize` evenly spaced /// subwindows; e.g. if `usize` is 2, the window will be split into 2 subwindows /// of equal width. -/// * `Uniform(SpanStep)` - Split the quadrupole settings into subwindows of -/// width `SpanStep.0` and step `SpanStep.1`; e.g. if `SpanStep` is (0.05, 0.02), +/// * `UniformMobility(SpanStep)` - Split the quadrupole settings into subwindows of +/// width `SpanStep.0` and step `SpanStep.1` in ion mobility space. +/// e.g. if `SpanStep` is (0.05, 0.02), /// the window will be split into subwindows of width 0.05 and step 0.02 between their /// in the mobility dimension. +/// * `UniformScan(SpanStep)` - Split the quadrupole settings into subwindows of +/// width `SpanStep.0` and step `SpanStep.1` in scan number space. +/// e.g. if `SpanStep` is (100, 80), +/// the window will be split into subwindows of width +/// 100 and step 80 between their in the scan number. /// #[derive(Debug, Copy, Clone)] pub enum QuadWindowExpansionStrategy { None, Even(usize), - Uniform(SpanStep), + UniformMobility(MobilitySpanStep, Scan2ImConverter), + UniformScan(ScanSpanStep), +} + +#[derive(Debug, Copy, Clone)] +pub enum QuadWindowExpansionConfiguration { + None, + Even(usize), + UniformMobility(MobilitySpanStep), + UniformScan(ScanSpanStep), +} + +impl Default for QuadWindowExpansionConfiguration { + fn default() -> Self { + Self::Even(1) + } +} + +impl QuadWindowExpansionConfiguration { + pub fn finalize( + self, + scan_converter: Scan2ImConverter, + ) -> QuadWindowExpansionStrategy { + match self { + QuadWindowExpansionConfiguration::None => { + QuadWindowExpansionStrategy::None + }, + QuadWindowExpansionConfiguration::Even(x) => { + QuadWindowExpansionStrategy::Even(x) + }, + QuadWindowExpansionConfiguration::UniformMobility((span, step)) => { + QuadWindowExpansionStrategy::UniformMobility( + (span, step), + scan_converter, + ) + }, + QuadWindowExpansionConfiguration::UniformScan((span, step)) => { + QuadWindowExpansionStrategy::UniformScan((span, step)) + }, + } + } } #[derive(Debug, Clone, Copy)] @@ -161,9 +202,33 @@ pub enum FrameWindowSplittingStrategy { Window(QuadWindowExpansionStrategy), } -impl Default for FrameWindowSplittingStrategy { +#[derive(Debug, Clone, Copy)] +pub enum FrameWindowSplittingConfiguration { + Quadrupole(QuadWindowExpansionConfiguration), + Window(QuadWindowExpansionConfiguration), +} + +impl Default for FrameWindowSplittingConfiguration { fn default() -> Self { - Self::Quadrupole(QuadWindowExpansionStrategy::Even(1)) + Self::Quadrupole(QuadWindowExpansionConfiguration::Even(1)) + } +} + +impl FrameWindowSplittingConfiguration { + pub fn finalize( + self, + scan_converter: Scan2ImConverter, + ) -> FrameWindowSplittingStrategy { + match self { + FrameWindowSplittingConfiguration::Quadrupole(x) => { + FrameWindowSplittingStrategy::Quadrupole( + x.finalize(scan_converter), + ) + }, + FrameWindowSplittingConfiguration::Window(x) => { + FrameWindowSplittingStrategy::Window(x.finalize(scan_converter)) + }, + } } } @@ -171,7 +236,6 @@ fn scan_range_subsplit( start: usize, end: usize, strategy: &QuadWindowExpansionStrategy, - converter: Option<&Scan2ImConverter>, ) -> Vec<(usize, usize)> { let out: Vec<(usize, usize)> = match strategy { QuadWindowExpansionStrategy::None => { @@ -190,11 +254,10 @@ fn scan_range_subsplit( } out }, - QuadWindowExpansionStrategy::Uniform((span, step)) => { - let converter = converter - .as_ref() - .expect("Uniform expansion requires a scan to IM converter"); - + QuadWindowExpansionStrategy::UniformMobility( + (span, step), + converter, + ) => { // Since scan start < scan end but low scans are high IMs, we need to // subtract instead of adding. let mut curr_start_offset = start.clone(); @@ -217,6 +280,20 @@ fn scan_range_subsplit( } out }, + QuadWindowExpansionStrategy::UniformScan((span, step)) => { + let mut curr_start_offset = start; + let mut curr_end_offset = end + span; + let mut out = Vec::new(); + while curr_end_offset < end { + out.push((curr_start_offset, curr_end_offset)); + curr_start_offset += step; + curr_end_offset += step; + } + if curr_start_offset > end { + out.push((curr_start_offset, end)); + } + out + }, }; debug_assert!( @@ -236,7 +313,6 @@ fn expand_window_settings( window_groups: &[SqlWindowGroup], quadrupole_settings: &[QuadrupoleSettings], strategy: &QuadWindowExpansionStrategy, - converter: Option<&Scan2ImConverter>, ) -> Vec { let mut expanded_quadrupole_settings: Vec = vec![]; for window_group in window_groups { @@ -246,12 +322,9 @@ fn expand_window_settings( let window_group_start = group.scan_starts.iter().min().unwrap().clone(); // SqlReader cannot return empty vecs, so always succeeds let window_group_end = group.scan_ends.iter().max().unwrap().clone(); // SqlReader cannot return empty vecs, so always succeeds - for (sws, swe) in scan_range_subsplit( - window_group_start, - window_group_end, - &strategy, - converter, - ) { + for (sws, swe) in + scan_range_subsplit(window_group_start, window_group_end, &strategy) + { let mut mz_min = std::f64::MAX; let mut mz_max = std::f64::MIN; let mut nce_sum = 0.0; @@ -288,7 +361,6 @@ fn expand_quadrupole_settings( window_groups: &[SqlWindowGroup], quadrupole_settings: &[QuadrupoleSettings], strategy: &QuadWindowExpansionStrategy, - converter: Option<&Scan2ImConverter>, ) -> Vec { let mut expanded_quadrupole_settings: Vec = vec![]; for window_group in window_groups { @@ -302,7 +374,6 @@ fn expand_quadrupole_settings( subwindow_scan_start, subwindow_scan_end, &strategy, - converter, ) { let sub_quad_settings = QuadrupoleSettings { index: frame, diff --git a/src/io/readers/spectrum_reader.rs b/src/io/readers/spectrum_reader.rs index 7f905cc..3e5a533 100644 --- a/src/io/readers/spectrum_reader.rs +++ b/src/io/readers/spectrum_reader.rs @@ -9,7 +9,7 @@ use tdf::{TDFSpectrumReader, TDFSpectrumReaderError}; use crate::ms_data::Spectrum; -use super::FrameWindowSplittingStrategy; +use super::FrameWindowSplittingConfiguration; pub struct SpectrumReader { spectrum_reader: Box, @@ -147,5 +147,5 @@ impl Default for SpectrumProcessingParams { #[derive(Debug, Default, Clone)] pub struct SpectrumReaderConfig { pub spectrum_processing_params: SpectrumProcessingParams, - pub frame_splitting_params: FrameWindowSplittingStrategy, + pub frame_splitting_params: FrameWindowSplittingConfiguration, } diff --git a/src/io/readers/spectrum_reader/tdf.rs b/src/io/readers/spectrum_reader/tdf.rs index f3d0d8c..f166dc4 100644 --- a/src/io/readers/spectrum_reader/tdf.rs +++ b/src/io/readers/spectrum_reader/tdf.rs @@ -45,12 +45,14 @@ impl TDFSpectrumReader { .with_config(config.frame_splitting_params) .finalize()?; let acquisition_type = frame_reader.get_acquisition(); + let splitting_strategy = config + .frame_splitting_params + .finalize(metadata.im_converter); let raw_spectrum_reader = RawSpectrumReader::new( &tdf_sql_reader, frame_reader, acquisition_type, - config.frame_splitting_params, - Some(&metadata.im_converter), + splitting_strategy, )?; let reader = Self { path: path_name.as_ref().to_path_buf(), diff --git a/src/io/readers/spectrum_reader/tdf/dia.rs b/src/io/readers/spectrum_reader/tdf/dia.rs index 1cb1e37..46c26ee 100644 --- a/src/io/readers/spectrum_reader/tdf/dia.rs +++ b/src/io/readers/spectrum_reader/tdf/dia.rs @@ -25,13 +25,11 @@ impl DIARawSpectrumReader { tdf_sql_reader: &SqlReader, frame_reader: FrameReader, splitting_strategy: FrameWindowSplittingStrategy, - im_converter: Option<&Scan2ImConverter>, ) -> Result { let expanded_quadrupole_settings = QuadrupoleSettingsReader::from_splitting( &tdf_sql_reader, splitting_strategy, - im_converter, )?; let reader = Self { expanded_quadrupole_settings, diff --git a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs index 40edfa1..6ad2b6e 100644 --- a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs +++ b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs @@ -98,7 +98,6 @@ impl RawSpectrumReader { frame_reader: FrameReader, acquisition_type: AcquisitionType, splitting_strategy: FrameWindowSplittingStrategy, - converter: Option<&Scan2ImConverter>, ) -> Result { let raw_spectrum_reader: Box = match acquisition_type { @@ -110,7 +109,6 @@ impl RawSpectrumReader { tdf_sql_reader, frame_reader, splitting_strategy, - converter, )?) }, acquisition_type => { diff --git a/tests/spectrum_readers.rs b/tests/spectrum_readers.rs index 2c77759..4965161 100644 --- a/tests/spectrum_readers.rs +++ b/tests/spectrum_readers.rs @@ -1,7 +1,7 @@ use std::path::Path; use timsrust::{ io::readers::{ - FrameWindowSplittingStrategy, QuadWindowExpansionStrategy, + FrameWindowSplittingConfiguration, QuadWindowExpansionConfiguration, SpectrumProcessingParams, SpectrumReader, SpectrumReaderConfig, }, ms_data::{Precursor, Spectrum}, @@ -151,8 +151,8 @@ fn test_dia_even() { .with_path(&file_path) .with_config(SpectrumReaderConfig { frame_splitting_params: - FrameWindowSplittingStrategy::Quadrupole( - QuadWindowExpansionStrategy::Even(i), + FrameWindowSplittingConfiguration::Quadrupole( + QuadWindowExpansionConfiguration::Even(i), ), spectrum_processing_params: SpectrumProcessingParams::default(), }) @@ -165,7 +165,7 @@ fn test_dia_even() { } #[test] -fn test_dia_uniform() { +fn test_dia_uniform_mobility() { let file_name = "dia_test.d"; let file_path = get_local_directory() .join(file_name) @@ -176,9 +176,12 @@ fn test_dia_uniform() { let spectra = SpectrumReader::build() .with_path(&file_path) .with_config(SpectrumReaderConfig { - frame_splitting_params: FrameWindowSplittingStrategy::Window( - QuadWindowExpansionStrategy::Uniform((i, i)), - ), + frame_splitting_params: + FrameWindowSplittingConfiguration::Window( + QuadWindowExpansionConfiguration::UniformMobility(( + i, i, + )), + ), spectrum_processing_params: SpectrumProcessingParams::default(), }) .finalize() @@ -199,3 +202,32 @@ fn test_dia_uniform() { // mobilities and see if they are within the expected range } } + +#[test] +fn test_dia_uniform_scans() { + let file_name = "dia_test.d"; + let file_path = get_local_directory() + .join(file_name) + .to_str() + .unwrap() + .to_string(); + for i in [50, 100, 200] { + let spectra = SpectrumReader::build() + .with_path(&file_path) + .with_config(SpectrumReaderConfig { + frame_splitting_params: + FrameWindowSplittingConfiguration::Window( + QuadWindowExpansionConfiguration::UniformScan((i, i)), + ), + spectrum_processing_params: SpectrumProcessingParams::default(), + }) + .finalize() + .unwrap() + .get_all(); + for f in spectra.iter() { + println!("i={} -> {:?}", i, f.as_ref().unwrap().precursor); + } + + panic!("not implemented"); + } +} From 12ef92b395eb2ef13a3f6bf6b1fbb0a269340223 Mon Sep 17 00:00:00 2001 From: "J. Sebastian Paez" Date: Mon, 26 Aug 2024 17:42:52 -0700 Subject: [PATCH 3/3] (feat) Added testing for uniform scan splitting --- src/io/readers/precursor_reader/tdf/dia.rs | 1 - src/io/readers/quad_settings_reader.rs | 5 +++-- src/io/readers/spectrum_reader/tdf/dia.rs | 1 - src/io/readers/spectrum_reader/tdf/raw_spectra.rs | 2 +- tests/spectrum_readers.rs | 14 ++++++++++++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/io/readers/precursor_reader/tdf/dia.rs b/src/io/readers/precursor_reader/tdf/dia.rs index b259f05..435636d 100644 --- a/src/io/readers/precursor_reader/tdf/dia.rs +++ b/src/io/readers/precursor_reader/tdf/dia.rs @@ -1,6 +1,5 @@ use std::path::Path; -use crate::io::readers::quad_settings_reader::FrameWindowSplittingStrategy; use crate::io::readers::FrameWindowSplittingConfiguration; use crate::{ domain_converters::{ diff --git a/src/io/readers/quad_settings_reader.rs b/src/io/readers/quad_settings_reader.rs index ffc22f9..8559122 100644 --- a/src/io/readers/quad_settings_reader.rs +++ b/src/io/readers/quad_settings_reader.rs @@ -282,14 +282,15 @@ fn scan_range_subsplit( }, QuadWindowExpansionStrategy::UniformScan((span, step)) => { let mut curr_start_offset = start; - let mut curr_end_offset = end + span; + let mut curr_end_offset = start + span; let mut out = Vec::new(); + while curr_end_offset < end { out.push((curr_start_offset, curr_end_offset)); curr_start_offset += step; curr_end_offset += step; } - if curr_start_offset > end { + if curr_start_offset < end { out.push((curr_start_offset, end)); } out diff --git a/src/io/readers/spectrum_reader/tdf/dia.rs b/src/io/readers/spectrum_reader/tdf/dia.rs index 46c26ee..3dad26c 100644 --- a/src/io/readers/spectrum_reader/tdf/dia.rs +++ b/src/io/readers/spectrum_reader/tdf/dia.rs @@ -1,4 +1,3 @@ -use crate::domain_converters::Scan2ImConverter; use crate::io::readers::quad_settings_reader::FrameWindowSplittingStrategy; use crate::io::readers::FrameReaderError; use crate::{ diff --git a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs index 6ad2b6e..95b4a46 100644 --- a/src/io/readers/spectrum_reader/tdf/raw_spectra.rs +++ b/src/io/readers/spectrum_reader/tdf/raw_spectra.rs @@ -1,7 +1,7 @@ use core::fmt; use crate::{ - domain_converters::{ConvertableDomain, Scan2ImConverter, Tof2MzConverter}, + domain_converters::{ConvertableDomain, Tof2MzConverter}, io::readers::{ file_readers::sql_reader::SqlReader, quad_settings_reader::FrameWindowSplittingStrategy, FrameReader, diff --git a/tests/spectrum_readers.rs b/tests/spectrum_readers.rs index 4965161..6b27e8c 100644 --- a/tests/spectrum_readers.rs +++ b/tests/spectrum_readers.rs @@ -211,7 +211,7 @@ fn test_dia_uniform_scans() { .to_str() .unwrap() .to_string(); - for i in [50, 100, 200] { + for i in [20, 100, 200] { let spectra = SpectrumReader::build() .with_path(&file_path) .with_config(SpectrumReaderConfig { @@ -228,6 +228,16 @@ fn test_dia_uniform_scans() { println!("i={} -> {:?}", i, f.as_ref().unwrap().precursor); } - panic!("not implemented"); + // Since there are 709 scans in the test data ... we can expect + // the number of breaks to be (709 / i) + 1 ... if we had a single + // window that spanned the entire scan range. + // ... A more strict test would filter for each frame index and + // within each make sure the number matches the ratio ... here I am + // Just checking the overall number. + const NUM_FRAMES: usize = 4; + const NUM_SCANS: usize = 709; + + assert!(spectra.len() >= (NUM_SCANS / i) as usize + 1); + assert!(spectra.len() < NUM_FRAMES * (NUM_SCANS / i) as usize + 1); } }