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

IsoDec Deconvolution Algorithm #791

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
3d7ebd1
Added in foundation for John to use
nbollis Aug 2, 2024
ddd03b5
removed charge from johnny decon parameters
nbollis Aug 2, 2024
6720fc5
instantiated johhnydeconparams.decontype
nbollis Aug 2, 2024
73df199
Merge branch 'master' into JohnnyDeconv
trishorts Aug 2, 2024
50b8d9d
Merge branch 'master' into JohnnyDeconv
trishorts Aug 5, 2024
b626f41
IsoDec incorporated!
Aug 5, 2024
7c5132e
Merge branch 'JohnnyDeconv' of https://github.com/nbollis/mzLib into …
Aug 5, 2024
fc0f4bb
Did a little cleanup and made IsoDec run on my device
nbollis Aug 5, 2024
097b4bd
Changed isodec to use the embedded dlls and resources
nbollis Aug 5, 2024
ba54e46
changed around assembly references and added IsoDec to Deconvolution …
nbollis Aug 5, 2024
678dbc3
added test for negative mode
nbollis Aug 5, 2024
64d4a4b
updated nuspec to pack isodec resources
nbollis Aug 5, 2024
6ef4447
Updated dll. Now just making monoisotopic errors but getting generall…
Aug 6, 2024
1a0bd54
Corrected some IsoDec issues. Not passing tests yet, but getting corr…
Aug 6, 2024
963826b
IsoDec passes (updated) tests.
Oct 4, 2024
bc1b6a9
began neutral mz spectrum
nbollis Oct 11, 2024
a8bba37
Refactor visibility and clean up deconvolution code
Oct 11, 2024
455f3c0
Finish NeutralMassSpectrum
Oct 11, 2024
0dd9e52
Refactor Deconvoluter and rename NeutralMzSpectrum
Oct 11, 2024
09cefc7
added neutral mass file bool
Oct 11, 2024
72d8202
Adjsuted and tested neutral mass spectra
nbollis Oct 11, 2024
4277814
Refactor Deconvoluter and add new tests
nbollis Oct 12, 2024
6c124c5
Make FirstX and LastX properties virtual; update tests
nbollis Oct 12, 2024
f049ee4
fixed nuspec
nbollis Oct 12, 2024
3c560ee
IsoDecDeconvolutionParameters and Multiple Monoisos
Oct 28, 2024
93e4161
Refactor IsoDec classes and enhance parameters
nbollis Oct 28, 2024
b97a23d
Merged in NeutralMassSpectrum and reconciled errors
nbollis Oct 29, 2024
492f7e0
Bug Fixes and parameter cleanup
Oct 30, 2024
fc32cd2
Fixed broken unit test and assertion structure in test deconvolution
nbollis Oct 30, 2024
2e4a772
Cleaned up isotopic Envelope
nbollis Oct 31, 2024
8ff5883
Refactor IsoDec classes and update parameters
nbollis Oct 31, 2024
302a07a
help me
nbollis Oct 31, 2024
e45fb3f
Changed resources from content to none
nbollis Nov 2, 2024
cf8b6a3
nuspec edit
nbollis Nov 14, 2024
9aa30a8
Refactor Deconvolute method and update variable handling
nbollis Nov 15, 2024
7cd2639
Fixed memory allocation/deallocation issues
Nov 18, 2024
3db9ab4
simple restructure of parameter handling
nbollis Nov 18, 2024
788aa81
merged John and Nic Changes
nbollis Nov 18, 2024
4bacc61
Update namespaces, references, and version number
nbollis Nov 18, 2024
60d7e4e
idk man
nbollis Nov 19, 2024
98a609f
look mom, I did it
nbollis Nov 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class SinglePeakDeconvolutionTestCase
public SinglePeakDeconvolutionTestCase(DeconvolutionParameters deconParameters, string sampleInformation, string spectrumPath, int scanNumber,
double expectedMostAbundantObservedIsotopicMass, int expectedIonChargeState, double selectedIonMz, double precursorPpmMassTolerance)
{

DeconvolutionParameters = deconParameters;
SampleInformation = sampleInformation;
ExpectedMostAbundantObservedIsotopicMass = expectedMostAbundantObservedIsotopicMass;
ExpectedIonChargeState = expectedIonChargeState;
Expand Down
6 changes: 3 additions & 3 deletions mzLib/Development/Development.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
</ItemGroup>

<ItemGroup>
<None Update="Deconvolution\TestData\Averaged_221110_CytoOnly.mzML">
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_CytoOnly.mzML">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Deconvolution\TestData\Averaged_221110_HGHOnly.mzML">
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_HGHOnly.mzML">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Deconvolution\TestData\Averaged_221110_UbiqOnly.mzML">
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_UbiqOnly.mzML">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Expand Down
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
@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Chemistry;
using MzLibUtil;

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 +80,8 @@ 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
129 changes: 129 additions & 0 deletions mzLib/MassSpectrometry/Deconvolution/Algorithms/IsoDecAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using MzLibUtil;

namespace MassSpectrometry
{
internal class IsoDecAlgorithm : DeconvolutionAlgorithm
{

internal IsoDecAlgorithm(DeconvolutionParameters deconParameters) : base(deconParameters)
{

}

[StructLayout(LayoutKind.Sequential, Pack =1)]
public struct MatchedPeak
{
public float mz;
Copy link
Contributor

Choose a reason for hiding this comment

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

would be good to use our standard variable names for these features.

public int z;
public float monoiso;
public float peakmass;
public float avgmass;
public float area;
public float peakint;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public float[] matchedindsiso;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public float[] matchedindsexp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public float[] isomz;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public float[] isodist;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public float[] isomass;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public float[] monoisos;
int startindex;
int endindex;
public float score;
public int realisolength;
}

[DllImport("isodeclib.dll", EntryPoint = "process_spectrum", CallingConvention = CallingConvention.Cdecl)]
protected static extern int process_spectrum(double[] cmz, float[] cintensity, int c, string fname, IntPtr matchedpeaks, IsoDecDeconvolutionParameters.IsoSettings settings);

internal override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range)
{
var deconParams = DeconvolutionParameters as IsoDecDeconvolutionParameters ?? throw new MzLibException("Deconvolution params and algorithm do not match");

var firstIndex = spectrum.GetClosestPeakIndex(range.Minimum);
var lastIndex = spectrum.GetClosestPeakIndex(range.Maximum);

var mzs = spectrum.XArray[firstIndex..lastIndex]
.Select(p => p)
.ToArray();
var intensities = spectrum.YArray[firstIndex..lastIndex]
.Select(p => (float)p)
.ToArray();

var mpArray = new byte[intensities.Length * Marshal.SizeOf(typeof(MatchedPeak))];
GCHandle handle = GCHandle.Alloc(mpArray, GCHandleType.Pinned);
try
{
IntPtr matchedPeaksPtr = (IntPtr)handle.AddrOfPinnedObject();
IsoDecDeconvolutionParameters.IsoSettings settings = deconParams.ToIsoSettings();
int result = process_spectrum(mzs, intensities, intensities.Length, null, matchedPeaksPtr, settings);
if (result <= 0)
return Enumerable.Empty<IsotopicEnvelope>();

// Handle results
MatchedPeak[] matchedpeaks = new MatchedPeak[result];
for (int i = 0; i < result; i++)
{
matchedpeaks[i] = Marshal.PtrToStructure<MatchedPeak>(matchedPeaksPtr + i * Marshal.SizeOf(typeof(MatchedPeak)));
}

return ConvertToIsotopicEnvelopes(deconParams, matchedpeaks, spectrum);
}
finally
{
handle.Free();
}
}

private List<IsotopicEnvelope> ConvertToIsotopicEnvelopes(IsoDecDeconvolutionParameters parameters, MatchedPeak[] matchedpeaks, MzSpectrum spectrum)
{
List<IsotopicEnvelope> result = new List<IsotopicEnvelope>();
int currentId = 0;
foreach(MatchedPeak peak in matchedpeaks)
{
List<(double,double)> peaks = new List<(double,double)> ();
for (int i = 0; i < peak.realisolength; i++)
{

List<int> indicesWithinTolerance = spectrum.GetPeakIndicesWithinTolerance(peak.isomz[i], new PpmTolerance(5));
double maxIntensity = 0;
int maxIndex = -1;
foreach (int index in indicesWithinTolerance)
{
if (spectrum.YArray[index] > maxIntensity) { maxIntensity = spectrum.YArray[index]; maxIndex = index; }
}
if (maxIndex >= 0)
{
peaks.Add((spectrum.XArray[maxIndex], spectrum.YArray[maxIndex]));
}
else
{
peaks.Add((peak.isomz[i], 0));
}

}
int charge = peak.z;
if(parameters.Polarity == Polarity.Negative) { charge = -peak.z; }
if(parameters.ReportMulitpleMonoisos)
{
foreach (float monoiso in peak.monoisos)
{
if (monoiso > 0) { result.Add(new IsotopicEnvelope(currentId, peaks, (double)monoiso, charge, peak.peakint, peak.score)); }
}
}
else { result.Add(new IsotopicEnvelope(currentId, peaks, (double)peak.monoiso, charge, peak.peakint, peak.score)); }
currentId++;
}
return result;
}
}
}
71 changes: 27 additions & 44 deletions mzLib/MassSpectrometry/Deconvolution/Deconvoluter.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Easy.Common.Extensions;
using Easy.Common.Interfaces;
using Chemistry;
using MzLibUtil;

namespace MassSpectrometry
{
public enum DeconvolutionType
{
ClassicDeconvolution,
ExampleNewDeconvolutionTemplate,
}


/// <summary>
/// Context class for all deconvolution
Expand All @@ -30,27 +22,10 @@ public static class Deconvoluter
public static IEnumerable<IsotopicEnvelope> Deconvolute(MsDataScan scan,
DeconvolutionParameters deconvolutionParameters, MzRange rangeToGetPeaksFrom = null)
{
rangeToGetPeaksFrom ??= scan.MassSpectrum.Range;

// 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);
// set any specific deconvolution parameters found only in the MsDataScan
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 All @@ -63,23 +38,31 @@ public static IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum,
DeconvolutionParameters deconvolutionParameters, MzRange rangeToGetPeaksFrom = null)
{
rangeToGetPeaksFrom ??= spectrum.Range;

// set deconvolution algorithm
DeconvolutionAlgorithm deconAlgorithm;
switch (deconvolutionParameters.DeconvolutionType)
DeconvolutionAlgorithm deconAlgorithm = deconvolutionParameters.DeconvolutionType switch
{
case DeconvolutionType.ClassicDeconvolution:
deconAlgorithm = new ClassicDeconvolutionAlgorithm(deconvolutionParameters);
break;
DeconvolutionType.ClassicDeconvolution => new ClassicDeconvolutionAlgorithm(deconvolutionParameters),
DeconvolutionType.ExampleNewDeconvolutionTemplate => new ExampleNewDeconvolutionAlgorithmTemplate(deconvolutionParameters),
DeconvolutionType.IsoDecDeconvolution => new IsoDecAlgorithm(deconvolutionParameters),
_ => throw new MzLibException("DeconvolutionType not yet supported")
};

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

default: throw new MzLibException("DeconvolutionType not yet supported");
// Short circuit deconvolution if it is called on a neutral mass spectrum
if (spectrum is NeutralMassSpectrum newt)
{
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).ToList())
yield return isotopicEnvelope;
}

return deconAlgorithm.Deconvolute(spectrum, rangeToGetPeaksFrom);
}
}
}
15 changes: 15 additions & 0 deletions mzLib/MassSpectrometry/Deconvolution/DeconvolutionType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MassSpectrometry
{
public enum DeconvolutionType
{
ClassicDeconvolution,
ExampleNewDeconvolutionTemplate,
IsoDecDeconvolution,
}
}
Loading