-
Notifications
You must be signed in to change notification settings - Fork 8
Add random sampling for read depth estimation. #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| #pragma once | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <forward_list> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <seqan3/io/sam_file/input.hpp> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| /*! \brief Returns a list of pairs, where the first integer is a random chromosome and the second is a random position. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * The list is sorted by default. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * \param sample_size - The number of positions to generate. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * \param header - The header from the SAM file input. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * \return Returns a sorted forward_list of pairs of reference chromosome IDs and positions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::forward_list<std::pair<int32_t, int32_t>> get_random_positions(uint64_t sample_size, seqan3::sam_file_header<std::deque<std::string>> & header) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::forward_list<std::pair<int32_t, int32_t>> output{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (sample_size == 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.push_front(std::pair<int32_t, int32_t>{-1, -1}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
this makes it clear that this is a special case. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| int32_t rand_chr{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| int32_t rand_pos{}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < sample_size; ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rand_chr = std::rand() % header.ref_ids().size(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should consider using the "real" random module. https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution#Example That would also make clear what your distribution is. Furthermore, I would require passing in a random generator into this function so that the "randomness" can be controlled from the outside. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| rand_pos = std::rand() % std::get<0>(header.ref_id_info[rand_chr]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.push_front(std::pair<int32_t, int32_t>{rand_chr, rand_pos}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+24
to
+30
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| output.sort(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return output; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| /*! \brief Get the read length of a read from its cigar string. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * \param cigar - The cigar according to the seqan3 representation (a vector of cigar alphabet). | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| * \return Returns the length of the cigar string. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint32_t get_read_length(std::vector<seqan3::cigar> & cigar) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| using seqan3::get; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint32_t result{0}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (auto e : cigar) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| result += get<0>(e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this correct? The sam specification says:
“Consumes query” and “consumes reference” indicate whether the CIGAR operation causes the alignment to step along the query sequence and the reference sequence respectively. So I would say that you over-count the read length. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||||||
| #include <seqan3/io/sam_file/input.hpp> // SAM/BAM support | ||||||||
| #include <seqan3/io/sequence_file/output.hpp> // FASTA support | ||||||||
|
|
||||||||
| #include "misc/statistics.hpp" // for calculating average read depth | ||||||||
| #include "modules/clustering/simple_clustering_method.hpp" // for the simple clustering method | ||||||||
| #include "modules/sv_detection_methods/analyze_cigar_method.hpp" // for the split read method | ||||||||
| #include "modules/sv_detection_methods/analyze_sa_tag_method.hpp" // for the cigar string method | ||||||||
|
|
@@ -20,7 +21,8 @@ void detect_variants_in_alignment_file(const std::filesystem::path & alignment_f | |||||||
| const clustering_methods & clustering_method, | ||||||||
| const refinement_methods & refinement_method, | ||||||||
| const uint64_t & min_var_length, | ||||||||
| const std::filesystem::path & output_file_path) | ||||||||
| const std::filesystem::path & output_file_path, | ||||||||
| const uint64_t & sample_size) | ||||||||
| { | ||||||||
| // Open input alignment file | ||||||||
| using my_fields = seqan3::fields<seqan3::field::id, | ||||||||
|
|
@@ -42,6 +44,12 @@ void detect_variants_in_alignment_file(const std::filesystem::path & alignment_f | |||||||
| std::vector<seqan3::dna5_vector> insertion_alleles{}; | ||||||||
| uint16_t num_good = 0; | ||||||||
|
|
||||||||
| // Obtain list of random chromosomes and positions to get read depth from. | ||||||||
| std::forward_list<std::pair<int32_t, int32_t>> rand_sample = get_random_positions(sample_size, alignment_file.header()); | ||||||||
| uint32_t avg_depth{0}; | ||||||||
| uint32_t cur_depth{0}; | ||||||||
| uint32_t num_pos{0}; | ||||||||
|
|
||||||||
| for (auto & rec : alignment_file) | ||||||||
| { | ||||||||
| const std::string query_name = seqan3::get<seqan3::field::id>(rec); // 1: QNAME | ||||||||
|
|
@@ -60,6 +68,26 @@ void detect_variants_in_alignment_file(const std::filesystem::path & alignment_f | |||||||
| continue; | ||||||||
|
|
||||||||
| const std::string ref_name = ref_ids[ref_id]; | ||||||||
| uint32_t read_length{get_read_length(cigar)}; | ||||||||
| // If there are positions to be sampled, then sample them. | ||||||||
| if (!rand_sample.empty() && sample_size > 0) | ||||||||
| { | ||||||||
| if (ref_id == std::get<0>(rand_sample.front()) && // Correct chromosome. | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
give the pair content a name that makes it easier to understand. |
||||||||
| pos <= std::get<1>(rand_sample.front()) && // Read starts before or at the position. | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, not all cigar length's are for reads, they can also only affect the sequence. |
||||||||
| std::get<1>(rand_sample.front()) <= pos + read_length) // Read ends after or at position. | ||||||||
| { | ||||||||
| ++cur_depth; | ||||||||
| } | ||||||||
| else if (ref_id > std::get<0>(rand_sample.front()) || // Record is at next chromosome | ||||||||
| (ref_id == std::get<0>(rand_sample.front()) && // Record is at same chromosome BUT | ||||||||
| pos > std::get<1>(rand_sample.front()))) // in a later position. | ||||||||
| { | ||||||||
| ++num_pos; | ||||||||
| avg_depth += cur_depth; | ||||||||
| cur_depth = 0; | ||||||||
| rand_sample.pop_front(); | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not completely sure what this does and why you consume your "random" sample throughout the loop without "refreshing" it. What happens if your random sample doesn't get fully consumed, but your next reference starts? Is that possible? |
||||||||
| } | ||||||||
| } | ||||||||
| for (uint8_t method : methods) { | ||||||||
| switch (method) | ||||||||
| { | ||||||||
|
|
@@ -101,6 +129,14 @@ void detect_variants_in_alignment_file(const std::filesystem::path & alignment_f | |||||||
| seqan3::debug_stream << num_good << " good alignments" << std::endl; | ||||||||
| } | ||||||||
| } | ||||||||
| if (sample_size == 0 || num_pos == 0) // User requested no sampling, or all of the random positions generated were not covered. | ||||||||
| { | ||||||||
| avg_depth = 0; | ||||||||
| } | ||||||||
| else | ||||||||
| { | ||||||||
| avg_depth = avg_depth/num_pos; | ||||||||
| } | ||||||||
| std::sort(junctions.begin(), junctions.end()); | ||||||||
|
|
||||||||
| seqan3::debug_stream << "Start clustering...\n"; | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this performance critical? I wouldn't use forward lists otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.