public ReadToRealignDetails(Read read, int position, bool keepProbeSoftclips = false, bool keepBothSideSoftclips = false)
            {
                var freshCigarWithoutTerminalNsRaw = new CigarAlignment();

                NPrefixLength = read.GetNPrefix();

                NSuffixLength = read.GetNSuffix();

                if (keepProbeSoftclips)
                {
                    if (keepBothSideSoftclips || (!read.BamAlignment.IsReverseStrand() || !read.BamAlignment.IsPaired()) && NPrefixLength == 0)
                    {
                        NPrefixLength = (int)read.CigarData.GetPrefixClip();
                    }
                    if (keepBothSideSoftclips || (read.BamAlignment.IsReverseStrand() || !read.BamAlignment.IsPaired()) && NSuffixLength == 0)
                    {
                        NSuffixLength = (int)read.CigarData.GetSuffixClip();
                    }
                }

                // Only build up the cigar for the non-N middle. Add the N prefix back on after the realignment attempts.
                freshCigarWithoutTerminalNsRaw.Add(new CigarOp('M', (uint)(read.Sequence.Length - NPrefixLength - NSuffixLength)));
                freshCigarWithoutTerminalNsRaw.Compress();

                // start with fresh position map
                var positionMapWithoutTerminalNs = new PositionMap(read.ReadLength - NPrefixLength - NSuffixLength);

                Read.UpdatePositionMap(position, freshCigarWithoutTerminalNsRaw, positionMapWithoutTerminalNs);
                PrefixSoftclip = read.CigarData.GetPrefixClip();
                SuffixSoftclip = read.CigarData.GetSuffixClip();

                SequenceWithoutTerminalNs =
                    read.Sequence.Substring(NPrefixLength, read.Sequence.Length - NPrefixLength - NSuffixLength);

                PositionMapWithoutTerminalNs = positionMapWithoutTerminalNs;
                PositionMapLength            = positionMapWithoutTerminalNs.Length;
                FreshCigarWithoutTerminalNs  = freshCigarWithoutTerminalNsRaw;
                Position = position;
            }
Exemplo n.º 2
0
        public void FindValidPositionsAndAddBuildings(List <Entity> entities)
        {
            PositionMap positionMap = new PositionMap();

            for (int i = 0; i < entities.Count; i++)
            {
                Entity            entity            = entities[i];
                BuildingComponent buildingComponent = entity.Get <BuildingComponent>();
                Building          buildingTO        = buildingComponent.BuildingTO;
                if (this.FindValidPositionAndUpdate(entity, buildingTO))
                {
                    positionMap.AddPosition(buildingTO.Key, new Position
                    {
                        X = buildingTO.X,
                        Z = buildingTO.Z
                    });
                }
            }
            Service.Get <ServerAPI>().Enqueue(new BuildingMultiMoveCommand(new BuildingMultiMoveRequest
            {
                PositionMap = positionMap
            }));
        }
Exemplo n.º 3
0
        private void LayoutThreadlines(long currentTick)
        {
            PositionMap.Clear();

            ThreadlineNodes.Clear();

            // go through each thread object and position nodes
            float xOffset    = 0;
            float nodeHeight = 18;
            float nodeWidth  = 18;

            foreach (var timeline in Threadlines.Values.OrderBy(t => t.ThreadID))
            {
                // do depth correction so we dont have empty columns
                int fixedDepth = 0;
                timeline.FixedDepths = new int[timeline.Deepest + 1];
                foreach (var depth in timeline.DepthSet)
                {
                    timeline.FixedDepths[depth] = fixedDepth;
                    fixedDepth++;
                }

                timeline.NodeDepths = new ThreadlineNode[timeline.Deepest + 2]; // an extra level to prevent outside bounds exc when checking lower level

                float yPos = ScreenSize.Height - nodeHeight - 16;

                float colWidth = timeline.Deepest * nodeWidth + 100;

                string label = "#" + timeline.ThreadID.ToString() + ": " + timeline.Name;
                float  x     = ScreenOffset.X + xOffset + 2;
                float  y     = ScreenOffset.Y + yPos + nodeHeight + 2;
                Renderer.DrawString(label, TextFont, timeline.IsAlive ? Color.Black : Color.Gray, x, y, colWidth, 18);

                foreach (var item in timeline.Sequence)
                {
                    var node = NodeModels[item.NodeID];

                    PositionMap[node.ID] = node;

                    int   depth = timeline.FixedDepths[item.Depth];
                    float xPos  = xOffset + nodeWidth * depth;

                    var area = new RectangleF(ScreenOffset.X + xPos, ScreenOffset.Y + yPos, nodeHeight, nodeWidth);

                    // only light up the latest node
                    if (!AddedNodes.Contains(node.ID))
                    {
                        node.RoomForLabel = true;
                        node.SetArea(area);
                    }

                    // extend this node down to the previous nodes (future node) depth
                    bool foundPrev = false;
                    for (int i = depth + 1; i < timeline.NodeDepths.Length; i++)
                    {
                        if (!foundPrev && timeline.NodeDepths[i] != null)
                        {
                            area.Height = timeline.NodeDepths[i].Area.Bottom - area.Top;
                            foundPrev   = true;
                        }


                        timeline.NodeDepths[i] = null;
                    }

                    bool showHit = false;
                    if (item.EndTick == 0 || Utilities.TicksToSeconds(currentTick - item.StartTick) < 1.0) // of started in last second
                    {
                        showHit = true;
                    }

                    float labelX     = ScreenOffset.X + xPos + nodeWidth + 3;
                    float labelWidth = colWidth - nodeWidth * (depth + 1) - 3;
                    var   labelArea  = new RectangleF(labelX, ScreenOffset.Y + yPos + 1, labelWidth, nodeHeight);
                    var   entry      = new ThreadlineNode()
                    {
                        Node = node, Area = area, LabelArea = labelArea, ShowHit = showHit
                    };

                    if (timeline.NodeDepths[depth] == null)
                    {
                        timeline.NodeDepths[depth] = entry;
                    }

                    ThreadlineNodes.Add(entry);

                    yPos -= nodeHeight;
                }

                xOffset += colWidth;
            }
        }
Exemplo n.º 4
0
        public void DrawCallGraph()
        {
            if (DoRevalue ||
                XRay.CallChange ||
                (ShowLayout != ShowNodes.All && XRay.CoverChange) ||
                (ShowLayout == ShowNodes.Instances && XRay.InstanceChange))
            {
                RecalcCover(InternalRoot);
                RecalcCover(ExternalRoot);

                PositionMap.Clear();
                CenterMap.Clear();

                var root = CurrentRoot;
                //causes method graph with ShowExternal on to show nothing
                //if (root == InternalRoot && ShowExternal)
                //    root = TopRoot;

                TopGraph = new GraphSet(this, root);

                // combine position and center maps for graph tree
                Utilities.RecurseTree(
                    TopGraph,
                    s =>
                {
                    foreach (var kvp in s.PositionMap)
                    {
                        PositionMap[kvp.Key] = kvp.Value;
                    }

                    foreach (var id in s.CenterMap)
                    {
                        CenterMap.Add(id);
                    }
                },
                    s => s.Subsets.Values
                    );

                XRay.CallChange     = false;
                XRay.CoverChange    = false;
                XRay.InstanceChange = false;

                DoRevalue = false;
                RevalueCount++;

                DoResize = true;
            }

            // graph created in relative coords so it doesnt need to be re-computed each resize, only on recalc

            if (DoResize)
            {
                Utilities.RecurseTree(
                    TopGraph,
                    s =>
                {
                    foreach (var graph in s.Graphs)
                    {
                        if (s.GraphContainer == null)
                        {
                            ScaleGraph(graph, new RectangleF(ScreenOffset, ScreenSize));
                        }

                        else if (s.GraphContainer.XNode.External)
                        {
                            // this is assuming the external node is a triangle
                            var area   = s.GraphContainer.AreaF;
                            var inside = new RectangleF(area.X + area.Width / 4f, area.Y + area.Height / 2f, area.Width / 2f, area.Height / 2f);
                            ScaleGraph(graph, inside);
                        }
                        else
                        {
                            ScaleGraph(graph, s.GraphContainer.AreaF);
                        }
                    }
                },
                    s => s.Subsets.Values
                    );

                DoResize = false;
                ResizeCount++;
            }
        }
Exemplo n.º 5
0
        public static int GetSumOfMismatchQualities(byte[] quals, string readSequence, PositionMap positionMap, string refSequence,
                                                    int startIndexInRefSequence = 0)
        {
            var matchMap = GetMismatchMap(readSequence, positionMap, refSequence, startIndexInRefSequence);

            return(GetSumOfMismatchQualities(matchMap, quals));
        }
Exemplo n.º 6
0
 internal static extern double ecore_animator_pos_map_n(double pos, PositionMap map, int v_size, double[] v);
Exemplo n.º 7
0
		private static PositionMap _ParseChildren(ElementNode parentNode, PositionValue parentPosition)
		{
			// Traverse every node.  Nodes with the position property will affect the childrens'
			// positions.
			PositionMap childValues = new PositionMap();

			PositionModule positionProperty = parentNode.Properties.Get(PositionDescriptor._typeId) as PositionModule;

			foreach (ElementNode childNode in parentNode.Children) {
				PositionValue childPosition = positionProperty.GetPositionValues(childNode.Id);
				if (childPosition != null) {
					// Parent has a modifying position for the child.
					childPosition = _Multiply(parentPosition, childPosition);
				}
				else {
					// Child inherits parent's position.
					childPosition = new PositionValue(parentPosition);
				}

				childValues[childNode.Id] = childPosition;
				childValues.AddRange(_ParseChildren(childNode, childPosition));
			}

			return childValues;
		}
Exemplo n.º 8
0
 public static void SearchMeposPositions(ILogger <Worker> logger)
 {
     // Configue all the meepos positions (How can we calculate the first position of the meepo bar? )
     PositionMap.RecalculateMeepos(logger);
 }
Exemplo n.º 9
0
 internal static extern double ecore_animator_pos_map(double pos, PositionMap map, double v1, double v2);
Exemplo n.º 10
0
 public void MoveMap(Location location)
 {
     PositionMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(location.Latitude, location.Longitude), Distance.FromKilometers(Settings.SearchRadius)), true);
 }
Exemplo n.º 11
0
        private RealignmentResult AddIndelAndGetResult(string readSequence, CandidateIndel priorIndel,
                                                       string refSequence, bool anchorLeft, PositionMap positionMap)
        {
            var foundIndel = false;
            var insertionPostionInReadStart = -1;
            var insertionPositionInReadEnd  = -1;

            if (anchorLeft)
            {
                // move along position map to see if we can insert indel
                for (var i = 0; i < positionMap.Length; i++)
                {
                    if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition && i != positionMap.Length - 1)  // make sure we dont end right before indel
                    {
                        foundIndel = true;

                        if (priorIndel.Type == AlleleCategory.Insertion)
                        {
                            insertionPostionInReadStart = i + 1;

                            // stick in -1 for insertion length, then adjust positions after
                            for (var j = i + 1; j < positionMap.Length; j++)
                            {
                                if (j - i <= priorIndel.Length)
                                {
                                    positionMap.UpdatePositionAtIndex(j, -1, true);
                                    if (j - i == priorIndel.Length || j == positionMap.Length - 1)
                                    {
                                        insertionPositionInReadEnd = j;
                                    }
                                }
                                else
                                {
                                    if (positionMap.GetPositionAtIndex(j) != -1) // preserve existing insertions
                                    {
                                        positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) - priorIndel.Length);
                                    }
                                }
                            }
                            break;
                        }

                        if (priorIndel.Type == AlleleCategory.Deletion)
                        {
                            // offset positions after deletion
                            for (var j = i + 1; j < positionMap.Length; j++)
                            {
                                if (positionMap.GetPositionAtIndex(j) != -1)  // preserve existing insertions
                                {
                                    positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) + priorIndel.Length);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            else
            {
                // walk backwards along position map to see if we can insert indel
                if (priorIndel.Type == AlleleCategory.Insertion)
                {
                    for (var i = positionMap.Length - 1; i >= 0; i--)
                    {
                        if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition + 1 && i != 0)
                        {
                            foundIndel = true;
                            insertionPositionInReadEnd = i - 1;
                        }
                        else if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition && i != positionMap.Length - 1)
                        {
                            foundIndel = true;
                            insertionPositionInReadEnd = i;
                        }

                        if (foundIndel)
                        {
                            // stick in -1 for insertion length, then adjust positions
                            for (var j = insertionPositionInReadEnd; j >= 0; j--)
                            {
                                if (insertionPositionInReadEnd - j + 1 <= priorIndel.Length)
                                {
                                    positionMap.UpdatePositionAtIndex(j, -1, true);
                                    if (insertionPositionInReadEnd - j + 1 == priorIndel.Length || j == 0)
                                    {
                                        insertionPostionInReadStart = j;
                                    }
                                }
                                else
                                {
                                    if (positionMap.GetPositionAtIndex(j) != -1) // Don't update position map for things that were already -1
                                    {
                                        positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) + priorIndel.Length);
                                    }
                                }
                            }

                            break;
                        }
                    }
                }
                else if (priorIndel.Type == AlleleCategory.Deletion)
                {
                    for (var i = positionMap.Length - 1; i >= 1; i--)
                    {
                        if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition + priorIndel.Length + 1) //deletions must be fully anchored to be observed
                        {
                            foundIndel = true;

                            // offset positions after deletion
                            for (var j = i - 1; j >= 0; j--)
                            {
                                if (positionMap.GetPositionAtIndex(j) != -1) // preserve existing insertions
                                {
                                    positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) - priorIndel.Length);
                                }
                            }

                            break;
                        }
                    }
                }
            }

            if (!foundIndel || !Helper.IsValidMap(positionMap.Map, refSequence))
            {
                return(null);
            }

            // verify insertion matches
            if (priorIndel.Type == AlleleCategory.Insertion)
            {
                if (insertionPostionInReadStart == -1 || insertionPositionInReadEnd == -1)
                {
                    return(null); // weird, this shouldnt ever happen
                }
                var readInsertedSequence = readSequence.Substring(insertionPostionInReadStart,
                                                                  insertionPositionInReadEnd - insertionPostionInReadStart + 1);

                var indelSequence = priorIndel.AlternateAllele.Substring(1);

                var clippedPriorSequence = anchorLeft
                    ? indelSequence.Substring(0, readInsertedSequence.Length)
                    : indelSequence.Substring(indelSequence.Length - readInsertedSequence.Length);

                var mismatches = Helper.GetNumMismatches(readInsertedSequence, clippedPriorSequence);
                if (mismatches == null || mismatches > 0)
                {
                    return(null); // inserted sequence doesn't match read
                }
            }

            var newCigar = Helper.ConstructCigar(positionMap.Map);

            var newSummary = Extensions.GetAlignmentSummary(positionMap.FirstMappableBase() - 1, newCigar, refSequence,
                                                            readSequence);

            if (newSummary == null)
            {
                return(null);
            }

            var readHasPosition = positionMap.HasAnyMappableBases();

            if (!readHasPosition)
            {
                throw new InvalidDataException(string.Format("Trying to generate result and read does not have any alignable bases. ({0}, {1})", newCigar, string.Join(",", positionMap)));
            }
            return(new RealignmentResult()
            {
                Cigar = newCigar,
                NumIndels = newCigar.NumIndels(),
                Position = positionMap.FirstMappableBase(),
                NumMismatches = newSummary.NumMismatches,
                NumNonNMismatches = newSummary.NumNonNMismatches,
                NumMismatchesIncludeSoftclip = newSummary.NumMismatchesIncludeSoftclip,
                NumSoftclips = newSummary.NumSoftclips,
                NumNonNSoftclips = newSummary.NumNonNSoftclips,
                NumIndelBases = newSummary.NumIndelBases
            });
        }
Exemplo n.º 12
0
        private RealignmentResult AddIndelAndGetResult(string readSequence, HashableIndel priorIndel,
                                                       string refSequence, bool anchorLeft, PositionMap positionMap, int refSequenceStartIndex, bool pairSpecific)
        {
            var  foundIndel = false;
            var  insertionPostionInReadStart     = -1;
            var  insertionPositionInReadEnd      = -1;
            var  deletionPositionInRead          = -1;
            bool anyPositionsAfterDeletionMapped = false;

            // TODO PERF can we bail out early if it's not possible that the indel could be inserted in the read, based on position?

            if (anchorLeft)
            {
                // move along position map to see if we can insert indel
                for (var i = 0; i < positionMap.Length; i++)
                {
                    if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition && i != positionMap.Length - 1)  // make sure we dont end right before indel
                    {
                        foundIndel = true;

                        if (priorIndel.Type == AlleleCategory.Insertion)
                        {
                            insertionPostionInReadStart = i + 1;

                            // stick in -1 for insertion length, then adjust positions after
                            for (var j = i + 1; j < positionMap.Length; j++)
                            {
                                if (j - i <= priorIndel.Length)
                                {
                                    positionMap.UpdatePositionAtIndex(j, -1, true);
                                    if (j - i == priorIndel.Length || j == positionMap.Length - 1)
                                    {
                                        insertionPositionInReadEnd = j;
                                    }
                                }
                                else
                                {
                                    if (positionMap.GetPositionAtIndex(j) != -1) // preserve existing insertions
                                    {
                                        positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) - priorIndel.Length);
                                    }
                                }
                            }
                            break;
                        }

                        if (priorIndel.Type == AlleleCategory.Deletion)
                        {
                            deletionPositionInRead = i;
                            // offset positions after deletion
                            for (var j = i + 1; j < positionMap.Length; j++)
                            {
                                if (positionMap.GetPositionAtIndex(j) != -1) // preserve existing insertions
                                {
                                    anyPositionsAfterDeletionMapped = true;
                                    positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) + priorIndel.Length);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            else
            {
                // walk backwards along position map to see if we can insert indel
                if (priorIndel.Type == AlleleCategory.Insertion)
                {
                    for (var i = positionMap.Length - 1; i >= 0; i--)
                    {
                        if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition + 1 && i != 0)
                        {
                            foundIndel = true;
                            insertionPositionInReadEnd = i - 1;
                        }
                        else if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition && i != positionMap.Length - 1)
                        {
                            foundIndel = true;
                            insertionPositionInReadEnd = i;
                        }

                        if (foundIndel)
                        {
                            // stick in -1 for insertion length, then adjust positions
                            for (var j = insertionPositionInReadEnd; j >= 0; j--)
                            {
                                if (insertionPositionInReadEnd - j + 1 <= priorIndel.Length)
                                {
                                    positionMap.UpdatePositionAtIndex(j, -1, true);
                                    if (insertionPositionInReadEnd - j + 1 == priorIndel.Length || j == 0)
                                    {
                                        insertionPostionInReadStart = j;
                                    }
                                }
                                else
                                {
                                    if (positionMap.GetPositionAtIndex(j) != -1) // Don't update position map for things that were already -1
                                    {
                                        positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) + priorIndel.Length);
                                    }
                                }
                            }

                            break;
                        }
                    }
                }
                else if (priorIndel.Type == AlleleCategory.Deletion)
                {
                    for (var i = positionMap.Length - 1; i >= 1; i--)
                    {
                        if (positionMap.GetPositionAtIndex(i) == priorIndel.ReferencePosition + priorIndel.Length + 1) //deletions must be fully anchored to be observed
                        {
                            foundIndel = true;

                            deletionPositionInRead = i - 1;
                            // offset positions after deletion
                            for (var j = i - 1; j >= 0; j--)
                            {
                                if (positionMap.GetPositionAtIndex(j) != -1) // preserve existing insertions
                                {
                                    anyPositionsAfterDeletionMapped = true;
                                    positionMap.UpdatePositionAtIndex(j, positionMap.GetPositionAtIndex(j) - priorIndel.Length);
                                }
                            }

                            break;
                        }
                    }
                }
            }

            //if (!foundIndel || !Helper.IsValidMap(positionMap, refSequence))
            //TODO changed this just for tailor
            if (!foundIndel || (priorIndel.Type == AlleleCategory.Deletion && !anyPositionsAfterDeletionMapped) || !Helper.IsValidMap(positionMap.Map))
            {
                return(null);
            }

            var isSketchy = false;

            if (priorIndel.IsRepeat)
            {
                //if (priorIndel.Type == AlleleCategory.Deletion)
                //{
                //    if (Helper.RepeatDeletionFlankedByRepeats(readSequence, priorIndel, deletionPositionInRead))
                //    {
                //        return null;
                //    }
                //}

                //// TODO in the case of using sketchy anchor test:
                //// Ideally, we'd check the anchor length against how many repeats are in the reference vs the variant,
                //// ... Or maybe just always check the whole anchor if it's a repeat.
                var anchorLength = priorIndel.Type == AlleleCategory.Insertion ? Math.Min(insertionPostionInReadStart, readSequence.Length - insertionPositionInReadEnd) : Math.Min(deletionPositionInRead, readSequence.Length - deletionPositionInRead);
                if (anchorLength >= readSequence.Length)
                {
                    throw new Exception("Anchor should never be longer than read length."); // TODO remove after dev.
                }
                if (anchorLength < Math.Max(10, priorIndel.Length))
                {
                    if (priorIndel.Type == AlleleCategory.Deletion)
                    {
                        if (Helper.DeletionHasSketchyAnchor(readSequence, priorIndel, deletionPositionInRead))
                        {
                            if (pairSpecific)
                            {
                                isSketchy = true;
                            }
                            else
                            {
                                return(null);
                            }
                        }
                    }
                    else
                    {
                        if (priorIndel.NumBasesInReferenceSuffixBeforeUnique >= anchorLength)
                        {
                            if (pairSpecific)
                            {
                                isSketchy = true;
                            }
                            else
                            {
                                return(null);
                            }
                        }
                    }
                }
            }

            // TODO do we need to be more nuanced about this and only do it in duplication areas?
            if (priorIndel.Type == AlleleCategory.Deletion)
            {
                var anchorStart       = deletionPositionInRead + 1;
                var rightAnchorLength = readSequence.Length - anchorStart;
                if (rightAnchorLength < priorIndel.Length)
                {
                    if (anchorStart < readSequence.Length)
                    {
                        if (readSequence.Substring(anchorStart) ==
                            priorIndel.ReferenceAllele.Substring(1, rightAnchorLength))
                        {
                            return(null);
                        }
                    }
                }
            }

            if (priorIndel.IsDuplication && priorIndel.Type == AlleleCategory.Insertion)
            {
                // TODO return to this - I think the thought was to prevent FP dups, but the implementation may have been wrong
                // No partial duplications?
                //if (readSequence.Length - insertionPositionInReadEnd <= priorIndel.Length)

                if (readSequence.Length - insertionPositionInReadEnd <= 3)
                {
                    // Assumes priors are left-aligned
                    return(null);
                }
            }

            //verify insertion matches
            var newReadSequence = readSequence;
            var nifiedAt        = new List <int>();

            if (priorIndel.Type == AlleleCategory.Insertion)
            {
                if (insertionPostionInReadStart == -1 || insertionPositionInReadEnd == -1)
                {
                    return(null); // weird, this shouldnt ever happen
                }
                var readInsertedSequence = readSequence.Substring(insertionPostionInReadStart,
                                                                  insertionPositionInReadEnd - insertionPostionInReadStart + 1);

                var indelSequence = priorIndel.AlternateAllele.Substring(1);

                if (anchorLeft && readInsertedSequence.Length < indelSequence.Length && priorIndel.NumApproxDupsRight > 0)
                {
                    // Don't allow partial realignment to dups
                    return(null);
                }
                if (!anchorLeft && readInsertedSequence.Length < indelSequence.Length && priorIndel.NumApproxDupsLeft > 0)
                {
                    // Don't allow partial realignment to dups
                    return(null);
                }

                var clippedPriorSequence = anchorLeft
                    ? indelSequence.Substring(0, readInsertedSequence.Length)
                    : indelSequence.Substring(indelSequence.Length - readInsertedSequence.Length);

                var isMismatch = readInsertedSequence != clippedPriorSequence;
                if (isMismatch)
                {
                    int?mismatches     = null;
                    var mismatchesToDq = 0d;
                    if (priorIndel.Length >= _minInsertionSizeToAllowMismatchingBases && !(priorIndel.NumApproxDupsLeft + priorIndel.NumApproxDupsRight > 0))
                    {
                        mismatches = Helper.GetHammingNumMismatches(readInsertedSequence, clippedPriorSequence);

                        mismatchesToDq = priorIndel.Length * _maxProportionInsertSequenceMismatch;

                        if (mismatches > mismatchesToDq)
                        {
                            //Console.WriteLine(
                            //    $"Too many mismatches between insertions: {mismatches} > {maxAllowedMismatches} ({clippedPriorSequence} vs {readInsertedSequence})");
                        }
                        else
                        {
                            //Console.WriteLine(
                            //    $"Able to Nify mismatches between insertions: {mismatches} <= {maxAllowedMismatches} ({clippedPriorSequence} vs {readInsertedSequence})");

                            var newSequence =
                                Helper.NifyMismatches(clippedPriorSequence, readInsertedSequence, nifiedAt);
                            // TODO PERF is this actually necessary now that we're not actually Nifying? We can just keep the bases that we're Nifying at.
                            newReadSequence = readSequence.Substring(0, insertionPostionInReadStart) +
                                              newSequence.ToLower() +
                                              readSequence.Substring(insertionPositionInReadEnd + 1);
                            nifiedAt = nifiedAt.Select(x => x + insertionPostionInReadStart).ToList();
                        }
                    }

                    if (mismatches == null || (mismatches > mismatchesToDq))
                    {
                        return(null); // inserted sequence doesn't match read
                    }
                }
            }

            // TODO update to use PositionMap class
            var newCigar = Helper.ConstructCigar(positionMap.Map);

            // TODO moved this, and probably should in original Hygea too?
            // Also, can cut down the calls to positionmap.First() in the original
            //var readHasPosition = positionMap.Any(p => p > 0); // Position map is one-based, so should be >, not >= 0.
            if (!positionMap.HasAnyMappableBases())
            {
                throw new InvalidDataException(string.Format("Trying to generate result and read does not have any alignable bases. ({0}, {1})", newCigar, string.Join(",", positionMap)));
            }

            var startIndexInReference          = positionMap.FirstMappableBase() - 1; // Position map is one-based, so should be >, not >= 0.
            var startIndexInRefSequenceSnippet = startIndexInReference - refSequenceStartIndex;

            var newSummary = Extensions.GetAlignmentSummary(startIndexInRefSequenceSnippet, newCigar, refSequence,
                                                            newReadSequence, _trackActualMismatches, _checkSoftclipsForMismatches);

            if (newSummary == null)
            {
                return(null);
            }

            return(new RealignmentResult()
            {
                Cigar = newCigar,
                NumIndels = newCigar.NumIndels(),
                Position = startIndexInReference + 1,
                NumMismatches = newSummary.NumMismatches,
                NumNonNMismatches = newSummary.NumNonNMismatches,
                NumSoftclips = newSummary.NumSoftclips,
                NumNonNSoftclips = newSummary.NumNonNSoftclips,
                NumDeletedBases = newSummary.NumDeletedBases,
                NumInsertedBases = newSummary.NumInsertedBases,
                NumMatches = newSummary.NumMatches,
                NumIndelBases = newSummary.NumIndelBases,
                NumMismatchesIncludeSoftclip = newSummary.NumMismatchesIncludeSoftclip,
                MismatchesIncludeSoftclip = newSummary.MismatchesIncludeSoftclip,
                Indels = StringifyIndel(priorIndel),
                NifiedAt = nifiedAt,
                IndelsAddedAt = new List <int> {
                    priorIndel.Type == AlleleCategory.Insertion ? insertionPostionInReadStart : deletionPositionInRead
                },
                IsSketchy = isSketchy
            });
        }
Exemplo n.º 13
0
        private RealignmentResult RealignForAnchor(HashableIndel[] indels, Dictionary <HashableIndel, GenomeSnippet> indelContexts,
                                                   Read read, bool anchorOnLeft, ReadToRealignDetails details, bool pairSpecific, int[] indexes)
        {
            try
            {
                var freshCigarWithoutTerminalNs = new CigarAlignment(details.FreshCigarWithoutTerminalNs);
                var freshPositionMap            = new PositionMap(details.PositionMapLength);

                for (int i = 0; i < details.PositionMapLength; i++)
                {
                    freshPositionMap.UpdatePositionAtIndex(i,
                                                           details.PositionMapWithoutTerminalNs.GetPositionAtIndex(i));
                }

                var result = new RealignmentResult();

                // layer on indels one by one, indels already sorted by ascending position

                if (LayerOnIndels(indels, indelContexts, anchorOnLeft, details.SequenceWithoutTerminalNs,
                                  freshPositionMap, ref result, pairSpecific))
                {
                    return(null);
                }

                var context = indelContexts[indels[0]];

                // Softclip partial insertions at read ends
                if (_maskPartialInsertion || _minimumUnanchoredInsertionLength > 0)
                {
                    MaskPartialInsertion(indels, read, context.Sequence, result, context.StartPosition);
                }

                _softclipReapplier.ReapplySoftclips(read, details.NPrefixLength, details.NSuffixLength, freshPositionMap, result, context,
                                                    details.PrefixSoftclip, details.SuffixSoftclip, freshCigarWithoutTerminalNs);

                result.AcceptedIndels         = new List <int>();
                result.AcceptedHashableIndels = new List <HashableIndel>();
                for (int i = 0; i < result.AcceptedIndelsInSubList.Count; i++)
                {
                    // TODO do we need to be more nuanced about this and only do it in duplication areas?
                    var currentSubIndex = result.AcceptedIndelsInSubList[i];
                    result.AcceptedIndels.Add(indexes[currentSubIndex]);
                    var currentIndel = indels[currentSubIndex];
                    result.AcceptedHashableIndels.Add(currentIndel);
                    if (currentIndel.Type == AlleleCategory.Deletion)
                    {
                        var addedAt             = result.IndelsAddedAt[i];
                        var anchorStart         = addedAt + 1;
                        var lastOp              = result.Cigar[result.Cigar.Count - 1];
                        var rightSoftclipLength = lastOp.Type == 'S' ? (int)lastOp.Length : 0;
                        var rightAnchorLength   = read.Sequence.Length - anchorStart - rightSoftclipLength;
                        if (rightAnchorLength < currentIndel.Length && anchorStart < read.Sequence.Length)
                        {
                            if (read.Sequence.Substring(anchorStart, rightAnchorLength) ==
                                currentIndel.ReferenceAllele.Substring(1, rightAnchorLength))
                            {
                                return(null);
                            }
                        }
                    }
                }

                if (result.SumOfMismatchingQualities == null)
                {
                    result.SumOfMismatchingQualities = Helper.GetSumOfMismatchQualities(read.Qualities, read.Sequence,
                                                                                        freshPositionMap, context.Sequence,
                                                                                        context.StartPosition);
                }


                result.Indels = string.Join("|", indels.Select(x => StringifyIndel(x)));

                return(result);
            }
            catch (Exception e)
            {
                if (_debug)
                {
                    Logger.WriteExceptionToLog(new Exception($"Realign for anchor failed: read '{read.Name}' with indels {(string.Join("|", indels.Select(x => StringifyIndel(x))))}, anchoring on {(anchorOnLeft ? "left" : "right")}.", e));
                }
                return(null);
            }
        }
Exemplo n.º 14
0
 public PositionData()
 {
     ChildrenPositions = new PositionMap();
 }
Exemplo n.º 15
0
 /*
 internal void setUserState (object obj) {
   userState = obj;
 }*/
 //caller should not change input after it is passed in.
 internal ParseContext(int at, string module, PositionMap pmap)
 {
     //this.userState = us;
     this.step = 0;
     this.at = at;
     this.module = module;
     this.pmap = pmap;
 }
Exemplo n.º 16
0
 //caller should not change input after it is passed in.
 internal ParserState(Tok[] input,
     int at, string module, PositionMap pmap,
     int end_index,
     string eof_str, ShowToken show)
     : base(at, module, pmap)
 {
     this.input = input;
     this.sys_unexpected = new ParsecError[input.Length];
     this.show = show;
     this.end_index = end_index;
     this.eof_unexpected = ParsecError.raiseSysUnexpected(
         end_index, eof_str);
 }
Exemplo n.º 17
0
 internal ScannerState(string src, int a,
     string module, PositionMap pmap,
     int l)
     : base(a, module, pmap)
 {
     this.src = src;
     this.len = l;
 }
Exemplo n.º 18
0
        public void Render()
        {
            // clear and pre-process marked depencies
            RecalcDependencies();

            // figure out if we need to do a search
            if (SearchString != LastSearch)
            {
                DoSearch();
            }

            // draw layout
            ScreenSize.Width  = Renderer.ViewWidth * ZoomFactor;
            ScreenSize.Height = Renderer.ViewHeight * ZoomFactor;
            ScreenOffset.X    = PanOffset.X * ScreenSize.Width;  // +(Width * CenterFactor.X - ModelSize.Width * CenterFactor.X);
            ScreenOffset.Y    = PanOffset.Y * ScreenSize.Height; // +(Height * CenterFactor.Y - ModelSize.Height * CenterFactor.Y);

            if (ViewLayout == LayoutType.TreeMap)
            {
                DrawTreeMap(Renderer);

                if (ShowingOutside)
                {
                    Renderer.DrawTextBackground(XColors.BorderColor, InternalRoot.AreaF.Width, 0, PanelBorderWidth, InternalRoot.AreaF.Height);
                    DrawNode(InternalRoot, 0, true);
                }

                if (ShowingExternal)
                {
                    Renderer.DrawTextBackground(XColors.BorderColor, ExternalRoot.AreaF.X - PanelBorderWidth, 0, PanelBorderWidth, ExternalRoot.AreaF.Height);
                    DrawNode(ExternalRoot, 0, true);
                }

                DrawNode(CurrentRoot, 0, true);
            }

            else if (ViewLayout == LayoutType.CallGraph)
            {
                DrawCallGraph();

                // id 0 nodes are intermediates
                foreach (var node in PositionMap.Values)
                {
                    //foreach (var node in Graphs.SelectMany(g => g.Nodes()).Where(n => n.ID != 0))
                    DrawNode(node, 0, false);
                }
            }

            else if (ViewLayout == LayoutType.Timeline)
            {
                DrawTheadline();

                foreach (var node in ThreadlineNodes)
                {
                    DrawNode(node.Node, node.Area, node.LabelArea, 0, false, node.ShowHit);
                }
            }


            // draw ignored over nodes ignored may contain

            /*foreach (var ignored in IgnoredNodes.Values)
             *  if (PositionMap.ContainsKey(ignored.ID))
             *  {
             *      Renderer.DrawLine(XColors.IgnoredColor, 1, ignored.AreaF.UpperLeftCorner(), ignored.AreaF.LowerRightCorner(), false);
             *      Renderer.DrawLine(XColors.IgnoredColor, 1, ignored.AreaF.UpperRightCorner(), ignored.AreaF.LowerLeftCorner(), false);
             *  }*/

            // draw dividers for call graph

            /*if (ViewLayout == LayoutType.CallGraph)
             * {
             *  if (ShowRightOutsideArea)
             *      buffer.DrawLine(CallDividerPen, RightDivider, 0, RightDivider, Height);
             *
             *  if (ShowLeftOutsideArea)
             *      buffer.DrawLine(CallDividerPen, LeftDivider, 0, LeftDivider, Height);
             * }*/


            // draw dependency graph
            if (ViewLayout == LayoutType.CallGraph &&
                (GraphMode == CallGraphMode.Dependencies ||
                 GraphMode == CallGraphMode.Init ||
                 GraphMode == CallGraphMode.Intermediates))
            {
                foreach (var source in PositionMap.Values)
                {
                    if (source.EdgesOut == null)
                    {
                        continue;
                    }

                    foreach (var to in source.EdgesOut)
                    {
                        if (!PositionMap.ContainsKey(to))
                        {
                            continue;
                        }

                        var destination = PositionMap[to];

                        int penWidth = (source.Focused || destination.Focused) ? 2 : 1;

                        if ((!DrawCallGraphVertically && source.AreaF.X < destination.AreaF.X) ||
                            (DrawCallGraphVertically && source.AreaF.Y < destination.AreaF.Y))
                        {
                            DrawGraphEdge(penWidth, XColors.CallOutColor, source, destination);
                        }
                        else
                        {
                            DrawGraphEdge(penWidth, XColors.CallInColor, source, destination);
                        }
                    }
                }
            }


            // draw call graph
            if (XRay.FlowTracking && ViewLayout != LayoutType.Timeline)
            {
                foreach (var source in PositionMap.Values)
                {
                    if (source.XNode.CallsOut == null)
                    {
                        continue;
                    }

                    if (ViewLayout == LayoutType.TreeMap && source.ObjType == XObjType.Class && ShowMethods)
                    {
                        continue;
                    }

                    if (ViewLayout == LayoutType.CallGraph &&
                        GraphMode != CallGraphMode.Init &&
                        source.ObjType == XObjType.Class &&
                        ShowMethods)
                    {
                        continue;
                    }


                    foreach (var call in source.XNode.CallsOut)
                    {
                        if (!PositionMap.ContainsKey(call.Destination))
                        {
                            continue;
                        }

                        if (ShowThreads != null && !call.ThreadIDs.Any(id => ShowThreads.Contains(id)))
                        {
                            continue;
                        }

                        var destination = PositionMap[call.Destination];

                        // if there are items we're filtering on then only show calls to those nodes
                        if (FilteredNodes.Count > 0 && !IsNodeFiltered(true, source) && !IsNodeFiltered(true, destination))
                        {
                            continue;
                        }

                        // do after select filter so we can have ignored nodes inside selected, but not the otherway around
                        if (IgnoredNodes.Count > 0 && IsNodeFiltered(false, source) || IsNodeFiltered(false, destination))
                        {
                            continue;
                        }

                        int lineWidth = (source.Focused || destination.Focused) ? 2 : 1;

                        if (call.StillInside > 0 && ShowCalls)
                        {
                            if (ViewLayout == LayoutType.TreeMap)
                            {
                                Renderer.DrawCallLine(XColors.HoldingCallColor, lineWidth, source.CenterF, destination.CenterF, false, source, destination);
                            }
                            else if (ViewLayout == LayoutType.CallGraph)
                            {
                                DrawGraphEdge(lineWidth, XColors.HoldingCallColor, source, destination);
                            }
                        }

                        else if (ShowAllCalls &&
                                 GraphMode != CallGraphMode.Intermediates &&
                                 GraphMode != CallGraphMode.Init)
                        {
                            if (ViewLayout == LayoutType.TreeMap)
                            {
                                var callSource = PositionMap[call.Source];
                                var callDest   = PositionMap[call.Destination];

                                PointF start = callSource.CenterF;
                                PointF end   = callDest.CenterF;
                                PointF mid   = new PointF(start.X + (end.X - start.X) / 2, start.Y + (end.Y - start.Y) / 2);

                                Renderer.DrawCallLine(XColors.CallOutColor, lineWidth, start, mid, false, callSource, callDest);
                                Renderer.DrawCallLine(XColors.CallInColor, lineWidth, mid, end, false, callSource, callDest);
                            }
                            else if (ViewLayout == LayoutType.CallGraph)
                            {
                                if ((!DrawCallGraphVertically && source.AreaF.X < destination.AreaF.X) ||
                                    (DrawCallGraphVertically && source.AreaF.Y < destination.AreaF.Y))
                                {
                                    DrawGraphEdge(lineWidth, XColors.CallOutColor, source, destination);
                                }
                                else
                                {
                                    DrawGraphEdge(lineWidth, XColors.CallInColor, source, destination);
                                }
                            }
                        }

                        if (call.Hit > 0 && ShowCalls)
                        {
                            var color = XColors.CallPenColors[call.Hit];

                            if (ViewLayout == LayoutType.TreeMap)
                            {
                                Renderer.DrawCallLine(color, lineWidth, source.CenterF, destination.CenterF, true, source, destination);
                            }

                            else if (ViewLayout == LayoutType.CallGraph)
                            {
                                DrawGraphEdge(lineWidth, color, source, destination, true);
                            }
                        }
                    }
                }
            }

            XRay.DashOffset = (XRay.DashOffset == 0) ? 2 : XRay.DashOffset - 1;

            // draw mouse over label
            if (ViewLayout != LayoutType.Timeline)
            {
                DrawFooterLabel();
            }

            DrawToolTip();
        }
Exemplo n.º 19
0
        public void ReapplySoftclips(Read read, int nPrefixLength, int nSuffixLength, PositionMap positionMapWithoutTerminalNs,
                                     RealignmentResult result, GenomeSnippet context, uint prefixSoftclip, uint suffixSoftclip,
                                     CigarAlignment freshCigarWithoutTerminalNs)
        {
            // Re-append the N-prefix
            var nPrefixPositionMap = Enumerable.Repeat(-1, nPrefixLength);
            var nSuffixPositionMap = Enumerable.Repeat(-1, nSuffixLength);
            // TODO maybe have a function for combining pos maps instead
            var finalPositionMap = new PositionMap(nPrefixPositionMap.Concat(positionMapWithoutTerminalNs.Map).Concat(nSuffixPositionMap).ToArray());


            var finalCigar = new CigarAlignment {
                new CigarOp('S', (uint)nPrefixLength)
            };

            foreach (CigarOp op in result.Cigar)
            {
                finalCigar.Add(op);
            }

            finalCigar.Add(new CigarOp('S', (uint)nSuffixLength));
            finalCigar.Compress();
            result.Cigar = finalCigar;



            // In case realignment introduced a bunch of mismatch-Ms where there was previously softclipping, optionally re-mask them.
            if (result != null && _remaskSoftclips)
            {
                var mismatchMap =
                    Helper.GetMismatchMap(read.Sequence, finalPositionMap, context.Sequence, context.StartPosition);

                var softclipAdjustedCigar = Helper.SoftclipCigar(result.Cigar, mismatchMap, prefixSoftclip, suffixSoftclip,
                                                                 maskNsOnly: _maskNsOnly, prefixNs: Helper.GetCharacterBookendLength(read.Sequence, 'N', false),
                                                                 suffixNs: Helper.GetCharacterBookendLength(read.Sequence, 'N', true), softclipEvenIfMatch: _keepProbeSoftclips || _keepBothSideSoftclips, softclipRepresentsMess: (!(_keepBothSideSoftclips || _keepProbeSoftclips)));

                // Update position map to account for any softclipping added
                var adjustedPrefixClip = softclipAdjustedCigar.GetPrefixClip();
                for (var i = 0; i < adjustedPrefixClip; i++)
                {
                    finalPositionMap.UpdatePositionAtIndex(i, -2, true);
                }

                var adjustedSuffixClip = softclipAdjustedCigar.GetSuffixClip();
                for (var i = 0; i < adjustedSuffixClip; i++)
                {
                    finalPositionMap.UpdatePositionAtIndex(finalPositionMap.Length - 1 - i, -2, true);
                }

                var editDistance =
                    Helper.GetNumMismatches(read.Sequence, finalPositionMap, context.Sequence, context.StartPosition);
                if (editDistance == null)
                {
                    // This shouldn't happen at this point - we already have a successful result
                    throw new InvalidDataException("Edit distance is null for :" + read.Name + " with position map " +
                                                   string.Join(",", finalPositionMap) + " and CIGAR " + softclipAdjustedCigar);
                }

                // TODO PERF - See how much this really helps analytically. I'm thinking maybe kill this altogether and remove from eval
                var sumOfMismatching = Helper.GetSumOfMismatchQualities(mismatchMap, read.Qualities);

                var readHasPosition = finalPositionMap.HasAnyMappableBases();
                if (!readHasPosition)
                {
                    throw new InvalidDataException(string.Format(
                                                       "Read does not have any alignable bases. ({2} --> {0} --> {3}, {1})", freshCigarWithoutTerminalNs,
                                                       string.Join(",", finalPositionMap), read.CigarData, softclipAdjustedCigar));
                }

                result.Position      = finalPositionMap.FirstMappableBase(); // TODO this used to be >= 0 but changed to > 0. Confirm correct.
                result.Cigar         = softclipAdjustedCigar;
                result.NumMismatches = editDistance.Value;

                var addedAtFinal = new List <int>();
                foreach (var i in result.IndelsAddedAt)
                {
                    addedAtFinal.Add(i + nPrefixLength);
                }
                result.IndelsAddedAt = addedAtFinal;
                var nifiedAtFinal = new List <int>();
                foreach (var i in result.NifiedAt)
                {
                    nifiedAtFinal.Add(i + nPrefixLength);
                }
                result.NifiedAt = nifiedAtFinal;

                var newSummary = Extensions.GetAlignmentSummary(result.Position - 1 - context.StartPosition, result.Cigar,
                                                                context.Sequence,
                                                                read.Sequence, _trackActualMismatches, _checkSoftclipsForMismatches);

                result.NumNonNMismatches            = newSummary.NumNonNMismatches;
                result.NumNonNSoftclips             = newSummary.NumNonNSoftclips;
                result.NumSoftclips                 = newSummary.NumSoftclips;
                result.NumInsertedBases             = newSummary.NumInsertedBases;
                result.NumMismatchesIncludeSoftclip = newSummary.NumMismatchesIncludeSoftclip;
                //result.MismatchesIncludeSoftclip = newSummary.MismatchesIncludeSoftclip;
                result.SumOfMismatchingQualities = sumOfMismatching;
                result.AnchorLength = newSummary.AnchorLength;
            }
        }
Exemplo n.º 20
0
        private RealignmentResult RealignForAnchor(CandidateIndel[] indels, Read read, string refSequence, bool anchorOnLeft)
        {
            var position = read.GetAdjustedPosition(anchorOnLeft);
            var freshCigarWithoutTerminalNs = new CigarAlignment();

            var nPrefixLength = read.GetNPrefix();
            var nSuffixLength = read.GetNSuffix();

            // Only build up the cigar for the non-N middle. Add the N prefix back on after the realignment attempts.
            freshCigarWithoutTerminalNs.Add(new CigarOp('M', (uint)(read.Sequence.Length - nPrefixLength - nSuffixLength)));
            freshCigarWithoutTerminalNs.Compress();

            // start with fresh position map
            //var positionMapWithoutTerminalNsArray = new int[read.ReadLength - nPrefixLength - nSuffixLength];
            var positionMapWithoutTerminalNs = new PositionMap(read.ReadLength - nPrefixLength - nSuffixLength);

            Read.UpdatePositionMap(position, freshCigarWithoutTerminalNs, positionMapWithoutTerminalNs);
            var prefixSoftclip = read.CigarData.GetPrefixClip();
            var suffixSoftclip = read.CigarData.GetSuffixClip();

            RealignmentResult result      = null;
            var sequenceWithoutTerminalNs = read.Sequence.Substring(nPrefixLength, read.Sequence.Length - nPrefixLength - nSuffixLength);

            // layer on indels one by one, indels already sorted by ascending position
            if (anchorOnLeft)
            {
                for (var i = 0; i < indels.Length; i++)
                {
                    result = AddIndelAndGetResult(sequenceWithoutTerminalNs, indels[i], refSequence, true, positionMapWithoutTerminalNs);

                    if (result == null)
                    {
                        return(null);
                    }
                }
            }
            else
            {
                for (var i = indels.Length - 1; i >= 0; i--)
                {
                    result = AddIndelAndGetResult(sequenceWithoutTerminalNs, indels[i], refSequence, false, positionMapWithoutTerminalNs);

                    if (result == null)
                    {
                        return(null);
                    }
                }
            }


            // Softclip partial insertions at read ends
            // Assumption: there should be no softclips in the cigar by this time
            // Assumption: there should be exactly as many/the same indels in "indels" as are represented in the cigar in "result.Cigar".
            var  firstIndel   = indels[0];
            var  lastIndel    = indels[indels.Length - 1];
            bool hasInsertion = (firstIndel.Type == AlleleCategory.Insertion || lastIndel.Type == AlleleCategory.Insertion);

            if (hasInsertion)
            {
                if (_minimumUnanchoredInsertionLength > 0 || _maskPartialInsertion)
                {
                    var newCigar = new CigarAlignment {
                    };
                    for (int i = 0; i < result.Cigar.Count; i++)
                    {
                        if (result.Cigar[i].Type == 'S')
                        {
                            throw new InvalidDataException(
                                      string.Format(
                                          "Found an unexpected cigar type [{0}] in CIGAR string {1} before re-softclipping", result.Cigar[i].Type, result.Cigar));
                        }
                        else if (i == 0 && Helper.EvaluateInsertionAtReadEnds(result.Cigar[i], firstIndel, _minimumUnanchoredInsertionLength, _maskPartialInsertion))
                        {
                            newCigar.Add(new CigarOp('S', result.Cigar[i].Length));
                        }
                        else if (i == result.Cigar.Count - 1 && Helper.EvaluateInsertionAtReadEnds(result.Cigar[i], lastIndel, _minimumUnanchoredInsertionLength, _maskPartialInsertion))
                        {
                            newCigar.Add(new CigarOp('S', result.Cigar[i].Length));
                        }
                        else
                        {
                            newCigar.Add(result.Cigar[i]);
                        }
                    }

                    newCigar.Compress();
                    result.Cigar = newCigar;
                }
            }


            // Re-append the N-prefix
            var nPrefixPositionMap = Enumerable.Repeat(-1, nPrefixLength);
            var nSuffixPositionMap = Enumerable.Repeat(-1, nSuffixLength);
            var finalPositionMap   = new PositionMap(nPrefixPositionMap.Concat(positionMapWithoutTerminalNs.Map).Concat(nSuffixPositionMap).ToArray());

            var finalCigar = new CigarAlignment {
                new CigarOp('S', (uint)nPrefixLength)
            };

            foreach (CigarOp op in result.Cigar)
            {
                finalCigar.Add(op);
            }
            finalCigar.Add(new CigarOp('S', (uint)nSuffixLength));
            finalCigar.Compress();
            result.Cigar = finalCigar;

            var UpdatedSummary = Extensions.GetAlignmentSummary(result.Position - 1, result.Cigar, refSequence, read.Sequence);

            result.NumIndels                    = UpdatedSummary.NumIndels;
            result.NumNonNMismatches            = UpdatedSummary.NumNonNMismatches;
            result.NumMismatchesIncludeSoftclip = UpdatedSummary.NumMismatchesIncludeSoftclip;
            result.NumNonNSoftclips             = UpdatedSummary.NumNonNSoftclips;
            result.NumSoftclips                 = UpdatedSummary.NumSoftclips;
            result.NumIndelBases                = UpdatedSummary.NumIndelBases;
            result.MismatchesIncludeSoftclip    = UpdatedSummary.MismatchesIncludeSoftclip;
            result.HasHighFrequencyIndel        = indels.Any(t => t.Frequency > HighFrequencyIndelCutoff);


            // In case realignment introduced a bunch of mismatch-Ms where there was previously softclipping, optionally re-mask them.
            if (result != null && _remaskSoftclips)
            {
                var mismatchMap = Helper.GetMismatchMap(read.Sequence, finalPositionMap.Map, refSequence);

                var softclipAdjustedCigar = Helper.SoftclipCigar(result.Cigar, mismatchMap, prefixSoftclip, suffixSoftclip, maskNsOnly: true, prefixNs: Helper.GetCharacterBookendLength(read.Sequence, 'N', false), suffixNs: Helper.GetCharacterBookendLength(read.Sequence, 'N', true));

                // Update position map to account for any softclipping added
                var adjustedPrefixClip = softclipAdjustedCigar.GetPrefixClip();
                for (var i = 0; i < adjustedPrefixClip; i++)
                {
                    finalPositionMap.UpdatePositionAtIndex(i, -2, true);
                }
                var adjustedSuffixClip = softclipAdjustedCigar.GetSuffixClip();
                for (var i = 0; i < adjustedSuffixClip; i++)
                {
                    finalPositionMap.UpdatePositionAtIndex(finalPositionMap.Length - 1 - i, -2, true);
                }

                var editDistance = Helper.GetEditDistance(read.Sequence, finalPositionMap.Map, refSequence);
                if (editDistance == null)
                {
                    // This shouldn't happen at this point - we already have a successful result
                    throw new InvalidDataException("Edit distance is null for :" + read.Name + " with position map " +
                                                   string.Join(",", finalPositionMap) + " and CIGAR " + softclipAdjustedCigar);
                }

                var readHasPosition = finalPositionMap.HasAnyMappableBases();
                if (!readHasPosition)
                {
                    throw new InvalidDataException(string.Format("Read does not have any alignable bases. ({2} --> {0} --> {3}, {1})", freshCigarWithoutTerminalNs, string.Join(",", finalPositionMap), read.CigarData, softclipAdjustedCigar));
                }

                result.Position      = finalPositionMap.FirstMappableBase();
                result.Cigar         = softclipAdjustedCigar;
                result.NumMismatches = editDistance.Value;


                var newSummary = Extensions.GetAlignmentSummary(result.Position - 1, result.Cigar, refSequence,
                                                                read.Sequence);

                result.NumNonNMismatches            = newSummary.NumNonNMismatches;
                result.NumMismatchesIncludeSoftclip = newSummary.NumMismatchesIncludeSoftclip;
                result.NumNonNSoftclips             = newSummary.NumNonNSoftclips;
                result.NumSoftclips              = newSummary.NumSoftclips;
                result.NumIndelBases             = newSummary.NumIndelBases;
                result.MismatchesIncludeSoftclip = newSummary.MismatchesIncludeSoftclip;
                result.HasHighFrequencyIndel     = indels.Any(t => t.Frequency > HighFrequencyIndelCutoff);
                result.NumIndelBases             = UpdatedSummary.NumIndelBases;
            }

            return(result);
        }