From 7309ae790df040fdd1ab007b1c2abe87267f6908 Mon Sep 17 00:00:00 2001 From: Yuki Matsuzawa Date: Sat, 22 Aug 2026 09:02:56 +0900 Subject: [PATCH 1/3] Optimize MS2 value peak extraction Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/MSDIAL5/MsdialCore/Utility/DataAccess.cs | 24 +++----------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs b/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs index bf8cccd0d..f351b381e 100644 --- a/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs +++ b/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs @@ -332,10 +332,7 @@ public static List GetMs2ValuePeaks(IDataProvider provider, double int startScanID, int endScanID, IReadOnlyList pMzValues, ParameterBase param, AcquisitionType acquisitionType, double targetCE = -1, ChromXType type = ChromXType.RT, ChromXUnit unit = ChromXUnit.Min) { - var counter = 0; - var arrayLength = GetTargetArrayLength(provider, startScanID, endScanID, precursorMz, targetCE, param, acquisitionType); - var valuePeakArrayList = new List(pMzValues.Count); - valuePeakArrayList.AddRange(pMzValues.Select(_ => new ValuePeak[arrayLength])); + var valuePeakLists = pMzValues.Select(_ => new List()).ToArray(); for (int i = startScanID; i <= endScanID; i++) { var spec = provider.LoadMsSpectrumFromIndex(i); @@ -348,27 +345,12 @@ public static List GetMs2ValuePeaks(IDataProvider provider, double var intensities = RetrieveIntensitiesFromMzValues(pMzValues, spec.Spectrum, param.CentroidMs2Tolerance); for (int j = 0; j < pMzValues.Count; j++) { - valuePeakArrayList[j][counter] = new ValuePeak(id, chromX, pMzValues[j], intensities[j]); + valuePeakLists[j].Add(new ValuePeak(id, chromX, pMzValues[j], intensities[j])); } - counter++; - } - } - } - return valuePeakArrayList; - } - - private static int GetTargetArrayLength(IDataProvider provider, int startScanID, int endScanID, double precursorMz, double targetCE, ParameterBase param, AcquisitionType type) { - var counter = 0; - for (int i = startScanID; i <= endScanID; i++) { - var spec = provider.LoadMsSpectrumFromIndex(i); - if (spec.MsLevel == 2 && spec.Precursor != null) { - if (targetCE >= 0 && spec.CollisionEnergy >= 0 && Math.Abs(targetCE - spec.CollisionEnergy) > 1) continue; // for AIF mode - if (IsInMassWindow(precursorMz, spec, param.CentroidMs1Tolerance, type)) { - counter++; } } } - return counter; + return valuePeakLists.Select(peaks => peaks.ToArray()).ToList(); } public static double[] RetrieveIntensitiesFromMzValues( From b278d8686d32043ace97bb38dab8add2e213f525 Mon Sep 17 00:00:00 2001 From: YukiMatsuzawa <122433968+YukiMatsuzawa@users.noreply.github.com> Date: Fri, 4 Sep 2026 15:23:20 +0900 Subject: [PATCH 2/3] Apply batched suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/MSDIAL5/MsdialCore/Utility/DataAccess.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs b/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs index f351b381e..6245a695b 100644 --- a/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs +++ b/src/MSDIAL5/MsdialCore/Utility/DataAccess.cs @@ -332,8 +332,10 @@ public static List GetMs2ValuePeaks(IDataProvider provider, double int startScanID, int endScanID, IReadOnlyList pMzValues, ParameterBase param, AcquisitionType acquisitionType, double targetCE = -1, ChromXType type = ChromXType.RT, ChromXUnit unit = ChromXUnit.Min) { - var valuePeakLists = pMzValues.Select(_ => new List()).ToArray(); - +var valuePeakLists = new List[pMzValues.Count]; +for (int j = 0; j < valuePeakLists.Length; j++) { + valuePeakLists[j] = new List(); +} for (int i = startScanID; i <= endScanID; i++) { var spec = provider.LoadMsSpectrumFromIndex(i); if (spec.MsLevel == 2 && spec.Precursor != null) { @@ -350,7 +352,11 @@ public static List GetMs2ValuePeaks(IDataProvider provider, double } } } - return valuePeakLists.Select(peaks => peaks.ToArray()).ToList(); +var results = new List(valuePeakLists.Length); +for (int j = 0; j < valuePeakLists.Length; j++) { + results.Add(valuePeakLists[j].ToArray()); +} +return results; } public static double[] RetrieveIntensitiesFromMzValues( From a3ececd372e70ae6ba76e4e30d2a8d2e007f3f9c Mon Sep 17 00:00:00 2001 From: Yuki Matsuzawa Date: Tue, 8 Sep 2026 13:47:00 +0900 Subject: [PATCH 3/3] Add MS2 peak extraction regression test Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Utility/DataAccessTests.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/MSDIAL5/MsdialCoreTests/Utility/DataAccessTests.cs b/tests/MSDIAL5/MsdialCoreTests/Utility/DataAccessTests.cs index f4c023aca..365a0e47f 100644 --- a/tests/MSDIAL5/MsdialCoreTests/Utility/DataAccessTests.cs +++ b/tests/MSDIAL5/MsdialCoreTests/Utility/DataAccessTests.cs @@ -1,8 +1,16 @@ using CompMs.Common.Components; using CompMs.Common.DataObj; +using CompMs.Common.Enum; +using CompMs.MsdialCore.Algorithm; using CompMs.Common.DataObj.Property; using CompMs.MsdialCore.DataObj; +using CompMs.MsdialCore.Parameter; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace CompMs.MsdialCore.Utility.Tests; @@ -118,6 +126,72 @@ public void GetAverageSpectrumTest() { } } + [TestMethod()] + public void GetMs2ValuePeaksReturnsMatchingPeaksInScanOrder() { + var provider = new StubDataProvider([ + new RawSpectrum { MsLevel = 1 }, + CreateMs2Spectrum(10, 500, 0, 3, 7), + CreateMs2Spectrum(11, 500, 2, 100, 200), + CreateMs2Spectrum(12, 500, 0, 5, 11), + new RawSpectrum { MsLevel = 2 }, + ]); + var parameter = new ParameterBase { + CentroidMs1Tolerance = 0.1f, + CentroidMs2Tolerance = 0.05f, + }; + + var actual = DataAccess.GetMs2ValuePeaks( + provider, 500, 0, 4, [100, 200], parameter, AcquisitionType.DDA, targetCE: 0); + + Assert.AreEqual(2, actual.Count); + Assert.AreEqual(2, actual[0].Length); + Assert.AreEqual(2, actual[1].Length); + CollectionAssert.AreEqual(new[] { 10, 12 }, actual[0].Select(peak => peak.Id).ToArray()); + CollectionAssert.AreEqual(new[] { 10, 12 }, actual[1].Select(peak => peak.Id).ToArray()); + Assert.AreEqual(3d, actual[0][0].Intensity); + Assert.AreEqual(5d, actual[0][1].Intensity); + Assert.AreEqual(7d, actual[1][0].Intensity); + Assert.AreEqual(11d, actual[1][1].Intensity); + } + + private static RawSpectrum CreateMs2Spectrum(int index, double precursorMz, double collisionEnergy, double firstIntensity, double secondIntensity) { + return new RawSpectrum { + Index = index, + MsLevel = 2, + CollisionEnergy = collisionEnergy, + ScanStartTime = index, + Precursor = new RawPrecursorIon { IsolationTargetMz = precursorMz }, + Spectrum = [ + new RawPeakElement { Mz = 100, Intensity = firstIntensity }, + new RawPeakElement { Mz = 150, Intensity = 0 }, + new RawPeakElement { Mz = 200, Intensity = secondIntensity }, + new RawPeakElement { Mz = 250, Intensity = 0 }, + ], + }; + } + + private sealed class StubDataProvider : IDataProvider { + private readonly ReadOnlyCollection _spectra; + + public StubDataProvider(IList spectra) { + _spectra = new ReadOnlyCollection(spectra); + } + + public ReadOnlyCollection LoadMsSpectrums() { + return _spectra; + } + + public ReadOnlyCollection LoadMs1Spectrums() => throw new System.NotImplementedException(); + + public ReadOnlyCollection LoadMsNSpectrums(int level) => throw new System.NotImplementedException(); + + public Task> LoadMsSpectrumsAsync(CancellationToken token) => throw new System.NotImplementedException(); + + public Task> LoadMs1SpectrumsAsync(CancellationToken token) => throw new System.NotImplementedException(); + + public Task> LoadMsNSpectrumsAsync(int level, CancellationToken token) => throw new System.NotImplementedException(); + } + [TestMethod()] public void ReferenceMatchedExportUsesAnnotationName() { foreach (var name in new[] { "", " ", "Unknown", "unknown feature", "null", "empty", "w/o MS2: compound", "RIKEN MS/MS" }) {