diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/BasePeakDetector.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/BasePeakDetector.java index de910cbae5..b6392d75a2 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/BasePeakDetector.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/BasePeakDetector.java @@ -23,15 +23,7 @@ import org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.support.IFirstDerivativeDetectorSlopes; import org.eclipse.chemclipse.model.core.IChromatogram; import org.eclipse.chemclipse.model.core.IPeak; -import org.eclipse.chemclipse.model.core.IScan; -import org.eclipse.chemclipse.model.support.ScanRange; import org.eclipse.chemclipse.msd.model.core.IPeakModelMSD; -import org.eclipse.chemclipse.msd.model.core.IScanMSD; -import org.eclipse.chemclipse.msd.model.core.support.IMarkedIons; -import org.eclipse.chemclipse.numeric.core.IPoint; -import org.eclipse.chemclipse.numeric.core.Point; -import org.eclipse.chemclipse.numeric.equations.Equations; -import org.eclipse.chemclipse.numeric.equations.LinearEquation; import org.eclipse.chemclipse.numeric.miscellaneous.Evaluation; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; @@ -111,76 +103,6 @@ public static List getRawPeaks(IFirstDerivativeDetectorSlopes slopes, return rawPeaks; } - protected ScanRange optimizeBaseline(IChromatogram chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { - - /* - * Right and left baseline optimization - */ - int stopScanOptimized = optimizeRightBaseline(chromatogram, startScan, centerScan, stopScan, ions); - int startScanOptimized = optimizeLeftBaseline(chromatogram, startScan, centerScan, stopScanOptimized, ions); - // - return new ScanRange(startScanOptimized, stopScanOptimized); - } - - protected float getScanSignal(IChromatogram chromatogram, int scanNumber, IMarkedIons ions) { - - float scanSignal = 0.0f; - IScan scan = chromatogram.getScan(scanNumber); - if(scan instanceof IScanMSD) { - IScanMSD scanMSD = (IScanMSD)scan; - scanSignal = scanMSD.getTotalSignal(ions); - } else { - scanSignal = scan.getTotalSignal(); - } - return scanSignal; - } - - private int optimizeRightBaseline(IChromatogram chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { - - IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, ions)); - IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); - LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); - /* - * Right border optimization - */ - int stopScanOptimized = stopScan; - for(int i = stopScan; i > centerScan; i--) { - float signal = getScanSignal(chromatogram, i, ions); - int retentionTime = chromatogram.getScan(i).getRetentionTime(); - if(signal < backgroundEquation.calculateY(retentionTime)) { - stopScanOptimized = i; - } - } - // - return stopScanOptimized; - } - - private int optimizeLeftBaseline(IChromatogram chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { - - IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, ions)); - IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); - LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); - /* - * Right border optimization - */ - int startScanOptimized = startScan; - for(int i = startScan; i < centerScan; i++) { - float signal = getScanSignal(chromatogram, i, ions); - int retentionTime = chromatogram.getScan(i).getRetentionTime(); - if(signal < backgroundEquation.calculateY(retentionTime)) { - /* - * Create a new equation - */ - startScanOptimized = i; - p1 = new Point(getRetentionTime(chromatogram, startScanOptimized), getScanSignal(chromatogram, startScanOptimized, ions)); - p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); - backgroundEquation = Equations.createLinearEquation(p1, p2); - } - } - // - return startScanOptimized; - } - protected int getRetentionTime(IChromatogram chromatogram, int scanNumber) { return chromatogram.getScan(scanNumber).getRetentionTime(); diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/FirstDerivativePeakDetector.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/FirstDerivativePeakDetector.java index de94b84009..c72381a57d 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/FirstDerivativePeakDetector.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/FirstDerivativePeakDetector.java @@ -91,7 +91,8 @@ public Map detectIMeasurementPeaks(Collect } else { configuration = globalConfiguration; } - slopes = PeakDetectorWSD.getFirstDerivativeSlopes(new ChromatogramSelectionWSD((IChromatogramWSD)measurement), configuration.getMovingAverageWindowSize()); + // TODO: filter wavelengths + slopes = PeakDetectorWSD.getFirstDerivativeSlopes(new ChromatogramSelectionWSD((IChromatogramWSD)measurement), configuration.getMovingAverageWindowSize(), null); } else if(measurement instanceof SpectrumMeasurement) { if(globalConfiguration == null) { configuration = new FirstDerivativePeakDetectorSettings(DataType.NMR); diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorCSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorCSD.java index 9e125312a1..ed056c9422 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorCSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorCSD.java @@ -35,6 +35,7 @@ import org.eclipse.chemclipse.logging.core.Logger; import org.eclipse.chemclipse.model.core.IChromatogram; import org.eclipse.chemclipse.model.core.IPeak; +import org.eclipse.chemclipse.model.core.IScan; import org.eclipse.chemclipse.model.exceptions.PeakException; import org.eclipse.chemclipse.model.signals.ITotalScanSignal; import org.eclipse.chemclipse.model.signals.ITotalScanSignals; @@ -45,6 +46,8 @@ import org.eclipse.chemclipse.msd.model.core.IChromatogramPeakMSD; import org.eclipse.chemclipse.numeric.core.IPoint; import org.eclipse.chemclipse.numeric.core.Point; +import org.eclipse.chemclipse.numeric.equations.Equations; +import org.eclipse.chemclipse.numeric.equations.LinearEquation; import org.eclipse.chemclipse.processing.core.IProcessingInfo; import org.eclipse.chemclipse.processing.core.MessageType; import org.eclipse.chemclipse.processing.core.ProcessingMessage; @@ -197,7 +200,7 @@ private List extractPeaks(List rawPeaks, IChroma */ ScanRange scanRange = new ScanRange(rawPeak.getStartScan(), rawPeak.getStopScan()); if(includeBackground && optimizeBaseline) { - scanRange = optimizeBaseline(chromatogram, scanRange.getStartScan(), rawPeak.getMaximumScan(), scanRange.getStopScan(), null); + scanRange = optimizeBaseline(chromatogram, scanRange.getStartScan(), rawPeak.getMaximumScan(), scanRange.getStopScan()); } /* * includeBackground @@ -272,9 +275,66 @@ public static IFirstDerivativeDetectorSlopes getFirstDerivativeSlopes(IChromatog */ private boolean isValidPeak(IChromatogramPeakCSD peak, PeakDetectorSettingsCSD peakDetectorSettings) { - if(peak != null && peak.getSignalToNoiseRatio() >= peakDetectorSettings.getMinimumSignalToNoiseRatio()) { - return true; + return (peak != null && peak.getSignalToNoiseRatio() >= peakDetectorSettings.getMinimumSignalToNoiseRatio()); + } + + private ScanRange optimizeBaseline(IChromatogramCSD chromatogram, int startScan, int centerScan, int stopScan) { + + int stopScanOptimized = optimizeRightBaseline(chromatogram, startScan, centerScan, stopScan); + int startScanOptimized = optimizeLeftBaseline(chromatogram, startScan, centerScan, stopScanOptimized); + // + return new ScanRange(startScanOptimized, stopScanOptimized); + } + + private int optimizeRightBaseline(IChromatogramCSD chromatogram, int startScan, int centerScan, int stopScan) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int stopScanOptimized = stopScan; + for(int i = stopScan; i > centerScan; i--) { + float signal = getScanSignal(chromatogram, i); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + stopScanOptimized = i; + } + } + // + return stopScanOptimized; + } + + private int optimizeLeftBaseline(IChromatogramCSD chromatogram, int startScan, int centerScan, int stopScan) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int startScanOptimized = startScan; + for(int i = startScan; i < centerScan; i++) { + float signal = getScanSignal(chromatogram, i); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + /* + * Create a new equation + */ + startScanOptimized = i; + p1 = new Point(getRetentionTime(chromatogram, startScanOptimized), getScanSignal(chromatogram, startScanOptimized)); + p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan)); + backgroundEquation = Equations.createLinearEquation(p1, p2); + } } - return false; + // + return startScanOptimized; + } + + protected float getScanSignal(IChromatogramCSD chromatogram, int scanNumber) { + + IScan scan = chromatogram.getScan(scanNumber); + return scan.getTotalSignal(); } } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorMSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorMSD.java index 97b2c866df..2f913cbe3b 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorMSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorMSD.java @@ -36,6 +36,7 @@ import org.eclipse.chemclipse.logging.core.Logger; import org.eclipse.chemclipse.model.core.IChromatogram; import org.eclipse.chemclipse.model.core.IPeak; +import org.eclipse.chemclipse.model.core.IScan; import org.eclipse.chemclipse.model.exceptions.ChromatogramIsNullException; import org.eclipse.chemclipse.model.signals.ITotalScanSignal; import org.eclipse.chemclipse.model.signals.ITotalScanSignals; @@ -44,6 +45,7 @@ import org.eclipse.chemclipse.model.support.ScanRange; import org.eclipse.chemclipse.msd.model.core.IChromatogramMSD; import org.eclipse.chemclipse.msd.model.core.IChromatogramPeakMSD; +import org.eclipse.chemclipse.msd.model.core.IScanMSD; import org.eclipse.chemclipse.msd.model.core.selection.IChromatogramSelectionMSD; import org.eclipse.chemclipse.msd.model.core.support.IMarkedIons; import org.eclipse.chemclipse.msd.model.core.support.IMarkedIons.IonMarkMode; @@ -53,6 +55,8 @@ import org.eclipse.chemclipse.msd.model.xic.TotalIonSignalExtractor; import org.eclipse.chemclipse.numeric.core.IPoint; import org.eclipse.chemclipse.numeric.core.Point; +import org.eclipse.chemclipse.numeric.equations.Equations; +import org.eclipse.chemclipse.numeric.equations.LinearEquation; import org.eclipse.chemclipse.processing.core.IProcessingInfo; import org.eclipse.chemclipse.processing.core.MessageType; import org.eclipse.chemclipse.processing.core.ProcessingMessage; @@ -131,12 +135,13 @@ public List detectPeaks(IChromatogramSelectionMSD chromato List extractPeaks = new ArrayList<>(); Collection filterIons = peakDetectorSettings.getFilterIons(); + IChromatogramMSD chromatogram = chromatogramSelection.getChromatogram(); for(IMarkedIons ions : filterIons) { Threshold threshold = peakDetectorSettings.getThreshold(); int windowSize = peakDetectorSettings.getMovingAverageWindowSize(); List rawPeaks = new ArrayList<>(); // - if(noiseSegments != null && noiseSegments.size() > 0) { + if(noiseSegments != null && !noiseSegments.isEmpty()) { /* * Initial retention time range before running the detection using * noise segments. @@ -159,11 +164,11 @@ public List detectPeaks(IChromatogramSelectionMSD chromato * Ranges between the noise segments * [S] --- [N] --- [E] */ - while(iterator.hasNext()) { - int startRetentionTimeSegment = noiseSegment.getStopRetentionTime(); + while(iterator.hasNext() && noiseSegment != null) { + int previousStopRetentionTimeSegment = noiseSegment.getStopRetentionTime(); noiseSegment = iterator.next(); - int stopRetentionTimeSegment = noiseSegment.getStartRetentionTime(); - chromatogramSelection.setRangeRetentionTime(startRetentionTimeSegment, stopRetentionTimeSegment); + int nextStartRetentionTimeSegment = noiseSegment.getStartRetentionTime(); + chromatogramSelection.setRangeRetentionTime(previousStopRetentionTimeSegment, nextStartRetentionTimeSegment); IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, ions); rawPeaks.addAll(getRawPeaks(slopes, threshold, monitor)); } @@ -187,7 +192,7 @@ public List detectPeaks(IChromatogramSelectionMSD chromato IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, ions); rawPeaks.addAll(getRawPeaks(slopes, threshold, monitor)); } - List peaks = extractPeaks(rawPeaks, chromatogramSelection.getChromatogram(), peakDetectorSettings, ions); + List peaks = extractPeaks(rawPeaks, chromatogram, peakDetectorSettings, ions); if(peakDetectorSettings.isUseIndividualTraces()) { String classifier = "Trace " + ions.getIonsNominal().iterator().next(); for(IChromatogramPeakMSD msd : peaks) { @@ -326,9 +331,74 @@ private static IonMarkMode buildFilterMode(FilterMode mode) { */ private boolean isValidPeak(IChromatogramPeakMSD peak, PeakDetectorSettingsMSD peakDetectorSettings) { - if(peak != null && peak.getSignalToNoiseRatio() >= peakDetectorSettings.getMinimumSignalToNoiseRatio()) { - return true; + return (peak != null && peak.getSignalToNoiseRatio() >= peakDetectorSettings.getMinimumSignalToNoiseRatio()); + } + + protected ScanRange optimizeBaseline(IChromatogramMSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { + + /* + * Right and left baseline optimization + */ + int stopScanOptimized = optimizeRightBaseline(chromatogram, startScan, centerScan, stopScan, ions); + int startScanOptimized = optimizeLeftBaseline(chromatogram, startScan, centerScan, stopScanOptimized, ions); + // + return new ScanRange(startScanOptimized, stopScanOptimized); + } + + protected float getScanSignal(IChromatogramMSD chromatogram, int scanNumber, IMarkedIons ions) { + + IScan scan = chromatogram.getScan(scanNumber); + if(scan instanceof IScanMSD) { + IScanMSD scanMSD = (IScanMSD)scan; + return scanMSD.getTotalSignal(ions); + } else { + return scan.getTotalSignal(); + } + } + + private int optimizeRightBaseline(IChromatogramMSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, ions)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int stopScanOptimized = stopScan; + for(int i = stopScan; i > centerScan; i--) { + float signal = getScanSignal(chromatogram, i, ions); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + stopScanOptimized = i; + } } - return false; + // + return stopScanOptimized; + } + + private int optimizeLeftBaseline(IChromatogramMSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedIons ions) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, ions)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int startScanOptimized = startScan; + for(int i = startScan; i < centerScan; i++) { + float signal = getScanSignal(chromatogram, i, ions); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + /* + * Create a new equation + */ + startScanOptimized = i; + p1 = new Point(getRetentionTime(chromatogram, startScanOptimized), getScanSignal(chromatogram, startScanOptimized, ions)); + p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, ions)); + backgroundEquation = Equations.createLinearEquation(p1, p2); + } + } + // + return startScanOptimized; } } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorWSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorWSD.java index 3d9219876f..8f0084db2e 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorWSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/core/PeakDetectorWSD.java @@ -13,12 +13,18 @@ package org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.core; import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.chemclipse.chromatogram.peak.detector.exceptions.ValueMustNotBeNullException; +import org.eclipse.chemclipse.chromatogram.peak.detector.model.Threshold; import org.eclipse.chemclipse.chromatogram.peak.detector.support.IRawPeak; import org.eclipse.chemclipse.chromatogram.wsd.peak.detector.core.IPeakDetectorWSD; import org.eclipse.chemclipse.chromatogram.wsd.peak.detector.settings.IPeakDetectorSettingsWSD; +import org.eclipse.chemclipse.chromatogram.xxd.calculator.core.noise.NoiseChromatogramClassifier; import org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.preferences.PreferenceSupplier; import org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.settings.PeakDetectorSettingsWSD; import org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.support.FirstDerivativeDetectorSlope; @@ -28,30 +34,39 @@ import org.eclipse.chemclipse.logging.core.Logger; import org.eclipse.chemclipse.model.core.IChromatogram; import org.eclipse.chemclipse.model.core.IPeak; +import org.eclipse.chemclipse.model.core.IScan; +import org.eclipse.chemclipse.model.exceptions.ChromatogramIsNullException; import org.eclipse.chemclipse.model.exceptions.PeakException; import org.eclipse.chemclipse.model.signals.ITotalScanSignal; import org.eclipse.chemclipse.model.signals.ITotalScanSignals; -import org.eclipse.chemclipse.model.signals.TotalScanSignals; import org.eclipse.chemclipse.model.signals.TotalScanSignalsModifier; import org.eclipse.chemclipse.model.support.IScanRange; +import org.eclipse.chemclipse.model.support.NoiseSegment; import org.eclipse.chemclipse.model.support.ScanRange; import org.eclipse.chemclipse.msd.model.core.IChromatogramPeakMSD; import org.eclipse.chemclipse.numeric.core.IPoint; import org.eclipse.chemclipse.numeric.core.Point; +import org.eclipse.chemclipse.numeric.equations.Equations; +import org.eclipse.chemclipse.numeric.equations.LinearEquation; import org.eclipse.chemclipse.processing.core.IProcessingInfo; import org.eclipse.chemclipse.processing.core.MessageType; import org.eclipse.chemclipse.processing.core.ProcessingMessage; import org.eclipse.chemclipse.wsd.model.core.IChromatogramPeakWSD; import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; +import org.eclipse.chemclipse.wsd.model.core.IScanWSD; import org.eclipse.chemclipse.wsd.model.core.selection.IChromatogramSelectionWSD; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; import org.eclipse.chemclipse.wsd.model.core.support.PeakBuilderWSD; +import org.eclipse.chemclipse.wsd.model.xwc.ITotalWavelengthSignalExtractor; +import org.eclipse.chemclipse.wsd.model.xwc.TotalWavelengthSignalExtractor; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; public class PeakDetectorWSD

, R> extends BasePeakDetector implements IPeakDetectorWSD { private static final Logger logger = Logger.getLogger(PeakDetectorWSD.class); // - private static float NORMALIZATION_BASE = 100000.0f; + private static final float NORMALIZATION_BASE = 100000.0f; @Override public IProcessingInfo detect(IChromatogramSelectionWSD chromatogramSelection, IPeakDetectorSettingsWSD detectorSettings, IProgressMonitor monitor) { @@ -62,13 +77,21 @@ public IProcessingInfo detect(IChromatogramSelectionWSD chromatogramSelection IProcessingInfo processingInfo = validate(chromatogramSelection, detectorSettings, monitor); if(!processingInfo.hasErrorMessages()) { if(detectorSettings instanceof PeakDetectorSettingsWSD) { + SubMonitor subMonitor = SubMonitor.convert(monitor, 100); PeakDetectorSettingsWSD peakDetectorSettings = (PeakDetectorSettingsWSD)detectorSettings; - List peaks = detectPeaks(chromatogramSelection, peakDetectorSettings, monitor); + /* + * Extract the noise segments. + */ + List noiseSegments = null; IChromatogramWSD chromatogram = chromatogramSelection.getChromatogram(); + if(peakDetectorSettings.isUseNoiseSegments()) { + noiseSegments = NoiseChromatogramClassifier.getNoiseSegments(chromatogram, chromatogramSelection, false, subMonitor.split(10)); + } + List peaks = detectPeaks(chromatogramSelection, peakDetectorSettings, noiseSegments, subMonitor.split(90)); for(IChromatogramPeakWSD peak : peaks) { chromatogram.addPeak(peak); } - processingInfo.addMessage(new ProcessingMessage(MessageType.INFO, FirstDerivativePeakDetector.DETECTOR_DESCRIPTION, "Peaks have been detected successfully.")); + processingInfo.addMessage(new ProcessingMessage(MessageType.INFO, FirstDerivativePeakDetector.DETECTOR_DESCRIPTION, peaks.size() + " peaks have been detected successfully.")); } else { logger.warn("Settings is not of type: " + PeakDetectorSettingsWSD.class); } @@ -92,11 +115,77 @@ public IProcessingInfo detect(IChromatogramSelectionWSD chromatogramSelection * @param chromatogramSelection * @throws ValueMustNotBeNullException */ - public List detectPeaks(IChromatogramSelectionWSD chromatogramSelection, PeakDetectorSettingsWSD peakDetectorSettings, IProgressMonitor monitor) { + public List detectPeaks(IChromatogramSelectionWSD chromatogramSelection, PeakDetectorSettingsWSD peakDetectorSettings, List noiseSegments, IProgressMonitor monitor) { - IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, peakDetectorSettings.getMovingAverageWindowSize()); - List rawPeaks = getRawPeaks(slopes, peakDetectorSettings.getThreshold(), monitor); - return extractPeaks(rawPeaks, chromatogramSelection.getChromatogram(), peakDetectorSettings); + List extractPeaks = new ArrayList<>(); + Collection filterWavelengths = peakDetectorSettings.getFilterWavelengths(); + IChromatogramWSD chromatogram = chromatogramSelection.getChromatogram(); + for(IMarkedWavelengths wavelengths : filterWavelengths) { + Threshold threshold = peakDetectorSettings.getThreshold(); + int windowSize = peakDetectorSettings.getMovingAverageWindowSize(); + List rawPeaks = new ArrayList<>(); + // + if(noiseSegments != null && !noiseSegments.isEmpty()) { + /* + * Initial retention time range before running the detection using + * noise segments. + * | --- [S] --- [N] --- [E] --- | + */ + Iterator iterator = noiseSegments.iterator(); + int startRetentionTime = chromatogramSelection.getStartRetentionTime(); + int stopRetentionTime = chromatogramSelection.getStopRetentionTime(); + NoiseSegment noiseSegment = iterator.hasNext() ? iterator.next() : null; + /* + * Range from the start of the chromatogram selection to the first noise segment + * | --- [S] + */ + if(noiseSegment != null) { + chromatogramSelection.setRangeRetentionTime(startRetentionTime, noiseSegment.getStartRetentionTime()); + IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, wavelengths); + rawPeaks.addAll(getRawPeaks(slopes, threshold, monitor)); + } + /* + * Ranges between the noise segments + * [S] --- [N] --- [E] + */ + while(iterator.hasNext() && noiseSegment != null) { + int previousStopRetentionTimeSegment = noiseSegment.getStopRetentionTime(); + noiseSegment = iterator.next(); + int nextStartRetentionTimeSegment = noiseSegment.getStartRetentionTime(); + chromatogramSelection.setRangeRetentionTime(previousStopRetentionTimeSegment, nextStartRetentionTimeSegment); + IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, wavelengths); + rawPeaks.addAll(getRawPeaks(slopes, threshold, monitor)); + } + /* + * Range from the last noise segment to the end of the chromatogram selection + * [E] --- | + */ + if(noiseSegment != null) { + chromatogramSelection.setRangeRetentionTime(noiseSegment.getStopRetentionTime(), stopRetentionTime); + IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, wavelengths); + rawPeaks.addAll(getRawPeaks(slopes, threshold, monitor)); + } + /* + * Reset the retention time range to its initial values. + */ + chromatogramSelection.setRangeRetentionTime(startRetentionTime, stopRetentionTime); + } else { + /* + * Default: no noise segments + */ + IFirstDerivativeDetectorSlopes slopes = getFirstDerivativeSlopes(chromatogramSelection, windowSize, wavelengths); + rawPeaks = getRawPeaks(slopes, peakDetectorSettings.getThreshold(), monitor); + } + List peaks = extractPeaks(rawPeaks, chromatogram, peakDetectorSettings, wavelengths); + if(peakDetectorSettings.isIndividualWavelengths()) { + String classifier = "Wavelength " + peaks.iterator().next(); + for(IChromatogramPeakWSD wsd : peaks) { + wsd.addClassifier(classifier); + } + } + extractPeaks.addAll(peaks); + } + return extractPeaks; } /** @@ -107,9 +196,12 @@ public List detectPeaks(IChromatogramSelectionWSD chromato * @param chromatogram * @return List */ - private List extractPeaks(List rawPeaks, IChromatogramWSD chromatogram, PeakDetectorSettingsWSD peakDetectorSettings) { + private List extractPeaks(List rawPeaks, IChromatogramWSD chromatogram, PeakDetectorSettingsWSD peakDetectorSettings, IMarkedWavelengths wavelengths) { List peaks = new ArrayList<>(); + Set traces = wavelengths.getWavelengths().stream().map(e -> e.intValue()).collect(Collectors.toSet()); + boolean includeBackground = peakDetectorSettings.isIncludeBackground(); + boolean optimizeBaseline = peakDetectorSettings.isOptimizeBaseline(); // IChromatogramPeakWSD peak = null; IScanRange scanRange = null; @@ -118,13 +210,19 @@ private List extractPeaks(List rawPeaks, IChroma * Build the peak and add it. */ try { + /* + * Optimize the scan range. + */ scanRange = new ScanRange(rawPeak.getStartScan(), rawPeak.getStopScan()); + if(includeBackground && optimizeBaseline) { + scanRange = optimizeBaseline(chromatogram, scanRange.getStartScan(), rawPeak.getMaximumScan(), scanRange.getStopScan(), wavelengths); + } /* * includeBackground * false: BV or VB * true: VV */ - peak = PeakBuilderWSD.createPeak(chromatogram, scanRange, peakDetectorSettings.isIncludeBackground()); + peak = PeakBuilderWSD.createPeak(chromatogram, scanRange, includeBackground, traces, wavelengths.getMode()); if(isValidPeak(peak)) { /* * Add the detector description. @@ -149,38 +247,45 @@ private List extractPeaks(List rawPeaks, IChroma * @param window * @return {@link IFirstDerivativeDetectorSlopes} */ - public static IFirstDerivativeDetectorSlopes getFirstDerivativeSlopes(IChromatogramSelectionWSD chromatogramSelection, int windowSize) { + public static IFirstDerivativeDetectorSlopes getFirstDerivativeSlopes(IChromatogramSelectionWSD chromatogramSelection, int windowSize, IMarkedWavelengths filterWavelengths) { - ITotalScanSignals signals = new TotalScanSignals(chromatogramSelection); - TotalScanSignalsModifier.normalize(signals, NORMALIZATION_BASE); - /* - * Get the start and stop scan of the chromatogram selection. - */ - IFirstDerivativeDetectorSlopes slopes = new FirstDerivativeDetectorSlopes(signals); - /* - * Fill the slope list. - */ - int startScan = signals.getStartScan(); - int stopScan = signals.getStopScan(); - // - for(int scan = startScan; scan < stopScan; scan++) { - ITotalScanSignal s1 = signals.getTotalScanSignal(scan); - ITotalScanSignal s2 = signals.getNextTotalScanSignal(scan); - if(s1 != null && s2 != null) { - IPoint p1 = new Point(s1.getRetentionTime(), s1.getTotalSignal()); - IPoint p2 = new Point(s2.getRetentionTime(), s2.getTotalSignal()); - IFirstDerivativeDetectorSlope slope = new FirstDerivativeDetectorSlope(p1, p2, s1.getRetentionTime()); - slopes.add(slope); + IChromatogramWSD chromatogram = chromatogramSelection.getChromatogram(); + try { + ITotalWavelengthSignalExtractor totalWavelengthSignalExtractor = new TotalWavelengthSignalExtractor(chromatogram); + ITotalScanSignals signals = totalWavelengthSignalExtractor.getTotalWavelengthSignals(chromatogramSelection, filterWavelengths); + TotalScanSignalsModifier.normalize(signals, NORMALIZATION_BASE); + /* + * Get the start and stop scan of the chromatogram selection. + */ + IFirstDerivativeDetectorSlopes slopes = new FirstDerivativeDetectorSlopes(signals); + /* + * Fill the slope list. + */ + int startScan = signals.getStartScan(); + int stopScan = signals.getStopScan(); + // + for(int scan = startScan; scan < stopScan; scan++) { + ITotalScanSignal s1 = signals.getTotalScanSignal(scan); + ITotalScanSignal s2 = signals.getNextTotalScanSignal(scan); + if(s1 != null && s2 != null) { + IPoint p1 = new Point(s1.getRetentionTime(), s1.getTotalSignal()); + IPoint p2 = new Point(s2.getRetentionTime(), s2.getTotalSignal()); + IFirstDerivativeDetectorSlope slope = new FirstDerivativeDetectorSlope(p1, p2, s1.getRetentionTime()); + slopes.add(slope); + } } + /* + * Moving average on the slopes + */ + if(windowSize != 0) { + slopes.calculateMovingAverage(windowSize); + } + // + return slopes; + } catch(ChromatogramIsNullException e) { + logger.warn(e.getLocalizedMessage(), e); + return null; } - /* - * Moving average on the slopes - */ - if(windowSize != 0) { - slopes.calculateMovingAverage(windowSize); - } - // - return slopes; } /** @@ -200,4 +305,72 @@ private boolean isValidPeak(IChromatogramPeakWSD peak) { } return false; } + + protected ScanRange optimizeBaseline(IChromatogramWSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedWavelengths wavelengths) { + + /* + * Right and left baseline optimization + */ + int stopScanOptimized = optimizeRightBaseline(chromatogram, startScan, centerScan, stopScan, wavelengths); + int startScanOptimized = optimizeLeftBaseline(chromatogram, startScan, centerScan, stopScanOptimized, wavelengths); + // + return new ScanRange(startScanOptimized, stopScanOptimized); + } + + protected float getScanSignal(IChromatogramWSD chromatogram, int scanNumber, IMarkedWavelengths wavelengths) { + + IScan scan = chromatogram.getScan(scanNumber); + if(scan instanceof IScanWSD) { + IScanWSD scanWSD = (IScanWSD)scan; + return scanWSD.getTotalSignal(wavelengths); + } else { + return scan.getTotalSignal(); + } + } + + private int optimizeRightBaseline(IChromatogramWSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedWavelengths wavelengths) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, wavelengths)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, wavelengths)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int stopScanOptimized = stopScan; + for(int i = stopScan; i > centerScan; i--) { + float signal = getScanSignal(chromatogram, i, wavelengths); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + stopScanOptimized = i; + } + } + // + return stopScanOptimized; + } + + private int optimizeLeftBaseline(IChromatogramWSD chromatogram, int startScan, int centerScan, int stopScan, IMarkedWavelengths wavelengths) { + + IPoint p1 = new Point(getRetentionTime(chromatogram, startScan), getScanSignal(chromatogram, startScan, wavelengths)); + IPoint p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, wavelengths)); + LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); + /* + * Right border optimization + */ + int startScanOptimized = startScan; + for(int i = startScan; i < centerScan; i++) { + float signal = getScanSignal(chromatogram, i, wavelengths); + int retentionTime = chromatogram.getScan(i).getRetentionTime(); + if(signal < backgroundEquation.calculateY(retentionTime)) { + /* + * Create a new equation + */ + startScanOptimized = i; + p1 = new Point(getRetentionTime(chromatogram, startScanOptimized), getScanSignal(chromatogram, startScanOptimized, wavelengths)); + p2 = new Point(getRetentionTime(chromatogram, stopScan), getScanSignal(chromatogram, stopScan, wavelengths)); + backgroundEquation = Equations.createLinearEquation(p1, p2); + } + } + // + return startScanOptimized; + } } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/FirstDerivativePeakDetectorSettings.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/FirstDerivativePeakDetectorSettings.java index 057e9c6a60..104ccffdca 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/FirstDerivativePeakDetectorSettings.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/FirstDerivativePeakDetectorSettings.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Lablicate GmbH. + * Copyright (c) 2019, 2021 Lablicate GmbH. * * All rights reserved. * This program and the accompanying materials are made available under the @@ -17,7 +17,7 @@ public class FirstDerivativePeakDetectorSettings extends PeakDetectorSettingsMSD public FirstDerivativePeakDetectorSettings() { - this(DataType.MSD); + this(DataType.MSD); // TODO: This is not very generic despite the class name. } public FirstDerivativePeakDetectorSettings(DataType dataType) { diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsCSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsCSD.java index 2f71b87697..b2abdc4b95 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsCSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsCSD.java @@ -40,7 +40,7 @@ public class PeakDetectorSettingsCSD extends AbstractPeakDetectorCSDSettings { @JsonDeserialize(using = WindowSizeDeserializer.class) private int windowSize = 5; @JsonProperty(value = "Use Noise-Segments", defaultValue = "false") - @JsonPropertyDescription(value = "Whether to use Nois-Segments to decide where peaks should be detected, this can improve the sensitivity of the algorithm") + @JsonPropertyDescription(value = "Whether to use noise segments to decide where peaks should be detected. This can improve the sensitivity of the algorithm.") private boolean useNoiseSegments = false; @JsonProperty(value = "Optimize Baseline (VV)", defaultValue = "false") private boolean optimizeBaseline = false; diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsMSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsMSD.java index 73f1553b51..98d4d61606 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsMSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsMSD.java @@ -57,7 +57,7 @@ public class PeakDetectorSettingsMSD extends AbstractPeakDetectorSettingsMSD { @IntSettingsProperty(minValue = PreferenceSupplier.MIN_WINDOW_SIZE, maxValue = PreferenceSupplier.MAX_WINDOW_SIZE, validation = Validation.ODD_NUMBER_INCLUDING_ZERO) private int windowSize = 5; @JsonProperty(value = "Use Noise-Segments", defaultValue = "false") - @JsonPropertyDescription(value = "Whether to use Nois-Segments to decide where peaks should be detected, this can improve the sensitivity of the algorithm") + @JsonPropertyDescription(value = "Whether to use noise segments to decide where peaks should be detected. This can improve the sensitivity of the algorithm.") private boolean useNoiseSegments = false; @JsonProperty(value = "Filter Mode", defaultValue = "EXCLUDE") private FilterMode filterMode = FilterMode.EXCLUDE; diff --git a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsWSD.java b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsWSD.java index cf1edde691..c709c9371a 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsWSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative/src/org/eclipse/chemclipse/chromatogram/xxd/peak/detector/supplier/firstderivative/settings/PeakDetectorSettingsWSD.java @@ -9,9 +9,20 @@ * Contributors: * Dr. Philip Wenig - initial API and implementation * Matthias Mailänder - remove the window size enum + * Matthias Mailänder - add wavelength filters *******************************************************************************/ package org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.settings; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.chemclipse.chromatogram.peak.detector.core.FilterMode; import org.eclipse.chemclipse.chromatogram.peak.detector.model.Threshold; import org.eclipse.chemclipse.chromatogram.wsd.peak.detector.settings.AbstractPeakDetectorWSDSettings; import org.eclipse.chemclipse.chromatogram.xxd.peak.detector.supplier.firstderivative.preferences.PreferenceSupplier; @@ -19,7 +30,13 @@ import org.eclipse.chemclipse.support.settings.IntSettingsProperty; import org.eclipse.chemclipse.support.settings.IntSettingsProperty.Validation; import org.eclipse.chemclipse.support.settings.serialization.WindowSizeDeserializer; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelength; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelength.WavelengthMarkMode; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; +import org.eclipse.chemclipse.wsd.model.core.support.MarkedWavelength; +import org.eclipse.chemclipse.wsd.model.core.support.MarkedWavelengths; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -39,6 +56,18 @@ public class PeakDetectorSettingsWSD extends AbstractPeakDetectorWSDSettings { @IntSettingsProperty(minValue = PreferenceSupplier.MIN_WINDOW_SIZE, maxValue = PreferenceSupplier.MAX_WINDOW_SIZE, validation = Validation.ODD_NUMBER_INCLUDING_ZERO) @JsonDeserialize(using = WindowSizeDeserializer.class) private int windowSize; + @JsonProperty(value = "Use Noise-Segments", defaultValue = "false") + @JsonPropertyDescription(value = "Whether to use noise segments to decide where peaks should be detected. This can improve the sensitivity of the algorithm.") + private boolean useNoiseSegments = false; + @JsonProperty(value = "Filter Mode", defaultValue = "EXCLUDE") + private FilterMode filterMode = FilterMode.EXCLUDE; + @JsonProperty(value = "Wavelengths to filter", defaultValue = "") + private String filterWavelengths; + @JsonProperty(value = "Use Individual Wavelengths", defaultValue = "false") + @JsonPropertyDescription("Uses each wavelength in the filter-list individualy to detect peaks") + private boolean useIndividualWavelengths = false; + @JsonProperty(value = "Optimize Baseline (VV)", defaultValue = "false") + private boolean optimizeBaseline = false; public PeakDetectorSettingsWSD() { @@ -86,4 +115,91 @@ public void setMovingAverageWindowSize(int windowSize) { this.windowSize = windowSize; } + + public boolean isUseNoiseSegments() { + + return useNoiseSegments; + } + + public void setUseNoiseSegments(boolean useNoiseSegments) { + + this.useNoiseSegments = useNoiseSegments; + } + + public FilterMode getFilterMode() { + + return filterMode == null ? FilterMode.EXCLUDE : filterMode; + } + + public void setFilterMode(FilterMode filterMode) { + + this.filterMode = filterMode; + } + + static Collection parseWavelengths(String input) { + + if(StringUtils.isBlank(input)) { + return Collections.emptyList(); + } + List waveLengths = new ArrayList<>(); + String[] split = input.trim().split("[\\s.,;]+"); + for(String s : split) { + try { + waveLengths.add(new BigDecimal(s)); + } catch(NumberFormatException e) { + // invalid or empty string + } + } + return waveLengths; + } + + public boolean isIndividualWavelengths() { + + return useIndividualWavelengths; + } + + public void setUseIndividualTraces(boolean useIndividualWavelengths) { + + this.useIndividualWavelengths = useIndividualWavelengths; + } + + @JsonIgnore + public Collection getFilterWavelengths() { + + WavelengthMarkMode wavelengthMarkMode; + switch(getFilterMode()) { + case EXCLUDE: + wavelengthMarkMode = WavelengthMarkMode.INCLUDE; + break; + case INCLUDE: + wavelengthMarkMode = WavelengthMarkMode.EXCLUDE; + break; + default: + throw new IllegalArgumentException("Unsupported filter mode " + getFilterMode()); + } + Set parsedWavelengths = parseWavelengths(filterWavelengths).stream().map(e -> new MarkedWavelength(e.doubleValue())).collect(Collectors.toSet()); + if(isIndividualWavelengths()) { + List listedWavelengths = new ArrayList<>(); + for(IMarkedWavelength wavelength : parsedWavelengths) { + IMarkedWavelengths markedWavelengths = new MarkedWavelengths(wavelengthMarkMode); + markedWavelengths.add(wavelength); + listedWavelengths.add(markedWavelengths); + } + return listedWavelengths; + } else { + IMarkedWavelengths markedWavelengths = new MarkedWavelengths(wavelengthMarkMode); + markedWavelengths.addAll(parsedWavelengths); + return Collections.singleton(markedWavelengths); + } + } + + public boolean isOptimizeBaseline() { + + return optimizeBaseline; + } + + public void setOptimizeBaseline(boolean optimizeBaseline) { + + this.optimizeBaseline = optimizeBaseline; + } } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/AbstractMarkedIons.java b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/AbstractMarkedIons.java index 06cf79bc79..f9d44c2fed 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/AbstractMarkedIons.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/AbstractMarkedIons.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2019 Lablicate GmbH. + * Copyright (c) 2010, 2021 Lablicate GmbH. * * All rights reserved. This * program and the accompanying materials are made available under the terms of @@ -31,7 +31,8 @@ public abstract class AbstractMarkedIons implements IMarkedIons { * @param ions */ protected AbstractMarkedIons(int[] ionsList) { - markedIons = new HashSet(); + + markedIons = new HashSet<>(); if(ionsList != null) { for(int ion : ionsList) { markedIons.add(new MarkedIon(ion)); @@ -41,8 +42,7 @@ protected AbstractMarkedIons(int[] ionsList) { protected AbstractMarkedIons(Collection ionsList) { - - markedIons = new HashSet(); + markedIons = new HashSet<>(); if(ionsList != null) { for(Number ion : ionsList) { markedIons.add(new MarkedIon(ion.intValue())); diff --git a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/PeakBuilderMSD.java b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/PeakBuilderMSD.java index 09be0888cb..642216f6e3 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/PeakBuilderMSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/core/support/PeakBuilderMSD.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2020 Lablicate GmbH. + * Copyright (c) 2008, 2021 Lablicate GmbH. * * All rights reserved. * This program and the accompanying materials are made available under the @@ -114,8 +114,7 @@ public static IChromatogramPeakMSD createPeak(IChromatogramMSD chromatogram, ISc * Create the peak. */ IPeakModelMSD peakModel = new PeakModelMSD(peakMassSpectrum, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); - IChromatogramPeakMSD peak = new ChromatogramPeakMSD(peakModel, chromatogram); - return peak; + return new ChromatogramPeakMSD(peakModel, chromatogram); } public static IChromatogramPeakMSD createPeak(IChromatogramMSD chromatogram, IScanRange scanRange, float startIntensity, float stopIntensity, Set includedIons, IonMarkMode filterMode) throws PeakException { diff --git a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/xic/TotalIonSignalExtractor.java b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/xic/TotalIonSignalExtractor.java index 4e94e9a6f6..06a09231da 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/xic/TotalIonSignalExtractor.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.msd.model/src/org/eclipse/chemclipse/msd/model/xic/TotalIonSignalExtractor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2019 Lablicate GmbH. + * Copyright (c) 2012, 2021 Lablicate GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -29,6 +29,7 @@ public class TotalIonSignalExtractor extends TotalScanSignalExtractor implements private IChromatogramMSD chromatogram; public TotalIonSignalExtractor(IChromatogramMSD chromatogram) throws ChromatogramIsNullException { + super(chromatogram); this.chromatogram = chromatogram; } @@ -70,9 +71,7 @@ public ITotalScanSignals getTotalIonSignals(IChromatogramSelectionMSD chromatogr * If excludedMassFragements is null the the total ion list will be * returned. */ - ITotalScanSignals signals; - signals = initializeTotalIonSignals(startScan, stopScan, excludedIons); - return signals; + return initializeTotalIonSignals(startScan, stopScan, excludedIons); } @Override @@ -90,8 +89,7 @@ public ITotalScanSignals getTotalIonSignals(IChromatogramSelectionMSD chromatogr */ int startScan = chromatogram.getScanNumber(chromatogramSelection.getStartRetentionTime()); int stopScan = chromatogram.getScanNumber(chromatogramSelection.getStopRetentionTime()); - ITotalScanSignals signals = initializeTotalIonSignals(startScan, stopScan, null); - return signals; + return initializeTotalIonSignals(startScan, stopScan, null); } @Override @@ -113,7 +111,9 @@ public ITotalScanSignals getTotalIonSignals(IMarkedIons excludedIons) { */ private ITotalScanSignals initializeTotalIonSignals(int startScan, int stopScan, IMarkedIons excludedIons) { - assert (startScan <= stopScan) : "The startScan must be lower or equal the stop scan."; + if(startScan > stopScan) { + throw new IllegalArgumentException("The start scan " + startScan + " must be lower or equal the stop scan " + stopScan + "."); + } /* * Validate the scan borders. */ @@ -125,7 +125,6 @@ private ITotalScanSignals initializeTotalIonSignals(int startScan, int stopScan, */ ITotalScanSignal totalIonSignal; ITotalScanSignals signals = new TotalScanSignals(startScan, stopScan, chromatogram); - /* * Add the selected scans. */ diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/AbstractScanWSD.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/AbstractScanWSD.java index 1881b56e9b..0f48c4fb46 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/AbstractScanWSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/AbstractScanWSD.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.Set; @@ -22,6 +23,7 @@ import org.eclipse.chemclipse.wsd.model.comparator.WavelengthCombinedComparator; import org.eclipse.chemclipse.wsd.model.comparator.WavelengthComparatorMode; import org.eclipse.chemclipse.wsd.model.core.implementation.ScanSignalWSD; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; import org.eclipse.chemclipse.wsd.model.xwc.ExtractedSingleWavelengthSignal; import org.eclipse.chemclipse.wsd.model.xwc.ExtractedWavelengthSignal; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedSingleWavelengthSignal; @@ -135,6 +137,40 @@ public float getTotalSignal() { return totalSignal; } + @Override + public float getTotalSignal(IMarkedWavelengths markedWavelengths) { + + float totalSignal = 0; + /* + * If the excluded ions are null, return the total signal. + */ + if(markedWavelengths == null || markedWavelengths.isEmpty()) { + totalSignal = getTotalSignal(); + } else { + Iterator iterator = scanSignals.iterator(); + while(iterator.hasNext()) { + IScanSignalWSD scan = iterator.next(); + if(useWavelength(scan, markedWavelengths)) { + totalSignal += scan.getAbundance(); + } + } + } + return totalSignal; + } + + private static boolean useWavelength(IScanSignalWSD scan, IMarkedWavelengths filterWavelengths) { + + Set wavelengths = filterWavelengths.getWavelengths(); + switch(filterWavelengths.getMode()) { + case EXCLUDE: + return wavelengths.contains(scan.getWavelength()); + case INCLUDE: + return !wavelengths.contains(scan.getWavelength()); + default: + return true; + } + } + @Override public void adjustTotalSignal(float totalSignal) { diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/IScanWSD.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/IScanWSD.java index 089938abc7..277afcc5b6 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/IScanWSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/IScanWSD.java @@ -8,6 +8,7 @@ * * Contributors: * Dr. Philip Wenig - initial API and implementation + * Matthias Mailänder - add total signal except excluded *******************************************************************************/ package org.eclipse.chemclipse.wsd.model.core; @@ -16,6 +17,7 @@ import java.util.Set; import org.eclipse.chemclipse.model.core.IScan; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedSingleWavelengthSignal; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedWavelengthSignal; @@ -47,11 +49,17 @@ public interface IScanWSD extends IScan { IExtractedWavelengthSignal getExtractedWavelengthSignal(); - IExtractedWavelengthSignal getExtractedWavelengthSignal(double startIon, double stopIon); + IExtractedWavelengthSignal getExtractedWavelengthSignal(double startWavelength, double stopWavelength); Optional getExtractedSingleWavelengthSignal(double wavelength); boolean hasScanSignals(); IWavelengthBounds getWavelengthBounds(); + + /** + * + * @return total intensity count (TIC) excepted excluded wavelengths + */ + float getTotalSignal(IMarkedWavelengths excludedWavelenths); } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/AbstractMarkedWavelengths.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/AbstractMarkedWavelengths.java index 6dfa23ccf1..735f44d846 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/AbstractMarkedWavelengths.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/AbstractMarkedWavelengths.java @@ -16,13 +16,23 @@ import java.util.Iterator; import java.util.Set; -public class AbstractMarkedWavelengths implements IMarkedWavelengths { +public abstract class AbstractMarkedWavelengths implements IMarkedWavelengths { private Set markedWavelengths; public AbstractMarkedWavelengths() { - markedWavelengths = new HashSet(); + markedWavelengths = new HashSet<>(); + } + + protected AbstractMarkedWavelengths(Collection wavelengths) { + + markedWavelengths = new HashSet<>(); + if(wavelengths != null) { + for(Number wavelength : wavelengths) { + markedWavelengths.add(new MarkedWavelength(wavelength.intValue())); + } + } } @Override @@ -106,7 +116,7 @@ public T[] toArray(T[] a) { @Override public Set getWavelengths() { - Set wavelengths = new HashSet(); + Set wavelengths = new HashSet<>(); for(IMarkedWavelength markedWavelength : markedWavelengths) { wavelengths.add(markedWavelength.getWavelength()); } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelength.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelength.java index 861f2d6b67..032aed9db1 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelength.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelength.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Lablicate GmbH. + * Copyright (c) 2016, 2021 Lablicate GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -12,9 +12,40 @@ package org.eclipse.chemclipse.wsd.model.core.support; import org.eclipse.chemclipse.model.core.IMarkedSignal; +import org.eclipse.chemclipse.support.text.ILabel; public interface IMarkedWavelength extends IMarkedSignal { + enum WavelengthMarkMode implements ILabel { + + /** + * In this mode, all wavelengths in the list are considered as an exclusion, that means apply the given function to all except the given wavelengths + */ + EXCLUDE("Exclude"), + /** + * In this mode, all wavelengths in the list are considered as an inclusion, that means apply the given function to all wavelengths given + */ + INCLUDE("Include"); + + private String label = ""; + + private WavelengthMarkMode(String label) { + + this.label = label; + } + + @Override + public String label() { + + return label; + } + + public static String[][] getOptions() { + + return ILabel.getOptions(values()); + } + } + double getWavelength(); void setWavelength(double wavelength); diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelengths.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelengths.java index 6bddb6d3d5..e3f1abb29f 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelengths.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/IMarkedWavelengths.java @@ -15,6 +15,7 @@ import java.util.Set; import org.eclipse.chemclipse.model.core.IMarkedSignals; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelength.WavelengthMarkMode; public interface IMarkedWavelengths extends IMarkedSignals { @@ -43,4 +44,6 @@ public interface IMarkedWavelengths extends IMarkedSignals { */ @Deprecated void add(int wavelengthStart, int wavelengthStop); + + WavelengthMarkMode getMode(); } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/MarkedWavelengths.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/MarkedWavelengths.java index 46d9d26c3d..f9677dde63 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/MarkedWavelengths.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/MarkedWavelengths.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Lablicate GmbH. + * Copyright (c) 2016, 2021 Lablicate GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,8 +8,36 @@ * * Contributors: * Dr. Philip Wenig - initial API and implementation + * Matthias Mailänder - add inclusive/exclusive mode *******************************************************************************/ package org.eclipse.chemclipse.wsd.model.core.support; +import java.util.Collection; + +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelength.WavelengthMarkMode; + public class MarkedWavelengths extends AbstractMarkedWavelengths implements IMarkedWavelengths { + + private WavelengthMarkMode mode; + + public MarkedWavelengths() { + + } + + public MarkedWavelengths(WavelengthMarkMode mode) { + + this.mode = mode; + } + + public MarkedWavelengths(Collection wavelengths, WavelengthMarkMode mode) { + + super(wavelengths); + this.mode = mode; + } + + @Override + public WavelengthMarkMode getMode() { + + return mode; + } } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/PeakBuilderWSD.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/PeakBuilderWSD.java index 3ddb085531..fd08721726 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/PeakBuilderWSD.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/core/support/PeakBuilderWSD.java @@ -40,13 +40,21 @@ import org.eclipse.chemclipse.wsd.model.core.implementation.PeakModelWSD; import org.eclipse.chemclipse.wsd.model.core.implementation.ScanSignalWSD; import org.eclipse.chemclipse.wsd.model.core.implementation.ScanWSD; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelength.WavelengthMarkMode; import org.eclipse.chemclipse.wsd.model.xwc.ExtractedWavelengthSignalExtractor; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedWavelengthSignal; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedWavelengthSignalExtractor; import org.eclipse.chemclipse.wsd.model.xwc.IExtractedWavelengthSignals; +import org.eclipse.chemclipse.wsd.model.xwc.ITotalWavelengthSignalExtractor; +import org.eclipse.chemclipse.wsd.model.xwc.TotalWavelengthSignalExtractor; public class PeakBuilderWSD { + private PeakBuilderWSD() { + + throw new IllegalStateException("This utility class is meant to only host static functions."); + } + public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, IScanRange scanRange, boolean calculatePeakIncludedBackground) throws PeakException { /* @@ -98,39 +106,69 @@ public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, ISc */ IScanWSD peakScanWSD = getPeakScan(chromatogram, totalScanSignals, backgroundEquation); IPeakModelWSD peakModel = new PeakModelWSD(peakScanWSD, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); - IChromatogramPeakWSD peak = new ChromatogramPeakWSD(peakModel, chromatogram); - return peak; + return new ChromatogramPeakWSD(peakModel, chromatogram); + } + + public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, IScanRange scanRange, boolean calculatePeakIncludedBackground, Set includedWavelengths, WavelengthMarkMode filterMode) throws PeakException { + + /* + * Get the total signals and determine the start and stop background + * abundance. + */ + ITotalScanSignals totalWavelengthSignals = getTotalIonSignals(chromatogram, scanRange, new MarkedWavelengths(includedWavelengths, filterMode)); + /* + * Retrieve the start and stop signals of the peak to calculate its + * chromatogram and eventually peak internal background, if the start + * abundance is higher than the stop abundance or vice versa. + */ + ITotalScanSignal totalWavelengthSignal = totalWavelengthSignals.getTotalScanSignal(scanRange.getStartScan()); + float startBackgroundAbundance = totalWavelengthSignal.getTotalSignal(); + totalWavelengthSignal = totalWavelengthSignals.getTotalScanSignal(scanRange.getStopScan()); + float stopBackgroundAbundance = totalWavelengthSignal.getTotalSignal(); + /* + * The abundance of base or startBackground/stopBackground (depends + * which is the lower value) is the chromatogram background.
Then a + * peak included background could be calculated or not.
This + * background is not the background of the chromatogram. It's the + * background of the peak.
Think of, a peak could be skewed, means + * it starts with an abundance of zero and stops with a higher + * abundance.
To include or exclude the background abundance in the + * IPeakModel affects the calculation of its width at different heights. + */ + IBackgroundAbundanceRange backgroundAbundanceRange; + if(calculatePeakIncludedBackground) { + backgroundAbundanceRange = new BackgroundAbundanceRange(startBackgroundAbundance, stopBackgroundAbundance); + } else { + float base = Math.min(startBackgroundAbundance, stopBackgroundAbundance); + backgroundAbundanceRange = new BackgroundAbundanceRange(base, base); + } + LinearEquation backgroundEquation = getBackgroundEquation(totalWavelengthSignals, scanRange, backgroundAbundanceRange); + /* + * Calculate the intensity values. + */ + ITotalScanSignals peakIntensityTotalIonSignals = adjustTotalScanSignals(totalWavelengthSignals, backgroundEquation); + IPeakIntensityValues peakIntensityValues = getPeakIntensityValues(peakIntensityTotalIonSignals); + IScanWSD peakScan = getPeakScan(chromatogram, peakIntensityTotalIonSignals, backgroundEquation); + /* + * Create the peak. + */ + IPeakModelWSD peakModel = new PeakModelWSD(peakScan, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); + return new ChromatogramPeakWSD(peakModel, chromatogram); } - public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, IScanRange scanRange, boolean calculatePeakIncludedBackground, Set traces) throws PeakException { + private static ITotalScanSignals getTotalIonSignals(IChromatogramWSD chromatogram, IScanRange scanRange, MarkedWavelengths excludedWavelengths) { + if(chromatogram == null || scanRange == null || excludedWavelengths == null) { + throw new PeakException("The given values must not be null."); + } + /* + * Try to get the signals. + */ try { - IExtractedWavelengthSignals extractedWavelengthSignals = getExtractedWavelengthSignals(chromatogram, scanRange, traces); - IExtractedWavelengthSignal extractedWavelengthSignalStart = extractedWavelengthSignals.getExtractedWavelengthSignal(scanRange.getStartScan()); - float startBackgroundAbundance = extractedWavelengthSignalStart.getTotalSignal(); - IExtractedWavelengthSignal extractedWavelengthSignalStop = extractedWavelengthSignals.getExtractedWavelengthSignal(scanRange.getStopScan()); - float stopBackgroundAbundance = extractedWavelengthSignalStop.getTotalSignal(); - /* - * The abundance of base or startBackground/stopBackground (depends - * which is the lower value) is the chromatogram background.
Then a - * peak included background could be calculated or not.
This - * background is not the background of the chromatogram. It's the - * background of the peak.
Think of, a peak could be skewed, means - * it starts with an abundance of zero and stops with a higher - * abundance.
To include or exclude the background abundance in the - * IPeakModel affects the calculation of its width at different heights. - */ - IBackgroundAbundanceRange backgroundAbundanceRange; - if(calculatePeakIncludedBackground) { - backgroundAbundanceRange = new BackgroundAbundanceRange(startBackgroundAbundance, stopBackgroundAbundance); - } else { - float base = Math.min(startBackgroundAbundance, stopBackgroundAbundance); - backgroundAbundanceRange = new BackgroundAbundanceRange(base, base); - } - // - return createPeak(chromatogram, scanRange, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance(), traces); - } catch(Exception e) { - throw new PeakException(); + ITotalWavelengthSignalExtractor totalWavelengthSignalExtractor = new TotalWavelengthSignalExtractor(chromatogram); + return totalWavelengthSignalExtractor.getTotalScanSignals(scanRange.getStartScan(), scanRange.getStopScan(), excludedWavelengths); + } catch(ChromatogramIsNullException e) { + throw new PeakException("The chromatogram must not be null."); } } @@ -185,8 +223,7 @@ public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, ISc double adjustedTotalSignal = peakScanWSD.getTotalSignal() - backgroundEquation.calculateY(retentionTime); peakScanWSD.adjustTotalSignal((float)adjustedTotalSignal); IPeakModelWSD peakModel = new PeakModelWSD(peakScanWSD, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); - IChromatogramPeakWSD peak = new ChromatogramPeakWSD(peakModel, chromatogram); - return peak; + return new ChromatogramPeakWSD(peakModel, chromatogram); } else { throw new PeakException(); } @@ -213,8 +250,7 @@ public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, ISc */ IScanWSD peakScanWSD = getPeakScan(chromatogram, totalScanSignals, backgroundEquation); IPeakModelWSD peakModel = new PeakModelWSD(peakScanWSD, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); - IChromatogramPeakWSD peak = new ChromatogramPeakWSD(peakModel, chromatogram); - return peak; + return new ChromatogramPeakWSD(peakModel, chromatogram); } public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, IScanRange scanRange, IBackgroundAbundanceRange backgroundAbundanceRange, boolean checkBackgroundAbundanceRange) throws PeakException { @@ -237,8 +273,7 @@ public static IChromatogramPeakWSD createPeak(IChromatogramWSD chromatogram, ISc */ IScanWSD peakScanWSD = getPeakScan(chromatogram, totalScanSignals, backgroundEquation); IPeakModelWSD peakModel = new PeakModelWSD(peakScanWSD, peakIntensityValues, backgroundAbundanceRange.getStartBackgroundAbundance(), backgroundAbundanceRange.getStopBackgroundAbundance()); - IChromatogramPeakWSD peak = new ChromatogramPeakWSD(peakModel, chromatogram); - return peak; + return new ChromatogramPeakWSD(peakModel, chromatogram); } protected static void validateChromatogram(IChromatogramWSD chromatogram) throws PeakException { @@ -257,8 +292,6 @@ protected static void validateScanRange(IScanRange scanRange) throws PeakExcepti protected static void checkScanRange(IChromatogramWSD chromatogram, IScanRange scanRange) throws PeakException { - assert (chromatogram != null) : "The chromatogram must not be null."; - assert (scanRange != null) : "The scan range must not be null."; if(chromatogram == null || scanRange == null) { throw new PeakException("The given chromatogram or scanRange must not be null."); } @@ -272,8 +305,6 @@ protected static void checkScanRange(IChromatogramWSD chromatogram, IScanRange s protected static ITotalScanSignals getTotalScanSignals(IChromatogramWSD chromatogram, IScanRange scanRange) throws PeakException { - assert (chromatogram != null) : "The chromatogram must not be null."; - assert (scanRange != null) : "The scan range must not be null."; if(chromatogram == null || scanRange == null) { throw new PeakException("The given values must not be null."); } @@ -311,8 +342,6 @@ protected static IExtractedWavelengthSignals getExtractedWavelengthSignals(IChro protected static IExtractedWavelengthSignals getExtractedWavelengthSignals(IChromatogramWSD chromatogram, IScanRange scanRange) throws PeakException { - assert (chromatogram != null) : "The chromatogram must not be null."; - assert (scanRange != null) : "The scan range must not be null."; if(chromatogram == null || scanRange == null) { throw new PeakException("The given values must not be null."); } @@ -329,9 +358,6 @@ protected static IExtractedWavelengthSignals getExtractedWavelengthSignals(IChro protected static LinearEquation getBackgroundEquation(ITotalScanSignals totalScanSignals, IScanRange scanRange, IBackgroundAbundanceRange backgroundAbundanceRange) throws PeakException { - assert (totalScanSignals != null) : "The total signals must not be null."; - assert (scanRange != null) : "The scan range must not be null."; - assert (backgroundAbundanceRange != null) : "The background abundance range must not be null."; if(totalScanSignals == null || scanRange == null || backgroundAbundanceRange == null) { throw new PeakException("The given totalIonSignals, scanRange or backgroundAbundanceRange must not be null."); } @@ -345,16 +371,11 @@ protected static LinearEquation getBackgroundEquation(ITotalScanSignals totalSca /* * Create the background abundance equation. */ - LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); - return backgroundEquation; + return Equations.createLinearEquation(p1, p2); } protected static LinearEquation getBackgroundEquation(IExtractedWavelengthSignals extractedWavelengthSignals, IScanRange scanRange, IBackgroundAbundanceRange backgroundAbundanceRange) throws Exception { - assert (extractedWavelengthSignals != null) : "The extracted wavelength signals must not be null."; - assert (scanRange != null) : "The scan range must not be null."; - assert (backgroundAbundanceRange != null) : "The background abundance range must not be null."; - // if(extractedWavelengthSignals == null || scanRange == null || backgroundAbundanceRange == null) { throw new PeakException("The given signals, scanRange or backgroundAbundanceRange must not be null."); } @@ -369,14 +390,11 @@ protected static LinearEquation getBackgroundEquation(IExtractedWavelengthSignal /* * Create the background abundance equation. */ - LinearEquation backgroundEquation = Equations.createLinearEquation(p1, p2); - return backgroundEquation; + return Equations.createLinearEquation(p1, p2); } protected static ITotalScanSignals adjustTotalScanSignals(ITotalScanSignals totalScanSignals, LinearEquation backgroundEquation) throws PeakException { - assert (totalScanSignals != null) : "The total ion signals must not be null."; - assert (backgroundEquation != null) : "The background equation must not be null."; if(totalScanSignals == null || backgroundEquation == null) { throw new PeakException("The given totalIonSignals or backgroundEquation must not be null."); } @@ -406,8 +424,6 @@ protected static ITotalScanSignals adjustTotalScanSignals(ITotalScanSignals tota protected static ITotalScanSignals adjustTotalScanSignals(IExtractedWavelengthSignals extractedWavelengthSignals, LinearEquation backgroundEquation) throws Exception { - assert (extractedWavelengthSignals != null) : "The wavelength signals must not be null."; - assert (backgroundEquation != null) : "The background equation must not be null."; if(extractedWavelengthSignals == null || backgroundEquation == null) { throw new PeakException("The given wavelength signals or backgroundEquation must not be null."); } @@ -440,7 +456,6 @@ protected static ITotalScanSignals adjustTotalScanSignals(IExtractedWavelengthSi protected static IPeakIntensityValues getPeakIntensityValues(ITotalScanSignals peakIntensityTotalIonSignals) throws PeakException { - assert (peakIntensityTotalIonSignals != null) : "The peak intensity total ion signals must not be null."; if(peakIntensityTotalIonSignals == null) { throw new PeakException("The peakIntensityTotalIonSignals must not be null."); } @@ -492,8 +507,6 @@ protected static void validateBackgroundAbundanceRange(IBackgroundAbundanceRange protected static IBackgroundAbundanceRange checkBackgroundAbundanceRange(ITotalScanSignals totalScanSignals, IScanRange scanRange, IBackgroundAbundanceRange backgroundAbundanceRange) throws PeakException { ITotalScanSignal totalScanSignal; - float background = 0.0f; - float signal = 0.0f; float startBackgroundAbundance = 0.0f; float stopBackgroundAbundance = 0.0f; boolean adjustBackgroundAbundance = false; @@ -505,8 +518,8 @@ protected static IBackgroundAbundanceRange checkBackgroundAbundanceRange(ITotalS */ totalScanSignal = totalScanSignals.getTotalScanSignal(scanRange.getStartScan()); if(totalScanSignal != null) { - background = backgroundAbundanceRange.getStartBackgroundAbundance(); - signal = totalScanSignal.getTotalSignal(); + float background = backgroundAbundanceRange.getStartBackgroundAbundance(); + float signal = totalScanSignal.getTotalSignal(); if(background <= signal) { startBackgroundAbundance = background; } else { @@ -521,8 +534,8 @@ protected static IBackgroundAbundanceRange checkBackgroundAbundanceRange(ITotalS */ totalScanSignal = totalScanSignals.getTotalScanSignal(scanRange.getStopScan()); if(totalScanSignal != null) { - background = backgroundAbundanceRange.getStopBackgroundAbundance(); - signal = totalScanSignal.getTotalSignal(); + float background = backgroundAbundanceRange.getStopBackgroundAbundance(); + float signal = totalScanSignal.getTotalSignal(); if(background <= signal) { stopBackgroundAbundance = background; } else { diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/ITotalWavelengthSignalExtractor.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/ITotalWavelengthSignalExtractor.java index e53ace92f3..8fb83ca5ee 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/ITotalWavelengthSignalExtractor.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/ITotalWavelengthSignalExtractor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Lablicate GmbH. + * Copyright (c) 2017, 2021 Lablicate GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -14,16 +14,14 @@ import org.eclipse.chemclipse.model.signals.ITotalScanSignalExtractor; import org.eclipse.chemclipse.model.signals.ITotalScanSignals; import org.eclipse.chemclipse.wsd.model.core.selection.IChromatogramSelectionWSD; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; +import org.eclipse.chemclipse.wsd.model.core.support.MarkedWavelengths; -/** - * @deprecated Use {@link IExtractedSingleWavelengthSignalExtractor} instead - * - * @see {@link ISingleWavelengthSignals} - * @see {@link ISingleWavelengthSignal} - * - */ -@Deprecated public interface ITotalWavelengthSignalExtractor extends ITotalScanSignalExtractor { ITotalScanSignals getTotalWavelengthSignals(IChromatogramSelectionWSD chromatogramSelection); + + ITotalScanSignals getTotalWavelengthSignals(IChromatogramSelectionWSD chromatogramSelection, IMarkedWavelengths excludedWavelengths); + + ITotalScanSignals getTotalScanSignals(int startScan, int stopScan, MarkedWavelengths excludedWavelengths); } diff --git a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/TotalWavelengthSignalExtractor.java b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/TotalWavelengthSignalExtractor.java index 4ca37118a8..d51683b2bb 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/TotalWavelengthSignalExtractor.java +++ b/chemclipse/plugins/org.eclipse.chemclipse.wsd.model/src/org/eclipse/chemclipse/wsd/model/xwc/TotalWavelengthSignalExtractor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Lablicate GmbH. + * Copyright (c) 2017, 2021 Lablicate GmbH. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,6 +8,7 @@ * * Contributors: * Dr. Philip Wenig - initial API and implementation + * Matthias Mailänder - add support for excluded wavelengths *******************************************************************************/ package org.eclipse.chemclipse.wsd.model.xwc; @@ -20,20 +21,15 @@ import org.eclipse.chemclipse.wsd.model.core.IChromatogramWSD; import org.eclipse.chemclipse.wsd.model.core.IScanWSD; import org.eclipse.chemclipse.wsd.model.core.selection.IChromatogramSelectionWSD; +import org.eclipse.chemclipse.wsd.model.core.support.IMarkedWavelengths; +import org.eclipse.chemclipse.wsd.model.core.support.MarkedWavelengths; -/** - * @deprecated Use {@link ExtractedSingleWavelengthSignalExtractor} instead - * - * @see {@link IExtractedSingleWavelengthSignals} - * @see {@link IExtractedSingleWavelengthSignal} - * - */ -@Deprecated public class TotalWavelengthSignalExtractor extends TotalScanSignalExtractor implements ITotalWavelengthSignalExtractor { private IChromatogramWSD chromatogram; public TotalWavelengthSignalExtractor(IChromatogramWSD chromatogram) throws ChromatogramIsNullException { + super(chromatogram); this.chromatogram = chromatogram; } @@ -49,26 +45,75 @@ public ITotalScanSignals getTotalWavelengthSignals(IChromatogramSelectionWSD chr */ int startScan = chromatogram.getScanNumber(chromatogramSelection.getStartRetentionTime()); int stopScan = chromatogram.getScanNumber(chromatogramSelection.getStopRetentionTime()); - ITotalScanSignals signals = initializeTotalWavelenghtSignals(startScan, stopScan); - return signals; + return initializeTotalWavelengthSignals(startScan, stopScan, null); } - private ITotalScanSignals initializeTotalWavelenghtSignals(int startScan, int stopScan) { + private ITotalScanSignals initializeTotalWavelengthSignals(int startScan, int stopScan, IMarkedWavelengths excludedWavelengths) { - assert (startScan <= stopScan) : "The startScan must be lower or equal the stop scan."; + if(startScan > stopScan) { + throw new IllegalArgumentException("The start scan " + startScan + " must be lower or equal the stop scan " + stopScan + "."); + } /* * Validate the scan borders. */ if(startScan < 1 || startScan > chromatogram.getNumberOfScans() || stopScan < 1 || stopScan > chromatogram.getNumberOfScans()) { return new TotalScanSignals(0, chromatogram); } + /* + * Create the total ion signals object. + */ + ITotalScanSignals signals = new TotalScanSignals(startScan, stopScan, chromatogram); /* * Add the selected scans. */ + for(int scan = startScan; scan <= stopScan; scan++) { + IScanWSD scanWSD = chromatogram.getSupplierScan(scan); + ITotalScanSignal totalWavelengthSignal = new TotalScanSignal(scanWSD.getRetentionTime(), scanWSD.getRetentionIndex(), scanWSD.getTotalSignal(excludedWavelengths)); + signals.add(totalWavelengthSignal); + } + return signals; + } + + @Override + public ITotalScanSignals getTotalWavelengthSignals(IChromatogramSelectionWSD chromatogramSelection, IMarkedWavelengths excludedWavelengths) { + + if(chromatogramSelection == null || chromatogramSelection.getChromatogram() != chromatogram) { + return new TotalScanSignals(0, chromatogram); + } + /* + * Get the start and stop scan. + */ + int startScan = chromatogram.getScanNumber(chromatogramSelection.getStartRetentionTime()); + int stopScan = chromatogram.getScanNumber(chromatogramSelection.getStopRetentionTime()); + /* + * If excludedMassFragements is null the the total ion list will be + * returned. + */ + return initializeTotalWavelengthSignals(startScan, stopScan, excludedWavelengths); + } + + @Override + public ITotalScanSignals getTotalScanSignals(int startScan, int stopScan, MarkedWavelengths excludedWavelengths) { + + if(startScan > stopScan) { + throw new IllegalArgumentException("The start scan " + startScan + " must be lower or equal the stop scan " + stopScan + "."); + } + /* + * Validate the scan borders. + */ + if(startScan < 1 || startScan > chromatogram.getNumberOfScans() || stopScan < 1 || stopScan > chromatogram.getNumberOfScans()) { + return new TotalScanSignals(0, chromatogram); + } + /* + * Create the total ion signals object. + */ ITotalScanSignals signals = new TotalScanSignals(startScan, stopScan, chromatogram); + /* + * Add the selected scans. + */ for(int scan = startScan; scan <= stopScan; scan++) { IScanWSD scanWSD = chromatogram.getSupplierScan(scan); - ITotalScanSignal totalWavelengthSignal = new TotalScanSignal(scanWSD.getRetentionTime(), scanWSD.getRetentionIndex(), scanWSD.getTotalSignal()); + ITotalScanSignal totalWavelengthSignal = new TotalScanSignal(scanWSD.getRetentionTime(), scanWSD.getRetentionIndex(), scanWSD.getTotalSignal(excludedWavelengths)); signals.add(totalWavelengthSignal); } return signals;