Example #1
0
 public PepV01(FastaSeqV01 fastaSequence, int begin, int end, int missedCleavages,
               double mh, double?rt)
     : this(fastaSequence, begin, end, missedCleavages)
 {
     MassH = new TypedMass(mh, MassType.MonoisotopicMassH);
     PredictedRetentionTime = rt;
 }
Example #2
0
        private static CellDesc CreateIon(IonType type, int ordinal, TypedMass massH, Adduct charge,
                                          IEnumerable <DocNode> choices, ICollection <DocNode> chosen, Transition tranSelected,
                                          RenderTools rt)
        {
            double   mz   = SequenceMassCalc.GetMZ(massH, charge);
            CellDesc cell = CreateData(string.Format(@"{0:F02}", mz), rt);

            foreach (TransitionDocNode nodeTran in choices)
            {
                Transition tran = nodeTran.Transition;
                if (tran.IonType == type &&
                    tran.Ordinal == ordinal &&
                    tran.Adduct == charge)
                {
                    cell.Font = rt.FontBold;
                    if (Equals(tran, tranSelected))
                    {
                        cell.Brush = rt.BrushSelected; // Stop after selected
                        break;
                    }
                    if (!chosen.Contains(nodeTran))
                    {
                        cell.Brush = rt.BrushChoice;  // Keep looking
                    }
                    else
                    {
                        cell.Brush = rt.BrushChosen;  // Stop after chosen
                        break;
                    }
                }
            }

            return(cell);
        }
        public void TestGetFragmentFormula()
        {
            var pepseq           = "PEPTIDE";
            var sequenceMassCalc = new SequenceMassCalc(MassType.Monoisotopic);
            var precursor        = FragmentedMolecule.EMPTY.ChangeModifiedSequence(
                new ModifiedSequence(pepseq, new ModifiedSequence.Modification[0], MassType.Monoisotopic));
            var peptide                = new Peptide(precursor.UnmodifiedSequence);
            var transitionGroup        = new TransitionGroup(peptide, Adduct.SINGLY_PROTONATED, IsotopeLabelType.light);
            var settings               = SrmSettingsList.GetDefault();
            var transitionGroupDocNode = new TransitionGroupDocNode(transitionGroup, Annotations.EMPTY, settings,
                                                                    ExplicitMods.EMPTY, null, null, null, new TransitionDocNode[0], false);

            foreach (var ionType in new[] { IonType.a, IonType.b, IonType.c, IonType.x, IonType.y, IonType.z })
            {
                for (int ordinal = 1; ordinal < pepseq.Length; ordinal++)
                {
                    var transition             = new Transition(transitionGroup, ionType, Transition.OrdinalToOffset(ionType, ordinal, pepseq.Length), 0, Adduct.SINGLY_PROTONATED);
                    var fragment               = precursor.ChangeFragmentIon(ionType, ordinal);
                    var actualMassDistribution = FragmentedMolecule.Settings.DEFAULT.GetMassDistribution(
                        fragment.FragmentFormula, 0, 0);
                    var expectedMz = sequenceMassCalc.GetFragmentMass(transition, transitionGroupDocNode.IsotopeDist);
                    if (expectedMz.IsMassH())
                    {
                        expectedMz = new TypedMass(expectedMz.Value - BioMassCalc.MassProton, expectedMz.MassType & ~MassType.bMassH);
                    }
                    var actualMz = actualMassDistribution.MostAbundanceMass;
                    if (Math.Abs(expectedMz - actualMz) > .001)
                    {
                        Assert.AreEqual(expectedMz, actualMz, .001, "Ion type {0} Ordinal {1}", ionType, ordinal);
                    }
                }
            }
        }
Example #4
0
 public TransitionDocNode(Transition id,
                          TransitionLosses losses,
                          TypedMass massH,
                          TransitionQuantInfo quantInfo)
     : this(id, Annotations.EMPTY, losses, massH, quantInfo, null)
 {
 }
Example #5
0
 public TransitionDocNode(Transition id,
                          TransitionLosses losses,
                          TypedMass massH,
                          TransitionQuantInfo quantInfo,
                          ExplicitTransitionValues explicitTransitionValues)
     : this(id, Annotations.EMPTY, losses, massH, quantInfo, explicitTransitionValues, null)
 {
 }
Example #6
0
        private TransitionDocNode CreateTransitionNode(int massIndex, TypedMass precursorMassH, TransitionIsotopeDistInfo isotopeDistInfo,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, CustomMolecule customMolecule = null)
        {
            Transition transition = new Transition(this, massIndex, customMolecule);
            var        quantInfo  = TransitionDocNode.TransitionQuantInfo.GetLibTransitionQuantInfo(transition, losses,
                                                                                                    Transition.CalcMass(precursorMassH, losses), transitionRanks).ChangeIsotopeDistInfo(isotopeDistInfo);

            return(new TransitionDocNode(transition, losses, precursorMassH, quantInfo));
        }
Example #7
0
 public CustomMolecule(string formula, TypedMass monoisotopicMass, TypedMass averageMass, string name, MoleculeAccessionNumbers moleculeAccessionNumbers)
 {
     Formula          = formula;
     MonoisotopicMass = monoisotopicMass;
     AverageMass      = averageMass;
     Name             = name ?? string.Empty;
     AccessionNumbers = moleculeAccessionNumbers ?? MoleculeAccessionNumbers.EMPTY;
     Validate();
 }
Example #8
0
 private static Adduct CalcProductCharge(TypedMass productMassH, int?productZ, double productMz, double tolerance, bool isCustomIon,
                                         Adduct maxCharge, MassShiftType massShiftType, out int massShift, out int nearestCharge)
 {
     return(CalcCharge(productMassH, productMz, tolerance, isCustomIon,
                       productZ ?? Transition.MIN_PRODUCT_CHARGE,
                       productZ ?? Math.Min(maxCharge.AdductCharge, Transition.MAX_PRODUCT_CHARGE),
                       Transition.MassShifts,
                       massShiftType,
                       out massShift,
                       out nearestCharge));
 }
Example #9
0
        private TransitionDocNode CreateTransitionNode(int massIndex, TypedMass precursorMassH, TransitionIsotopeDistInfo isotopeDistInfo,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, Adduct productAdduct, CustomMolecule customMolecule = null)
        {
            Transition transition = new Transition(this, massIndex, productAdduct, customMolecule);
            var        quantInfo  = TransitionDocNode.TransitionQuantInfo.GetLibTransitionQuantInfo(transition, losses,
                                                                                                    Transition.CalcMass(precursorMassH, losses), transitionRanks).ChangeIsotopeDistInfo(isotopeDistInfo);
            var transitionDocNode = new TransitionDocNode(transition, losses, precursorMassH, quantInfo, ExplicitTransitionValues.EMPTY);

            if (massIndex < 0)
            {
                transitionDocNode = transitionDocNode.ChangeQuantitative(false);
            }
            return(transitionDocNode);
        }
Example #10
0
        /// <summary>
        /// Calculates the matching charge within a tolerance for a mass, assuming (de)protonation.
        /// </summary>
        /// <param name="mass">The mass to calculate charge for (actually massH if !IsCustomIon)</param>
        /// <param name="mz">The desired m/z value the charge should produce</param>
        /// <param name="tolerance">How far off the actual m/z is allowed to be</param>
        /// <param name="isCustomIon">Is this a custom ion formula?</param>
        /// <param name="minCharge">Minimum charge to consider</param>
        /// <param name="maxCharge">Maximum charge to consider</param>
        /// <param name="massShifts">Possible mass shifts that may have been applied to decoys</param>
        /// <param name="massShiftType"></param>
        /// <param name="massShift">Mass shift required to to achieve this charge state or zero</param>
        /// <param name="nearestCharge">closest matching charge, useful when return value is null</param>
        /// <returns>A matching charge or null, in which case the closest non-matching charge can be found in the nearestCharge value.</returns>
        public static Adduct CalcCharge(TypedMass mass, double mz, double tolerance, bool isCustomIon, int minCharge, int maxCharge,
                                        ICollection <int> massShifts, MassShiftType massShiftType, out int massShift, out int nearestCharge)
        {
            Assume.IsTrue(minCharge <= maxCharge);

            massShift = 0;

            nearestCharge = 0;
            double nearestDelta = double.MaxValue;

            for (int i = minCharge; i <= maxCharge; i++)
            {
                if (i != 0) // Avoid z=0 if we're entertaining negative charge states
                {
                    double calculatedMz = isCustomIon
                        ? Adduct.FromChargeProtonated(i).MzFromNeutralMass(mass)
                        : SequenceMassCalc.GetMZ(mass, i);
                    double delta           = mz - calculatedMz;
                    double deltaAbs        = Math.Abs(delta);
                    int    potentialShift  = (int)Math.Round(deltaAbs);
                    double fractionalDelta = deltaAbs - potentialShift;
                    if (MatchMz(fractionalDelta, tolerance) && MatchMassShift(potentialShift, massShifts, massShiftType))
                    {
                        massShift = potentialShift;
                        if (delta < 0)
                        {
                            massShift = -massShift;
                        }
                        var result = i;
                        nearestCharge = i;
                        return(Adduct.FromCharge(result, isCustomIon ? Adduct.ADDUCT_TYPE.non_proteomic : Adduct.ADDUCT_TYPE.proteomic));
                    }
                    if (deltaAbs < nearestDelta)
                    {
                        nearestDelta  = deltaAbs;
                        nearestCharge = i;
                    }
                    // If the charge is positive and the calculated m/z is smaller than the desired m/z
                    // increasing the charge further cannot possibly produce a match
                    if (massShiftType == MassShiftType.none && minCharge > 0 && delta > 0)
                    {
                        break;
                    }
                }
            }

            Debug.Assert(nearestCharge != 0);   // Could only happen if min > max

            return(Adduct.EMPTY);
        }
Example #11
0
 public static Adduct CalcPrecursorCharge(TypedMass precursorMassH,
                                          double precursorMz,
                                          double tolerance,
                                          bool isCustomIon,
                                          bool isDecoy,
                                          out int massShift,
                                          out int nearestCharge)
 {
     return(CalcCharge(precursorMassH, precursorMz, tolerance, isCustomIon,
                       TransitionGroup.MIN_PRECURSOR_CHARGE,
                       TransitionGroup.MAX_PRECURSOR_CHARGE,
                       TransitionGroup.MassShifts,
                       isDecoy ? MassShiftType.shift_only : MassShiftType.none,
                       out massShift, out nearestCharge));
 }
Example #12
0
        private static void CheckLabel(string label)
        {
            string unlabel     = label.Substring(0, label.Length - 1);
            var    adductLabel = Adduct.DICT_ADDUCT_ISOTOPE_NICKNAMES.FirstOrDefault(x => x.Value == label).Key;
            var    labeled     = Adduct.FromStringAssumeProtonated("[2M3C13-Na]");
            var    unlabeled   = Adduct.FromStringAssumeProtonated("[2M-Na]");
            var    relabeled   = Adduct.FromStringAssumeProtonated("[2M3Cl374H2-Na]".Replace("Cl37", adductLabel));
            var    massNeutral = 5.6;

            Assert.AreEqual(
                2 * (massNeutral + 3 * (BioMassCalc.MONOISOTOPIC.GetMass("C'") - BioMassCalc.MONOISOTOPIC.GetMass("C"))) -
                BioMassCalc.MONOISOTOPIC.GetMass("Na"),
                labeled.ApplyToMass(new TypedMass(massNeutral, MassType.Monoisotopic)));
            Assert.AreEqual(unlabeled, labeled.ChangeIsotopeLabels(null));
            var labels = new Dictionary <string, int> {
                { label, 3 }, { "H2", 4 }
            };

            Assert.AreEqual(relabeled, labeled.ChangeIsotopeLabels(labels));
            var labelsToo = new Dictionary <string, int> {
                { label, 3 }, { "H'", 4 }
            };

            Assert.AreEqual(relabeled, unlabeled.ChangeIsotopeLabels(labelsToo));
            var labelsAlso = new Dictionary <string, int> {
                { adductLabel, 3 }, { "H'", 4 }
            };                                                                          // Mixed

            Assert.AreEqual(relabeled, unlabeled.ChangeIsotopeLabels(labelsAlso));
            Assert.AreNotEqual(labeled, unlabeled.ChangeIsotopeLabels(labelsAlso));

            // Check Deuterium and Tritium handling
            Assert.AreEqual(BioMassCalc.MONOISOTOPIC.GetMass("Cl2Cl'3H5H'4N12"), BioMassCalc.MONOISOTOPIC.GetMass("Cl2Cl'3H5D4N12"));
            Assert.AreEqual(BioMassCalc.MONOISOTOPIC.GetMass("Cl2Cl'3H5H\"4N12"), BioMassCalc.MONOISOTOPIC.GetMass("Cl2Cl'3H5T4N12"));
            Assert.AreEqual(Molecule.Parse("Cl2Cl'3H5H'4N12".Replace("Cl'", label).Replace("Cl", unlabel)),
                            Molecule.Parse(relabeled.ApplyIsotopeLabelsToFormula("Cl5H9N12".Replace("Cl", unlabel)))); // Replaces three of five Cl and four of nine H
            var m100  = new TypedMass(100, MassType.Monoisotopic);
            var mdiff = 2 * (3 * (BioMassCalc.MONOISOTOPIC.GetMass(label) -
                                  BioMassCalc.MONOISOTOPIC.GetMass(unlabel)) +
                             4 * (BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.H2) -
                                  BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.H)));

            Assert.AreEqual(m100 + mdiff, relabeled.ApplyIsotopeLabelsToMass(m100),
                            .005); // Expect increase of 2*(3(Cl37-Cl)+4(H2-H))
            var isotopeAsMass = Adduct.FromStringAssumeProtonated("[2M1.23-Na]");

            Assert.AreEqual(102.46, isotopeAsMass.ApplyIsotopeLabelsToMass(m100), .005); // Expect increase of 2*1.23
        }
Example #13
0
 public CustomIon(string formula, Adduct adduct, TypedMass monoisotopicMass, TypedMass averageMass, string name)
     : base(formula, monoisotopicMass, averageMass, name)
 {
     if (adduct.IsEmpty)
     {
         var ionInfo = new IonInfo(NeutralFormula, adduct); // Analyzes the formula to see if it's something like "CH12[M+Na]"
         if (!Equals(NeutralFormula, ionInfo.NeutralFormula))
         {
             Formula = ionInfo.NeutralFormula;
         }
         Adduct = Adduct.FromStringAssumeProtonated(ionInfo.AdductText);
     }
     else
     {
         Adduct = adduct;
     }
 }
Example #14
0
        public static CustomMolecule FromTSV(string val)
        {
            var vals    = val.FromEscapedTSV();
            var name    = vals.Length > 0 ? vals[0] : null;
            var formula = vals.Length > 1 ? vals[1] : null;
            // ReSharper disable PossibleNullReferenceException
            var keysTSV = vals.Length > 2 ? val.Substring(name.Length + formula.Length + 2) : null;

            // ReSharper restore PossibleNullReferenceException
            if (formula == null && name != null && name.StartsWith(INVARIANT_NAME_DETAIL))
            {
                // Looks like a mass-only description
                Regex r = new Regex(massFormatRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant);
                Match m = r.Match(val);
                if (m.Success)
                {
                    try
                    {
                        var massMono = new TypedMass(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture), MassType.Monoisotopic);
                        var massAvg  = new TypedMass(double.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture), MassType.Average);
                        return(new CustomMolecule(massMono, massAvg));
                    }
                    catch
                    {
                        Assume.Fail("unable to read custom molecule information"); // Not L10N
                    }
                }
            }
            else if (formula != null && formula.Contains("/")) // Not L10N
            {
                // "formula" is actually mono and average masses
                try
                {
                    var values   = formula.Split('/');
                    var massMono = new TypedMass(double.Parse(values[0], CultureInfo.InvariantCulture), MassType.Monoisotopic);
                    var massAvg  = new TypedMass(double.Parse(values[1], CultureInfo.InvariantCulture), MassType.Average);
                    return(new CustomMolecule(massMono, massAvg, name, new MoleculeAccessionNumbers(keysTSV)));
                }
                catch
                {
                    Assume.Fail("unable to read custom molecule information"); // Not L10N
                }
            }
            return(new CustomMolecule(formula, null, null, name, new MoleculeAccessionNumbers(keysTSV)));
        }
Example #15
0
        public FragmentIon(PepV01 peptide, IonType type, int offset, double mh)
        {
            _peptide = peptide;

            IType          = type;
            CleavageOffset = offset;
            MassH          = new TypedMass(mh, MassType.MonoisotopicMassH);

            // Derived values
            if (IsNTerminal())
            {
                Ordinal = offset + 1;
                AA      = peptide.Target.Sequence[offset];
            }
            else
            {
                Ordinal = _peptide.Length - offset - 1;
                AA      = peptide.Target.Sequence[offset + 1];
            }
        }
Example #16
0
        /// <summary>
        /// Calculates the matching charge within a tolerance for a mass, assuming (de)protonation.
        /// </summary>
        /// <param name="mass">The mass to calculate charge for (actually massH if !IsCustomIon)</param>
        /// <param name="mz">The desired m/z value the charge should produce</param>
        /// <param name="tolerance">How far off the actual m/z is allowed to be</param>
        /// <param name="isCustomIon">Is this a custom ion formula?</param>
        /// <param name="minCharge">Minimum charge to consider</param>
        /// <param name="maxCharge">Maximum charge to consider</param>
        /// <param name="massShifts">Possible mass shifts that may have been applied to decoys</param>
        /// <param name="massShiftType"></param>
        /// <param name="massShift">Mass shift required to to achieve this charge state or zero</param>
        /// <param name="nearestCharge">closest matching charge, useful when return value is null</param>
        /// <returns>A matching charge or null, in which case the closest non-matching charge can be found in the nearestCharge value.</returns>
        public static Adduct CalcCharge(TypedMass mass, double mz, double tolerance, bool isCustomIon, int minCharge, int maxCharge,
                                        ICollection <int> massShifts, MassShiftType massShiftType, out int massShift, out int nearestCharge)
        {
            Assume.IsTrue(minCharge <= maxCharge);

            massShift = 0;

            nearestCharge = 0;
            double nearestDelta = double.MaxValue;

            for (int i = minCharge; i <= maxCharge; i++)
            {
                if (i != 0) // Avoid z=0 if we're entertaining negative charge states
                {
                    double delta           = mz - (isCustomIon ? Adduct.FromChargeProtonated(i).MzFromNeutralMass(mass) : SequenceMassCalc.GetMZ(mass, i));
                    double deltaAbs        = Math.Abs(delta);
                    int    potentialShift  = (int)Math.Round(deltaAbs);
                    double fractionalDelta = deltaAbs - potentialShift;
                    if (MatchMz(fractionalDelta, tolerance) && MatchMassShift(potentialShift, massShifts, massShiftType))
                    {
                        massShift = potentialShift;
                        if (delta < 0)
                        {
                            massShift = -massShift;
                        }
                        var result = i;
                        nearestCharge = i;
                        return(Adduct.FromChargeProtonated(result));
                    }
                    if (deltaAbs < nearestDelta)
                    {
                        nearestDelta  = deltaAbs;
                        nearestCharge = i;
                    }
                }
            }

            Debug.Assert(nearestCharge != 0);   // Could only happen if min > max

            return(Adduct.EMPTY);
        }
Example #17
0
        private List <SpectrumPeaksInfo.MI> CalcMIs(TypedMass mass, float[] intensities, int offset)
        {
            var result = new List <SpectrumPeaksInfo.MI>(PrositConstants.IONS_PER_RESIDUE / 2);

            for (var c = 0; c < PrositConstants.IONS_PER_RESIDUE / 2; ++c)
            {
                // Not a possible charge
                if (PeptidePrecursorNCE.NodeGroup.PrecursorCharge <= c)
                {
                    break;
                }

                result.Add(new SpectrumPeaksInfo.MI
                {
                    Mz        = SequenceMassCalc.GetMZ(mass, c + 1),
                    Intensity = intensities[c + offset]
                });
            }

            return(result);
        }
Example #18
0
 public TransitionDocNode(Transition id,
                          Annotations annotations,
                          TransitionLosses losses,
                          TypedMass mass,
                          TransitionQuantInfo transitionQuantInfo,
                          Results <TransitionChromInfo> results)
     : base(id, annotations)
 {
     Losses = losses;
     if (losses != null)
     {
         mass -= losses.Mass;
     }
     Mz = id.IsCustom() ?
          new SignedMz(id.Adduct.MzFromNeutralMass(mass), id.IsNegative()) :
          new SignedMz(SequenceMassCalc.GetMZ(mass, id.Adduct) + SequenceMassCalc.GetPeptideInterval(id.DecoyMassShift), id.IsNegative());
     MzMassType      = mass.MassType;
     IsotopeDistInfo = transitionQuantInfo.IsotopeDistInfo;
     LibInfo         = transitionQuantInfo.LibInfo;
     Results         = results;
     Quantitative    = transitionQuantInfo.Quantititative;
 }
Example #19
0
        public static Adduct CalcProductCharge(TypedMass productPrecursorMass,
                                               int?productZ,
                                               Adduct precursorCharge,
                                               IList <IonType> acceptedIonTypes,
                                               IonTable <TypedMass> productMasses,
                                               IList <IList <ExplicitLoss> > potentialLosses,
                                               double productMz,
                                               double tolerance,
                                               MassType massType,
                                               MassShiftType massShiftType,
                                               out IonType?ionType,
                                               out int?ordinal,
                                               out TransitionLosses losses,
                                               out int massShift)
        {
            // Get length of fragment ion mass array
            int len = productMasses.GetLength(1);

            // Check all possible ion types and offsets
            double?minDelta = null;
            double?minFragmentMass = null, maxFragmentMass = null, maxLoss = null;

            if (massShiftType == MassShiftType.none)
            {
                if (!productZ.HasValue)
                {
                    minFragmentMass = productMz - tolerance;
                }
                else
                {
                    minFragmentMass = SequenceMassCalc.GetMH(productMz - tolerance, productZ.Value);
                    maxFragmentMass = SequenceMassCalc.GetMH(productMz + tolerance, productZ.Value);
                }
            }

            var              bestCharge    = Adduct.EMPTY;
            IonType?         bestIonType   = null;
            int?             bestOrdinal   = null;
            TransitionLosses bestLosses    = null;
            int              bestMassShift = 0;

            // Check to see if it is the precursor
            foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(IonType.precursor, 0, massType, potentialLosses))
            {
                var productMass = productPrecursorMass;
                if (lossesTrial != null)
                {
                    productMass -= lossesTrial.Mass;
                    maxLoss      = Math.Max(maxLoss ?? 0, lossesTrial.Mass);
                }
                int potentialMassShift;
                int nearestCharge;
                var charge = CalcProductCharge(productMass, productZ, productMz, tolerance, false, precursorCharge,
                                               massShiftType, out potentialMassShift, out nearestCharge);
                if (Equals(charge, precursorCharge))
                {
                    double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift;
                    double delta       = Math.Abs(productMz - potentialMz);

                    if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0)
                    {
                        bestCharge    = charge;
                        bestIonType   = IonType.precursor;
                        bestOrdinal   = len + 1;
                        bestLosses    = lossesTrial;
                        bestMassShift = potentialMassShift;

                        minDelta = delta;
                    }
                }
            }

            if (maxLoss.HasValue)
            {
                maxFragmentMass += maxLoss.Value;
            }

            var categoryLast = -1;

            foreach (var typeAccepted in GetIonTypes(acceptedIonTypes))
            {
                var type     = typeAccepted.IonType;
                var category = typeAccepted.IonCategory;

                // Types have priorities.  If changing type category, and there is already a
                // suitable answer stop looking.
                if (category != categoryLast && minDelta.HasValue && MatchMz(minDelta.Value, tolerance))
                {
                    break;
                }
                categoryLast = category;

                // The peptide length is 1 longer than the mass array
                for (int ord = len; ord > 0; ord--)
                {
                    int offset          = Transition.OrdinalToOffset(type, ord, len + 1);
                    var productMassBase = productMasses[type, offset];
                    // Until below the maximum fragment mass no possible matches
                    if (maxFragmentMass.HasValue && productMassBase > maxFragmentMass.Value)
                    {
                        continue;
                    }
                    // Once below the minimum fragment mass no more possible matches, so stop
                    if (minFragmentMass.HasValue && productMassBase < minFragmentMass.Value)
                    {
                        break;
                    }

                    foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(type, offset, massType, potentialLosses))
                    {
                        // Look for the closest match.
                        var productMass = productMassBase;
                        if (lossesTrial != null)
                        {
                            productMass -= lossesTrial.Mass;
                        }
                        int potentialMassShift;
                        int nearestCharge;
                        var chargeFound = CalcProductCharge(productMass, productZ, productMz, tolerance, false, precursorCharge,
                                                            massShiftType, out potentialMassShift, out nearestCharge);
                        if (!chargeFound.IsEmpty)
                        {
                            var    charge      = chargeFound;
                            double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift;
                            double delta       = Math.Abs(productMz - potentialMz);
                            if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0)
                            {
                                bestCharge    = charge;
                                bestIonType   = type;
                                bestOrdinal   = ord;
                                bestLosses    = lossesTrial;
                                bestMassShift = potentialMassShift;

                                minDelta = delta;
                            }
                        }
                    }
                }
            }

            ionType   = bestIonType;
            ordinal   = bestOrdinal;
            losses    = bestLosses;
            massShift = bestMassShift;
            return(bestCharge);
        }
Example #20
0
 public CustomMolecule(TypedMass monoisotopicMass, TypedMass averageMass, string name = null, MoleculeAccessionNumbers moleculeAccessionNumbers = null)
     : this(null, monoisotopicMass, averageMass, name, moleculeAccessionNumbers)
 {
 }
Example #21
0
        public IsotopeDistInfo(MassDistribution massDistribution,
                               TypedMass monoisotopicMass,
                               Adduct adduct,
                               Func <double, double> calcFilterWindow,
                               double massResolution,
                               double minimumAbundance)
        {
            _monoisotopicMass = monoisotopicMass;
            _adduct           = adduct.Unlabeled; // Don't reapply explicit isotope labels

            // Get peak center of mass values for the given resolution
            var q1FilterValues = MassDistribution.NewInstance(massDistribution, massResolution, 0).Keys.ToList();
            // Find the monoisotopic m/z and make sure it is exactly the expected number
            double monoMz        = _adduct.MzFromNeutralMass(_monoisotopicMass);
            double monoMzDist    = monoMz;
            int    monoMassIndex = 0;

            for (int i = 0; i < q1FilterValues.Count; i++)
            {
                double peakCenterMz = q1FilterValues[i];
                double filterWindow = calcFilterWindow(peakCenterMz);
                double startMz      = peakCenterMz - filterWindow / 2;
                double endMz        = startMz + filterWindow;
                if (startMz < monoMz && monoMz < endMz)
                {
                    monoMzDist        = q1FilterValues[i];
                    q1FilterValues[i] = monoMz;
                    monoMassIndex     = i;
                    break;
                }
            }
            // Insert a M-1 peak, even if it is not expected in the isotope mass distribution
            if (monoMassIndex == 0 && q1FilterValues.Count > 1)
            {
                // Use the delta from the original distribution monoMz to the next peak
                q1FilterValues.Insert(0, monoMz + monoMzDist - q1FilterValues[1]);
                monoMassIndex++;
            }

            if (!q1FilterValues.Any())
            {
                // This should never happen, but just in case it does happen, we safely exit the constructor
                ExpectedPeaks = ImmutableList.Singleton(new MzRankProportion(monoMz, 0, 1.0f));
                MonoMassIndex = BaseMassIndex = 0;
                return;
            }

            var signedQ1FilterValues = q1FilterValues.Select(q => new SignedMz(q, adduct.AdductCharge < 0)).ToList();

            // Use the filtering algorithm that will be used on real data to determine the
            // expected proportions of the mass distribution that will end up filtered into
            // peaks
            // CONSIDER: Mass accuracy information is not calculated here
            var key    = new PrecursorTextId(signedQ1FilterValues[monoMassIndex], null, null, ChromExtractor.summed);
            var filter = new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, 0, null, null, false, false);

            filter.AddQ1FilterValues(signedQ1FilterValues, calcFilterWindow);

            var expectedSpectrum = filter.FilterQ1SpectrumList(new[] { new MsDataSpectrum
                                                                       {
                                                                           Mzs = massDistribution.Keys.ToArray(), Intensities = massDistribution.Values.ToArray(), NegativeCharge = (adduct.AdductCharge < 0)
                                                                       } });

            int startIndex = expectedSpectrum.Intensities.IndexOf(inten => inten >= minimumAbundance);

            if (startIndex == -1)
            {
                // This can happen if the amino acid modifications are messed up,
                // and the peptide mass is negative or something.
                ExpectedPeaks = ImmutableList.Singleton(new MzRankProportion(monoMz, 0, 1.0f));
                MonoMassIndex = BaseMassIndex = 0;
                return;
            }
            // Always include the M-1 peak, even if it is expected to have zero intensity
            if (startIndex > monoMassIndex - 1)
            {
                startIndex = monoMassIndex - 1;
            }
            if (startIndex < 0)
            {
                startIndex = 0;
            }
            int endIndex              = expectedSpectrum.Intensities.LastIndexOf(inten => inten >= minimumAbundance) + 1;
            int countPeaks            = endIndex - startIndex;
            var listProportionIndices = new List <KeyValuePair <float, int> >(countPeaks);

            for (int i = 0; i < countPeaks; i++)
            {
                listProportionIndices.Add(new KeyValuePair <float, int>(
                                              expectedSpectrum.Intensities[i + startIndex], i));
            }
            // Sort proportions descending.
            listProportionIndices.Sort((p1, p2) => Comparer.Default.Compare(p2.Key, p1.Key));

            // Set proportions and ranks back in the original locations
            var expectedProportionRanks = new KeyValuePair <float, int> [countPeaks];

            for (int i = 0; i < countPeaks; i++)
            {
                expectedProportionRanks[listProportionIndices[i].Value] =
                    new KeyValuePair <float, int>(listProportionIndices[i].Key, i + 1);
            }

            MonoMassIndex = monoMassIndex - startIndex;

            // Find the base peak and fill in the masses and proportions
            var expectedPeaks = new List <MzRankProportion>();

            for (int i = 0; i < countPeaks; i++)
            {
                float expectedProportion = expectedProportionRanks[i].Key;
                int   rank = expectedProportionRanks[i].Value;
                expectedPeaks.Add(new MzRankProportion(q1FilterValues[i + startIndex], rank, expectedProportion));
                if (expectedProportion > expectedProportionRanks[BaseMassIndex].Key)
                {
                    BaseMassIndex = i;
                }
            }
            ExpectedPeaks = expectedPeaks;
        }
Example #22
0
 public static TypedMass CalcMass(TypedMass massH, TransitionLosses losses)
 {
     return(massH - (losses != null ? losses.Mass : 0));
 }
Example #23
0
 public void CalcMass(SequenceMassCalc massCalc)
 {
     MassH = massCalc.GetPrecursorMass(Target.Sequence);
 }
Example #24
0
        public void OkDialog()
        {
            var helper = new MessageBoxHelper(this);
            var charge = 0;

            if (textCharge.Visible &&
                !helper.ValidateSignedNumberTextBox(textCharge, _minCharge, _maxCharge, out charge))
            {
                return;
            }
            var adduct = Adduct.NonProteomicProtonatedFromCharge(charge);

            if (RetentionTimeWindow.HasValue && !RetentionTime.HasValue)
            {
                helper.ShowTextBoxError(textRetentionTimeWindow,
                                        Resources
                                        .Peptide_ExplicitRetentionTimeWindow_Explicit_retention_time_window_requires_an_explicit_retention_time_value_);
                return;
            }
            if (Adduct.IsEmpty || Adduct.AdductCharge != adduct.AdductCharge)
            {
                Adduct =
                    adduct; // Note: order matters here, this settor indirectly updates _formulaBox.MonoMass when formula is empty
            }
            if (string.IsNullOrEmpty(_formulaBox.NeutralFormula))
            {
                // Can the text fields be understood as mz?
                if (!_formulaBox.ValidateAverageText(helper))
                {
                    return;
                }
                if (!_formulaBox.ValidateMonoText(helper))
                {
                    return;
                }
            }
            var monoMass    = new TypedMass(_formulaBox.MonoMass ?? 0, MassType.Monoisotopic);
            var averageMass = new TypedMass(_formulaBox.AverageMass ?? 0, MassType.Average);

            if (monoMass < CustomMolecule.MIN_MASS || averageMass < CustomMolecule.MIN_MASS)
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    string.Format(
                                                        Resources
                                                        .EditCustomMoleculeDlg_OkDialog_Custom_molecules_must_have_a_mass_greater_than_or_equal_to__0__,
                                                        CustomMolecule.MIN_MASS));
                return;
            }
            if (monoMass > CustomMolecule.MAX_MASS || averageMass > CustomMolecule.MAX_MASS)
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    string.Format(
                                                        Resources
                                                        .EditCustomMoleculeDlg_OkDialog_Custom_molecules_must_have_a_mass_less_than_or_equal_to__0__,
                                                        CustomMolecule.MAX_MASS));
                return;
            }

            if ((_transitionSettings != null) &&
                (!_transitionSettings.IsMeasurablePrecursor(
                     adduct.MzFromNeutralMass(monoMass, MassType.Monoisotopic)) ||
                 !_transitionSettings.IsMeasurablePrecursor(adduct.MzFromNeutralMass(averageMass, MassType.Average))))
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    Resources
                                                    .SkylineWindow_AddMolecule_The_precursor_m_z_for_this_molecule_is_out_of_range_for_your_instrument_settings_);
                return;
            }
            if (_usageMode == UsageMode.precursor)
            {
                // Only the adduct should be changing
                SetResult(_resultCustomMolecule, Adduct);
            }
            else if (!string.IsNullOrEmpty(_formulaBox.NeutralFormula))
            {
                try
                {
                    var name = textName.Text;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = _formulaBox.NeutralFormula; // Clip off any adduct description
                    }
                    SetResult(new CustomMolecule(_formulaBox.NeutralFormula, name), Adduct);
                }
                catch (InvalidDataException x)
                {
                    _formulaBox.ShowTextBoxErrorFormula(helper, x.Message);
                    return;
                }
            }
            else
            {
                SetResult(new CustomMolecule(monoMass, averageMass, textName.Text), Adduct);
            }
            // Did user change the list of heavy labels?
            if (_driverLabelType != null)
            {
                PeptideModifications modifications = new PeptideModifications(
                    _peptideSettings.Modifications.StaticModifications,
                    _peptideSettings.Modifications.MaxVariableMods,
                    _peptideSettings.Modifications.MaxNeutralLosses,
                    _driverLabelType.GetHeavyModifications(), // This is the only thing the user may have altered
                    _peptideSettings.Modifications.InternalStandardTypes);
                var settings = _peptideSettings.ChangeModifications(modifications);
                // Only update if anything changed
                if (!Equals(settings, _peptideSettings))
                {
                    SrmSettings newSettings = _parent.DocumentUI.Settings.ChangePeptideSettings(settings);
                    if (!_parent.ChangeSettings(newSettings, true))
                    {
                        return;
                    }
                    _peptideSettings = newSettings.PeptideSettings;
                }
            }

            // See if this combination of charge and label would conflict with any existing transition groups
            if (_existingIds != null && _existingIds.Any(t =>
            {
                var transitionGroup = t as TransitionGroup;
                return(transitionGroup != null && Equals(transitionGroup.LabelType, IsotopeLabelType) &&
                       Equals(transitionGroup.PrecursorAdduct.AsFormula(),
                              Adduct
                              .AsFormula()) &&  // Compare AsFormula so proteomic and non-proteomic protonation are seen as same thing
                       !ReferenceEquals(t, _initialId));
            }))
            {
                helper.ShowTextBoxError(textName,
                                        Resources
                                        .EditCustomMoleculeDlg_OkDialog_A_precursor_with_that_adduct_and_label_type_already_exists_,
                                        textName.Text);
                return;
            }

            // See if this would conflict with any existing transitions
            if (_existingIds != null && (_existingIds.Any(t =>
            {
                var transition = t as Transition;
                return(transition != null && (Equals(transition.Adduct.AsFormula(), Adduct.AsFormula()) &&
                                              Equals(transition.CustomIon, ResultCustomMolecule)) &&
                       !ReferenceEquals(t, _initialId));
            })))
            {
                helper.ShowTextBoxError(textName,
                                        Resources.EditCustomMoleculeDlg_OkDialog_A_similar_transition_already_exists_, textName.Text);
                return;
            }
            DialogResult = DialogResult.OK;
        }
Example #25
0
        private static void TestEditingTransitionAsMasses()
        {
            double massPrecisionTolerance = Math.Pow(10, -SequenceMassCalc.MassPrecision);
            var    doc = SkylineWindow.Document;

            RunUI(() =>
            {
                SkylineWindow.ExpandPrecursors();
                SkylineWindow.SequenceTree.SelectedNode = SkylineWindow.SequenceTree.Nodes[0].FirstNode.FirstNode.FirstNode;
            });
            var editMoleculeDlg =
                ShowDialog <EditCustomMoleculeDlg>(
                    () => SkylineWindow.ModifyTransition((TransitionTreeNode)SkylineWindow.SequenceTree.SelectedNode));
            var monoMass = new TypedMass(805, MassType.Monoisotopic);

            RunUI(() =>
            {
                Assert.AreEqual(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12),
                                editMoleculeDlg.FormulaBox.MonoMass ?? -1, massPrecisionTolerance);
                Assert.AreEqual(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12),
                                editMoleculeDlg.FormulaBox.AverageMass ?? -1, massPrecisionTolerance);
                Assert.AreEqual(BioMassCalc.CalculateIonMz(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12), editMoleculeDlg.Adduct), double.Parse(editMoleculeDlg.FormulaBox.MonoText), massPrecisionTolerance);
                Assert.AreEqual(BioMassCalc.CalculateIonMz(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12), editMoleculeDlg.Adduct), double.Parse(editMoleculeDlg.FormulaBox.AverageText), massPrecisionTolerance);

                Assert.AreEqual(Adduct.M_PLUS.AdductFormula, editMoleculeDlg.FormulaBox.Adduct.AdductFormula);
                editMoleculeDlg.FormulaBox.AverageMass = 800;
                editMoleculeDlg.FormulaBox.MonoMass    = monoMass.Value;
                editMoleculeDlg.NameText = "Fragment";
            });
            OkDialog(editMoleculeDlg, editMoleculeDlg.OkDialog);
            var newdoc = WaitForDocumentChange(doc);

            Assert.AreEqual("Fragment", newdoc.MoleculeTransitions.ElementAt(0).Transition.CustomIon.ToString());
            Assert.AreEqual(BioMassCalc.CalculateIonMz(monoMass, editMoleculeDlg.Adduct), newdoc.MoleculeTransitions.ElementAt(0).Mz, massPrecisionTolerance);
            Assert.IsFalse(ReferenceEquals(doc.MoleculeTransitions.ElementAt(0).Id, newdoc.MoleculeTransitions.ElementAt(0).Id)); // Changing the mass changes the Id

            // Verify that tree selection doesn't change just because we changed an ID object
            // (formerly the tree node would collapse and focus would jump up a level)
            RunUI(() =>
            {
                Assert.AreEqual(SkylineWindow.SequenceTree.SelectedNode, SkylineWindow.SequenceTree.Nodes[0].FirstNode.FirstNode.FirstNode);
            });

            // And test undo/redo
            RunUI(() => SkylineWindow.Undo());
            newdoc = WaitForDocumentChange(newdoc);
            Assert.AreNotEqual("Fragment", newdoc.MoleculeTransitions.ElementAt(0).Transition.CustomIon.ToString());
            Assert.AreNotEqual(BioMassCalc.CalculateIonMz(monoMass, editMoleculeDlg.Adduct), newdoc.MoleculeTransitions.ElementAt(0).Mz, massPrecisionTolerance);
            Assert.IsTrue(ReferenceEquals(doc.MoleculeTransitions.ElementAt(0).Id, newdoc.MoleculeTransitions.ElementAt(0).Id));
            RunUI(() => SkylineWindow.Redo());
            newdoc = WaitForDocumentChange(newdoc);
            Assert.AreEqual("Fragment", newdoc.MoleculeTransitions.ElementAt(0).Transition.CustomIon.ToString());
            Assert.AreEqual(BioMassCalc.CalculateIonMz(monoMass, editMoleculeDlg.Adduct), newdoc.MoleculeTransitions.ElementAt(0).Mz, massPrecisionTolerance);

            // Verify that tree selection doesn't change just because we changed an ID object
            // (formerly the tree node would collapse and focus would jump up a level)
            RunUI(() =>
            {
                Assert.AreEqual(SkylineWindow.SequenceTree.SelectedNode, SkylineWindow.SequenceTree.Nodes[0].FirstNode.FirstNode.FirstNode);
            });
        }
Example #26
0
            public static TransitionQuantInfo GetTransitionQuantInfo(Transition transition, TransitionLosses losses, IsotopeDistInfo isotopeDist, TypedMass massH, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> ranks)
            {
                var transitionIsotopeDistInfo = GetIsotopeDistInfo(transition, losses, isotopeDist);

                return(GetLibTransitionQuantInfo(transition, losses, massH, ranks).ChangeIsotopeDistInfo(transitionIsotopeDistInfo));
            }
Example #27
0
            public static TransitionQuantInfo GetLibTransitionQuantInfo(Transition transition, TransitionLosses losses, TypedMass massH,
                                                                        IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> ranks)
            {
                LibraryRankedSpectrumInfo.RankedMI rmi = null;
                if (ranks != null)
                {
                    ranks.TryGetValue(SequenceMassCalc.GetMZ(massH, transition.Adduct), out rmi);
                }
                TransitionLibInfo transitionLibInfo = null;

                if (rmi != null)
                {
                    transitionLibInfo = new TransitionLibInfo(rmi.Rank, rmi.Intensity);
                }
                return(new TransitionQuantInfo(null, transitionLibInfo,
                                               rmi == null || rmi.Quantitative));
            }
Example #28
0
        public static Adduct CalcProductCharge(TypedMass productPrecursorMass,
                                               Adduct precursorCharge,
                                               IList <IonType> acceptedIonTypes,
                                               IonTable <TypedMass> productMasses,
                                               IList <IList <ExplicitLoss> > potentialLosses,
                                               double productMz,
                                               double tolerance,
                                               MassType massType,
                                               MassShiftType massShiftType,
                                               out IonType?ionType,
                                               out int?ordinal,
                                               out TransitionLosses losses,
                                               out int massShift)
        {
            // Get length of fragment ion mass array
            int len = productMasses.GetLength(1);

            // Check all possible ion types and offsets
            double?          minDelta      = null;
            var              bestCharge    = Adduct.EMPTY;
            IonType?         bestIonType   = null;
            int?             bestOrdinal   = null;
            TransitionLosses bestLosses    = null;
            int              bestMassShift = 0;

            // Check to see if it is the precursor
            foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(IonType.precursor, 0, massType, potentialLosses))
            {
                var productMass = productPrecursorMass - (lossesTrial != null ? lossesTrial.Mass : 0);
                int potentialMassShift;
                int nearestCharge;
                var charge = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge,
                                               massShiftType, out potentialMassShift, out nearestCharge);
                if (Equals(charge, precursorCharge))
                {
                    double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift;
                    double delta       = Math.Abs(productMz - potentialMz);

                    if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0)
                    {
                        bestCharge    = charge;
                        bestIonType   = IonType.precursor;
                        bestOrdinal   = len + 1;
                        bestLosses    = lossesTrial;
                        bestMassShift = potentialMassShift;

                        minDelta = delta;
                    }
                }
            }

            var categoryLast = -1;

            foreach (var typeAccepted in GetIonTypes(acceptedIonTypes))
            {
                var type     = typeAccepted.IonType;
                var category = typeAccepted.IonCategory;

                // Types have priorities.  If changing type category, and there is already a
                // suitable answer stop looking.
                if (category != categoryLast && minDelta.HasValue && MatchMz(minDelta.Value, tolerance))
                {
                    break;
                }
                categoryLast = category;

                for (int offset = 0; offset < len; offset++)
                {
                    foreach (var lossesTrial in TransitionGroup.CalcTransitionLosses(type, offset, massType, potentialLosses))
                    {
                        // Look for the closest match.
                        var productMass = productMasses[type, offset];
                        if (lossesTrial != null)
                        {
                            productMass -= lossesTrial.Mass;
                        }
                        int potentialMassShift;
                        int nearestCharge;
                        var chargeFound = CalcProductCharge(productMass, productMz, tolerance, false, precursorCharge,
                                                            massShiftType, out potentialMassShift, out nearestCharge);
                        if (!chargeFound.IsEmpty)
                        {
                            var    charge      = chargeFound;
                            double potentialMz = SequenceMassCalc.GetMZ(productMass, charge) + potentialMassShift;
                            double delta       = Math.Abs(productMz - potentialMz);
                            if (CompareIonMatch(delta, lossesTrial, potentialMassShift, minDelta, bestLosses, bestMassShift) < 0)
                            {
                                bestCharge  = charge;
                                bestIonType = type;
                                // The peptide length is 1 longer than the mass array
                                bestOrdinal   = Transition.OffsetToOrdinal(type, offset, len + 1);
                                bestLosses    = lossesTrial;
                                bestMassShift = potentialMassShift;

                                minDelta = delta;
                            }
                        }
                    }
                }
            }

            ionType   = bestIonType;
            ordinal   = bestOrdinal;
            losses    = bestLosses;
            massShift = bestMassShift;
            return(bestCharge);
        }
Example #29
0
        private TransitionDocNode CreateTransitionNode(IonType type, int cleavageOffset, Adduct charge, TypedMass massH,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, CustomMolecule customMolecule = null)
        {
            Transition transition = new Transition(this, type, cleavageOffset, 0, charge, null, customMolecule);
            var        info       = TransitionDocNode.TransitionQuantInfo.GetLibTransitionQuantInfo(transition, losses, Transition.CalcMass(massH, losses), transitionRanks);

            return(new TransitionDocNode(transition, losses, massH, info));
        }
Example #30
0
        public void OkDialog()
        {
            var helper = new MessageBoxHelper(this);
            var charge = 0;

            if (textCharge.Visible &&
                !helper.ValidateSignedNumberTextBox(textCharge, _minCharge, _maxCharge, out charge))
            {
                return;
            }
            var adduct = Adduct.NonProteomicProtonatedFromCharge(charge);

            if (RetentionTimeWindow.HasValue && !RetentionTime.HasValue)
            {
                helper.ShowTextBoxError(textRetentionTimeWindow,
                                        Resources
                                        .Peptide_ExplicitRetentionTimeWindow_Explicit_retention_time_window_requires_an_explicit_retention_time_value_);
                return;
            }
            if (Adduct.IsEmpty || Adduct.AdductCharge != adduct.AdductCharge)
            {
                Adduct =
                    adduct; // Note: order matters here, this settor indirectly updates _formulaBox.MonoMass when formula is empty
            }
            if (string.IsNullOrEmpty(_formulaBox.NeutralFormula))
            {
                // Can the text fields be understood as mz?
                if (!_formulaBox.ValidateAverageText(helper))
                {
                    return;
                }
                if (!_formulaBox.ValidateMonoText(helper))
                {
                    return;
                }
            }
            var monoMass    = new TypedMass(_formulaBox.MonoMass ?? 0, MassType.Monoisotopic);
            var averageMass = new TypedMass(_formulaBox.AverageMass ?? 0, MassType.Average);

            if (monoMass < CustomMolecule.MIN_MASS || averageMass < CustomMolecule.MIN_MASS)
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    string.Format(
                                                        Resources
                                                        .EditCustomMoleculeDlg_OkDialog_Custom_molecules_must_have_a_mass_greater_than_or_equal_to__0__,
                                                        CustomMolecule.MIN_MASS));
                return;
            }
            if (monoMass > CustomMolecule.MAX_MASS || averageMass > CustomMolecule.MAX_MASS)
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    string.Format(
                                                        Resources
                                                        .EditCustomMoleculeDlg_OkDialog_Custom_molecules_must_have_a_mass_less_than_or_equal_to__0__,
                                                        CustomMolecule.MAX_MASS));
                return;
            }

            if ((_transitionSettings != null) &&
                (!_transitionSettings.IsMeasurablePrecursor(
                     adduct.MzFromNeutralMass(monoMass, MassType.Monoisotopic)) ||
                 !_transitionSettings.IsMeasurablePrecursor(adduct.MzFromNeutralMass(averageMass, MassType.Average))))
            {
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    Resources
                                                    .SkylineWindow_AddMolecule_The_precursor_m_z_for_this_molecule_is_out_of_range_for_your_instrument_settings_);
                return;
            }

            // Ion mobility value must have ion mobility units
            if (textIonMobility.Visible && IonMobility.HasValue)
            {
                if (IonMobilityUnits == eIonMobilityUnits.none)
                {
                    helper.ShowTextBoxError(textIonMobility, Resources.EditCustomMoleculeDlg_OkDialog_Please_specify_the_ion_mobility_units_);
                    comboBoxIonMobilityUnits.Focus();
                    return;
                }

                if (IonMobility.Value == 0 ||
                    (IonMobility.Value < 0 && !IonMobilityFilter.AcceptNegativeMobilityValues(IonMobilityUnits)))
                {
                    helper.ShowTextBoxError(textIonMobility,
                                            string.Format(Resources.SmallMoleculeTransitionListReader_ReadPrecursorOrProductColumns_Invalid_ion_mobility_value__0_, IonMobility));
                    textIonMobility.Focus();
                    return;
                }
            }
            if (_usageMode == UsageMode.precursor)
            {
                // Only the adduct should be changing
                SetResult(_resultCustomMolecule, Adduct);
            }
            else if (!string.IsNullOrEmpty(_formulaBox.NeutralFormula))
            {
                try
                {
                    var name = textName.Text;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = _formulaBox.NeutralFormula; // Clip off any adduct description
                    }
                    SetResult(new CustomMolecule(_formulaBox.NeutralFormula, name), Adduct);
                }
                catch (InvalidDataException x)
                {
                    _formulaBox.ShowTextBoxErrorFormula(helper, x.Message);
                    return;
                }
            }
            else
            {
                SetResult(new CustomMolecule(monoMass, averageMass, textName.Text), Adduct);
            }
            // Did user change the list of heavy labels?
            if (_driverLabelType != null)
            {
                // This is the only thing the user may have altered
                var newHeavyMods = _driverLabelType.GetHeavyModifications().ToArray();
                if (!ArrayUtil.EqualsDeep(newHeavyMods, _peptideSettings.Modifications.HeavyModifications))
                {
                    var labelTypes = _peptideSettings.Modifications.InternalStandardTypes.Where(t =>
                                                                                                newHeavyMods.Any(m => Equals(m.LabelType, t))).ToArray();
                    if (labelTypes.Length == 0)
                    {
                        labelTypes = new[] { newHeavyMods.First().LabelType }
                    }
                    ;

                    PeptideModifications modifications = new PeptideModifications(
                        _peptideSettings.Modifications.StaticModifications,
                        _peptideSettings.Modifications.MaxVariableMods,
                        _peptideSettings.Modifications.MaxNeutralLosses,
                        newHeavyMods,
                        labelTypes);
                    var         settings    = _peptideSettings.ChangeModifications(modifications);
                    SrmSettings newSettings = _parent.DocumentUI.Settings.ChangePeptideSettings(settings);
                    if (!_parent.ChangeSettings(newSettings, true))
                    {
                        // Not expected, since we checked for a change before calling
                        // Otherwise, this is very confusing. The form just refuses to go away
                        // We would prefer to get an unhandled exception and fix this
                        Assume.Fail();
                        return;
                    }
                    _peptideSettings = newSettings.PeptideSettings;
                }
            }

            // See if this combination of charge and label would conflict with any existing transition groups
            if (_existingIds != null && _existingIds.Any(t =>
            {
                var transitionGroup = t as TransitionGroup;
                return(transitionGroup != null && Equals(transitionGroup.LabelType, IsotopeLabelType) &&
                       Equals(transitionGroup.PrecursorAdduct.AsFormula(),
                              Adduct
                              .AsFormula()) &&  // Compare AsFormula so proteomic and non-proteomic protonation are seen as same thing
                       !ReferenceEquals(t, _initialId));
            }))
            {
                helper.ShowTextBoxError(textName,
                                        Resources
                                        .EditCustomMoleculeDlg_OkDialog_A_precursor_with_that_adduct_and_label_type_already_exists_,
                                        textName.Text);
                return;
            }

            // See if this would conflict with any existing transitions
            if (_existingIds != null && (_existingIds.Any(t =>
            {
                var transition = t as Transition;
                return(transition != null && (Equals(transition.Adduct.AsFormula(), Adduct.AsFormula()) &&
                                              Equals(transition.CustomIon, ResultCustomMolecule)) &&
                       !ReferenceEquals(t, _initialId));
            })))
            {
                helper.ShowTextBoxError(textName,
                                        Resources.EditCustomMoleculeDlg_OkDialog_A_similar_transition_already_exists_, textName.Text);
                return;
            }
            DialogResult = DialogResult.OK;
        }