/// <summary> /// Trace simple path in specified direction. /// </summary> /// <param name="contigPath">List of graph nodes corresponding to contig path.</param> /// <param name="contigSequence">Sequence of contig being assembled.</param> /// <param name="isForwardDirection">Boolean indicating direction of path.</param> /// <param name="sameOrientation">Path orientation.</param> /// <param name="node">Next node on the path.</param> /// <param name="createContigSequences">Indicates whether the contig sequences are to be created or not.</param> private void TraceSimplePathLinks( List<DeBruijnNode> contigPath, List<byte> contigSequence, bool isForwardDirection, bool sameOrientation, DeBruijnNode node, bool createContigSequences) { bool endFound = false; while (!endFound) { node.IsVisited = true; // Get extensions going in same directions. Dictionary<DeBruijnNode, bool> sameDirectionExtensions = (isForwardDirection ^ sameOrientation) ? node.GetLeftExtensionNodesWithOrientation() : node.GetRightExtensionNodesWithOrientation(); if (sameDirectionExtensions.Count == 0) { // Found end of path. Add this and return CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences); endFound = true; } else { var sameDirectionExtension = sameDirectionExtensions.First(); // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1) // Continue traceback in the same direction. Add this node to list and continue. if (!CheckAndAddNode(contigPath, contigSequence, node, isForwardDirection, sameOrientation, createContigSequences)) { // Loop is found. Cannot extend simple path further //Assuming that any node with extensions >2 from either side have been trimmed, this should only be possible if the first //node in list is last node as well, this means there is a circle in the graph of length >1, going to report it if (contigPath != null && contigPath.Count > 0 && contigPath[0] == node) { endFound = true; } } else { node = sameDirectionExtension.Key; sameOrientation = !(sameOrientation ^ sameDirectionExtension.Value); } } } }
/// <summary> /// Starting from potential end of dangling link, trace back along /// extension edges in graph to find if it is a valid dangling link. /// Parallelization Note: No locks used in TraceDanglingLink. /// We only read graph structure here. No modifications are made. /// </summary> /// <param name="isForwardDirection">Boolean indicating direction of dangling link.</param> /// <param name="link">Dangling Link.</param> /// <param name="node">Node that is next on the link.</param> /// <param name="sameOrientation">Orientation of link.</param> /// <returns>List of nodes in dangling link.</returns> private DeBruijnPath TraceDanglingExtensionLink(bool isForwardDirection, DeBruijnPath link, DeBruijnNode node, bool sameOrientation) { for (; ;) { // Get extensions going in same and opposite directions. Dictionary<DeBruijnNode, bool> sameDirectionExtensions; int sameDirectionExtensionsCount, oppDirectionExtensionsCount; if (isForwardDirection ^ sameOrientation) { sameDirectionExtensionsCount = node.LeftExtensionNodesCount; oppDirectionExtensionsCount = node.RightExtensionNodesCount; sameDirectionExtensions = node.GetLeftExtensionNodesWithOrientation(); } else { sameDirectionExtensionsCount = node.RightExtensionNodesCount; oppDirectionExtensionsCount = node.LeftExtensionNodesCount; sameDirectionExtensions = node.GetRightExtensionNodesWithOrientation(); } bool reachedEndPoint; if (sameDirectionExtensionsCount == 0) { // Found other end of dangling link return CheckAndAddDanglingNode(link, node, out reachedEndPoint); } if (oppDirectionExtensionsCount > 1) { // Have reached a point of ambiguity. Return list without updating it. if (this.erodeThreshold != -1 && !node.IsMarkedForDelete) { lock (this.danglingLinkExtensionTasks) { // This task essentially just returns back to this method after other ones are removed this.danglingLinkExtensionTasks.Add(new Task<int>(_ => ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, false), TaskCreationOptions.None)); } return null; } return link; } if (sameDirectionExtensionsCount > 1) { // Have reached a point of ambiguity. Return list after updating it. link = CheckAndAddDanglingNode(link, node, out reachedEndPoint); if (this.erodeThreshold != -1 && reachedEndPoint != true && !node.IsMarkedForDelete) { lock (this.danglingLinkExtensionTasks) { this.danglingLinkExtensionTasks.Add(new Task<int>(_ => ExtendDanglingLink(isForwardDirection, link, node, sameOrientation, true), TaskCreationOptions.None)); } return null; } return link; } // (sameDirectionExtensions == 1 && oppDirectionExtensions == 1) // Continue trace back. Add this node to that list and recurse. link = CheckAndAddDanglingNode(link, node, out reachedEndPoint); if (reachedEndPoint) { // Loop is found or threshold length has been exceeded. return link; } // Still in loop, so just add the extension and keeps going var item = sameDirectionExtensions.First(); node = item.Key; sameOrientation = !(sameOrientation ^ item.Value); } }
/// <summary> /// Trace simple path starting from 'node' in specified direction. /// </summary> /// <param name="assembledContigs">List of assembled contigs.</param> /// <param name="node">Starting node of contig path.</param> /// <param name="isForwardDirection">Boolean indicating direction of path.</param> /// <param name="createContigSequences">Boolean indicating whether the contig sequences are to be created or not.</param> /// <param name="DuplicatesPossible">Boolean indicating if duplicates are possible, true if both the forward and reverse path could be generated</param> private void TraceSimplePath(List<ISequence> assembledContigs, DeBruijnNode node, bool isForwardDirection, bool createContigSequences,bool DuplicatesPossible) { ISequence nodeSequence = _graph.GetNodeSequence(node); List<byte> contigSequence = new List<byte>(nodeSequence); node.IsVisited = true; List<DeBruijnNode> contigPath = new List<DeBruijnNode> { node }; KeyValuePair<DeBruijnNode, bool> nextNode = isForwardDirection ? node.GetRightExtensionNodesWithOrientation().First() : node.GetLeftExtensionNodesWithOrientation().First(); TraceSimplePathLinks(contigPath, contigSequence, isForwardDirection, nextNode.Value, nextNode.Key, createContigSequences); // Check to remove duplicates if (!DuplicatesPossible || contigPath[0].NodeValue.CompareTo(contigPath.Last().NodeValue) >= 0) { // Check contig coverage. if (_coverageThreshold != -1) { // Definition from Velvet Manual: http://helix.nih.gov/Applications/velvet_manual.pdf // "k-mer coverage" is how many times a k-mer has been seen among the reads. double coverage = contigPath.Average(n => n.KmerCount); if (coverage < _coverageThreshold) { contigPath.ForEach(n => n.MarkNodeForDelete()); } } else { if (createContigSequences) { lock (assembledContigs) { assembledContigs.Add(new Sequence(nodeSequence.Alphabet, contigSequence.ToArray())); } } } } }