Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 14 additions & 23 deletions tests/MSDIAL5/MsdialCoreTestApp/Process/LcimmsProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private async Task<int> ExecuteAsync(IMsdialDataStorage<MsdialLcImMsParameter> s
aligner.ProviderFactory = providerFactory;
var result = aligner.Alignment(files, alignmentFile, serializer);
result.Save(alignmentFile);
var align_decResults = LoadRepresentativeDeconvolutions(storage, result.AlignmentSpotProperties).ToList();
var align_decResults = LoadRepresentativeDeconvolutions(files, result.AlignmentSpotProperties).ToList();
MsdecResultsWriter.Write(alignmentFile.SpectraFilePath, align_decResults);

var align_accessor = new LcimmsMetadataAccessor(storage.DataBaseMapper, storage.Parameter, false);
Expand Down Expand Up @@ -184,29 +184,20 @@ private async Task<int> ExecuteAsync(IMsdialDataStorage<MsdialLcImMsParameter> s
return 0;
}

private static IEnumerable<MSDecResult> LoadRepresentativeDeconvolutions(IMsdialDataStorage<MsdialLcImMsParameter> storage, IReadOnlyList<AlignmentSpotProperty> spots) {
var files = storage.AnalysisFiles;

var pointerss = new List<(int version, List<long> pointers, bool isAnnotationInfo)>();
foreach (var file in files) {
MsdecResultsReader.GetSeekPointers(file.DeconvolutionFilePath, out var version, out var pointers, out var isAnnotationInfo);
pointerss.Add((version, pointers, isAnnotationInfo));
}

var streams = new List<FileStream>();
try {
streams = files.Select(file => File.OpenRead(file.DeconvolutionFilePath)).ToList();
foreach (var spot in spots.OrEmptyIfNull()) {
var repID = spot.RepresentativeFileID;
var peakID = spot.AlignedPeakProperties[repID].MasterPeakID;
var decResult = MsdecResultsReader.ReadMSDecResult(
streams[repID], pointerss[repID].pointers[peakID],
pointerss[repID].version, pointerss[repID].isAnnotationInfo);
yield return decResult;
/// <summary>
/// One deconvolution result per alignment spot, indexed by MasterAlignmentID: each RT spot followed by its
/// drift spots, the order LcimmsAlignmentRefiner numbers them in and the GUI's
/// AlignmentFileBeanModel.LoadMSDecResultsFromEachFiles reads them in. AlignmentCSVExporter and
/// MztabFormatExporter index this list by the drift spots' MasterAlignmentID too, so a list of the RT
/// spots alone overflowed on the first drift spot.
/// </summary>
internal static IEnumerable<MSDecResult> LoadRepresentativeDeconvolutions(IReadOnlyList<AnalysisFileBean> files, IReadOnlyList<AlignmentSpotProperty>? spots) {
using var reader = new RepresentativeDeconvolutionReader(files);
foreach (var spot in spots.OrEmptyIfNull()) {
yield return reader.Read(spot.AlignedPeakProperties[spot.RepresentativeFileID]);
foreach (var driftSpot in spot.AlignmentDriftSpotFeatures.OrEmptyIfNull()) {
yield return reader.Read(driftSpot.AlignedPeakProperties[driftSpot.RepresentativeFileID]);
}
}
finally {
streams.ForEach(stream => stream.Close());
}
}
}
82 changes: 82 additions & 0 deletions tests/MSDIAL5/MsdialCoreTestAppTests/Process/LcimmsProcessTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using CompMs.App.MsdialConsole.Process;
using CompMs.MsdialCore.DataObj;
using CompMs.MsdialCore.MSDec;
using CompMs.MsdialCore.Parser;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace MsdialCoreTestAppTests.Process;

/// <summary>
/// The LC-IM-MS alignment export indexes the deconvolution results by MasterAlignmentID for the drift spots as
/// well as the RT spots. The Console loaded one result per RT spot only, so AlignmentCSVExporter.Export threw
/// ArgumentOutOfRangeException on the first drift spot.
/// </summary>
[TestClass]
public sealed class LcimmsProcessTests
{
private string _scratch = null!;

[TestInitialize]
public void Initialize() {
_scratch = Path.Combine(Path.GetTempPath(), $"msdial-lcimms-dcl-{Guid.NewGuid():N}");
Directory.CreateDirectory(_scratch);
}

[TestCleanup]
public void Cleanup() {
if (Directory.Exists(_scratch)) {
Directory.Delete(_scratch, recursive: true);
}
}

[TestMethod]
public void EveryRtAndDriftSpotHasItsResultAtItsMasterAlignmentId() {
var file0 = NewFile(0, "file0", peakCount: 6);
var file1 = NewFile(1, "file1", peakCount: 6);
// Numbered as LcimmsAlignmentRefiner numbers them: each RT spot, then its drift spots.
var spots = new List<AlignmentSpotProperty>
{
Spot(0, representative: 0, masterPeakId: 0, Spot(1, representative: 1, masterPeakId: 1), Spot(2, representative: 0, masterPeakId: 2)),
Spot(3, representative: 1, masterPeakId: 3),
Spot(4, representative: 1, masterPeakId: 4, Spot(5, representative: 0, masterPeakId: 5)),
};

var results = LcimmsProcess.LoadRepresentativeDeconvolutions([file0, file1], spots).ToList();

Assert.AreEqual(6, results.Count);
foreach (var spot in spots.SelectMany(s => s.AlignmentDriftSpotFeatures.Prepend(s))) {
var peak = spot.AlignedPeakProperties[spot.RepresentativeFileID];
Assert.AreEqual(Marker(peak.FileID, peak.MasterPeakID), results[spot.MasterAlignmentID].PrecursorMz, $"spot {spot.MasterAlignmentID}");
}
}

private AnalysisFileBean NewFile(int id, string name, int peakCount) {
var file = new AnalysisFileBean {
AnalysisFileId = id,
AnalysisFileName = name,
AnalysisFilePath = Path.Combine(_scratch, name + ".d"),
DeconvolutionFilePath = Path.Combine(_scratch, name + "_202610181.dcl"),
};
var results = Enumerable.Range(0, peakCount).Select(i => new MSDecResult { ScanID = i, PrecursorMz = Marker(id, i), }).ToList();
MsdecResultsWriter.Write(file.DeconvolutionFilePath, results);
return file;
}

private static AlignmentSpotProperty Spot(int masterAlignmentId, int representative, int masterPeakId, params AlignmentSpotProperty[] driftSpots) {
return new AlignmentSpotProperty {
MasterAlignmentID = masterAlignmentId,
RepresentativeFileID = representative,
AlignedPeakProperties = Enumerable.Range(0, 2)
.Select(fileId => new AlignmentChromPeakFeature { FileID = fileId, MasterPeakID = fileId == representative ? masterPeakId : -1, })
.ToList(),
AlignmentDriftSpotFeatures = driftSpots.ToList(),
};
}

// Which file and which peak a result came from.
private static double Marker(int fileId, int peak) => fileId * 1000d + peak;
}
Loading