/// <summary>
 /// Set this peak based on another best peak for a peak group
 /// </summary>
 public void SetBestPeak(PeptideChromDataPeak peakBest, int indexSet)
 {
     PeakGroup = Data.SetBestPeak(PeakGroup, peakBest, indexSet);
 }
        private List <PeptideChromDataPeakList> PickPeptidePeaks(ICollection <ChromDataSet> dataSets)
        {
            var listPeakSets = new List <PeptideChromDataPeakList>();

            // Only possible to improve upon individual precursor peak picking,
            // if there are more than one precursor
            if (dataSets.Count == 0)
            {
                return(listPeakSets);
            }
            if (dataSets.Count == 1)
            {
                // Create peptide peak group data structures for scoring only
                var dataSet = dataSets.First();
                // Truncate to maximum peak groups, unless this is a summary chromatogram
                // where we want to leave more annotated peaks
                listPeakSets.AddRange(dataSet.PeakSets.Select(p =>
                                                              new PeptideChromDataPeakList(NodePep, FileInfo, new PeptideChromDataPeak(dataSet, p))));
                return(listPeakSets);
            }

            // Merge all the peaks into a single set
            var allPeakGroups = MergePeakGroups(dataSets);

            if (allPeakGroups.Count == 0)
            {
                return(listPeakSets);
            }

            // Create coeluting groups
            while (allPeakGroups.Count > 0)
            {
                var peakNext = allPeakGroups[0];
                allPeakGroups.RemoveAt(0);

                var peakSetNext = FindCoelutingPeptidePeaks(dataSets, peakNext, allPeakGroups);
                listPeakSets.Add(peakSetNext);
            }

            // Reset best picked peaks and reintegrate if necessary
            for (int i = 0; i < listPeakSets.Count; i++)
            {
                var peakSet = listPeakSets[i];
                PeptideChromDataPeak peakBest = null, peakNarrowest = null;
                int minLength = int.MaxValue;

                foreach (var peak in peakSet.OrderedPeaks)
                {
                    peak.SetBestPeak(peakBest, i);

                    // The first peak seen is the best peak
                    if (peakBest == null)
                    {
                        peakBest = peak;
                    }
                    int lenPeak = peak.Length;
                    if (0 < lenPeak && lenPeak < minLength)
                    {
                        peakNarrowest = peak;
                        minLength     = lenPeak;
                    }
                }

                // If any peak trunctation occurred in peaks that should be matching
                if (peakNarrowest != null && !ReferenceEquals(peakBest, peakNarrowest))
                {
                    foreach (var peak in peakSet)
                    {
                        if (peak.PeakGroup == null || peak.Length == peakNarrowest.Length)
                        {
                            continue;
                        }
                        peak.Data.NarrowPeak(peak.PeakGroup, peakNarrowest, i);
                    }
                }
            }

            // Discard peaks not included in a peptide peak list
            foreach (var chromDataSet in dataSets)
            {
                chromDataSet.TruncatePeakSets(listPeakSets.Count);
            }

            return(listPeakSets);
        }
        /// <summary>
        /// Given a high scoring peak precursor peak group, find other lower scoring precursor peak
        /// groups from different precursors for the same peptide, which overlap in time with the
        /// high scoring peak.
        /// </summary>
        /// <param name="dataSets">Chromatogram data sets from which to create peptide peaks</param>
        /// <param name="dataPeakMax">High scoring precursor peak group</param>
        /// <param name="allPeakGroups">List of all lower scoring precursor peak groups for the same peptide</param>
        /// <returns>A list of coeluting precursor peak groups for this peptide</returns>
        private PeptideChromDataPeakList FindCoelutingPeptidePeaks(IEnumerable <ChromDataSet> dataSets,
                                                                   PeptideChromDataPeak dataPeakMax,
                                                                   IList <PeptideChromDataPeak> allPeakGroups)
        {
            TransitionGroupDocNode nodeGroupMax = dataPeakMax.Data.NodeGroup;
            int startMax = dataPeakMax.StartIndex;
            int endMax   = dataPeakMax.EndIndex;
            int timeMax  = dataPeakMax.TimeIndex;

            // Initialize the collection of peaks with this peak
            var listPeaks = new PeptideChromDataPeakList(NodePep, FileInfo, dataPeakMax);

            // Enumerate the precursors for this peptide
            foreach (var chromData in dataSets)
            {
                // Skip the precursor for the max peak itself
                if (ReferenceEquals(chromData, dataPeakMax.Data))
                {
                    continue;
                }

                int    iPeakBest   = -1;
                double bestProduct = 0;

                // Find nearest peak in remaining set that is less than 1/4 length
                // from the primary peak's center
                for (int i = 0, len = allPeakGroups.Count; i < len; i++)
                {
                    var peakGroup = allPeakGroups[i];
                    // Consider only peaks for the current precursor
                    if (!ReferenceEquals(peakGroup.Data, chromData))
                    {
                        continue;
                    }

                    // Exclude peaks that do not overlap with the maximum peak
                    TransitionGroupDocNode nodeGroup = peakGroup.Data.NodeGroup;
                    int startPeak = peakGroup.StartIndex;
                    int endPeak   = peakGroup.EndIndex;
                    if (Math.Min(endPeak, endMax) - Math.Max(startPeak, startMax) <= 0)
                    {
                        continue;
                    }

                    int timeIndex = peakGroup.TimeIndex;
                    if ((nodeGroup.RelativeRT == RelativeRT.Matching && nodeGroupMax.RelativeRT == RelativeRT.Matching) ||
                        // Matching label types (i.e. different charge states of same label type should always match)
                        ReferenceEquals(nodeGroup.TransitionGroup.LabelType, nodeGroupMax.TransitionGroup.LabelType))
                    {
                        // If the peaks are supposed to have the same elution time,
                        // then be more strict about how they overlap
                        if (startMax >= timeIndex || timeIndex >= endMax)
                        {
                            continue;
                        }
                    }
                    else if (nodeGroup.RelativeRT == RelativeRT.Matching && nodeGroupMax.RelativeRT == RelativeRT.Preceding)
                    {
                        // If the maximum is supposed to precede this, look for any
                        // indication that this relationship holds, by testing the peak apex
                        // and the peak center.
                        if (timeIndex < timeMax && (startPeak + endPeak) / 2 < (startMax + endMax) / 2)
                        {
                            continue;
                        }
                    }
                    else if (nodeGroup.RelativeRT == RelativeRT.Preceding && nodeGroupMax.RelativeRT == RelativeRT.Matching)
                    {
                        // If this peak is supposed to precede the maximum, look for any
                        // indication that this relationship holds, by testing the peak apex
                        // and the peak center.
                        if (timeIndex > timeMax && (startPeak + endPeak) / 2 > (startMax + endMax) / 2)
                        {
                            continue;
                        }
                    }

                    // Choose the next best peak that overlaps
                    if (peakGroup.PeakGroup.CombinedScore > bestProduct)
                    {
                        iPeakBest   = i;
                        bestProduct = peakGroup.PeakGroup.CombinedScore;
                    }
                }

                // If no coeluting peaks found, add an empty peak group
                if (iPeakBest == -1)
                {
                    listPeaks.Add(new PeptideChromDataPeak(chromData, null));
                }
                // Otherwise, add the found coeluting peak group, and remove it from the full list
                else
                {
                    listPeaks.Add(new PeptideChromDataPeak(chromData, allPeakGroups[iPeakBest].PeakGroup));
                    allPeakGroups.RemoveAt(iPeakBest);
                }
            }
            return(listPeaks);
        }
 /// <summary>
 /// Returns true if the apex for the given peak is contained in this peak
 /// </summary>
 public bool IsContained(PeptideChromDataPeak peak)
 {
     return(StartIndex <= peak.TimeIndex && peak.TimeIndex <= EndIndex);
 }