1use std::collections::HashSet;
6use std::fmt::Debug;
7use std::hash::Hash;
8use std::mem;
9use std::ops::Range;
10use std::sync::Arc;
11use std::sync::Mutex;
12use std::time::Instant;
13
14use boomphf::hashmap::BoomHashMap2;
15use indicatif::MultiProgress;
16use indicatif::ProgressBar;
17use indicatif::ProgressIterator;
18use indicatif::ProgressStyle;
19use itertools::Itertools;
20use log::debug;
21use log::warn;
22use rayon::current_num_threads;
23use rayon::prelude::*;
24
25use crate::KmerDataItem;
26use crate::reads::Read;
27use crate::reads::ReadsPaired;
28use crate::reads::Strandedness;
29use crate::summarizer::SummaryConfig;
30use crate::summarizer::SummaryData;
31use crate::Dir;
32use crate::Exts;
33use crate::Kmer;
34use crate::Vmer;
35use crate::BUCKETS;
36use crate::PROGRESS_STYLE;
37
38const HEAP_APPROX: f32 = 1.5;
39
40pub fn bucket<K: Kmer>(kmer: K) -> usize {
42 if K::k() > 3 {
43 (kmer.get(0) as usize) << 6
44 | (kmer.get(1) as usize) << 4
45 | (kmer.get(2) as usize) << 2
46 | (kmer.get(3) as usize)
47 } else {
48 kmer.to_u64() as usize
49 }
50}
51
52fn bucket_flip<K: Kmer>(kmer: K, stranded: Strandedness) -> (usize, K) {
53 let min_kmer = match stranded {
57 Strandedness::Unstranded => {
58 let (min_kmer, _) = kmer.min_rc_flip();
59 min_kmer
60 },
61 Strandedness::Forward => kmer,
62 Strandedness::Reverse => kmer.rc(),
63 };
64
65 (bucket(min_kmer), min_kmer)
67}
68
69fn bucket_ext_flip<K: Kmer>(kmer: K, exts: Exts, stranded: Strandedness, bucket_range: Range<usize>) ->Option<(K, Exts, usize)> {
70 let (min_kmer, flip_exts) = match stranded {
74 Strandedness::Unstranded => {
75 let (min_kmer, flip) = kmer.min_rc_flip();
76 let flip_exts = if flip { exts.rc() } else { exts };
77 (min_kmer, flip_exts)
78 },
79 Strandedness::Forward => (kmer, exts),
80 Strandedness::Reverse => (kmer.rc(), exts.rc()),
81 };
82
83 let bucket = if K::k() > 3 { bucket(min_kmer) } else { min_kmer.to_u64() as usize };
85
86 let in_range = bucket >= bucket_range.start && bucket < bucket_range.end;
88
89 if in_range {
90 Some((min_kmer, flip_exts, bucket))
91 } else {
92 None
93 }
94}
95
96fn add_seq_bucket_capacities<K: Kmer, DI: Clone + Copy>(read: &Read<DI>, capacities: &mut [usize; BUCKETS], unique_kmers: &mut HashSet<K>) {
98 for kmer in read.seq().iter_kmers::<K>() {
100 let (bucket, min_kmer) = bucket_flip(kmer, read.stranded());
102 capacities[bucket] += 1;
103
104 unique_kmers.insert(min_kmer);
106 }
107}
108
109fn bucket_ranges<K, SD, DI, I>(n_nodes: usize, input_kmers: usize, memory_size: f32, iter_capacities: I) -> Vec<Range<usize>>
111where I: Iterator<Item = (usize, usize)>
112{
113 let exp_node_mem = mem::size_of::<K>() + mem::size_of::<Exts>() + (mem::size_of::<SD>() as f32 * HEAP_APPROX) as usize;
116
117 let graph_mem = n_nodes * exp_node_mem;
118 debug!("n final nodes: {n_nodes}");
119 debug!("expected graph memory: {graph_mem}");
120
121 let mem_per_kmer = mem::size_of::<(K, Exts, DI)>();
123 debug!("size used for calculation: {} bytes", mem_per_kmer);
124 debug!("size of kmer, E, D: {} bytes", mem::size_of::<(K, Exts, DI)>());
125 debug!("size of K: {} bytes, size of Exts: {} bytes, size of DI: {} bytes", mem::size_of::<K>(), mem::size_of::<Exts>(), mem::size_of::<DI>());
126 debug!("type DI: {}", std::any::type_name::<DI>());
127
128 let memory_limit = (memory_size * 10f32.powf(9.)) as usize;
129 let max_mem = memory_limit.saturating_sub(graph_mem);
130 let required_slices = if max_mem == 0 {
131 BUCKETS
132 } else {
133 mem_per_kmer * input_kmers / max_mem
134 };
135
136 let bucket_ranges = if required_slices >= BUCKETS {
137 warn!("supplied memory limit might not be sufficient, will construct graph with lowest possible memory usage");
138 (0..BUCKETS).map(|i| i..(i+1)).collect::<Vec<_>>()
140 } else {
141 debug!("splitting k-mers into {required_slices} slices");
143
144 let mut start_bucket = 0;
145 let mut size = 0;
146
147 let max_size = max_mem / mem_per_kmer;
149
150 let mut bucket_ranges = Vec::with_capacity(required_slices);
151
152 for (i, capacity) in iter_capacities {
153 size += capacity;
154 if size > max_size {
155 bucket_ranges.push(start_bucket..i);
156 start_bucket = i;
157 size = capacity;
158 }
159 }
160 bucket_ranges.push(start_bucket..BUCKETS);
161
162 bucket_ranges
163 };
164
165 debug!("bucket ranges: {:?}", bucket_ranges);
166 debug!("kmer_mem: {} bytes, max_mem: {} bytes, slices: {}", mem_per_kmer * input_kmers, max_mem, bucket_ranges.len());
167 debug!("bucket_ranges: {:?}", bucket_ranges);
168 assert!(bucket_ranges[bucket_ranges.len() - 1].end >= BUCKETS);
169
170 bucket_ranges
171}
172
173#[inline(never)]
242pub fn filter_kmers_parallel<K, SD, DI>(
244 seqs: &ReadsPaired<DI>,
245 summariy_config: &SummaryConfig,
246 report_all_kmers: bool,
247 memory_size: f32,
248 time: bool,
249) -> (BoomHashMap2<K, Exts, SD>, Vec<K>)
250where
251K: Kmer + Sync + Send,
252SD: Clone + std::fmt::Debug + Send + SummaryData<DI>,
253DI: Clone + Copy + Send + Sync
254{
255 let before_all = Instant::now();
257
258 let multi_pb = MultiProgress::new();
260 let style = ProgressStyle::with_template(PROGRESS_STYLE).unwrap().progress_chars("#/-");
261
262 let n_threads = current_num_threads();
264 let n_reads = seqs.n_reads();
265 let sz = n_reads / n_threads + 1;
266
267 debug!("n_reads: {}", n_reads);
268 debug!("sz: {}", sz);
269
270 let mut parallel_ranges = Vec::with_capacity(n_threads);
271 let mut start = 0;
272 while start < n_reads {
273 parallel_ranges.push(start..start + sz);
274 start += sz;
275 }
276
277 let last_start = parallel_ranges.pop().expect("no kmers in parallel ranges").start;
278 parallel_ranges.push(last_start..n_reads);
279 debug!("parallel ranges: {:?}", parallel_ranges);
280
281 let capacities = Arc::new(Mutex::new(vec![[0; BUCKETS]; n_threads]));
282 let unique_kmers = Arc::new(Mutex::new(vec![HashSet::<K>::new(); n_threads]));
283 let too_short_reads = Arc::new(Mutex::new(0));
284
285 let pb_size_buckets = multi_pb.add(ProgressBar::new(seqs.n_reads() as u64));
286 pb_size_buckets.set_style(style.clone());
287 pb_size_buckets.set_message(format!("{:<32}", "finding bucket sizes"));
288
289 parallel_ranges.clone().into_par_iter().enumerate().for_each(|(i, range)| {
290
291 let mut thread_capacities = [0usize; BUCKETS];
293 let mut thread_kmers = HashSet::new();
294 let mut threads_too_short_reads = 0;
295 for ref read in seqs.iter_partial(range.clone())
296 {
297 add_seq_bucket_capacities(read, &mut thread_capacities, &mut thread_kmers);
299 if read.seq().len() < K::k() { threads_too_short_reads += 1 };
300 pb_size_buckets.inc(1);
301 }
302
303 let mut cap = capacities.lock().expect("error locking capacity mutex");
304 cap[i] = thread_capacities;
305
306 let mut u_kmers = unique_kmers.lock().expect("error locking coverages mutex");
307 u_kmers[i] = thread_kmers;
308
309 let mut tsr = too_short_reads.lock().expect("error locking n short reads");
310 *tsr += threads_too_short_reads;
311 });
312
313 let capacities = capacities.lock().expect("error in final lock capacities");
314 let input_kmers = capacities.iter().flatten().sum::<usize>();
315 let too_short_reads = *too_short_reads.lock().expect("error in last lock n short reads");
316
317 if too_short_reads > 0 {
318 warn!("{too_short_reads} out of {} reads will be skipped in graph construction because they are shorter than k", seqs.n_reads());
319 }
320 if too_short_reads >= seqs.n_reads() {
321 panic!("none of the reads were longer than k, aborting")
322 }
323
324 let mut unique_kmers = unique_kmers.lock().expect("error final lock coverages");
325
326 let mut combined_kmers = unique_kmers.pop().expect("no k-mers, empty graph");
328
329 while let Some(k) = unique_kmers.pop() {
330 combined_kmers.extend(k);
331 }
332
333 let iter_capacities = (0..BUCKETS).map(|i| (i, capacities.iter().map(|c_bucket| c_bucket[i]).sum::<usize>()));
334 let bucket_ranges = bucket_ranges::<K, SD, DI, _>(combined_kmers.len(), input_kmers, memory_size, iter_capacities);
335
336 let n_slices = bucket_ranges.len();
337
338 debug!("n of seqs: {}", seqs.n_reads());
339
340 let mut time_picking_par = 0.;
341 let mut time_picking = 0.;
342 let mut time_summarizing = 0.;
343
344 let shared_target_vecs = Arc::new(Mutex::new((Vec::new(), Vec::new(), Vec::new(), Vec::new())));
345
346 if time { println!("time all prepariations before sliced in filter_kmers (s): {}", before_all.elapsed().as_secs_f32()) }
347
348 let pb_bucket_ranges = multi_pb.add(ProgressBar::new(bucket_ranges.len() as u64));
349 pb_bucket_ranges.set_style(style.clone());
350 pb_bucket_ranges.set_message(format!("{:<32}", "filtering kmers"));
351
352 for (i, bucket_range) in bucket_ranges.into_iter().enumerate() {
353
354 debug!("Processing slice {} of {}", i+1, n_slices);
355
356 let before_kmer_picking = Instant::now();
357 let kmer_buckets = Arc::new(Mutex::new(vec![Vec::new(); n_threads]));
365
366 let before_picking_parallel = Instant::now();
367
368 let pb_fill_buckets = multi_pb.add(ProgressBar::new(seqs.n_reads() as u64));
369 pb_fill_buckets.set_style(style.clone());
370 pb_fill_buckets.set_message(format!("{:<32}", "filling buckets with k-mers"));
371
372 let pb_sum_buckets = multi_pb.add(ProgressBar::new(BUCKETS as u64));
373 pb_sum_buckets.set_style(style.clone());
374 pb_sum_buckets.set_message(format!("{:<32}", "summarizing k-mers in buckets"));
375
376 parallel_ranges.clone().into_par_iter().enumerate().for_each(|(i, range)| {
377 let mut kmer_buckets1d = Vec::with_capacity(BUCKETS);
378
379 for (i, capacity) in capacities[i].into_iter().enumerate() {
381 if bucket_range.contains(&i) {
382 kmer_buckets1d.push(Vec::with_capacity(capacity));
384 } else {
385 kmer_buckets1d.push(Vec::new());
387 }
388
389 }
390
391 for ref read in seqs.iter_partial(range.clone())
393 {
394 for (kmer, exts, quality) in read.iter_kmer_exts_quality::<K>() {
395 if let Some((min_kmer, flip_exts, bucket)) = bucket_ext_flip(kmer, exts, read.stranded(), bucket_range.clone()) {
398 kmer_buckets1d[bucket].push(KmerDataItem::new(min_kmer, flip_exts, read.data(), quality));
399 }
400 }
401
402 pb_fill_buckets.inc(1);
403 }
404
405 let _kb_clone = Arc::clone(&kmer_buckets);
407 let mut kb2d = kmer_buckets.lock().expect("lock kmer buckets 2d");
408 kb2d[i] = kmer_buckets1d;
410
411 });
412
413 time_picking_par += before_picking_parallel.elapsed().as_secs_f32();
414
415 let mut kmer_buckets = kmer_buckets.lock().expect("unlock kmer_buckets final");
417 let kmer_buckets = mem::take(&mut *kmer_buckets);
418
419 let mut new_buckets = vec![Vec::new(); BUCKETS];
421 for thread_vec in kmer_buckets.into_iter() {
423 for (i, mut bucket) in thread_vec.into_iter().enumerate() {
424 new_buckets[i].reserve_exact(bucket.len());
425 new_buckets[i].append(&mut bucket);
426 }
427 }
428
429 time_picking += before_kmer_picking.elapsed().as_secs_f32();
430
431 let before_parallel = Instant::now();
432
433 new_buckets.into_par_iter().for_each(|mut kmer_vec| {
436 kmer_vec.sort_by_key(|elt| elt.kmer);
437
438 let size = kmer_vec.iter().chunk_by(|elt| elt.kmer).into_iter().count();
439
440 let mut all_kmers = Vec::with_capacity(size);
441 let mut valid_kmers = Vec::with_capacity(size);
442 let mut valid_exts = Vec::with_capacity(size);
443 let mut valid_data = Vec::with_capacity(size);
444
445
446 for (kmer, kmer_obs_iter) in kmer_vec.into_iter().chunk_by(|elt| elt.kmer).into_iter() {
447 let (is_valid, exts, summary_data) = SD::summarize(kmer_obs_iter, summariy_config);
448 if report_all_kmers {
449 all_kmers.push(kmer);
450 }
451 if is_valid {
452 valid_kmers.push(kmer);
453 valid_exts.push(exts);
454 valid_data.push(summary_data);
455 }
456 }
457
458 if !valid_kmers.is_empty() {
461
462 let _stv_clone = Arc::clone(&shared_target_vecs);
463 let mut stv = shared_target_vecs.lock().expect("lock target vectors");
464 stv.0.reserve_exact(valid_kmers.len());
466 stv.0.append(&mut valid_kmers);
467 stv.1.reserve_exact(valid_exts.len());
469 stv.1.append(&mut valid_exts);
470 stv.2.reserve_exact(valid_data.len());
472 stv.2.append(&mut valid_data);
473 }
474
475 if !all_kmers.is_empty() {
477 let _stv_clone = Arc::clone(&shared_target_vecs);
478 let mut stv = shared_target_vecs.lock().expect("lock target vectors");
479 stv.3.reserve_exact(all_kmers.len());
481 stv.3.append(&mut all_kmers);
482 }
483
484 pb_sum_buckets.inc(1);
485 });
486 pb_bucket_ranges.inc(1);
489
490 time_summarizing += before_parallel.elapsed().as_secs_f32();
491
492 debug!("processed slice {}", i+1);
493 }
494 pb_bucket_ranges.finish_and_clear();
495
496 if time {
497 println!("time collecting par (s): {}", time_picking_par);
498 println!("time collecting (s): {}", time_picking);
499 println!("time summarizing (s): {}", time_summarizing);
500 }
501
502 let stv = shared_target_vecs.lock().expect("final lock target vectors");
503
504 debug!("valid kmers - capacity: {}, size: {}, mem: {}", stv.0.capacity(), stv.0.len(), mem::size_of_val(&*stv.0));
505 debug!("valid exts - capacity: {}, size: {}, mem: {}", stv.1.capacity(), stv.1.len(), mem::size_of_val(&*stv.1));
506 debug!("valid data - capacity: {}, size: {}, struct mem: {}, real mem: {}", stv.2.capacity(), stv.2.len(), mem::size_of_val(&*stv.2), {
507 let mut data_size = 0;
508 for data in &stv.2 {
509 data_size += data.mem();
510 }
511 data_size
512 });
513 debug!("all kmers - capacity: {}, size: {}, mem: {}", stv.3.capacity(), stv.3.len(), mem::size_of_val(&*stv.3));
514
515
516 let before_hash = Instant::now();
517 let hm = BoomHashMap2::new_parallel(stv.0.to_vec(), stv.1.to_vec(), stv.2.to_vec());
518 let after_hash = before_hash.elapsed().as_secs_f32();
519 let all_kmers = stv.3.to_vec();
520
521 let filter_kmers_inner = before_all.elapsed().as_secs_f32();
522 if time {
523 println!("time filter_kmers inner (s): {}", filter_kmers_inner);
524 println!("time build filtered hash map (s): {}", after_hash);
525 }
526
527 (
528 hm,
529 all_kmers,
530 )
531}
532
533#[inline(never)]
602pub fn filter_kmers<SD, K, DI>(
603 seqs: &ReadsPaired<DI>,
604 summary_config: &SummaryConfig,
605 report_all_kmers: bool,
606 memory_size: f32,
607 time: bool,
608) -> (BoomHashMap2<K, Exts, SD>, Vec<K>)
609where
610 SD: Debug + SummaryData<DI>,
611 K: Kmer,
612 DI: Copy + Clone + Debug + Hash + Eq
613{
614 let before_all = Instant::now();
615
616 let multi_pb = MultiProgress::new();
618 let style = ProgressStyle::with_template(PROGRESS_STYLE).unwrap().progress_chars("#/-");
619
620 let pb = multi_pb.add(ProgressBar::new(seqs.n_reads() as u64));
621 pb.set_style(style.clone());
622 pb.set_message(format!("{:<32}", "finding bucket lengths"));
623
624 let mut capacities = [0; BUCKETS];
626
627 let mut unique_kmers = HashSet::<K>::new();
629 let mut too_short_reads = 0;
630
631 for ref read in seqs.iter().progress_with(pb) {
632 add_seq_bucket_capacities(read, &mut capacities, &mut unique_kmers);
634 if read.seq().len() < K::k() { too_short_reads += 1}
635 }
636
637 if too_short_reads > 0 {
638 warn!("{too_short_reads} out of {} reads will be skipped in graph construction because they are shorter than k", seqs.n_reads());
639 }
640 if too_short_reads >= seqs.n_reads() {
641 panic!("none of the reads were longer than k, aborting")
642 }
643
644 debug!("kmer capacities: {:?}, times {}", capacities, mem::size_of::<(K, Exts, DI)>());
645 let input_kmers = capacities.iter().sum::<usize>();
646
647 if time { println!("time counting kmers (s): {}", before_all.elapsed().as_secs_f32()) }
648
649 let iter_capacities = capacities.iter().enumerate().map(|(i, &c)| (i, c));
650 let bucket_ranges = bucket_ranges::<K, SD, DI, _>(unique_kmers.len(), input_kmers, memory_size, iter_capacities);
651
652 let n_slices = bucket_ranges.len();
653
654 debug!("n of seqs: {}", seqs.n_reads());
655
656 let mut all_kmers = Vec::new();
657 let mut valid_kmers = Vec::new();
658 let mut valid_exts = Vec::new();
659 let mut valid_data = Vec::new();
660
661 let mut time_collecting = 0.;
662 let mut time_summarizing = 0.;
663
664 if time { println!("time all prepariations before sliced in filter_kmers (s): {}", before_all.elapsed().as_secs_f32()) }
665
666 let pb_bucket_ranges = multi_pb.add(ProgressBar::new(bucket_ranges.len() as u64));
667 pb_bucket_ranges.set_style(style.clone());
668 pb_bucket_ranges.set_message(format!("{:<32}", "filtering k-mers"));
669
670
671 for (i, bucket_range) in bucket_ranges.into_iter().enumerate() {
673 debug!("Processing slice {} of {}", i+1, n_slices);
674
675 let before_kmer_picking = Instant::now();
676 let mut kmer_buckets = Vec::with_capacity(BUCKETS);
683 for (i, capacity) in capacities.iter().enumerate() {
685 if bucket_range.contains(&i) {
686 kmer_buckets.push(Vec::with_capacity(*capacity));
688 } else {
689 kmer_buckets.push(Vec::new());
691 }
692
693 }
694
695 let pb = multi_pb.add(ProgressBar::new(seqs.n_reads() as u64));
697 pb.set_style(style.clone());
698 pb.set_message(format!("{:<32}", "filling buckets with kmers"));
699
700 for ref read in seqs.iter().progress_with(pb) {
701 for (kmer, exts, quality) in read.iter_kmer_exts_quality::<K>() {
703 if let Some((min_kmer, flip_exts, bucket)) = bucket_ext_flip(kmer, exts, read.stranded(), bucket_range.clone()) {
706 kmer_buckets[bucket].push(KmerDataItem::new(min_kmer, flip_exts, read.data(), quality));
707 }
708 }
709 }
710
711 time_collecting += before_kmer_picking.elapsed().as_secs_f32();
712
713 let before_summarizing = Instant::now();
714
715 let pb = multi_pb.add(ProgressBar::new(kmer_buckets.len() as u64));
717 pb.set_style(style.clone());
718 pb.set_message(format!("{:<32}", "summarizing k-mers in buckets"));
719
720 for mut kmer_vec in kmer_buckets.into_iter().progress_with(pb) {
721 kmer_vec.sort_by_key(|elt| elt.kmer);
723
724
725 let size = kmer_vec.iter().chunk_by(|elt| elt.kmer).into_iter().count();
727
728 valid_kmers.reserve_exact(size);
732 valid_exts.reserve_exact(size);
733 valid_data.reserve_exact(size);
734
735 if report_all_kmers {
737 all_kmers.reserve_exact(size);
738 }
739
740 for (kmer, kmer_obs_iter) in kmer_vec.into_iter().chunk_by(|elt| elt.kmer).into_iter() {
742 let (is_valid, exts, summary_data) = SD::summarize(kmer_obs_iter, summary_config);
744 if report_all_kmers {
745 all_kmers.push(kmer);
746 }
747 if is_valid {
748 valid_kmers.push(kmer);
749 valid_exts.push(exts);
750 valid_data.push(summary_data);
751 }
752 }
753 }
754
755 pb_bucket_ranges.inc(1);
756
757 time_summarizing += before_summarizing.elapsed().as_secs_f32();
758
759 debug!("valid kmers - capacity: {}, size: {}, mem: {} Bytes", valid_kmers.capacity(), valid_kmers.len(), mem::size_of_val(&*valid_kmers));
760 debug!("valid exts - capacity: {}, size: {}, mem: {} Bytes", valid_exts.capacity(), valid_exts.len(), mem::size_of_val(&*valid_exts));
761 debug!("valid data - capacity: {}, size: {}, mem: {} Bytes", valid_data.capacity(), valid_data.len(), mem::size_of_val(&*valid_data));
762 }
763
764 pb_bucket_ranges.finish_and_clear();
765
766 if time {
767 println!("time collecting (s): {}", time_collecting);
768 println!("time summarizing (s): {}", time_summarizing);
769 }
770
771
772 debug!(
773 "Unique kmers: {}, All kmers (if returned): {}",
774 valid_kmers.len(),
775 all_kmers.len(),
776 );
777
778 debug!("size of valid kmers: {} Bytes
779 size of valid exts: {} Bytes
780 size of valid data: {} Bytes", mem::size_of_val(&*valid_kmers), mem::size_of_val(&*valid_exts), mem::size_of_val(&*valid_data));
781
782 let before_hash = Instant::now();
783 let hm = BoomHashMap2::new(valid_kmers, valid_exts, valid_data);
784 let after_hash = before_hash.elapsed().as_secs_f32();
785
786 let filter_kmers_inner = before_all.elapsed().as_secs_f32();
787 if time {
788 println!("time filter_kmers inner (s): {}", filter_kmers_inner);
789 println!("time build filter hash map (s): {}", after_hash);
790 }
791 (
792 hm,
793 all_kmers,
794 )
795}
796
797pub fn remove_censored_exts_sharded<K: Kmer, D>(
803 stranded: bool,
804 valid_kmers: &mut [(K, (Exts, D))],
805 all_kmers: &[K],
806) {
807 for idx in 0..valid_kmers.len() {
808 let mut new_exts = Exts::empty();
809 let kmer = valid_kmers[idx].0;
810 let exts = (valid_kmers[idx].1).0;
811
812 for dir in [Dir::Left, Dir::Right].iter() {
813 for i in 0..4 {
814 if exts.has_ext(*dir, i) {
815 let _ext_kmer = kmer.extend(i, *dir);
816
817 let ext_kmer = if stranded {
818 _ext_kmer
819 } else {
820 _ext_kmer.min_rc()
821 };
822
823 let censored = if valid_kmers.binary_search_by_key(&ext_kmer, |d| d.0).is_ok() {
824 false
826 } else {
827 all_kmers.binary_search(&ext_kmer).is_ok()
829 };
830
831 if !censored {
832 new_exts = new_exts.set(*dir, i);
833 }
834 }
835 }
836 }
837
838 (valid_kmers[idx].1).0 = new_exts;
839 }
840}
841
842pub fn remove_censored_exts<K: Kmer, D>(stranded: bool, valid_kmers: &mut [(K, (Exts, D))]) {
845 for idx in 0..valid_kmers.len() {
846 let mut new_exts = Exts::empty();
847 let kmer = valid_kmers[idx].0;
848 let exts = (valid_kmers[idx].1).0;
849
850 for dir in [Dir::Left, Dir::Right].iter() {
851 for i in 0..4 {
852 if exts.has_ext(*dir, i) {
853 let ext_kmer = if stranded {
854 kmer.extend(i, *dir)
855 } else {
856 kmer.extend(i, *dir).min_rc()
857 };
858
859 let kmer_valid = valid_kmers.binary_search_by_key(&ext_kmer, |d| d.0).is_ok();
860
861 if kmer_valid {
862 new_exts = new_exts.set(*dir, i);
863 }
864 }
865 }
866 }
867
868 (valid_kmers[idx].1).0 = new_exts;
869 }
870}
871
872#[cfg(test)]
873mod tests {
874 use boomphf::hashmap::BoomHashMap2;
875 use crate::{Exts, dna_string::DnaString, filter::*, kmer::{Kmer2, Kmer6, Kmer80}, reads::Reads, summarizer::{SampleInfo, TagsSumData}, test::{random_dna, random_kmer}};
876
877 #[test]
878 fn test_filter_kmers() {
879 let fastq = [
880 (DnaString::from_dna_string("AAAAATTT"), Exts::empty(), 6u8),
881 (DnaString::from_dna_string("TTTTTTTTTTAAAAAA"), Exts::empty(), 6u8),
882 (DnaString::from_dna_string("AAAAAAAAAAAAA"), Exts::empty(), 7u8),
883 ];
884
885 let reads = Reads::from_vmer_vec(fastq, crate::reads::Strandedness::Unstranded);
886
887 let sample_info = SampleInfo::new(0, 0, Vec::new());
888
889 let config = SummaryConfig::new(sample_info).with_stat_test(crate::summarizer::StatTest::StudentsTTest);
890
891
892 let (hm, _): (BoomHashMap2<Kmer6, Exts, TagsSumData>, Vec<_>) = filter_kmers(
893 &ReadsPaired::Unpaired { reads },
894 &config,
895 false,
896 1.,
897 false,
898 );
899
900 println!("{:?}", hm);
901
902 }
903
904 #[test]
905 fn test_filter_kmers_parallel() {
906 let mut reads = Reads::new(crate::reads::Strandedness::Unstranded);
920
921 for _i in 0..10000 {
922 let dna = random_dna(150);
923 reads.add_from_bytes(&dna, None, 0u8);
924 }
925
926 let sample_info = SampleInfo::new(0, 0, Vec::new());
927 let config = SummaryConfig::new(sample_info.clone()).with_stat_test(crate::summarizer::StatTest::StudentsTTest);
928
929
930 let (hm, _): (BoomHashMap2<Kmer6, Exts, TagsSumData>, Vec<_>) = filter_kmers_parallel(
931 &ReadsPaired::Unpaired { reads },
932 &config,
933 false,
934 1.,
935 false,
936 );
937
938 println!("{:?}", hm);
939
940 }
941
942 #[test]
943 fn test_filter_kmers_parallel_k80() {
944 let mut reads = Reads::new(crate::reads::Strandedness::Unstranded);
958
959 for _i in 0..10000 {
960 let dna = random_dna(150);
961 reads.add_from_bytes(&dna, None, 0u8);
962 }
963
964 let sample_info = SampleInfo::new(0, 0, Vec::new());
965 let config = SummaryConfig::new(sample_info.clone()).with_stat_test(crate::summarizer::StatTest::StudentsTTest);
966
967
968 let (_hm, _): (BoomHashMap2<Kmer80, Exts, TagsSumData>, Vec<_>) = filter_kmers_parallel(
969 &ReadsPaired::Unpaired { reads },
970 &config,
971 false,
972 1.,
973 false,
974 );
975 }
976
977
978 #[test]
979 fn test_par_hmap_combination() {
980 let n_threads = rayon::current_num_threads();
981 let kmers = Arc::new(Mutex::new(vec![HashSet::new(); n_threads]));
982
983 (0..n_threads).into_par_iter().for_each(|i| {
984 let mut ks = HashSet::new();
985 for _j in 0..100 {
986 let kmer = random_kmer::<Kmer2>();
987 ks.insert(kmer);
988 }
989 let mut c = kmers.lock().expect("cov lock");
990 c[i] = ks;
991 });
992
993 println!("k-mers uncombinded: {:?}", kmers);
994
995 let mut kmers = kmers.lock().expect("final lock coverages");
996
997 let mut combined_kmers = kmers.pop().expect("no kmers");
998 while let Some(kmap) = kmers.pop() {
999 combined_kmers.extend(kmap);
1000 }
1001
1002 assert_eq!(combined_kmers.len(), 16);
1003
1004 println!("combined k-mers: {:?}", combined_kmers)
1005 }
1006}
1007