1use mscore::data::peptide::{PeptideIon, PeptideProductIonSeriesCollection};
2use mscore::data::spectrum::{IndexedMzSpectrum, MsType, MzSpectrum};
3use mscore::simulation::annotation::{
4 MzSpectrumAnnotated, TimsFrameAnnotated, TimsSpectrumAnnotated,
5};
6use mscore::timstof::collision::{TimsTofCollisionEnergy, TimsTofCollisionEnergyDIA};
7use mscore::timstof::frame::TimsFrame;
8use mscore::timstof::quadrupole::{IonTransmission, TimsTransmissionDIA};
9use mscore::timstof::spectrum::TimsSpectrum;
10use std::collections::{BTreeMap, HashSet};
11use std::path::Path;
12
13use rayon::prelude::*;
14use rayon::ThreadPoolBuilder;
15
16use crate::sim::handle::TimsTofSyntheticsDataHandle;
17use crate::sim::precursor::TimsTofSyntheticsPrecursorFrameBuilder;
18
19pub struct TimsTofSyntheticsFrameBuilderDIA {
20 pub path: String,
21 pub precursor_frame_builder: TimsTofSyntheticsPrecursorFrameBuilder,
22 pub transmission_settings: TimsTransmissionDIA,
23 pub fragmentation_settings: TimsTofCollisionEnergyDIA,
24 pub fragment_ions:
25 Option<BTreeMap<(u32, i8, i32), (PeptideProductIonSeriesCollection, Vec<MzSpectrum>)>>,
26 pub fragment_ions_annotated: Option<
27 BTreeMap<(u32, i8, i32), (PeptideProductIonSeriesCollection, Vec<MzSpectrumAnnotated>)>,
28 >,
29}
30
31impl TimsTofSyntheticsFrameBuilderDIA {
32 pub fn new(path: &Path, with_annotations: bool, num_threads: usize) -> rusqlite::Result<Self> {
33 let synthetics = TimsTofSyntheticsPrecursorFrameBuilder::new(path)?;
34 let handle = TimsTofSyntheticsDataHandle::new(path)?;
35
36 let fragment_ions = handle.read_fragment_ions()?;
37
38 let fragmentation_settings = handle.get_collision_energy_dia();
40 let transmission_settings = handle.get_transmission_dia();
42
43 match with_annotations {
44 true => {
45 let fragment_ions =
46 Some(TimsTofSyntheticsDataHandle::build_fragment_ions_annotated(
47 &synthetics.peptides,
48 &fragment_ions,
49 num_threads,
50 ));
51 Ok(Self {
52 path: path.to_str().unwrap().to_string(),
53 precursor_frame_builder: synthetics,
54 transmission_settings,
55 fragmentation_settings,
56 fragment_ions: None,
57 fragment_ions_annotated: fragment_ions,
58 })
59 }
60
61 false => {
62 let fragment_ions = Some(TimsTofSyntheticsDataHandle::build_fragment_ions(
63 &synthetics.peptides,
64 &fragment_ions,
65 num_threads,
66 ));
67 Ok(Self {
68 path: path.to_str().unwrap().to_string(),
69 precursor_frame_builder: synthetics,
70 transmission_settings,
71 fragmentation_settings,
72 fragment_ions,
73 fragment_ions_annotated: None,
74 })
75 }
76 }
77 }
78
79 pub fn build_frame(
91 &self,
92 frame_id: u32,
93 fragmentation: bool,
94 mz_noise_precursor: bool,
95 uniform: bool,
96 precursor_noise_ppm: f64,
97 mz_noise_fragment: bool,
98 fragment_noise_ppm: f64,
99 right_drag: bool,
100 ) -> TimsFrame {
101 match self
103 .precursor_frame_builder
104 .precursor_frame_id_set
105 .contains(&frame_id)
106 {
107 true => self.build_ms1_frame(
108 frame_id,
109 mz_noise_precursor,
110 uniform,
111 precursor_noise_ppm,
112 right_drag,
113 ),
114 false => self.build_ms2_frame(
115 frame_id,
116 fragmentation,
117 mz_noise_fragment,
118 uniform,
119 fragment_noise_ppm,
120 right_drag,
121 ),
122 }
123 }
124
125 pub fn build_frame_annotated(
126 &self,
127 frame_id: u32,
128 fragmentation: bool,
129 mz_noise_precursor: bool,
130 uniform: bool,
131 precursor_noise_ppm: f64,
132 mz_noise_fragment: bool,
133 fragment_noise_ppm: f64,
134 right_drag: bool,
135 ) -> TimsFrameAnnotated {
136 match self
137 .precursor_frame_builder
138 .precursor_frame_id_set
139 .contains(&frame_id)
140 {
141 true => self.build_ms1_frame_annotated(
142 frame_id,
143 mz_noise_precursor,
144 uniform,
145 precursor_noise_ppm,
146 right_drag,
147 ),
148 false => self.build_ms2_frame_annotated(
149 frame_id,
150 fragmentation,
151 mz_noise_fragment,
152 uniform,
153 fragment_noise_ppm,
154 right_drag,
155 ),
156 }
157 }
158
159 pub fn get_fragment_ion_ids(&self, precursor_frame_ids: Vec<u32>) -> Vec<u32> {
160 let mut peptide_ids: HashSet<u32> = HashSet::new();
161 for frame_id in precursor_frame_ids {
163 for (peptide_id, peptide) in self.precursor_frame_builder.peptides.iter() {
164 if peptide.frame_start <= frame_id && peptide.frame_end >= frame_id {
165 peptide_ids.insert(*peptide_id);
166 }
167 }
168 }
169 let mut result: Vec<u32> = Vec::new();
171 for item in peptide_ids {
172 let ions = self.precursor_frame_builder.ions.get(&item).unwrap();
173 for ion in ions.iter() {
174 result.push(ion.ion_id);
175 }
176 }
177 result
178 }
179
180 pub fn build_frames(
181 &self,
182 frame_ids: Vec<u32>,
183 fragmentation: bool,
184 mz_noise_precursor: bool,
185 uniform: bool,
186 precursor_noise_ppm: f64,
187 mz_noise_fragment: bool,
188 fragment_noise_ppm: f64,
189 right_drag: bool,
190 num_threads: usize,
191 ) -> Vec<TimsFrame> {
192 let thread_pool = ThreadPoolBuilder::new()
193 .num_threads(num_threads)
194 .build()
195 .unwrap();
196 let mut tims_frames: Vec<TimsFrame> = Vec::new();
197
198 thread_pool.install(|| {
199 tims_frames = frame_ids
200 .par_iter()
201 .map(|frame_id| {
202 self.build_frame(
203 *frame_id,
204 fragmentation,
205 mz_noise_precursor,
206 uniform,
207 precursor_noise_ppm,
208 mz_noise_fragment,
209 fragment_noise_ppm,
210 right_drag,
211 )
212 })
213 .collect();
214 });
215
216 tims_frames.sort_by(|a, b| a.frame_id.cmp(&b.frame_id));
217
218 tims_frames
219 }
220
221 pub fn build_frames_annotated(
222 &self,
223 frame_ids: Vec<u32>,
224 fragmentation: bool,
225 mz_noise_precursor: bool,
226 uniform: bool,
227 precursor_noise_ppm: f64,
228 mz_noise_fragment: bool,
229 fragment_noise_ppm: f64,
230 right_drag: bool,
231 num_threads: usize,
232 ) -> Vec<TimsFrameAnnotated> {
233 let thread_pool = ThreadPoolBuilder::new()
234 .num_threads(num_threads)
235 .build()
236 .unwrap();
237 let mut tims_frames: Vec<TimsFrameAnnotated> = Vec::new();
238
239 thread_pool.install(|| {
240 tims_frames = frame_ids
241 .par_iter()
242 .map(|frame_id| {
243 self.build_frame_annotated(
244 *frame_id,
245 fragmentation,
246 mz_noise_precursor,
247 uniform,
248 precursor_noise_ppm,
249 mz_noise_fragment,
250 fragment_noise_ppm,
251 right_drag,
252 )
253 })
254 .collect();
255 });
256
257 tims_frames.sort_by(|a, b| a.frame_id.cmp(&b.frame_id));
258
259 tims_frames
260 }
261
262 fn build_ms1_frame(
263 &self,
264 frame_id: u32,
265 mz_noise_precursor: bool,
266 uniform: bool,
267 precursor_ppm: f64,
268 right_drag: bool,
269 ) -> TimsFrame {
270 let mut tims_frame = self.precursor_frame_builder.build_precursor_frame(
271 frame_id,
272 mz_noise_precursor,
273 uniform,
274 precursor_ppm,
275 right_drag,
276 );
277 let intensities_rounded = tims_frame
278 .ims_frame
279 .intensity
280 .iter()
281 .map(|x| x.round())
282 .collect::<Vec<_>>();
283 tims_frame.ims_frame.intensity = intensities_rounded;
284 tims_frame
285 }
286
287 fn build_ms1_frame_annotated(
288 &self,
289 frame_id: u32,
290 mz_noise_precursor: bool,
291 uniform: bool,
292 precursor_ppm: f64,
293 right_drag: bool,
294 ) -> TimsFrameAnnotated {
295 let mut tims_frame = self
296 .precursor_frame_builder
297 .build_precursor_frame_annotated(
298 frame_id,
299 mz_noise_precursor,
300 uniform,
301 precursor_ppm,
302 right_drag,
303 );
304 let intensities_rounded = tims_frame
305 .intensity
306 .iter()
307 .map(|x| x.round())
308 .collect::<Vec<_>>();
309 tims_frame.intensity = intensities_rounded;
310 tims_frame
311 }
312
313 fn build_ms2_frame(
314 &self,
315 frame_id: u32,
316 fragmentation: bool,
317 mz_noise_fragment: bool,
318 uniform: bool,
319 fragment_ppm: f64,
320 right_drag: bool,
321 ) -> TimsFrame {
322 match fragmentation {
323 false => {
324 let mut frame = self.transmission_settings.transmit_tims_frame(
325 &self.build_ms1_frame(
326 frame_id,
327 mz_noise_fragment,
328 uniform,
329 fragment_ppm,
330 right_drag,
331 ),
332 None,
333 );
334 let intensities_rounded = frame
335 .ims_frame
336 .intensity
337 .iter()
338 .map(|x| x.round())
339 .collect::<Vec<_>>();
340 frame.ims_frame.intensity = intensities_rounded;
341 frame.ms_type = MsType::FragmentDia;
342 frame
343 }
344 true => {
345 let mut frame = self.build_fragment_frame(
346 frame_id,
347 &self.fragment_ions.as_ref().unwrap(),
348 mz_noise_fragment,
349 uniform,
350 fragment_ppm,
351 None,
352 None,
353 None,
354 Some(right_drag),
355 );
356 let intensities_rounded = frame
357 .ims_frame
358 .intensity
359 .iter()
360 .map(|x| x.round())
361 .collect::<Vec<_>>();
362 frame.ims_frame.intensity = intensities_rounded;
363 frame
364 }
365 }
366 }
367
368 fn build_ms2_frame_annotated(
369 &self,
370 frame_id: u32,
371 fragmentation: bool,
372 mz_noise_fragment: bool,
373 uniform: bool,
374 fragment_ppm: f64,
375 right_drag: bool,
376 ) -> TimsFrameAnnotated {
377 match fragmentation {
378 false => {
379 let mut frame = self.transmission_settings.transmit_tims_frame_annotated(
380 &self.build_ms1_frame_annotated(
381 frame_id,
382 mz_noise_fragment,
383 uniform,
384 fragment_ppm,
385 right_drag,
386 ),
387 None,
388 );
389 let intensities_rounded = frame
390 .intensity
391 .iter()
392 .map(|x| x.round())
393 .collect::<Vec<_>>();
394 frame.intensity = intensities_rounded;
395 frame.ms_type = MsType::FragmentDia;
396 frame
397 }
398 true => {
399 let mut frame = self.build_fragment_frame_annotated(
400 frame_id,
401 &self.fragment_ions_annotated.as_ref().unwrap(),
402 mz_noise_fragment,
403 uniform,
404 fragment_ppm,
405 None,
406 None,
407 None,
408 Some(right_drag),
409 );
410 let intensities_rounded = frame
411 .intensity
412 .iter()
413 .map(|x| x.round())
414 .collect::<Vec<_>>();
415 frame.intensity = intensities_rounded;
416 frame
417 }
418 }
419 }
420
421 fn build_fragment_frame(
435 &self,
436 frame_id: u32,
437 fragment_ions: &BTreeMap<
438 (u32, i8, i32),
439 (PeptideProductIonSeriesCollection, Vec<MzSpectrum>),
440 >,
441 mz_noise_fragment: bool,
442 uniform: bool,
443 fragment_ppm: f64,
444 mz_min: Option<f64>,
445 mz_max: Option<f64>,
446 intensity_min: Option<f64>,
447 right_drag: Option<bool>,
448 ) -> TimsFrame {
449 let ms_type = match self
451 .precursor_frame_builder
452 .precursor_frame_id_set
453 .contains(&frame_id)
454 {
455 false => MsType::FragmentDia,
456 true => MsType::Unknown,
457 };
458
459 let mut tims_spectra: Vec<TimsSpectrum> = Vec::new();
460
461 if !self
463 .precursor_frame_builder
464 .frame_to_abundances
465 .contains_key(&frame_id)
466 {
467 return TimsFrame::new(
468 frame_id as i32,
469 ms_type.clone(),
470 *self
471 .precursor_frame_builder
472 .frame_to_rt
473 .get(&frame_id)
474 .unwrap() as f64,
475 vec![],
476 vec![],
477 vec![],
478 vec![],
479 vec![],
480 );
481 }
482
483 let (peptide_ids, frame_abundances) = self
485 .precursor_frame_builder
486 .frame_to_abundances
487 .get(&frame_id)
488 .unwrap();
489
490 for (peptide_id, frame_abundance) in peptide_ids.iter().zip(frame_abundances.iter()) {
492 if !self
494 .precursor_frame_builder
495 .peptide_to_ions
496 .contains_key(&peptide_id)
497 {
498 continue;
499 }
500
501 let (ion_abundances, scan_occurrences, scan_abundances, charges, spectra) = self
503 .precursor_frame_builder
504 .peptide_to_ions
505 .get(&peptide_id)
506 .unwrap();
507
508 for (index, ion_abundance) in ion_abundances.iter().enumerate() {
509 let all_scan_occurrence = scan_occurrences.get(index).unwrap();
511 let all_scan_abundance = scan_abundances.get(index).unwrap();
512
513 let spectrum = spectra.get(index).unwrap();
515
516 for (scan, scan_abundance) in
518 all_scan_occurrence.iter().zip(all_scan_abundance.iter())
519 {
520 if !self.transmission_settings.any_transmitted(
522 frame_id as i32,
523 *scan as i32,
524 &spectrum.mz,
525 None,
526 ) {
527 continue;
528 }
529
530 let total_events = self
532 .precursor_frame_builder
533 .peptide_to_events
534 .get(&peptide_id)
535 .unwrap();
536 let fraction_events =
537 frame_abundance * scan_abundance * ion_abundance * total_events;
538
539 let collision_energy = self
541 .fragmentation_settings
542 .get_collision_energy(frame_id as i32, *scan as i32);
543 let collision_energy_quantized = (collision_energy * 1e1).round() as i32;
544
545 let charge_state = charges.get(index).unwrap();
547 let maybe_value = fragment_ions.get(&(
549 *peptide_id,
550 *charge_state,
551 collision_energy_quantized,
552 ));
553
554 if maybe_value.is_none() {
556 continue;
557 }
558
559 for fragment_ion_series in maybe_value.unwrap().1.iter() {
561 let scaled_spec = fragment_ion_series.clone() * fraction_events as f64;
562 let right_drag = right_drag.unwrap_or(false);
563
564 let mz_spectrum = if mz_noise_fragment {
565 match uniform {
566 true => scaled_spec.add_mz_noise_uniform(fragment_ppm, right_drag),
567 false => scaled_spec.add_mz_noise_normal(fragment_ppm),
568 }
569 } else {
570 scaled_spec
571 };
572
573 tims_spectra.push(TimsSpectrum::new(
574 frame_id as i32,
575 *scan as i32,
576 *self
577 .precursor_frame_builder
578 .frame_to_rt
579 .get(&frame_id)
580 .unwrap() as f64,
581 *self
582 .precursor_frame_builder
583 .scan_to_mobility
584 .get(&scan)
585 .unwrap() as f64,
586 ms_type.clone(),
587 IndexedMzSpectrum::new(
588 vec![0; mz_spectrum.mz.len()],
589 mz_spectrum.mz,
590 mz_spectrum.intensity,
591 )
592 .filter_ranged(100.0, 1700.0, 1.0, 1e9),
593 ));
594 }
595 }
596 }
597 }
598
599 if tims_spectra.is_empty() {
600 return TimsFrame::new(
601 frame_id as i32,
602 ms_type.clone(),
603 *self
604 .precursor_frame_builder
605 .frame_to_rt
606 .get(&frame_id)
607 .unwrap() as f64,
608 vec![],
609 vec![],
610 vec![],
611 vec![],
612 vec![],
613 );
614 }
615
616 let tims_frame = TimsFrame::from_tims_spectra(tims_spectra);
617 tims_frame.filter_ranged(
618 mz_min.unwrap_or(100.0),
619 mz_max.unwrap_or(1700.0),
620 0,
621 1000,
622 0.0,
623 10.0,
624 intensity_min.unwrap_or(1.0),
625 1e9,
626 )
627 }
628
629 pub fn build_fragment_frame_annotated(
630 &self,
631 frame_id: u32,
632 fragment_ions: &BTreeMap<
633 (u32, i8, i32),
634 (PeptideProductIonSeriesCollection, Vec<MzSpectrumAnnotated>),
635 >,
636 mz_noise_fragment: bool,
637 uniform: bool,
638 fragment_ppm: f64,
639 mz_min: Option<f64>,
640 mz_max: Option<f64>,
641 intensity_min: Option<f64>,
642 right_drag: Option<bool>,
643 ) -> TimsFrameAnnotated {
644 let ms_type = match self
645 .precursor_frame_builder
646 .precursor_frame_id_set
647 .contains(&frame_id)
648 {
649 false => MsType::FragmentDia,
650 true => MsType::Unknown,
651 };
652
653 let mut tims_spectra: Vec<TimsSpectrumAnnotated> = Vec::new();
654
655 if !self
656 .precursor_frame_builder
657 .frame_to_abundances
658 .contains_key(&frame_id)
659 {
660 return TimsFrameAnnotated::new(
661 frame_id as i32,
662 *self
663 .precursor_frame_builder
664 .frame_to_rt
665 .get(&frame_id)
666 .unwrap() as f64,
667 ms_type.clone(),
668 vec![],
669 vec![],
670 vec![],
671 vec![],
672 vec![],
673 vec![],
674 );
675 }
676
677 let (peptide_ids, frame_abundances) = self
678 .precursor_frame_builder
679 .frame_to_abundances
680 .get(&frame_id)
681 .unwrap();
682
683 for (peptide_id, frame_abundance) in peptide_ids.iter().zip(frame_abundances.iter()) {
684 if !self
685 .precursor_frame_builder
686 .peptide_to_ions
687 .contains_key(&peptide_id)
688 {
689 continue;
690 }
691
692 let (ion_abundances, scan_occurrences, scan_abundances, charges, _) = self
693 .precursor_frame_builder
694 .peptide_to_ions
695 .get(&peptide_id)
696 .unwrap();
697
698 for (index, ion_abundance) in ion_abundances.iter().enumerate() {
699 let all_scan_occurrence = scan_occurrences.get(index).unwrap();
700 let all_scan_abundance = scan_abundances.get(index).unwrap();
701
702 let peptide = self
703 .precursor_frame_builder
704 .peptides
705 .get(peptide_id)
706 .unwrap();
707 let ion = PeptideIon::new(
708 peptide.sequence.sequence.clone(),
709 charges[index] as i32,
710 *ion_abundance as f64,
711 Some(*peptide_id as i32),
712 );
713 let spectrum = ion.calculate_isotopic_spectrum_annotated(1e-3, 1e-8, 200, 1e-4);
715
716 for (scan, scan_abundance) in
717 all_scan_occurrence.iter().zip(all_scan_abundance.iter())
718 {
719 if !self.transmission_settings.any_transmitted(
720 frame_id as i32,
721 *scan as i32,
722 &spectrum.mz,
723 None,
724 ) {
725 continue;
726 }
727
728 let total_events = self
729 .precursor_frame_builder
730 .peptide_to_events
731 .get(&peptide_id)
732 .unwrap();
733 let fraction_events =
734 frame_abundance * scan_abundance * ion_abundance * total_events;
735
736 let collision_energy = self
737 .fragmentation_settings
738 .get_collision_energy(frame_id as i32, *scan as i32);
739 let collision_energy_quantized = (collision_energy * 1e1).round() as i32;
740
741 let charge_state = charges.get(index).unwrap();
742 let maybe_value = fragment_ions.get(&(
743 *peptide_id,
744 *charge_state,
745 collision_energy_quantized,
746 ));
747
748 if maybe_value.is_none() {
749 continue;
750 }
751
752 for fragment_ion_series in maybe_value.unwrap().1.iter() {
753 let scaled_spec = fragment_ion_series.clone() * fraction_events as f64;
754 let right_drag = right_drag.unwrap_or(false);
755
756 let mz_spectrum = if mz_noise_fragment {
757 match uniform {
758 true => scaled_spec.add_mz_noise_uniform(fragment_ppm, right_drag),
759 false => scaled_spec.add_mz_noise_normal(fragment_ppm),
760 }
761 } else {
762 scaled_spec
763 };
764
765 tims_spectra.push(TimsSpectrumAnnotated::new(
766 frame_id as i32,
767 *scan,
768 *self
769 .precursor_frame_builder
770 .frame_to_rt
771 .get(&frame_id)
772 .unwrap() as f64,
773 *self
774 .precursor_frame_builder
775 .scan_to_mobility
776 .get(&scan)
777 .unwrap() as f64,
778 ms_type.clone(),
779 vec![0; mz_spectrum.mz.len()],
780 mz_spectrum,
781 ));
782 }
783 }
784 }
785 }
786
787 if tims_spectra.is_empty() {
788 return TimsFrameAnnotated::new(
789 frame_id as i32,
790 *self
791 .precursor_frame_builder
792 .frame_to_rt
793 .get(&frame_id)
794 .unwrap() as f64,
795 ms_type.clone(),
796 vec![],
797 vec![],
798 vec![],
799 vec![],
800 vec![],
801 vec![],
802 );
803 }
804
805 let tims_frame = TimsFrameAnnotated::from_tims_spectra_annotated(tims_spectra);
806
807 tims_frame.filter_ranged(
808 mz_min.unwrap_or(100.0),
809 mz_max.unwrap_or(1700.0),
810 0.0,
811 10.0,
812 0,
813 1000,
814 intensity_min.unwrap_or(1.0),
815 1e9,
816 )
817 }
818
819 pub fn get_ion_transmission_matrix(
820 &self,
821 peptide_id: u32,
822 charge: i8,
823 include_precursor_frames: bool,
824 ) -> Vec<Vec<f32>> {
825 let maybe_peptide_sim = self.precursor_frame_builder.peptides.get(&peptide_id);
826
827 let mut frame_ids = match maybe_peptide_sim {
828 Some(maybe_peptide_sim) => maybe_peptide_sim.frame_distribution.occurrence.clone(),
829 _ => vec![],
830 };
831
832 if !include_precursor_frames {
833 frame_ids = frame_ids
834 .iter()
835 .filter(|frame_id| {
836 !self
837 .precursor_frame_builder
838 .precursor_frame_id_set
839 .contains(frame_id)
840 })
841 .cloned()
842 .collect();
843 }
844
845 let ion = self
846 .precursor_frame_builder
847 .ions
848 .get(&peptide_id)
849 .unwrap()
850 .iter()
851 .find(|ion| ion.charge == charge)
852 .unwrap();
853 let spectrum = ion.simulated_spectrum.clone();
854 let scan_distribution = &ion.scan_distribution;
855
856 let mut transmission_matrix =
857 vec![vec![0.0; frame_ids.len()]; scan_distribution.occurrence.len()];
858
859 for (frame_index, frame) in frame_ids.iter().enumerate() {
860 for (scan_index, scan) in scan_distribution.occurrence.iter().enumerate() {
861 if self.transmission_settings.all_transmitted(
862 *frame as i32,
863 *scan as i32,
864 &spectrum.mz,
865 None,
866 ) {
867 transmission_matrix[scan_index][frame_index] = 1.0;
868 } else if self.transmission_settings.any_transmitted(
869 *frame as i32,
870 *scan as i32,
871 &spectrum.mz,
872 None,
873 ) {
874 let transmitted_spectrum = self.transmission_settings.transmit_spectrum(
875 *frame as i32,
876 *scan as i32,
877 spectrum.clone(),
878 None,
879 );
880 let percentage_transmitted = transmitted_spectrum.intensity.iter().sum::<f64>()
881 / spectrum.intensity.iter().sum::<f64>();
882 transmission_matrix[scan_index][frame_index] = percentage_transmitted as f32;
883 }
884 }
885 }
886
887 transmission_matrix
888 }
889
890 pub fn count_number_transmissions(&self, peptide_id: u32, charge: i8) -> (usize, usize) {
891 let frame_ids: Vec<_> = self
892 .precursor_frame_builder
893 .peptides
894 .get(&peptide_id)
895 .unwrap()
896 .frame_distribution
897 .occurrence
898 .clone()
899 .iter()
900 .filter(|frame_id| {
901 !self
902 .precursor_frame_builder
903 .precursor_frame_id_set
904 .contains(frame_id)
905 })
906 .cloned()
907 .collect();
908 let ion = self
909 .precursor_frame_builder
910 .ions
911 .get(&peptide_id)
912 .unwrap()
913 .iter()
914 .find(|ion| ion.charge == charge)
915 .unwrap();
916 let spectrum = ion.simulated_spectrum.clone();
917 let scan_distribution = &ion.scan_distribution;
918
919 let mut frame_count = 0;
920 let mut scan_count = 0;
921
922 for frame in frame_ids.iter() {
923 let mut frame_transmitted = false;
924 for scan in scan_distribution.occurrence.iter() {
925 if self.transmission_settings.any_transmitted(
926 *frame as i32,
927 *scan as i32,
928 &spectrum.mz,
929 None,
930 ) {
931 frame_transmitted = true;
932 scan_count += 1;
933 }
934 }
935 if frame_transmitted {
936 frame_count += 1;
937 }
938 }
939
940 (frame_count, scan_count)
941 }
942
943 pub fn count_number_transmissions_parallel(
944 &self,
945 peptide_ids: Vec<u32>,
946 charge: Vec<i8>,
947 num_threads: usize,
948 ) -> Vec<(usize, usize)> {
949 let thread_pool = ThreadPoolBuilder::new()
950 .num_threads(num_threads)
951 .build()
952 .unwrap();
953 let result: Vec<(usize, usize)> = thread_pool.install(|| {
954 peptide_ids
955 .par_iter()
956 .zip(charge.par_iter())
957 .map(|(peptide_id, charge)| self.count_number_transmissions(*peptide_id, *charge))
958 .collect()
959 });
960
961 result
962 }
963}
964
965impl TimsTofCollisionEnergy for TimsTofSyntheticsFrameBuilderDIA {
966 fn get_collision_energy(&self, frame_id: i32, scan_id: i32) -> f64 {
967 self.fragmentation_settings
968 .get_collision_energy(frame_id, scan_id)
969 }
970}