Skip to content

Commit 8374343

Browse files
authored
Merge pull request #422 from AngieHinrichs/clade-mutations-update
Improved file format for matUtils annotate --clade-mutations.
2 parents d54fa3e + f66dc4a commit 8374343

1 file changed

Lines changed: 44 additions & 21 deletions

File tree

src/matUtils/annotate.cpp

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -206,17 +206,24 @@ void assignLineages (MAT::Tree& T, const std::string& clade_to_nid_filename, boo
206206

207207
void parse_clade_mutations(const std::string& clade_mutations_filename,
208208
std::map<std::string, std::vector<MAT::Mutation>>& clade_mutations,
209-
std::unordered_set<std::string> clades_already_assigned) {
209+
std::unordered_set<std::string>& clades_already_assigned) {
210210
std::ifstream infile(clade_mutations_filename);
211211
if (!infile) {
212212
fprintf(stderr, "ERROR: Could not open the clade mutations file: %s!\n", clade_mutations_filename.c_str());
213213
exit(1);
214214
}
215+
// While parsing, keep a map of lineage name to mutations for all clades, even the ones that we won't need to
216+
// search for because they're in clades_already_assigned, in case a descendant refers to the lineage as ancestor.
217+
std::map<std::string, std::vector<MAT::Mutation>> all_clade_mutations;
215218
std::string line;
216219

217220
fprintf(stderr, "Reading clade mutations file %s.\n", clade_mutations_filename.c_str());
218221
bool got_error = false;
219222
while (std::getline(infile, line)) {
223+
if (line[0] == '#') {
224+
// Comment line -- skip it
225+
continue;
226+
}
220227
std::vector<std::string> words;
221228
MAT::string_split(line, '\t', words);
222229
// Empty second word (for root node, no mutations) is ignored by string_split; add it back.
@@ -229,15 +236,28 @@ void parse_clade_mutations(const std::string& clade_mutations_filename,
229236
continue;
230237
}
231238
std::string clade = words[0];
232-
// If clade has already been assigned by a method with higher precedence, move on to the next one.
233-
if (clades_already_assigned.find(clade) != clades_already_assigned.end()) {
239+
// It's an error if the same clade is defined on multiple lines (probably copy-paste symptom).
240+
if (all_clade_mutations.find(clade) != all_clade_mutations.end()) {
241+
fprintf(stderr, "ERROR: clade %s is defined on multiple lines\n", clade.c_str());
242+
got_error = true;
234243
continue;
235244
}
236-
// Parse mutations from words[1] and store in clade_mutations[words[0]]
237-
std::vector<MAT::Mutation> mutations;
238-
std::vector<int> mut_positions;
245+
// Parse mutations from words[1] and store in all_clade_mutations[words[0]]
246+
// Use MAT::Node to store mutations so we can use its method add_mutation to handle multiple mutations at the
247+
// same position.
248+
MAT::Node node;
239249
std::vector<std::string> mut_words;
240250
MAT::string_split(words[1], mut_words);
251+
// If first mut_word is the name of a lineage defined on a previous line, start with that lineage's mutations
252+
if (mut_words.size() > 0) {
253+
auto iter = all_clade_mutations.find(mut_words[0]);
254+
if (iter != all_clade_mutations.end()) {
255+
// Copy the included lineage's vector of mutations
256+
node.mutations = iter->second;
257+
// Remove the lineage name from mut_words
258+
mut_words.erase(mut_words.begin());
259+
}
260+
}
241261
for (std::string path_el: mut_words) {
242262
// Ignore empty string or ">"
243263
if (path_el == "" || path_el == ">") {
@@ -256,20 +276,22 @@ void parse_clade_mutations(const std::string& clade_mutations_filename,
256276
mut_string.c_str(), clade.c_str(), path_el.c_str());
257277
got_error = true;
258278
} else {
259-
if (std::find(mut_positions.begin(), mut_positions.end(), mut->position) != mut_positions.end()) {
260-
fprintf(stderr, "ERROR: Clade %s: position %d used multiple times, must appear only once per clade.\n",
261-
clade.c_str(), mut->position);
262-
got_error = true;
263-
continue;
264-
}
265-
mut_positions.emplace_back(mut->position);
266-
mutations.emplace_back(std::move(*mut));
279+
node.add_mutation(*mut);
267280
}
281+
delete mut;
268282
}
269283
}
270-
clade_mutations[clade] = mutations;
284+
all_clade_mutations[clade] = node.mutations;
271285
}
272286
infile.close();
287+
288+
// For all clades that are not in clades_already_assigned, add mutations to clade_mutations.
289+
for (auto it: all_clade_mutations) {
290+
const std::string clade = (const std::string)(it.first);
291+
if (clades_already_assigned.find(clade) == clades_already_assigned.end()) {
292+
clade_mutations[clade] = it.second;
293+
}
294+
}
273295
if (got_error) {
274296
fprintf(stderr, "Encountered errors -- exiting.\n");
275297
exit(1);
@@ -465,11 +487,6 @@ void assignLineages (MAT::Tree& T, const std::string& clade_filename,
465487
const std::string& mutations_filename, const std::string& details_filename) {
466488
static tbb::affinity_partitioner ap;
467489

468-
fprintf(stderr, "Copying tree with uncondensed leaves.\n");
469-
timer.Start();
470-
auto uncondensed_T = MAT::get_tree_copy(T);
471-
uncondensed_T.uncondense_leaves();
472-
473490
auto dfs = T.depth_first_expansion();
474491
size_t total_nodes = dfs.size();
475492
FILE *mutations_file = NULL, *details_file = NULL;
@@ -486,6 +503,8 @@ void assignLineages (MAT::Tree& T, const std::string& clade_filename,
486503
}
487504

488505

506+
fprintf(stderr, "Initializing annotations.\n");
507+
timer.Start();
489508
init_annotations(dfs, clear_current);
490509
std::unordered_map<std::string, size_t> dfs_idx;
491510
for (size_t idx = 0; idx < total_nodes; idx++) {
@@ -505,9 +524,13 @@ void assignLineages (MAT::Tree& T, const std::string& clade_filename,
505524
parse_clade_mutations(clade_mutations_filename, clade_mutations_map, clades_already_assigned);
506525
}
507526
if (clade_filename != "") {
527+
fprintf(stderr, "Copying tree with uncondensed leaves.\n");
528+
timer.Start();
529+
auto uncondensed_T = MAT::get_tree_copy(T);
530+
uncondensed_T.uncondense_leaves();
508531
parse_clade_names(clade_filename, clade_mutations_map, clades_already_assigned, clade_map,
509532
uncondensed_T, min_freq, mask_freq);
510-
533+
fprintf(stderr, "Completed in %ld msec \n\n", timer.Stop());
511534
}
512535

513536
struct Node_freq {

0 commit comments

Comments
 (0)