Пример #1
0
        private int findPointWithTolerance(pwiz.MSGraph.MSPointList points, double mz, MZTolerance tolerance, bool scaled = false)
        {
            double lowestMatchMz = mz - tolerance;
            double highestMatchMz = mz + tolerance;

            var pointPairList = scaled ? points.ScaledList : points.FullList;
            int index = scaled ? points.ScaledLowerBound(mz) : points.FullLowerBound(mz);

            // if index is below the tolerance threshold, bump it to the next one or set to -1 if doing so would exceed the list size
            if (index > -1 && pointPairList[index].X < lowestMatchMz)
                index = index + 1 == pointPairList.Count ? -1 : index + 1;

            if (index == -1 || pointPairList[index].X > highestMatchMz)
                return -1;

            return index;
        }
Пример #2
0
 ///<summary>
 /// Takes a left mz value and right mz value and returns true if both are found in the spectrum.
 /// TODO: make mass tolerance user-configurable (currently hard-coded to 0.5 m/z)
 ///</summary>
 private bool aminoAcidHasFragmentEvidence( pwiz.MSGraph.MSPointList points, double leftMZ, double rightMZ )
 {
     // Search index
     int index = -1;
     bool leftMZFound = false;
     bool righMZFound = false;
     if( points != null )
     {
         // Find the left mz value using a mass tolerance of 0.5 da.
         index = points.FullLowerBound( leftMZ - 0.5 );
         if (index != -1 && points.FullList[index].X <= (leftMZ + 0.5))
             leftMZFound = true;
         // Find the right mz value using a mass tolerance of 0.5 da.
         index = points.FullLowerBound(rightMZ - 0.5);
         if (index != -1 && points.FullList[index].X <= (rightMZ + 0.5))
             righMZFound = true;
     }
     // Return if both are found
     return (leftMZFound & righMZFound);
 }
Пример #3
0
        public override void Update( GraphItem item, pwiz.MSGraph.MSPointList points, GraphObjList annotations )
        {
            double basePeakIntensity = 0;
            double cutoff = 0;
            foreach (var pointlist in points)
            {
                if (basePeakIntensity < pointlist.Y)
                    basePeakIntensity = pointlist.Y;
            }
            cutoff = basePeakIntensity * basePeakPercentage * 0.01;

            if( !Enabled )
                return;

            if( !( item is MassSpectrum ) )
                return; // throw exception?

            GraphObjList list = annotations;
            Peptide peptide;

            try
            {
                peptide = new Peptide( sequence,
                    pwiz.CLI.proteome.ModificationParsing.ModificationParsing_Auto,
                    pwiz.CLI.proteome.ModificationDelimiter.ModificationDelimiter_Brackets );
            } catch( Exception )
            {
                return;
            }

            //if (annotationPanels.peptideInfoGridView.InvokeRequired)
            //{
            //    annotationPanels.peptideInfoGridView.BeginInvoke(new MethodInvoker(() => Update(item, points, annotations)));
            //    //return;
            //}

            var spectrum = ( item as MassSpectrum ).Element;

            if (spectrum.precursors.Count > 0 && ionSeriesIsEnabled(IonSeries.Auto))
            {
                bool cid = (item as MassSpectrum).Element.precursors[0].activation.hasCVParam(CVID.MS_CID);
                bool etd = (item as MassSpectrum).Element.precursors[0].activation.hasCVParam(CVID.MS_ETD);
                ionSeries |= cid ? IonSeries.b | IonSeries.y : IonSeries.Off;
                ionSeries |= etd ? IonSeries.c | IonSeries.zRadical : IonSeries.Off;
            }

            string unmodifiedSequence = peptide.sequence;
            int sequenceLength = unmodifiedSequence.Length;
            Fragmentation fragmentation = peptide.fragmentation( fragmentMassType == 0 ? true : false, true );

            //test neutral
            ModificationMap modifications = peptide.modifications();
            ///
            #region adding labels for series a/b/c/x/y/z:::::::::naive fragmentation modeling

            if (!showBasophileModel)
            {
                for (int i = 1; i < sequenceLength; ++i)
                {
                    //test neutral loss
                    //note here the Cseq is slightly different than those in addFragmentSummary
                    string Nseq = peptide.sequence.Substring(0, i);
                    string Cseq = peptide.sequence.Substring(sequenceLength - i, i);
                    string NTempSeq = peptide.sequence.Substring(0, sequenceLength - i);
                    char[] Nseqchars = Nseq.ToCharArray();
                    char[] NTempSeqchars = NTempSeq.ToCharArray();
                    char[] seqchars = peptide.sequence.ToCharArray();
                    int Nphosmodi = 0;
                    int NTempPhosmodi = 0;
                    int Cphosmodi = 0;
                    int phosmodi = 0;
                    for (int k = 0; k < i; k++)
                    {
                        if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y'))
                        {
                            Nphosmodi++;
                        }
                    }
                    for (int k = 0; k < sequenceLength - i; k++)
                    {
                        if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y'))
                        {
                            NTempPhosmodi++;
                        }
                    }
                    for (int k = 0; k < sequenceLength; k++)
                    {
                        if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y'))
                        {
                            phosmodi++;
                        }
                    }
                    Cphosmodi = phosmodi - NTempPhosmodi;

                    for (int charge = min; charge <= max; ++charge)
                    {
                        if (ionSeriesIsEnabled(IonSeries.a)) addFragment(list, points, "a", i, charge, fragmentation.a(i, charge));
                        if (ionSeriesIsEnabled(IonSeries.b)) addFragment(list, points, "b", i, charge, fragmentation.b(i, charge));
                        if (ionSeriesIsEnabled(IonSeries.y)) addFragment(list, points, "y", i, charge, fragmentation.y(i, charge));
                        if (ionSeriesIsEnabled(IonSeries.z)) addFragment(list, points, "z", i, charge, fragmentation.z(i, charge));
                        if (ionSeriesIsEnabled(IonSeries.zRadical)) addFragment(list, points, "z*", i, charge, fragmentation.zRadical(i, charge));

                        if (i < sequenceLength)
                        {
                            if (ionSeriesIsEnabled(IonSeries.c)) addFragment(list, points, "c", i, charge, fragmentation.c(i, charge));
                            if (ionSeriesIsEnabled(IonSeries.x)) addFragment(list, points, "x", i, charge, fragmentation.x(i, charge));
                        }

                        //test neutral loss
                        #region water loss
                        if (waterLoss == true)
                        {
                            if (Nseq.Contains("S") || Nseq.Contains("T") || Nseq.Contains("E") || Nseq.Contains("D"))
                            {
                                if (ionSeriesIsEnabled(IonSeries.a)) addFragment(list, points, "a-water", i, charge, fragmentation.a(i, charge) - WATERMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.b)) addFragment(list, points, "b-water", i, charge, fragmentation.b(i, charge) - WATERMONOMASS / charge);
                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.c)) addFragment(list, points, "c-water", i, charge, fragmentation.c(i, charge) - WATERMONOMASS / charge);
                                }
                            }

                            if (Cseq.Contains("S") || Cseq.Contains("T") || Cseq.Contains("E") || Cseq.Contains("D"))
                            {
                                if (ionSeriesIsEnabled(IonSeries.y)) addFragment(list, points, "y-water", i, charge, fragmentation.y(i, charge) - WATERMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.z)) addFragment(list, points, "z-water", i, charge, fragmentation.z(i, charge) - WATERMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.zRadical)) addFragment(list, points, "z*-water", i, charge, fragmentation.zRadical(i, charge) - WATERMONOMASS / charge);

                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.x)) addFragment(list, points, "x-water", i, charge, fragmentation.x(i, charge) - WATERMONOMASS / charge);
                                }
                            }
                        }
                        #endregion

                        //test neutral loss
                        #region ammonium loss
                        if (ammoniumLoss == true)
                        {
                            if (Nseq.Contains("R") || Nseq.Contains("K") || Nseq.Contains("Q") || Nseq.Contains("N"))
                            {
                                if (ionSeriesIsEnabled(IonSeries.a)) addFragment(list, points, "a-ammonium", i, charge, fragmentation.a(i, charge) - AMMONIUMMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.b)) addFragment(list, points, "b-ammonium", i, charge, fragmentation.b(i, charge) - AMMONIUMMONOMASS / charge);
                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.c)) addFragment(list, points, "c-ammonium", i, charge, fragmentation.c(i, charge) - AMMONIUMMONOMASS / charge);
                                }
                            }

                            if (Cseq.Contains("R") || Cseq.Contains("K") || Cseq.Contains("Q") || Cseq.Contains("N"))
                            {
                                if (ionSeriesIsEnabled(IonSeries.y)) addFragment(list, points, "y-ammonium", i, charge, fragmentation.y(i, charge) - AMMONIUMMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.z)) addFragment(list, points, "z-ammonium", i, charge, fragmentation.z(i, charge) - AMMONIUMMONOMASS / charge);
                                if (ionSeriesIsEnabled(IonSeries.zRadical)) addFragment(list, points, "z*-ammonium", i, charge, fragmentation.zRadical(i, charge) - AMMONIUMMONOMASS / charge);

                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.x)) addFragment(list, points, "x-ammonium", i, charge, fragmentation.x(i, charge) - AMMONIUMMONOMASS / charge);
                                }
                            }
                        }
                        #endregion

                        //test neutral loss
                        #region phosphate loss
                        if (phosphateLoss == true)
                        {
                            int minNPhosphate = Math.Min(Nphosmodi, numPhosphate);
                            if (minNPhosphate > 0)
                            {
                                if (ionSeriesIsEnabled(IonSeries.a))
                                {
                                    for (int k = 1; k <= minNPhosphate; k++)
                                    {
                                        addFragment(list, points, "a-" + k + "phos", i, charge, fragmentation.a(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                    }
                                }
                                if (ionSeriesIsEnabled(IonSeries.b))
                                {
                                    for (int k = 1; k <= minNPhosphate; k++)
                                    {
                                        addFragment(list, points, "b-" + k + "phos", i, charge, fragmentation.b(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                    }
                                }
                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.c))
                                    {
                                        for (int k = 1; k <= minNPhosphate; k++)
                                        {
                                            addFragment(list, points, "c-" + k + "phos", i, charge, fragmentation.c(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                        }
                                    }
                                }

                            }

                            int minCPhosphate = Math.Min(Cphosmodi, numPhosphate);
                            if (minCPhosphate > 0)
                            {

                                if (ionSeriesIsEnabled(IonSeries.y))
                                {
                                    for (int k = 1; k <= minCPhosphate; k++)
                                    {
                                        addFragment(list, points, "y-" + k + "phos", i, charge, fragmentation.y(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                    }
                                }
                                if (ionSeriesIsEnabled(IonSeries.z))
                                {
                                    for (int k = 1; k <= minCPhosphate; k++)
                                        addFragment(list, points, "z-" + k + "phos", i, charge, fragmentation.z(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                }
                                if (ionSeriesIsEnabled(IonSeries.zRadical))
                                {
                                    for (int k = 1; k <= minCPhosphate; k++)
                                        addFragment(list, points, "z*-" + k + "phos", i, charge, fragmentation.zRadical(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                }

                                if (i < sequenceLength)
                                {
                                    if (ionSeriesIsEnabled(IonSeries.x))
                                    {
                                        for (int k = 1; k <= minCPhosphate; k++)
                                            addFragment(list, points, "x-" + k + "phos", i, charge, fragmentation.x(i, charge) - k * PHOSPHATEMONOMASS / charge);
                                    }
                                }
                            }

                        }
                        #endregion

                    }
                }
            }

            //for basophile fragmentation modeling
            else if (showBasophileModel)
            {
                //clear the panel
                //annotationPanels.bCheckBox.Checked = false;
                //annotationPanels.yCheckBox.Checked = false;
                String peptideSeq = peptide.sequence;
                int seqLength = peptideSeq.Length;
                char[] seq = peptideSeq.ToCharArray();
                int totalR = 0, totalK = 0, totalH = 0;

                for (int i = 0; i < seqLength; ++i)
                {
                    if (seq[i] == 'R')
                        ++totalR;
                    else if (seq[i] == 'K')
                        ++totalK;
                    else if (seq[i] == 'H')
                        ++totalH;
                }

                for (int c = 1; c < seqLength; c++)
                {
                    int totalNR = 0, totalNK = 0, totalNH = 0, totalNL = 0;
                    int totalCR = 0, totalCK = 0, totalCH = 0, totalCL = 0;
                    for (int i = 0; i < c; ++i)
                    {
                        if (seq[i] == 'R') { ++totalNR; }
                        else if (seq[i] == 'K') { ++totalNK; }
                        else if (seq[i] == 'H') { ++totalNH; }
                    }
                    totalNL = c;
                    totalCR = totalR - totalNR;
                    totalCK = totalK - totalNK;
                    totalCH = totalH - totalNH;
                    totalCL = seqLength - totalNL;

                    double y1_logit = 0.1098112 * totalNR + 0.2085831 * totalNK + 0.1512109 * totalNH + 0.0460839 * totalNL
                                    - 0.3872417 * totalCR - 0.3684911 * totalCK - 0.1634741 * totalCH - 0.1693931 * totalCL + 1.2632997;
                    double y2_logit = -0.6345364 * totalNR - 0.3365917 * totalNK - 0.4577882 * totalNH - 0.1492703 * totalNL
                                     + 0.7738133 * totalCR + 0.6036758 * totalCK + 0.5942542 * totalCH + 0.0701467 * totalCL + 0.0806280;
                    double b1_logit = 0.0801432 * totalNR - 0.1088081 * totalNK - 0.1338220 * totalNH - 0.1413059 * totalNL
                                    - 0.3157957 * totalCR - 0.2708274 * totalCK - 0.3703136 * totalCH + 0.0157418 * totalCL + 1.2124699;
                    double b2_logit = 0.8606449 * totalNR + 0.2763119 * totalNK + 0.4969152 * totalNH + 0.0685712 * totalNL
                                    - 1.3346995 * totalCR - 1.0977316 * totalCK - 1.0973677 * totalCH - 0.2028884 * totalCL + 1.9355980;

                    if (ionSeriesIsEnabled(IonSeries.b))
                    {
                        if (b1_logit > -0.5) addFragment(list, points, "b", c, 1, fragmentation.b(c, 1));
                        if (b2_logit > 0)    addFragment(list, points, "b", c, 2, fragmentation.b(c, 2));
                    }
                    if (ionSeriesIsEnabled(IonSeries.y))
                    {
                        if (y1_logit > -0.5) addFragment(list, points, "y", seqLength - c, 1, fragmentation.y(seqLength - c, 1));
                        if (y2_logit > -0.5) addFragment(list, points, "y", seqLength - c, 2, fragmentation.y(seqLength - c, 2));
                    }
                                            //if (b1_logit > -0.5)
                                            //    if (ionSeriesIsEnabled(IonSeries.b))
                                            //        addFragment(list, points, "b", c, 1, fragmentation.b(c, 1));
                                            //if (b2_logit > 0)
                                            //    if (ionSeriesIsEnabled(IonSeries.b))
                                            //        addFragment(list, points, "b", c, 2, fragmentation.b(c, 2));
                                            //if (y1_logit > -0.5)
                                            //    if (ionSeriesIsEnabled(IonSeries.y))
                                            //        addFragment(list, points, "y", seqLength - c, 1, fragmentation.y(seqLength - c, 1));
                                            //if (y2_logit > -0.5)
                                            //    if (ionSeriesIsEnabled(IonSeries.y))
                                            //        addFragment(list, points, "y", seqLength - c, 2, fragmentation.y(seqLength - c, 2));

                }
            }

            #endregion

            if ( showLadders || showFragmentationSummary)
            {
                //test neutral loss
                //string topSeries = ionSeriesIsEnabled(IonSeries.a) ? "a" : ionSeriesIsEnabled(IonSeries.b) ? "b" : ionSeriesIsEnabled(IonSeries.c) ? "c" : "";
                //string bottomSeries = ionSeriesIsEnabled(IonSeries.x) ? "x" : ionSeriesIsEnabled(IonSeries.y) ? "y" : ionSeriesIsEnabled(IonSeries.z) ? "z" : ionSeriesIsEnabled(IonSeries.zRadical) ? "z*" : "";
                //if (showLadders)
                //    addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                //if (showFragmentationSummary)
                //    addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                string topSeries = "";
                string bottomSeries = "";

                if (ionSeriesIsEnabled(IonSeries.a))
                {
                    topSeries = "a";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.b))
                {
                    topSeries = "b";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.c))
                {
                    topSeries = "c";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.x))
                {
                    bottomSeries = "x";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.y))
                {
                    bottomSeries = "y";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.z))
                {
                    bottomSeries = "z";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
                if (ionSeriesIsEnabled(IonSeries.zRadical))
                {
                    bottomSeries = "z*";
                    if (showLadders)
                        addIonSeries(list, points, peptide, fragmentation, topSeries, bottomSeries);
                    if (showFragmentationSummary)
                        addFragmentationSummary(list, points, peptide, fragmentation, topSeries, bottomSeries);
                }
            }

            annotationPanels.peptideInfoGridView.Rows.Clear();

            if( spectrum.precursors.Count > 0 &&
                spectrum.precursors[0].selectedIons.Count > 0 &&
                spectrum.precursors[0].selectedIons[0].hasCVParam( CVID.MS_selected_ion_m_z ) &&
                spectrum.precursors[0].selectedIons[0].hasCVParam( CVID.MS_charge_state ) )
            {
                double selectedMz = (double) spectrum.precursors[0].selectedIons[0].cvParam( CVID.MS_selected_ion_m_z ).value;
                int chargeState = (int) spectrum.precursors[0].selectedIons[0].cvParam( CVID.MS_charge_state ).value;
                double calculatedMass = ( precursorMassType == 0 ? peptide.monoisotopicMass( chargeState ) : peptide.molecularWeight( chargeState ) ) * chargeState;
                double observedMass = selectedMz * chargeState;
                annotationPanels.peptideInfoGridView.Rows.Add( "Calculated mass:", calculatedMass, "Mass error (daltons):", observedMass - calculatedMass );
                annotationPanels.peptideInfoGridView.Rows.Add( "Observed mass:", observedMass, "Mass error (ppm):", ( ( observedMass - calculatedMass ) / calculatedMass ) * 1e6 );
            } else
                annotationPanels.peptideInfoGridView.Rows.Add( "Calculated neutral mass:", precursorMassType == 0 ? peptide.monoisotopicMass() : peptide.molecularWeight() );

            annotationPanels.peptideInfoGridView.Columns[1].DefaultCellStyle.Format = "F4";
            foreach( DataGridViewRow row in annotationPanels.peptideInfoGridView.Rows )
                row.Height = row.InheritedStyle.Font.Height + 2;

            // TODO: fragmentInfoGridView is slow: make it faster, optional, or both!

            annotationPanels.fragmentInfoGridView.SuspendLayout();

            if( ionSeries > IonSeries.Auto )
            {
                if( annotationPanels.fragmentInfoGridView.Columns.Count == 0 )
                {
                    if (ionSeriesIsEnabled(IonSeries.a))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "a" + charge.ToString(),
                                "a" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                    if (ionSeriesIsEnabled(IonSeries.b))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "b" + charge.ToString(),
                                "b" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                    if (ionSeriesIsEnabled(IonSeries.c))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "c" + charge.ToString(),
                                "c" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));

                    annotationPanels.fragmentInfoGridView.Columns.Add("N", "#");
                    annotationPanels.fragmentInfoGridView.Columns.Add("Sequence", "seq");
                    annotationPanels.fragmentInfoGridView.Columns.Add("C", "#");

                    if (ionSeriesIsEnabled(IonSeries.x))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "x" + charge.ToString(),
                                "x" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                    if (ionSeriesIsEnabled(IonSeries.y))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "y" + charge.ToString(),
                                "y" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                    if (ionSeriesIsEnabled(IonSeries.z))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "z" + charge.ToString(),
                                "z" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                    if (ionSeriesIsEnabled(IonSeries.zRadical))
                        for (int charge = min; charge <= max; ++charge)
                            annotationPanels.fragmentInfoGridView.Columns.Add(
                                "z*" + charge.ToString(),
                                "z*" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));

                    foreach( DataGridViewColumn column in annotationPanels.fragmentInfoGridView.Columns )
                    {
                        column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                        if( column.Name != "N" && column.Name != "C" && column.Name != "Sequence" )
                            column.DefaultCellStyle.Format = "F3";
                    }
                }

                while( annotationPanels.fragmentInfoGridView.Rows.Count > sequenceLength )
                    annotationPanels.fragmentInfoGridView.Rows.RemoveAt( annotationPanels.fragmentInfoGridView.Rows.Count - 1 );
                if( sequenceLength - annotationPanels.fragmentInfoGridView.Rows.Count > 0 )
                    annotationPanels.fragmentInfoGridView.Rows.Add( sequenceLength - annotationPanels.fragmentInfoGridView.Rows.Count );

                for( int i = 1; i <= sequenceLength; ++i )
                {
                    int cTerminalLength = sequenceLength - i + 1;
                    var row = annotationPanels.fragmentInfoGridView.Rows[i - 1];
                    var values = new List<object>(10);
                    //var row = annotationPanels.fragmentInfoGridView.Rows.Add()];

                    if (ionSeriesIsEnabled(IonSeries.a))
                        for (int charge = min; charge <= max; ++charge)
                            values.Add(fragmentation.a(i, charge));
                    if (ionSeriesIsEnabled(IonSeries.b))
                        for (int charge = min; charge <= max; ++charge)
                            values.Add(fragmentation.b(i, charge));
                    if (ionSeriesIsEnabled(IonSeries.c))
                        for (int charge = min; charge <= max; ++charge)
                            if (i < sequenceLength)
                                values.Add(fragmentation.c(i, charge));
                            else
                                values.Add("");

                    values.Add(i);
                    values.Add(unmodifiedSequence[i - 1]);
                    values.Add(cTerminalLength);

                    if (ionSeriesIsEnabled(IonSeries.x))
                        for (int charge = min; charge <= max; ++charge)
                            if (i > 1)
                                values.Add(fragmentation.x(cTerminalLength, charge));
                            else
                                values.Add("");
                    if (ionSeriesIsEnabled(IonSeries.y))
                        for (int charge = min; charge <= max; ++charge)
                            values.Add(fragmentation.y(cTerminalLength, charge));
                    if (ionSeriesIsEnabled(IonSeries.z))
                        for (int charge = min; charge <= max; ++charge)
                            values.Add(fragmentation.z(cTerminalLength, charge));
                    if (ionSeriesIsEnabled(IonSeries.zRadical))
                        for (int charge = min; charge <= max; ++charge)
                            values.Add(fragmentation.zRadical(cTerminalLength, charge));
                    row.SetValues(values.ToArray());
                }

                //add my code in between
                //the purpose is to switch the fragmentInfoGridView table into a html
                //to solve the bug that the table can be copied, but the bold font information can not be copied
                //basically, a stringbuilder object is created and going to copy values, formats from gridview, and then output
                //currently the html output is only stored in local, and I am trying to adapt it into a applet-like viewer.

                //first a stringbuilder is created
                StringBuilder sb_original = new StringBuilder();
                //Setting HTML and table tags
                sb_original.Append("<html>");
                sb_original.Append("<head>");
                sb_original.Append("<title>fragmentGridView2HTML</title>");
                sb_original.Append("</head>");
                sb_original.Append("<body>");
                sb_original.Append("<br>");
                sb_original.AppendLine("<" + "table border='2' cellpadding='1' cellspacing='1'>");
                sb_original.AppendLine("<tr>");
                //setting table headers
                //make them bold
                for (int i = 0; i < annotationPanels.fragmentInfoGridView.Columns.Count; i++)
                {
                    sb_original.AppendLine("<th>" + annotationPanels.fragmentInfoGridView.Columns[i].HeaderText + "</th>");
                }
                sb_original.AppendLine("</tr>");

                //starting copying cells to html
                foreach( DataGridViewRow row in annotationPanels.fragmentInfoGridView.Rows )
                {
                    sb_original.AppendLine("<tr>");
                    row.Height = row.InheritedStyle.Font.Height + 2;

                    foreach( DataGridViewCell cell in row.Cells )
                    {
                        if (!(cell.Value is double))
                        {
                            //note: added two line here
                            sb_original.AppendLine("<td>" + cell.FormattedValue + "</td>");
                            continue;
                        }

                        double mz = (double) cell.Value;

                        int index = -1;
                        if( points != null )
                            index = points.FullLowerBound(mz - 0.5);

                        if (index == -1 || points.FullList[index].X > (mz + 0.5))
                        {
                            //note: added two line here
                            //first is to pass value to sb;
                            //second is to change the cell fontstyle back to regular, if previouly bold
                            sb_original.AppendLine("<td>" + cell.FormattedValue + "</td>");
                            cell.Style.Font = new Font(annotationPanels.fragmentInfoGridView.Font, FontStyle.Regular);
                            continue;
                        }

                        cell.Style.Font = new Font(annotationPanels.fragmentInfoGridView.Font, FontStyle.Bold);
                        //note: added one line here
                        sb_original.AppendLine("<td><b>" + cell.FormattedValue + "</b></td>");
                    }
                }

                sb_original.AppendLine("</tr>");
                sb_original.AppendLine("</body>");
                sb_original.AppendLine("</head>");
                sb_original.AppendLine("</html>");
                //for storation of stringbuilder into local file
                //test only

                string file_original = "C:\\Temp\\originalTable.html";
                Directory.CreateDirectory(Path.GetDirectoryName(file_original));
                TextWriter tw_original = new StreamWriter(file_original);
                tw_original.WriteLine(sb_original.ToString());
                tw_original.Flush();
                tw_original.Close();

                /////////////////////////////////////////////////////////
                /////////////////////////////////////////////////////////
                //test neutral loss
                #region Neutral Loss
                StringBuilder sb_neutral = new StringBuilder();

                if (waterLoss == false && ammoniumLoss == false && phosphateLoss == false)
                {
                    sb_neutral = sb_original;
                }
                else //if any of the neutral loss is clicked
                {
                    #region if any of the neutral loss is clicked
                    DataGridView neutralLossDataGridView = new DataGridView();

                    ///
                    #region add first columns part

                    if (ionSeriesIsEnabled(IonSeries.a))
                        for (int charge = min; charge <= max; ++charge)
                        {
                            neutralLossDataGridView.Columns.Add(
                                "a" + charge.ToString(),
                                "a" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                            if (waterLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "a" + charge.ToString() + "waterLoss",
                                    "a" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                            if (ammoniumLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "a" + charge.ToString() + "ammoniumLoss",
                                    "a" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                            if (phosphateLoss == true)
                            {
                                for (int k = 1; k<= numPhosphate; k++)
                                {
                                    if (k == 1)
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "a" + charge.ToString() + "phosphateLoss",
                                            "a" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                    }
                                    else
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "a" + charge.ToString() + "phosphateLoss",
                                            "a" + (charge > 1 ? "(+" + charge.ToString() + ")-"+k+"PHO" : "-"+k+"PHO"));
                                    }
                                }
                            }

                        }

                    if (ionSeriesIsEnabled(IonSeries.b))
                        for (int charge = min; charge <= max; ++charge)
                        {
                            neutralLossDataGridView.Columns.Add(
                                "b" + charge.ToString(),
                                "b" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                            if (waterLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "b" + charge.ToString() + "waterLoss",
                                    "b" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                            if (ammoniumLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "b" + charge.ToString() + "ammoniumLoss",
                                    "b" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                            if (phosphateLoss == true)
                            {
                                for (int k = 1; k<= numPhosphate; k++)
                                {
                                    if (k == 1)
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "b" + charge.ToString() + "phosphateLoss",
                                            "b" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                    }
                                    else
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "b" + charge.ToString() + "phosphateLoss",
                                            "b" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                    }
                                }
                            }
                        }

                    if (ionSeriesIsEnabled(IonSeries.c))
                        for (int charge = min; charge <= max; ++charge)
                        {
                            neutralLossDataGridView.Columns.Add(
                                "c" + charge.ToString(),
                                "c" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                            if (waterLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "c" + charge.ToString() + "waterLoss",
                                    "c" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                            if (ammoniumLoss == true)
                                neutralLossDataGridView.Columns.Add(
                                    "c" + charge.ToString() + "ammoniumLoss",
                                    "c" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                            if (phosphateLoss == true)
                            {
                                for (int k = 1; k<= numPhosphate; k++)
                                {
                                    if (k == 1)
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "c" + charge.ToString() + "phosphateLoss",
                                            "c" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                    }
                                    else
                                    {
                                        neutralLossDataGridView.Columns.Add(
                                            "c" + charge.ToString() + "phosphateLoss",
                                            "c" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                    }
                                }
                            }

                        }
                    #endregion

                    neutralLossDataGridView.Columns.Add("N", "#");
                    neutralLossDataGridView.Columns.Add("Sequence", "seq");
                    neutralLossDataGridView.Columns.Add("C", "#");
                    ///
                    #region add second columns part
                        if (ionSeriesIsEnabled(IonSeries.x))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                neutralLossDataGridView.Columns.Add(
                                   "x" + charge.ToString(),
                                   "x" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                                if (waterLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "x" + charge.ToString() + "waterLoss",
                                        "x" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                                if (ammoniumLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "x" + charge.ToString() + "ammoniumLoss",
                                        "x" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k<= numPhosphate; k++)
                                    {
                                        if (k == 1)
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "x" + charge.ToString() + "phosphateLoss",
                                                "x" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                        }
                                        else
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "x" + charge.ToString() + "phosphateLoss",
                                                "x" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                        }
                                    }
                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.y))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                neutralLossDataGridView.Columns.Add(
                                    "y" + charge.ToString(),
                                    "y" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                                if (waterLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "y" + charge.ToString() + "waterLoss",
                                        "y" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                                if (ammoniumLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "y" + charge.ToString() + "ammoniumLoss",
                                        "y" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k<= numPhosphate; k++)
                                    {
                                        if (k == 1)
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "y" + charge.ToString() + "phosphateLoss",
                                                "y" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                        }
                                        else
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "y" + charge.ToString() + "phosphateLoss",
                                                "y" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                        }
                                    }
                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.z))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                neutralLossDataGridView.Columns.Add(
                                    "z" + charge.ToString(),
                                    "z" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                                if (waterLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "z" + charge.ToString() + "waterLoss",
                                        "z" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                                if (ammoniumLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "z" + charge.ToString() + "ammoniumLoss",
                                        "z" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k<= numPhosphate; k++)
                                    {
                                        if (k == 1)
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "z" + charge.ToString() + "phosphateLoss",
                                                "z" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                        }
                                        else
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "z" + charge.ToString() + "phosphateLoss",
                                                "z" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                        }
                                    }
                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.zRadical))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                neutralLossDataGridView.Columns.Add(
                                   "z*" + charge.ToString(),
                                   "z*" + (charge > 1 ? "(+" + charge.ToString() + ")" : ""));
                                if (waterLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "z*" + charge.ToString() + "waterLoss",
                                        "z*" + (charge > 1 ? "(+" + charge.ToString() + ")-H2O" : "-H2O"));
                                if (ammoniumLoss == true)
                                    neutralLossDataGridView.Columns.Add(
                                        "z*" + charge.ToString() + "ammoniumLoss",
                                        "z*" + (charge > 1 ? "(+" + charge.ToString() + ")-NH3" : "-NH3"));
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k<= numPhosphate; k++)
                                    {
                                        if (k == 1)
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "z*" + charge.ToString() + "phosphateLoss",
                                                "z*" + (charge > 1 ? "(+" + charge.ToString() + ")-PHO" : "-PHO"));
                                        }
                                        else
                                        {
                                            neutralLossDataGridView.Columns.Add(
                                                "z*" + charge.ToString() + "phosphateLoss",
                                                "z*" + (charge > 1 ? "(+" + charge.ToString() + ")-" + k + "PHO" : "-" + k + "PHO"));
                                        }
                                    }
                                }
                            }
                        #endregion

                    while (neutralLossDataGridView.Rows.Count > sequenceLength)
                        neutralLossDataGridView.Rows.RemoveAt(neutralLossDataGridView.Rows.Count - 1);
                    if (sequenceLength - neutralLossDataGridView.Rows.Count > 0)
                        neutralLossDataGridView.Rows.Add(sequenceLength - neutralLossDataGridView.Rows.Count);

                    char[] aminoAcids = peptide.sequence.ToCharArray();
                    for (int i = 1; i <= sequenceLength; ++i)
                    {
                        int Nphosmodi = 0;
                        int Cphosmodi = 0;

                        int cTerminalLength = sequenceLength - i + 1;
                        var row = neutralLossDataGridView.Rows[i - 1];
                        var values = new List<object>();

                        //define the amino acides that are capable of losing water
                        //AA = S,T,E,D
                        bool nSTED = false;
                        bool cSTED = false;
                        bool nRKQN = false;
                        bool cRKQN = false;

                        for (int index = 0; index < i; index++)
                        {
                            if (aminoAcids[index] == 'S' || aminoAcids[index] == 'T' || aminoAcids[index] == 'E' || aminoAcids[index] == 'D')
                                nSTED = true;
                            if (aminoAcids[index] == 'R' || aminoAcids[index] == 'K' || aminoAcids[index] == 'Q' || aminoAcids[index] == 'N')
                                nRKQN = true;
                            if (Math.Round(modifications[index].monoisotopicDeltaMass()) == 80 && (aminoAcids[index] == 'S' || aminoAcids[index] == 'T' || aminoAcids[index] == 'Y'))
                                Nphosmodi++;
                        }

                        //here is more tricky. since the display is
                        //b1    -----     y(seq-1+1)
                        //b2    -----     y(seq-2+1)
                        for (int index = sequenceLength - 1; index >= i - 1; index--)
                        {
                            if (aminoAcids[index] == 'S' || aminoAcids[index] == 'T' || aminoAcids[index] == 'E' || aminoAcids[index] == 'D')
                                cSTED = true;
                            if (aminoAcids[index] == 'R' || aminoAcids[index] == 'K' || aminoAcids[index] == 'Q' || aminoAcids[index] == 'N')
                                cRKQN = true;
                            if (Math.Round(modifications[index].monoisotopicDeltaMass()) == 80 && (aminoAcids[index] == 'S' || aminoAcids[index] == 'T' || aminoAcids[index] == 'Y'))
                                Cphosmodi++;

                        }

                        int minNPhosphate = Math.Min(numPhosphate, Nphosmodi);
                        int minCPhosphate = Math.Min(numPhosphate, Cphosmodi);
                        if (ionSeriesIsEnabled(IonSeries.a))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                values.Add(Math.Round(fragmentation.a(i, charge), 3));
                                if (waterLoss == true)
                                {
                                    if (nSTED) values.Add(Math.Round(fragmentation.a(i, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (nRKQN) values.Add(Math.Round(fragmentation.a(i, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k <= numPhosphate; k++)
                                    {
                                        if (k <= minNPhosphate)
                                        {
                                            values.Add(Math.Round(fragmentation.a(i, charge) - k*PHOSPHATEMONOMASS / charge, 3));
                                        }
                                        else
                                        {
                                            values.Add("-");
                                        }

                                    }
                                }

                            }

                        if (ionSeriesIsEnabled(IonSeries.b))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                values.Add(Math.Round(fragmentation.b(i, charge), 3));
                                if (waterLoss == true)
                                {
                                    if (nSTED) values.Add(Math.Round(fragmentation.b(i, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (nRKQN) values.Add(Math.Round(fragmentation.b(i, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k <= numPhosphate; k++)
                                    {
                                        if (k <= minNPhosphate)
                                        {
                                            values.Add(Math.Round(fragmentation.b(i, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                        }
                                        else
                                        {
                                            values.Add("-");
                                        }
                                    }
                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.c))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                if (i < sequenceLength)
                                    values.Add(Math.Round(fragmentation.c(i, charge), 3));
                                else
                                    values.Add("-");
                                if (waterLoss == true)
                                {
                                    if (nSTED && i < sequenceLength)
                                        values.Add(Math.Round(fragmentation.c(i, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (nRKQN && i < sequenceLength)
                                        values.Add(Math.Round(fragmentation.c(i, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    if (i < sequenceLength)
                                    {
                                        for (int k = 1; k <= numPhosphate; k++)
                                        {
                                            if (k <= minNPhosphate)
                                            {
                                                values.Add(Math.Round(fragmentation.c(i, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                            }
                                            else
                                            {
                                                values.Add("-");
                                            }
                                        }
                                    }
                                    else values.Add("-");

                                }
                            }

                        values.Add(i);
                        values.Add(unmodifiedSequence[i - 1]);
                        values.Add(cTerminalLength);

                        if (ionSeriesIsEnabled(IonSeries.x))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                if (i > 1)
                                    values.Add(Math.Round(fragmentation.x(sequenceLength - i + 1, charge), 3));
                                else
                                    values.Add("-");
                                if (waterLoss == true)
                                {
                                    if (cSTED && i > 1)
                                        values.Add(Math.Round(fragmentation.x(sequenceLength - i + 1, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (cRKQN && i > 1)
                                        values.Add(Math.Round(fragmentation.x(sequenceLength - i + 1, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    if (i > 1)
                                    {
                                        for (int k = 1; k <= numPhosphate; k++)
                                        {
                                            if (k <= minCPhosphate)
                                            {
                                                values.Add(Math.Round(fragmentation.x(sequenceLength - i + 1, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                            }
                                            else
                                            {
                                                values.Add("-");
                                            }
                                        }
                                    }
                                    else values.Add("-");

                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.y))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                values.Add(Math.Round(fragmentation.y(sequenceLength - i + 1, charge), 3));
                                if (waterLoss == true)
                                {
                                    if (cSTED) values.Add(Math.Round(fragmentation.y(sequenceLength - i + 1, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (cRKQN) values.Add(Math.Round(fragmentation.y(sequenceLength - i + 1, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k <= numPhosphate; k++)
                                    {
                                        if (k <= minCPhosphate)
                                        {
                                            values.Add(Math.Round(fragmentation.y(sequenceLength - i + 1, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                        }
                                        else
                                        {
                                            values.Add("-");
                                        }
                                    }
                                }
                            }

                        if (ionSeriesIsEnabled(IonSeries.z))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                values.Add(Math.Round(fragmentation.z(sequenceLength - i + 1, charge), 3));
                                if (waterLoss == true)
                                {
                                    if (cSTED) values.Add(Math.Round(fragmentation.z(sequenceLength - i + 1, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (cRKQN) values.Add(Math.Round(fragmentation.z(sequenceLength - i + 1, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k <= numPhosphate; k++)
                                    {
                                        if (k <= minCPhosphate)
                                        {
                                            values.Add(Math.Round(fragmentation.z(sequenceLength - i + 1, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                        }
                                        else
                                        {
                                            values.Add("-");
                                        }
                                    }
                                }
                            }
                        if (ionSeriesIsEnabled(IonSeries.zRadical))
                            for (int charge = min; charge <= max; ++charge)
                            {
                                values.Add(Math.Round(fragmentation.zRadical(sequenceLength - i + 1, charge), 3));
                                if (waterLoss == true)
                                {
                                    if (cSTED) values.Add(Math.Round(fragmentation.zRadical(sequenceLength - i + 1, charge) - WATERMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (ammoniumLoss == true)
                                {
                                    if (cRKQN) values.Add(Math.Round(fragmentation.zRadical(sequenceLength - i + 1, charge) - AMMONIUMMONOMASS / charge, 3));
                                    else values.Add("-");
                                }
                                if (phosphateLoss == true)
                                {
                                    for (int k = 1; k <= numPhosphate; k++)
                                    {
                                        if (k <= minCPhosphate)
                                        {
                                            values.Add(Math.Round(fragmentation.zRadical(sequenceLength - i + 1, charge) - k * PHOSPHATEMONOMASS / charge, 3));
                                        }
                                        else
                                        {
                                            values.Add("-");
                                        }
                                    }
                                }
                            }

                        row.SetValues(values.ToArray());

                    }//end for

                    //add sb_neutral loss table
                    #region add sb_neutral loss table
                    sb_neutral.Append("<html>");
                    sb_neutral.Append("<head>");
                    sb_neutral.Append("<title>neutralLossFragmentGridView2HTML</title>");
                    sb_neutral.Append("</head>");
                    sb_neutral.Append("<body>");
                    sb_neutral.Append("<br>");
                    sb_neutral.AppendLine("<" + "table border='2' cellpadding='1' cellspacing='1'>");
                    sb_neutral.AppendLine("<tr>");

                    for (int i = 0; i < neutralLossDataGridView.Columns.Count; i++)
                    {
                        sb_neutral.AppendLine("<th>" + neutralLossDataGridView.Columns[i].HeaderText + "</th>");
                    }

                    foreach (DataGridViewRow row in neutralLossDataGridView.Rows)
                    {
                        sb_neutral.AppendLine("<tr>");

                        #region basepeakthresholding is false
                        if (basePeakThresholding == false)
                        {
                            foreach (DataGridViewCell cell in row.Cells)
                            {
                                if (!(cell.Value is double))
                                {
                                    sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                    continue;
                                }

                                double mz = (double)cell.Value;

                                int index = -1;
                                if (points != null)
                                    index = points.FullLowerBound(mz - 0.5);

                                if (index == -1 || points.FullList[index].X > (mz + 0.5))
                                {
                                    sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                    //cell.Style.Font = new Font(annotationPanels.fragmentInfoGridView.Font, FontStyle.Regular);
                                    continue;
                                }
                                //cell.Style.Font = new Font(annotationPanels.fragmentInfoGridView.Font, FontStyle.Bold);
                                sb_neutral.AppendLine("<td><b>" + cell.FormattedValue + "</b></td>");
                            }
                        }
                        #endregion

                        else//basepeakthresholding is true
                        {
                            int columnIndex = 0;
                            foreach (DataGridViewCell cell in row.Cells)
                            {
                                if (neutralLossDataGridView.Columns[columnIndex].HeaderText.Contains("H2O") || neutralLossDataGridView.Columns[columnIndex].HeaderText.Contains("NH3") || neutralLossDataGridView.Columns[columnIndex].HeaderText.Contains("PHO"))
                                {
                                    if (!(cell.Value is double))
                                    {
                                        sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                        columnIndex++;
                                        continue;
                                    }

                                    double mz = (double)cell.Value;

                                    int index = -1;
                                    if (points != null)
                                        index = points.FullLowerBound(mz - 0.5);

                                    if (index == -1 || points.FullList[index].X > (mz + 0.5) || points.FullList[index].Y < cutoff)
                                    {
                                        sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                        columnIndex++;
                                        continue;
                                    }
                                    sb_neutral.AppendLine("<td><b>" + cell.FormattedValue + "</b></td>");
                                    columnIndex++;
                                }
                                else
                                {
                                    if (!(cell.Value is double))
                                    {
                                        sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                        columnIndex++;
                                        continue;
                                    }

                                    double mz = (double)cell.Value;

                                    int index = -1;
                                    if (points != null)
                                        index = points.FullLowerBound(mz - 0.5);

                                    if (index == -1 || points.FullList[index].X > (mz + 0.5))
                                    {
                                        sb_neutral.AppendLine("<td>" + cell.FormattedValue + "</td>");
                                        columnIndex++;
                                        continue;
                                    }
                                    sb_neutral.AppendLine("<td><b>" + cell.FormattedValue + "</b></td>");
                                    columnIndex++;
                                }
                            }
                        }

                    }
                    sb_neutral.AppendLine("</tr>");
                    sb_neutral.AppendLine("</body>");
                    sb_neutral.AppendLine("</head>");
                    sb_neutral.AppendLine("</html>");
                    #endregion

                    #endregion
                } //end of else
                string file_neutral = "C:\\Temp\\neutralLossTable.html";
                Directory.CreateDirectory(Path.GetDirectoryName(file_neutral));
                TextWriter tw_neutral = new StreamWriter(file_neutral);
                tw_neutral.WriteLine(sb_neutral.ToString());
                tw_neutral.Flush();
                tw_neutral.Close();
                #endregion
            }
            else
                annotationPanels.fragmentInfoGridView.Rows.Clear();

            annotationPanels.fragmentInfoGridView.ResumeLayout();
        }
Пример #4
0
        ///<summary>Adds user requested ion series to the fragmentation summary.</summary>
        private void addFragmentationSummary(GraphObjList list, pwiz.MSGraph.MSPointList points, Peptide peptide, Fragmentation fragmentation, string topSeries, string bottomSeries)
        {
            ///cutoff definition for neutral loss
            double basePeakIntensity = 0;
            double cutoff = 0;
            foreach (var pointlist in points)
            {
                if (basePeakIntensity < pointlist.Y)
                    basePeakIntensity = pointlist.Y;
            }
            cutoff = basePeakIntensity * basePeakPercentage * 0.01;
            ///

            int ionSeriesChargeState = min;
            string sequence = peptide.sequence;
            int sequenceLength = peptide.sequence.Length;
            ModificationMap modifications = peptide.modifications();

            // Select the color for the ion series.
            Color topSeriesColor;
            Color bottomSeriesColor;
            switch (topSeries)
            {
                default: topSeriesColor = Color.Gray; break;
                case "a": topSeriesColor = Color.YellowGreen; break;
                case "b": topSeriesColor = Color.Red; break;
                case "c": topSeriesColor = Color.Orange; break;
            }

            switch (bottomSeries)
            {
                default: bottomSeriesColor = Color.Gray; break;
                case "x": bottomSeriesColor = Color.Green; break;
                case "y": bottomSeriesColor = Color.Blue; break;
                case "z": bottomSeriesColor = Color.OrangeRed; break;
                case "z*": bottomSeriesColor = Color.Crimson; break;
            }
            // Ion series offsets. These offsets control where on the chart a particular ion series
            // get displayed
            //change the seriesTopLeftOffset value to 0.1 to make the label higher in the image.
            //original is 0.031
            double seriesTopLeftOffset = 0.05;
            // Set the constants for starting the label paint
            double topSeriesLeftPoint = 0.025;
            //test and looks reasonalbe
            double residueWidth = 0.031;
            //double residueWidth = 0.25 / ((double)sequence.Length);

            // Process all the series except c and x

            //small block modified
            //here is a big bug: if go like orignal code, then the y ions is just the like the order of b ions, which are not right.
            //My modification is to seperate a/b/c and x/y/z ions, and then it will solve this problem.
            //it seems works well.

            ///
            #region Process a/b ions
            //first we are going to touch only a/b ions
            ///
            for (int i = 1; i <= sequence.Length; ++i)
            {
                double tickStart = residueWidth * 4 / 5.0;
                double topSeriesFragmentMZ = 0.0;

                //test neutral loss
                //this block is to give clear clue for phospate loss
                //exact number of phosphated amino acids are counted.
                string Nseq = peptide.sequence.Substring(0, i);
                char[] Nseqchars = Nseq.ToCharArray();
                int Nphosmodi = 0;
                for (int k = 0; k < i; k++)
                {
                    if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (Nseqchars[k] == 'S' || Nseqchars[k] == 'T' || Nseqchars[k] == 'Y'))
                    {
                        Nphosmodi++;
                    }
                }

                //correct the bug:
                //when multiple charges allowed for fragmentation, then there is no tick thing showing the existance of the fragment
                //what I did is: make top/bottomSeriesHasMatch true if there is fragment of any charges matched.
                //bug fixed
                bool topSeriesHasMatch = false;
                for (int z = min; z <= max; z++)
                {
                    switch (topSeries)
                    {
                        case "a": topSeriesFragmentMZ = fragmentation.a(i, z); break;
                        case "b": topSeriesFragmentMZ = fragmentation.b(i, z); break;
                        default: topSeriesFragmentMZ = 0.0; break;
                    }

                    // Check if the top and bottom fragments have evidence
                    if (points != null)
                    {
                        // Search index
                        int index = -1;
                        // Find the left mz value using a mass tolerance of 0.5 da.
                        index = points.FullLowerBound(topSeriesFragmentMZ - 0.5);
                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ + 0.5))
                        {
                            topSeriesHasMatch = true;
                            break;
                        }
                    }

                    //test neutral loss
                    #region water loss a/b top series
                    if (waterLoss == true)
                    {
                        if (Nseq.Contains("S") || Nseq.Contains("T") || Nseq.Contains("E") || Nseq.Contains("D"))
                        {
                            // Check if the top and bottom fragments have evidence
                            if (points != null)
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(topSeriesFragmentMZ - WATERMONOMASS/z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5))
                                    {
                                        topSeriesHasMatch = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y >= cutoff)
                                    {
                                        topSeriesHasMatch = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    //test neutral loss
                    #region ammonium loss a/b top series
                    if (ammoniumLoss == true)
                    {
                        if (Nseq.Contains("R") || Nseq.Contains("K") || Nseq.Contains("Q") || Nseq.Contains("N"))
                        {
                            if (points != null)
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(topSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5))
                                    {
                                        topSeriesHasMatch = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                    {
                                        topSeriesHasMatch = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    //test neutral loss
                    #region phosphate loss a/b top series
                    if (phosphateLoss == true)
                    {
                        //need to judge qualified number of AAs;
                        int minPhosphate = Math.Min(Nphosmodi, numPhosphate);

                        if (minPhosphate > 0)
                        {
                            for (int k = 1; k <= minPhosphate; k++)
                            {
                                //first need to judge if there are as many as phos AAs
                                //then if AA <= phos, then deal with AA;
                                //if AA > phos, then deal with phos.
                                if (points != null)
                                {
                                    // Search index
                                    int index = -1;
                                    // Find the left mz value using a mass tolerance of 0.5 da.
                                    index = points.FullLowerBound(topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5);
                                    if (basePeakThresholding == false)
                                    {
                                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5))
                                        {
                                            topSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        {
                                            topSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                    }
                    #endregion
                }

                // Build the label for the amino acid
                // Add a text box in the middle of the left and right mz boundaries
                StringBuilder label = new StringBuilder(sequence[i - 1].ToString());
                // Figure out if any mods are there on this amino acid
                double deltaMass = modifications[i - 1].monoisotopicDeltaMass();
                string deltaMassString = deltaMass.ToString();

                TextObj text = new TextObj(label.ToString(), topSeriesLeftPoint,
                       seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);
                text.ZOrder = ZOrder.E_BehindCurves;
                text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false);
                text.FontSpec.Border.IsVisible = false;
                text.FontSpec.Fill.IsVisible = false;
                text.IsClippedToChartRect = true;
                list.Add(text);

                SizeF size = text.LayoutArea;
                float width = size.Width;

                if (deltaMass > 0.0)
                {
                    deltaMassString = "+" + Math.Round(deltaMass).ToString();
                    TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.011,
                       seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);

                    textModi.ZOrder = ZOrder.A_InFront;
                    textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false);
                    textModi.FontSpec.Border.IsVisible = false;
                    textModi.FontSpec.Fill.IsVisible = false ;
                    textModi.IsClippedToChartRect = true;
                    list.Add(textModi);

                }
                else if (deltaMass < 0.0)
                {
                    deltaMassString = Math.Round(deltaMass).ToString();
                    TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01,
                       seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);

                    textModi.ZOrder = ZOrder.B_BehindLegend;
                    textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false);
                    textModi.FontSpec.Border.IsVisible = false;
                    textModi.FontSpec.Fill.IsVisible = false ;
                    textModi.IsClippedToChartRect = true;
                    list.Add(textModi);
                }

                if (topSeriesHasMatch)
                {
                    // Paint the tick in the middle
                    LineObj tick = new LineObj(topSeriesColor, topSeriesLeftPoint + tickStart, (seriesTopLeftOffset - 0.03), topSeriesLeftPoint + tickStart, seriesTopLeftOffset);
                    tick.Location.CoordinateFrame = CoordType.ChartFraction;
                    tick.Line.Width = 2;
                    tick.IsClippedToChartRect = true;
                    list.Add(tick);
                    // Paint the hook
                    LineObj hook = new LineObj(topSeriesColor, topSeriesLeftPoint, (seriesTopLeftOffset - 0.05), topSeriesLeftPoint + tickStart, seriesTopLeftOffset - 0.03);
                    hook.Location.CoordinateFrame = CoordType.ChartFraction;
                    hook.Line.Width = 2;
                    hook.IsClippedToChartRect = true;
                    list.Add(hook);
                }
                // Update the next paint point
                topSeriesLeftPoint += residueWidth;
            }

            // Reset the series starting point
            topSeriesLeftPoint = 0.025;
            #endregion

            ///
            #region Process y/z ions
            //then for y/z ions:
            //note: since the fragmentsummary starts the ticking/lining from left to right,
            //so we need to adjust the starting point of bottoms series from the highest to lowest.
            ///
            for (int i = sequence.Length; i >= 1; --i)
            {
                double tickStart = residueWidth / 5.0;
                double bottomSeriesFragmentMZ = 0.0;
                bool bottomSeriesHasMatch = false;
                //test neutral
                string Cseq = peptide.sequence.Substring(sequenceLength - i, i);
                char[] seqchars = peptide.sequence.ToCharArray();
                int Cphosmodi = 0;
                for (int k = sequenceLength - i; k < sequenceLength; k++)
                {
                    if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y'))
                    {
                        Cphosmodi++;
                    }
                }

                for (int z = min; z <= max; z++)
                {
                    switch (bottomSeries)
                    {
                        case "y": bottomSeriesFragmentMZ = fragmentation.y(i, z); break;
                        case "z": bottomSeriesFragmentMZ = fragmentation.z(i, z); break;
                        case "z*": bottomSeriesFragmentMZ = fragmentation.zRadical(i, z); break;
                        default: bottomSeriesFragmentMZ = 0.0; break;
                    }

                    // Check if the top and bottom fragments have evidence

                    if (points != null)
                    {
                        // Search index
                        int index = -1;
                        // Find the left mz value using a mass tolerance of 0.5 da.
                        index = points.FullLowerBound(bottomSeriesFragmentMZ - 0.5);
                        if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ + 0.5))
                        {
                            bottomSeriesHasMatch = true;
                            break;
                        }
                    }

                    //test neutral loss
                    #region water loss y/z bottom series
                    if (waterLoss == true)
                    {
                        if (Cseq.Contains("S") || Cseq.Contains("T") || Cseq.Contains("E") || Cseq.Contains("D"))
                        {
                            if (points != null)
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(bottomSeriesFragmentMZ - WATERMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5))
                                    {
                                        bottomSeriesHasMatch = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                    {
                                        bottomSeriesHasMatch = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    //test neutral loss
                    #region ammonium loss y/z bottom series
                    if (ammoniumLoss == true)
                    {
                        if (Cseq.Contains("R") || Cseq.Contains("K") || Cseq.Contains("Q") || Cseq.Contains("N"))
                        if (points != null)
                        {
                            // Search index
                            int index = -1;
                            // Find the left mz value using a mass tolerance of 0.5 da.
                            index = points.FullLowerBound(bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5);
                            if (basePeakThresholding == false)
                            {
                                if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5))
                                {
                                    bottomSeriesHasMatch = true;
                                    break;
                                }
                            }
                            else
                            {
                                if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                {
                                    bottomSeriesHasMatch = true;
                                    break;
                                }
                            }
                        }
                    }
                    #endregion

                    //test neutral loss
                    #region phosphate loss y/z bottom series
                    if (phosphateLoss == true)
                    {
                        int minPhosphate = Math.Min(Cphosmodi, numPhosphate);
                        if (minPhosphate > 0)
                        {
                            for (int k = 1; k <= minPhosphate; k++)
                            {
                                if (points != null)
                                {
                                    // Search index
                                    int index = -1;
                                    // Find the left mz value using a mass tolerance of 0.5 da.
                                    index = points.FullLowerBound(bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5);
                                    if (basePeakThresholding == false)
                                    {
                                        if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5))
                                        {
                                            bottomSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        {
                                            bottomSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    #endregion
                }

                if (bottomSeriesHasMatch)
                {
                    // Paint the tick in the middle
                    LineObj tick = new LineObj(bottomSeriesColor, topSeriesLeftPoint - tickStart, seriesTopLeftOffset, topSeriesLeftPoint - tickStart, seriesTopLeftOffset + 0.03);
                    tick.Location.CoordinateFrame = CoordType.ChartFraction;
                    tick.Line.Width = 2;
                    tick.IsClippedToChartRect = true;
                    list.Add(tick);
                    // Paint the hook
                    LineObj hook = new LineObj(bottomSeriesColor, topSeriesLeftPoint - tickStart, seriesTopLeftOffset + 0.03, topSeriesLeftPoint + 2.0 * tickStart, seriesTopLeftOffset + 0.05);
                    hook.Location.CoordinateFrame = CoordType.ChartFraction;
                    hook.Line.Width = 2;
                    hook.IsClippedToChartRect = true;
                    list.Add(hook);
                }
                // Update the next paint point
                topSeriesLeftPoint += residueWidth;
            }

            // Reset the series starting point
            topSeriesLeftPoint = 0.025;
            #endregion

            ///
            #region Process x/c series
            ///
            //the reason that I didn't split c/x as ab/yz, is that c/x doesn't have to deal with the termini. so good to go.
            //disable the function of neutral losses
            for (int i = 1; i < sequence.Length; ++i)
            {
                double tickStart = residueWidth *4 / 5.0;
                double topSeriesFragmentMZ = 0.0;
                double bottomSeriesFragmentMZ = 0.0;
                // Check if the top and bottom fragments have evidence
                bool topSeriesHasMatch = false;
                bool bottomSeriesHasMatch = false;

                ///
                //test neutral loss
                //test neutral
                //adjust the "i" accordingly, must let the C ions be left=>right.
                //if it goes from left to right, then N series is i;
                //C series is more tricky. Get a NTempSeq from 0 to sequenceLength-i; then get C from total.
                ///
                string Nseq = peptide.sequence.Substring(0, i);
                string NTempSeq = peptide.sequence.Substring(0, sequenceLength - i);
                string Cseq = peptide.sequence.Substring(i, sequenceLength-i);
                char[] Nseqchars = Nseq.ToCharArray();
                char[] seqchars = peptide.sequence.ToCharArray();
                char[] NTempSeqChars = NTempSeq.ToCharArray();
                int Nphosmodi = 0;
                int NTempPhosmodi = 0;
                int Cphosmodi = 0;
                int phosmodi = 0;
                for (int k = 0; k < i; k++)
                {
                    if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (Nseqchars[k] == 'S' || Nseqchars[k] == 'T' || Nseqchars[k] == 'Y'))
                    {
                        Nphosmodi++;
                    }
                }

                for (int k = 0; k < sequenceLength - i; k++)
                {
                    if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (NTempSeqChars[k] == 'S' || NTempSeqChars[k] == 'T' || NTempSeqChars[k] == 'Y'))
                    {
                        NTempPhosmodi++;
                    }
                }
                for (int k = 0; k < sequenceLength; k++)
                {
                    if (Math.Round(modifications[k].monoisotopicDeltaMass()) == 80 && (seqchars[k] == 'S' || seqchars[k] == 'T' || seqchars[k] == 'Y'))
                    {
                        phosmodi++;
                    }
                }
                Cphosmodi = phosmodi - NTempPhosmodi;

                for (int z = min; z <= max; z++)
                {
                    switch (topSeries)
                    {
                        case "c": topSeriesFragmentMZ = fragmentation.c(i, z); break;
                        default: topSeriesFragmentMZ = 0.0; break;
                    }
                    switch (bottomSeries)
                    {
                        case "x": bottomSeriesFragmentMZ = fragmentation.x(sequence.Length - i, z); break;
                        default: bottomSeriesFragmentMZ = 0.0; break;
                    }

                    if (points != null)
                    {
                        // Search index
                        int index = -1;
                        // Find the left mz value using a mass tolerance of 0.5 da.
                        index = points.FullLowerBound(topSeriesFragmentMZ - 0.5);
                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ + 0.5))
                            topSeriesHasMatch = true;

                        // Reset the search index
                        index = -1;
                        // Find the left mz value using a mass tolerance of 0.5 da.
                        index = points.FullLowerBound(bottomSeriesFragmentMZ - 0.5);
                        if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ + 0.5))
                            bottomSeriesHasMatch = true;
                    }

                    //disable neutral losses for c/x series
                    //test neutral loss
                    #region water loss c/x
                    if (waterLoss == true)
                    {
                        if (Nseq.Contains("S") || Nseq.Contains("T") || Nseq.Contains("E") || Nseq.Contains("D"))
                        {
                            if (points != null)
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(topSeriesFragmentMZ - WATERMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5))
                                        topSeriesHasMatch = true;
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        topSeriesHasMatch = true;
                                }
                            }
                        }
                        if (Cseq.Contains("S") || Cseq.Contains("T") || Cseq.Contains("E") || Cseq.Contains("D"))
                        {
                            if (points != null)
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(bottomSeriesFragmentMZ - WATERMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5))
                                        bottomSeriesHasMatch = true;
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - WATERMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        bottomSeriesHasMatch = true;
                                }
                            }
                        }
                    }
                    #endregion

                    ////test neutral loss
                    #region ammonium loss c/x
                    if (ammoniumLoss == true)
                    {
                        if (points != null)
                        {
                            if (Nseq.Contains("R") || Nseq.Contains("K") || Nseq.Contains("Q") || Nseq.Contains("N"))
                            {
                                // Search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(topSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5))
                                        topSeriesHasMatch = true;
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        topSeriesHasMatch = true;
                                }

                            }

                            if (Cseq.Contains("R") || Cseq.Contains("K") || Cseq.Contains("Q") || Cseq.Contains("N"))
                            {
                                // Reset the search index
                                int index = -1;
                                // Find the left mz value using a mass tolerance of 0.5 da.
                                index = points.FullLowerBound(bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z - 0.5);
                                if (basePeakThresholding == false)
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5))
                                        bottomSeriesHasMatch = true;
                                }
                                else
                                {
                                    if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - AMMONIUMMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        bottomSeriesHasMatch = true;
                                }

                            }
                        }
                    }
                    #endregion

                    ////test neutral loss
                    #region phosphate loss c/x
                    if (phosphateLoss == true)
                    {
                        int minPhosphate = Math.Min(Nphosmodi, numPhosphate);
                        if (minPhosphate > 0)
                        {
                            for (int k = 1; k <= minPhosphate; k++)
                            {
                                if (points != null)
                                {
                                    // Search index
                                    int index = -1;
                                    // Find the left mz value using a mass tolerance of 0.5 da.
                                    index = points.FullLowerBound(topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5);
                                    if (basePeakThresholding == false)
                                    {
                                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5))
                                        {
                                            topSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        if (index != -1 && points.FullList[index].X <= (topSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                        {
                                            topSeriesHasMatch = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        minPhosphate = Math.Min(Cphosmodi, numPhosphate);
                        {
                            if (minPhosphate > 0)
                            {
                                for (int k = 1; k <= minPhosphate; k++)
                                {
                                    if (points != null)
                                    {
                                        // Search index
                                        int index = -1;
                                        // Find the left mz value using a mass tolerance of 0.5 da.
                                        index = points.FullLowerBound(bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z - 0.5);
                                        if (basePeakThresholding == false)
                                        {
                                            if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5))
                                            {
                                                bottomSeriesHasMatch = true;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            if (index != -1 && points.FullList[index].X <= (bottomSeriesFragmentMZ - k * PHOSPHATEMONOMASS / z + 0.5) && points.FullList[index].Y > cutoff)
                                            {
                                                bottomSeriesHasMatch = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }

                        }
                    }
                    #endregion

                }

                // Build the label for the amino acid
                // Add a text box in the middle of the left and right mz boundaries
                StringBuilder label = new StringBuilder(sequence[i - 1].ToString());
                // Figure out if any mods are there on this amino acid
                double deltaMass = modifications[i - 1].monoisotopicDeltaMass();
                string deltaMassString = deltaMass.ToString();
                // Round the mod mass and append it to the amino acid as a string
                //if (deltaMass > 0.0)
                //{
                //    label.Append("+" + Math.Round(deltaMass));
                //}
                //else if (deltaMass < 0.0)
                //{
                //    label.Append(Math.Round(deltaMass));
                //}
                TextObj text = new TextObj(label.ToString(), topSeriesLeftPoint,
                            seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);
                text.ZOrder = ZOrder.B_BehindLegend;
                text.FontSpec = new FontSpec("Arial", 13, Color.Black, true, false, false);
                text.FontSpec.Border.IsVisible = false;
                text.FontSpec.Fill.IsVisible = false;
                text.IsClippedToChartRect = true;
                list.Add(text);

                SizeF size = text.LayoutArea;
                float width = size.Width;

                if (deltaMass > 0.0)
                {
                    deltaMassString = "+" + Math.Round(deltaMass).ToString();
                    TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01,
                       seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);

                    textModi.ZOrder = ZOrder.B_BehindLegend;
                    textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false);
                    textModi.FontSpec.Border.IsVisible = false;
                    textModi.FontSpec.Fill.IsVisible = false;
                    textModi.IsClippedToChartRect = true;
                    list.Add(textModi);

                }
                else if (deltaMass < 0.0)
                {
                    deltaMassString = Math.Round(deltaMass).ToString();
                    TextObj textModi = new TextObj(deltaMassString, topSeriesLeftPoint + 0.01,
                       seriesTopLeftOffset, CoordType.ChartFraction, AlignH.Left, AlignV.Center);

                    textModi.ZOrder = ZOrder.B_BehindLegend;
                    textModi.FontSpec = new FontSpec("Arial", 8, Color.Black, true, false, false);
                    textModi.FontSpec.Border.IsVisible = false;
                    textModi.FontSpec.Fill.IsVisible = false;
                    textModi.IsClippedToChartRect = true;
                    list.Add(textModi);
                }

                if (topSeriesHasMatch)
                {
                    // Paint the tick in the middle
                    LineObj tick = new LineObj(topSeriesColor, topSeriesLeftPoint + tickStart, (seriesTopLeftOffset - 0.03), topSeriesLeftPoint + tickStart, seriesTopLeftOffset);
                    tick.Location.CoordinateFrame = CoordType.ChartFraction;
                    tick.Line.Width = 2;
                    tick.IsClippedToChartRect = true;
                    list.Add(tick);
                    // Paint the hook
                    LineObj hook = new LineObj(topSeriesColor, topSeriesLeftPoint, (seriesTopLeftOffset - 0.05), topSeriesLeftPoint + tickStart, seriesTopLeftOffset - 0.03);
                    hook.Location.CoordinateFrame = CoordType.ChartFraction;
                    hook.Line.Width = 2;
                    hook.IsClippedToChartRect = true;
                    list.Add(hook);
                }
                if (bottomSeriesHasMatch)
                {
                    // Paint the tick in the middle
                    LineObj tick = new LineObj(bottomSeriesColor, topSeriesLeftPoint + tickStart, seriesTopLeftOffset, topSeriesLeftPoint + tickStart, seriesTopLeftOffset + 0.03);
                    tick.Location.CoordinateFrame = CoordType.ChartFraction;
                    tick.Line.Width = 2;
                    tick.IsClippedToChartRect = true;
                    list.Add(tick);
                    // Paint the hook
                    LineObj hook = new LineObj(bottomSeriesColor, topSeriesLeftPoint + tickStart, seriesTopLeftOffset + 0.03, topSeriesLeftPoint + 2.0 * tickStart, seriesTopLeftOffset + 0.05);
                    hook.Location.CoordinateFrame = CoordType.ChartFraction;
                    hook.Line.Width = 2;
                    hook.IsClippedToChartRect = true;
                    list.Add(hook);
                }
                // Update the next paint point
                topSeriesLeftPoint += residueWidth;
            }
            #endregion
        }