package com.compomics.util.experiment.biology;
import com.compomics.util.experiment.biology.ions.*;
import com.compomics.util.experiment.personalization.ExperimentObject;
import com.compomics.util.pride.CvTerm;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
/**
* This class models an ion.
*
* @author Marc Vaudel
*/
public abstract class Ion extends ExperimentObject {
/**
* Serial number for backward compatibility.
*/
static final long serialVersionUID = -1505719074403886934L;
/**
* Cache for the neutral losses as string.
*/
private String neutralLossesAsString = null;
/**
* An enumerator of the supported ion types.
*/
public enum IonType {
/**
* Identifier for a peptide fragment ion.
*/
PEPTIDE_FRAGMENT_ION(0),
/**
* A tag fragment ion
*/
TAG_FRAGMENT_ION(1),
/**
* Identifier for an MH ion. The number of H is not represented here.
*/
PRECURSOR_ION(2),
/**
* Identifier for an immonium ion.
*/
IMMONIUM_ION(3),
/**
* Identifier for a reporter ion.
*/
REPORTER_ION(4),
/**
* Identifier for a glycan.
*/
GLYCAN(5),
/**
* Identifier for an elementary ion.
*/
ELEMENTARY_ION(6),
/**
* Identifier for an unknown ion.
*/
UNKNOWN(7),
/**
* Identifier for a related ion.
*/
RELATED_ION(8);
/**
* The index of the type.
*/
public final int index;
/**
* Constructor.
*
* @param index the index of the type
*/
private IonType(int index) {
this.index = index;
}
}
/**
* Type of ion.
*/
protected IonType type = IonType.UNKNOWN;
/**
* The theoretic mass.
*/
protected Double theoreticMass;
/**
* The atomic composition of the ion.
*/
protected AtomChain atomChain;
/**
* Returns the name of the ion. The name should be short enough to be
* displayed on a spectrum.
*
* @return the name of the ion
*/
public abstract String getName();
/**
* Returns the CV term adapted to the fragment ion. Null if none
* corresponding.
*
* @return the CV term adapted to the fragment ion. Null if none
* corresponding
*/
public abstract CvTerm getPrideCvTerm();
/**
* Returns the CV term adapted to the fragment ion. Null if none
* corresponding.
*
* @return the CV term adapted to the fragment ion. Null if none
* corresponding
*/
public abstract CvTerm getPsiMsCvTerm();
/**
* Returns the ion subtype.
*
* @return the ion subtype as integer
*/
public abstract int getSubType();
/**
* Returns the subtype as string.
*
* @return the subtype as string
*/
public abstract String getSubTypeAsString();
/**
* Returns an arraylist of possible subtypes.
*
* @param ionType an arraylist of possible subtypes
* @return an arraylist of possible subtypes
*/
public static ArrayList<Integer> getPossibleSubtypes(IonType ionType) {
switch (ionType) {
case ELEMENTARY_ION:
return ElementaryIon.getPossibleSubtypes();
case GLYCAN:
return Glycan.getPossibleSubtypes();
case IMMONIUM_ION:
return ImmoniumIon.getPossibleSubtypes();
case PEPTIDE_FRAGMENT_ION:
return PeptideFragmentIon.getPossibleSubtypes();
case TAG_FRAGMENT_ION:
return TagFragmentIon.getPossibleSubtypes();
case PRECURSOR_ION:
return PrecursorIon.getPossibleSubtypes();
case REPORTER_ION:
return ReporterIon.getPossibleSubtypes();
case RELATED_ION:
return RelatedIon.getPossibleSubtypes();
default:
throw new UnsupportedOperationException("Not supported yet.");
}
}
/**
* Returns the possible neutral losses of this ion type. An empty list if
* none.
*
* @return the possible neutral losses of this ion type
*/
public abstract ArrayList<NeutralLoss> getNeutralLosses();
/**
* Indicates whether the ion has a neutral loss.
*
* @return a boolean indicating whether the ion has a neutral loss
*/
public boolean hasNeutralLosses() {
switch (type) {
case PEPTIDE_FRAGMENT_ION:
case TAG_FRAGMENT_ION:
case PRECURSOR_ION:
ArrayList<NeutralLoss> neutralLosses = getNeutralLosses();
return neutralLosses != null && !neutralLosses.isEmpty();
default:
return false;
}
}
/**
* Returns a boolean indicating whether the ion is the same as another ion.
*
* @param anotherIon the other ion
* @return a boolean indicating whether the ion is the same as another ion
*/
public abstract boolean isSameAs(Ion anotherIon);
/**
* Returns the neutral loss (if any), the empty string if no loss.
*
* @return the neutral loss
*/
public String getNeutralLossesAsString() {
if (neutralLossesAsString == null) {
neutralLossesAsString = getNeutralLossesAsString(getNeutralLosses());
}
return neutralLossesAsString;
}
/**
* Returns the neutral loss (if any), the empty string if no loss.
*
* @param neutralLosses the neutral loss (if any)
* @return the neutral loss
*/
public static String getNeutralLossesAsString(ArrayList<NeutralLoss> neutralLosses) {
if (neutralLosses == null) {
return "";
}
ArrayList<String> names = new ArrayList<String>(neutralLosses.size());
for (NeutralLoss neutralLoss : neutralLosses) {
names.add(neutralLoss.name);
}
Collections.sort(names);
StringBuilder result = new StringBuilder(4 * neutralLosses.size());
for (String name : names) {
result.append("-").append(name);
}
return result.toString();
}
/**
* Returns the theoretic mass, from the atomic composition if available,
* from the theoreticMass field otherwise.
*
* @return the theoretic mass
*/
public Double getTheoreticMass() {
if (atomChain != null) {
return atomChain.getMass();
}
return theoreticMass;
}
/**
* Returns the m/z expected for this ion at the given charge.
*
* @param charge the charge of interest
*
* @return the m/z expected for this ion
*/
public Double getTheoreticMz(Integer charge) {
Double protonMass = ElementaryIon.proton.getTheoreticMass();
Double mz = getTheoreticMass() + protonMass;
if (charge > 1) {
mz = (mz + (charge - 1) * protonMass) / charge;
}
return mz;
}
/**
* Returns the atomic composition.
*
* @return the atomic composition
*/
public AtomChain getAtomicComposition() {
return atomChain;
}
/**
* Returns the atomic composition.
*
* @param atomChain the atomic composition
*/
public void setAtomicComposition(AtomChain atomChain) {
this.atomChain = atomChain;
}
/**
* Sets a new theoretic mass.
*
* @param theoreticMass a new theoretic mass
*/
public void setTheoreticMass(double theoreticMass) {
this.theoreticMass = theoreticMass;
}
/**
* Returns the ion type.
*
* @return the ion type
*/
public IonType getType() {
return type;
}
/**
* Returns the implemented ion types.
*
* @return the implemented ion types
*/
public static ArrayList<IonType> getImplementedIonTypes() {
ArrayList<IonType> result = new ArrayList<IonType>();
result.add(IonType.ELEMENTARY_ION);
result.add(IonType.GLYCAN);
result.add(IonType.IMMONIUM_ION);
result.add(IonType.PEPTIDE_FRAGMENT_ION);
result.add(IonType.TAG_FRAGMENT_ION);
result.add(IonType.PRECURSOR_ION);
result.add(IonType.REPORTER_ION);
result.add(IonType.RELATED_ION);
return result;
}
/**
* Returns the type of ion as string.
*
* @return the type of ion as string
*/
public String getTypeAsString() {
return getTypeAsString(type);
}
/**
* Returns the type of ion as string.
*
* @param type the type of ion as string
* @return the type of ion as string
*/
public static String getTypeAsString(IonType type) {
switch (type) {
case PEPTIDE_FRAGMENT_ION:
return "Peptide fragment ion";
case TAG_FRAGMENT_ION:
return "Tag fragment ion";
case PRECURSOR_ION:
return "Precursor ion";
case IMMONIUM_ION:
return "Immonium ion";
case REPORTER_ION:
return "Reporter ion";
case GLYCAN:
return "Glycan";
case ELEMENTARY_ION:
return "Elementary ion";
case RELATED_ION:
return "Related ion";
case UNKNOWN:
return "Unknown ion type";
default:
throw new UnsupportedOperationException("No name for ion type " + type + ".");
}
}
/**
* Convenience method returning a generic ion based on the given ion type.
*
* @param ionType the ion type
* @param subType the ion subtype
* @param neutralLosses the neutral losses. Null list if none.
* @return a generic ion
*/
public static Ion getGenericIon(IonType ionType, int subType, ArrayList<NeutralLoss> neutralLosses) {
switch (ionType) {
case ELEMENTARY_ION:
return new ElementaryIon("new ElementaryIon", 0.0, subType);
case GLYCAN:
return new Glycan("new Glycan", "new Glycan");
case IMMONIUM_ION:
return new ImmoniumIon(subType);
case PEPTIDE_FRAGMENT_ION:
return new PeptideFragmentIon(subType, neutralLosses);
case TAG_FRAGMENT_ION:
return new TagFragmentIon(subType, neutralLosses);
case PRECURSOR_ION:
return new PrecursorIon(neutralLosses);
case REPORTER_ION:
return ReporterIon.getReporterIon(subType);
case RELATED_ION:
return new RelatedIon(AminoAcid.A, AtomChain.getAtomChain("H"), -1, false);
default:
throw new UnsupportedOperationException("No generic constructor for " + getTypeAsString(ionType) + ".");
}
}
/**
* Convenience method returning a generic ion based on the given ion type
* without neutral losses.
*
* @param ionType the ion type
* @param subType the ion subtype
* @return a generic ion
*/
public static Ion getGenericIon(IonType ionType, int subType) {
switch (ionType) {
case ELEMENTARY_ION:
return new ElementaryIon("new ElementaryIon", 0.0, subType);
case GLYCAN:
return new Glycan("new Glycon", "new Glycon");
case IMMONIUM_ION:
return new ImmoniumIon(subType);
case PEPTIDE_FRAGMENT_ION:
return new PeptideFragmentIon(subType);
case TAG_FRAGMENT_ION:
return new TagFragmentIon(subType);
case PRECURSOR_ION:
return new PrecursorIon();
case REPORTER_ION:
return ReporterIon.getReporterIon(subType);
case RELATED_ION:
return new RelatedIon(AminoAcid.A, AtomChain.getAtomChain("H"), -1, false);
default:
throw new UnsupportedOperationException("No generic constructor for " + getTypeAsString(ionType) + ".");
}
}
}