/*
* 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 #$
*/
package org.eurocarbdb.application.glycanbuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import javax.xml.transform.sax.TransformerHandler;
import org.xml.sax.helpers.AttributesImpl;
/**
This class holds computed information about a fragment structure to
improve the performance of the various views. The fragment
structure could be also an intact molecule, and this class is used
for compatibility also for profiling.
@author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
public class FragmentEntry implements Comparable<FragmentEntry>, SAXUtils.SAXWriter {
// ---
/** The fragment */
public Glycan fragment;
/** The fragment type */
public String name;
/** The mass of the fragment given its mass settings */
public Double mass;
/** The mass-to-charge ratio of the fragment given its mass
settings */
public Double mz_ratio;
/** A string representation of the fragment structure */
public String structure;
/** The likelyhood of the fragment structure (for future use)*/
public Double score;
/** The object that generated this fragment **/
public FragmentSource source;
/**
Empty constructor.
*/
public FragmentEntry() {
fragment = null;
name = "";
mass = 0.;
mz_ratio = 0.;
structure = "";
score = 0.;
source = null;
}
/**
Create a new fragment entry from a fragment structure. Compute
all values from the fragment it-self
*/
public FragmentEntry(Glycan _fragment, String _name) {
fragment = (_fragment!=null) ?_fragment.clone() :null;
name = (_name!=null) ?_name :"";
mass = (fragment!=null) ?fragment.computeMass() :0.;
mz_ratio = (fragment!=null) ?fragment.computeMZ() :0.;
structure = (fragment!=null) ?fragment.toString() :"";
score = 0.;
source = null;
}
/**
Create a new fragment entry from a fragment structure with a
supplied scoring. Compute all values from the fragment it-self
*/
public FragmentEntry(Glycan _fragment, String _name, double _score) {
fragment = (_fragment!=null) ?_fragment.clone() :null;
name = (_name!=null) ?_name :"";
mass = (fragment!=null) ?fragment.computeMass() :0.;
mz_ratio = (fragment!=null) ?fragment.computeMZ() :0.;
structure = (fragment!=null) ?fragment.toString() :"";
score = _score;
source = null;
}
/**
Create a new fragment entry filling the information with the supplied values
@param _fragment the fragment structure
@param _name the fragment type
@param _mass the fragment mass
@param _mz_ratio the fragment mass-to-charge ratio
@param _structure a string representation of the fragment
*/
public FragmentEntry(Glycan _fragment, String _name, double _mass, double _mz_ratio, String _structure) {
fragment = (_fragment!=null) ?_fragment.clone() :null;
name = (_name!=null) ?_name :"";
mass = _mass;
mz_ratio = _mz_ratio;
structure = (_structure!=null) ?_structure :"";
score = 0.;
source = null;
}
/**
Create a new fragment entry filling the information with the supplied values
@param _fragment the fragment structure
@param _name the fragment type
@param _mass the fragment mass
@param _mz_ratio the fragment mass-to-charge ratio
@param _structure a string representation of the fragment
@param _score the likelyhood of the fragment
*/
public FragmentEntry(Glycan _fragment, String _name, double _mass, double _mz_ratio, String _structure, double _score) {
fragment = (_fragment!=null) ?_fragment.clone() :null;
name = (_name!=null) ?_name :"";
mass = _mass;
mz_ratio = _mz_ratio;
structure = (_structure!=null) ?_structure :"";
score = _score;
source = null;
}
/**
Create a copy of the current object.
*/
public FragmentEntry clone() {
FragmentEntry ret = new FragmentEntry();
ret.fragment = (fragment!=null) ?fragment.clone() :null;
ret.name = name;
ret.mass = mass;
ret.mz_ratio = mz_ratio;
ret.structure = structure;
ret.score = score;
ret.source = source;
return ret;
}
/**
Compare two fragment entries. The entries are ordered: first by
score (descending), then by mass-to-charge ratio (ascending)
and finally by structure.
@see Glycan#compareTo
*/
public int compareTo(FragmentEntry fe) {
if( fe==null ) return 1;
if( this.score>fe.score ) return -1;
if( this.score<fe.score ) return 1;
if( this.mz_ratio<fe.mz_ratio ) return -1;
if( this.mz_ratio>fe.mz_ratio ) return 1;
if( this.fragment==null && fe.fragment==null ) return 0;
if( this.fragment==null && fe.fragment!=null ) return -1;
return this.fragment.compareTo(fe.fragment);
}
/**
Return <code>true</code> if this entry contains an empty
structure.
@see Glycan#isEmpty
*/
public boolean isEmpty() {
return fragment==null || fragment.isEmpty();
}
/**
Return the fragment structure.
*/
public Glycan getFragment() {
return fragment;
}
/**
Return the fragment mass.
*/
public Double getMass() {
return mass;
}
/**
Return the fragment mass-to-charge ratio.
*/
public Double getMZ() {
return mz_ratio;
}
/**
Return the fragment name.
*/
public String getName() {
return name;
}
/**
Return the string representation of the fragment structure.
*/
public String getStructure() {
return structure;
}
/**
Return the fragment likelyhood.
*/
public Double getScore() {
return score;
}
/**
Set the fragment likelyhood.
*/
public void setScore(double d) {
score = d;
}
/**
Return the fragment generator.
*/
public FragmentSource getSource() {
return source;
}
/**
Set the fragment generator.
*/
public void setSource(FragmentSource s) {
source = s ;
}
/**
Return the charges associated with the fragment molecule.
@see MassOptions#ION_CLOUD
*/
public IonCloud getCharges() {
return fragment.getMassOptions().ION_CLOUD;
}
/**
Return the neutral exchanges associated with the fragment
molecule.
@see MassOptions#NEUTRAL_EXCHANGES
*/
public IonCloud getNeutralExchanges() {
return fragment.getMassOptions().NEUTRAL_EXCHANGES;
}
/**
Create a copy of this fragment entry and add the specified
charges to it.
*/
public FragmentEntry and(IonCloud charges) {
FragmentEntry ret = this.clone();
ret.setCharges(charges);
return ret;
}
/**
Create a copy of this fragment entry and add the specified
charges and neutral exchanges to it.
*/
public FragmentEntry and(IonCloud charges, IonCloud exchanges) {
FragmentEntry ret = this.clone();
ret.setCharges(charges,exchanges);
return ret;
}
/**
Set the charges associated with the fragment molecule, and
update the mass-to-charge value.
@see MassOptions#ION_CLOUD
*/
public void setCharges(IonCloud charges) {
setCharges(charges,new IonCloud(),true);
}
/**
Set the charges and neutral exchanges associated with the
fragment molecule, and update the mass-to-charge value.
@see MassOptions#ION_CLOUD
*/
public void setCharges(IonCloud charges, IonCloud exchanges) {
setCharges(charges,exchanges,true);
}
/**
Set the charges and neutral exchanges associated with the
fragment molecule. If <code>update_mz</code> is
<code>true</code> update the mass-to-charge value.
@see MassOptions#ION_CLOUD
*/
public void setCharges(IonCloud charges, IonCloud exchanges, boolean update_mz) {
if( fragment!=null ) {
fragment.getMassOptions().ION_CLOUD = charges;
fragment.getMassOptions().NEUTRAL_EXCHANGES = exchanges;
structure = fragment.toString();
if( update_mz )
mz_ratio = charges.computeMZ(exchanges.getIonsMass() + mass);
}
}
/**
Update the mass of the fragment.
*/
public void updateMass() {
IonCloud charges = fragment.getMassOptions().ION_CLOUD;
IonCloud exchanges = fragment.getMassOptions().NEUTRAL_EXCHANGES;
mass = fragment.computeMass();
mz_ratio = charges.computeMZ(exchanges.getIonsMass() + mass);
}
/**
Return <code>true</code> if the two fragment entries contain
the same structure and have the same type.
*/
public boolean equals(Object other) {
if( !(other instanceof FragmentEntry) )
return false;
FragmentEntry fe = (FragmentEntry)other;
if( this.fragment==null )
return fe.fragment==null;
return (Math.abs(this.mass-fe.mass)<0.005 && this.fragment.equalsStructure(fe.fragment) && this.name.equals(fe.name));
}
/**
Generate an hash code for this entry using the mass, the
structure and the type of the fragment.
*/
public int hashCode() {
int ret = 0;
ret += mass.hashCode();
ret += fragment.hashCode();
ret += name.hashCode();
return ret;
}
// serialization
/**
Generate a string representation of this entry using the type, the mass, the
score and the structure of the fragment.
*/
public String toString() {
return ("" + name + " " + mass + " " + score + " " + structure);
}
/**
Create a new object from its XML representation as part of a
DOM tree.
*/
static public FragmentEntry fromXML(Node fe_node) throws Exception {
FragmentEntry ret = new FragmentEntry();
ret.structure = XMLUtils.getAttribute(fe_node,"fragment");
ret.name = XMLUtils.getAttribute(fe_node,"name");
ret.mass = Double.valueOf(XMLUtils.getAttribute(fe_node,"mass"));
ret.mz_ratio = Double.valueOf(XMLUtils.getAttribute(fe_node,"mz_ratio"));
ret.fragment = (ret.structure.length()>0) ?Glycan.fromString(ret.structure,new MassOptions()) :null;
if( XMLUtils.getAttribute(fe_node,"score")!=null )
ret.score = Double.valueOf(XMLUtils.getAttribute(fe_node,"score"));
return ret;
}
/**
Create an XML representation of this object to
be part of a DOM tree.
*/
public Element toXML(Document document) {
if( document==null )
return null;
// create root node
Element fe_node = document.createElement("FragmentEntry");
if( fe_node==null )
return null;
fe_node.setAttribute("fragment",(fragment!=null) ?fragment.toString() :"");
fe_node.setAttribute("name",name);
fe_node.setAttribute("mass",mass.toString());
fe_node.setAttribute("mz_ratio",mz_ratio.toString());
fe_node.setAttribute("score",score.toString());
return fe_node;
}
/**
Default SAX handler to read a representation of this object
from an XML stream.
*/
public static class SAXHandler extends SAXUtils.ObjectTreeHandler {
public boolean isElement(String namespaceURI, String localName, String qName) {
return qName.equals(getNodeElementName());
}
/**
Return the element tag recognized by this handler
*/
public static String getNodeElementName() {
return "FragmentEntry";
}
protected void initContent(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
super.initContent(namespaceURI,localName,qName,atts);
FragmentEntry ret = new FragmentEntry();
ret.structure = stringAttribute(atts,"fragment","");
ret.name = stringAttribute(atts,"name","");
ret.mass = doubleAttribute(atts,"mass",0.);
ret.mz_ratio = doubleAttribute(atts,"mz_ratio",0.);
ret.score = doubleAttribute(atts,"score",0.);
ret.fragment = (ret.structure.length()>0) ?Glycan.fromString(ret.structure,new MassOptions()) :null;
object = ret;
}
}
/**
Write a representation of this object into an XML stream using
a SAX handler.
*/
public void write(javax.xml.transform.sax.TransformerHandler th) throws SAXException {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("","","fragment","CDATA",(fragment!=null) ?fragment.toString() :"");
atts.addAttribute("","","name","CDATA",name);
atts.addAttribute("","","mass","CDATA",mass.toString());
atts.addAttribute("","","mz_ratio","CDATA",mz_ratio.toString());
atts.addAttribute("","","score","CDATA",score.toString());
th.startElement("","","FragmentEntry",atts);
th.endElement("","","FragmentEntry");
}
}