/* * 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.resourcesdb.atom; import java.util.HashMap; import java.util.List; import org.eurocarbdb.resourcesdb.Config; import org.eurocarbdb.resourcesdb.ResourcesDbException; import org.eurocarbdb.resourcesdb.monosaccharide.MonosaccharideException; import org.eurocarbdb.resourcesdb.util.StringUtils; /** * Class to store / handle element compositions (element counts). * @author Thomas Lütteke * */ public class Composition implements java.lang.Cloneable { private HashMap<String, Integer> compositionMap; /** * Constructor to create an empty composition */ public Composition() { this.setCompositionMap(new HashMap<String, Integer>()); } /** * Constructor to create a new composition and initialize it using a chemical formula * @param formula a chemical formula like C6H12O6 or CH2OHCOCHOHCH2Cl * @throws ResourcesDbException in case the formula cannot be parsed properly */ public Composition(String formula) throws ResourcesDbException { this.parseFormula(formula); } /** * Constructor to create a new composition and initialize it using an already existing composition * @param compo a Composition object */ public Composition(Composition compo) { this.addComposition(compo); } //***************************************************************************** //*** getters/setters: ******************************************************** //***************************************************************************** public HashMap<String, Integer> getCompositionMap() { return this.compositionMap; } private void setCompositionMap(HashMap<String, Integer> composMap) { this.compositionMap = composMap; } public int getElementCount(Periodic el) { if(el == null) { return 0; } return getElementCount(el.getSymbol()); } public int getElementCount(String elSymbol) { if(getCompositionMap().get(elSymbol) == null) { return 0; } return getCompositionMap().get(elSymbol).intValue(); } public void setElementCount(Periodic el, int value) { getCompositionMap().put(el.getSymbol(), new Integer(value)); } public void setElementCount(String elSymbol, int value) { getCompositionMap().put(elSymbol, new Integer(value)); } //***************************************************************************** //*** methods to change composition: ****************************************** //***************************************************************************** /** * Increase the number of atoms of a given element type by a given number * @param el the element type * @param step the value to be added to the element count */ public void increaseCount(Periodic el, int step) { Integer countObj = getCompositionMap().get(el.getSymbol()); if(countObj == null) { countObj = new Integer(step); } else { countObj += step; } getCompositionMap().put(el.getSymbol(), countObj); } /** * Increase the number of atoms of a given element type by 1 * @param el the element type */ public void increaseCount(Periodic el) { increaseCount(el, 1); } public void increaseCount(String elSymbol, int step) { Integer countObj = getCompositionMap().get(elSymbol); if(countObj == null) { countObj = new Integer(step); } else { countObj += step; } getCompositionMap().put(elSymbol, countObj); } /** * Decrease the number of atoms of a given element type by a given number * @param el the element type * @param step the value to be substracted from the element count */ public void decreaseCount(Periodic el, int step) { Integer countObj = getCompositionMap().get(el.getSymbol()); if(countObj == null) { countObj = new Integer(-1 * step); } else { countObj -= step; } getCompositionMap().put(el.getSymbol(), countObj); } /** * Decrease the number of atoms of a given element type by 1 * @param el the element type */ public void decreaseCount(Periodic el) { decreaseCount(el, 1); } /** * Set the composition using a chemical formula. * This method initializes the composition, existing element counts are deleted. * To preserve the existing counts and just add the ones from the formula use the addFormula(Str) method instead. * @param formula a chemical formula like C6H12O6 or CH2OHCOCHOHCH2Cl * @throws ResourcesDbException in case the formula cannot be parsed properly */ public void parseFormula(String formula) throws ResourcesDbException { //*** empty composition map: *** if(this.getCompositionMap() != null) { this.getCompositionMap().clear(); } //*** get elements and counts from formula: *** this.addFormula(formula); } /** * Add a chemical formula to this composition. * Element counts yielded from the formula are added to ones that are already present in this composition. * @param formula a chemical formula like C6H12O6 or CH2OHCOCHOHCH2Cl * @throws ResourcesDbException in case the formula cannot be parsed properly */ public void addFormula(String formula) throws ResourcesDbException { //*** set composition map if not done yet (avoid null pointer exceptions): *** if(this.getCompositionMap() == null) { this.setCompositionMap(new HashMap<String, Integer>()); } //*** get elements and counts from formula: *** String subformula; if(formula != null) { subformula = formula; } else { subformula = ""; } while(subformula.length() > 0) { if(subformula.startsWith(" ")) { //*** ignore blanks *** subformula = subformula.substring(1); continue; } if(subformula.startsWith("(")) { //*** parse subcomposition *** int closeBracketPos = StringUtils.findClosingBracketPosition(subformula); if(closeBracketPos > 0) { Composition subCompo = new Composition(subformula.substring(1, closeBracketPos)); subformula = subformula.substring(closeBracketPos + 1); int count; if(subformula.length() == 0 || subformula.matches("^[A-Z()].*")) { count = 1; } else { count = 0; while(subformula.matches("^[0-9].*")) { count = 10 * count + Integer.parseInt(subformula.substring(0, 1)); subformula = subformula.substring(1); } } if(count != 1) { for(String elSymbol : subCompo.getCompositionMap().keySet()) { subCompo.getCompositionMap().put(elSymbol, subCompo.getElementCount(elSymbol) * count); } } this.addComposition(subCompo); continue; } } boolean foundElement = false; //for(Periodic el : Periodic.getElementsList()) { for(Periodic el : Periodic.values()) { String symbol = el.getSymbol(); if(subformula.matches("^" + symbol + "[0-9A-Z()].*") || subformula.equals(symbol)) { subformula = subformula.substring(symbol.length()); foundElement = true; int count; if(subformula.length() == 0 || subformula.matches("^[A-Z()].*")) { count = 1; } else { count = 0; while(subformula.matches("^[0-9].*")) { count = 10 * count + Integer.parseInt(subformula.substring(0, 1)); subformula = subformula.substring(1); } } this.increaseCount(el, count); break; } } if(!foundElement) { throw new MonosaccharideException("Cannot parse formula " + formula); } } } /** * Add another composition to this composition. * The element counts of the other composition are added to the ones of this composition. * @param compo the composition to add */ public void addComposition(Composition compo) { //*** set composition map if not done yet (avoid null pointer exceptions): *** if(this.getCompositionMap() == null) { this.setCompositionMap(new HashMap<String, Integer>()); } //*** add element counts: *** for(String elSymbol : compo.getCompositionMap().keySet()) { Integer elCount = compo.getElementCount(elSymbol); if(elCount == null || elCount.intValue() == 0) { continue; } this.increaseCount(elSymbol, elCount.intValue()); } } /** * Add a list of atoms to this composition * @param atomList the atoms to add */ public void addAtoms(List<Atom> atomList) { for(Atom a : atomList) { this.addAtom(a); } } /** * Add a single atom to this composition * @param a the atom to add */ public void addAtom(Atom a) { this.increaseCount(a.getElement()); } //***************************************************************************** //*** mass related methods: *************************************************** //***************************************************************************** /** * Calculate the average mass of the atoms contained in this composition * @return the average mass */ public double getAvgMass() { double mass = 0.0; for(String elSymbol : this.getCompositionMap().keySet()) { try { Periodic el = Periodic.getElementBySymbol(elSymbol); Integer elCount = this.getElementCount(el); if(elCount != null) { mass += elCount.intValue() * el.getAvgMass().doubleValue(); } } catch(ResourcesDbException me) { if(Config.getGlobalConfig().isPrintErrorMsgs()) { System.err.println("Exception: " + me); me.printStackTrace(); } } } return(mass); } /** * Calculate the monoisotopic mass of the atoms contained in this composition * @return the monoisotopic mass */ public double getMonoMass() { double mass = 0.0; for(String elSymbol : this.getCompositionMap().keySet()) { try { Periodic el = Periodic.getElementBySymbol(elSymbol); int elCount = this.getElementCount(el); if(elCount != 0) { mass += elCount * el.getMostAbundantIsotope().getMass().doubleValue(); } } catch(ResourcesDbException me) { if(Config.getGlobalConfig().isPrintErrorMsgs()) { System.err.println("Exception: " + me); me.printStackTrace(); } } } return(mass); } //***************************************************************************** //*** other methods: ********************************************************** //***************************************************************************** /** * Convert the composition into a chemical formula string * @return the chemical formula representing this composition */ public String toFormula() { String outStr = ""; /*for(Periodic el : Periodic.getElementsList()) { Integer elCount = this.getElementCount(el); if(elCount != null && elCount.intValue() != 0) { outStr += el.getSymbol() + elCount.intValue(); } }*/ for(String elemSymbol : this.getCompositionMap().keySet()) { Integer elCount = this.getElementCount(elemSymbol); if(elCount != null && elCount.intValue() != 0) { outStr += elemSymbol + elCount.intValue(); } } return(outStr); } public String toWebFormula() { String outStr = ""; /*for(Periodic el : Periodic.getElementsList()) { Integer elCount = this.getElementCount(el); if(elCount != null && elCount.intValue() != 0) { outStr += el.getSymbol() + "<sub>" + elCount.intValue() + "</sub>"; } }*/ for(String elemSymbol : this.getCompositionMap().keySet()) { Integer elCount = this.getElementCount(elemSymbol); if(elCount != null && elCount.intValue() != 0) { outStr += elemSymbol + "<sub>" + elCount.intValue() + "</sub>"; } } return outStr; } public String toString() { String outStr = "Composition:"; /*for(Periodic el : Periodic.getElementsList()) { Integer elCount = this.getElementCount(el); if(elCount != null && elCount.intValue() != 0) { outStr += " " + el.getSymbol() + elCount.intValue(); } }*/ for(String elemSymbol : this.getCompositionMap().keySet()) { Integer elCount = this.getElementCount(elemSymbol); if(elCount != null && elCount.intValue() != 0) { outStr += " " + elemSymbol + elCount.intValue(); } } return(outStr); } public Composition clone() { Composition retComp = new Composition(this); return(retComp); } }