package com.compomics.util.general;
import com.compomics.util.enumeration.MolecularElement;
import com.compomics.util.protein.MolecularFormula;
import org.apache.commons.math.distribution.BinomialDistributionImpl;
import org.apache.log4j.Logger;
import java.util.Vector;
/**
* This class calculates the isotopic distribution based on a molecular formula.
*
* Created by IntelliJ IDEA.
* User: Niklaas
* Date: 11-Aug-2010
* Time: 09:13:06
*/
public class IsotopicDistribution {
// Class specific log4j logger for AASequenceImpl instances.
Logger logger = Logger.getLogger(IsotopicDistribution.class);
/**
* The result of the isotopic distributions calculation. Percentage of the total contribution
*/
private Vector<Double> iPercTot = null;
/**
* The result of the isotopic distributions calculation. Percentage of the contribution compared to the maximum
*/
private Vector<Double> iPercMax = null;
/**
* The molecular formula
*/
private MolecularFormula iMolecularFormula;
/**
* boolean that indicates if a LABEL isotopic distribution must be used
*/
private boolean iLabel = false;
/**
* int with the dalton difference
*/
private int iLabelDaltonDifference;
/**
* Constructor
* @param lFormula MolecularFormula
*/
public IsotopicDistribution(MolecularFormula lFormula){
this.iMolecularFormula = lFormula;
}
/**
* Constructor
* @param lFormula MolecularFormula
* @param lDaltonDifference The label dalton difference
*/
public IsotopicDistribution(MolecularFormula lFormula, int lDaltonDifference){
this.iMolecularFormula = lFormula;
this.iLabel = true;
this.iLabelDaltonDifference = lDaltonDifference;
}
/**
* This method set the label dalton difference
* @param lLabelDifference The label dalton difference
*/
public void setLabelDifference(int lLabelDifference){
this.iLabel = true;
this.iLabelDaltonDifference = lLabelDifference;
}
/**
* This method will do the calculations
*/
public void calculate(){
Vector<Vector<Double>> lPerc = new Vector<Vector<Double>>();
Vector<Integer> lNumbers = new Vector<Integer>();
Vector<Integer> lDaltonDifferences = new Vector<Integer>();
Vector<BinomialDistributionImpl> lBinomDistributions = new Vector<BinomialDistributionImpl>();
Vector<IsotopicElement> lElements = IsotopicElement.getAllIsotopicElements(this.getClass(), logger);
for(int e = 0; e<lElements.size(); e ++){
IsotopicElement lElmnt = lElements.get(e);
int lCount = iMolecularFormula.getElementCount(lElmnt.getElement());
if(lCount > 0){
lNumbers.add(lCount);
Vector<Double> lPercElement = new Vector<Double>();
lPerc.add(lPercElement);
lBinomDistributions.add(new BinomialDistributionImpl(lCount, lElmnt.getOccurrence()));
lDaltonDifferences.add(lElmnt.getDaltonDifference());
}
}
for(int i = 0; i<15; i++){
for(int p = 0; p<lPerc.size(); p ++){
Vector<Double> lPercElement = lPerc.get(p);
BinomialDistributionImpl lBinom = lBinomDistributions.get(p);
int lDaltonDiff = lDaltonDifferences.get(p);
if(lDaltonDiff > 1){
if(i%lDaltonDiff == 0){
lPercElement.add(lBinom.probability(i/lDaltonDiff)*lNumbers.get(p));
} else {
lPercElement.add(0.0);
}
} else {
lPercElement.add(lBinom.probability(i)*lNumbers.get(p));
}
}
}
Vector<Double> lPercTotal = new Vector<Double>();
for(int i = 0 ; i<lPerc.size(); i ++){
if(i==0){
for(int j = 0; j<lPerc.get(i).size(); j ++){
lPercTotal.add(lPerc.get(i).get(j));
}
} else {
if(lNumbers.get(i) != 0){
Vector<Double> lTempTotal = new Vector<Double>();
for(int k = 1; k<=lPercTotal.size(); k ++){
double lTempValue = 0.0;
for(int l = 0; l<k; l ++){
if(lPercTotal.get(l) != 0.0 && lPerc.get(i).get(k - l - 1) != 0.0){
lTempValue = lTempValue + ((lPercTotal.get(l))*lPerc.get(i).get(k - l - 1));
}
}
lTempTotal.add(lTempValue);
}
lPercTotal = lTempTotal;
}
}
}
double lMax = 0.0;
for(int k = 0; k<lPercTotal.size(); k ++){
for(int e = 0; e<lNumbers.size(); e ++){
lPercTotal.set(k, lPercTotal.get(k)/lNumbers.get(e));
}
if(lPercTotal.get(k)>lMax){
lMax = lPercTotal.get(k);
}
}
if(iLabel){
lMax = 0.0;
Vector<Double> lTempPercTotal = new Vector<Double>();
for(int i = 0; i<lPercTotal.size(); i ++){
double lTempPeak1 = lPercTotal.get(i);
double lTempPeak2 = 0.0;
if(i-iLabelDaltonDifference >= 0){
lTempPeak2 = lPercTotal.get(i-iLabelDaltonDifference);
}
lTempPeak1 = lTempPeak1 + lTempPeak2;
lTempPercTotal.add(lTempPeak1/2.0);
}
for(int k = 0; k<lTempPercTotal.size(); k ++){
if(lTempPercTotal.get(k)>lMax){
lMax = lTempPercTotal.get(k);
}
}
lPercTotal = lTempPercTotal;
}
iPercTot = lPercTotal;
iPercMax = new Vector<Double>();
for(int k = 0; k<iPercTot.size(); k ++){
iPercMax.add(iPercTot.get(k)/lMax);
}
}
/**
* This will calculate the isotopic distribution pattern for the given elements. Labeled atoms (13C, Deut, 15N) must not be given since these are always limited to one peak (100% occurrence)
* and do not contribute to the distribution pattern
* @param lC Number of C atoms
* @param lN Number of N atoms
* @param lH Number of H atoms
* @param lO Number of O atoms
* @param lS Number of S atoms
*/
public IsotopicDistribution(int lC, int lN, int lH, int lO, int lS){
iMolecularFormula = new MolecularFormula();
iMolecularFormula.addElement(MolecularElement.C, lC);
iMolecularFormula.addElement(MolecularElement.N, lN);
iMolecularFormula.addElement(MolecularElement.H, lH);
iMolecularFormula.addElement(MolecularElement.O, lO);
iMolecularFormula.addElement(MolecularElement.S, lS);
}
/**
* Getter for result of the isotopic distributions calculation. Percentage of the contribution compared to the maximum.
* @return Array of doubles with %, location in array corresponds with the number of the peak
*/
public Double[] getPercMax() {
if(iPercMax == null){
calculate();
}
Double[] lReturn = new Double[iPercMax.size()];
iPercMax.toArray(lReturn);
return lReturn;
}
/**
* Getter for result of the isotopic distributions calculation. Percentage of the total contribution.
* @return Array of doubles with %, location in array corresponds with the number of the peak
*/
public Double[] getPercTot() {
if(iPercTot == null){
calculate();
}
Double[] lReturn = new Double[iPercTot.size()];
iPercTot.toArray(lReturn);
return lReturn;
}
}