All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.chem.Molecule Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.chem;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.hfg.bio.HfgBioXML;
import com.hfg.bio.PhysicalProperty;
import com.hfg.exception.UnmodifyableObjectException;
import com.hfg.util.AttributeMgr;
import com.hfg.util.CompareUtil;
import com.hfg.util.collection.CollectionUtil;
import com.hfg.util.StringUtil;
import com.hfg.xml.HfgXML;
import com.hfg.xml.HfgXMLSerializable;
import com.hfg.xml.XMLAttribute;
import com.hfg.xml.XMLNode;
import com.hfg.xml.XMLTag;

//------------------------------------------------------------------------------
/**
 Generic chemical entity.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library 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 library 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 library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class Molecule implements OrganicMatter, HfgXMLSerializable, Cloneable, Comparable { //########################################################################## // PUBLIC FIELDS //########################################################################## public static final Molecule H2O = new Molecule("water").addAtoms(Element.HYDROGEN, 2).addAtoms(Element.OXYGEN, 1).lock(); public static final Molecule NH3 = new Molecule("ammonia").addAtoms(Element.NITROGEN, 1).addAtoms(Element.HYDROGEN, 3).lock(); public static final Molecule NaCl = new Molecule("sodium chloride").addAtoms(Element.SODIUM, 1).addAtoms(Element.CHLORINE, 1).lock(); //########################################################################## // PRIVATE FIELDS //########################################################################## private List mKas; private Map mPropertyMap; private AttributeMgr mAttributeMgr; protected String mName; protected boolean mLocked; protected OrganicMatterImpl mMatter = new OrganicMatterImpl(); //########################################################################## // CONSTRUCTORS //########################################################################## //-------------------------------------------------------------------------- public Molecule() { } //-------------------------------------------------------------------------- public Molecule(String inName) { mName = inName; } //-------------------------------------------------------------------------- public Molecule(String inName, Map inElementalComposition) { mName = inName; mMatter.setElementalComposition(inElementalComposition); } //-------------------------------------------------------------------------- public Molecule(OrganicMatter inInitialValue) { mMatter = new OrganicMatterImpl(inInitialValue); } //-------------------------------------------------------------------------- public Molecule(XMLNode inXML) { mName = inXML.getAttributeValue(HfgBioXML.NAME_ATT); XMLNode compTag = inXML.getOptionalSubtagByName(HfgBioXML.ELEMENTAL_COMP_TAG); if (compTag != null) { for (XMLAttribute attr : compTag.getAttributes()) { addAtoms(Element.valueOf(attr.getName()), Float.parseFloat(attr.getValue())); } } XMLNode attributesTag = inXML.getOptionalSubtagByName(HfgXML.ATTRIBUTES); if (attributesTag != null) { mAttributeMgr = new AttributeMgr(attributesTag); } } //########################################################################## // PUBLIC METHODS //########################################################################## //-------------------------------------------------------------------------- public static Molecule fromChemicalFormula(String inChemicalFormula) { Molecule molecule = null; if (StringUtil.isSet(inChemicalFormula)) { Matter matter = MatterImpl.fromChemicalFormula(inChemicalFormula); molecule = new Molecule(); molecule.addElementalComposition(matter.getElementalComposition()); } return molecule; } //-------------------------------------------------------------------------- public Molecule setName(String inValue) { mName = inValue; return this; } //-------------------------------------------------------------------------- public String name() { return mName; } //-------------------------------------------------------------------------- @Override public String toString() { return name(); } //-------------------------------------------------------------------------- @Override public int hashCode() { int hashcode = mMatter.hashCode(); if (mName != null) { hashcode = hashcode + 31 * mName.hashCode(); } return hashcode; } //-------------------------------------------------------------------------- @Override public boolean equals(Object inObj) { boolean result = false; if (inObj != null) { result = (0 == compareTo(inObj)); } return result; } //-------------------------------------------------------------------------- public int compareTo(Object inObj) { int result = -1; if (inObj != null) { if (inObj instanceof Molecule) { Molecule mol2 = (Molecule) inObj; result = mMatter.compareTo(mol2.mMatter); if (0 == result) { if (mName != null) { result = mName.compareTo(mol2.name()); } else if (mol2.name() != null) { result = -1; } } } else { result = CompareUtil.compare(hashCode(), inObj.hashCode()); } } return result; } //-------------------------------------------------------------------------- /** Returns an unlocked copy of the Molecule. @return an unlocked copy of the Molecule */ public Molecule clone() { Molecule copy = null; try { copy = (Molecule) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("Coding problem! CloneNotSupportedException should not be possible when cloning a " + this.getClass().getSimpleName() + " object!", e); } copy.mMatter = mMatter.clone(); if (mPropertyMap != null) { copy.mPropertyMap = new HashMap(mPropertyMap); } if (mAttributeMgr != null) { // For right now this is a shallow clone of the attributes copy.mAttributeMgr = mAttributeMgr.clone(); } // Clones should be unlocked. copy.mLocked = false; return copy; } //-------------------------------------------------------------------------- public boolean isLocked() { return mLocked; } //-------------------------------------------------------------------------- public Molecule lock() { mLocked = true; return this; } //-------------------------------------------------------------------------- public Molecule addAtoms(Element inElement, int inNum) { return addAtoms(inElement, new Float(inNum)); } //-------------------------------------------------------------------------- public Molecule addAtoms(Element inElement, float inNum) { if (mLocked) throw new UnmodifyableObjectException(mName + " is locked and cannot be modified!"); mMatter.addAtoms(inElement, inNum); return this; } //-------------------------------------------------------------------------- public void setElementalComposition(Map inMap) { mMatter.setElementalComposition(inMap); } //-------------------------------------------------------------------------- public Molecule addElementalComposition(Map inMap) { mMatter.addElementalComposition(inMap); return this; } //-------------------------------------------------------------------------- public Molecule add(OrganicMatter inValue) { return add(inValue, 1); } //-------------------------------------------------------------------------- public Molecule add(OrganicMatter inValue, int inCount) { mMatter.add(inValue, inCount); return this; } //-------------------------------------------------------------------------- public Molecule remove(OrganicMatter inValue) { return remove(inValue, 1); } //-------------------------------------------------------------------------- public Molecule remove(OrganicMatter inValue, int inCount) { mMatter.remove(inValue, inCount); return this; } //-------------------------------------------------------------------------- /** Returns an unmodifiable copy of the elemental composition Map. The keys are Element objects and the values are Floats. Why Floats instead of Integers you ask? Because some amino acid codes such as B and Z are ambiguous averages. @return a Map specifying the Molecule's elemental composition */ public Map getElementalComposition() { return mMatter.getElementalComposition(); } //-------------------------------------------------------------------------- public Double getMonoisotopicMass() { return mMatter.getMonoisotopicMass(); } //-------------------------------------------------------------------------- public Double getAverageMass() { return mMatter.getAverageMass(); } //-------------------------------------------------------------------------- public Double getOrganicAverageMass() { return mMatter.getOrganicAverageMass(); } //-------------------------------------------------------------------------- public void clearCalculatedProperties() { mMatter.clearCalculatedProperties(); } //-------------------------------------------------------------------------- /** Returns a chemical formula String like 'C5H11NO'. If carbon is present, it is listed first followed by the other elements in ascending mass order. Symbols for pure elements are enclosed in square brackets such as '[2H]2O' for deuterated water. @return the Molecule's chemical formula string */ public String getChemicalFormula() { return mMatter.getChemicalFormula(); } //-------------------------------------------------------------------------- public XMLNode toXMLNode() { XMLNode node = new XMLTag(HfgBioXML.MOL_TAG); if (StringUtil.isSet(name())) node.setAttribute(HfgBioXML.NAME_ATT, name()); if (getMonoisotopicMass() != null) node.setAttribute(HfgBioXML.MONO_MASS_ATT, formatMassString(getMonoisotopicMass())); if (getAverageMass() != null) node.setAttribute(HfgBioXML.AVG_MASS_ATT, formatMassString(getAverageMass())); // TODO: Add an organic mass tag? Map elementalCompositionMap = getElementalComposition(); if (CollectionUtil.hasValues(elementalCompositionMap)) { XMLNode elementalCompTag = new XMLTag(HfgBioXML.ELEMENTAL_COMP_TAG); node.addSubtag(elementalCompTag); for (Map.Entry entry : elementalCompositionMap.entrySet()) { elementalCompTag.setAttribute(entry.getKey().getName(), entry.getValue()); } } if (CollectionUtil.hasValues(getKas())) { XMLNode kasTag = new XMLTag(HfgBioXML.KAS_TAG); node.addSubtag(kasTag); for (IonizableGroup grp : getKas()) { kasTag.addSubtag(grp.toXMLNode()); } } if (mAttributeMgr != null) { node.addSubtag(mAttributeMgr.toXMLNode()); } return node; } //-------------------------------------------------------------------------- public Molecule addKa(IonizableGroup inValue) { return addKa(inValue, 1); } //-------------------------------------------------------------------------- public Molecule addKa(IonizableGroup inValue, int inCount) { if (isLocked()) throw new UnmodifyableObjectException(name() + " is locked and cannot be modified!"); if (null == mKas) { mKas = new ArrayList<>(3); } for (int i = 0; i < inCount; i++) { mKas.add(inValue); } return this; } //-------------------------------------------------------------------------- /** Returns a List of IonizableGroup objects. @return List of IonizableGroups */ public List getKas() { return mKas; } //-------------------------------------------------------------------------- public Double getPhysicalProperty(PhysicalProperty inProperty) { Double value = null; if (mPropertyMap != null) { value = mPropertyMap.get(inProperty); } return value; } //-------------------------------------------------------------------------- public Molecule setPhysicalProperty(PhysicalProperty inProperty, Double inValue) { if (null == mPropertyMap) { mPropertyMap = new HashMap<>(5); } mPropertyMap.put(inProperty, inValue); return this; } //-------------------------------------------------------------------------- public void setAttribute(String inName, Object inValue) { getOrInitAttributeMgr().setAttribute(inName, inValue); } //-------------------------------------------------------------------------- public boolean hasAttribute(String inName) { return mAttributeMgr != null && getOrInitAttributeMgr().hasAttribute(inName); } //-------------------------------------------------------------------------- public Object getAttribute(String inName) { return getOrInitAttributeMgr().getAttribute(inName); } //-------------------------------------------------------------------------- public Collection getAttributeNames() { return getOrInitAttributeMgr().getAttributeNames(); } //-------------------------------------------------------------------------- public void clearAttributes() { if (mAttributeMgr != null) { mAttributeMgr.clearAttributes(); } } //-------------------------------------------------------------------------- public Object removeAttribute(String inName) { Object attr = null; if (mAttributeMgr != null) { attr = getOrInitAttributeMgr().removeAttribute(inName); } return attr; } //########################################################################## // PROTECTED METHODS //########################################################################## //-------------------------------------------------------------------------- /** If the elemental composition is known, use setElementalComposition() and the masses will be derived automatically; this method is for use in those (hopefully) rare times when the mass is known but not the elemental composition. @param inValue the monoisotopic mass value to use for the Molecule @return this Molecule object to enable method chaining */ protected Molecule setMonoisotopicMass(Double inValue) { mMatter.setMonoisotopicMass(inValue); return this; } //-------------------------------------------------------------------------- /** If the elemental composition is known, use setElementalComposition() and the masses will be derived automatically; this method is for use in those (hopefully) rare times when the mass is known but not the elemental composition. @param inValue the average mass value to use for the Molecule @return this Molecule object to enable method chaining */ protected Molecule setAverageMass(Double inValue) { mMatter.setAverageMass(inValue); return this; } //-------------------------------------------------------------------------- /** If the elemental composition is known, use setElementalComposition() and the masses will be derived automatically; this method is for use in those (hopefully) rare times when the mass is known but not the elemental composition. @param inValue the organic average mass value to use for the Molecule @return this Molecule object to enable method chaining */ protected Molecule setOrganicAverageMass(Double inValue) { mMatter.setOrganicAverageMass(inValue); return this; } //-------------------------------------------------------------------------- protected static String formatMassString(double inValue) { String massString = inValue + ""; int index = massString.indexOf("."); // More than 6 decimal places? Round to 6. if (index > 0 && massString.length() - index > 6) { massString = String.format("%.6f", inValue); } return massString; } //########################################################################## // PRIVATE METHODS //########################################################################## //-------------------------------------------------------------------------- private AttributeMgr getOrInitAttributeMgr() { if (null == mAttributeMgr) { mAttributeMgr = new AttributeMgr(); } return mAttributeMgr; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy