Beispiel #1
0
        private void TestTaxolAdduct(string adductText, double expectedMz, int expectedCharge, HashSet <string> coverage)
        {
            // See http://fiehnlab.ucdavis.edu/staff/kind/Metabolomics/MS-Adduct-Calculator/
            var Taxol    = "C47H51NO14"; // M=853.33089 (agrees with chemspider)
            var calcMass = BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(Taxol);

            Assert.AreEqual(massTaxol, calcMass, .0001);
            var adduct = Adduct.FromStringAssumeProtonated(adductText);

            Assert.AreEqual(expectedCharge, adduct.AdductCharge);
            var mz = BioMassCalc.CalculateIonMz(calcMass, adduct);

            Assert.AreEqual(expectedMz, mz, .001);
            var massWithIsotopes = adduct.MassFromMz(mz, MassType.Monoisotopic);

            Assert.AreEqual(massTaxol, massWithIsotopes - adduct.GetIsotopesIncrementalMonoisotopicMass() / adduct.GetMassMultiplier(), .0001);
            coverage.Add(adduct.AsFormula());
        }
Beispiel #2
0
        public Adduct GetProductAdduct(Adduct precursorAdduct)
        {
            var totalCharge = TotalCharge;

            if (totalCharge == 0)
            {
                return(precursorAdduct);
            }

            var newCharge = precursorAdduct.AdductCharge - totalCharge;

            if (Math.Sign(newCharge) != Math.Sign(precursorAdduct.AdductCharge))
            {
                return(null);
            }

            return(precursorAdduct.ChangeCharge(newCharge));
        }
 private static void CheckRefSpectra(IList <DbRefSpectra> spectra, string name, string formula, string precursorAdduct, double precursorMz, ushort numPeaks)
 {
     name = RefinementSettings.TestingConvertedFromProteomicPeptideNameDecorator + name;
     for (var i = 0; i < spectra.Count; i++)
     {
         var spectrum = spectra[i];
         if (spectrum.MoleculeName.Equals(name) &&
             spectrum.ChemicalFormula.Equals(formula) &&
             spectrum.PrecursorCharge.Equals(Adduct.FromStringAssumeProtonated(precursorAdduct).AdductCharge) &&
             spectrum.PrecursorAdduct.Equals(precursorAdduct) &&
             Math.Abs(spectrum.PrecursorMZ - precursorMz) < 0.001 &&
             spectrum.NumPeaks.Equals(numPeaks))
         {
             spectra.RemoveAt(i);
             return;
         }
     }
     Assume.Fail(string.Format("{0}, {1}, precursor charge {2}, precursor m/z {3}, with {4} peaks not found", name, formula, precursorAdduct, precursorMz, numPeaks));
 }
Beispiel #4
0
        private static void VerifySharedDocLibraryAnnotations(string shareDocPath)
        {
            RunUI(() => SkylineWindow.OpenSharedFile(shareDocPath));
            var doc = WaitForDocumentLoaded();

            AssertEx.IsDocumentState(doc, null, 1, 4, 4, 4); // int revision, int groups, int peptides, int tranGroups, int transitions
            SpectrumPeaksInfo spectrum;
            IsotopeLabelType  label;

            // ReSharper disable PossibleNullReferenceException
            doc.Settings.TryLoadSpectrum(doc.Molecules.FirstOrDefault().Target, Adduct.FromStringAssumeChargeOnly("M+NH4"),
                                         null, out label, out spectrum);
            Assume.IsTrue(spectrum.Annotations.Count() == 1);
            var spectrumPeakAnnotations = (spectrum.Annotations.FirstOrDefault() ?? new SpectrumPeakAnnotation[0]).ToArray();

            Assume.IsTrue(spectrumPeakAnnotations.Length == 1);
            Assume.IsTrue(spectrumPeakAnnotations.FirstOrDefault().Ion.Name == "GP");
            // ReSharper restore PossibleNullReferenceException
        }
Beispiel #5
0
        public static Adduct GetChargeFromIndicator(string text, int min, int max, out int foundAt)
        {
            foundAt = -1;
            if (!MayHaveChargeIndicator(text))
            {
                return(Adduct.EMPTY);
            }

            // Handle runs of charge characters no matter how long, because users guess this should work
            foundAt = FindChargeSymbolRepeatStart('+', text, min, max);
            if (foundAt != -1)
            {
                return(Adduct.FromChargeProtonated(text.Length - foundAt));
            }
            foundAt = FindChargeSymbolRepeatStart('-', text, min, max);
            if (foundAt != -1)
            {
                return(Adduct.FromChargeProtonated(foundAt - text.Length));
            }

            Adduct adduct;

            for (int i = max; i >= min; i--)
            {
                adduct = GetChargeFromIndicator(text, i, out foundAt);
                if (!adduct.IsEmpty)
                {
                    return(adduct);
                }
                adduct = GetChargeFromIndicator(text, -i, out foundAt);
                if (!adduct.IsEmpty)
                {
                    return(adduct);
                }
            }
            foundAt = FindAdductDescription(text, out adduct);
            if (foundAt != -1)
            {
                return(adduct);
            }
            return(Adduct.EMPTY);
        }
Beispiel #6
0
        public Transition(TransitionGroup group, IonType type, int?offset, int?massIndex, Adduct adduct,
                          int?decoyMassShift, CustomMolecule customMolecule = null)
        {
            _group = group;

            IonType        = type;
            CleavageOffset = offset ?? 0;
            MassIndex      = massIndex ?? 0;
            Adduct         = adduct;
            DecoyMassShift = decoyMassShift;
            // Small molecule precursor transition should have same custom molecule as parent
            if (IsPrecursor(type) && group.IsCustomIon)
            {
                CustomIon = new CustomIon(group.CustomMolecule, adduct);
            }
            else if (customMolecule is CustomIon)
            {
                // As with reporter ions
                CustomIon = (CustomIon)customMolecule;
                Assume.IsTrue(Equals(adduct.AdductCharge, CustomIon.Adduct.AdductCharge));
                Adduct = CustomIon.Adduct; // Ion mass is part of formula, so use charge only adduct
            }
            else if (customMolecule != null)
            {
                CustomIon = new CustomIon(customMolecule, adduct);
            }
            // Derived values
            if (!IsCustom(type, group))
            {
                Peptide peptide = group.Peptide;
                Ordinal = OffsetToOrdinal(type, (int)offset, peptide.Length);
                AA      = (IsNTerminal()
                    ? peptide.Sequence[(int)offset]
                    : peptide.Sequence[(int)offset + 1]);
            }
            else
            {
                // caller may have passed in offset = group.Peptide.Length - 1, which for custom ions gives -1
                CleavageOffset = 0;
            }
            Validate();
        }
Beispiel #7
0
        private static int FindChargeIndicatorPos(string line, int min, int max, CultureInfo cultureInfo)
        {
            for (int i = max; i >= min; i--)
            {
                // Handle negative charges
                int pos = FindChargeIndicatorPos(line, GetChargeIndicator(Adduct.FromChargeProtonated(-i), cultureInfo));
                if (pos != -1)
                {
                    return(pos);
                }
                // Handle positive charges
                pos = FindChargeIndicatorPos(line, GetChargeIndicator(Adduct.FromChargeProtonated(i), cultureInfo));
                if (pos != -1)
                {
                    return(pos);
                }
            }

            return(-1);
        }
        private bool DeriveAdductsForCommonFormula(Peptide peptide)
        {
            // Try to come up with a set of adducts to common formula that explain the declared mz values
            var success = false;

            if (_precursorRawDetails.TrueForAll(d => Adduct.IsNullOrEmpty(d._nominalAdduct)))
            {
                // No explicit adducts, just charges.
                // Start with the most common scenario, which is that the user meant (de)protonation
                // See if we can arrive at a common formula ( by adding or removing H) that works with all charges as (de)protonations
                // N.B. the parent molecule may well be completely unrelated to the children, as users were allowed to enter anything they wanted
                var commonFormula          = ProposedMolecule.Formula;
                var precursorsWithFormulas = _precursorRawDetails.Where(d => !string.IsNullOrEmpty(d._formulaUnlabeled)).ToList();
                foreach (var detail in precursorsWithFormulas)
                {
                    var revisedCommonFormula = Molecule.AdjustElementCount(commonFormula, BioMassCalc.H, -detail._declaredCharge);
                    var adjustedMolecule     = new CustomMolecule(revisedCommonFormula, peptide.CustomMolecule.Name);
                    var mass = adjustedMolecule.MonoisotopicMass;
                    if (precursorsWithFormulas.TrueForAll(d =>
                    {
                        d._proposedAdduct = Adduct.ProtonatedFromFormulaDiff(d._formulaUnlabeled, revisedCommonFormula, d._declaredCharge)
                                            .ChangeIsotopeLabels(d._labels);
                        return(Math.Abs(d._declaredMz - d._proposedAdduct.MzFromNeutralMass(mass)) <= MzToler);
                    }))
                    {
                        ProposedMolecule = adjustedMolecule;
                        success          = true;
                        break;
                    }
                }
                success &= _precursorRawDetails.All(d => !Adduct.IsNullOrEmpty(d._proposedAdduct));
                if (!success)
                {
                    foreach (var d in _precursorRawDetails)
                    {
                        d._proposedAdduct = Adduct.EMPTY;
                    }
                }
            }
            return(success);
        }
Beispiel #9
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);
        }
Beispiel #10
0
        private void LoadPeptides(IEnumerable <DbIonMobilityPeptide> peptides)
        {
            var dictLibrary = new Dictionary <LibKey, DbIonMobilityPeptide>();

            foreach (var pep in peptides)
            {
                var dict = dictLibrary;
                try
                {
                    DbIonMobilityPeptide ignored;
                    var adduct = pep.GetPrecursorAdduct();
                    if (adduct.IsEmpty)
                    {
                        // Older formats didn't consider charge to be a factor is CCS, so just fake up M+H, M+2H and M+3H
                        for (int z = 1; z <= 3; z++)
                        {
                            var newPep = new DbIonMobilityPeptide(pep.GetNormalizedModifiedSequence(),
                                                                  Adduct.FromChargeProtonated(z), pep.CollisionalCrossSection, pep.HighEnergyDriftTimeOffsetMsec);
                            var key = newPep.GetLibKey();
                            if (!dict.TryGetValue(key, out ignored))
                            {
                                dict.Add(key, newPep);
                            }
                        }
                    }
                    else
                    {
                        var key = pep.GetLibKey();
                        if (!dict.TryGetValue(key, out ignored))
                        {
                            dict.Add(key, pep);
                        }
                    }
                }
                catch (ArgumentException)
                {
                }
            }

            DictLibrary = dictLibrary;
        }
Beispiel #11
0
 public void WriteXml(XmlWriter writer, Adduct adduct)
 {
     if (adduct.IsEmpty)
     {
         writer.WriteAttributeIfString(ATTR.neutral_formula, Formula);
     }
     else
     {
         writer.WriteAttributeIfString(ATTR.ion_formula,
                                       (Formula ?? string.Empty) +
                                       (adduct.IsProteomic ? string.Empty : adduct.ToString()));
     }
     Assume.IsFalse(AverageMass.IsMassH()); // We're going to read these as neutral masses
     Assume.IsFalse(MonoisotopicMass.IsMassH());
     writer.WriteAttributeNullable(ATTR.neutral_mass_average, AverageMass);
     writer.WriteAttributeNullable(ATTR.neutral_mass_monoisotopic, MonoisotopicMass);
     if (!string.IsNullOrEmpty(Name))
     {
         writer.WriteAttribute(ATTR.custom_ion_name, Name);
     }
     writer.WriteAttributeIfString(ATTR.id, AccessionNumbers.ToSerializableString());
 }
Beispiel #12
0
        // Helper function for PrecursorIonFormula and PrecursorNeutralFormula
        private void GetPrecursorFormulaAndAdduct(out Adduct adduct, out string formula)
        {
            if (IsSmallMolecule())
            {
                formula = (DocNode.CustomMolecule.Formula ?? string.Empty);
                adduct  = DocNode.PrecursorAdduct;
            }
            else
            {
                PeptideDocNode parent = DataSchema.Document.FindNode(IdentityPath.Parent) as PeptideDocNode;
                if (parent == null)
                {
                    adduct  = Util.Adduct.EMPTY;
                    formula = String.Empty;
                    return;
                }

                var molecule = RefinementSettings.ConvertToSmallMolecule(
                    RefinementSettings.ConvertToSmallMoleculesMode.formulas, SrmDocument, parent, out adduct,
                    DocNode.TransitionGroup.PrecursorAdduct.AdductCharge, DocNode.TransitionGroup.LabelType);
                formula = molecule.Formula ?? string.Empty;
            }
        }
Beispiel #13
0
            public MockTranPeakData(double[] data,
                                    IonType ionType            = IonType.a,
                                    IsotopeLabelType labelType = null,
                                    int?charge               = null,
                                    double?massError         = null,
                                    double libIntensity      = 0,
                                    double?isotopeProportion = null)
            {
                if (labelType == null)
                {
                    labelType = IsotopeLabelType.light;
                }
                PeakData = new MockPeakData(data, massError) as TPeak;
                var peptide = new Peptide(null, "AVVAVVA", null, null, 0);

                charge = charge ?? 2;
                var tranGroup   = new TransitionGroup(peptide, Adduct.FromChargeProtonated(charge), labelType);
                int offset      = ionType == IonType.precursor ? 6 : 0;
                var isotopeInfo = isotopeProportion == null ? null : new TransitionIsotopeDistInfo(1, (float)isotopeProportion);

                NodeTran = new TransitionDocNode(new Transition(tranGroup, ionType, offset, 0, Adduct.FromChargeProtonated(charge), null),
                                                 null, TypedMass.ZERO_MONO_MASSH, new TransitionDocNode.TransitionQuantInfo(isotopeInfo, new TransitionLibInfo(1, (float)libIntensity), true));
            }
Beispiel #14
0
        private double?_monoMass;     // Our internal value for mass, regardless of whether displaying mass or mz

        /// <summary>
        /// Reusable control for dealing with chemical formulas and their masses
        /// </summary>
        /// <param name="isProteomic">if true, don't offer Cl, Br, or heavy P or heavy S in elements popup</param>
        /// <param name="labelFormulaText">Label text for the formula textedit control</param>
        /// <param name="labelAverageText">Label text for the average mass or m/z textedit control</param>
        /// <param name="labelMonoText">Label text for the monoisotopic mass or m/z textedit control</param>
        /// <param name="adduct">If non-null, treat the average and monoisotopic textedits as describing m/z instead of mass</param>
        /// <param name="mode">Controls editing of the formula and/or adduct edit</param>
        /// <param name="suggestOnlyAdductsWithMass">If presenting an adduct dropdown menu, do we include things like "[M+]"?</param>
        public FormulaBox(bool isProteomic, string labelFormulaText, string labelAverageText, string labelMonoText, Adduct adduct, EditMode mode = EditMode.formula_only, bool suggestOnlyAdductsWithMass = true)
        {
            InitializeComponent();
            if (isProteomic)
            {
                // Don't offer exotic atoms or isotopes
                p32ToolStripMenuItem.Visible                              =
                    s33ToolStripMenuItem.Visible                          =
                        s34ToolStripMenuItem.Visible                      =
                            h3ToolStripMenuItem.Visible                   =
                                clToolStripMenuItem.Visible               =
                                    cl37ToolStripMenuItem.Visible         =
                                        brToolStripMenuItem.Visible       =
                                            br81ToolStripMenuItem.Visible = false;
            }
            _adduct   = adduct;
            _editMode = mode;

            switch (mode)
            {
            case EditMode.adduct_only:
            case EditMode.formula_and_adduct:
                TransitionSettingsUI.AppendAdductMenus(contextFormula, suggestOnlyAdductsWithMass, adductStripMenuItem_Click);
                break;
            }

            toolTip1.SetToolTip(textFormula, _editMode == EditMode.adduct_only ? AdductHelpText : FormulaHelpText);  // Explain how formulas work, and ion formula adducts if charge.HasValue

            labelFormula.Text = labelFormulaText;
            labelAverage.Text = labelAverageText;
            labelMono.Text    = labelMonoText;

            Bitmap bm = Resources.PopupBtn;

            bm.MakeTransparent(Color.Fuchsia);
            btnFormula.Image = bm;
        }
        private TransitionDocNode TransitionFromPeakAndAnnotations(LibKey key, TransitionGroupDocNode nodeGroup,
                                                                   Adduct fragmentCharge, SpectrumPeaksInfo.MI peak, int?rank)
        {
            var charge           = fragmentCharge;
            var monoisotopicMass = charge.MassFromMz(peak.Mz, MassType.Monoisotopic);
            var averageMass      = charge.MassFromMz(peak.Mz, MassType.Average);
            // Caution here - library peak (observed) mz may not exactly match (theoretical) mz of the annotation

            // In the case of multiple annotations, produce single transition for display in library explorer
            var annotations = peak.GetAnnotationsEnumerator().ToArray();
            var spectrumPeakAnnotationIon = peak.AnnotationsAggregateDescriptionIon;
            var molecule = spectrumPeakAnnotationIon.Adduct.IsEmpty
                ? new CustomMolecule(monoisotopicMass, averageMass)
                : spectrumPeakAnnotationIon;
            var note = (annotations.Length > 1) ? TextUtil.LineSeparate(annotations.Select(a => a.ToString())) : null;
            var noteIfAnnotationMzDisagrees = NoteIfAnnotationMzDisagrees(key, peak);

            if (noteIfAnnotationMzDisagrees != null)
            {
                if (note == null)
                {
                    note = noteIfAnnotationMzDisagrees;
                }
                else
                {
                    note = TextUtil.LineSeparate(note, noteIfAnnotationMzDisagrees);
                }
            }
            var transition = new Transition(nodeGroup.TransitionGroup,
                                            spectrumPeakAnnotationIon.Adduct.IsEmpty ? charge : spectrumPeakAnnotationIon.Adduct, 0, molecule);

            return(new TransitionDocNode(transition, Annotations.EMPTY.ChangeNote(note), null, monoisotopicMass,
                                         rank.HasValue ?
                                         new TransitionDocNode.TransitionQuantInfo(null,
                                                                                   new TransitionLibInfo(rank.Value, peak.Intensity), true) :
                                         TransitionDocNode.TransitionQuantInfo.DEFAULT, ExplicitTransitionValues.EMPTY, null));
        }
Beispiel #16
0
        public static Adduct GetChargeFromIndicator(string text, int min, int max, out int foundAt)
        {
            foundAt = -1;
            if (!MayHaveChargeIndicator(text))
            {
                return(Adduct.EMPTY);
            }
            Adduct adduct;

            for (int i = max; i >= min; i--)
            {
                // Handle negative charges
                adduct = Adduct.FromChargeProtonated(-i);
                var chargeIndicator = GetChargeIndicator(adduct);
                if (text.EndsWith(chargeIndicator))
                {
                    foundAt = text.Length - chargeIndicator.Length;
                    return(adduct);
                }
                adduct          = Adduct.FromChargeProtonated(i);
                chargeIndicator = GetChargeIndicator(adduct);
                if (text.EndsWith(chargeIndicator))
                {
                    foundAt = text.Length - chargeIndicator.Length;
                    return(adduct);
                }
            }
            var adductStart = FindAdductDescription(text, out adduct);

            if (adductStart >= 0)
            {
                foundAt = adductStart;
                return(adduct);
            }
            return(Adduct.EMPTY);
        }
Beispiel #17
0
        protected override void DoTest()
        {
            var testFilesDir = TestFilesDir;

            // Verify our use of explict RT where multiple nodes and multiple chromatograms all have same Q1>Q3
            // This data set has three chromatograms with Q1=150 Q3=150 (one in negative ion mode), and
            // three transition nodes with that Q1>Q3 but different RTs (one with neg charge)
            // Expected alignment:
            // function 65/ index 242 : RT 6.95 glutamate
            // function 66/ index 243 : RT 7.95 glutamine (peak found at 8.1, but declared explicit RT window is 7.95 +/- .1 so no match)
            // function 197/ index 117 (neg ion mode): RT 6.4 alpha_ketogluterate
            DoSubTest(testFilesDir, "glutes.sky", new[] { 6.95, 0, 6.4 }, new[] { "090215_033" }, null,
                      new[] { Adduct.M_PLUS_H, Adduct.M_PLUS_H, Adduct.M_MINUS_H });

            // Verify our handling of two Q1>Q3 transitions with no RT overlap - formerly we just ignored one or the other though both are needed
            // As in https://skyline.gs.washington.edu/labkey/announcements/home/support/thread.view?entityId=924e3c51-7c00-1033-9ff1-da202582a252&_anchor=24723
            DoSubTest(testFilesDir, "lysine.sky", new[] { 13.8, 13.8, 13.8, 13.8 }, new[] { "ESvKprosp_20151120_035", "ESvKprosp_20151120_036" }, .5,
                      new[] { Adduct.M_PLUS_H, Adduct.FromStringAssumeChargeOnly("[M6C132N15+H]") });

            // Verify our use of explict RT in peak picking where the correct peak isn't the largest
            // As in https://skyline.gs.washington.edu/labkey/announcements/home/support/thread.view?entityId=273ccc30-8258-1033-9ff1-da202582a252&_anchor=24774
            DoSubTest(testFilesDir, "test_b.sky", new[] { 9.1, 9.1, 9.1, 9.1, 9.1, 9.1, 9.1, 9.1 }, new[] { "120315_120", "120315_121", "120315_125", "120315_126" }, null,
                      new[] { Adduct.M_PLUS_H, Adduct.M_PLUS_H });
        }
Beispiel #18
0
 /// <summary>
 /// Get a mass value from the text string, treating the string as m/z info if we have a charge state
 /// </summary>
 private double?GetMassFromText(string text, MassType massType)
 {
     try
     {
         if (String.IsNullOrEmpty(text))
         {
             return(null);
         }
         else
         {
             double parsed = double.Parse(text);
             if (!Adduct.IsEmpty)
             {
                 // Convert from m/z to mass
                 return(Adduct.MassFromMz(parsed, massType));
             }
             return(parsed);
         }
     }
     catch (Exception)
     {
         return(null);
     }
 }
Beispiel #19
0
        public static string GetChargeIndicator(Adduct adduct, CultureInfo cultureInfo)
        {
            if (!adduct.IsProteomic && !adduct.IsChargeOnly)
            {
                return(adduct.AsFormulaOrSignedInt());
            }
            var charge = adduct.AdductCharge;

            if (charge >= 0)
            {
                const string pluses = "++++";
                return(charge <= pluses.Length
                    ? pluses.Substring(0, Math.Min(charge, pluses.Length))
                    : string.Format(@"{0} +{1}", GetChargeSeparator(cultureInfo), charge));
            }
            else
            {
                const string minuses = "--";
                charge = -charge;
                return(charge <= minuses.Length
                    ? minuses.Substring(0, Math.Min(charge, minuses.Length))
                    : string.Format(@"{0} -{1}", GetChargeSeparator(cultureInfo), charge));
            }
        }
Beispiel #20
0
        public static string GetChargeIndicator(Adduct adduct)
        {
            if (!adduct.IsProteomic && !adduct.IsChargeOnly)
            {
                return(adduct.AsFormulaOrSignedInt());
            }
            var charge = adduct.AdductCharge;

            if (charge >= 0)
            {
                const string pluses = "++++"; // Not L10N
                return(charge <= pluses.Length
                    ? pluses.Substring(0, Math.Min(charge, pluses.Length))
                    : string.Format("{0} +{1}", LocalizationHelper.CurrentCulture.NumberFormat.NumberGroupSeparator, charge)); // Not L10N
            }
            else
            {
                const string minuses = "--"; // Not L10N
                charge = -charge;
                return(charge <= minuses.Length
                    ? minuses.Substring(0, Math.Min(charge, minuses.Length))
                    : string.Format("{0} -{1}", LocalizationHelper.CurrentCulture.NumberFormat.NumberGroupSeparator, charge)); // Not L10N
            }
        }
Beispiel #21
0
        public static bool IsFormulaWithAdduct(string formula, out Molecule molecule, out Adduct adduct, out string neutralFormula)
        {
            molecule       = null;
            adduct         = Adduct.EMPTY;
            neutralFormula = null;
            if (string.IsNullOrEmpty(formula))
            {
                return(false);
            }
            // Does formula contain an adduct description?  If so, pull charge from that.
            var parts = formula.Split('[');

            if (parts.Length == 2 && parts[1].Count(c => c == ']') == 1)
            {
                neutralFormula = parts[0];
                var adductString = formula.Substring(neutralFormula.Length);
                if (Adduct.TryParse(adductString, out adduct))
                {
                    molecule = neutralFormula.Length > 0 ? ApplyAdductToFormula(neutralFormula, adduct) : Molecule.Empty;
                    return(true);
                }
            }
            return(false);
        }
Beispiel #22
0
        /// <summary>
        /// Creates a ComplexFragmentIon representing something which has no amino acids from the parent peptide.
        /// </summary>
        public static ComplexFragmentIon NewOrphanFragmentIon(TransitionGroup transitionGroup, ExplicitMods explicitMods, Adduct adduct)
        {
            var transition = new Transition(transitionGroup, IonType.precursor,
                                            transitionGroup.Peptide.Sequence.Length - 1, 0, adduct);

            return(new ComplexFragmentIon(transition, null, explicitMods?.Crosslinks, true));
        }
Beispiel #23
0
        private void TestAdductOperators()
        {
            // Test some underlying formula handling for fanciful user-supplied values
            Assert.IsTrue(Molecule.AreEquivalentFormulas("C10H30Si5O5H-CH4", "C9H27O5Si5"));
            Assert.AreEqual("C7H27O5Si4", BioMassCalc.MONOISOTOPIC.FindFormulaIntersection(new[] { "C8H30Si5O5H-CH4", "C9H27O5Si4", "C9H27O5Si5Na" }));
            Assert.AreEqual("C7H27O5Si4", BioMassCalc.MONOISOTOPIC.FindFormulaIntersectionUnlabeled(new[] { "C7C'H30Si5O5H-CH4", "C9H27O5Si4", "C9H25H'2O5Si5Na" }));

            // There is a difference between a proteomic adduct and non proteomic, primarily in how they display
            Assert.AreEqual(Adduct.FromStringAssumeChargeOnly("M+H"), Adduct.M_PLUS_H);
            Assert.AreEqual(Adduct.FromStringAssumeProtonatedNonProteomic("1"), Adduct.M_PLUS_H);
            Assert.AreEqual(Adduct.FromStringAssumeChargeOnly("1"), Adduct.M_PLUS);
            Assert.AreEqual(Adduct.FromStringAssumeProtonatedNonProteomic("M+H"), Adduct.M_PLUS_H);
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("1"), Adduct.SINGLY_PROTONATED);
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+H"), Adduct.SINGLY_PROTONATED);
            Assert.AreEqual(Adduct.FromStringAssumeChargeOnly("M+H").AsFormula(), Adduct.SINGLY_PROTONATED.AsFormula()); // But the underlying chemistry is the same

            Assert.AreEqual(Adduct.FromStringAssumeProtonated("[M+S]+"), Adduct.FromStringAssumeProtonated("M+S").ChangeCharge(1));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M(-1.234)+2Na"), Adduct.FromStringAssumeProtonated("M(-1.234)+3Na").ChangeCharge(2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M1.234+2Na"), Adduct.FromStringAssumeProtonated("M1.234+3Na").ChangeCharge(2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M2Cl37-2Na"), Adduct.FromStringAssumeProtonated("M2Cl37+3Na").ChangeCharge(-2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M1.234-2Na"), Adduct.FromStringAssumeProtonated("M1.234+3Na").ChangeCharge(-2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M(-1.234)-2Na"), Adduct.FromStringAssumeProtonated("M(-1.234)+3Na").ChangeCharge(-2));

            Assert.IsFalse(Adduct.M_PLUS_H.IsProteomic);
            Assert.IsTrue(Adduct.M_PLUS_H.IsProtonated);
            Assert.IsTrue(Adduct.SINGLY_PROTONATED.IsProteomic);
            Assert.IsTrue(Adduct.SINGLY_PROTONATED.IsProtonated);
            Assert.IsFalse(Adduct.SINGLY_PROTONATED.IsEmpty);
            Assert.IsFalse(Adduct.EMPTY.IsProteomic);
            Assert.IsTrue(Adduct.EMPTY.IsEmpty);

            // Exercise the ability to work with masses and isotope labels
            Assert.IsTrue(ReferenceEquals(Adduct.SINGLY_PROTONATED, Adduct.SINGLY_PROTONATED.Unlabeled));
            var nolabel = Adduct.FromStringAssumeProtonated("M-2Na");
            var label   = Adduct.FromStringAssumeProtonated("M2Cl37-2Na");

            Assert.AreEqual(nolabel, label.Unlabeled);
            Assert.IsTrue(ReferenceEquals(nolabel, nolabel.Unlabeled));
            Assert.IsFalse(nolabel.MassFromMz(300.0, MassType.Monoisotopic).IsHeavy());
            Assert.IsFalse(label.MassFromMz(300.0, MassType.Monoisotopic).IsHeavy());
            Assert.IsTrue(label.MassFromMz(300.0, MassType.MonoisotopicHeavy).IsHeavy());
            Assert.IsTrue(label.MassFromMz(300.0, MassType.Monoisotopic).IsMonoIsotopic());
            Assert.IsFalse(nolabel.MassFromMz(300.0, MassType.Average).IsHeavy());
            Assert.IsFalse(label.MassFromMz(300.0, MassType.Average).IsHeavy());
            Assert.IsTrue(label.MassFromMz(300.0, MassType.AverageHeavy).IsHeavy());
            Assert.IsTrue(label.MassFromMz(300.0, MassType.Average).IsAverage());
            var massHeavy = label.ApplyToMass(new TypedMass(300, MassType.MonoisotopicHeavy)); // Will not have isotope effect added in mz calc, as it's already heavy
            var massLight = label.ApplyToMass(new TypedMass(300, MassType.Monoisotopic));      // Will have isotope effect added in mz calc

            Assert.AreNotEqual(massHeavy, massLight);
            Assert.AreNotEqual(label.MzFromNeutralMass(massHeavy), label.MzFromNeutralMass(massLight));

            Assert.IsTrue(Adduct.PossibleAdductDescriptionStart("["));
            Assert.IsTrue(Adduct.PossibleAdductDescriptionStart("M"));
            Assert.IsTrue(Adduct.PossibleAdductDescriptionStart("[2M+CH3COO]"));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+2CH3COO"), Adduct.FromStringAssumeProtonated("M+CH3COO").ChangeCharge(-2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M-2CH3COO"), Adduct.FromStringAssumeProtonated("M+CH3COO").ChangeCharge(2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M-2Na"), Adduct.FromStringAssumeProtonated("M+Na").ChangeCharge(-2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+Na"), Adduct.FromStringAssumeProtonated("M+Na").ChangeCharge(1));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+2Na"), Adduct.FromStringAssumeProtonated("M+Na").ChangeCharge(2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+2Na"), Adduct.FromStringAssumeProtonated("M+3Na").ChangeCharge(2));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M2Cl37+2Na"), Adduct.FromStringAssumeProtonated("M2Cl37+3Na").ChangeCharge(2));
            AssertEx.ThrowsException <InvalidOperationException>(() => Adduct.FromStringAssumeProtonated("M+2Na-H").ChangeCharge(2)); // Too complex to adjust formula

            AssertEx.ThrowsException <InvalidOperationException>(() => Adduct.FromStringAssumeProtonatedNonProteomic("[M2"));         // Seen in the wild, wasn't handled well

            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M++++").AdductCharge, Adduct.FromChargeNoMass(4).AdductCharge);
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M+4"), Adduct.FromChargeNoMass(4));
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M--").AdductCharge, Adduct.FromChargeNoMass(-2).AdductCharge);
            Assert.AreEqual(Adduct.FromStringAssumeProtonated("M-2"), Adduct.FromChargeNoMass(-2));
            Assert.IsTrue(ReferenceEquals(Adduct.FromStringAssumeChargeOnly("M-"), Adduct.FromChargeNoMass(-1)));  // Both should return Adduct.M_MINUS
            Assert.IsTrue(ReferenceEquals(Adduct.FromStringAssumeChargeOnly("M+"), Adduct.FromChargeNoMass(1)));   // Both should return Adduct.M_PLUS
            Assert.IsTrue(ReferenceEquals(Adduct.FromStringAssumeChargeOnly("[M+]"), Adduct.FromChargeNoMass(1))); // Both should return Adduct.M_PLUS
            Assert.IsTrue(ReferenceEquals(Adduct.FromStringAssumeChargeOnly("M-H"), Adduct.M_MINUS_H));
            Assert.IsTrue(ReferenceEquals(Adduct.FromStringAssumeChargeOnly("M+H"), Adduct.M_PLUS_H));

            var a    = Adduct.FromChargeProtonated(-1);
            var aa   = Adduct.FromStringAssumeProtonated("M+CH3COO");
            var b    = Adduct.FromChargeProtonated(2);
            var bb   = Adduct.FromChargeProtonated(2);
            var bbb  = Adduct.FromChargeProtonated(2);
            var bbbb = Adduct.FromChargeProtonated(2);
            var c    = Adduct.FromChargeProtonated(3);
            var cc   = Adduct.FromStringAssumeChargeOnly("M+3H");
            var ccc  = Adduct.FromStringAssumeChargeOnly("[M+3H]");

            Assert.AreEqual(a.AdductCharge, aa.AdductCharge);
            Assert.IsTrue(b == bb);
            Assert.IsTrue(b == bbb);
            Assert.IsTrue(ReferenceEquals(bbb, bbbb));
            Assert.IsTrue(c.AdductCharge == cc.AdductCharge);
            Assert.IsFalse(c == cc);
            Assert.IsTrue(c != cc);
            Assert.IsTrue(cc == ccc);
            Assert.IsTrue(a < aa);
            Assert.IsTrue(a < b);
            Assert.IsTrue(b > a);
            Assert.IsTrue(b != a);

            var sorted = new List <Adduct> {
                a, aa, b, bb, bbb, bbbb, c, cc, ccc
            };
            var unsorted = new List <Adduct> {
                bb, aa, ccc, b, c, bbb, a, bbbb, cc
            };

            Assert.IsFalse(sorted.SequenceEqual(unsorted));
            unsorted.Sort();
            Assert.IsTrue(sorted.SequenceEqual(unsorted));

            var ints = new AdductMap <int>();

            Assert.AreEqual(0, ints[a]);
            ints[a] = 7;
            Assert.AreEqual(7, ints[a]);

            var adducts = new AdductMap <Adduct>();

            Assert.AreEqual(null, adducts[a]);
            adducts[a] = b;
            Assert.AreEqual(b, adducts[a]);
            adducts[a] = c;
            Assert.AreEqual(c, adducts[a]);

            var d   = Adduct.FromStringAssumeProtonated("[2M+3H]");
            var dd  = Adduct.FromStringAssumeProtonated("[M+3H]");
            var ddd = Adduct.FromStringAssumeProtonated("[M-Na]");

            Assert.IsTrue(d.ChangeMassMultiplier(1).SameEffect(dd));
            Assert.IsTrue(dd.ChangeMassMultiplier(2).SameEffect(d));
            Assert.AreEqual(dd.ChangeIonFormula("-Na"), ddd);
            Assert.AreEqual(d.ChangeMassMultiplier(1).ChangeIonFormula("-Na"), ddd);

            CheckLabel(BioMassCalc.Cl37);
            CheckLabel(BioMassCalc.Br81);
            CheckLabel(BioMassCalc.S33);
            CheckLabel(BioMassCalc.S34);
            CheckLabel(BioMassCalc.P32);
            CheckLabel(BioMassCalc.C14);
            CheckLabel(BioMassCalc.O17);
            CheckLabel(BioMassCalc.O18);

            var tips = Adduct.Tips;

            foreach (var nickname in Adduct.DICT_ADDUCT_NICKNAMES)
            {
                Assert.IsTrue(tips.Contains(nickname.Key));
            }
            foreach (var nickname in Adduct.DICT_ADDUCT_ISOTOPE_NICKNAMES)
            {
                Assert.IsTrue(tips.Contains(nickname.Key));
            }
        }
Beispiel #24
0
        public void AdductParserTest()
        {
            TestAdductOperators();

            var coverage = new HashSet <string>();

            TestPentaneAdduct("[M+2NH4]", "C5H20N2", 2, coverage);           // multiple of a group
            TestPentaneAdduct("[M+2(NH4)]", "C5H20N2", 2, coverage);         // multiple of a group in parenthesis
            TestPentaneAdduct("[M+2H]", "C5H14", 2, coverage);
            TestPentaneAdduct("[M2C13+2H]", "C3C'2H14", 2, coverage);        // Labeled
            TestPentaneAdduct("[2M2C13+2H]", "C6C'4H26", 2, coverage);       // Labeled dimer
            TestPentaneAdduct("[2M2C14+2H]", "C6C\"4H26", 2, coverage);      // Labeled dimer
            TestPentaneAdduct("[M2C13]", "C3C'2H12", 0, coverage);           // Labeled no charge
            TestPentaneAdduct("[2M2C13]", "C6C'4H24", 0, coverage);          // Labeled, dimer, no charge
            TestPentaneAdduct("[2M]", "C10H24", 0, coverage);                // dimer no charge
            TestPentaneAdduct("[2M2C13+3]", "C6C'4H24", 3, coverage);        // Labeled, dimer, charge only
            TestPentaneAdduct("[2M2C13]+3", "C6C'4H24", 3, coverage);        // Labeled, dimer, charge only
            TestPentaneAdduct("[2M2C13+++]", "C6C'4H24", 3, coverage);       // Labeled, dimer, charge only
            TestPentaneAdduct("[2M2C13]+++", "C6C'4H24", 3, coverage);       // Labeled, dimer, charge only
            TestPentaneAdduct("[2M+3]", "C10H24", 3, coverage);              // dimer charge only
            TestPentaneAdduct("[2M]+3", "C10H24", 3, coverage);              // dimer charge only
            TestPentaneAdduct("[2M+++]", "C10H24", 3, coverage);             // dimer charge only
            TestPentaneAdduct("[2M]+++", "C10H24", 3, coverage);             // dimer charge only
            TestPentaneAdduct("[2M2C13-3]", "C6C'4H24", -3, coverage);       // Labeled, dimer, charge only
            TestPentaneAdduct("[2M2C13---]", "C6C'4H24", -3, coverage);      // Labeled, dimer, charge only
            TestPentaneAdduct("[2M-3]", "C10H24", -3, coverage);             // dimer charge only
            TestPentaneAdduct("[2M---]", "C10H24", -3, coverage);            // dimer charge only
            TestPentaneAdduct("[2M2C133H2+2H]", "C6C'4H20H'6", 2, coverage); // Labeled with some complexity, multiplied
            TestPentaneAdduct("M+H", "C5H13", 1, coverage);
            TestPentaneAdduct("M+", PENTANE, 1, coverage);
            TestPentaneAdduct("M+2", PENTANE, 2, coverage);
            TestPentaneAdduct("M+3", PENTANE, 3, coverage);
            TestPentaneAdduct("M-", PENTANE, -1, coverage);
            TestPentaneAdduct("M-2", PENTANE, -2, coverage);
            TestPentaneAdduct("M-3", PENTANE, -3, coverage);
            TestPentaneAdduct("M++", PENTANE, 2, coverage);
            TestPentaneAdduct("M--", PENTANE, -2, coverage);
            TestPentaneAdduct("M", PENTANE, 0, coverage);           // Trivial non-adduct
            TestPentaneAdduct("M+CH3COO", "C7H15O2", -1, coverage); // From XCMS
            TestPentaneAdduct("[M+H]1+", "C5H13", 1, coverage);
            TestPentaneAdduct("[M-H]1-", "C5H11", -1, coverage);
            TestPentaneAdduct("[M-2H]", "C5H10", -2, coverage);
            TestPentaneAdduct("[M-2H]2-", "C5H10", -2, coverage);
            TestPentaneAdduct("[M+2H]++", "C5H14", 2, coverage);
            TestPentaneAdduct("[MH2+2H]++", "C5H13H'", 2, coverage);        // Isotope
            TestPentaneAdduct("[MH3+2H]++", "C5H13H\"", 2, coverage);       // Isotope
            TestPentaneAdduct("[MD+2H]++", "C5H13H'", 2, coverage);         // Isotope
            TestPentaneAdduct("[MD+DMSO+2H]++", "C7H19H'OS", 2, coverage);  // Check handling of Deuterium and DMSO together
            TestPentaneAdduct("[MT+DMSO+2H]++", "C7H19H\"OS", 2, coverage); // Check handling of Tritium
            TestPentaneAdduct("[M+DMSO+2H]++", "C7H20OS", 2, coverage);
            TestPentaneAdduct("[M+DMSO+2H]2+", "C7H20OS", 2, coverage);
            TestPentaneAdduct("[M+MeOH-H]", "C6H15O", -1, coverage); // Methanol "CH3OH"
            TestPentaneAdduct("[M+MeOX-H]", "C6H14N", -1, coverage); // Methoxamine "CH3N"
            TestPentaneAdduct("[M+TMS-H]", "C8H19Si", -1, coverage); // MSTFA(N-methyl-N-trimethylsilytrifluoroacetamide) "C3H8Si"
            TestPentaneAdduct("[M+TMS+MeOX]-", "C9H23NSi", -1, coverage);
            TestPentaneAdduct("[M+HCOO]", "C6H13O2", -1, coverage);
            TestPentaneAdduct("[M+NOS]5+", "C5H12NOS", 5, coverage);  // Not a real adduct, but be ready for adducts we just don't know about
            TestPentaneAdduct("[M+NOS]5", "C5H12NOS", 5, coverage);   // Not a real adduct, but be ready for adducts we just don't know about
            TestPentaneAdduct("[M+NOS]5-", "C5H12NOS", -5, coverage); // Not a real adduct, but be ready for adducts we just don't know about

            // See http://fiehnlab.ucdavis.edu/staff/kind/Metabolomics/MS-Adduct-Calculator/
            // There you will find an excel spreadsheet from which I pulled these numbers, which as it turns out has several errors in it.
            // There is also a table in the web page itself that contains the same values and some unmarked corrections.
            // Sadly that faulty spreadsheet is copied all over the internet.  I've let the author know what we found. - bspratt
            TestTaxolAdduct("M+3H", 285.450928, 3, coverage);
            TestTaxolAdduct("M+2H+Na", 292.778220, 3, coverage);
            TestTaxolAdduct("M+H+2Na", 300.105557, 3, coverage); // Spreadsheet and table both say 300.209820, but also says adduct "mass" = 15.766190, I get 15.6618987 using their H and Na masses (and this is clearly m/z, not mass)
            TestTaxolAdduct("M+3Na", 307.432848, 3, coverage);
            TestTaxolAdduct("M+2H", 427.672721, 2, coverage);
            TestTaxolAdduct("M+H+NH4", 436.185995, 2, coverage);
            TestTaxolAdduct("M+H+Na", 438.663692, 2, coverage);
            TestTaxolAdduct("M+H+K", 446.650662, 2, coverage);
            TestTaxolAdduct("M+ACN+2H", 448.185995, 2, coverage);
            TestTaxolAdduct("M+2Na", 449.654663, 2, coverage);
            TestTaxolAdduct("M+2ACN+2H", 468.699268, 2, coverage);
            TestTaxolAdduct("M+3ACN+2H", 489.212542, 2, coverage);
            TestTaxolAdduct("M+H", 854.338166, 1, coverage);
            TestTaxolAdduct("M+NH4", 871.364713, 1, coverage);
            TestTaxolAdduct("M+Na", 876.320108, 1, coverage);
            TestTaxolAdduct("M+CH3OH+H", 886.364379, 1, coverage);
            TestTaxolAdduct("M+K", 892.294048, 1, coverage);
            TestTaxolAdduct("M+ACN+H", 895.364713, 1, coverage);
            TestTaxolAdduct("M+2Na-H", 898.302050, 1, coverage);
            TestTaxolAdduct("M+IsoProp+H", 914.396230, 1, coverage);
            TestTaxolAdduct("M+ACN+Na", 917.346655, 1, coverage);
            TestTaxolAdduct("M+2K-H", 930.249930, 1, coverage);  // Spreadsheet and table disagree - spreadsheet says "M+2K+H" but that's 3+, not 1+, and this fits the mz value
            TestTaxolAdduct("M+DMSO+H", 932.352110, 1, coverage);
            TestTaxolAdduct("M+2ACN+H", 936.391260, 1, coverage);
            TestTaxolAdduct("M+IsoProp+Na+H", 468.692724, 2, coverage); // Spreadsheet and table both say mz=937.386000 z=1 (does Isoprop interact somehow to eliminate half the ionization?)
            TestTaxolAdduct("2M+H", 1707.669056, 1, coverage);
            TestTaxolAdduct("2M+NH4", 1724.695603, 1, coverage);
            TestTaxolAdduct("2M+Na", 1729.650998, 1, coverage);
            TestTaxolAdduct("2M+3H2O+2H", 881.354, 2, coverage); // Does not appear in table.  Charge agrees but spreadsheet says mz= 1734.684900
            TestTaxolAdduct("2M+K", 1745.624938, 1, coverage);
            TestTaxolAdduct("2M+ACN+H", 1748.695603, 1, coverage);
            TestTaxolAdduct("2M+ACN+Na", 1770.677545, 1, coverage);
            TestTaxolAdduct("M-3H", 283.436354, -3, coverage);
            TestTaxolAdduct("M-2H", 425.658169, -2, coverage);
            TestTaxolAdduct("M-H2O-H", 834.312500, -1, coverage);
            TestTaxolAdduct("M+-H2O-H", 834.312500, -1, coverage); // Tolerate empty atom description ("+-")
            TestTaxolAdduct("M-H", 852.323614, -1, coverage);
            TestTaxolAdduct("M+Na-2H", 874.305556, -1, coverage);
            TestTaxolAdduct("M+Cl", 888.300292, -1, coverage);
            TestTaxolAdduct("M+K-2H", 890.279496, -1, coverage);
            TestTaxolAdduct("M+FA-H", 898.329091, -1, coverage);
            TestTaxolAdduct("M+Hac-H", 912.344741, -1, coverage);
            TestTaxolAdduct("M+Br", 932.249775, -1, coverage);
            TestTaxolAdduct("MT+TFA-H", 968.324767, -1, coverage); // Tritium label + TFA
            TestTaxolAdduct("M+TFA-H", 966.316476, -1, coverage);
            TestTaxolAdduct("2M-H", 1705.654504, -1, coverage);
            TestTaxolAdduct("2M+FA-H", 1751.659981, -1, coverage);
            TestTaxolAdduct("2M+Hac-H", 1765.675631, -1, coverage);
            TestTaxolAdduct("3M-H", 2558.985394, -1, coverage); // Spreadsheet and table give mz as 2560.999946 -but also gives adduct "mass" as 1.007276, should be -1.007276

            // A couple more simple ones we support with statics
            TestTaxolAdduct("M+4H", 214.3400149, 4, coverage);
            TestTaxolAdduct("M+5H", 171.6734671, 5, coverage);

            // And a few of our own to exercise the interaction of multiplier and isotope
            var dC13 = BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.C13) - BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.C);

            TestTaxolAdduct("M2C13+3H", 285.450928 + (2 * dC13) / 3.0, 3, coverage);
            TestTaxolAdduct("M2C13+2H+Na", 292.778220 + (2 * dC13) / 3.0, 3, coverage);
            TestTaxolAdduct("2M2C13+3H", 285.450906 + (massTaxol + 4 * dC13) / 3.0, 3, coverage);
            TestTaxolAdduct("2M2C13+2H+Na", 292.778220 + (massTaxol + 4 * dC13) / 3.0, 3, coverage);
            var dC14 = BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.C14) - BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.C);

            TestTaxolAdduct("M2C14+3H", 285.450928 + (2 * dC14) / 3.0, 3, coverage);
            TestTaxolAdduct("M2C14+2H+Na", 292.778220 + (2 * dC14) / 3.0, 3, coverage);
            TestTaxolAdduct("2M2C14+3H", 285.450906 + (massTaxol + 4 * dC14) / 3.0, 3, coverage);
            TestTaxolAdduct("2M2C14+2H+Na", 292.778220 + (massTaxol + 4 * dC14) / 3.0, 3, coverage);

            // Using example adducts from
            // https://gnps.ucsd.edu/ProteoSAFe/gnpslibrary.jsp?library=GNPS-LIBRARY#%7B%22Library_Class_input%22%3A%221%7C%7C2%7C%7C3%7C%7CEXACT%22%7D
            var Hectochlorin     = "C27H34Cl2N2O9S2";
            var massHectochlorin = 664.108276; // http://www.chemspider.com/Chemical-Structure.552449.html?rid=3a7c08af-0886-4e82-9e4f-5211b8efb373
            var adduct           = Adduct.FromStringAssumeProtonated("M+H");
            var mol  = IonInfo.ApplyAdductToFormula(Hectochlorin, adduct).ToString();
            var mass = BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(mol);

            Assert.AreEqual(massHectochlorin + BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula("H"), mass, 0.00001);
            var mz = BioMassCalc.CalculateIonMz(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(Hectochlorin), adduct);

            Assert.AreEqual(665.11555415, mz, .000001);  // GNPS says 665.0 for Hectochlorin M+H
            mol = IonInfo.ApplyAdductToFormula(Hectochlorin, Adduct.FromStringAssumeProtonated("MCl37+H")).ToString();
            Assert.AreEqual("C27ClCl'H35N2O9S2", mol);
            mass = BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(mol);
            Assert.AreEqual(667.11315, mass, .00001);
            mol = IonInfo.ApplyAdductToFormula(Hectochlorin, Adduct.FromStringAssumeProtonated("M2Cl37+H")).ToString();
            Assert.AreEqual("C27Cl'2H35N2O9S2", mol);

            // Test ability to describe isotope label by mass only
            var heavy = Adduct.FromStringAssumeProtonated("2M1.2345+H");

            mz    = BioMassCalc.CalculateIonMz(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            heavy = Adduct.FromStringAssumeProtonated("2M1.2345");
            mz    = BioMassCalc.CalculateIonMass(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual(2 * (massHectochlorin + 1.23456), mz, .001);
            heavy = Adduct.FromStringAssumeProtonated("M1.2345");
            mz    = BioMassCalc.CalculateIonMass(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual(massHectochlorin + 1.23456, mz, .001);
            heavy = Adduct.FromStringAssumeProtonated("2M(-1.2345)+H");
            mz    = BioMassCalc.CalculateIonMz(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual((2 * (massHectochlorin - 1.23456) + BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula("H")), mz, .001);
            heavy = Adduct.FromStringAssumeProtonated("2M(-1.2345)");
            mz    = BioMassCalc.CalculateIonMass(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual(2 * (massHectochlorin - 1.23456), mz, .001);
            heavy = Adduct.FromStringAssumeProtonated("2M(1.2345)+H");
            mz    = BioMassCalc.CalculateIonMz(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual((2 * (massHectochlorin + 1.23456) + BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula("H")), mz, .001);
            heavy = Adduct.FromStringAssumeProtonated("2M(1.2345)");
            mz    = BioMassCalc.CalculateIonMass(new TypedMass(massHectochlorin, MassType.Monoisotopic), heavy);
            Assert.AreEqual(2 * (massHectochlorin + 1.23456), mz, .001);

            TestException(Hectochlorin, "M3Cl37+H"); // Trying to label more chlorines than exist in the molecule
            TestException(Hectochlorin, "M-3Cl+H");  // Trying to remove more chlorines than exist in the molecule
            TestException(PENTANE, "M+foo+H");       // Unknown adduct
            TestException(PENTANE, "M2Cl37H+H");     // nonsense label ("2Cl37H2" would make sense, but regular H doesn't belong)
            TestException(PENTANE, "M+2H+");         // Trailing sign - we now understand this as a charge state declaration, but this one doesn't match described charge
            TestException(PENTANE, "[M-2H]3-");      // Declared charge doesn't match described charge

            // Test label stripping
            Assert.AreEqual("C5H9NO2S", (new IonInfo("C5H9H'3NO2S[M-3H]")).UnlabeledFormula);

            // Peptide representations
            Assert.AreEqual("C40H65N11O16", (new SequenceMassCalc(MassType.Average)).GetNeutralFormula("PEPTIDER", null));

            // Figuring out adducts from old style skyline doc ion molecules and ion precursors
            var adductDiff = Adduct.FromFormulaDiff("C6H27NO2Si2C'5", "C'5H11NO2", 3);

            Assert.AreEqual("[M+C6H16Si2]3+", adductDiff.AdductFormula);
            Assert.AreEqual(3, adductDiff.AdductCharge);
            Assert.AreEqual(Adduct.FromString("[M+C6H16Si2]3+", Adduct.ADDUCT_TYPE.non_proteomic, null), adductDiff);
            adductDiff = Adduct.FromFormulaDiff("C6H27NO2", "C6H27NO2", 3);
            Assert.AreEqual("[M+3]", adductDiff.AdductFormula);
            Assert.AreEqual(3, adductDiff.AdductCharge);
            adductDiff = Adduct.ProtonatedFromFormulaDiff("C6H27NO2Si2C'5", "C'5H11NO2", 3);
            var expectedFromProtonatedDiff = "[M+C6H13Si2+3H]";

            Assert.AreEqual(expectedFromProtonatedDiff, adductDiff.AdductFormula);
            Assert.AreEqual(3, adductDiff.AdductCharge);
            Assert.AreEqual(Adduct.FromString(expectedFromProtonatedDiff, Adduct.ADDUCT_TYPE.non_proteomic, null), adductDiff);
            adductDiff = Adduct.ProtonatedFromFormulaDiff("C6H27NO2", "C6H27NO2", 3);
            Assert.AreEqual("[M+3H]", adductDiff.AdductFormula);
            Assert.AreEqual(3, adductDiff.AdductCharge);

            // Implied positive mode
            TestPentaneAdduct("MH", "C5H13", 1, coverage);       // implied pos mode seems to be fairly common in the wild
            TestPentaneAdduct("MH+", "C5H13", 1, coverage);      // implied pos mode seems to be fairly common in the wild
            TestPentaneAdduct("MNH4", "C5H16N", 1, coverage);    // implied pos mode seems to be fairly common in the wild
            TestPentaneAdduct("MNH4+", "C5H16N", 1, coverage);   // implied pos mode seems to be fairly common in the wild
            TestPentaneAdduct("2MNH4+", "C10H28N", 1, coverage); // implied pos mode seems to be fairly common in the wild

            // Explict charge states within the adduct
            TestPentaneAdduct("[M+S+]", "C5H12S", 1, coverage);   // We're trusting the user to declare charge
            TestPentaneAdduct("[3M+S+]", "C15H36S", 1, coverage); // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S++]", "C5H12S", 2, coverage);  // We're trusting the user to declare charge
            TestPentaneAdduct("[MS+]", "C5H12S", 1, coverage);    // We're trusting the user to declare charge
            TestPentaneAdduct("[MS++]", "C5H12S", 2, coverage);   // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S+2]", "C5H12S", 2, coverage);  // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S]2+", "C5H12S", 2, coverage);  // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S-]", "C5H12S", -1, coverage);  // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S--]", "C5H12S", -2, coverage); // We're trusting the user to declare charge
            TestPentaneAdduct("[M-3H-3]", "C5H9", -3, coverage);  // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S-2]", "C5H12S", -2, coverage); // We're trusting the user to declare charge
            TestPentaneAdduct("[M+S]2-", "C5H12S", -2, coverage); // We're trusting the user to declare charge

            // Did we test all the adducts we claim to support?
            foreach (var adducts in new[] {
                Adduct.DEFACTO_STANDARD_ADDUCTS,
                Adduct.COMMON_CHARGEONLY_ADDUCTS,
                Adduct.COMMON_SMALL_MOL_ADDUCTS.Select(a => a.AdductFormula),
                Adduct.COMMON_PROTONATED_ADDUCTS.Select(a => a.AdductFormula),
            })
            {
                foreach (var adductText in adducts)
                {
                    if (!coverage.Contains(adductText))
                    {
                        Assert.Fail("Need to add a test for adduct {0}", adductText);
                    }
                }
            }
        }
Beispiel #25
0
        private string _unlabledFormula; // Chemical formula after adduct application and stripping of labels


        /// <summary>
        /// Constructs an IonInfo, which holds a neutral formula and adduct, or possibly just a chemical formula if no adduct is included in the description
        /// </summary>
        public IonInfo(string formulaWithOptionalAdduct, Adduct adduct)
        {
            Formula = formulaWithOptionalAdduct + adduct.AdductFormula;
        }
Beispiel #26
0
 /// <summary>
 /// For test purposes
 /// </summary>
 public static double CalculateIonMass(TypedMass mass, Adduct adduct)
 {
     return(adduct.ApplyToMass(mass));
 }
Beispiel #27
0
 /// <summary>
 /// For test purposes
 /// </summary>
 public static double CalculateIonMz(TypedMass mass, Adduct adduct)
 {
     return(adduct.MzFromNeutralMass(mass));
 }
Beispiel #28
0
        /// <summary>
        /// For test purposes
        /// </summary>
        public double CalculateIonMz(string desc, Adduct adduct)
        {
            var mass = CalculateMassFromFormula(desc);

            return(adduct.MzFromNeutralMass(mass));
        }
Beispiel #29
0
 public IList <int> ShowIonCharges(IEnumerable <Adduct> adductPriority)
 {
     return(Adduct.OrderedAbsoluteChargeValues(adductPriority).ToList());
 }
Beispiel #30
0
        public void UpdateUI(bool selectionChanged = true)
        {
            // Only worry about updates, if the graph is visible
            // And make sure it is not disposed, since rendering happens on a timer
            if (!Visible || IsDisposed)
            {
                return;
            }

            // Clear existing data from the graph pane
            var graphPane = (MSGraphPane)graphControl.MasterPane[0];

            graphPane.CurveList.Clear();
            graphPane.GraphObjList.Clear();
            GraphItem = null;

            GraphHelper.FormatGraphPane(graphControl.GraphPane);
            GraphHelper.FormatFontSize(graphControl.GraphPane, Settings.Default.SpectrumFontSize);
            // Try to find a tree node with spectral library info associated
            // with the current selection.
            var nodeTree      = _stateProvider.SelectedNode as SrmTreeNode;
            var nodeGroupTree = nodeTree as TransitionGroupTreeNode;
            var nodeTranTree  = nodeTree as TransitionTreeNode;

            if (nodeTranTree != null)
            {
                nodeGroupTree = nodeTranTree.Parent as TransitionGroupTreeNode;
            }

            var             nodeGroup = (nodeGroupTree != null ? nodeGroupTree.DocNode : null);
            PeptideTreeNode nodePepTree;

            if (nodeGroup == null)
            {
                nodePepTree = nodeTree as PeptideTreeNode;
                if (nodePepTree != null)
                {
                    var listInfoGroups = GetLibraryInfoChargeGroups(nodePepTree);
                    if (listInfoGroups.Length == 1)
                    {
                        nodeGroup = listInfoGroups[0];
                    }
                    else if (listInfoGroups.Length > 1)
                    {
                        _nodeGroup      = null;
                        toolBar.Visible = false;
                        _graphHelper.SetErrorGraphItem(new NoDataMSGraphItem(
                                                           Resources.GraphSpectrum_UpdateUI_Multiple_charge_states_with_library_spectra));
                        return;
                    }
                }
            }
            else
            {
                nodePepTree = nodeGroupTree.Parent as PeptideTreeNode;
            }

            // Check for appropriate spectrum to load
            SrmSettings      settings  = DocumentUI.Settings;
            PeptideLibraries libraries = settings.PeptideSettings.Libraries;
            bool             available = false;

            if (nodeGroup == null || (!nodeGroup.HasLibInfo && !libraries.HasMidasLibrary))
            {
                _spectra = null;
            }
            else
            {
                TransitionGroup   group      = nodeGroup.TransitionGroup;
                TransitionDocNode transition = (nodeTranTree == null ? null : nodeTranTree.DocNode);
                var          lookupSequence  = group.Peptide.Target;// Sequence or custom ion id
                ExplicitMods lookupMods      = null;
                if (nodePepTree != null)
                {
                    lookupSequence = nodePepTree.DocNode.SourceUnmodifiedTarget;
                    lookupMods     = nodePepTree.DocNode.SourceExplicitMods;
                }
                try
                {
                    // Try to load a list of spectra matching the criteria for
                    // the current node group.
                    if (libraries.HasLibraries && libraries.IsLoaded)
                    {
                        if (NodeGroupChanged(nodeGroup))
                        {
                            try
                            {
                                UpdateSpectra(nodeGroup, lookupSequence, lookupMods);
                                UpdateToolbar();
                            }
                            catch (Exception)
                            {
                                _spectra = null;
                                UpdateToolbar();
                                throw;
                            }

                            _nodeGroup = nodeGroup;
                            if (settings.TransitionSettings.Instrument.IsDynamicMin)
                            {
                                ZoomSpectrumToSettings();
                            }
                        }

                        var spectrum = SelectedSpectrum;
                        if (spectrum != null)
                        {
                            IsotopeLabelType typeInfo = spectrum.LabelType;
                            var types   = _stateProvider.ShowIonTypes(group.IsProteomic);
                            var adducts = (group.IsProteomic ?
                                           Transition.DEFAULT_PEPTIDE_LIBRARY_CHARGES :
                                           nodeGroup.InUseAdducts).ToArray();
                            var charges     = _stateProvider.ShowIonCharges(adducts);
                            var rankTypes   = group.IsProteomic ? settings.TransitionSettings.Filter.PeptideIonTypes : settings.TransitionSettings.Filter.SmallMoleculeIonTypes;
                            var rankAdducts = group.IsProteomic ? settings.TransitionSettings.Filter.PeptideProductCharges : settings.TransitionSettings.Filter.SmallMoleculeFragmentAdducts;
                            var rankCharges = Adduct.OrderedAbsoluteChargeValues(rankAdducts);
                            // Make sure the types and charges in the settings are at the head
                            // of these lists to give them top priority, and get rankings correct.
                            int i = 0;
                            foreach (IonType type in rankTypes)
                            {
                                if (types.Remove(type))
                                {
                                    types.Insert(i++, type);
                                }
                            }
                            i = 0;
                            var showAdducts = new List <Adduct>();
                            foreach (var charge in rankCharges)
                            {
                                if (charges.Remove(charge))
                                {
                                    charges.Insert(i++, charge);
                                }
                                // NB for all adducts we just look at abs value of charge
                                // CONSIDER(bspratt): we may want finer per-adduct control for small molecule use
                                showAdducts.AddRange(adducts.Where(a => charge == Math.Abs(a.AdductCharge)));
                            }
                            showAdducts.AddRange(adducts.Where(a => charges.Contains(Math.Abs(a.AdductCharge)) && !showAdducts.Contains(a)));
                            SpectrumPeaksInfo spectrumInfo = spectrum.SpectrumPeaksInfo;
                            var spectrumInfoR = new LibraryRankedSpectrumInfo(spectrumInfo,
                                                                              typeInfo,
                                                                              nodeGroup,
                                                                              settings,
                                                                              lookupSequence,
                                                                              lookupMods,
                                                                              showAdducts,
                                                                              types,
                                                                              rankAdducts,
                                                                              rankTypes);
                            GraphItem = new SpectrumGraphItem(nodeGroup, transition, spectrumInfoR, spectrum.LibName)
                            {
                                ShowTypes      = types,
                                ShowCharges    = charges,
                                ShowRanks      = Settings.Default.ShowRanks,
                                ShowMz         = Settings.Default.ShowIonMz,
                                ShowObservedMz = Settings.Default.ShowObservedMz,
                                ShowDuplicates = Settings.Default.ShowDuplicateIons,
                                FontSize       = Settings.Default.SpectrumFontSize,
                                LineWidth      = Settings.Default.SpectrumLineWidth
                            };
                            LibraryChromGroup chromatogramData = null;
                            if (Settings.Default.ShowLibraryChromatograms)
                            {
                                chromatogramData = spectrum.LoadChromatogramData();
                            }
                            if (null == chromatogramData)
                            {
                                _graphHelper.ResetForSpectrum(new[] { nodeGroup.TransitionGroup });
                                _graphHelper.AddSpectrum(GraphItem);
                                _graphHelper.ZoomSpectrumToSettings(DocumentUI, nodeGroup);
                            }
                            else
                            {
                                _graphHelper.ResetForChromatograms(new[] { nodeGroup.TransitionGroup });

                                var displayType = GraphChromatogram.GetDisplayType(DocumentUI, nodeGroup);
                                IList <TransitionDocNode> displayTransitions =
                                    GraphChromatogram.GetDisplayTransitions(nodeGroup, displayType).ToArray();
                                int numTrans      = displayTransitions.Count;
                                var allChromDatas =
                                    chromatogramData.ChromDatas.Where(
                                        chromData => DisplayTypeMatches(chromData, displayType)).ToList();
                                var chromDatas = new List <LibraryChromGroup.ChromData>();
                                for (int iTran = 0; iTran < numTrans; iTran++)
                                {
                                    var displayTransition = displayTransitions[iTran];
                                    var indexMatch        =
                                        allChromDatas.IndexOf(chromData => IonMatches(displayTransition.Transition, chromData));
                                    if (indexMatch >= 0)
                                    {
                                        chromDatas.Add(allChromDatas[indexMatch]);
                                        allChromDatas.RemoveAt(indexMatch);
                                    }
                                    else
                                    {
                                        chromDatas.Add(null);
                                    }
                                }
                                allChromDatas.Sort((chromData1, chromData2) => chromData1.Mz.CompareTo(chromData2.Mz));
                                chromDatas.AddRange(allChromDatas);
                                double maxHeight         = chromDatas.Max(chromData => null == chromData ? double.MinValue : chromData.Height);
                                int    iChromDataPrimary = chromDatas.IndexOf(chromData => null != chromData && maxHeight == chromData.Height);
                                int    colorOffset       = displayType == DisplayTypeChrom.products
                                                      ? GraphChromatogram.GetDisplayTransitions(nodeGroup,
                                                                                                DisplayTypeChrom.
                                                                                                precursors).Count()
                                                      : 0;
                                for (int iChromData = 0; iChromData < chromDatas.Count; iChromData++)
                                {
                                    var chromData = chromDatas[iChromData];
                                    if (chromData == null)
                                    {
                                        continue;
                                    }
                                    string label;
                                    var    pointAnnotation = GraphItem.AnnotatePoint(new PointPair(chromData.Mz, 1.0));
                                    if (null != pointAnnotation)
                                    {
                                        label = pointAnnotation.Label;
                                    }
                                    else
                                    {
                                        label = chromData.Mz.ToString(@"0.####");
                                    }
                                    TransitionDocNode matchingTransition;
                                    Color             color;
                                    if (iChromData < numTrans)
                                    {
                                        matchingTransition = displayTransitions[iChromData];
                                        color =
                                            GraphChromatogram.COLORS_LIBRARY[
                                                (iChromData + colorOffset) % GraphChromatogram.COLORS_LIBRARY.Count];
                                    }
                                    else
                                    {
                                        matchingTransition = null;
                                        color =
                                            GraphChromatogram.COLORS_GROUPS[
                                                iChromData % GraphChromatogram.COLORS_GROUPS.Count];
                                    }

                                    TransitionChromInfo tranPeakInfo;
                                    ChromatogramInfo    chromatogramInfo;
                                    MakeChromatogramInfo(nodeGroup.PrecursorMz, chromatogramData, chromData, out chromatogramInfo, out tranPeakInfo);
                                    var graphItem = new ChromGraphItem(nodeGroup, matchingTransition, chromatogramInfo, iChromData == iChromDataPrimary ? tranPeakInfo : null, null,
                                                                       new[] { iChromData == iChromDataPrimary }, null, 0, false, false, null, 0,
                                                                       color, Settings.Default.ChromatogramFontSize, 1);
                                    LineItem curve = (LineItem)_graphHelper.AddChromatogram(PaneKey.DEFAULT, graphItem);
                                    if (matchingTransition == null)
                                    {
                                        curve.Label.Text = label;
                                    }
                                    curve.Line.Width = Settings.Default.ChromatogramLineWidth;
                                    if (null != transition)
                                    {
                                        if (IonMatches(transition.Transition, chromData))
                                        {
                                            color = ChromGraphItem.ColorSelected;
                                        }
                                    }
                                    curve.Color = color;
                                }
                                graphPane.Title.IsVisible  = false;
                                graphPane.Legend.IsVisible = true;
                                _graphHelper.FinishedAddingChromatograms(chromatogramData.StartTime, chromatogramData.EndTime, false);
                                graphControl.Refresh();
                            }
                            graphControl.IsEnableVPan = graphControl.IsEnableVZoom =
                                !Settings.Default.LockYAxis;
                            available = true;
                        }
                    }
                }
                catch (Exception)
                {
                    _graphHelper.SetErrorGraphItem(new NoDataMSGraphItem(
                                                       Resources.GraphSpectrum_UpdateUI_Failure_loading_spectrum__Library_may_be_corrupted));
                    return;
                }
            }
            // Show unavailable message, if no spectrum loaded
            if (!available)
            {
                UpdateToolbar();
                _nodeGroup = null;
                _graphHelper.SetErrorGraphItem(new UnavailableMSGraphItem());
            }
        }