Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neutral Mass Spectrum #806

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Chemistry;
using Easy.Common.Extensions;
using MathNet.Numerics.Statistics;
using MzLibUtil;

namespace MassSpectrometry
{
public class ClassicDeconvolutionAlgorithm : DeconvolutionAlgorithm
internal class ClassicDeconvolutionAlgorithm : DeconvolutionAlgorithm
{
private MzSpectrum spectrum;

public ClassicDeconvolutionAlgorithm(DeconvolutionParameters deconParameters) : base(deconParameters)
internal ClassicDeconvolutionAlgorithm(DeconvolutionParameters deconParameters) : base(deconParameters)
{

}
Expand All @@ -25,7 +22,7 @@ public ClassicDeconvolutionAlgorithm(DeconvolutionParameters deconParameters) :
/// <param name="spectrumToDeconvolute">spectrum to deconvolute</param>
/// <param name="range">Range of peaks to deconvolute</param>
/// <returns></returns>
public override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrumToDeconvolute, MzRange range)
internal override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrumToDeconvolute, MzRange range)
{
var deconParams = DeconvolutionParameters as ClassicDeconvolutionParameters ?? throw new MzLibException("Deconvolution params and algorithm do not match");
spectrum = spectrumToDeconvolute;
Expand Down Expand Up @@ -205,7 +202,7 @@ private IsotopicEnvelope FindIsotopicEnvelope(int massIndex, double candidateFor
}
}

return new IsotopicEnvelope(listOfObservedPeaks, monoisotopicMass, chargeState, totalIntensity, Statistics.StandardDeviation(listOfRatios), massIndex);
return new IsotopicEnvelope(listOfObservedPeaks, monoisotopicMass, chargeState, totalIntensity, listOfRatios.StandardDeviation());
}

private int ObserveAdjacentChargeStates(IsotopicEnvelope originalEnvelope, double mostIntensePeakMz, int massIndex, double deconvolutionTolerancePpm, double intensityRatioLimit, double minChargeToLookFor, double maxChargeToLookFor, List<double> monoisotopicMassPredictions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

namespace MassSpectrometry
{
/// <summary>
/// Parent class defining minimum requirement to be used <see cref="Deconvoluter"/>
/// </summary>
public abstract class DeconvolutionAlgorithm
{
// For ClassicDeconv. If not used elsewhere, move to that class
Expand Down Expand Up @@ -79,6 +82,6 @@ protected DeconvolutionAlgorithm(DeconvolutionParameters deconParameters)
/// <param name="spectrum">spectrum to be deconvoluted</param>
/// <param name="range">Range of peaks to deconvolute</param>
/// <returns></returns>
public abstract IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range);
internal abstract IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MzLibUtil;

namespace MassSpectrometry
{
[ExcludeFromCodeCoverage]
public class ExampleNewDeconvolutionAlgorithmTemplate : DeconvolutionAlgorithm
internal class ExampleNewDeconvolutionAlgorithmTemplate : DeconvolutionAlgorithm
{
public ExampleNewDeconvolutionAlgorithmTemplate(DeconvolutionParameters deconParameters) : base(deconParameters)
internal ExampleNewDeconvolutionAlgorithmTemplate(DeconvolutionParameters deconParameters) : base(deconParameters)
{

}

public override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range = null)
internal override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range = null)
{
var deconParams = DeconvolutionParameters as ExampleNewDeconvolutionParametersTemplate ?? throw new MzLibException("Deconvolution params and algorithm do not match");
range ??= spectrum.Range;
Expand Down
48 changes: 21 additions & 27 deletions mzLib/MassSpectrometry/Deconvolution/Deconvoluter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Easy.Common.Extensions;
using Easy.Common.Interfaces;
using System.Collections.Generic;
using Chemistry;
using MzLibUtil;

namespace MassSpectrometry
Expand All @@ -30,27 +25,11 @@ public static class Deconvoluter
public static IEnumerable<IsotopicEnvelope> Deconvolute(MsDataScan scan,
DeconvolutionParameters deconvolutionParameters, MzRange rangeToGetPeaksFrom = null)
{
rangeToGetPeaksFrom ??= scan.MassSpectrum.Range;
// set any specific deconvolution parameters found only in the MsDataScan

// set deconvolution algorithm and any specific deconvolution parameters found in the MsDataScan
DeconvolutionAlgorithm deconAlgorithm;
switch (deconvolutionParameters.DeconvolutionType)
{
case DeconvolutionType.ClassicDeconvolution:
deconAlgorithm = new ClassicDeconvolutionAlgorithm(deconvolutionParameters);
break;

case DeconvolutionType.ExampleNewDeconvolutionTemplate:
deconAlgorithm = new ExampleNewDeconvolutionAlgorithmTemplate(deconvolutionParameters);
break;

default: throw new MzLibException("DeconvolutionType not yet supported");
}

return deconAlgorithm.Deconvolute(scan.MassSpectrum, rangeToGetPeaksFrom);
foreach (var isotopicEnvelope in Deconvolute(scan.MassSpectrum, deconvolutionParameters, rangeToGetPeaksFrom))
yield return isotopicEnvelope;
}



/// <summary>
/// Static deconvolution of an MzSpectrum that does not require Deconvoluter construction
Expand Down Expand Up @@ -79,7 +58,22 @@ public static IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum,
default: throw new MzLibException("DeconvolutionType not yet supported");
}

return deconAlgorithm.Deconvolute(spectrum, rangeToGetPeaksFrom);
// Short circuit deconvolution if it is called on a neutral mass spectrum
if (spectrum is NeutralMassSpectrum newt)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good variable name

for (int i = 0; i < newt.XArray.Length; i++)
{
// skip this peak if it's outside the range of interest (e.g. if we're only interested in deconvoluting a small m/z range)
if (!rangeToGetPeaksFrom.Contains(newt.XArray[i].ToMz(newt.Charges[i])))
continue;
yield return new IsotopicEnvelope(newt.XArray[i], newt.YArray[i], newt.Charges[i]);
}
}
else
{
foreach (var isotopicEnvelope in deconAlgorithm.Deconvolute(spectrum, rangeToGetPeaksFrom))
yield return isotopicEnvelope;
}
}
}
}
4 changes: 4 additions & 0 deletions mzLib/MassSpectrometry/MassSpectrometry.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@
<ProjectReference Include="..\MzLibUtil\MzLibUtil.csproj" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Development" />
<InternalsVisibleTo Include="Test" />
</ItemGroup>
</Project>
3 changes: 0 additions & 3 deletions mzLib/MassSpectrometry/MsDataFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@

namespace MassSpectrometry
{
// TODO: Define scope of class
// Class scope is to provide to the data loaded from the DataFile.

/// <summary>
/// A class for interacting with data collected from a Mass Spectrometer, and stored in a file
/// </summary>
Expand Down
32 changes: 19 additions & 13 deletions mzLib/MassSpectrometry/MzSpectra/IsotopicEnvelope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,47 @@ public class IsotopicEnvelope : IHasMass
/// <summary>
/// Mass of most abundant observed isotopic peak, not accounting for addition or subtraction or protons due to ESI charge state induction
/// </summary>
public double MostAbundantObservedIsotopicMass { get; private set; }
internal double MostAbundantObservedIsotopicMass { get; private set; }
public readonly int Charge;
public readonly double TotalIntensity;
public readonly double StDev;
public readonly int MassIndex;

public double Score { get; private set; }

public IsotopicEnvelope(List<(double mz, double intensity)> bestListOfPeaks, double bestMonoisotopicMass, int bestChargeState, double bestTotalIntensity, double bestStDev, int bestMassIndex)
/// <summary>
/// Used for an isotopic envelope that mzLib deconvoluted (e.g., from a mass spectrum)
/// </summary>
public IsotopicEnvelope(List<(double mz, double intensity)> bestListOfPeaks, double bestMonoisotopicMass, int bestChargeState, double bestTotalIntensity, double bestStDev)
{
Peaks = bestListOfPeaks;
MonoisotopicMass = bestMonoisotopicMass;
MostAbundantObservedIsotopicMass = GetMostAbundantObservedIsotopicMass(bestListOfPeaks, bestChargeState);
MostAbundantObservedIsotopicMass = bestListOfPeaks.MaxBy(p => p.intensity).mz * Math.Abs(bestChargeState);
Charge = bestChargeState;
TotalIntensity = bestTotalIntensity;
StDev = bestStDev;
MassIndex = bestMassIndex;
Score = ScoreIsotopeEnvelope();
Score = ScoreIsotopeEnvelope(bestStDev);
}

public double GetMostAbundantObservedIsotopicMass(List<(double mz, double intensity)> peaks, int charge)
/// <summary>
/// Used for a neutral mass read in from a deconvoluted file
/// Assumes the mass is correct: score is max value
/// </summary>
public IsotopicEnvelope(double monoisotopicMass, double intensity, int charge)
{
return peaks.MaxBy(p => p.intensity).mz * Math.Abs(charge);
MonoisotopicMass = monoisotopicMass;
Charge = charge;
TotalIntensity = intensity;
Score = double.MaxValue;
Peaks = [(monoisotopicMass.ToMz(charge), intensity)];
}

public override string ToString()
{
return Charge + "\t" + Peaks[0].mz.ToString("G8") + "\t" + Peaks.Count + "\t" + TotalIntensity;
}

private double ScoreIsotopeEnvelope() //likely created by Stefan Solntsev using peptide data
private double ScoreIsotopeEnvelope(double stDev) //likely created by Stefan Solntsev using peptide data
{
return Peaks.Count >= 2 ?
TotalIntensity / Math.Pow(StDev, 0.13) * Math.Pow(Peaks.Count, 0.4) / Math.Pow(Math.Abs(Charge), 0.06) :
TotalIntensity / Math.Pow(stDev, 0.13) * Math.Pow(Peaks.Count, 0.4) / Math.Pow(Math.Abs(Charge), 0.06) :
0;
}

Expand All @@ -60,6 +67,5 @@ public void SetMedianMonoisotopicMass(List<double> monoisotopicMassPredictions)
{
MonoisotopicMass = monoisotopicMassPredictions.Median();
}

}
}
15 changes: 9 additions & 6 deletions mzLib/MassSpectrometry/MzSpectra/MzSpectrum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;

namespace MassSpectrometry
{
Expand Down Expand Up @@ -126,7 +124,7 @@
}
}

public double? FirstX
public virtual double? FirstX
{
get
{
Expand All @@ -138,7 +136,7 @@
}
}

public double? LastX
public virtual double? LastX
{
get
{
Expand Down Expand Up @@ -373,7 +371,7 @@
}
}

return new IsotopicEnvelope(listOfObservedPeaks, monoisotopicMass, chargeState, totalIntensity, Statistics.StandardDeviation(listOfRatios), massIndex);
return new IsotopicEnvelope(listOfObservedPeaks, monoisotopicMass, chargeState, totalIntensity, listOfRatios.StandardDeviation());
}

[Obsolete("Deconvolution Has been moved to the Deconvoluter Object")]
Expand Down Expand Up @@ -764,14 +762,14 @@
return numerator / denominator;
}

public bool Equals(MzSpectrum? other)

Check warning on line 765 in mzLib/MassSpectrometry/MzSpectra/MzSpectrum.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 765 in mzLib/MassSpectrometry/MzSpectra/MzSpectrum.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return (XArray.SequenceEqual(other.XArray) && YArray.SequenceEqual(other.YArray));
}

public override bool Equals(object? spectrumToCompare)

Check warning on line 772 in mzLib/MassSpectrometry/MzSpectra/MzSpectrum.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 772 in mzLib/MassSpectrometry/MzSpectra/MzSpectrum.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (ReferenceEquals(null, spectrumToCompare)) return false;
if (ReferenceEquals(this, spectrumToCompare)) return true;
Expand All @@ -796,7 +794,12 @@
return peakList[index];
}

private MzPeak GeneratePeak(int index)
/// <summary>
/// The source of all peaks which populate the peakList
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
protected virtual MzPeak GeneratePeak(int index)
{
return new MzPeak(XArray[index], YArray[index]);
}
Expand Down
65 changes: 65 additions & 0 deletions mzLib/MassSpectrometry/MzSpectra/NeutralMassSpectrum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using Chemistry;

namespace MassSpectrometry
{
public class NeutralMassSpectrum : MzSpectrum
{
public int[] Charges { get; init; }
public NeutralMassSpectrum(double[,] monoisotopicMassesIntensities, int[] charges) : base(monoisotopicMassesIntensities)
{
if (monoisotopicMassesIntensities.GetLength(0) != charges.Length)
throw new ArgumentException("The lengths of monoisotopicMasses, intensities, and charges must be the same.");

Charges = charges;

double minMz = double.MaxValue;
double maxMz = double.MinValue;
for (int i = 0; i < monoisotopicMassesIntensities.GetLength(0); i++)
{
var mz = monoisotopicMassesIntensities[i,0].ToMz(charges[i]);
if (mz < minMz)
minMz = mz;
if (mz > maxMz)
maxMz = mz;
}

FirstX = minMz;
LastX = maxMz;
}

public NeutralMassSpectrum(double[] monoisotopicMasses, double[] intensities, int[] charges, bool shouldCopy)
: base(monoisotopicMasses, intensities, shouldCopy)
{
if (monoisotopicMasses.GetLength(0) != intensities.Length || monoisotopicMasses.Length != charges.Length)
throw new ArgumentException("The lengths of monoisotopicMasses, intensities, and charges must be the same.");

Charges = charges;

double minMz = double.MaxValue;
double maxMz = double.MinValue;
for (int i = 0; i < monoisotopicMasses.Length; i++)
{
var mz = monoisotopicMasses[i].ToMz(charges[i]);
if (mz < minMz)
minMz = mz;
if (mz > maxMz)
maxMz = mz;
}

FirstX = minMz;
LastX = maxMz;
}

public override double? FirstX { get; } // in m/z
public override double? LastX { get; } // in m/z

/// <summary>
/// Converts to a charged spectrum
/// </summary>
protected override MzPeak GeneratePeak(int index)
{
return new MzPeak(XArray[index].ToMz(Charges[index]), YArray[index]);
}
}
}
Loading
Loading