package com.compomics.util.experiment.biology;
import com.compomics.util.Util;
import com.compomics.util.experiment.biology.ions.ReporterIon;
import com.compomics.util.experiment.personalization.ExperimentObject;
import com.compomics.util.preferences.SequenceMatchingPreferences;
import com.compomics.util.pride.CvTerm;
import java.util.ArrayList;
/**
* This class models a post-translational modification.
*
* @author Marc Vaudel
* @author Harald Barsnes
*/
public class PTM extends ExperimentObject {
/**
* The version UID for backward compatibility.
*/
static final long serialVersionUID = -545472596243822505L;
/**
* Modification at particular amino acids.
*/
public static final int MODAA = 0;
/**
* Modification at the N terminus of a protein.
*/
public static final int MODN = 1;
/**
* Modification at the N terminus of a protein at particular amino acids.
*/
public static final int MODNAA = 2;
/**
* Modification at the C terminus of a protein.
*/
public static final int MODC = 3;
/**
* Modification at the C terminus of a protein at particular amino acids.
*/
public static final int MODCAA = 4;
/**
* Modification at the N terminus of a peptide.
*/
public static final int MODNP = 5;
/**
* Modification at the N terminus of a peptide at particular amino acids.
*/
public static final int MODNPAA = 6;
/**
* Modification at the C terminus of a peptide.
*/
public static final int MODCP = 7;
/**
* Modification at the C terminus of a peptide at particular amino acids.
*/
public static final int MODCPAA = 8;
/**
* The max number of modification types.
*/
public static final int MODMAX = 9;
/**
* The modification type according to static field.
*/
private int type;
/**
* Name of the modification.
*/
private String name;
/**
* Short name of the modification.
*/
private String shortName;
/**
* Mass difference produced by this modification. Null if not set.
*/
private Double mass = null;
/**
* List of known neutral losses for this modification.
*/
private ArrayList<NeutralLoss> neutralLosses = new ArrayList<NeutralLoss>(0);
/**
* List of known reporter ions for this modification.
*/
private ArrayList<ReporterIon> reporterIons = new ArrayList<ReporterIon>(0);
/**
* The amino acid pattern targeted by this modification (can be set using
* the AminoAcidPatternDialog).
*/
private AminoAcidPattern pattern = new AminoAcidPattern();
/**
* The composition of the molecule added.
*/
private AtomChain atomChainAdded = new AtomChain();
/**
* The composition of the molecule removed.
*/
private AtomChain atomChainRemoved = new AtomChain();
/**
* The CV term associated with this PTM. Null if not set.
*/
private CvTerm cvTerm = null;
/**
* The number of decimals used in the getRoundedMass method.
*/
private static final int NUMBER_OF_ROUNDED_DECIMALS = 6;
/**
* Constructor for the modification.
*/
public PTM() {
}
/**
* Constructor for a reference modification.
*
* @param type type of modification according to static attributes
* @param name name of the modification
* @param shortName short name of the modification
* @param atomChainAdded atomic composition of the molecule added
* @param atomChainRemoved atomic composition of the molecule removed
* @param aminoAcidPattern residue pattern affected by this modification
*/
public PTM(int type, String name, String shortName, AtomChain atomChainAdded, AtomChain atomChainRemoved, AminoAcidPattern aminoAcidPattern) {
this.type = type;
this.name = name;
this.shortName = shortName;
this.atomChainAdded = atomChainAdded;
this.atomChainRemoved = atomChainRemoved;
this.pattern = aminoAcidPattern;
this.cvTerm = null;
mass = null;
}
/**
* Constructor for a reference modification.
*
* @param type type of modification according to static attributes
* @param name name of the modification
* @param shortName short name of the modification
* @param atomChainAdded atomic composition of the molecule added
* @param atomChainRemoved atomic composition of the molecule removed
* @param aminoAcidPattern residue pattern affected by this modification
* @param cvTerm the CV term associated with this PTM, null if not set
*/
public PTM(int type, String name, String shortName, AtomChain atomChainAdded, AtomChain atomChainRemoved, AminoAcidPattern aminoAcidPattern, CvTerm cvTerm) {
this.type = type;
this.name = name;
this.shortName = shortName;
this.atomChainAdded = atomChainAdded;
this.atomChainRemoved = atomChainRemoved;
this.pattern = aminoAcidPattern;
this.cvTerm = cvTerm;
mass = null;
}
/**
* Simple constructor for a PTM. This constructor does not set the atomic
* composition or the cv term.
*
* @param type type of modification according to static attributes
* @param name name of the modification
* @param mass the mass of the modification
* @param residues list of residues possibly targeted by this modification
*/
public PTM(int type, String name, Double mass, ArrayList<String> residues) {
this.type = type;
this.name = name;
this.mass = mass;
if (residues != null) {
this.pattern = new AminoAcidPattern(residues);
}
}
/**
* Getter for the modification type.
*
* @return the modification type
*/
public int getType() {
return type;
}
/**
* Getter for the modification name.
*
* @return the modification name
*/
public String getName() {
return name;
}
/**
* Sets the PTM name.
*
* @param name the PTM name
*/
public void setName(String name) {
this.name = name;
}
/**
* Getter for the short modification name.
*
* @return the short modification name
*/
public String getShortName() {
return shortName;
}
/**
* Sets the short PTM name.
*
* @param shortName the PTM name
*/
public void setShortName(String shortName) {
this.shortName = shortName;
}
/**
* Getter for the mass difference induced by this modification.
*
* @return the mass difference induced by the modification
*/
public double getMass() {
if (mass == null) {
estimateMass();
}
return mass;
}
/**
* Estimates the mass of the PTM and stores it in the mass attribute.
*/
private synchronized void estimateMass() {
if (mass == null) {
Double tempMass = 0.0;
if (atomChainAdded != null) {
tempMass += atomChainAdded.getMass();
}
if (atomChainRemoved != null) {
tempMass -= atomChainRemoved.getMass();
}
mass = tempMass;
}
}
/**
* Getter for the rounded mass difference induced by this modification.
*
* @param numberOfDecimals the number of decimals to round to
* @return the rounded mass difference induced by the modification
*/
public double getRoundedMass(int numberOfDecimals) {
double roundedMass = getMass();
return Util.roundDouble(roundedMass, numberOfDecimals);
}
/**
* Getter for the rounded mass difference induced by this modification.
* Rounded to the number of decimals set in NUMBER_OF_ROUNDED_DECIMALS.
*
* @return the rounded mass difference induced by the modification
*/
public double getRoundedMass() {
return getRoundedMass(NUMBER_OF_ROUNDED_DECIMALS);
}
/**
* Returns the atom chain added.
*
* @return the atom chain added
*/
public AtomChain getAtomChainAdded() {
return atomChainAdded;
}
/**
* Sets the atom chain added.
*
* @param atomChainAdded the atom chain added
*/
public void setAtomChainAdded(AtomChain atomChainAdded) {
this.atomChainAdded = atomChainAdded;
mass = null;
}
/**
* Returns the atom chain removed.
*
* @return the atom chain removed
*/
public AtomChain getAtomChainRemoved() {
return atomChainRemoved;
}
/**
* Sets the atom chain removed.
*
* @param atomChainRemoved the atom chain removed
*/
public void setAtomChainRemoved(AtomChain atomChainRemoved) {
this.atomChainRemoved = atomChainRemoved;
mass = null;
}
/**
* Returns true if the atomic composition of the PTM is the same as another
* one.
*
* @param anotherPTM the PTM to compare to
*
* @return true if the atomic composition of the PTM is the same as the
* other one
*/
public boolean isSameAtomicComposition(PTM anotherPTM) {
if (atomChainAdded != null && !atomChainAdded.isSameCompositionAs(anotherPTM.getAtomChainAdded())
|| atomChainRemoved != null && !atomChainRemoved.isSameCompositionAs(anotherPTM.getAtomChainRemoved())) {
return false;
}
if (atomChainAdded == null && anotherPTM.getAtomChainAdded() != null && !anotherPTM.getAtomChainAdded().getAtomChain().isEmpty()
|| atomChainRemoved == null && anotherPTM.getAtomChainRemoved() != null && !anotherPTM.getAtomChainRemoved().getAtomChain().isEmpty()) {
return false;
}
return true;
}
/**
* Returns true if the targeted pattern of the PTM is the same as another
* one. An empty pattern is considered to be the same as a null pattern.
*
* @param anotherPTM the PTM to compare to
*
* @return true if the targeted pattern of the PTM is the same as the other
* one
*/
public boolean isSamePattern(PTM anotherPTM) {
if (pattern == null && anotherPTM.getPattern() != null && anotherPTM.getPattern().length() > 0) {
return false;
}
if (pattern != null && !pattern.isSameAs(anotherPTM.getPattern(), SequenceMatchingPreferences.defaultStringMatching)) {
return false;
}
return true;
}
/**
* Returns true if the PTM is the same as another one.
*
* @param anotherPTM another PTM
*
* @return true if the PTM is the same as the other one
*/
public boolean isSameAs(PTM anotherPTM) {
if (type != anotherPTM.getType()) {
// System.out.println("type difference");
// System.out.println("local: " + type);
// System.out.println("parameters: " + anotherPTM.getType());
return false;
}
if (!isSamePattern(anotherPTM)) {
// System.out.println("pattern difference");
// System.out.println("local: " + pattern);
// System.out.println("parameters: " + anotherPTM.getPattern());
return false;
}
if (!isSameAtomicComposition(anotherPTM)) {
// System.out.println("composition difference");
// System.out.println("local added: " + atomChainAdded);
// System.out.println("local removed: " + atomChainRemoved);
// System.out.println("parameters added: " + anotherPTM.getAtomChainAdded());
// System.out.println("parameters removed: " + anotherPTM.getAtomChainRemoved());
return false;
}
return true;
}
/**
* Returns the neutral losses possibly encountered with this modification.
*
* @return the neutral losses possibly encountered with this modification
*/
public ArrayList<NeutralLoss> getNeutralLosses() {
return neutralLosses;
}
/**
* Sets the neutral losses possibly encountered with this modification.
*
* @param neutralLosses the neutral losses possibly encountered with this
* modification
*/
public void setNeutralLosses(ArrayList<NeutralLoss> neutralLosses) {
this.neutralLosses = neutralLosses;
}
/**
* Adds a neutral loss.
*
* @param neutralLoss the new neutral loss
*/
public void addNeutralLoss(NeutralLoss neutralLoss) {
neutralLosses.add(neutralLoss);
}
/**
* Returns the reporter ions possibly encountered with this modification.
*
* @return the reporter ions possibly encountered with this modification
*/
public ArrayList<ReporterIon> getReporterIons() {
return reporterIons;
}
/**
* Sets the reporter ions possibly encountered with this modification.
*
* @param reporterIons the reporter ions possibly encountered with this
* modification
*/
public void setReporterIons(ArrayList<ReporterIon> reporterIons) {
this.reporterIons = reporterIons;
}
/**
* Adds a reporter ion.
*
* @param reporterIon the reporter ion to add
*/
public void addReporterIon(ReporterIon reporterIon) {
reporterIons.add(reporterIon);
}
/**
* Returns the amino acid pattern targeted by this modification.
*
* @return the amino acid pattern targeted by this modification
*/
public AminoAcidPattern getPattern() {
return pattern;
}
/**
* Sets the amino acid pattern targeted by this modification.
*
* @param pattern the amino acid pattern targeted by this modification
*/
public void setPattern(AminoAcidPattern pattern) {
this.pattern = pattern;
}
/**
* Indicates whether a modification can be searched with standard search
* engines, i.e., true if it targets a single amino acid position, false if
* it targets a complex pattern.
*
* @return a boolean indicating whether a modification can be searched with
* standard search engines
*/
public boolean isStandardSearch() {
return pattern == null || pattern.length() == 1;
}
/**
* Returns true if the PTM is an n-term PTM.
*
* @return true if the PTM is an n-term PTM
*/
public boolean isNTerm() {
return type == PTM.MODN
|| type == PTM.MODNAA
|| type == PTM.MODNP
|| type == PTM.MODNPAA;
}
/**
* Returns true if the PTM is a c-term PTM.
*
* @return true if the PTM is a c-term PTM
*/
public boolean isCTerm() {
return type == PTM.MODC
|| type == PTM.MODCAA
|| type == PTM.MODCP
|| type == PTM.MODCPAA;
}
/**
* Returns information about the PTM as an HTML tooltip.
*
* @return information about the PTM as an HTML tooltip
*/
public String getHtmlTooltip() {
String tooltip = "<html>";
tooltip += "Name: " + name + "<br>";
tooltip += "Mass: " + getRoundedMass(4) + "<br>";
tooltip += "Type: ";
switch (type) {
case MODAA:
tooltip += "Particular amino acid(s)";
break;
case MODN:
case MODNAA:
tooltip += "Protein N terminus";
break;
case MODC:
case MODCAA:
tooltip += "Protein C terminus";
break;
case MODNP:
case MODNPAA:
tooltip += "Peptide N terminus";
break;
case MODCP:
case MODCPAA:
tooltip += "Peptide C terminus";
break;
default:
break;
}
tooltip += "<br>";
tooltip += "Target: ";
if (pattern != null && !pattern.getAminoAcidsAtTarget().isEmpty()) {
String patternAsString = pattern.toString();
tooltip += patternAsString;
} else {
tooltip += "All";
}
tooltip += "</html>";
return tooltip;
}
/**
* Returns the CV term associated with this PTM.
*
* @return the cvTerm
*/
public CvTerm getCvTerm() {
return cvTerm;
}
/**
* Set the CV term associated with this PTM.
*
* @param cvTerm the cvTerm to set
*/
public void setCvTerm(CvTerm cvTerm) {
this.cvTerm = cvTerm;
}
@Override
public String toString() {
String target = "";
switch (getType()) {
case PTM.MODAA:
target = getPattern().toString();
break;
case PTM.MODC:
target = "Protein C-terminus";
break;
case PTM.MODCAA:
target = "Protein C-terminus ending with " + getPattern().toString();
break;
case PTM.MODCP:
target = "Peptide C-terminus";
break;
case PTM.MODCPAA:
target = "Peptide C-terminus ending with " + getPattern().toString();
break;
case PTM.MODN:
target = "Protein N-terminus";
break;
case PTM.MODNAA:
target = "Protein N-terminus starting with " + getPattern().toString();
break;
case PTM.MODNP:
target = "Peptide N-terminus";
break;
case PTM.MODNPAA:
target = "Peptide N-terminus starting with " + getPattern().toString();
break;
}
StringBuilder description = new StringBuilder();
description.append(name);
if (shortName != null && !shortName.equals("")) {
description.append("(").append(shortName).append(")");
}
description.append("\t");
if (atomChainAdded != null) {
description.append("+{").append(atomChainAdded).append("}");
}
if (atomChainRemoved != null) {
description.append("-{").append(atomChainRemoved).append("}");
}
double ptmMass = getRoundedMass();
String sign;
if (ptmMass > 0) {
sign = "+";
} else {
sign = "-";
}
description.append(" (").append(sign).append(ptmMass).append(")");
description.append(" targeting ").append(target);
return description.toString();
}
}