/* $Revision$ $Author$ $Date$ * * Copyright (C) 2007 Miguel Rojasch <miguelrojasch@users.sf.net> * * Contact: cdk-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.formula; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import org.openscience.cdk.annotations.TestClass; import org.openscience.cdk.config.IsotopeFactory; import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IIsotope; import org.openscience.cdk.interfaces.IMolecularFormula; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; import org.openscience.cdk.tools.manipulator.MolecularFormulaManipulator; /** * Generates all Combinatorial chemical isotopes given a structure. * * @cdk.module formula * @author Miguel Rojas Cherto * @cdk.created 2007-11-20 * @cdk.githash * * @cdk.keyword isotope pattern * */ @TestClass("org.openscience.cdk.formula.IsotopePatternGeneratorTest") public class IsotopePatternGenerator{ private IChemObjectBuilder builder = null; private IsotopeFactory isoFactory; private IsotopePattern abundance_Mass = null; private ILoggingTool logger = LoggingToolFactory.createLoggingTool(IsotopePatternGenerator.class); /** Minimal abundance of the isotopes to be added in the combinatorial search.*/ private double minAbundance = .1; /** * Constructor for the IsotopeGenerator. */ public IsotopePatternGenerator(){ this(0.1); } /** * Constructor for the IsotopeGenerator. * * @param minAb Minimal abundance of the isotopes to be added * in the combinatorial search * */ public IsotopePatternGenerator(double minAb){ minAbundance = minAb; logger.info("Generating all Isotope structures with IsotopeGenerator"); } /** * Get all combinatorial chemical isotopes given a structure. * * @param molFor The IMolecularFormula to start * @return A IsotopePattern object containing the different combinations */ public IsotopePattern getIsotopes(IMolecularFormula molFor){ if(builder==null){ try { isoFactory = IsotopeFactory.getInstance(molFor.getBuilder()); builder = molFor.getBuilder(); } catch (Exception e) { e.printStackTrace(); } } String mf = MolecularFormulaManipulator.getString(molFor,true); // Divide the chemical formula into tokens (element and coefficients) HashMap<String, Integer> tokens = new HashMap<String, Integer>(); IMolecularFormula molecularFormula = MolecularFormulaManipulator.getMajorIsotopeMolecularFormula(mf, builder); for(IIsotope isos :molecularFormula.isotopes()) tokens.put(isos.getSymbol(), molecularFormula.getIsotopeCount(isos)); int atomCount; for(IIsotope isos : molecularFormula.isotopes()){ String elementSymbol = isos.getSymbol(); atomCount = tokens.get(elementSymbol); for (int i = 0; i < atomCount; i++) { if (!calculateAbundanceAndMass(elementSymbol)) { } } } IsotopePattern isoP = IsotopePatternManipulator.sortAndNormalizedByIntensity(abundance_Mass); isoP = cleanAbundance(isoP, minAbundance); IsotopePattern isoPattern = IsotopePatternManipulator.sortByMass(isoP); return isoPattern; } /** * Calculates the mass and abundance of all isotopes generated by adding one * atom. Receives the periodic table element and calculate the isotopes, if * there exist a previous calculation, add these new isotopes. In the * process of adding the new isotopes, remove those that has an abundance * less than setup parameter minAbundance, and remove duplicated masses. * * @param elementSymbol The chemical element symbol * @return */ private boolean calculateAbundanceAndMass(String elementSymbol) { IIsotope[] isotopes = isoFactory.getIsotopes(elementSymbol); if (isotopes == null) return false; if (isotopes.length == 0) return false; double mass, previousMass, abundance, totalAbundance, newAbundance; HashMap<Double, Double> isotopeMassAndAbundance = new HashMap<Double, Double>(); IsotopePattern currentISOPattern = new IsotopePattern(); // Generate isotopes for the current atom (element) for (int i = 0; i < isotopes.length; i++) { mass = isotopes[i].getExactMass(); abundance = isotopes[i].getNaturalAbundance(); currentISOPattern.addIsotope(new IsotopeContainer(mass, abundance)); } // Verify if there is a previous calculation. If it exists, add the new // isotopes if (abundance_Mass == null) { abundance_Mass = currentISOPattern; return true; } else { for (int i = 0; i < abundance_Mass.getNumberOfIsotopes(); i++) { totalAbundance = abundance_Mass.getIsotopes().get(i).getIntensity(); if (totalAbundance == 0) continue; for (int j = 0; j < currentISOPattern.getNumberOfIsotopes(); j++) { abundance = currentISOPattern.getIsotopes().get(j).getIntensity(); mass = abundance_Mass.getIsotopes().get(i).getMass(); if (abundance == 0) continue; newAbundance = totalAbundance * abundance * 0.01f; mass += currentISOPattern.getIsotopes().get(j).getMass(); // Filter duplicated masses previousMass = searchMass(isotopeMassAndAbundance.keySet(), mass); if (isotopeMassAndAbundance.containsKey(previousMass)) { newAbundance += isotopeMassAndAbundance .get(previousMass); mass = previousMass; } // Filter isotopes too small if (isNotZero(newAbundance)) { isotopeMassAndAbundance.put(mass, newAbundance); } previousMass = 0; } } Iterator<Double> itr = isotopeMassAndAbundance.keySet().iterator(); int i = 0; abundance_Mass = new IsotopePattern(); while (itr.hasNext()) { mass = itr.next(); abundance_Mass.addIsotope(new IsotopeContainer(mass, isotopeMassAndAbundance.get(mass))); i++; } } return true; } /** * Search the key mass in this Set. * * @param keySet The Set object * @param mass The mass to look for * @return The key value */ private double searchMass(Set<Double> keySet, double mass) { double TOLERANCE = 0.00005f; double diff; for (double key : keySet) { diff = Math.abs(key - mass); if (diff < TOLERANCE) return key; } return 0.0d; } /** * Detection if the value is zero. * * @param number The number to analyze * @return TRUE, if it zero */ private boolean isNotZero(double number) { double pow = (double) Math.pow(10, 6); int fraction = (int) (number * pow); if (fraction <= 0) return false; return true; } /** * Normalize the intensity (relative abundance) of all isotopes in relation * of the most abundant isotope. * * @param isopattern The IsotopePattern object * @param minAbundance The minimum abundance * @return The IsotopePattern cleaned */ private IsotopePattern cleanAbundance(IsotopePattern isopattern, double minAbundance) { double intensity, biggestIntensity = 0.0f; for (IsotopeContainer sc : isopattern.getIsotopes()) { intensity = sc.getIntensity(); if (intensity > biggestIntensity) biggestIntensity = intensity; } for (IsotopeContainer sc : isopattern.getIsotopes()) { intensity = sc.getIntensity(); intensity /= biggestIntensity; if (intensity < 0) intensity = 0; sc.setIntensity(intensity); } IsotopePattern sortedIsoPattern = new IsotopePattern(); sortedIsoPattern.setMonoIsotope(new IsotopeContainer(isopattern.getIsotopes().get(0).getMass(),isopattern.getIsotopes().get(0).getIntensity())); for (int i = 1; i < isopattern.getNumberOfIsotopes();i++) { if (isopattern.getIsotopes().get(i).getIntensity() >= (minAbundance )) sortedIsoPattern.addIsotope(new IsotopeContainer(isopattern.getIsotopes().get(i).getMass(),isopattern.getIsotopes().get(i).getIntensity())); } return sortedIsoPattern; } }