/* * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fhcrc.cpl.viewer.feature; import org.apache.log4j.Logger; import org.fhcrc.cpl.toolbox.proteomics.MSRun; import org.fhcrc.cpl.toolbox.datastructure.FloatRange; import org.fhcrc.cpl.toolbox.ApplicationContext; import org.fhcrc.cpl.toolbox.proteomics.Scan; import org.fhcrc.cpl.toolbox.proteomics.feature.Spectrum; import org.fhcrc.cpl.toolbox.proteomics.feature.Feature; import org.fhcrc.cpl.toolbox.proteomics.feature.FeatureSet; import java.lang.reflect.Constructor; import java.util.*; /** * User: mbellew * Date: Sep 7, 2004 * Time: 12:08:54 PM */ public abstract class FeatureExtractor { static Logger _log = Logger.getLogger(FeatureExtractor.class); public static final String DEFAULT_EXTRACTOR_PROPERTYNAME = FeatureExtractor.class + ".defaultExtractor"; public static final int TYPE_1D = 1; // process scans one at a time, cross scan features need to be combined public static final int TYPE_2D = 2; // returns individual features in a window protected MSRun _run; protected int _maxCharge; protected FloatRange _mzRange; protected double _sn; protected StatusListener _status = null; protected int _startScan; protected int _scanCount; protected int _dumpWindowSize = 0; // size of the intensity window to grab around each feature int _accurateMassAdjustmentScans = 0; // Number of scans around a feature to consider for accurate mass adjustment static { setDefault(org.fhcrc.cpl.viewer.feature.extraction.strategy.FeatureStrategyPeakClusters.class); } public interface StatusListener { void progress(float percent); } public static void setDefault(Class c) { ApplicationContext.setProperty(DEFAULT_EXTRACTOR_PROPERTYNAME, c); } public static Class getDefaultClass() { Class defaultClass = (Class) ApplicationContext.getProperty(DEFAULT_EXTRACTOR_PROPERTYNAME); return defaultClass; } /** * Instantiate the default FeatureExtractor * @param run * @param scan * @param count * @param maxCharge * @param range * @param sn * @return */ public static FeatureExtractor getDefault(MSRun run, int scan, int count, int maxCharge, FloatRange range, double sn) { Class c = getDefaultClass(); try { Constructor cons = c.getConstructor( MSRun.class, Integer.TYPE, Integer.TYPE, Integer.TYPE, FloatRange.class, Double.TYPE ); return (FeatureExtractor)cons.newInstance( run, new Integer(scan), new Integer(count), new Integer(maxCharge), range, new Double(sn) ); } catch (Exception x) { x.printStackTrace(); System.exit(1); return null; // make compiler happy } } /** * Return the mz range for the given scan. If computed lowMz and highMz were * supplied, use those; otherwise try startMz and endMz. */ public static FloatRange getMzExtractionRange(MSRun.MSScan scan) { if (scan.getLowMz() >= 0 && scan.getHighMz() >= 0) return new FloatRange(scan.getLowMz() - 1, scan.getHighMz() + 1); return new FloatRange(scan.getStartMz() - 1, scan.getEndMz() + 1); } /** * Return the mz range for the given run. First, check scan zero. * If range is no good, use the mzRange computed when the run was * read. */ public static FloatRange getMzExtractionRange(MSRun run) { FloatRange range = getMzExtractionRange(run.getScan(0)); if (range.min >= 0 && range.max >= 0) return range; return new FloatRange(run.getMzRange().min - 1, run.getMzRange().max + 1); } protected FeatureExtractor(MSRun run, int startScan, int scanCount, int maxCharge, FloatRange mzRange, double sn) { assert(mzRange.min < mzRange.max); _run = run; _startScan = startScan; _scanCount = scanCount; _maxCharge = maxCharge; _mzRange = mzRange; _sn = sn; } public void setStatusListener(StatusListener status) { _status = status; } public void setDumpWindowSize(int dumpWindowSize) { _dumpWindowSize = dumpWindowSize; } protected int getDumpWindowSize() { return _dumpWindowSize; } public void setAccurateMassAdjustmentScans(int accurateMassAdjustmentScans) { _accurateMassAdjustmentScans = accurateMassAdjustmentScans; } protected int getAccurateMassAdjustmentScans() { return _accurateMassAdjustmentScans; } protected Scan[] getScans(MSRun run, int start, int count) { //eh? boolean bSkipLockSpray = false; start = Math.max(0, start); int maxScanIndex = run.getScanCount(); List<Scan> scanList = new ArrayList<Scan>(); for (int i = start; i < maxScanIndex && scanList.size() < count; i++) { Scan scan = run.getScan(i); if (bSkipLockSpray && 1 == (scan.getNum() % 20)) continue; scanList.add(scan); } return scanList.toArray(new Scan[scanList.size()]); } protected float[][] CombineScans(Scan[] scans, FloatRange range, int resample_freq) { float[][] zeroChargeSpectrum = null; int countScans = 0; for (int s = 0; s < scans.length; s++) { if (null == scans[s]) continue; countScans++; float[][] spectrumRaw = scans[s].getSpectrum(); float[][] t = Spectrum.ResampleSpectrum(spectrumRaw, range, resample_freq, true); if (null == zeroChargeSpectrum) zeroChargeSpectrum = t; else { int len = t[1].length; for (int i = 0; i < len; i++) zeroChargeSpectrum[1][i] += t[1][i]; } } int len = zeroChargeSpectrum[1].length; if (countScans > 1) for (int i = 0; i < len; i++) zeroChargeSpectrum[1][i] /= countScans; return zeroChargeSpectrum; } /** * Helper function for one scan at a time analyzer (TYPE_1D) * * @param scans * @return */ protected Feature[] analyzeScanAtATime(Scan[] scans) throws InterruptedException { Thread currentThread = Thread.currentThread(); ArrayList<Feature> all = new ArrayList<Feature>(); if (null != _status) _status.progress(0.0F); for (int i = 0; i < scans.length; i++) { Collection<Feature> byScan = analyze1D(scans[i]); all.addAll(byScan); if (null != _status) _status.progress(i*100.0F/scans.length); if (currentThread.isInterrupted()) throw new InterruptedException(); } if (null != _status) _status.progress(100.0F); return all.toArray(new Feature[all.size()]); } /** * Helper function for window analyzer (TYPE_2D) * * @param scans * @return */ protected Feature[] analyzeWindow(Scan[] scans, int windowWidth, int windowMargin) throws InterruptedException { _logDebug("analyzeWindow " + scans[0].getNum() + "-" + scans[scans.length-1].getNum()); Thread currentThread = Thread.currentThread(); List<Feature> all = new ArrayList<Feature>(); int scan = 0; int end = 0; if (null != _status) _status.progress(0.0F); do { end = Math.min(scans.length, scan+windowWidth); int start = Math.max(0, end - windowWidth); Scan[] scanWindow = new Scan[end-start]; System.arraycopy(scans, start, scanWindow, 0, end-start); Collection<Feature> byScan = analyze2D(scanWindow); // only add features found between the margins (exclude overlapping areas) int s = (scan == 0) ? scan : scan + windowMargin; int e = (end == scans.length) ? end : end - windowMargin; int fromScanNum = scans[s].getNum(); int toScanNum = scans[e-1].getNum(); _logDebug("WINDOW [" + scans[start].getNum() + "-" + scans[end-1].getNum() + "] " + fromScanNum + "-" + toScanNum + "*******"); for (Feature feature : byScan) { if (feature.scan >= fromScanNum && feature.scan <= toScanNum) all.add(feature); } if (null != _status) _status.progress((end-windowMargin)*100.0F/scans.length); if (currentThread.isInterrupted()) throw new InterruptedException(); scan += windowWidth - 2 * windowMargin; } while (end < scans.length); if (null != _status) _status.progress(100.0F); return all.toArray(new Feature[all.size()]); } // implement this in order to use the analyzeScanAtATime() helper protected Collection<Feature> analyze1D(Scan scan) throws InterruptedException { throw new java.lang.UnsupportedOperationException(); } // implement this in order to use the analyzeWindow() helper protected Collection<Feature> analyze2D(Scan[] scans) throws InterruptedException { throw new java.lang.UnsupportedOperationException(); } public int getType() { return TYPE_1D; } protected static void _logDebug(String s) { _log.debug(s); } protected abstract Feature[] _analyze() throws InterruptedException; public FeatureSet analyze() throws InterruptedException { Feature[] features = _analyze(); FeatureSet fs = new FeatureSet(features); String revision = (String) ApplicationContext.getProperty("REVISION"); if (null == revision) revision = ""; if (revision.toLowerCase().startsWith("revision:")) revision = revision.substring("Revision:".length()).trim(); Map m = fs.getProperties(); m.put("revision", revision); m.put("algorithm", this.getClass().getName()); m.put("java.vendor", System.getProperty("java.vendor")); m.put("java.version", System.getProperty("java.version")); m.put("user.name", System.getProperty("user.name")); m.put("date", (new Date()).toString()); return fs; } }