Ejemplo n.º 1
0
        // Unit test of annotations handler class
        private static void TestSpectrumPeakAnnotations()
        {
            var noNote      = SpectrumPeakAnnotation.Create(new CustomIon(null, Adduct.FromChargeNoMass(-2), 100, 101, "noNote"), null);
            var noName      = SpectrumPeakAnnotation.Create(new CustomIon(null, Adduct.FromChargeNoMass(-2), 100, 101, null), "noted");
            var fullIon     = new CustomIon("C12H5O3", Adduct.FromStringAssumeChargeOnly("M-H2O+"), null, null, "full");
            var full        = SpectrumPeakAnnotation.Create(fullIon, "noted");
            var fullToo     = SpectrumPeakAnnotation.Create(fullIon, "noted");
            var nameOnlyTab = SpectrumPeakAnnotation.Create(new CustomIon(null, Adduct.FromChargeNoMass(-2), 100, 101, "test\ttabs"), "noted"); // Check tab escape
            var fullIonTabs = new CustomIon("C12H5", Adduct.FromChargeNoMass(-2), null, null, "full\ttabs");
            var tabbedFull  = SpectrumPeakAnnotation.Create(fullIonTabs, "noted\ttabs");                                                        // Check tab escape

            Assume.AreEqual(full, fullToo);
            Assume.AreNotEqual(full, tabbedFull);
            var tests = new List <List <SpectrumPeakAnnotation> >
            {
                new List <SpectrumPeakAnnotation> {
                    noNote, noName, full
                },
                new List <SpectrumPeakAnnotation> {
                    fullToo, nameOnlyTab, tabbedFull
                }
            };
            var cached    = SpectrumPeakAnnotation.ToCacheFormat(tests);
            var roundtrip = SpectrumPeakAnnotation.FromCacheFormat(cached);
            int i         = 0;

            foreach (var annotsPerPeak in tests)
            {
                Assume.IsTrue(CollectionUtil.EqualsDeep(annotsPerPeak, roundtrip[i++]));
            }
        }
Ejemplo n.º 2
0
        public override void ReadXml(XmlReader reader)
        {
            // Read tag attributes
            base.ReadXml(reader);
            Fragment = reader.GetAttribute(ATTR.cut);
            if (IsFragment)
            {
                Restrict          = reader.GetAttribute(ATTR.no_cut);
                Terminus          = reader.GetAttribute(ATTR.sense, ToSeqTerminus);
                MinFragmentLength = reader.GetNullableIntAttribute(ATTR.min_length) ??
                                    DEFAULT_MIN_FRAGMENT_LENGTH;
            }
            else
            {
                var charges = TextUtil.ParseInts(reader.GetAttribute(ATTR.charges)); // Old version?
                if (charges.Length > 1)
                {
                    throw new InvalidDataException(Resources.MeasuredIon_ReadXml_Multiple_charge_states_for_custom_ions_are_no_longer_supported_);
                }
                var    parsedIon = CustomIon.Deserialize(reader);
                Adduct adduct;
                if (charges.Any())  // Old style - fix it up a little for our revised ideas about custom ion ionization
                {
                    adduct = Adduct.FromChargeNoMass(charges[0]);
                    if (string.IsNullOrEmpty(parsedIon.NeutralFormula)) // Adjust the user-supplied masses
                    {
                        SettingsCustomIon = new SettingsCustomIon(parsedIon.NeutralFormula, adduct,
                                                                  Math.Round(parsedIon.MonoisotopicMass + charges[0] * BioMassCalc.MONOISOTOPIC.GetMass(BioMassCalc.H), SequenceMassCalc.MassPrecision), // Assume user provided neutral mass.  Round new value easiest XML roundtripping.
                                                                  Math.Round(parsedIon.AverageMass + charges[0] * BioMassCalc.AVERAGE.GetMass(BioMassCalc.H), SequenceMassCalc.MassPrecision),           // Assume user provided neutral mass.  Round new value easiest XML roundtripping.
                                                                  parsedIon.Name);
                    }
                    else // Adjust the formula to include ion atoms
                    {
                        if (charges[0] > 1) // XML deserializer will have added an H already
                        {
                            var adductProtonated = Adduct.FromChargeProtonated(charges[0] - 1);
                            var formula          = adductProtonated.ApplyToFormula(parsedIon.NeutralFormula);
                            parsedIon = new CustomIon(formula, adduct, parsedIon.MonoisotopicMass, parsedIon.AverageMass, Name);
                        }
                    }
                }
                else
                {
                    adduct = Adduct.FromStringAssumeChargeOnly(reader.GetAttribute(ATTR.charge)); // Ionization mass is already in formula
                }
                if (SettingsCustomIon == null)
                {
                    SettingsCustomIon = new SettingsCustomIon(parsedIon.NeutralFormula, adduct,
                                                              parsedIon.MonoisotopicMass,
                                                              parsedIon.AverageMass,
                                                              parsedIon.Name);
                }
                IsOptional = reader.GetBoolAttribute(ATTR.optional);
            }
            // Consume tag
            reader.Read();

            Validate();
        }
        private XmlReader HandleMassOnlyDeclarations(ref Peptide peptide)
        {
            for (var retry = 0; retry < 4; retry++)                                                                      // Looking for a common mass and set of adducts that all agree
            {
                var adjustParentMass = retry < 2;                                                                        // Do/don't try adjusting the neutral mass as if it had proton gain or loss built in
                var assumeProtonated = retry % 2 == 0;                                                                   // Do/don't try [M+H] vs [M+]
                foreach (var detail in _precursorRawDetails.OrderBy(d => d._declaredHeavy ? 1 : 0, SortOrder.Ascending)) // Look at lights first
                {
                    var parentMassAdjustment = adjustParentMass
                        ? Adduct.NonProteomicProtonatedFromCharge(detail._declaredCharge).ApplyToMass(TypedMass.ZERO_MONO_MASSH)
                        : TypedMass.ZERO_MONO_MASSH;
                    var parentMonoisotopicMass = ProposedMolecule.MonoisotopicMass - parentMassAdjustment;
                    if (_precursorRawDetails.TrueForAll(d =>
                    {
                        var adduct = assumeProtonated
                            ? Adduct.NonProteomicProtonatedFromCharge(d._declaredCharge)
                            : Adduct.FromChargeNoMass(d._declaredCharge);
                        if (d._declaredHeavy)
                        {
                            var unexplainedMass = adduct.MassFromMz(d._declaredMz, MassType.Monoisotopic) - parentMonoisotopicMass;
                            adduct = adduct.ChangeIsotopeLabels(unexplainedMass, _mzDecimalPlaces);
                        }
                        d._proposedAdduct = adduct;
                        return(Math.Abs(d._declaredMz - d._proposedAdduct.MzFromNeutralMass(parentMonoisotopicMass)) <= MzToler);
                    }))
                    {
                        var parentAverageMass = ProposedMolecule.AverageMass - parentMassAdjustment;
                        ProposedMolecule = new CustomMolecule(parentMonoisotopicMass, parentAverageMass,
                                                              peptide.CustomMolecule.Name);
                        return(UpdatePeptideAndInsertAdductsInXML(ref peptide, _precursorRawDetails.Select(d => d._proposedAdduct)));
                    }
                }
            }

            // Unexplained masses can be expressed as mass labels
            if (_precursorRawDetails.TrueForAll(d =>
            {
                var adduct = Adduct.FromChargeNoMass(d._declaredCharge);
                var unexplainedMass = adduct.MassFromMz(d._declaredMz, MassType.Monoisotopic) - ProposedMolecule.MonoisotopicMass;
                d._proposedAdduct = adduct.ChangeIsotopeLabels(unexplainedMass, _mzDecimalPlaces);
                return(Math.Abs(d._declaredMz - d._proposedAdduct.MzFromNeutralMass(ProposedMolecule.MonoisotopicMass)) <= MzToler);
            }))
            {
                return(UpdatePeptideAndInsertAdductsInXML(ref peptide, _precursorRawDetails.Select(d => d._proposedAdduct)));
            }

            // Should never arrive here
            Assume.Fail("Unable to to deduce adducts and common molecule for " + peptide); // Not L10N
            return(UpdatePeptideAndInsertAdductsInXML(ref peptide, _precursorRawDetails.Select(d => d._nominalAdduct)));
        }
Ejemplo n.º 4
0
        private int?ValidateCharge()
        {
            var       helper = new MessageBoxHelper(this);
            int       charge;
            const int min = Transition.MIN_PRODUCT_CHARGE;
            const int max = Transition.MAX_PRODUCT_CHARGE;

            if (!helper.ValidateNumberTextBox(textCharge, min, max, out charge))
            {
                return(null);
            }
            // CONSIDER(bspratt): should we switch to using adducts instead of baking ions into formula?
            _formulaBox.Adduct = Adduct.FromChargeNoMass(charge); // Charge-only adduct, ionizing elements assumed to be included in formula
            return(charge);
        }
Ejemplo n.º 5
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));
            }
        }
Ejemplo n.º 6
0
        private MeasuredIon ValidateCustomIon(string name)
        {
            var    helper  = new MessageBoxHelper(this);
            string formula = (_formulaBox.NeutralFormula ?? string.Empty).ToString(LocalizationHelper.CurrentCulture);
            var    charge  = ValidateCharge();

            if (!charge.HasValue)
            {
                return(null);
            }
            double monoMass;
            double avgMass;

            if (!string.IsNullOrEmpty(formula))
            {
                // Mass is specified by chemical formula
                try
                {
                    monoMass = SequenceMassCalc.FormulaMass(BioMassCalc.MONOISOTOPIC, formula, SequenceMassCalc.MassPrecision);
                    avgMass  = SequenceMassCalc.FormulaMass(BioMassCalc.AVERAGE, formula, SequenceMassCalc.MassPrecision);
                }
                catch (ArgumentException x)
                {
                    helper.ShowTextBoxError(_formulaBox, x.Message);
                    return(null);
                }
            }
            else if (_formulaBox.MonoMass != null ||
                     _formulaBox.AverageMass != null)
            {
                // Mass is specified by combination of mz and charge
                formula = null;
                if (!_formulaBox.ValidateMonoText(helper))
                {
                    return(null);
                }
                if (!_formulaBox.ValidateAverageText(helper))
                {
                    return(null);
                }
                // CONSIDER(bspratt): should we switch to using adducts instead of baking ions into formula?
                _formulaBox.Adduct = Adduct.FromChargeNoMass(charge.Value); // This provokes calculation of mass from displayed mz values
                monoMass           = _formulaBox.MonoMass.Value;
                avgMass            = _formulaBox.AverageMass.Value;
            }
            else
            {
                // User hasn't fully specified either way
                _formulaBox.ShowTextBoxErrorFormula(helper,
                                                    Resources.EditMeasuredIonDlg_OkDialog_Please_specify_a_formula_or_constant_masses);
                return(null);
            }
            if (MeasuredIon.MIN_REPORTER_MASS > monoMass || MeasuredIon.MIN_REPORTER_MASS > avgMass)
            {
                _formulaBox.ShowTextBoxErrorMonoMass(helper, string.Format(Resources.EditMeasuredIonDlg_OkDialog_Reporter_ion_masses_must_be_less_than_or_equal_to__0__,
                                                                           MeasuredIon.MAX_REPORTER_MASS));
                return(null);
            }
            if (monoMass > MeasuredIon.MAX_REPORTER_MASS || avgMass > MeasuredIon.MAX_REPORTER_MASS)
            {
                _formulaBox.ShowTextBoxErrorAverageMass(helper, string.Format(Resources.EditMeasuredIonDlg_OkDialog_Reporter_ion_masses_must_be_less_than_or_equal_to__0__,
                                                                              MeasuredIon.MAX_REPORTER_MASS));
                return(null);
            }

            return(new MeasuredIon(name, formula, monoMass, avgMass, Adduct.FromChargeNoMass(charge.Value))); // Charge-only adduct: user is assumed to have placed ion elements in formula
        }
Ejemplo n.º 7
0
        public void ConvertSmallMolMzOnlyFrom37Test()
        {
            var docSmall = ResultsUtil.DeserializeDocument("SmallMoleculesMzOnly_3-7.sky", GetType());

            AssertEx.IsDocumentState(docSmall, 0, 4, 8, 13, 13);
            int iGroup  = 0;
            var iTran   = 0;
            var heavies = new HashSet <int> {
                2, 3, 5, 11, 13
            };                                                  // Indexes of nodes expected to be !isLight
            var mzPrecursorDeclared = new[]
            {
                "146.2",
                "155.2",
                "500.",
                "300.",
                "320.",
                "177.044724",
                "88.522088",
                "819.42",
                "1639.7",
                "351.217698",
                "355.242805",
                "335.001097",
                "339.247891"
            };

            foreach (var nodeGroup in docSmall.MoleculeTransitionGroups)
            {
                Adduct expectedPrecursorAdduct;
                switch (++iGroup)
                {
                case 6:
                    expectedPrecursorAdduct = Adduct.M_PLUS;
                    break;

                case 7:
                    expectedPrecursorAdduct = Adduct.M_PLUS_2;
                    break;

                case 8:
                    expectedPrecursorAdduct = Adduct.M_MINUS_2.ChangeIsotopeLabels(-.86055);
                    break;

                case 9:
                    expectedPrecursorAdduct = Adduct.M_MINUS;
                    break;

                case 10:
                    expectedPrecursorAdduct = Adduct.M_MINUS_H;
                    break;

                case 11:
                    expectedPrecursorAdduct = Adduct.FromString("[M4H2-H]", Adduct.ADDUCT_TYPE.non_proteomic, null);
                    break;

                case 12:
                    expectedPrecursorAdduct = Adduct.M_MINUS_H.ChangeIsotopeLabels(-.221687, 6);
                    break;

                case 13:
                    expectedPrecursorAdduct = Adduct.FromString("[M4H2-H]", Adduct.ADDUCT_TYPE.non_proteomic, null);
                    break;

                default:
                    // Check translation to adducts worked as expected
                    expectedPrecursorAdduct =
                        Adduct.FromCharge(nodeGroup.PrecursorCharge, Adduct.ADDUCT_TYPE.non_proteomic);
                    if (iGroup == 5)
                    {
                        expectedPrecursorAdduct = expectedPrecursorAdduct.ChangeIsotopeLabels(60.0);
                    }
                    break;
                }
                var prec = mzPrecursorDeclared[iGroup - 1].Split('.')[1].Length;
                Assert.AreEqual(double.Parse(mzPrecursorDeclared[iGroup - 1], CultureInfo.InvariantCulture), Math.Round(nodeGroup.PrecursorMz, prec), "mz iGroup=" + iGroup);
                Assert.AreEqual(expectedPrecursorAdduct, nodeGroup.PrecursorAdduct, "iGroup=" + iGroup);
                Assert.AreEqual(heavies.Contains(iGroup), !nodeGroup.IsLight, "iGroup=" + iGroup);
                // Most product m/z values should be single-digit precision (entered by a person)
                foreach (var nodeTran in nodeGroup.Transitions)
                {
                    if (++iTran < 7)
                    {
                        Assert.AreEqual(Math.Round(nodeTran.Mz, 1), nodeTran.Mz.Value);
                    }
                    var expectedTransitionAdduct = nodeTran.IsMs1 ? expectedPrecursorAdduct : Adduct.FromChargeNoMass(nodeTran.Transition.Charge);
                    Assert.AreEqual(expectedTransitionAdduct, nodeTran.Transition.Adduct, "iTran=" + iTran);
                }
            }

            AssertEx.Serializable(docSmall);
        }