/// <summary> /// Computes the isotope distribution of the tracer /// </summary> private void ComputeMasses() { var res = Workspace.GetAminoAcidFormulas(); if (!AminoAcidSymbol.HasValue) { // If the tracer is a single element, then its mass is just the normal mass // of the element plus the mass shift. TraceeMasses = res.GetMassDistribution(Molecule.Parse(TraceeSymbol), 0); double tracerMass = TraceeMasses.MostAbundanceMass + DeltaMass; TracerMasses = MassDistribution.NewInstance(new Dictionary <double, double> { { tracerMass, 1.0 } }, 0, 0); return; } // If the tracer is an amino acid, get the masses of the amino acid, and // add in atoms with the correct mass shift. var heavyMasses = new Dictionary <double, double>(); heavyMasses.Add(0, 1 - AtomPercentEnrichment / 100); heavyMasses.Add(DeltaMass / AtomCount, AtomPercentEnrichment / 100); const string tempName = "Temp"; var isotopeAbundances = res.IsotopeAbundances.SetAbundances( tempName, MassDistribution.NewInstance(heavyMasses, 0, 0)); res = res.SetIsotopeAbundances(isotopeAbundances); var formula = Molecule.Parse(res.Formulas[AminoAcidSymbol.Value]); var tracerFormula = Molecule.Parse(formula + tempName + AtomCount); TraceeMasses = res.GetMassDistribution(formula, 0); TracerMasses = res.GetMassDistribution(tracerFormula, 0); }
public MassDistribution GetPrecursorMassDistribution() { if (_precursorMassDistribution == null) { var fragmentedMoleculeSettings = FragmentedMolecule.Settings.FromSrmSettings(Settings); _precursorMassDistribution = fragmentedMoleculeSettings .GetMassDistribution(GetPrecursorFormula().Molecule, 0, 0); } return(_precursorMassDistribution); }
/// <summary> /// Constructor for an IsotopeDistInfo using TransitionFullScanSettings /// </summary> public static IsotopeDistInfo MakeIsotopeDistInfo(MassDistribution mzDistribution, TypedMass monoisotopicMass, Adduct adduct, TransitionFullScan fullScan) { // Centering resolution must be inversely proportional to charge state // High charge states can bring major peaks close enough together to // cause them to be combined and centered in isotope distribution valleys double massResolution = TransitionFullScan.ISOTOPE_PEAK_CENTERING_RES / (1 + Math.Abs(adduct.AdductCharge / 15.0)); return(new IsotopeDistInfo(mzDistribution, monoisotopicMass, adduct, fullScan.GetPrecursorFilterWindow, massResolution, TransitionFullScan.MIN_ISOTOPE_PEAK_ABUNDANCE)); }
public MassDistribution GetMassDistribution(Molecule molecule, double massShift, int charge) { var emptyMassDistribution = new MassDistribution(MassResolution, MinAbundance); var massDistribution = emptyMassDistribution; foreach (var entry in molecule) { massDistribution = massDistribution.Add(emptyMassDistribution.Add(IsotopeAbundances[entry.Key]).Multiply(entry.Value)); } if (charge != 0 || massShift != 0) { massDistribution = massDistribution.OffsetAndDivide(massShift - charge * BioMassCalc.MassElectron, Math.Max(1, Math.Abs(charge))); } return(massDistribution); }
/// <summary> /// Synchronizes a single <see cref="MassDistribution"/> object with corresponding /// masses from a <see cref="BioMassCalc"/>. /// </summary> private static MassDistribution SynchDist(MassDistribution massDist, double monoMassCalc, double secondMassCalc, double thirdMassCalc) { var massDistOrdered = massDist.MassesSortedByAbundance(); if (EqualDistMasses(massDistOrdered, monoMassCalc, secondMassCalc, thirdMassCalc)) { return(massDist); } var dictFixDist = new Dictionary <double, double>(massDist); ReplaceMass(dictFixDist, massDistOrdered, 0, monoMassCalc); ReplaceMass(dictFixDist, massDistOrdered, 1, secondMassCalc); ReplaceMass(dictFixDist, massDistOrdered, 2, thirdMassCalc); return(MassDistribution.NewInstance(dictFixDist, 0, 0)); }
private List <MzRange> GetMasses() { var massesAndFrequency = new Dictionary <double, double>(); var tracerFormulaEnumerator = new TracerFormulaEnumerator(Sequence, _tracerDefs.Values); while (tracerFormulaEnumerator.MoveNext()) { MassDistribution massDistribution = _aminoAcidFormulas.GetMassDistribution( MoleculeFromTracerFormula(tracerFormulaEnumerator.Current), 0); massDistribution = massDistribution.OffsetAndDivide(_aminoAcidFormulas.GetMassShift(Sequence), 1); foreach (var entry in massDistribution) { if (entry.Value < MinAbundance) { continue; } double currentAbundance; massesAndFrequency.TryGetValue(entry.Key, out currentAbundance); if (currentAbundance >= entry.Value) { continue; } massesAndFrequency[entry.Key] = entry.Value; } } var allMasses = new List <double>(massesAndFrequency.Keys); allMasses.Sort(); var result = new List <MzRange>(); foreach (var mass in allMasses) { if (result.Count == 0) { result.Add(new MzRange(mass)); continue; } var lastMass = result[result.Count - 1]; if (lastMass.Distance(mass) > MassResolution) { result.Add(new MzRange(mass)); continue; } result[result.Count - 1] = lastMass.Union(mass); } return(result); }
public IsotopeDistInfo(MassDistribution massDistribution, TypedMass monoisotopicMass, Adduct adduct, Func <double, double> calcFilterWindow, double massResolution, double minimumAbundance) { _monoisotopicMass = monoisotopicMass; _adduct = adduct.Unlabeled; // Don't reapply explicit isotope labels // Get peak center of mass values for the given resolution var q1FilterValues = MassDistribution.NewInstance(massDistribution, massResolution, 0).Keys.ToList(); // Find the monoisotopic m/z and make sure it is exactly the expected number double monoMz = _adduct.MzFromNeutralMass(_monoisotopicMass); double monoMzDist = monoMz; int monoMassIndex = 0; for (int i = 0; i < q1FilterValues.Count; i++) { double peakCenterMz = q1FilterValues[i]; double filterWindow = calcFilterWindow(peakCenterMz); double startMz = peakCenterMz - filterWindow / 2; double endMz = startMz + filterWindow; if (startMz < monoMz && monoMz < endMz) { monoMzDist = q1FilterValues[i]; q1FilterValues[i] = monoMz; monoMassIndex = i; break; } } // Insert a M-1 peak, even if it is not expected in the isotope mass distribution if (monoMassIndex == 0 && q1FilterValues.Count > 1) { // Use the delta from the original distribution monoMz to the next peak q1FilterValues.Insert(0, monoMz + monoMzDist - q1FilterValues[1]); monoMassIndex++; } if (!q1FilterValues.Any()) { // This should never happen, but just in case it does happen, we safely exit the constructor ExpectedPeaks = ImmutableList.Singleton(new MzRankProportion(monoMz, 0, 1.0f)); MonoMassIndex = BaseMassIndex = 0; return; } var signedQ1FilterValues = q1FilterValues.Select(q => new SignedMz(q, adduct.AdductCharge < 0)).ToList(); // Use the filtering algorithm that will be used on real data to determine the // expected proportions of the mass distribution that will end up filtered into // peaks // CONSIDER: Mass accuracy information is not calculated here var key = new PrecursorTextId(signedQ1FilterValues[monoMassIndex], null, null, ChromExtractor.summed); var filter = new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, 0, null, null, false, false); filter.AddQ1FilterValues(signedQ1FilterValues, calcFilterWindow); var expectedSpectrum = filter.FilterQ1SpectrumList(new[] { new MsDataSpectrum { Mzs = massDistribution.Keys.ToArray(), Intensities = massDistribution.Values.ToArray(), NegativeCharge = (adduct.AdductCharge < 0) } }); int startIndex = expectedSpectrum.Intensities.IndexOf(inten => inten >= minimumAbundance); if (startIndex == -1) { // This can happen if the amino acid modifications are messed up, // and the peptide mass is negative or something. ExpectedPeaks = ImmutableList.Singleton(new MzRankProportion(monoMz, 0, 1.0f)); MonoMassIndex = BaseMassIndex = 0; return; } // Always include the M-1 peak, even if it is expected to have zero intensity if (startIndex > monoMassIndex - 1) { startIndex = monoMassIndex - 1; } if (startIndex < 0) { startIndex = 0; } int endIndex = expectedSpectrum.Intensities.LastIndexOf(inten => inten >= minimumAbundance) + 1; int countPeaks = endIndex - startIndex; var listProportionIndices = new List <KeyValuePair <float, int> >(countPeaks); for (int i = 0; i < countPeaks; i++) { listProportionIndices.Add(new KeyValuePair <float, int>( expectedSpectrum.Intensities[i + startIndex], i)); } // Sort proportions descending. listProportionIndices.Sort((p1, p2) => Comparer.Default.Compare(p2.Key, p1.Key)); // Set proportions and ranks back in the original locations var expectedProportionRanks = new KeyValuePair <float, int> [countPeaks]; for (int i = 0; i < countPeaks; i++) { expectedProportionRanks[listProportionIndices[i].Value] = new KeyValuePair <float, int>(listProportionIndices[i].Key, i + 1); } MonoMassIndex = monoMassIndex - startIndex; // Find the base peak and fill in the masses and proportions var expectedPeaks = new List <MzRankProportion>(); for (int i = 0; i < countPeaks; i++) { float expectedProportion = expectedProportionRanks[i].Key; int rank = expectedProportionRanks[i].Value; expectedPeaks.Add(new MzRankProportion(q1FilterValues[i + startIndex], rank, expectedProportion)); if (expectedProportion > expectedProportionRanks[BaseMassIndex].Key) { BaseMassIndex = i; } } ExpectedPeaks = expectedPeaks; }
public IsotopeDistInfo(MassDistribution massDistribution, double monoisotopicMass, bool isMassH, // Is monoisotopicMass M+H, or just M as in small molecule use? int charge, Func <double, double> calcFilterWindow, double massResolution, double minimumAbundance) { _monoisotopicMass = monoisotopicMass; _charge = charge; _isMassH = isMassH; // Get peak center of mass values for the given resolution var q1FilterValues = MassDistribution.NewInstance(massDistribution, massResolution, 0).Keys.ToList(); // Find the monoisotopic m/z and make sure it is exactly the expected number double monoMz = isMassH ? SequenceMassCalc.GetMZ(_monoisotopicMass, _charge) : BioMassCalc.CalculateIonMz(_monoisotopicMass, _charge); double monoMzDist = monoMz; int monoMassIndex = 0; for (int i = 0; i < q1FilterValues.Count; i++) { double peakCenterMz = q1FilterValues[i]; double filterWindow = calcFilterWindow(peakCenterMz); double startMz = peakCenterMz - filterWindow / 2; double endMz = startMz + filterWindow; if (startMz < monoMz && monoMz < endMz) { monoMzDist = q1FilterValues[i]; q1FilterValues[i] = monoMz; monoMassIndex = i; break; } } // Insert a M-1 peak, even if it is not expected in the isotope mass distribution if (monoMassIndex == 0 && q1FilterValues.Count > 1) { // Use the delta from the original distribution monoMz to the next peak q1FilterValues.Insert(0, monoMz + monoMzDist - q1FilterValues[1]); monoMassIndex++; } if (!q1FilterValues.Any()) // As is small molecule docs with mz values only, no formulas { return; } // Use the filtering algorithm that will be used on real data to determine the // expected proportions of the mass distribution that will end up filtered into // peaks // CONSIDER: Mass accuracy information is not calculated here var key = new PrecursorTextId(q1FilterValues[monoMassIndex], null, ChromExtractor.summed); var filter = new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, 0, null, null, null, null, 0, false, false); filter.AddQ1FilterValues(q1FilterValues, calcFilterWindow); var expectedSpectrum = filter.FilterQ1SpectrumList(new[] { new MsDataSpectrum { Mzs = massDistribution.Keys.ToArray(), Intensities = massDistribution.Values.ToArray() } }); int startIndex = expectedSpectrum.Intensities.IndexOf(inten => inten >= minimumAbundance); if (startIndex == -1) { throw new InvalidOperationException( string.Format(Resources.IsotopeDistInfo_IsotopeDistInfo_Minimum_abundance__0__too_high, minimumAbundance)); } // Always include the M-1 peak, even if it is expected to have zero intensity if (startIndex > monoMassIndex - 1) { startIndex = monoMassIndex - 1; } if (startIndex < 0) { startIndex = 0; } int endIndex = expectedSpectrum.Intensities.LastIndexOf(inten => inten >= minimumAbundance) + 1; int countPeaks = endIndex - startIndex; var listProportionIndices = new List <KeyValuePair <float, int> >(countPeaks); for (int i = 0; i < countPeaks; i++) { listProportionIndices.Add(new KeyValuePair <float, int>( expectedSpectrum.Intensities[i + startIndex], i)); } // Sort proportions descending. listProportionIndices.Sort((p1, p2) => Comparer.Default.Compare(p2.Key, p1.Key)); // Set proportions and ranks back in the original locations var expectedProportionRanks = new KeyValuePair <float, int> [countPeaks]; for (int i = 0; i < countPeaks; i++) { expectedProportionRanks[listProportionIndices[i].Value] = new KeyValuePair <float, int>(listProportionIndices[i].Key, i + 1); } // TODO: Can this be discarded? // MassDistribution = massDistribution; MonoMassIndex = monoMassIndex - startIndex; // Find the base peak and fill in the masses and proportions var expectedPeaks = new List <MzRankProportion>(); for (int i = 0; i < countPeaks; i++) { float expectedProportion = expectedProportionRanks[i].Key; int rank = expectedProportionRanks[i].Value; expectedPeaks.Add(new MzRankProportion(q1FilterValues[i + startIndex], rank, expectedProportion)); if (expectedProportion > expectedProportionRanks[BaseMassIndex].Key) { BaseMassIndex = i; } } ExpectedPeaks = expectedPeaks; }
/// <summary> /// Synchronizes a single <see cref="MassDistribution"/> object with corresponding /// masses from a <see cref="BioMassCalc"/>. /// </summary> private static MassDistribution SynchDist(MassDistribution massDist, double monoMassCalc, double secondMassCalc, double thirdMassCalc) { var massDistOrdered = massDist.MassesSortedByAbundance(); if (EqualDistMasses(massDistOrdered, monoMassCalc, secondMassCalc, thirdMassCalc)) return massDist; var dictFixDist = new Dictionary<double, double>(massDist); ReplaceMass(dictFixDist, massDistOrdered, 0, monoMassCalc); ReplaceMass(dictFixDist, massDistOrdered, 1, secondMassCalc); ReplaceMass(dictFixDist, massDistOrdered, 2, thirdMassCalc); return MassDistribution.NewInstance(dictFixDist, 0, 0); }
// ReSharper disable once ParameterTypeCanBeEnumerable.Local private MassDistribution GetMzDistribution(Molecule molecule, int charge, IsotopeAbundances abundances, double unexplainedMass, bool isMassH) { // Low resolution to get back only peaks at Dalton (i.e. neutron) boundaries var md = new MassDistribution(_massResolution, _minimumAbundance); var result = md; foreach (var element in molecule) { result = result.Add(md.Add(abundances[element.Key]).Multiply(element.Value)); } return result.OffsetAndDivide(unexplainedMass + charge* (isMassH ? BioMassCalc.MassProton : -BioMassCalc.MassElectron), charge); }
public MassDistribution GetMassDistribution(Molecule molecule, int charge) { var md = new MassDistribution(MassResolution, .00001); var result = md; foreach (var element in molecule) { result = result.Add(md.Add(IsotopeAbundances[element.Key]).Multiply(element.Value)); } if (charge != 0) { result = result.OffsetAndDivide(charge * ProtonMass, charge); } return result; }
public IsotopeDistInfo(MassDistribution massDistribution, double monoisotopicMass, bool isMassH, // Is monoisotopicMass M+H, or just M as in small molecule use? int charge, Func<double, double> calcFilterWindow, double massResolution, double minimumAbundance) { _monoisotopicMass = monoisotopicMass; _charge = charge; _isMassH = isMassH; // Get peak center of mass values for the given resolution var q1FilterValues = MassDistribution.NewInstance(massDistribution, massResolution, 0).Keys.ToList(); // Find the monoisotopic m/z and make sure it is exactly the expected number double monoMz = isMassH ? SequenceMassCalc.GetMZ(_monoisotopicMass, _charge) : BioMassCalc.CalculateIonMz(_monoisotopicMass, _charge); double monoMzDist = monoMz; int monoMassIndex = 0; for (int i = 0; i < q1FilterValues.Count; i++) { double peakCenterMz = q1FilterValues[i]; double filterWindow = calcFilterWindow(peakCenterMz); double startMz = peakCenterMz - filterWindow/2; double endMz = startMz + filterWindow; if (startMz < monoMz && monoMz < endMz) { monoMzDist = q1FilterValues[i]; q1FilterValues[i] = monoMz; monoMassIndex = i; break; } } // Insert a M-1 peak, even if it is not expected in the isotope mass distribution if (monoMassIndex == 0 && q1FilterValues.Count > 1) { // Use the delta from the original distribution monoMz to the next peak q1FilterValues.Insert(0, monoMz + monoMzDist - q1FilterValues[1]); monoMassIndex++; } if (!q1FilterValues.Any()) // As is small molecule docs with mz values only, no formulas return; // Use the filtering algorithm that will be used on real data to determine the // expected proportions of the mass distribution that will end up filtered into // peaks // CONSIDER: Mass accuracy information is not calculated here var key = new PrecursorTextId(q1FilterValues[monoMassIndex], null, ChromExtractor.summed); var filter = new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, 0, null, null, null, null, 0, false, false); filter.AddQ1FilterValues(q1FilterValues, calcFilterWindow); var expectedSpectrum = filter.FilterQ1SpectrumList(new[] { new MsDataSpectrum { Mzs = massDistribution.Keys.ToArray(), Intensities = massDistribution.Values.ToArray() } }); int startIndex = expectedSpectrum.Intensities.IndexOf(inten => inten >= minimumAbundance); if (startIndex == -1) { throw new InvalidOperationException( string.Format(Resources.IsotopeDistInfo_IsotopeDistInfo_Minimum_abundance__0__too_high, minimumAbundance)); } // Always include the M-1 peak, even if it is expected to have zero intensity if (startIndex > monoMassIndex - 1) startIndex = monoMassIndex - 1; if (startIndex < 0) startIndex = 0; int endIndex = expectedSpectrum.Intensities.LastIndexOf(inten => inten >= minimumAbundance) + 1; int countPeaks = endIndex - startIndex; var listProportionIndices = new List<KeyValuePair<float, int>>(countPeaks); for (int i = 0; i < countPeaks; i++) { listProportionIndices.Add(new KeyValuePair<float, int>( expectedSpectrum.Intensities[i + startIndex], i)); } // Sort proportions descending. listProportionIndices.Sort((p1, p2) => Comparer.Default.Compare(p2.Key, p1.Key)); // Set proportions and ranks back in the original locations var expectedProportionRanks = new KeyValuePair<float, int>[countPeaks]; for (int i = 0; i < countPeaks; i++) { expectedProportionRanks[listProportionIndices[i].Value] = new KeyValuePair<float, int>(listProportionIndices[i].Key, i + 1); } // TODO: Can this be discarded? // MassDistribution = massDistribution; MonoMassIndex = monoMassIndex - startIndex; // Find the base peak and fill in the masses and proportions var expectedPeaks = new List<MzRankProportion>(); for (int i = 0; i < countPeaks; i++) { float expectedProportion = expectedProportionRanks[i].Key; int rank = expectedProportionRanks[i].Value; expectedPeaks.Add(new MzRankProportion(q1FilterValues[i + startIndex], rank, expectedProportion)); if (expectedProportion > expectedProportionRanks[BaseMassIndex].Key) BaseMassIndex = i; } ExpectedPeaks = expectedPeaks; }