void CoordSearchDialog::EditCompleted( Edit& sender ){ m_targetObj=sender.Text(); }
void NewImageInterface::UpdateInitialValue( Edit& e, Slider& s, double v ) { e.SetText( String().Format( "%.8lf", v ) ); s.SetValue( RoundI( v*s.MaxValue() ) ); }
// merge that properly handles long indels // assumes that alignments should line up end-to-end Alignment merge_alignments(const vector<Alignment>& alns, bool debug) { if (alns.size() == 0) { Alignment aln; return aln; } else if (alns.size() == 1) { return alns.front(); } // where possible get node and target lengths // to validate after merge /* map<int64_t, map<size_t, set<const Alignment*> > > node_lengths; map<int64_t, map<size_t, set<const Alignment*> > > to_lengths; for (auto& aln : alns) { auto& path = aln.path(); // find a mapping that overlaps the whole node // note that edits aren't simplified // so deletions are intact for (size_t i = 0; i < path.mapping_size(); ++i) { auto& m = path.mapping(i); if (m.position().offset() == 0) { // can we see if the next mapping is on the following node if (i < path.mapping_size()-1 && path.mapping(i+1).position().offset() == 0 && mapping_from_length(path.mapping(i+1)) && mapping_from_length(m)) { // we cover the node, record the to_length and from_length set<const Alignment*>& n = node_lengths[m.position().node_id()][from_length(m)]; n.insert(&aln); set<const Alignment*>& t = to_lengths[m.position().node_id()][to_length(m)]; t.insert(&aln); } } } } // verify our input by checking for disagreements for (auto& n : node_lengths) { auto& node_id = n.first; if (n.second.size() > 1) { cerr << "disagreement in node lengths for " << node_id << endl; for (auto& l : n.second) { cerr << "alignments that report length of " << l.first << endl; for (auto& a : l.second) { cerr << pb2json(*a) << endl; } } } else { //cerr << n.second.begin()->second.size() << " alignments support " // << n.second.begin()->first << " as length for " << node_id << endl; } } */ // parallel merge algorithm // for each generation // merge 0<-0+1, 1<-2+3, ... // until there is only one alignment vector<Alignment> last = alns; // get the alignments ready for merge #pragma omp parallel for for (size_t i = 0; i < last.size(); ++i) { Alignment& aln = last[i]; //cerr << "on " << i << "th aln" << endl // << pb2json(aln) << endl; if (!aln.has_path()) { Mapping m; Edit* e = m.add_edit(); e->set_to_length(aln.sequence().size()); e->set_sequence(aln.sequence()); *aln.mutable_path()->add_mapping() = m; } } while (last.size() > 1) { //cerr << "last size " << last.size() << endl; size_t new_count = last.size()/2; //cerr << "new count b4 " << new_count << endl; new_count += last.size() % 2; // force binary //cerr << "New count = " << new_count << endl; vector<Alignment> curr; curr.resize(new_count); #pragma omp parallel for for (size_t i = 0; i < curr.size(); ++i) { //cerr << "merging " << 2*i << " and " << 2*i+1 << endl; // take a pair from the old alignments // merge them into this one if (2*i+1 < last.size()) { auto& a1 = last[2*i]; auto& a2 = last[2*i+1]; curr[i] = merge_alignments(a1, a2, debug); // check that the merge did the right thing /* auto& a3 = curr[i]; for (size_t j = 0; j < a3.path().mapping_size()-1; ++j) { // look up reported node length // and compare to what we saw // skips last mapping auto& m = a3.path().mapping(j); if (from_length(m) == to_length(m) && m.has_position() && m.position().offset()==0 && a3.path().mapping(j+1).has_position() && a3.path().mapping(j+1).position().offset()==0) { auto nl = node_lengths.find(m.position().node_id()); if (nl != node_lengths.end()) { if (nl->second.find(from_length(m)) == nl->second.end()) { cerr << "node length is not consistent for " << m.position().node_id() << endl; cerr << "expected " << nl->second.begin()->first << endl; cerr << "got " << from_length(m) << endl; cerr << "inputs:" << endl << pb2json(a1) << endl << pb2json(a2) << endl << "output: " << endl << pb2json(a3) << endl; //exit(1); } } } } */ } else { auto& a1 = last[2*i]; //cerr << "no need to merge" << endl; curr[i] = a1; } } last = curr; } Alignment res = last.front(); *res.mutable_path() = simplify(res.path()); return res; }
pair<size_t, size_t> Simplifier::simplify_once(size_t iteration) { // Set up the deleted node and edge counts pair<size_t, size_t> to_return {0, 0}; auto& deleted_nodes = to_return.first; auto& deleted_edges = to_return.second; if(!graph.is_valid(true, true, true, true)) { // Make sure the graph is valid and not missing nodes or edges cerr << "error:[vg::Simplifier] Invalid graph on iteration " << iteration << endl; exit(1); } // Make a list of leaf sites list<const Snarl*> leaves; if (show_progress) { cerr << "Iteration " << iteration << ": Scanning " << graph.node_count() << " nodes and " << graph.edge_count() << " edges for sites..." << endl; } for (const Snarl* top_level_site : site_manager.top_level_snarls()) { list<const Snarl*> queue {top_level_site}; while (queue.size()) { const Snarl* site = queue.front(); queue.pop_front(); if (site_manager.is_leaf(site)) { // It's a leaf. Filter it out if it is trivial if (site->type() == ULTRABUBBLE) { auto contents = site_manager.shallow_contents(site, graph, false); if (contents.first.empty()) { // Nothing but the boundary nodes in this snarl continue; } } // Not trivial. Keep it. leaves.push_back(site); } else { for (const Snarl* child_site : site_manager.children_of(site)) { queue.push_back(child_site); } } } } if (show_progress) { cerr << "Found " << leaves.size() << " leaves" << endl; } // Index all the graph paths map<string, unique_ptr<PathIndex>> path_indexes; graph.paths.for_each_name([&](const string& name) { // For every path name, go index it and put it in this collection path_indexes.insert(make_pair(name, move(unique_ptr<PathIndex>(new PathIndex(graph, name))))); }); // Now we have a list of all the leaf sites. create_progress("simplifying leaves", leaves.size()); // We can't use the SnarlManager after we modify the graph, so we load the // contents of all the leaves we're going to modify first. map<const Snarl*, pair<unordered_set<Node*>, unordered_set<Edge*>>> leaf_contents; // How big is each leaf in bp map<const Snarl*, size_t> leaf_sizes; // We also need to pre-calculate the traversals for the snarls that are the // right size, since the traversal finder uses the snarl manager amd might // not work if we modify the graph. map<const Snarl*, vector<SnarlTraversal>> leaf_traversals; for (const Snarl* leaf : leaves) { // Look at all the leaves // Get the contents of the bubble, excluding the boundary nodes leaf_contents[leaf] = site_manager.deep_contents(leaf, graph, false); // For each leaf, calculate its total size. unordered_set<Node*>& nodes = leaf_contents[leaf].first; size_t& total_size = leaf_sizes[leaf]; for (Node* node : nodes) { // For each node include it in the size figure total_size += node->sequence().size(); } if (total_size == 0) { // This site is just the start and end nodes, so it doesn't make // sense to try and remove it. continue; } if (total_size >= min_size) { // This site is too big to remove continue; } // Identify the replacement traversal for the bubble if it's the right size. // We can't necessarily do this after we've modified the graph. vector<SnarlTraversal>& traversals = leaf_traversals[leaf]; traversals = traversal_finder.find_traversals(*leaf); } for (const Snarl* leaf : leaves) { // Look at all the leaves // Get the contents of the bubble, excluding the boundary nodes unordered_set<Node*>& nodes = leaf_contents[leaf].first; unordered_set<Edge*>& edges = leaf_contents[leaf].second; // For each leaf, grab its total size. size_t& total_size = leaf_sizes[leaf]; if (total_size == 0) { // This site is just the start and end nodes, so it doesn't make // sense to try and remove it. continue; } if (total_size >= min_size) { // This site is too big to remove continue; } #ifdef debug cerr << "Found " << total_size << " bp leaf" << endl; for (auto* node : nodes) { cerr << "\t" << node->id() << ": " << node->sequence() << endl; } #endif // Otherwise we want to simplify this site away // Grab the replacement traversal for the bubble vector<SnarlTraversal>& traversals = leaf_traversals[leaf]; if (traversals.empty()) { // We couldn't find any paths through the site. continue; } // Get the traversal out of the vector SnarlTraversal& traversal = traversals.front(); // Determine the length of the new traversal size_t new_site_length = 0; for (size_t i = 1; i < traversal.visit_size() - 1; i++) { // For every non-anchoring node const Visit& visit = traversal.visit(i); // Total up the lengths of all the nodes that are newly visited. assert(visit.node_id()); new_site_length += graph.get_node(visit.node_id())->sequence().size(); } #ifdef debug cerr << "Chosen traversal is " << new_site_length << " bp" << endl; #endif // Now we have to rewrite paths that visit nodes/edges not on this // traversal, or in a different order, or whatever. To be safe we'll // just rewrite all paths. // Find all the paths that traverse this region. // We start at the start node. Copy out all the mapping pointers on that // node, so we can go through them while tampering with them. map<string, set<Mapping*> > mappings_by_path = graph.paths.get_node_mapping(graph.get_node(leaf->start().node_id())); // It's possible a path can enter the site through the end node and // never hit the start. So we're going to trim those back before we delete nodes and edges. map<string, set<Mapping*> > end_mappings_by_path = graph.paths.get_node_mapping(graph.get_node(leaf->end().node_id())); if (!drop_hairpin_paths) { // We shouldn't drop paths if they hairpin and can't be represented // in a simplified bubble. So we instead have to not simplify // bubbles that would have that problem. bool found_hairpin = false; for (auto& kv : mappings_by_path) { // For each path that hits the start node if (found_hairpin) { // We only care if there are 1 or more hairpins, not how many break; } // Unpack the name auto& path_name = kv.first; for (Mapping* start_mapping : kv.second) { // For each visit to the start node if (found_hairpin) { // We only care if there are 1 or more hairpins, not how many break; } // Determine what orientation we're going to scan in bool backward = start_mapping->position().is_reverse(); // Start at the start node Mapping* here = start_mapping; while (here) { // Until we hit the start/end of the path or the mapping we want if (here->position().node_id() == leaf->end().node_id() && here->position().is_reverse() == (leaf->end().backward() != backward)) { // We made it out. // Stop scanning! break; } if (here->position().node_id() == leaf->start().node_id() && here->position().is_reverse() != (leaf->start().backward() != backward)) { // We have encountered the start node with an incorrect orientation. cerr << "warning:[vg simplify] Path " << path_name << " doubles back through start of site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << "; skipping site!" << endl; found_hairpin = true; break; } // Scan left along ther path if we found the site start backwards, and right if we found it forwards. here = backward ? graph.paths.traverse_left(here) : graph.paths.traverse_right(here); } } } for (auto& kv : end_mappings_by_path) { // For each path that hits the end node if (found_hairpin) { // We only care if there are 1 or more hairpins, not how many break; } // Unpack the name auto& path_name = kv.first; for (Mapping* end_mapping : kv.second) { if (found_hairpin) { // We only care if there are 1 or more hairpins, not how many break; } // Determine what orientation we're going to scan in bool backward = end_mapping->position().is_reverse(); // Start at the end Mapping* here = end_mapping; while (here) { if (here->position().node_id() == leaf->start().node_id() && here->position().is_reverse() == (leaf->start().backward() != backward)) { // We made it out. // Stop scanning! break; } if (here->position().node_id() == leaf->end().node_id() && here->position().is_reverse() != (leaf->end().backward() != backward)) { // We have encountered the end node with an incorrect orientation. cerr << "warning:[vg simplify] Path " << path_name << " doubles back through end of site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << "; dropping site!" << endl; found_hairpin = true; break; } // Scan right along the path if we found the site end backwards, and left if we found it forwards. here = backward ? graph.paths.traverse_right(here) : graph.paths.traverse_left(here); } } } if (found_hairpin) { // We found a hairpin, so we want to skip the site. cerr << "warning:[vg simplify] Site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << " skipped due to hairpin path." << endl; continue; } } // We'll keep a set of the end mappings we managed to find, starting from the start set<Mapping*> found_end_mappings; for (auto& kv : mappings_by_path) { // For each path that hits the start node // Unpack the name auto& path_name = kv.first; // If a path can't be represented after a bubble is popped // (because the path reversed and came out the same side as it // went in), we just clobber the path entirely. TODO: handle // out-the-same-side traversals as valid genotypes somehow.. bool kill_path = false; for (Mapping* start_mapping : kv.second) { // For each visit to the start node // Determine what orientation we're going to scan in bool backward = start_mapping->position().is_reverse(); // We're going to fill this list with the mappings we need to // remove and replace in this path for this traversal. Initially // runs from start of site to end of site, but later gets // flipped into path-local orientation. list<Mapping*> existing_mappings; // Tracing along forward/backward from each as appropriate, see // if the end of the site is found in the expected orientation // (or if the path ends first). bool found_end = false; Mapping* here = start_mapping; // We want to remember the end mapping when we find it Mapping* end_mapping = nullptr; #ifdef debug cerr << "Scanning " << path_name << " from " << pb2json(*here) << " for " << to_node_traversal(leaf->end(), graph) << " orientation " << backward << endl; #endif while (here) { // Until we hit the start/end of the path or the mapping we want #ifdef debug cerr << "\tat " << pb2json(*here) << endl; #endif if (here->position().node_id() == leaf->end().node_id() && here->position().is_reverse() == (leaf->end().backward() != backward)) { // We have encountered the end of the site in the // orientation we expect, given the orientation we saw // for the start. found_end = true; end_mapping = here; // Know we got to this mapping at the end from the // start, so we don't need to clobber everything // before it. found_end_mappings.insert(here); // Stop scanning! break; } if (here->position().node_id() == leaf->start().node_id() && here->position().is_reverse() != (leaf->start().backward() != backward)) { // We have encountered the start node with an incorrect orientation. cerr << "warning:[vg simplify] Path " << path_name << " doubles back through start of site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << "; dropping!" << endl; assert(drop_hairpin_paths); kill_path = true; break; } if (!nodes.count(graph.get_node(here->position().node_id()))) { // We really should stay inside the site! cerr << "error:[vg simplify] Path " << path_name << " somehow escapes site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << endl; exit(1); } if (here != start_mapping) { // Remember the mappings that aren't to the start or // end of the site, so we can remove them later. existing_mappings.push_back(here); } // Scan left along ther path if we found the site start backwards, and right if we found it forwards. Mapping* next = backward ? graph.paths.traverse_left(here) : graph.paths.traverse_right(here); if (next == nullptr) { // We hit the end of the path without finding the end of the site. // We've found all the existing mappings, so we can stop. break; } // Make into NodeTraversals NodeTraversal here_traversal(graph.get_node(here->position().node_id()), here->position().is_reverse()); NodeTraversal next_traversal(graph.get_node(next->position().node_id()), next->position().is_reverse()); if (backward) { // We're scanning the other way std::swap(here_traversal, next_traversal); } // Make sure we have an edge so we can traverse this node and then the node we're going to. if(graph.get_edge(here_traversal, next_traversal) == nullptr) { cerr << "error:[vg::Simplifier] No edge " << here_traversal << " to " << next_traversal << endl; exit(1); } here = next; } if (kill_path) { // This path can't exist after we pop this bubble. break; } if (!found_end) { // This path only partly traverses the site, and is // anchored at the start. Remove the part inside the site. // TODO: let it stay if it matches the one true traversal. for(auto* mapping : existing_mappings) { // Trim the path out of the site graph.paths.remove_mapping(mapping); } // TODO: update feature positions if we trim off the start of a path // Maybe the next time the path visits the site it will go // all the way through. continue; } // If we found the end, remove all the mappings encountered, in // order so that the last one removed is the last one along the // path. if (backward) { // Make sure the last mapping in the list is the last // mapping to occur along the path. existing_mappings.reverse(); } // Where does the variable region of the site start for this // traversal of the path? If there are no existing mappings, // it's the start mapping's position if we traverse the site // backwards and the end mapping's position if we traverse // the site forwards. If there are existing mappings, it's // the first existing mapping's position in the path. TODO: // This is super ugly. Can we view the site in path // coordinates or something? PathIndex& path_index = *path_indexes.at(path_name).get(); Mapping* mapping_after_first = existing_mappings.empty() ? (backward ? start_mapping : end_mapping) : existing_mappings.front(); assert(path_index.mapping_positions.count(mapping_after_first)); size_t variable_start = path_index.mapping_positions.at(mapping_after_first); // Determine the total length of the old traversal of the site size_t old_site_length = 0; for (auto* mapping : existing_mappings) { // Add in the lengths of all the mappings that will get // removed. old_site_length += mapping_from_length(*mapping); } #ifdef debug cerr << "Replacing " << old_site_length << " bp at " << variable_start << " with " << new_site_length << " bp" << endl; #endif // Actually update any BED features features.on_path_edit(path_name, variable_start, old_site_length, new_site_length); // Where will we insert the new site traversal into the path? list<Mapping>::iterator insert_position; if (!existing_mappings.empty()) { // If there are existing internal mappings, we'll insert right where they were for (auto* mapping : existing_mappings) { // Remove each mapping from left to right along the // path, saving the position after the mapping we just // removed. At the end we'll have the position of the // mapping to the end of the site. #ifdef debug cerr << path_name << ": Drop mapping " << pb2json(*mapping) << endl; #endif insert_position = graph.paths.remove_mapping(mapping); } } else { // Otherwise we'll insert right before the mapping to // the start or end of the site (whichever occurs last // along the path) insert_position = graph.paths.find_mapping(backward ? start_mapping : here); } // Make sure we're going to insert starting from the correct end of the site. if (backward) { assert(insert_position->position().node_id() == leaf->start().node_id()); } else { assert(insert_position->position().node_id() == leaf->end().node_id()); } // Loop through the internal visits in the canonical // traversal backwards along the path we are splicing. If // it's a forward path this is just right to left, but if // it's a reverse path it has to be left to right. for (size_t i = 0; i < traversal.visit_size(); i++) { // Find the visit we need next, as a function of which // way we need to insert this run of visits. Normally we // go through the visits right to left, but when we have // a backward path we go left to right. const Visit& visit = backward ? traversal.visit(i) : traversal.visit(traversal.visit_size() - i - 1); // Make a Mapping to represent it Mapping new_mapping; new_mapping.mutable_position()->set_node_id(visit.node_id()); // We hit this node backward if it's backward along the // traversal, xor if we are traversing the traversal // backward new_mapping.mutable_position()->set_is_reverse(visit.backward() != backward); // Add an edit Edit* edit = new_mapping.add_edit(); size_t node_seq_length = graph.get_node(visit.node_id())->sequence().size(); edit->set_from_length(node_seq_length); edit->set_to_length(node_seq_length); #ifdef debug cerr << path_name << ": Add mapping " << pb2json(new_mapping) << endl; #endif // Insert the mapping in the path, moving right to left insert_position = graph.paths.insert_mapping(insert_position, path_name, new_mapping); } // Now we've corrected this site on this path. Update its index. // TODO: right now this means retracing the entire path. path_indexes[path_name].get()->update_mapping_positions(graph, path_name); } if (kill_path) { // Destroy the path completely, because it needs to reverse // inside a site that we have popped. graph.paths.remove_path(path_name); } } for (auto& kv : end_mappings_by_path) { // Now we handle the end mappings not reachable from the start. For each path that touches the end... // Unpack the name auto& path_name = kv.first; // We might have to kill the path, if it reverses inside a // bubble we're popping bool kill_path = false; for (Mapping* end_mapping : kv.second) { if (found_end_mappings.count(end_mapping)) { // Skip the traversals of the site that we handled. continue; } // Now we're left with paths that leave the site but don't // enter. We're going to clobber everything before the path // leaves the site. // Determine what orientation we're going to scan in bool backward = end_mapping->position().is_reverse(); // Start at the end Mapping* here = end_mapping; // Keep a list of mappings we need to remove list<Mapping*> to_remove; while (here) { if (here->position().node_id() == leaf->end().node_id() && here->position().is_reverse() != (leaf->end().backward() != backward)) { // We have encountered the end node with an incorrect orientation. cerr << "warning:[vg simplify] Path " << path_name << " doubles back through end of site " << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << "; dropping!" << endl; assert(drop_hairpin_paths); kill_path = true; break; } // Say we should remove the mapping. to_remove.push_back(here); // Scan right along the path if we found the site end backwards, and left if we found it forwards. here = backward ? graph.paths.traverse_right(here) : graph.paths.traverse_left(here); // Eventually we should hit the end of the path, or the // end of the site, since we don't hit the start. } if (kill_path) { // Just go kill the whole path break; } for (auto* mapping: to_remove) { // Get rid of all the mappings once we're done tracing them out. graph.paths.remove_mapping(mapping); } } if (kill_path) { // Destroy the path completely, because it needs to reverse // inside a site that we have popped. graph.paths.remove_path(path_name); } } // Now delete all edges that aren't connecting adjacent nodes on the // blessed traversal (before we delete their nodes). set<Edge*> blessed_edges; for (int i = 0; i < traversal.visit_size() - 1; ++i) { // For each node and the next node (which won't be the end) const Visit visit = traversal.visit(i); const Visit next = traversal.visit(i); // Find the edge between them NodeTraversal here(graph.get_node(visit.node_id()), visit.backward()); NodeTraversal next_traversal(graph.get_node(next.node_id()), next.backward()); Edge* edge = graph.get_edge(here, next_traversal); assert(edge != nullptr); // Remember we need it blessed_edges.insert(edge); } // Also get the edges from the boundary nodes into the traversal if (traversal.visit_size() > 0) { NodeTraversal first_visit = to_node_traversal(traversal.visit(0), graph); NodeTraversal last_visit = to_node_traversal(traversal.visit(traversal.visit_size() - 1), graph); blessed_edges.insert(graph.get_edge(to_node_traversal(leaf->start(), graph), first_visit)); blessed_edges.insert(graph.get_edge(last_visit, to_node_traversal(leaf->end(), graph))); } else { // This is a deletion traversal, so get the edge from the start to end of the site blessed_edges.insert(graph.get_edge(to_node_traversal(leaf->start(), graph), to_node_traversal(leaf->end(), graph))); } for (auto* edge : edges) { if (!blessed_edges.count(edge)) { // Get rid of all the edges not needed for the one true traversal #ifdef debug cerr << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << ": Delete edge: " << pb2json(*edge) << endl; #endif graph.destroy_edge(edge); deleted_edges++; } } // Now delete all the nodes that aren't on the blessed traversal. // What nodes are on it? set<Node*> blessed_nodes; for (int i = 0; i < traversal.visit_size(); i++) { const Visit& visit = traversal.visit(i); blessed_nodes.insert(graph.get_node(visit.node_id())); } for (auto* node : nodes) { // For every node in the site if (!blessed_nodes.count(node)) { // If we don't need it for the chosen path, destroy it #ifdef debug cerr << to_node_traversal(leaf->start(), graph) << " - " << to_node_traversal(leaf->end(), graph) << ": Delete node: " << pb2json(*node) << endl; #endif // There may be paths still touching this node, if they // managed to get into the site without touching the start // node. We'll delete those paths. set<string> paths_to_kill; for (auto& kv : graph.paths.get_node_mapping(node)) { if (mappings_by_path.count(kv.first)) { // We've already actually updated this path; the // node_mapping data is just out of date. continue; } paths_to_kill.insert(kv.first); } for (auto& path : paths_to_kill) { graph.paths.remove_path(path); cerr << "warning:[vg simplify] Path " << path << " removed" << endl; } graph.destroy_node(node); deleted_nodes++; } } // OK we finished a leaf increment_progress(); } destroy_progress(); // Reset the ranks in the graph, since we rewrote paths graph.paths.clear_mapping_ranks(); // Return the statistics. return to_return; }
bool edit_is_insertion(const Edit& e) { return e.from_length() == 0 && e.to_length() > 0 && !e.sequence().empty(); }
void ColorCalibrationInterface::__GetFocus( Control& sender ) { Edit* e = dynamic_cast<Edit*>( &sender ); if ( e != 0 && e->Text() == TARGET_IMAGE ) e->Clear(); }
int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset) { Edit* current; current = append_new_edit(); current->load_properties(file, startproject); startproject += current->length; int result = 0; do{ result = file->read_tag(); if(!result) { if(file->tag.title_is("NESTED_EDL")) { char path[BCTEXTLEN]; path[0] = 0; file->tag.get_property("SRC", path); //printf("Edits::load_edit %d path=%s\n", __LINE__, path); if(path[0] != 0) { current->nested_edl = edl->nested_edls->get(path); } // printf("Edits::load_edit %d nested_edl->path=%s\n", // __LINE__, // current->nested_edl->path); } else if(file->tag.title_is("FILE")) { char filename[BCTEXTLEN]; filename[0] = 0; file->tag.get_property("SRC", filename); // Extend path if(filename[0] != 0) { char directory[BCTEXTLEN], edl_directory[BCTEXTLEN]; FileSystem fs; fs.set_current_dir(""); fs.extract_dir(directory, filename); if(!strlen(directory)) { fs.extract_dir(edl_directory, file->filename); fs.join_names(directory, edl_directory, filename); strcpy(filename, directory); } current->asset = edl->assets->get_asset(filename); } else { current->asset = 0; } //printf("Edits::load_edit 5\n"); } else if(file->tag.title_is("TRANSITION")) { current->transition = new Transition(edl, current, "", track->to_units(edl->session->default_transition_length, 1)); current->transition->load_xml(file); } else if(file->tag.title_is("/EDIT")) { result = 1; } } }while(!result); //printf("Edits::load_edit %d\n", __LINE__); //track->dump(); //printf("Edits::load_edit %d\n", __LINE__); return 0; }
LRESULT CALLBACK Edit::SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { Edit *iam = (Edit *)GetWindowLong(hwnd, GWL_USERDATA); switch (msg) { case WM_GETDLGCODE: return CallWindowProc(iam->wndproc, hwnd, msg, wParam, lParam) | DLGC_WANTALLKEYS; case WM_KILLFOCUS: if (iam->editing) { if (iam->read_value()) { iam->write_value(); SendMessage(iam->dlg, WM_COMMAND, MAKEWPARAM(iam->item, CB_ENTER), 0); } else { iam->restore_value(); iam->write_value(); MessageBox(0, iam->incorrect_value(), "Error", MB_ICONEXCLAMATION | MB_OK); } iam->editing = false; } break; case WM_KEYDOWN: if (!iam->editing) { iam->backup_value(); iam->editing = true; } if (iam->editing && wParam == VK_RETURN) { if (iam->read_value()) { iam->editing = false; SendMessage(iam->dlg, WM_COMMAND, MAKEWPARAM(iam->item, CB_ENTER), 0); } else MessageBox(0, iam->incorrect_value(), "Error", MB_ICONEXCLAMATION | MB_OK); return 0; } if (iam->editing && wParam == VK_ESCAPE) { iam->restore_value(); iam->write_value(); iam->editing = false; return 0; } break; case WM_KEYUP: case WM_CHAR: switch (wParam) { case VK_RETURN: case VK_ESCAPE: return 0; } break; } // switch (msg) // Call the original window procedure for default processing. return CallWindowProc(iam->wndproc, hwnd, msg, wParam, lParam); }
Edit::Edit(const Edit ©) : QObject(copy.parent()) { this->localVersion = copy.localVersion; this->patches = copy.patches; }
int Edits::optimize() { int result = 1; Edit *current; //printf("Edits::optimize %d\n", __LINE__); // Sort edits by starting point while(result) { result = 0; for(current = first; current; current = NEXT) { Edit *next_edit = NEXT; if(next_edit && next_edit->startproject < current->startproject) { swap(next_edit, current); result = 1; } } } // Insert silence between edits which aren't consecutive for(current = last; current; current = current->previous) { if(current->previous) { Edit *previous_edit = current->previous; if(current->startproject - previous_edit->startproject - previous_edit->length > 0) { Edit *new_edit = create_edit(); insert_before(current, new_edit); new_edit->startproject = previous_edit->startproject + previous_edit->length; new_edit->length = current->startproject - previous_edit->startproject - previous_edit->length; } } else if(current->startproject > 0) { Edit *new_edit = create_edit(); insert_before(current, new_edit); new_edit->length = current->startproject; } } result = 1; while(result) { result = 0; // delete 0 length edits for(current = first; current && !result; ) { if(current->length == 0) { Edit* next = current->next; delete current; result = 1; current = next; } else current = current->next; } //printf("Edits::optimize %d result=%d\n", __LINE__, result); // merge same files or transitions for(current = first; current && current->next && !result; ) { Edit *next_edit = current->next; // printf("Edits::optimize %d %lld=%lld %d=%d %p=%p %p=%p\n", // __LINE__, // current->startsource + current->length, // next_edit->startsource, // current->channel, // next_edit->channel, // current->asset, // next_edit->asset, // current->nested_edl, // next_edit->nested_edl); if( // both edits are silence & not a plugin (current->silence() && next_edit->silence() && !current->is_plugin) || (current->startsource + current->length == next_edit->startsource && // source channels are identical current->channel == next_edit->channel && // assets are identical current->asset == next_edit->asset && current->nested_edl == next_edit->nested_edl)) { //printf("Edits::optimize %d\n", __LINE__); current->length += next_edit->length; remove(next_edit); result = 1; } current = current->next; } // delete last edit of 0 length or silence if(last && (last->silence() || !last->length)) { delete last; result = 1; } } //track->dump(); return 0; }
Alignment Filter::depth_filter(Alignment& aln){ if (use_avg && window_length != 0){ } else if (use_avg != 0){ } else{ } Path path = aln.path(); //TODO handle reversing mappings vector<int>* qual_window; if (window_length > 0){ qual_window = new vector<int>(); } for (int i = 0; i < path.mapping_size(); i++){ Mapping mapping = path.mapping(i); Position start_pos = mapping.position(); int64_t start_node = start_pos.node_id(); int64_t start_offset = start_pos.offset(); int64_t curr_offset_in_graph = 0; int64_t curr_offset_in_alignment = 0; stringstream pst; pst << start_node << "_" << curr_offset_in_graph; string p_hash = pst.str(); for (int j = 0; j < mapping.edit_size(); j++){ Edit ee = mapping.edit(j); if (ee.from_length() == ee.to_length() && ee.sequence() == ""){ if (!filter_matches){ continue; } } stringstream est; est << ee.from_length() << "_" << ee.to_length() << "_" + ee.sequence(); string e_hash = est.str(); #pragma omp critical(write) pos_to_edit_to_depth[p_hash][e_hash] += 1; /** * If an edit fails the filter, either return a new empty alignment * OR * return a new alignment identical to the old one EXCEPT where * the offending edit has been replaced by a match to the reference. */ if (pos_to_edit_to_depth[p_hash][e_hash] < min_depth){ if (!remove_failing_edits){ return inverse ? aln : Alignment(); } else { Alignment edited_aln = Alignment(aln); edited_aln.mutable_path()->mutable_mapping(i)->mutable_edit(j)->set_sequence(""); edited_aln.mutable_path()->mutable_mapping(i)->mutable_edit(j)->set_from_length(ee.from_length()); edited_aln.mutable_path()->mutable_mapping(i)->mutable_edit(j)->set_to_length(ee.from_length()); return edited_aln; } } } return inverse ? Alignment() : aln; } }
bool edit_is_sub(const Edit& e) { return e.from_length() == e.to_length() && !e.sequence().empty(); }
bool edit_is_deletion(const Edit& e) { return e.from_length() > 0 && e.to_length() == 0; }
void ChannelCombinationInterface::__ChannelId_GetFocus( Control& sender ) { Edit* e = dynamic_cast<Edit*>( &sender ); if ( e != 0 && e->Text() == AUTO_ID ) e->Clear(); }
void Aligner::gssw_mapping_to_alignment(gssw_graph* graph, gssw_graph_mapping* gm, Alignment& alignment, bool print_score_matrices) { alignment.clear_path(); alignment.set_score(gm->score); alignment.set_query_position(0); Path* path = alignment.mutable_path(); //alignment.set_cigar(graph_cigar(gm)); gssw_graph_cigar* gc = &gm->cigar; gssw_node_cigar* nc = gc->elements; int to_pos = 0; int from_pos = gm->position; //cerr << "gm->position " << gm->position << endl; string& to_seq = *alignment.mutable_sequence(); //cerr << "-------------" << endl; if (print_score_matrices) { gssw_graph_print_score_matrices(graph, to_seq.c_str(), to_seq.size(), stderr); //cerr << alignment.DebugString() << endl; } for (int i = 0; i < gc->length; ++i, ++nc) { if (i > 0) from_pos = 0; // reset for each node after the first // check that the current alignment has a non-zero length gssw_cigar* c = nc->cigar; int l = c->length; if (l == 0) continue; gssw_cigar_element* e = c->elements; Node* from_node = (Node*) nc->node->data; string& from_seq = *from_node->mutable_sequence(); Mapping* mapping = path->add_mapping(); mapping->mutable_position()->set_node_id(nc->node->id); mapping->mutable_position()->set_offset(from_pos); mapping->set_rank(path->mapping_size()); //cerr << from_node->id() << ":" << endl; for (int j=0; j < l; ++j, ++e) { Edit* edit; int32_t length = e->length; //cerr << e->length << e->type << endl; switch (e->type) { case 'M': case 'X': case 'N': { // do the sequences match? // emit a stream of "SNPs" and matches int h = from_pos; int last_start = from_pos; int k = to_pos; for ( ; h < from_pos + length; ++h, ++k) { //cerr << h << ":" << k << " " << from_seq[h] << " " << to_seq[k] << endl; if (from_seq[h] != to_seq[k]) { // emit the last "match" region if (h-last_start > 0) { edit = mapping->add_edit(); edit->set_from_length(h-last_start); edit->set_to_length(h-last_start); } // set up the SNP edit = mapping->add_edit(); edit->set_from_length(1); edit->set_to_length(1); edit->set_sequence(to_seq.substr(k,1)); last_start = h+1; } } // handles the match at the end or the case of no SNP if (h-last_start > 0) { edit = mapping->add_edit(); edit->set_from_length(h-last_start); edit->set_to_length(h-last_start); } to_pos += length; from_pos += length; } break; case 'D': edit = mapping->add_edit(); edit->set_from_length(length); edit->set_to_length(0); from_pos += length; break; case 'I': edit = mapping->add_edit(); edit->set_from_length(0); edit->set_to_length(length); edit->set_sequence(to_seq.substr(to_pos, length)); to_pos += length; break; case 'S': // note that soft clips and insertions are semantically equivalent // and can only be differentiated by their position in the read // with soft clips coming at the start or end edit = mapping->add_edit(); edit->set_from_length(0); edit->set_to_length(length); edit->set_sequence(to_seq.substr(to_pos, length)); to_pos += length; break; default: cerr << "error:[Aligner::gssw_mapping_to_alignment] " << "unsupported cigar op type " << e->type << endl; exit(1); break; } } //cerr << "path to_length " << path_to_length(*path) << endl; } // set identity alignment.set_identity(identity(alignment.path())); }
vector<Edit> Sampler::mutate_edit(const Edit& edit, const pos_t& position, double base_error, double indel_error, const string& bases, uniform_real_distribution<double>& rprob, uniform_int_distribution<int>& rbase) { // we will build up a mapping representing the modified edit Mapping new_mapping; //*new_mapping.mutable_position() = make_position(position); // determine to-length of edit size_t to_length = edit.to_length(); // we will keep track of the current base using this pos_t curr_pos = position; /// TODO we should punt if we aren't a pure edit // as in, we are something with mixed to and from lengths; like a block sub with an indel if (edit_is_match(edit) || edit_is_sub(edit) || edit_is_insertion(edit)) { // distribute mutations across this length for (size_t k = 0; k < to_length; ++k) { char c = 'N'; // in the case that we are in an insertion if (!edit_is_insertion(edit)) { c = pos_char(curr_pos); ++get_offset(curr_pos); } if (rprob(rng) <= base_error) { // pick another base than what c is char n; do { n = bases[rbase(rng)]; } while (n == c); // make the edit for the sub Edit* e = new_mapping.add_edit(); string s(1, n); e->set_sequence(s); e->set_from_length(1); e->set_to_length(1); // if we've got a indel // note that we're using a simple geometric indel dsitribution here } else if (rprob(rng) <= indel_error) { if (rprob(rng) < 0.5) { char n = bases[rbase(rng)]; Edit* e = new_mapping.add_edit(); string s(1, c); e->set_sequence(s); e->set_to_length(1); } else { Edit* e = new_mapping.add_edit(); e->set_from_length(1); } } else { // make the edit for the 1bp match Edit* e = new_mapping.add_edit(); e->set_from_length(1); e->set_to_length(1); } } } else if (edit_is_deletion(edit)) { // special case: 0 (deletion) // maybe we do nothing; as there is no length in the read } // simplify the mapping new_mapping = simplify(new_mapping); // copy the new edits vector<Edit> new_edits; for (size_t i = 0; i < new_mapping.edit_size(); ++i) { new_edits.push_back(new_mapping.edit(i)); } // and send them back return new_edits; }
void Aligner::align_internal(Alignment& alignment, vector<Alignment>* multi_alignments, Graph& g, int64_t pinned_node_id, bool pin_left, int32_t max_alt_alns, bool print_score_matrices) { // check input integrity if (pin_left && !pinned_node_id) { cerr << "error:[Aligner] cannot choose pinned end in non-pinned alignment" << endl; exit(EXIT_FAILURE); } if (multi_alignments && !pinned_node_id) { cerr << "error:[Aligner] multiple traceback is not valid in local alignment, only pinned and global" << endl; exit(EXIT_FAILURE); } if (!(multi_alignments) && max_alt_alns != 1) { cerr << "error:[Aligner] cannot specify maximum number of alignments in single alignment" << endl; exit(EXIT_FAILURE); } // alignment pinning algorithm is based on pinning in bottom right corner, if pinning in top // left we need to reverse all the sequences first and translate the alignment back later // create reversed objects if necessary Graph reversed_graph; string reversed_sequence; if (pin_left) { reversed_sequence.resize(alignment.sequence().length()); reverse_copy(alignment.sequence().begin(), alignment.sequence().end(), reversed_sequence.begin()); reverse_graph(g, reversed_graph); } // choose forward or reversed objects Graph* align_graph; string* align_sequence; if (pin_left) { align_graph = &reversed_graph; align_sequence = &reversed_sequence; } else { align_graph = &g; align_sequence = alignment.mutable_sequence(); } // convert into gssw graph and get the counterpart to pinned node (if pinning) gssw_node* pinned_node = nullptr; gssw_graph* graph = create_gssw_graph(*align_graph, pinned_node_id, &pinned_node); if (pinned_node_id & !pinned_node) { cerr << "error:[Aligner] pinned node for pinned alignment is not in graph" << endl; exit(EXIT_FAILURE); } // perform dynamic programming gssw_graph_fill(graph, (*align_sequence).c_str(), nt_table, score_matrix, gap_open, gap_extension, 15, 2); // traceback either from pinned position or optimal local alignment if (pinned_node) { // trace back pinned alignment gssw_graph_mapping** gms = gssw_graph_trace_back_pinned_multi (graph, pinned_node, max_alt_alns, (*align_sequence).c_str(), (*align_sequence).size(), nt_table, score_matrix, gap_open, gap_extension); if (pin_left) { // translate graph and mappings into original node space unreverse_graph(reversed_graph); for (int32_t i = 0; i < max_alt_alns; i++) { unreverse_graph_mapping(gms[i]); } } // convert optimal alignment and store it in the input Alignment object (in the multi alignment, // this will have been set to the first in the vector) if (gms[0]->score > 0) { // have a mapping, can just convert normally gssw_mapping_to_alignment(graph, gms[0], alignment, print_score_matrices); } else { // gssw will not identify mappings with 0 score, infer location based on pinning Mapping* mapping = alignment.mutable_path()->add_mapping(); mapping->set_rank(1); // locate at the end of the node Position* position = mapping->mutable_position(); position->set_node_id(pinned_node_id); position->set_offset(pin_left ? 0 : pinned_node->len); // soft clip Edit* edit = mapping->add_edit(); edit->set_to_length(alignment.sequence().length()); edit->set_sequence(alignment.sequence()); } if (multi_alignments) { // determine how many non-null alignments were returned int32_t num_non_null = max_alt_alns; for (int32_t i = 1; i < max_alt_alns; i++) { if (gms[i]->score <= 0) { num_non_null = i; break; } } // reserve to avoid illegal access errors that occur when the vector reallocates multi_alignments->reserve(num_non_null); // copy the primary alignment multi_alignments->emplace_back(alignment); // convert the alternate alignments and store them at the back of the vector (this will not // execute if we are doing single alignment) for (int32_t i = 1; i < num_non_null; i++) { gssw_graph_mapping* gm = gms[i]; // make new alignment object multi_alignments->emplace_back(); Alignment& next_alignment = multi_alignments->back(); // copy over sequence information from the primary alignment next_alignment.set_sequence(alignment.sequence()); next_alignment.set_quality(alignment.quality()); // get path of the alternate alignment gssw_mapping_to_alignment(graph, gm, next_alignment, print_score_matrices); } } for (int32_t i = 0; i < max_alt_alns; i++) { gssw_graph_mapping_destroy(gms[i]); } free(gms); } else { // trace back local alignment gssw_graph_mapping* gm = gssw_graph_trace_back (graph, (*align_sequence).c_str(), (*align_sequence).size(), nt_table, score_matrix, gap_open, gap_extension); gssw_mapping_to_alignment(graph, gm, alignment, print_score_matrices); gssw_graph_mapping_destroy(gm); } //gssw_graph_print_score_matrices(graph, sequence.c_str(), sequence.size(), stderr); gssw_graph_destroy(graph); }
void Pileups::compute_from_edit(NodePileup& pileup, int64_t& node_offset, int64_t& read_offset, const Node& node, const Alignment& alignment, const Mapping& mapping, const Edit& edit) { string seq = edit.sequence(); bool is_reverse = mapping.position().is_reverse(); // ***** MATCH ***** if (edit.from_length() == edit.to_length()) { assert (edit.from_length() > 0); make_match(seq, edit.from_length(), is_reverse); assert(seq.length() == edit.from_length()); int64_t delta = 1; for (int64_t i = 0; i < edit.from_length(); ++i) { BasePileup* base_pileup = get_create_base_pileup(pileup, node_offset); // reference_base if empty if (base_pileup->num_bases() == 0) { base_pileup->set_ref_base(node.sequence()[node_offset]); } else { assert(base_pileup->ref_base() == node.sequence()[node_offset]); } // add base to bases field (converting to ,. if match) char base = seq[i]; if (!edit.sequence().empty() && base_equal(seq[i], node.sequence()[node_offset], is_reverse)) { base = is_reverse ? ',' : '.'; } *base_pileup->mutable_bases() += base; // add quality if there if (!alignment.quality().empty()) { *base_pileup->mutable_qualities() += alignment.quality()[read_offset]; } // pileup size increases by 1 base_pileup->set_num_bases(base_pileup->num_bases() + 1); // move right along read, and left/right depending on strand on reference node_offset += delta; ++read_offset; } } // ***** INSERT ***** else if (edit.from_length() < edit.to_length()) { make_insert(seq, is_reverse); assert(edit.from_length() == 0); // we define insert (like sam) as insertion between current and next // position (on forward node coordinates). this means an insertion before // offset 0 is invalid! int64_t insert_offset = is_reverse ? node_offset : node_offset - 1; if (insert_offset >= 0) { BasePileup* base_pileup = get_create_base_pileup(pileup, insert_offset); // reference_base if empty if (base_pileup->num_bases() == 0) { base_pileup->set_ref_base(node.sequence()[insert_offset]); } else { assert(base_pileup->ref_base() == node.sequence()[insert_offset]); } // add insertion string to bases field // todo: should we reverse complement this if mapping is reversed ??? base_pileup->mutable_bases()->append(seq); if (!alignment.quality().empty()) { *base_pileup->mutable_qualities() += alignment.quality()[read_offset]; } // pileup size increases by 1 base_pileup->set_num_bases(base_pileup->num_bases() + 1); } else { // todo: need to either forget about these, or extend pileup format. // easy solution: change insert to come before position, and just add // optional pileup at n+1st base of node. would like to figure out // how samtools does it first... /* stringstream ss; ss << "Warning: pileup does not support insertions before 0th base in node." << " Offending edit: " << pb2json(edit) << endl; #pragma omp critical(cerr) cerr << ss.str(); */ } // move right along read (and stay put on reference) read_offset += edit.to_length(); } // ***** DELETE ***** else { assert(edit.to_length() == 0); assert(edit.sequence().empty()); int64_t del_start = !is_reverse ? node_offset : node_offset - edit.from_length() + 1; seq = node.sequence().substr(del_start, edit.from_length()); make_delete(seq, is_reverse); BasePileup* base_pileup = get_create_base_pileup(pileup, node_offset); // reference_base if empty if (base_pileup->num_bases() == 0) { base_pileup->set_ref_base(node.sequence()[node_offset]); } else { assert(base_pileup->ref_base() == node.sequence()[node_offset]); } // add deletion string to bases field // todo: should we reverse complement this if mapping is reversed ??? base_pileup->mutable_bases()->append(seq); if (!alignment.quality().empty()) { *base_pileup->mutable_qualities() += alignment.quality()[read_offset]; } // pileup size increases by 1 base_pileup->set_num_bases(base_pileup->num_bases() + 1); int64_t delta = edit.from_length(); // stay put on read, move left/right depending on strand on reference node_offset += delta; } }
void Tracks::move_edits(ArrayList<Edit*> *edits, Track *track, double position, int edit_labels, // Ignored int edit_plugins, // Ignored int edit_autos) // Ignored { //printf("Tracks::move_edits 1\n"); for(Track *dest_track = track; dest_track; dest_track = dest_track->next) { if(dest_track->record) { // Need a local copy of the source edit since the original source edit may // change in the editing operation. Edit *source_edit = 0; Track *source_track = 0; // Get source track if(dest_track->data_type == TRACK_AUDIO) { int current_aedit = 0; while(current_aedit < edits->total && edits->values[current_aedit]->track->data_type != TRACK_AUDIO) current_aedit++; if(current_aedit < edits->total) { source_edit = edits->values[current_aedit]; source_track = source_edit->track; edits->remove_number(current_aedit); } } else if(dest_track->data_type == TRACK_VIDEO) { int current_vedit = 0; while(current_vedit < edits->total && edits->values[current_vedit]->track->data_type != TRACK_VIDEO) current_vedit++; if(current_vedit < edits->total) { source_edit = edits->values[current_vedit]; source_track = source_edit->track; edits->remove_number(current_vedit); } } //printf("Tracks::move_edits 2 %s %s %d\n", source_track->title, dest_track->title, source_edit->length); if(source_edit) { // Copy keyframes FileXML temp; AutoConf temp_autoconf; int64_t position_i = source_track->to_units(position, 0); // Source edit changes int64_t source_length = source_edit->length; temp_autoconf.set_all(1); source_track->automation->copy(source_edit->startproject, source_edit->startproject + source_edit->length, &temp, 0, 1); temp.terminate_string(); temp.rewind(); // Insert new keyframes //printf("Tracks::move_edits 2 %d %p\n", result->startproject, result->asset); source_track->automation->clear(source_edit->startproject, source_edit->startproject + source_edit->length, &temp_autoconf, 1); int64_t position_a = position_i; if (dest_track == source_track) { if (position_a > source_edit->startproject) position_a -= source_length; } dest_track->automation->paste_silence(position_a, position_a + source_length); while(!temp.read_tag()) dest_track->automation->paste(position_a, source_length, 1.0, &temp, 0, 1, &temp_autoconf); // Insert new edit Edit *dest_edit = dest_track->edits->shift(position_i, source_length); Edit *result = dest_track->edits->insert_before(dest_edit, new Edit(edl, dest_track)); result->copy_from(source_edit); result->startproject = position_i; result->length = source_length; // Clear source source_track->edits->clear(source_edit->startproject, source_edit->startproject + source_length); source_track->optimize(); dest_track->optimize(); } } } }