Skip to content

Commit 5443e36

Browse files
nbollistrishortsjgpavekNic Bollis
authored
IsoDec Deconvolution Algorithm (#791)
* Added in foundation for John to use * removed charge from johnny decon parameters * instantiated johhnydeconparams.decontype * IsoDec incorporated! * Did a little cleanup and made IsoDec run on my device * Changed isodec to use the embedded dlls and resources * changed around assembly references and added IsoDec to Deconvolution testing environment * added test for negative mode * updated nuspec to pack isodec resources * Updated dll. Now just making monoisotopic errors but getting generally correct charge states * IsoDec passes (updated) tests. * began neutral mz spectrum * Refactor visibility and clean up deconvolution code Changed `ClassicDeconvolutionAlgorithm`, `DeconvolutionAlgorithm`, and `ExampleNewDeconvolutionAlgorithmTemplate` classes and their members from `public` to `internal` to restrict visibility within the assembly. Added summary comment to `DeconvolutionAlgorithm` class. Refactored `Deconvoluter` class to remove unnecessary `using` directives and simplify the `Deconvolute` method by removing switch-case logic. Updated `IsotopicEnvelope` class by removing `MassIndex` and `StDev` properties, and modified constructor and `ScoreIsotopeEnvelope` method accordingly. Updated `MzSpectrum` class to use `StandardDeviation` extension method from `Easy.Common.Extensions`. Removed various unnecessary `using` directives from multiple files. * Finish NeutralMassSpectrum - Added `InternalsVisibleTo` entries for "Development" and "Test" in `MassSpectrometry.csproj`. - Changed `MostAbundantObservedIsotopicMass` to `internal` in `IsotopicEnvelope.cs`. - Added a new constructor to `IsotopicEnvelope` with monoisotopic mass, intensity, and charge. - Added XML documentation and changed `GeneratePeak` to `protected virtual` in `MzSpectrum.cs`. - Removed unused `using` directives in `MzSpectrum.cs` and `NeutralMzSpectrum.cs`. - Modified `NeutralMzSpectrum` constructor to validate array lengths. - Added `Charges` property to `NeutralMzSpectrum` and initialized it in the constructor. - Overrode `GeneratePeak` in `NeutralMzSpectrum` to convert to a charged spectrum using `Charges`. * Refactor Deconvoluter and rename NeutralMzSpectrum Added necessary using directives in Deconvoluter.cs. Modified Deconvoluter class for short-circuit deconvolution. Removed redundant lines in Deconvoluter.cs. Renamed NeutralMzSpectrum to NeutralMassSpectrum. Updated constructor and references accordingly. * added neutral mass file bool * Adjsuted and tested neutral mass spectra * Refactor Deconvoluter and add new tests Refactored Deconvoluter.cs to use a foreach loop for yielding IsotopicEnvelopes. Reformatted multiple test methods in TestDeconvolution.cs for better readability. Added new test methods to validate Deconvolute with NeutralMassSpectrum, ensuring correct processing of spectra with various charge states and ranges. * Make FirstX and LastX properties virtual; update tests - Changed FirstX and LastX properties in MzSpectrum to virtual. - Included MzLibUtil namespace in NeutralMassSpectrum class. - Updated NeutralMassSpectrum constructor to set FirstX and LastX. - Overrode FirstX and LastX in NeutralMassSpectrum class. - Added test NeutralMassSpectrum_MzRange to validate m/z range. * fixed nuspec * IsoDecDeconvolutionParameters and Multiple Monoisos * Refactor IsoDec classes and enhance parameters Updated IsoDecAlgorithm to use generic DeconvolutionParameters. Enhanced IsoDecDeconvolutionParameters with new properties. Refactored constructor to use camelCase parameter names. Removed unused using directives from IsoDecAlgorithm.cs. Ensured correct casting in IsoDecAlgorithm. Renamed Css_Threshold to CssThreshold for consistency. * Bug Fixes and parameter cleanup * Fixed broken unit test and assertion structure in test deconvolution * Cleaned up isotopic Envelope * Refactor IsoDec classes and update parameters Updated the `MassSpectrometry` namespace in `IsoDecAlgorithm.cs` and `IsoDecDeconvolutionParameters.cs`. In `IsoDecAlgorithm.cs`, added a type check for `DeconvolutionParameters` and replaced redundant type casting with `deconParams`. In `IsoDecDeconvolutionParameters.cs`, removed unnecessary `using` directives, moved the class under the `MassSpectrometry` namespace, added user-accessible and hard-coded parameters with comments, updated the constructor to initialize new parameters, and removed the nested class declaration. * help me * Changed resources from content to none * nuspec edit * Refactor Deconvolute method and update variable handling - Change `_phaseModelPath` to readonly static string to prevent modification after initial set. - Remove `process_spectrum` method declaration from the class. - Add `try-finally` block in `Deconvolute` to ensure `matchedPeaksPtr` memory is freed even if an exception occurs. - Move allocation of `matchedPeaksPtr` inside `try` block to allocate only if needed. - Invert check for `process_spectrum` result to return empty enumerable if result is <= 0. - Reformat loop processing matched peaks for better readability. - Ensure `Marshal.FreeHGlobal` is called in `finally` block to free `matchedPeaksPtr` if not zero. * Fixed memory allocation/deallocation issues * simple restructure of parameter handling * Update namespaces, references, and version number Removed unused using directives from IsoDecAlgorithm.cs and Deconvoluter.cs. Updated IsoSettings namespace in IsoDecAlgorithm.cs. Simplified NUnit assertions in TestDeconvolution.cs. Updated MassSpectrometry.csproj with HintPath and PackagePath for DLLs. Replaced phase_model.bin with isogenmass.dll. Incremented version number in mzLib.nuspec to 5.2.35. Added isogenmass.dll to mzLib.nuspec for net8.0 and net8.0-windows7.0 targets. * idk man * look mom, I did it * Adjusted in response to merging in master * revised from PR and added tests for GetPeakIndicesWithinTolerance. * Removed unnecessary changes * Added comments to isodec algorithm --------- Co-authored-by: trishorts <mshort@chem.wisc.edu> Co-authored-by: jgpavek <jpavek@arizona.edu> Co-authored-by: Nic Bollis <nbollis@wisc.edu>
1 parent 264521b commit 5443e36

23 files changed

+789
-139
lines changed

mzLib/Development/Deconvolution/StandardDeconvolutionTest.cs renamed to mzLib/Development/DeconvolutionDevelopment/StandardDeconvolutionTest.cs

Lines changed: 109 additions & 74 deletions
Large diffs are not rendered by default.

mzLib/Development/Deconvolution/TestCases/SinglePeakDeconvolutionTestCase.cs renamed to mzLib/Development/DeconvolutionDevelopment/TestCases/SinglePeakDeconvolutionTestCase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class SinglePeakDeconvolutionTestCase
2323
public SinglePeakDeconvolutionTestCase(DeconvolutionParameters deconParameters, string sampleInformation, string spectrumPath, int scanNumber,
2424
double expectedMostAbundantObservedIsotopicMass, int expectedIonChargeState, double selectedIonMz, double precursorPpmMassTolerance)
2525
{
26-
26+
DeconvolutionParameters = deconParameters;
2727
SampleInformation = sampleInformation;
2828
ExpectedMostAbundantObservedIsotopicMass = expectedMostAbundantObservedIsotopicMass;
2929
ExpectedIonChargeState = expectedIonChargeState;

mzLib/Development/Deconvolution/TestCases/TestDevelopmentTestCases.cs renamed to mzLib/Development/DeconvolutionDevelopment/TestCases/TestDevelopmentTestCases.cs

File renamed without changes.

mzLib/Development/Deconvolution/TestCases/WholeSpectrumDeconvolutionTestCase.cs renamed to mzLib/Development/DeconvolutionDevelopment/TestCases/WholeSpectrumDeconvolutionTestCase.cs

File renamed without changes.

mzLib/Development/Deconvolution/TestData/Averaged_221110_CytoOnly.mzML renamed to mzLib/Development/DeconvolutionDevelopment/TestData/Averaged_221110_CytoOnly.mzML

File renamed without changes.

mzLib/Development/Deconvolution/TestData/Averaged_221110_HGHOnly.mzML renamed to mzLib/Development/DeconvolutionDevelopment/TestData/Averaged_221110_HGHOnly.mzML

File renamed without changes.

mzLib/Development/Deconvolution/TestData/Averaged_221110_UbiqOnly.mzML renamed to mzLib/Development/DeconvolutionDevelopment/TestData/Averaged_221110_UbiqOnly.mzML

File renamed without changes.

mzLib/Development/Development.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
</ItemGroup>
2424

2525
<ItemGroup>
26-
<None Update="Deconvolution\TestData\Averaged_221110_CytoOnly.mzML">
26+
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_CytoOnly.mzML">
2727
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
2828
</None>
29-
<None Update="Deconvolution\TestData\Averaged_221110_HGHOnly.mzML">
29+
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_HGHOnly.mzML">
3030
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3131
</None>
32-
<None Update="Deconvolution\TestData\Averaged_221110_UbiqOnly.mzML">
32+
<None Update="DeconvolutionDevelopment\TestData\Averaged_221110_UbiqOnly.mzML">
3333
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3434
</None>
3535
</ItemGroup>

mzLib/MassSpectrometry/Deconvolution/Algorithms/DeconvolutionAlgorithm.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
64
using Chemistry;
75
using MzLibUtil;
86

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.InteropServices;
5+
using MzLibUtil;
6+
7+
namespace MassSpectrometry
8+
{
9+
/// <summary>
10+
/// Performs deconvolution on a single spectrum or region of spectrum using the Isodec algorithm
11+
/// <remarks>
12+
/// Isodec only needs to region of interest and does not use surrounding charge states as references.
13+
/// Isodec can report multiple monoisotopic masses for a single peak if enabled by ReportMultipleMonoisos parameter
14+
/// In this case, the resulting isotopic envelopes will have the same precursor ID.
15+
/// </remarks>
16+
/// </summary>
17+
internal class IsoDecAlgorithm : DeconvolutionAlgorithm
18+
{
19+
internal IsoDecAlgorithm(DeconvolutionParameters deconParameters) : base(deconParameters)
20+
{
21+
22+
}
23+
24+
/// <summary>
25+
/// Struct passed by pointer in memory to the Isodec.dll
26+
/// </summary>
27+
[StructLayout(LayoutKind.Sequential, Pack =1)]
28+
public struct MatchedPeak
29+
{
30+
public float mz;
31+
public int z;
32+
public float monoiso;
33+
public float peakmass;
34+
public float avgmass;
35+
public float area;
36+
public float peakint;
37+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
38+
public float[] matchedindsiso;
39+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
40+
public float[] matchedindsexp;
41+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
42+
public float[] isomz;
43+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
44+
public float[] isodist;
45+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
46+
public float[] isomass;
47+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
48+
public float[] monoisos;
49+
int startindex;
50+
int endindex;
51+
public float score;
52+
public int realisolength;
53+
}
54+
55+
/// <summary>
56+
/// Calls the Isodec.dll to perform deconvolution on the given spectrum
57+
/// The Isodec.dll requires three other dll's as dependencies: isogenmass.dll, libmmd.dll, scml_dispmd.dll
58+
/// </summary>
59+
/// <param name="cmz"></param>
60+
/// <param name="cintensity"></param>
61+
/// <param name="c"></param>
62+
/// <param name="fname"></param>
63+
/// <param name="matchedpeaks"></param>
64+
/// <param name="settings"></param>
65+
/// <returns></returns>
66+
67+
[DllImport("isodeclib.dll", EntryPoint = "process_spectrum", CallingConvention = CallingConvention.Cdecl)]
68+
protected static extern int process_spectrum(double[] cmz, float[] cintensity, int c, string fname, IntPtr matchedpeaks, IsoDecDeconvolutionParameters.IsoSettings settings);
69+
70+
internal override IEnumerable<IsotopicEnvelope> Deconvolute(MzSpectrum spectrum, MzRange range)
71+
{
72+
var deconParams = DeconvolutionParameters as IsoDecDeconvolutionParameters ?? throw new MzLibException("Deconvolution params and algorithm do not match");
73+
74+
var firstIndex = spectrum.GetClosestPeakIndex(range.Minimum);
75+
var lastIndex = spectrum.GetClosestPeakIndex(range.Maximum);
76+
77+
var mzs = spectrum.XArray[firstIndex..lastIndex]
78+
.Select(p => p)
79+
.ToArray();
80+
var intensities = spectrum.YArray[firstIndex..lastIndex]
81+
.Select(p => (float)p)
82+
.ToArray();
83+
84+
var mpArray = new byte[intensities.Length * Marshal.SizeOf(typeof(MatchedPeak))];
85+
GCHandle handle = GCHandle.Alloc(mpArray, GCHandleType.Pinned);
86+
try
87+
{
88+
IntPtr matchedPeaksPtr = (IntPtr)handle.AddrOfPinnedObject();
89+
IsoDecDeconvolutionParameters.IsoSettings settings = deconParams.ToIsoSettings();
90+
int result = process_spectrum(mzs, intensities, intensities.Length, null, matchedPeaksPtr, settings);
91+
if (result <= 0)
92+
return Enumerable.Empty<IsotopicEnvelope>();
93+
94+
// Handle results
95+
MatchedPeak[] matchedpeaks = new MatchedPeak[result];
96+
for (int i = 0; i < result; i++)
97+
{
98+
matchedpeaks[i] = Marshal.PtrToStructure<MatchedPeak>(matchedPeaksPtr + i * Marshal.SizeOf(typeof(MatchedPeak)));
99+
}
100+
101+
return ConvertToIsotopicEnvelopes(deconParams, matchedpeaks, spectrum);
102+
}
103+
finally
104+
{
105+
handle.Free();
106+
}
107+
}
108+
109+
/// <summary>
110+
/// Converts the isodec output (MatchedPeak) to IsotopicEnvelope for return
111+
/// </summary>
112+
/// <param name="parameters"></param>
113+
/// <param name="matchedpeaks"></param>
114+
/// <param name="spectrum"></param>
115+
/// <returns></returns>
116+
private List<IsotopicEnvelope> ConvertToIsotopicEnvelopes(IsoDecDeconvolutionParameters parameters, MatchedPeak[] matchedpeaks, MzSpectrum spectrum)
117+
{
118+
List<IsotopicEnvelope> result = new List<IsotopicEnvelope>();
119+
int currentId = 0;
120+
var tolerance = new PpmTolerance(5);
121+
foreach(MatchedPeak peak in matchedpeaks)
122+
{
123+
List<(double,double)> peaks = new List<(double,double)> ();
124+
for (int i = 0; i < peak.realisolength; i++)
125+
{
126+
127+
List<int> indicesWithinTolerance = spectrum.GetPeakIndicesWithinTolerance(peak.isomz[i], tolerance);
128+
double maxIntensity = 0;
129+
int maxIndex = -1;
130+
foreach (int index in indicesWithinTolerance)
131+
{
132+
if (spectrum.YArray[index] > maxIntensity) { maxIntensity = spectrum.YArray[index]; maxIndex = index; }
133+
}
134+
if (maxIndex >= 0)
135+
{
136+
peaks.Add((spectrum.XArray[maxIndex], spectrum.YArray[maxIndex]));
137+
}
138+
else
139+
{
140+
peaks.Add((peak.isomz[i], 0));
141+
}
142+
143+
}
144+
int charge = peak.z;
145+
if(parameters.Polarity == Polarity.Negative) { charge = -peak.z; }
146+
if(parameters.ReportMulitpleMonoisos)
147+
{
148+
foreach (float monoiso in peak.monoisos)
149+
{
150+
if (monoiso > 0) { result.Add(new IsotopicEnvelope(currentId, peaks, (double)monoiso, charge, peak.peakint, peak.score)); }
151+
}
152+
}
153+
else { result.Add(new IsotopicEnvelope(currentId, peaks, (double)peak.monoiso, charge, peak.peakint, peak.score)); }
154+
currentId++;
155+
}
156+
return result;
157+
}
158+
}
159+
}

0 commit comments

Comments
 (0)