public void TestCustomMoleculeToTSV() { var moleculeAccessionNumbers = new MoleculeAccessionNumbers(new Dictionary <string, string> { { MoleculeAccessionNumbers.TagCAS, "MyCAS" }, { MoleculeAccessionNumbers.TagHMDB, "MyHMDB" }, { MoleculeAccessionNumbers.TagInChI, "MyInChI" }, { MoleculeAccessionNumbers.TagSMILES, "MySmiles" }, { MoleculeAccessionNumbers.TagKEGG, "MyKegg" } }); var smallMoleculeLibraryAttributes = SmallMoleculeLibraryAttributes.Create("MyMolecule", "H2O", "MyInChiKey", moleculeAccessionNumbers.GetNonInChiKeys()); for (var loop = 0; loop < 2; loop++) { var customMolecule = CustomMolecule.FromSmallMoleculeLibraryAttributes(smallMoleculeLibraryAttributes); var target = new Target(customMolecule); var serializableString = target.ToSerializableString(); var roundTrip = Target.FromSerializableString(serializableString); Assert.AreEqual(target, roundTrip); Assert.AreEqual(customMolecule, roundTrip.Molecule); Assert.AreEqual(customMolecule.AccessionNumbers, roundTrip.Molecule.AccessionNumbers); smallMoleculeLibraryAttributes = // Masses instead of formula SmallMoleculeLibraryAttributes.Create("MyMolecule", null, new TypedMass(123.4, MassType.Monoisotopic), new TypedMass(123.45, MassType.Average), "MyInChiKey", moleculeAccessionNumbers.GetNonInChiKeys()); } }
private static void TestAddingSmallMoleculeAsMasses() { RunUI(() => SkylineWindow.SelectedPath = new IdentityPath(SkylineWindow.Document.MoleculeGroups.ElementAt(0).Id)); var doc = SkylineWindow.Document; var formula = COOO13H; var editMoleculeDlg = ShowDialog <EditCustomMoleculeDlg>(SkylineWindow.AddSmallMolecule); var monoMass = BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(formula); var averageMass = BioMassCalc.AVERAGE.CalculateMassFromFormula(formula); var adduct = Adduct.M_PLUS_Na; RunUI(() => { // Verify the interaction of explicitly set mz and charge without formula editMoleculeDlg.NameText = formula; editMoleculeDlg.Adduct = adduct; var mzMono = editMoleculeDlg.Adduct.MzFromNeutralMass(monoMass); var mzAverage = editMoleculeDlg.Adduct.MzFromNeutralMass(averageMass); editMoleculeDlg.FormulaBox.MonoMass = monoMass; editMoleculeDlg.FormulaBox.AverageMass = averageMass; var massPrecisionTolerance = 0.00001; Assert.AreEqual(mzMono, double.Parse(editMoleculeDlg.FormulaBox.MonoText), massPrecisionTolerance); Assert.AreEqual(mzAverage, double.Parse(editMoleculeDlg.FormulaBox.AverageText), massPrecisionTolerance); }); OkDialog(editMoleculeDlg, editMoleculeDlg.OkDialog); var newDoc = WaitForDocumentChange(doc); var compareIon = new CustomMolecule(new TypedMass(monoMass, MassType.Monoisotopic), new TypedMass(averageMass, MassType.Average), formula); Assert.AreEqual(compareIon, newDoc.Molecules.ElementAt(0).CustomMolecule); Assert.AreEqual(compareIon, newDoc.MoleculeTransitionGroups.ElementAt(0).CustomMolecule); Assert.AreEqual(adduct.AdductCharge, newDoc.MoleculeTransitionGroups.ElementAt(0).PrecursorCharge); var predictedMz = BioMassCalc.MONOISOTOPIC.CalculateIonMz(formula, adduct); var actualMz = newDoc.MoleculeTransitionGroups.ElementAt(0).PrecursorMz; Assert.AreEqual(predictedMz, actualMz, Math.Pow(10, -SequenceMassCalc.MassPrecision)); }
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))); }
private void ProposeMoleculeWithCommonFormula(Peptide peptide) { // Examine any provided formulas (including parent molecule and/or precursor ions) and find common basis ProposedMolecule = peptide.CustomMolecule; var precursorsWithFormulas = _precursorRawDetails.Where(d => !string.IsNullOrEmpty(d._formulaUnlabeled)).ToList(); var parentFormula = peptide.CustomMolecule.UnlabeledFormula; var commonFormula = string.IsNullOrEmpty(parentFormula) ? BioMassCalc.MONOISOTOPIC.FindFormulaIntersectionUnlabeled( precursorsWithFormulas.Select(p => p._formulaUnlabeled)) : parentFormula; // Check for consistent and correctly declared precursor formula+adduct var precursorsWithFormulasAndAdducts = precursorsWithFormulas.Where(d => !Adduct.IsNullOrEmpty(d._nominalAdduct)).ToList(); if (precursorsWithFormulasAndAdducts.Any() && precursorsWithFormulas.All( d => d._formulaUnlabeled.Equals(precursorsWithFormulasAndAdducts[0]._formulaUnlabeled))) { commonFormula = precursorsWithFormulasAndAdducts[0]._formulaUnlabeled; } if (!string.IsNullOrEmpty(commonFormula)) { var parentComposition = Molecule.ParseExpression(commonFormula); // Check for children proposing to label more atoms than parent provides, adjust parent as needed foreach (var precursor in _precursorRawDetails.Where(d => d._labels != null)) { foreach (var kvpIsotopeCount in precursor._labels) { var unlabeled = BioMassCalc.UnlabeledFromIsotopeSymbol(kvpIsotopeCount.Key); int parentCount; parentComposition.TryGetValue(unlabeled, out parentCount); if (kvpIsotopeCount.Value > parentCount) { // Child proposes to label more of an atom than the parent possesses (seen in the wild) - update the parent commonFormula = Molecule.AdjustElementCount(commonFormula, unlabeled, kvpIsotopeCount.Value - parentCount); parentComposition = Molecule.ParseExpression(commonFormula); } } } if (!Equals(peptide.CustomMolecule.Formula, commonFormula)) { ProposedMolecule = new CustomMolecule(commonFormula, peptide.CustomMolecule.Name); } } }
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); }
public void TestCustomMoleculeToTSV() { var moleculeAccessionNumbers = new MoleculeAccessionNumbers(new Dictionary <string, string> { { MoleculeAccessionNumbers.TagCAS, "MyCAS" }, { MoleculeAccessionNumbers.TagHMDB, "MyHMDB" }, { MoleculeAccessionNumbers.TagInChI, "MyInChI" }, { MoleculeAccessionNumbers.TagSMILES, "MySmiles" } }); var smallMoleculeLibraryAttributes = SmallMoleculeLibraryAttributes.Create("MyMolecule", "H2O", "MyInChiKey", moleculeAccessionNumbers.GetNonInChiKeys()); var customMolecule = new CustomMolecule(smallMoleculeLibraryAttributes); var target = new Target(customMolecule); var serializableString = target.ToSerializableString(); var roundTrip = Target.FromSerializableString(serializableString); Assert.AreEqual(target, roundTrip); Assert.AreEqual(customMolecule, roundTrip.Molecule); Assert.AreEqual(customMolecule.AccessionNumbers, roundTrip.Molecule.AccessionNumbers); }
public void TestLibIonMobilityInfo() { const string caffeineFormula = "C8H10N4O2"; const string caffeineInChiKey = "RYYVLZVUVIJVGH-UHFFFAOYSA-N"; const string caffeineHMDB = "HMDB01847"; const double HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC = -.01; var dbIon1 = new DbIonMobilityPeptide(new Target("JKLMN"), Adduct.SINGLY_PROTONATED, 1.2, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) { Id = 12345 }; for (var loop = 0; loop < 2; loop++) { var dbIon2 = new DbIonMobilityPeptide(dbIon1); DbIonMobilityPeptide dbIon3 = null; Assert.AreEqual(dbIon1.GetHashCode(), dbIon2.GetHashCode()); Assert.IsFalse(dbIon1.Equals(null)); Assert.IsTrue(dbIon1.Equals(dbIon2 as object)); // ReSharper disable once ExpressionIsAlwaysNull Assert.IsFalse(dbIon1.Equals(dbIon3 as object)); Assert.IsTrue(dbIon1.Equals(dbIon1)); Assert.IsTrue(dbIon1.Equals(dbIon1 as object)); Assert.IsTrue(dbIon1.Equals(dbIon2)); dbIon1.CollisionalCrossSection = 1.3; Assert.AreNotEqual(dbIon1.CollisionalCrossSection, dbIon2.CollisionalCrossSection); if (loop == 1) { dbIon1.ModifiedTarget = new Target("foo"); Assert.AreNotEqual(dbIon1.Target, dbIon2.Target); Assert.AreNotEqual(dbIon1.ModifiedTarget, dbIon2.ModifiedTarget); } else { Assert.AreEqual(dbIon1.ModifiedTarget, dbIon2.ModifiedTarget); Assert.AreEqual(dbIon1.ModifiedTarget.Molecule, dbIon2.ModifiedTarget.Molecule); } dbIon1 = new DbIonMobilityPeptide( SmallMoleculeLibraryAttributes.Create("caffeine", caffeineFormula, caffeineInChiKey, caffeineHMDB), Adduct.FromStringAssumeProtonated("M+Na"), 1.2, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) { Id = 12345 }; } var dictCCS1 = new Dictionary <LibKey, IonMobilityAndCCS[]>(); var ccs1 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 1, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 2, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Collisional cross sections var ccs2 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 3, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 4, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Collisional cross sections const string seq1 = "JKLM"; const string seq2 = "KLMN"; dictCCS1.Add(new LibKey(seq1, 1), ccs1.ToArray()); dictCCS1.Add(new LibKey(seq2, 1), ccs2.ToArray()); var lib = new List <LibraryIonMobilityInfo> { new LibraryIonMobilityInfo("test", dictCCS1) }; var peptideTimes = CollisionalCrossSectionGridViewDriver.ConvertDriftTimesToCollisionalCrossSections(null, lib, 1, null); var validatingIonMobilityPeptides = peptideTimes as ValidatingIonMobilityPeptide[] ?? peptideTimes.ToArray(); Assert.AreEqual(2, validatingIonMobilityPeptides.Length); Assert.AreEqual(1.5, validatingIonMobilityPeptides[0].CollisionalCrossSection); Assert.AreEqual(3.5, validatingIonMobilityPeptides[1].CollisionalCrossSection); Assert.AreEqual(HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC, validatingIonMobilityPeptides[1].HighEnergyDriftTimeOffsetMsec); // Test serialization of molecule with '$' in it, which we use as a tab replacement against XML parser variability var molser = new CustomMolecule(SmallMoleculeLibraryAttributes.Create("caffeine$", caffeineFormula, caffeineInChiKey, caffeineHMDB)); var text = molser.ToSerializableString(); Assert.AreEqual(molser, CustomMolecule.FromSerializableString(text)); var dictCCS2 = new Dictionary <LibKey, IonMobilityAndCCS[]>(); var ccs3 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.GetIonMobilityValue(4, eIonMobilityUnits.drift_time_msec), null, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.GetIonMobilityValue(5, eIonMobilityUnits.drift_time_msec), null, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Drift times const string seq3 = "KLMNJ"; dictCCS2.Add(new LibKey(seq3, Adduct.SINGLY_PROTONATED), ccs3.ToArray()); lib.Add(new LibraryIonMobilityInfo("test2", dictCCS2)); List <LibraryIonMobilityInfo> lib1 = lib; AssertEx.ThrowsException <Exception>(() => CollisionalCrossSectionGridViewDriver.ConvertDriftTimesToCollisionalCrossSections(null, lib1, 2, null), String.Format( Resources.CollisionalCrossSectionGridViewDriver_ProcessIonMobilityValues_Cannot_import_measured_ion_mobility_for_sequence__0___no_collisional_cross_section_conversion_parameters_were_provided_for_charge_state__1__, seq3, 1)); var regressions = new Dictionary <int, RegressionLine> { { 1, new RegressionLine(2, 1) } }; lib = new List <LibraryIonMobilityInfo> { new LibraryIonMobilityInfo("test", dictCCS2) }; peptideTimes = CollisionalCrossSectionGridViewDriver.ConvertDriftTimesToCollisionalCrossSections(null, lib, 1, regressions); validatingIonMobilityPeptides = peptideTimes as ValidatingIonMobilityPeptide[] ?? peptideTimes.ToArray(); Assert.AreEqual(1, validatingIonMobilityPeptides.Length); Assert.AreEqual(1.75, validatingIonMobilityPeptides[0].CollisionalCrossSection); }
/// <summary> /// For creating at the Molecule level (create molecule and first transition group) or modifying at the transition level /// Null values imply "don't ask user for this" /// </summary> public EditCustomMoleculeDlg(SkylineWindow parent, UsageMode usageMode, string title, Identity initialId, IEnumerable <Identity> existingIds, int minCharge, int maxCharge, SrmSettings settings, CustomMolecule molecule, Adduct defaultCharge, ExplicitTransitionGroupValues explicitTransitionGroupAttributes, ExplicitTransitionValues explicitTransitionAttributes, ExplicitRetentionTimeInfo explicitRetentionTime, IsotopeLabelType defaultIsotopeLabelType) { Text = title; _parent = parent; _initialId = initialId; _existingIds = existingIds; _minCharge = minCharge; _maxCharge = maxCharge; _transitionSettings = settings != null ? settings.TransitionSettings : null; _peptideSettings = settings != null ? settings.PeptideSettings : null; _resultAdduct = Adduct.EMPTY; _resultCustomMolecule = molecule; _usageMode = usageMode; var enableFormulaEditing = usageMode == UsageMode.moleculeNew || usageMode == UsageMode.moleculeEdit || usageMode == UsageMode.fragment; var enableAdductEditing = usageMode == UsageMode.moleculeNew || usageMode == UsageMode.precursor || usageMode == UsageMode.fragment; var suggestOnlyAdductsWithMass = usageMode != UsageMode.fragment; var needExplicitTransitionValues = usageMode == UsageMode.fragment; var needExplicitTransitionGroupValues = usageMode == UsageMode.moleculeNew || usageMode == UsageMode.precursor; InitializeComponent(); NameText = molecule == null ? String.Empty : molecule.Name; textName.Enabled = usageMode == UsageMode.moleculeNew || usageMode == UsageMode.moleculeEdit || usageMode == UsageMode.fragment; // Can user edit name? var needOptionalValuesBox = explicitRetentionTime != null || explicitTransitionGroupAttributes != null || explicitTransitionAttributes != null; if (!needExplicitTransitionValues) { labelCollisionEnergy.Visible = false; textCollisionEnergy.Visible = false; labelSLens.Visible = false; textSLens.Visible = false; labelConeVoltage.Visible = false; textConeVoltage.Visible = false; labelIonMobilityHighEnergyOffset.Visible = false; textIonMobilityHighEnergyOffset.Visible = false; labelDeclusteringPotential.Visible = false; textDeclusteringPotential.Visible = false; } if (!needExplicitTransitionGroupValues) { labelCCS.Visible = false; textBoxCCS.Visible = false; labelIonMobility.Visible = false; textIonMobility.Visible = false; labelIonMobilityUnits.Visible = false; comboBoxIonMobilityUnits.Visible = false; } var heightDelta = 0; // Initialise the ion mobility units dropdown with L10N values foreach (eIonMobilityUnits t in Enum.GetValues(typeof(eIonMobilityUnits))) { comboBoxIonMobilityUnits.Items.Add(IonMobilityFilter.IonMobilityUnitsL10NString(t)); } if (needOptionalValuesBox) { var newHeight = groupBoxOptionalValues.Height; var movers = new List <Control>(); int offset = 0; if (!needExplicitTransitionGroupValues && !needExplicitTransitionValues) { // We blanked out everything but the retention time newHeight = labelCollisionEnergy.Location.Y; } else if (!needExplicitTransitionGroupValues) { // We need to shift transition-level items up to where retention time was movers.AddRange(new Control[] { textCollisionEnergy, labelCollisionEnergy, textDeclusteringPotential, labelDeclusteringPotential, textSLens, labelSLens, textConeVoltage, labelConeVoltage, textIonMobilityHighEnergyOffset, labelIonMobilityHighEnergyOffset }); labelIonMobilityHighEnergyOffset.Location = labelIonMobility.Location; textIonMobilityHighEnergyOffset.Location = textIonMobility.Location; offset = labelCollisionEnergy.Location.Y - labelRetentionTime.Location.Y; newHeight = textBoxCCS.Location.Y; } else if (!needExplicitTransitionValues) { // We need to shift precursor-level items up to where retention time was movers.AddRange(new Control[] { textBoxCCS, labelCCS, textIonMobility, labelIonMobility, comboBoxIonMobilityUnits, labelIonMobilityUnits }); offset = labelIonMobility.Location.Y - (explicitRetentionTime == null ? labelRetentionTime.Location.Y : labelCollisionEnergy.Location.Y); newHeight = explicitRetentionTime == null ? textSLens.Location.Y : textIonMobility.Location.Y; } foreach (var mover in movers) { mover.Anchor = AnchorStyles.Left | AnchorStyles.Top; mover.Location = new Point(mover.Location.X, mover.Location.Y - offset); } heightDelta = groupBoxOptionalValues.Height - newHeight; groupBoxOptionalValues.Height = newHeight; } ResultExplicitTransitionGroupValues = new ExplicitTransitionGroupValues(explicitTransitionGroupAttributes); ResultExplicitTransitionValues = new ExplicitTransitionValues(explicitTransitionAttributes); string labelAverage = !defaultCharge.IsEmpty ? Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg_A_verage_m_z_ : Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg_A_verage_mass_; string labelMono = !defaultCharge.IsEmpty ? Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg__Monoisotopic_m_z_ : Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg__Monoisotopic_mass_; var defaultFormula = molecule == null ? string.Empty : molecule.Formula; var transition = initialId as Transition; FormulaBox.EditMode editMode; if (enableAdductEditing && !enableFormulaEditing) { editMode = FormulaBox.EditMode.adduct_only; } else if (!enableAdductEditing && enableFormulaEditing) { editMode = FormulaBox.EditMode.formula_only; } else { editMode = FormulaBox.EditMode.formula_and_adduct; } string formulaBoxLabel; if (defaultCharge.IsEmpty) { formulaBoxLabel = Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg_Chemi_cal_formula_; } else if (editMode == FormulaBox.EditMode.adduct_only) { var prompt = defaultFormula; if (string.IsNullOrEmpty(defaultFormula) && molecule != null) { // Defined by mass only prompt = molecule.ToString(); } formulaBoxLabel = string.Format(Resources.EditCustomMoleculeDlg_EditCustomMoleculeDlg_Addu_ct_for__0__, prompt); } else { formulaBoxLabel = Resources.EditMeasuredIonDlg_EditMeasuredIonDlg_Ion__chemical_formula_; } double?averageMass = null; double?monoMass = null; if (transition != null && string.IsNullOrEmpty(defaultFormula) && transition.IsCustom()) { averageMass = transition.CustomIon.AverageMass; monoMass = transition.CustomIon.MonoisotopicMass; } else if (molecule != null) { averageMass = molecule.AverageMass; monoMass = molecule.MonoisotopicMass; } _formulaBox = new FormulaBox(false, // Not proteomic, so offer Cl and Br in atoms popup formulaBoxLabel, labelAverage, labelMono, defaultCharge, editMode, suggestOnlyAdductsWithMass) { NeutralFormula = defaultFormula, AverageMass = averageMass, MonoMass = monoMass, Location = new Point(textName.Left, textName.Bottom + 12) }; _formulaBox.ChargeChange += (sender, args) => { if (!_formulaBox.Adduct.IsEmpty) { Adduct = _formulaBox.Adduct; var revisedFormula = _formulaBox.NeutralFormula + Adduct.AdductFormula; if (!Equals(revisedFormula, _formulaBox.Formula)) { _formulaBox.Formula = revisedFormula; } if (string.IsNullOrEmpty(_formulaBox.NeutralFormula) && averageMass.HasValue) { _formulaBox.AverageMass = averageMass; _formulaBox.MonoMass = monoMass; } } }; Controls.Add(_formulaBox); _formulaBox.TabIndex = 2; _formulaBox.Enabled = enableFormulaEditing || enableAdductEditing; Adduct = defaultCharge; var needCharge = !Adduct.IsEmpty; textCharge.Visible = labelCharge.Visible = needCharge; if (needOptionalValuesBox && !needCharge) { heightDelta += groupBoxOptionalValues.Location.Y - labelCharge.Location.Y; groupBoxOptionalValues.Location = new Point(groupBoxOptionalValues.Location.X, labelCharge.Location.Y); } if (explicitRetentionTime == null) { // Don't ask user for retetention times RetentionTime = null; RetentionTimeWindow = null; labelRetentionTime.Visible = false; labelRetentionTimeWindow.Visible = false; textRetentionTime.Visible = false; textRetentionTimeWindow.Visible = false; } else { RetentionTime = explicitRetentionTime.RetentionTime; RetentionTimeWindow = explicitRetentionTime.RetentionTimeWindow; } if (!needOptionalValuesBox) { groupBoxOptionalValues.Visible = false; heightDelta = groupBoxOptionalValues.Height; } // Initialize label if (settings != null && defaultIsotopeLabelType != null) { _driverLabelType = new PeptideSettingsUI.LabelTypeComboDriver(PeptideSettingsUI.LabelTypeComboDriver.UsageType.InternalStandardPicker, comboIsotopeLabelType, settings.PeptideSettings.Modifications, null, null, null, null) { SelectedName = defaultIsotopeLabelType.Name }; } else { comboIsotopeLabelType.Visible = false; labelIsotopeLabelType.Visible = false; } Height -= heightDelta; }
/// <summary> /// For modifying at the Molecule level /// </summary> public EditCustomMoleculeDlg(SkylineWindow parent, string title, SrmSettings settings, CustomMolecule molecule, ExplicitRetentionTimeInfo explicitRetentionTime) : this(parent, UsageMode.moleculeEdit, title, null, null, 0, 0, null, molecule, Adduct.EMPTY, null, null, explicitRetentionTime, null) { }
public void SetResult(CustomMolecule mol, Adduct adduct) { _resultCustomMolecule = mol; _resultAdduct = adduct; SetNameAndFormulaBoxText(); }
private static void TestAddingSmallMolecule() { RunUI(() => SkylineWindow.SelectedPath = new IdentityPath(SkylineWindow.Document.MoleculeGroups.ElementAt(0).Id)); var doc = SkylineWindow.Document; var editMoleculeDlg = ShowDialog <EditCustomMoleculeDlg>(SkylineWindow.AddSmallMolecule); // Less extreme values should trigger a warning about instrument limits RunUI(() => { editMoleculeDlg.FormulaBox.MonoMass = CustomMolecule.MAX_MASS - 100; editMoleculeDlg.FormulaBox.AverageMass = editMoleculeDlg.FormulaBox.MonoMass; }); RunDlg <MessageDlg>(editMoleculeDlg.OkDialog, dlg => { AssertEx.AreComparableStrings( Resources .SkylineWindow_AddMolecule_The_precursor_m_z_for_this_molecule_is_out_of_range_for_your_instrument_settings_, dlg.Message); dlg.OkDialog(); // Dismiss the warning }); RunUI(() => { // Verify the interaction of explicitly set formula, mz and charge editMoleculeDlg.FormulaBox.Formula = C12H12; var mono = editMoleculeDlg.FormulaBox.MonoMass ?? -1; var average = editMoleculeDlg.FormulaBox.AverageMass ?? -1; var massPrecisionTolerance = Math.Pow(10, -SequenceMassCalc.MassPrecision); Assert.AreEqual(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12), mono, massPrecisionTolerance); Assert.AreEqual(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12), average, massPrecisionTolerance); Assert.AreEqual(mono, double.Parse(editMoleculeDlg.FormulaBox.MonoText), massPrecisionTolerance); Assert.AreEqual(average, double.Parse(editMoleculeDlg.FormulaBox.AverageText), massPrecisionTolerance); editMoleculeDlg.Adduct = Adduct.NonProteomicProtonatedFromCharge(3); Assert.AreEqual( Math.Round(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), mono); // Masses should not change Assert.AreEqual( Math.Round(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), average); editMoleculeDlg.Adduct = Adduct.FromChargeProtonated(1); Assert.AreEqual( Math.Round(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), mono); // Masses should not change Assert.AreEqual( Math.Round(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), average); Assert.AreEqual(BioMassCalc.MONOISOTOPIC.CalculateIonMz(C12H12, editMoleculeDlg.Adduct), mono + BioMassCalc.MassProton, massPrecisionTolerance); Assert.AreEqual(BioMassCalc.AVERAGE.CalculateIonMz(C12H12, editMoleculeDlg.Adduct), average + BioMassCalc.MassProton, massPrecisionTolerance); editMoleculeDlg.Adduct = Adduct.NonProteomicProtonatedFromCharge(-1); // Validate negative charges Assert.AreEqual( Math.Round(BioMassCalc.MONOISOTOPIC.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), mono); // Masses should not change Assert.AreEqual( Math.Round(BioMassCalc.AVERAGE.CalculateMassFromFormula(C12H12), SequenceMassCalc.MassPrecision), average); Assert.AreEqual(BioMassCalc.MONOISOTOPIC.CalculateIonMz(C12H12, editMoleculeDlg.Adduct), mono - BioMassCalc.MassProton, massPrecisionTolerance); Assert.AreEqual(BioMassCalc.AVERAGE.CalculateIonMz(C12H12, editMoleculeDlg.Adduct), average - BioMassCalc.MassProton, massPrecisionTolerance); editMoleculeDlg.FormulaBox.Formula = string.Empty; // Simulate user blanking out the formula Assert.AreEqual(mono, editMoleculeDlg.FormulaBox.MonoMass); // Leaves masses untouched Assert.AreEqual(average, editMoleculeDlg.FormulaBox.AverageMass); editMoleculeDlg.FormulaBox.AverageMass = averageMass100; editMoleculeDlg.FormulaBox.MonoMass = monoMass105; editMoleculeDlg.NameText = "test"; Assert.IsTrue(string.IsNullOrEmpty(editMoleculeDlg.FormulaBox.Formula)); Assert.AreEqual(averageMass100, editMoleculeDlg.FormulaBox.AverageMass); Assert.AreEqual(monoMass105, editMoleculeDlg.FormulaBox.MonoMass); var monoMzText = editMoleculeDlg.FormulaBox.MonoText; var averageMzText = editMoleculeDlg.FormulaBox.AverageText; var mzMonoAtMminusH = double.Parse(monoMzText); var mzAverageAtMminusH = double.Parse(averageMzText); editMoleculeDlg.Adduct = Adduct.NonProteomicProtonatedFromCharge(3); Assert.AreEqual(monoMzText, editMoleculeDlg.FormulaBox.MonoText); // m/z readout should not change Assert.AreEqual(averageMzText, editMoleculeDlg.FormulaBox.AverageText); // If this mz is now said to be due to higher charge, then mass must greater Assert.AreEqual(3 * (mzAverageAtMminusH - BioMassCalc.MassProton), editMoleculeDlg.FormulaBox.AverageMass.Value, massPrecisionTolerance); Assert.AreEqual(3 * (mzMonoAtMminusH - BioMassCalc.MassProton), editMoleculeDlg.FormulaBox.MonoMass.Value, massPrecisionTolerance); // If this mz is now said to be due to lesser z, then mass must smaller editMoleculeDlg.Adduct = Adduct.NonProteomicProtonatedFromCharge(1); Assert.AreEqual(monoMzText, editMoleculeDlg.FormulaBox.MonoText); // m/z readout should not change Assert.AreEqual(averageMzText, editMoleculeDlg.FormulaBox.AverageText); var massAverage = editMoleculeDlg.FormulaBox.AverageMass.Value; var massMono = editMoleculeDlg.FormulaBox.MonoMass.Value; Assert.AreEqual(averageMass100 - BioMassCalc.MassProton, massAverage, massPrecisionTolerance); // Mass should change back Assert.AreEqual(monoMass105 - BioMassCalc.MassProton, massMono, massPrecisionTolerance); }); var adduct = Adduct.NonProteomicProtonatedFromCharge(1); RunUI(() => { editMoleculeDlg.NameText = COOO13H; editMoleculeDlg.FormulaBox.Formula = COOO13H + adduct.AdductFormula; }); OkDialog(editMoleculeDlg, editMoleculeDlg.OkDialog); var compareIon = new CustomMolecule(COOO13H, COOO13H); var newDoc = WaitForDocumentChange(doc); Assert.AreEqual(compareIon, newDoc.Molecules.ElementAt(0).CustomMolecule); Assert.AreEqual(compareIon, newDoc.MoleculeTransitionGroups.ElementAt(0).CustomMolecule); Assert.AreEqual(adduct.AdductCharge, newDoc.MoleculeTransitionGroups.ElementAt(0).PrecursorCharge); var predictedMz = BioMassCalc.MONOISOTOPIC.CalculateIonMz(COOO13H, adduct); var actualMz = newDoc.MoleculeTransitionGroups.ElementAt(0).PrecursorMz; Assert.AreEqual(predictedMz, actualMz, Math.Pow(10, -SequenceMassCalc.MassPrecision)); }
public void TestLibIonMobilityInfo() { const string caffeineFormula = "C8H10N4O2"; const string caffeineInChiKey = "RYYVLZVUVIJVGH-UHFFFAOYSA-N"; const string caffeineHMDB = "HMDB01847"; const double HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC = -.01; var dbMolecule = new DbMolecule(new Target("JKLMN")) { Id = 123456 }; var dbPrecursorIon = new DbPrecursorIon(dbMolecule, Adduct.SINGLY_PROTONATED) { Id = 1234567 }; var dbIonMobilityValue = new DbPrecursorAndIonMobility(dbPrecursorIon, 1.2, 2.3, eIonMobilityUnits.drift_time_msec, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) { Id = 12345 }; DbPrecursorAndIonMobility dbPrecursorAndIonMobilityValue2 = new DbPrecursorAndIonMobility(dbIonMobilityValue); for (var loop = 0; loop < 2; loop++) { Assert.AreEqual(dbIonMobilityValue.GetHashCode(), dbPrecursorAndIonMobilityValue2.GetHashCode()); Assert.IsFalse(dbIonMobilityValue.Equals(null)); Assert.IsTrue(dbIonMobilityValue.Equals(dbPrecursorAndIonMobilityValue2 as object)); Assert.IsTrue(dbIonMobilityValue.Equals(dbIonMobilityValue)); Assert.IsTrue(dbIonMobilityValue.Equals(dbIonMobilityValue as object)); Assert.IsTrue(dbPrecursorAndIonMobilityValue2.Equals(dbIonMobilityValue)); dbIonMobilityValue.CollisionalCrossSectionSqA = 1.3; Assert.AreNotEqual(dbIonMobilityValue.CollisionalCrossSectionSqA, dbPrecursorAndIonMobilityValue2.CollisionalCrossSectionSqA); if (loop == 1) { dbIonMobilityValue.DbPrecursorIon = new DbPrecursorIon(new Target("foo"), Adduct.SINGLY_PROTONATED) { Id = 1234567 }; Assert.AreNotEqual(dbIonMobilityValue.DbPrecursorIon.GetTarget(), dbMolecule); } else { Assert.AreEqual(dbIonMobilityValue.DbPrecursorIon.DbMolecule, dbMolecule); } dbIonMobilityValue = new DbPrecursorAndIonMobility( new DbPrecursorIon( SmallMoleculeLibraryAttributes.Create("caffeine", caffeineFormula, caffeineInChiKey, caffeineHMDB), Adduct.FromStringAssumeProtonated("M+Na")) { Id = 23456 }, 1.2, 2.3, eIonMobilityUnits.drift_time_msec, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) { Id = 12345 }; dbPrecursorAndIonMobilityValue2 = new DbPrecursorAndIonMobility(dbIonMobilityValue); } var dictCCS1 = new Dictionary <LibKey, IonMobilityAndCCS[]>(); var im = IonMobilityValue.GetIonMobilityValue(12, eIonMobilityUnits.drift_time_msec); var ccs1 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 1, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 2, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Collisional cross sections var ccs2 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(im, 3, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.EMPTY, 4, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Collisional cross sections const string seq1 = "JKLM"; const string seq2 = "KLMN"; dictCCS1.Add(new LibKey(seq1, 1), ccs1.ToArray()); dictCCS1.Add(new LibKey(seq2, 1), ccs2.ToArray()); var lib = new List <LibraryIonMobilityInfo> { new LibraryIonMobilityInfo("test", false, dictCCS1) }; var peptideTimes = CollisionalCrossSectionGridViewDriver.CollectIonMobilitiesAndCollisionalCrossSections(null, lib, 1); var validatingIonMobilityPeptides = peptideTimes as ValidatingIonMobilityPrecursor[] ?? peptideTimes.ToArray(); Assert.AreEqual(2, validatingIonMobilityPeptides.Length); Assert.AreEqual(1.5, validatingIonMobilityPeptides[0].CollisionalCrossSectionSqA); Assert.AreEqual(3.5, validatingIonMobilityPeptides[1].CollisionalCrossSectionSqA); Assert.AreEqual(HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC, validatingIonMobilityPeptides[1].HighEnergyIonMobilityOffset); // This time with multiple CCS conformers supported lib = new List <LibraryIonMobilityInfo> { new LibraryIonMobilityInfo("test", true, dictCCS1) }; peptideTimes = CollisionalCrossSectionGridViewDriver.CollectIonMobilitiesAndCollisionalCrossSections(null, lib, 1); validatingIonMobilityPeptides = peptideTimes as ValidatingIonMobilityPrecursor[] ?? peptideTimes.ToArray(); Assert.AreEqual(4, validatingIonMobilityPeptides.Length); Assert.AreEqual(1, validatingIonMobilityPeptides[0].CollisionalCrossSectionSqA); Assert.AreEqual(2, validatingIonMobilityPeptides[1].CollisionalCrossSectionSqA); Assert.AreEqual(3, validatingIonMobilityPeptides[2].CollisionalCrossSectionSqA); Assert.AreEqual(4, validatingIonMobilityPeptides[3].CollisionalCrossSectionSqA); Assert.AreEqual(HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC, validatingIonMobilityPeptides[1].HighEnergyIonMobilityOffset); // Test serialization of molecule with '$' in it, which we use as a tab replacement against XML parser variability var molser = CustomMolecule.FromSmallMoleculeLibraryAttributes(SmallMoleculeLibraryAttributes.Create("caffeine$", caffeineFormula, caffeineInChiKey, caffeineHMDB)); var text = molser.ToSerializableString(); Assert.AreEqual(molser, CustomMolecule.FromSerializableString(text)); // Test handling of SmallMoleculeLibraryAttributes for mass-only descriptions var molserB = CustomMolecule.FromSmallMoleculeLibraryAttributes(SmallMoleculeLibraryAttributes.Create("caffeine$", null, new TypedMass(123.4, MassType.Monoisotopic), new TypedMass(123.45, MassType.Average), caffeineInChiKey, caffeineHMDB)); var textB = molserB.ToSerializableString(); Assert.AreEqual(molserB, CustomMolecule.FromSerializableString(textB)); var dictCCS2 = new Dictionary <LibKey, IonMobilityAndCCS[]>(); var ccs3 = new List <IonMobilityAndCCS> { IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.GetIonMobilityValue(4, eIonMobilityUnits.drift_time_msec), 1.75, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC), IonMobilityAndCCS.GetIonMobilityAndCCS(IonMobilityValue.GetIonMobilityValue(5, eIonMobilityUnits.drift_time_msec), null, HIGH_ENERGY_DRIFT_TIME_OFFSET_MSEC) }; // Drift times const string seq3 = "KLMNJ"; dictCCS2.Add(new LibKey(seq3, Adduct.SINGLY_PROTONATED), ccs3.ToArray()); lib = new List <LibraryIonMobilityInfo> { new LibraryIonMobilityInfo("test", false, dictCCS2) }; peptideTimes = CollisionalCrossSectionGridViewDriver.CollectIonMobilitiesAndCollisionalCrossSections(null, lib, 1); validatingIonMobilityPeptides = peptideTimes as ValidatingIonMobilityPrecursor[] ?? peptideTimes.ToArray(); Assert.AreEqual(1, validatingIonMobilityPeptides.Length); Assert.AreEqual(1.75, validatingIonMobilityPeptides[0].CollisionalCrossSectionSqA); }
public Dictionary <LibKey, IonMobilityAndCCS> GetTableMeasuredIonMobility(bool useHighEnergyOffsets, eIonMobilityUnits units) { var e = new CancelEventArgs(); var dict = new Dictionary <LibKey, IonMobilityAndCCS>(); foreach (DataGridViewRow row in _gridMeasuredDriftTimePeptides.Rows) { if (row.IsNewRow) { continue; } string seq; if (!ValidateSequence(e, row.Cells[EditDriftTimePredictorDlg.COLUMN_SEQUENCE], out seq)) { return(null); } // OK, we have a non-empty "sequence" string, but is that actually a peptide or a molecule? // See if there's anything in the document whose text representation matches what's in the list var target = Program.MainWindow.Document.Molecules.Select(m => m.Target).FirstOrDefault(t => seq.Equals(t.ToString())); if (target == null || target.IsEmpty) { // Does seq evaluate as a peptide? target = !seq.All(c => char.IsUpper(c) || char.IsDigit(c) || @"[+-,.]()".Contains(c)) ? new Target(CustomMolecule.FromSerializableString(seq)) : Target.FromSerializableString(seq); } Adduct charge; if (!ValidateCharge(e, row.Cells[EditDriftTimePredictorDlg.COLUMN_CHARGE], target.IsProteomic, out charge)) { return(null); } double mobility; if (!ValidateDriftTime(e, row.Cells[EditDriftTimePredictorDlg.COLUMN_ION_MOBILITY], out mobility)) { return(null); } double?ccs; if (!ValidateCCS(e, row.Cells[EditDriftTimePredictorDlg.COLUMN_CCS], out ccs)) { return(null); } double highEnergyOffset = 0; // Set default value in case user does not provide one if (useHighEnergyOffsets && !ValidateHighEnergyDriftTimeOffset(e, row.Cells[EditDriftTimePredictorDlg.COLUMN_HIGH_ENERGY_OFFSET], out highEnergyOffset)) { return(null); } var ionMobility = IonMobilityValue.GetIonMobilityValue(mobility, units); try { dict.Add(new LibKey(target, charge), IonMobilityAndCCS.GetIonMobilityAndCCS(ionMobility, ccs, highEnergyOffset)); } // ReSharper disable once EmptyGeneralCatchClause catch { // just take the first seen } } return(dict); }