/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1210 $ by $Author: glycoslave $ on $Date:: 2009-06-12 #$
*/
/**
@author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
package org.eurocarbdb.application.glycoworkbench;
import org.eurocarbdb.application.glycoworkbench.plugin.peakpicker.*;
import org.eurocarbdb.application.glycanbuilder.*;
import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import java.nio.MappedByteBuffer;
import java.nio.DoubleBuffer;
import org.jfree.data.Range;
import org.xml.sax.SAXException;
import javax.xml.transform.sax.TransformerHandler;
import org.xml.sax.helpers.AttributesImpl;
public class PeakData implements SAXUtils.SAXWriter {
protected int no_peaks;
protected double min_mz;
protected double max_mz;
protected MMFCreator.Pointer theData;
public PeakData() {
initData();
}
public PeakData(org.systemsbiology.jrap.Scan s, MMFCreator mmfc) throws Exception {
if( s!=null )
setData(s.getMassIntensityList(),mmfc);
else
initData();
}
public PeakData(org.proteomecommons.io.PeakList p, MMFCreator mmfc) throws Exception {
if( p!=null )
setData(p.getPeaks(),mmfc);
else
initData();
}
public PeakData(List<Peak> peaks, MMFCreator mmfc) throws Exception {
setData(peaks,mmfc);
}
private void initData() {
no_peaks = 0;
min_mz = max_mz = 0.;
theData = null;
}
private void setData(org.proteomecommons.io.Peak[] data, MMFCreator mmfc) throws Exception {
// init
initData();
// check for empty data
if( data==null || data.length==0 )
return;
// skip trailing zeros
int start = 0;
for( ; start<data.length && data[start].getMassOverCharge()==0.; start++ );
if( start==data.length )
return;
//add data
for( int i=start; i<data.length; i++ ) {
mmfc.addDouble(data[i].getMassOverCharge());
mmfc.addDouble(data[i].getIntensity());
}
no_peaks = data.length-start;
min_mz = data[start].getMassOverCharge();
max_mz = data[data.length-1].getMassOverCharge();
theData = mmfc.getPointerFromLast();
}
private void setData(float[][] data, MMFCreator mmfc) throws Exception {
// init
initData();
// check for empty data
if( data==null || data[0].length==0 )
return;
// skip trailing zeros
int start = 0;
for( ; start<data[0].length && data[0][start]==0.; start++ );
if( start==data[0].length )
return;
// add data
for( int i=start; i<data[0].length; i++ ) {
mmfc.addDouble(data[0][i]);
mmfc.addDouble(data[1][i]);
}
no_peaks = data[0].length-start;
min_mz = data[0][start];
max_mz = data[0][data[0].length-1];
theData = mmfc.getPointerFromLast();
}
private void setData(List<Peak> data, MMFCreator mmfc) throws Exception {
// init
initData();
// check for empty data
if( data==null || data.size()==0 )
return;
int data_peaks = data.size();
// skip trailing zeros
int start = 0;
for( ; start<data_peaks && data.get(start).getMZ()==0.; start++ );
if( start==data_peaks )
return;
// add data
for( int i=start; i<data_peaks; i++ ) {
mmfc.addDouble(data.get(i).getMZ());
mmfc.addDouble(data.get(i).getIntensity());
}
no_peaks = data_peaks - start;
min_mz = data.get(start).getMZ();
max_mz = data.get(data_peaks-1).getMZ();
theData = mmfc.getPointerFromLast();
}
public int getPeakCount() {
return no_peaks;
}
public double getMinMZ() {
return min_mz;
}
public double getMaxMZ() {
return max_mz;
}
public Range getMZRange() {
return new Range(min_mz,max_mz);
}
// retrieve data
public double[] findNearestPeak(double mz) {
// get data
DoubleBuffer buffer = null;
try {
buffer = theData.getBuffer(true).asDoubleBuffer();
}
catch(Exception e) {
LogUtils.report(e);
return null;
}
// estimate position
int best_pos = (int)((mz-min_mz)/(max_mz-min_mz));
if( best_pos<0 )
return new double[] {buffer.get(0),buffer.get(1)};
if( best_pos>=no_peaks )
return new double[] {buffer.get(2*no_peaks-2),buffer.get(2*no_peaks-1)};
double pos_mz = buffer.get(2*best_pos);
double min_dist = Math.abs(pos_mz-mz);
if( pos_mz>mz ) {
for( int i=best_pos-1; i>=0; i-- ) {
double dist = Math.abs(buffer.get(2*i)-mz);
if( dist>min_dist )
break;
min_dist = dist;
best_pos = i;
}
}
else if( pos_mz<mz ) {
for( int i=best_pos+1; i<no_peaks; i++ ) {
double dist = Math.abs(buffer.get(2*i)-mz);
if( dist>min_dist )
break;
min_dist = dist;
best_pos = i;
}
}
return new double[] {buffer.get(2*best_pos),buffer.get(2*best_pos+1)};
}
public double[][] getData() {
return getData(0.);
}
public double[][] getData(double from_mz, double to_mz) {
return getData(from_mz,to_mz,0.);
}
public double[][] getData(double mz_toll) {
return getData(getMinMZ(),getMaxMZ(),mz_toll,false);
}
public double[][] getData(double mz_toll, boolean rel_int) {
return getData(getMinMZ(),getMaxMZ(),mz_toll,rel_int);
}
public double[][] getData(Range range, double mz_toll) {
return getData(range.getLowerBound(),range.getUpperBound(),mz_toll,false);
}
public double[][] getData(Range range, double mz_toll, boolean rel_int) {
return getData(range.getLowerBound(),range.getUpperBound(),mz_toll,rel_int);
}
public double[][] getData(double from_mz, double to_mz, double mz_toll) {
return getData(from_mz,to_mz,mz_toll,false);
}
public double[][] getData(double from_mz, double to_mz, double mz_toll, boolean rel_int) {
DoubleBuffer buffer = null;
try {
buffer = theData.getBuffer(true).asDoubleBuffer();
}
catch(Exception e) {
LogUtils.report(e);
return null;
}
double max_int = 0;
Vector<Peak> peaks = new Vector<Peak>();
for( int i=0; ; ) {
// skip initial peaks
if( buffer.get(2*i)<from_mz ) {
i++;
continue;
}
// get highest peak in the tolerange
double last_mz = buffer.get(2*i);
double add_mz = buffer.get(2*i);
double add_int = buffer.get(2*i+1);
for( ++i; i<no_peaks && buffer.get(2*i)<(last_mz+mz_toll) && buffer.get(2*i)<=to_mz ; i++ ) {
if( buffer.get(2*i+1)>add_int ) {
add_mz = buffer.get(2*i);
add_int = buffer.get(2*i+1);
}
}
// add peak
max_int = Math.max(max_int,add_int);
peaks.add(new Peak(add_mz,add_int));
// skip last peaks
if( i>=no_peaks || buffer.get(2*i)>to_mz )
break;
}
// return (normalized) value
double[][] ret = new double[2][];
ret[0] = new double[peaks.size()];
ret[1] = new double[peaks.size()];
double div = (rel_int) ?(max_int/100) :1.;
for( int i=0; i<peaks.size(); i++ ) {
ret[0][i] = peaks.get(i).getMZ();
ret[1][i] = peaks.get(i).getIntensity()/div;
}
return ret;
}
/*
public double[][] getData(Range range, double mz_toll, boolean rel_int) {
double div = 1.;
if( rel_int )
div = getMaxIntensity(range)/100.;
mz_toll = Math.abs(mz_toll);
// restrict to range
java.util.SortedMap<Double,Double> submap = theData.subMap(range.getLowerBound(),range.getUpperBound());
if( submap.size()==0 ) {
double[][] ret = new double[2][];
ret[0] = new double[0];
ret[1] = new double[0];
return ret;
}
// count entries
int count = 1;
double last_mz = submap.firstKey();
if( mz_toll>0. )
last_mz = getMinMZ() + (int)((last_mz-getMinMZ())/mz_toll)*mz_toll;
for( Map.Entry<Double,Double> e : submap.entrySet() ) {
if( (e.getKey()-last_mz)>mz_toll ) {
count++;
last_mz = e.getKey();
}
}
// allocate space
double[][] ret = new double[2][];
ret[0] = new double[count];
ret[1] = new double[count];
// save entries
int i = 0;
last_mz = submap.firstKey();
if( mz_toll>0. )
last_mz = getMinMZ() + (int)((last_mz-getMinMZ())/mz_toll)*mz_toll;
double max_int = submap.get(submap.firstKey());
for( Map.Entry<Double,Double> e : submap.entrySet() ) {
if( (e.getKey()-last_mz)>mz_toll ) {
ret[0][i] = last_mz;
ret[1][i] = max_int/div;
last_mz = e.getKey();
max_int = e.getValue();
i++;
}
else
max_int = Math.max(max_int,e.getValue());
}
if( i<count ) {
ret[0][i] = last_mz;
ret[1][i] = max_int/div;
}
return ret;
}
*/
public void baselineCorrection() {
try {
DoubleBuffer buffer = theData.getBuffer(false).asDoubleBuffer();
// put data in memory
double[][] data = new double[2][];
data[0] = new double[no_peaks];
data[1] = new double[no_peaks];
for( int i=0; i<no_peaks; i++ ) {
data[0][i] = buffer.get(2*i);
data[1][i] = buffer.get(2*i+1);
}
// compute baseline correction
TopHatFilter.filter(data,2.5);
// save corrected data
for( int i=0; i<no_peaks; i++ ) {
buffer.put(2*i,data[0][i]);
buffer.put(2*i+1,data[1][i]);
}
}
catch(Exception e) {
LogUtils.report(e);
}
}
public void recalibrate(List<Double> params) {
if( params==null || params.size()<2 )
return;
try {
// save corrected data
DoubleBuffer buffer = theData.getBuffer(false).asDoubleBuffer();
for( int i=0; i<no_peaks; i++ ) {
double old_mz = buffer.get(2*i);
double new_mz = recalibrate(old_mz,params);
buffer.put(2*i,new_mz);
}
// recalibrate min/max
min_mz = recalibrate(min_mz,params);
max_mz = recalibrate(max_mz,params);
}
catch(Exception e) {
LogUtils.report(e);
}
}
private double recalibrate(double mz, List<Double> params) {
double ret = mz;
double mul = 1;
for( Double param : params ) {
ret += param * mul;
mul *= mz;
}
return ret;
}
public void noiseFilter() {
noiseFilter(0.8);
}
public void noiseFilter(double width) {
try {
DoubleBuffer buffer = theData.getBuffer(false).asDoubleBuffer();
// put data in memory
double[][] data = new double[2][];
data[0] = new double[no_peaks];
data[1] = new double[no_peaks];
for( int i=0; i<no_peaks; i++ ) {
data[0][i] = buffer.get(2*i);
data[1][i] = buffer.get(2*i+1);
}
// compute gaussian filtering
GaussFilter gf = new GaussFilter();
gf.setKernelWidth(width);
data = gf.filter(data);
// save corrected data
for( int i=0; i<no_peaks; i++ ) {
buffer.put(2*i,data[0][i]);
buffer.put(2*i+1,data[1][i]);
}
}
catch(Exception e) {
LogUtils.report(e);
}
}
// Serialization
public void write(File f) throws Exception {
write(new FileOutputStream(f));
}
public void write(OutputStream os) throws Exception {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
DoubleBuffer buffer = theData.getBuffer(true).asDoubleBuffer();
for( int i=0; i<no_peaks; i++ ) {
String str = "" + buffer.get(2*i) + " " + buffer.get(2*i+1);
bw.write(str,0,str.length());
bw.newLine();
}
bw.close();
}
static public PeakData fromXML(Node pd_node, MMFCreator mmfc) throws Exception {
PeakData ret = new PeakData();
if( pd_node==null )
return ret;
// get text representation of peaks
String text = XMLUtils.getText(pd_node);
if( text==null || text.length()==0 )
return ret;
// decode peaks from string
byte[] decoded = Base64.decode(text);
for( int i=0; i<decoded.length; i++ )
mmfc.addByte(decoded[i]);
// setting data
ret.theData = mmfc.getPointerFromLast();
ret.no_peaks = (int)(8*ret.theData.getSize()/Double.SIZE)/2;
DoubleBuffer buffer = ret.theData.getBuffer(true).asDoubleBuffer();
ret.min_mz = buffer.get(0);
ret.max_mz = buffer.get(2*(ret.no_peaks-1));
return ret;
}
public Element toXML(Document document) {
if( document==null )
return null;
// create root node
Element pd_node = document.createElement("PeakData");
// create string encoding of peaks
try {
// create string encoding of peaks
MappedByteBuffer buffer = theData.getBuffer(true);
byte[] toencode = new byte[buffer.capacity()];
for( int i=0; i<buffer.capacity(); i++ )
toencode[i] = buffer.get(i);
// store encoding
XMLUtils.setText(pd_node,Base64.encodeToString(toencode,false));
}
catch(Exception e) {
LogUtils.report(e);
}
return pd_node;
}
public static class SAXHandler extends SAXUtils.ObjectTreeHandler {
private MMFCreator mmfc;
public SAXHandler(MMFCreator _mmfc) {
mmfc = _mmfc;
}
public boolean isElement(String namespaceURI, String localName, String qName) {
return qName.equals(getNodeElementName());
}
public static String getNodeElementName() {
return "PeakData";
}
protected void addWhiteSpace() {
}
protected Object finalizeContent(String namespaceURI, String localName, String qName) throws SAXException{
PeakData ret = new PeakData();
try {
// decode peaks from string
byte[] decoded = Base64.decode(text.toString());
for( int i=0; i<decoded.length; i++ )
mmfc.addByte(decoded[i]);
// set data
ret.theData = mmfc.getPointerFromLast();
ret.no_peaks = (int)(8*ret.theData.getSize()/Double.SIZE)/2;
DoubleBuffer buffer = ret.theData.getBuffer(true).asDoubleBuffer();
ret.min_mz = buffer.get(0);
ret.max_mz = buffer.get(2*(ret.no_peaks-1));
}
catch(Exception e) {
throw new SAXException(e);
}
return (object = ret);
}
}
public void write(TransformerHandler th) throws SAXException {
th.startElement("","","PeakData",new AttributesImpl());
char[] text = new char[0];
try {
// create string encoding of peaks
MappedByteBuffer buffer = theData.getBuffer(true);
byte[] toencode = new byte[buffer.capacity()];
for( int i=0; i<buffer.capacity(); i++ )
toencode[i] = buffer.get(i);
// store encoding
text = Base64.encodeToChar(toencode,true);
}
catch(Exception e) {
LogUtils.report(e);
}
th.characters(text,0,text.length);
th.endElement("","","PeakData");
}
}