All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jcamp.spectrum.MSPeakPicking Maven / Gradle / Ivy

package org.jcamp.spectrum;

import java.util.Vector;

import org.jcamp.math.IArray1D;

/**
 * mass spectrum specific peak picking (Thorstens algo)
 * does not work!
 * 
 * @author Thomas Weber
 */
public class MSPeakPicking
  implements IPeakPicking {
  
  final int MS_SIGNIFICANT_PEAKS = 32;
  
  /**
   * MSPeakPicking constructor comment.
   */
  public MSPeakPicking() {
    super();
  }
  /**
   * calculate method comment.
   */
  public Vector calculate(Spectrum1D spectrum) {
    double amu = 100;
    double rj = 40;
    double rk = 50;
    double rl = 7;
    Vector assigns = new Vector();
    IArray1D x = spectrum.getXData();
    IArray1D y = spectrum.getYData();
    int n = y.getLength();
    Integer[] peaks = new Integer[n];
    for (int i = 0; i < n; i++) {
      peaks[i] = new Integer(i);
    }
    int[] sigPeaks = new int[MS_SIGNIFICANT_PEAKS];
    int nSigs;
    // sort peak by descending weight
    sortPeaksWeighted(spectrum, peaks, 0, n - 1);
    // insert first 16 peaks
    nSigs = Math.min(MS_SIGNIFICANT_PEAKS, n);
    for (int i = 0; i < nSigs; i++)
      sigPeaks[i] = peaks[i].intValue();
    if (n <= MS_SIGNIFICANT_PEAKS) {
      for (int i = 0; i < nSigs; i++)
	assigns.addElement(new Peak1D(spectrum, x.pointAt(sigPeaks[i])));
      return assigns;
    }

    // check if range of masses is lower then amu
    double range = x.getRange1D().getXWidth();
    if (amu > 0.0 && range < amu) {
      double sf = range / amu;
      amu = range;
      rj *= sf;
      rk *= sf;
    }
    // start filtering
    //
    // Pass 1:
    // Each peak is considered in turn to be the center of a mass window
    // at most (amu + 1)  wide.
    // A peak is rejected during pass 1 if there are ((rj/amu)*(2*rk+1))
    // larger peaks in its own window.
    // The first peak in the spectrum has a mass window only amu/2 wide, so
    // it is rejected if therare ((rj/amu)*((amu+1)/2) larger peaks in the
    // amu/2 above it. Similar remarks apply to all peaks near the beginning or
    // end of the spectrum.
    // If pass 1 would save more than 200 peaks, the parameters are implicitetly reduced so
    // that 200 or fewer peaks are saved.
    //
    // Pass 2:
    // Most of the noise peaks have now been eliminated, producing for most psectra, a series of
    // relatively separated clusters. The algorithm of pass 1 is repeated, but the mass window
    // is narrowed (default rl = +/- 7*amu).
    // Thus a peak will be rejected during pass 2 if there are
    // (rj/amu*(rl*2+1) in its (rl*2+1) neighborhood.
    // After pass 2, the 16 largest peaks saved are added to the list of peaks if they are not
    // already present.

    double a1;
    double intervalLeft;
    double intervalRight;
    double realLeft;
    double realRight;
    double ratio;
    for (int filter = 0; filter < 2; filter++) {
      int resultDatapoints = 0;
      int[] tmpPeaks = new int[n];
      if (filter == 0)
	a1 = rk;
      else
	a1 = rl;
      // select peak
      for (int i = 0; i < n; i++) {
	int remainPeaks = (int) ((rj / amu) * (2 * a1 + 1));
	intervalLeft = x.pointAt(i) - a1;
	intervalRight = x.pointAt(i) + a1;
	realLeft = Math.max(intervalLeft, x.pointAt(0));
	realRight = Math.min(intervalLeft, x.pointAt(n - 1));
	if ((intervalRight - intervalLeft) == 0.0)
	  ratio = 1.0;
	else
	  ratio = (realRight - realLeft) / (intervalRight - intervalLeft);
	remainPeaks = (int) (remainPeaks * ratio);
	int j = 0;
	for (int k = 0; k < n; k++) {
	  if (x.pointAt(k) >= realLeft && x.pointAt(k) <= realRight && y.pointAt(i) < y.pointAt(k))
	    j++;
	}
	if (j < remainPeaks) {
	  tmpPeaks[resultDatapoints] = i;
	  resultDatapoints++;
	}
      }
      // copy peaks back
      for (int i = 0; i < resultDatapoints; i++)
	peaks[i] = new Integer(tmpPeaks[i]);
      n = resultDatapoints;
    }
    // add most significant peaks	
    int k = 0;
    for (int i = 0; i < nSigs; i++) {
      boolean peakFound = false;
      // check if peak already there
      for (int j = 0; j < n; j++) {
	if (j == sigPeaks[i]) {
	  peakFound = true;
	  break;
	}
      }
      if (!peakFound) {
	peaks[n + k] = new Integer(sigPeaks[i]);
	k++;
      }
    }
    n += k;
    if (n > 0) {
      sortPeaksWeighted(spectrum, peaks, 0, n - 1);
    }
    for (int i = 0; i < n; i++) {
      assigns.addElement(new Peak1D(spectrum, x.pointAt(peaks[i].intValue())));
    }
    return assigns;
  }
  /**
   * sort peaks descending by sqrt(m*i)
   * @param peakIndices java.lang.Integer[]
   */
  private void sortPeaksWeighted(Spectrum1D spectrum, Integer[] peaks, int from, int to) {
    final IArray1D x = spectrum.getXData();
    final IArray1D y = spectrum.getYData();
    java.util.Arrays.sort(peaks, from, to, new java.util.Comparator() {
      public int compare(Object o1, Object o2) {
	int i1 = ((Integer) o1).intValue();
	int i2 = ((Integer) o2).intValue();
	double w1 = Math.sqrt(x.pointAt(i1) * y.pointAt(i1));
	double w2 = Math.sqrt(x.pointAt(i2) * y.pointAt(i2));
	if (w1 < w2)
	  return 1;
	else if (w1 == w2)
	  return 0;
	else
	  return -1;
      }
    });
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy