/* $Revision$ $Author$ $Date$
*
* Copyright (C) 2007-2008 Egon Willighagen <egonw@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, version 2.1.
*
* 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.atomtype;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.config.AtomTypeFactory;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.exception.NoSuchAtomException;
import org.openscience.cdk.graph.SpanningTree;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IAtomType;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IPseudoAtom;
import org.openscience.cdk.interfaces.IRing;
import org.openscience.cdk.interfaces.IRingSet;
import org.openscience.cdk.interfaces.ISingleElectron;
import org.openscience.cdk.interfaces.IAtomType.Hybridization;
/**
* Atom Type matcher that perceives atom types as defined in the CDK atom type list
* <code>org/openscience/cdk/dict/data/cdk-atom-types.owl</code>.
* If there is not an atom type defined for the tested atom, then NULL
* is returned.
*
* @author egonw
* @cdk.created 2007-07-20
* @cdk.module core
* @cdk.githash
* @cdk.bug 1802998
*/
@TestClass("org.openscience.cdk.atomtype.CDKAtomTypeMatcherTest")
public class CDKAtomTypeMatcher implements IAtomTypeMatcher {
public final static int REQUIRE_NOTHING = 1;
public final static int REQUIRE_EXPLICIT_HYDROGENS = 2;
private AtomTypeFactory factory;
private int mode;
private static Map<Integer,Map<IChemObjectBuilder,CDKAtomTypeMatcher>>
factories = new Hashtable<Integer,Map<IChemObjectBuilder,CDKAtomTypeMatcher>>(1);
private CDKAtomTypeMatcher(IChemObjectBuilder builder, int mode) {
factory = AtomTypeFactory.getInstance(
"org/openscience/cdk/dict/data/cdk-atom-types.owl",
builder
);
this.mode = mode;
}
@TestMethod("testGetInstance_IChemObjectBuilder")
public static CDKAtomTypeMatcher getInstance(IChemObjectBuilder builder) {
return getInstance(builder, REQUIRE_NOTHING);
}
@TestMethod("testGetInstance_IChemObjectBuilder_int")
public static CDKAtomTypeMatcher getInstance(IChemObjectBuilder builder, int mode) {
if (!factories.containsKey(mode))
factories.put(mode, new Hashtable<IChemObjectBuilder,CDKAtomTypeMatcher>(1));
if (!factories.get(mode).containsKey(builder))
factories.get(mode).put(builder, new CDKAtomTypeMatcher(builder, mode));
return factories.get(mode).get(builder);
}
@TestMethod("testFindMatchingAtomType_IAtomContainer")
public IAtomType[] findMatchingAtomType(IAtomContainer atomContainer) throws CDKException {
IAtomType[] types = new IAtomType[atomContainer.getAtomCount()];
int typeCounter = 0;
for (IAtom atom : atomContainer.atoms()) {
types[typeCounter] = findMatchingAtomType(atomContainer, atom);
typeCounter++;
}
return types;
}
@TestMethod("testFindMatchingAtomType_IAtomContainer_IAtom")
public IAtomType findMatchingAtomType(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
IAtomType type = null;
if (atom instanceof IPseudoAtom) {
return factory.getAtomType("X");
}
if ("C".equals(atom.getSymbol())) {
type = perceiveCarbons(atomContainer, atom);
} else if ("Li".equals(atom.getSymbol())) {
type = perceiveLithium(atomContainer, atom);
} else if ("O".equals(atom.getSymbol())) {
type = perceiveOxygens(atomContainer, atom);
} else if ("N".equals(atom.getSymbol())) {
type = perceiveNitrogens(atomContainer, atom);
} else if ("H".equals(atom.getSymbol())) {
type = perceiveHydrogens(atomContainer, atom);
} else if ("S".equals(atom.getSymbol())) {
type = perceiveSulphurs(atomContainer, atom);
} else if ("P".equals(atom.getSymbol())) {
type = perceivePhosphors(atomContainer, atom);
} else if ("Si".equals(atom.getSymbol())) {
type = perceiveSilicon(atomContainer, atom);
} else if ("B".equals(atom.getSymbol())) {
type = perceiveBorons(atomContainer, atom);
} else if ("Be".equals(atom.getSymbol())) {
type = perceiveBeryllium(atomContainer, atom);
} else if ("Se".equals(atom.getSymbol())) {
type = perceiveSelenium(atomContainer, atom);
} else if ("Ga".equals(atom.getSymbol())) {
type = perceiveGallium(atomContainer, atom);
} else if ("Ge".equals(atom.getSymbol())) {
type = perceiveGermanium(atomContainer, atom);
} else {
if (type == null) type = perceiveHalogens(atomContainer, atom);
if (type == null) type = perceiveCommonSalts(atomContainer, atom);
if (type == null) type = perceiveOrganometallicCenters(atomContainer, atom);
if (type == null) type = perceiveNobelGases(atomContainer, atom);
}
return type;
}
private IAtomType perceiveGallium(IAtomContainer atomContainer, IAtom atom) throws CDKException {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE &&
atomContainer.getConnectedAtomsCount(atom) <= 3) {
IAtomType type = getAtomType("Ga");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == 3) {
IAtomType type = getAtomType("Ga.3plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private IAtomType perceiveGermanium(IAtomContainer atomContainer, IAtom atom) throws CDKException {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE &&
atomContainer.getConnectedAtomsCount(atom) <= 4) {
IAtomType type = getAtomType("Ge");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private IAtomType perceiveSelenium(IAtomContainer atomContainer, IAtom atom) throws CDKException {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE && atomContainer.getConnectedAtomsCount(atom) <= 2) {
IAtomType type = getAtomType("Se.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private IAtomType perceiveBorons(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (atom.getFormalCharge() == -1 &&
maxBondOrder == IBond.Order.SINGLE &&
atomContainer.getConnectedAtomsCount(atom) <= 4) {
IAtomType type = getAtomType("B.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedAtomsCount(atom) <= 3) {
IAtomType type = getAtomType("B");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private IAtomType perceiveBeryllium(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
if (atom.getFormalCharge() == -2 &&
atomContainer.getMaximumBondOrder(atom) == IBond.Order.SINGLE &&
atomContainer.getConnectedAtomsCount(atom) <= 4) {
IAtomType type = getAtomType("Be.2minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private IAtomType perceiveCarbonRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("C.radical.planar");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedBondsCount(atom) <= 3) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("C.radical.planar");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("C.radical.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == IBond.Order.TRIPLE) {
IAtomType type = getAtomType("C.radical.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveCarbons(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
// if hybridization is given, use that
if (hasOneSingleElectron(atomContainer, atom)) {
return perceiveCarbonRadicals(atomContainer, atom);
} else if (hasHybridization(atom) && !isCharged(atom)) {
if (atom.getHybridization() == Hybridization.SP2) {
IAtomType type = getAtomType("C.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getHybridization() == Hybridization.SP3) {
IAtomType type = getAtomType("C.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getHybridization() == Hybridization.SP1) {
IAtomType type = getAtomType("C.sp");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFlag(CDKConstants.ISAROMATIC)) {
IAtomType type = getAtomType("C.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (isCharged(atom)) {
if (atom.getFormalCharge() == 1) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("C.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE) {
IAtomType type = getAtomType("C.plus.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
IAtomType type = getAtomType("C.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
IAtomType type = getAtomType("C.plus.planar");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if (atom.getFormalCharge() == -1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE &&
atomContainer.getConnectedBondsCount(atom) <= 3) {
if (isRingAtom(atom, atomContainer) && bothNeighborsAreSp2(atom, atomContainer)) {
IAtomType type = getAtomType("C.minus.planar");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("C.minus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE &&
atomContainer.getConnectedBondsCount(atom) <= 3) {
IAtomType type = getAtomType("C.minus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE &&
atomContainer.getConnectedBondsCount(atom) <= 1) {
IAtomType type = getAtomType("C.minus.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if (atomContainer.getConnectedBondsCount(atom) > 4) {
// FIXME: I don't perceive carbons with more than 4 connections yet
return null;
} else { // OK, use bond order info
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.QUADRUPLE) {
// WTF??
return null;
} else if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE) {
IAtomType type = getAtomType("C.sp");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
// OK, one or two double bonds?
int doubleBondCount = countAttachedDoubleBonds(atomContainer, atom);
if (doubleBondCount == 2) {
IAtomType type = getAtomType("C.sp");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (doubleBondCount == 1) {
IAtomType type = getAtomType("C.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else {
if (hasAromaticBond(atomContainer, atom)) {
IAtomType type = getAtomType("C.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("C.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private boolean hasOneSingleElectron(IAtomContainer atomContainer, IAtom atom) {
Iterator<ISingleElectron> singleElectrons = atomContainer.singleElectrons().iterator();
while (singleElectrons.hasNext()) {
if (singleElectrons.next().contains(atom)) return true;
}
return false;
}
private int countSingleElectrons(IAtomContainer atomContainer, IAtom atom) {
Iterator<ISingleElectron> singleElectrons = atomContainer.singleElectrons().iterator();
int count = 0;
while (singleElectrons.hasNext()) {
if (singleElectrons.next().contains(atom)) count++;
}
return count;
}
private IAtomType perceiveOxygenRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if (atom.getFormalCharge() == 0) {
if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IAtomType type = getAtomType("O.sp3.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFormalCharge() == +1) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("O.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedBondsCount(atom) <= 2) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("O.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("O.plus.sp2.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
}
return null;
}
private boolean isCharged(IAtom atom) {
return (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != 0);
}
private boolean hasHybridization(IAtom atom) {
return atom.getHybridization() != CDKConstants.UNSET;
}
private IAtomType perceiveOxygens(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if (hasOneSingleElectron(atomContainer, atom)) {
return perceiveOxygenRadicals(atomContainer, atom);
}
// if hybridization is given, use that
if (hasHybridization(atom) && !isCharged(atom)) {
if (atom.getHybridization() == Hybridization.SP2) {
int connectedAtomsCount = atomContainer.getConnectedAtomsCount(atom);
if (connectedAtomsCount == 1) {
if (isCarboxylate(atom, atomContainer)) {
IAtomType type = getAtomType("O.sp2.co2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("O.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (connectedAtomsCount == 2) {
IAtomType type = getAtomType("O.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getHybridization() == Hybridization.SP3) {
IAtomType type = getAtomType("O.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getHybridization() == Hybridization.PLANAR3) {
IAtomType type = getAtomType("O.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (isCharged(atom)) {
if (atom.getFormalCharge() == -1 &&
atomContainer.getConnectedAtomsCount(atom) <= 1) {
if (isCarboxylate(atom, atomContainer)) {
IAtomType type = getAtomType("O.minus.co2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("O.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFormalCharge() == -2 &&
atomContainer.getConnectedAtomsCount(atom) == 0) {
IAtomType type = getAtomType("O.minus2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == +1) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("O.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
IAtomType type = getAtomType("O.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE) {
IAtomType type = getAtomType("O.plus.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("O.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if (atomContainer.getConnectedBondsCount(atom) > 2) {
// FIXME: I don't perceive carbons with more than 4 connections yet
return null;
} else if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("O.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else { // OK, use bond order info
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
if (isCarboxylate(atom, atomContainer)) {
IAtomType type = getAtomType("O.sp2.co2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("O.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
int explicitHydrogens = countExplicitHydrogens(atom, atomContainer);
int connectedHeavyAtoms = atomContainer.getConnectedBondsCount(atom) - explicitHydrogens;
if (connectedHeavyAtoms == 2) {
// a O.sp3 which is expected to take part in an aromatic system
if (isRingAtom(atom, atomContainer) && bothNeighborsAreSp2(atom, atomContainer)) {
IAtomType type = getAtomType("O.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("O.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("O.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
}
return null;
}
private boolean isCarboxylate(IAtom atom, IAtomContainer container) {
// assumes that the oxygen only has one neighbor (C=O, or C-[O-])
List<IAtom> neighbors = container.getConnectedAtomsList(atom);
if (neighbors.size() != 1) return false;
IAtom carbon = neighbors.get(0);
if (!"C".equals(carbon.getSymbol())) return false;
int oxygenCount = 0;
int singleBondedNegativeOxygenCount = 0;
int doubleBondedOxygenCount = 0;
for (IBond cBond : container.getConnectedBondsList(carbon)) {
IAtom neighbor = cBond.getConnectedAtom(carbon);
if ("O".equals(neighbor.getSymbol())) {
oxygenCount++;
IBond.Order order = cBond.getOrder();
Integer charge = neighbor.getFormalCharge();
if (order == IBond.Order.SINGLE && charge != null && charge == -1) {
singleBondedNegativeOxygenCount++;
} else if (order == IBond.Order.DOUBLE) {
doubleBondedOxygenCount++;
}
}
}
return (oxygenCount == 2) && (singleBondedNegativeOxygenCount == 1) && (doubleBondedOxygenCount == 1);
}
private boolean atLeastTwoNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer) {
int count = 0;
Iterator<IAtom> atoms = atomContainer.getConnectedAtomsList(atom).iterator();
while (atoms.hasNext() && (count < 2)) {
IAtom nextAtom = atoms.next();
if (!nextAtom.getSymbol().equals("H")) {
if (nextAtom.getHybridization() != CDKConstants.UNSET &&
nextAtom.getHybridization() == Hybridization.SP2) {
// OK, it's SP2
count++;
} else if (countAttachedDoubleBonds(atomContainer, nextAtom) > 0) {
// OK, it's SP2
count++;
} // OK, not SP2
}
}
return count >= 2;
}
private boolean bothNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer) {
return atLeastTwoNeighborsAreSp2(atom, atomContainer);
}
private IAtomType perceiveNitrogenRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if (atomContainer.getConnectedBondsCount(atom) >= 1 &&
atomContainer.getConnectedBondsCount(atom) <= 2) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("N.plus.sp2.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("N.plus.sp3.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("N.sp3.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("N.sp2.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1 && maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("N.plus.sp3.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveNitrogens(IAtomContainer atomContainer, IAtom atom) throws CDKException {
// if hybridization is given, use that
if (hasOneSingleElectron(atomContainer, atom)) {
return perceiveNitrogenRadicals(atomContainer, atom);
} else if (hasHybridization(atom) && !isCharged(atom)) {
if (atom.getHybridization() == Hybridization.SP1) {
int neighborCount = atomContainer.getConnectedAtomsCount(atom);
if (neighborCount > 1) {
IAtomType type = getAtomType("N.sp1.2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("N.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getHybridization() == Hybridization.SP2) {
if (isAmide(atom, atomContainer)) {
IAtomType type = getAtomType("N.amide");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (isThioAmide(atom, atomContainer)) {
IAtomType type = getAtomType("N.thioamide");
if (isAcceptable(atom, atomContainer, type)) return type;
}
// but an sp2 hyb N might N.sp2 or N.planar3 (pyrrole), so check for the latter
int neighborCount = atomContainer.getConnectedAtomsCount(atom);
if (neighborCount > 1 && bothNeighborsAreSp2(atom, atomContainer)) {
IRing ring = getRing(atom, atomContainer);
int ringSize = ring == null ? 0 : ring.getAtomCount();
if (ring != null && ring.getAtomCount() > 0) {
if (neighborCount == 3) {
IBond.Order maxOrder = atomContainer.getMaximumBondOrder(atom);
if (maxOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("N.sp2.3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborCount == 2) {
IBond.Order maxOrder = atomContainer.getMaximumBondOrder(atom);
if (maxOrder == IBond.Order.SINGLE) {
if (atom.getHydrogenCount() != CDKConstants.UNSET && atom.getHydrogenCount() == 1) {
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("N.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (maxOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("N.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
}
}
IAtomType type = getAtomType("N.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getHybridization() == Hybridization.SP3) {
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getHybridization() == Hybridization.PLANAR3) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (atomContainer.getConnectedAtomsCount(atom) == 3 &&
maxBondOrder == CDKConstants.BONDORDER_DOUBLE &&
countAttachedDoubleBonds(atomContainer, atom, "O") == 2) {
IAtomType type = getAtomType("N.nitro");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (isCharged(atom)) {
if (atom.getFormalCharge() == 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE ||
atomContainer.getConnectedBondsCount(atom) == 0) {
if (atom.getHybridization() == IAtomType.Hybridization.SP2) {
IAtomType type = getAtomType("N.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("N.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
int doubleBonds= countAttachedDoubleBonds(atomContainer, atom);
if (doubleBonds == 1) {
IAtomType type = getAtomType("N.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (doubleBonds == 2) {
IAtomType type = getAtomType("N.plus.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE) {
if (atomContainer.getConnectedBondsCount(atom) == 2) {
IAtomType type = getAtomType("N.plus.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if (atom.getFormalCharge() == -1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
if (atomContainer.getConnectedAtomsCount(atom) >= 2 &&
bothNeighborsAreSp2(atom,atomContainer) &&
isRingAtom(atom, atomContainer)) {
IAtomType type = getAtomType("N.minus.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedBondsCount(atom) <= 2) {
IAtomType type = getAtomType("N.minus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IAtomType type = getAtomType("N.minus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
}
} else if (atomContainer.getConnectedBondsCount(atom) > 3) {
// FIXME: I don't perceive carbons with more than 3 connections yet
return null;
} else if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else { // OK, use bond order info
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
if (isAmide(atom, atomContainer)) {
IAtomType type = getAtomType("N.amide");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (isThioAmide(atom, atomContainer)) {
IAtomType type = getAtomType("N.thioamide");
if (isAcceptable(atom, atomContainer, type)) return type;
}
int explicitHydrogens = countExplicitHydrogens(atom, atomContainer);
int connectedHeavyAtoms = atomContainer.getConnectedBondsCount(atom) - explicitHydrogens;
if (connectedHeavyAtoms == 2) {
List<IBond> bonds = atomContainer.getConnectedBondsList(atom);
if (bonds.get(0).getFlag(CDKConstants.ISAROMATIC) &&
bonds.get(1).getFlag(CDKConstants.ISAROMATIC)) {
Integer hCount = atom.getHydrogenCount();
if (hCount == CDKConstants.UNSET || hCount == 0) {
IAtomType type = getAtomType("N.sp2");
if (isAcceptable(atom, atomContainer, type))
return type;
} else if (hCount == 1) {
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type))
return type;
}
} else if (bothNeighborsAreSp2(atom, atomContainer) && isRingAtom(atom, atomContainer)) {
// a N.sp3 which is expected to take part in an aromatic system
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (connectedHeavyAtoms == 3) {
if (bothNeighborsAreSp2(atom, atomContainer) && isRingAtom(atom, atomContainer)) {
IAtomType type = getAtomType("N.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (connectedHeavyAtoms == 1) {
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (connectedHeavyAtoms == 0) {
IAtomType type = getAtomType("N.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
if (atomContainer.getConnectedAtomsCount(atom) == 3 &&
countAttachedDoubleBonds(atomContainer, atom, "O") == 2) {
IAtomType type = getAtomType("N.nitro");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedAtomsCount(atom) == 3 &&
countAttachedDoubleBonds(atomContainer, atom) > 0) {
IAtomType type = getAtomType("N.sp2.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IAtomType type = getAtomType("N.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_TRIPLE) {
int neighborCount = atomContainer.getConnectedAtomsCount(atom);
if (neighborCount > 1) {
IAtomType type = getAtomType("N.sp1.2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("N.sp1");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
}
return null;
}
private boolean isRingAtom(IAtom atom, IAtomContainer atomContainer) {
SpanningTree st = new SpanningTree(atomContainer);
return st.getCyclicFragmentsContainer().contains(atom);
}
private IRing getRing(IAtom atom, IAtomContainer atomContainer) {
SpanningTree st = new SpanningTree(atomContainer);
try {
if (st.getCyclicFragmentsContainer().contains(atom)) {
IRingSet set = st.getAllRings();
for (int i=0; i<set.getAtomContainerCount(); i++) {
IRing ring = (IRing)set.getAtomContainer(i);
if (ring.contains(atom)) {
return ring;
}
}
}
} catch (NoSuchAtomException exception) {
return null;
}
return null;
}
private boolean isAmide(IAtom atom, IAtomContainer atomContainer) {
List<IAtom> neighbors = atomContainer.getConnectedAtomsList(atom);
for (IAtom neighbor : neighbors) {
if (neighbor.getSymbol().equals("C")) {
if (countAttachedDoubleBonds(atomContainer, neighbor, "O") == 1) return true;
}
}
return false;
}
private boolean isThioAmide(IAtom atom, IAtomContainer atomContainer) {
List<IAtom> neighbors = atomContainer.getConnectedAtomsList(atom);
for (IAtom neighbor : neighbors) {
if (neighbor.getSymbol().equals("C")) {
if (countAttachedDoubleBonds(atomContainer, neighbor, "S") == 1) return true;
}
}
return false;
}
private int countExplicitHydrogens(IAtom atom, IAtomContainer atomContainer) {
int count = 0;
for (IAtom aAtom : atomContainer.getConnectedAtomsList(atom)) {
if (aAtom.getSymbol().equals("H")) {
count++;
}
}
return count;
}
private IAtomType perceiveSulphurs(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
List<IBond> neighbors = atomContainer.getConnectedBondsList(atom);
int neighborcount = neighbors.size();
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if (atom.getHybridization() != CDKConstants.UNSET &&
atom.getHybridization() == Hybridization.SP2 &&
atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
if (neighborcount == 3) {
IAtomType type = getAtomType("S.inyl.charged");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("S.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() != 0) {
if (atom.getFormalCharge() == -1 &&
neighborcount == 1) {
IAtomType type = getAtomType("S.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == +1 &&
neighborcount == 2) {
IAtomType type = getAtomType("S.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == +1 &&
neighborcount == 3) {
IAtomType type = getAtomType("S.inyl.charged");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == +2 &&
neighborcount == 4) {
IAtomType type = getAtomType("S.onyl.charged");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 6) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
IAtomType type = getAtomType("S.octahedral");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 6) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
IAtomType type = getAtomType("S.octahedral");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 2) {
if (isRingAtom(atom, atomContainer) && bothNeighborsAreSp2(atom, atomContainer)) {
IAtomType type = getAtomType("S.planar3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (countAttachedDoubleBonds(atomContainer, atom, "O") == 2) {
IAtomType type = getAtomType("S.oxide");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (countAttachedDoubleBonds(atomContainer, atom) == 2) {
IAtomType type = getAtomType("S.inyl.2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("S.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 1) {
if (atomContainer.getConnectedBondsList(atom).get(0).getOrder() == CDKConstants.BONDORDER_DOUBLE) {
IAtomType type = getAtomType("S.2");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("S.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 0) {
IAtomType type = getAtomType("S.3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (neighborcount == 3) {
int doubleBondedAtoms = countAttachedDoubleBonds(atomContainer, atom);
if (doubleBondedAtoms == 1) {
IAtomType type = getAtomType("S.inyl");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (doubleBondedAtoms == 3) {
IAtomType type = getAtomType("S.trioxide");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 4) {
// count the number of double bonded oxygens
int doubleBondedOxygens = countAttachedDoubleBonds(atomContainer, atom, "O");
int doubleBondedNitrogens = countAttachedDoubleBonds(atomContainer, atom, "N");
if (doubleBondedOxygens + doubleBondedNitrogens == 2){
IAtomType type = getAtomType("S.onyl");
if (isAcceptable(atom, atomContainer, type)) return type;
}
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
IAtomType type = getAtomType("S.anyl");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceivePhosphors(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
List<IBond> neighbors = atomContainer.getConnectedBondsList(atom);
int neighborcount = neighbors.size();
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (countSingleElectrons(atomContainer, atom) == 3) {
IAtomType type = getAtomType("P.se.3");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if (neighborcount == 3) {
IAtomType type = getAtomType("P.ine");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (neighborcount == 2) {
if (maxBondOrder == CDKConstants.BONDORDER_DOUBLE) {
IAtomType type = getAtomType("P.irane");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (maxBondOrder == CDKConstants.BONDORDER_SINGLE) {
IAtomType type = getAtomType("P.ine");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 4) {
// count the number of double bonded oxygens
int doubleBonds = countAttachedDoubleBonds(atomContainer, atom);
if (atom.getFormalCharge() == 1 && doubleBonds == 0) {
IAtomType type = getAtomType("P.ate.charged");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (doubleBonds == 1){
IAtomType type = getAtomType("P.ate");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveHydrogens(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
int neighborcount = atomContainer.getConnectedBondsCount(atom);
if (hasOneSingleElectron(atomContainer, atom)) {
if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) &&
neighborcount == 0) {
IAtomType type = getAtomType("H.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
} else if (neighborcount == 2) {
// FIXME: bridging hydrogen as in B2H6
return null;
} else if (neighborcount == 1) {
if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("H");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (neighborcount == 0) {
if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("H");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == 1){
IAtomType type = getAtomType("H.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == -1){
IAtomType type = getAtomType("H.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveLithium(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
int neighborcount = atomContainer.getConnectedBondsCount(atom);
if (neighborcount == 1) {
if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("Li");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveHalogens(IAtomContainer atomContainer, IAtom atom)
throws CDKException {
if ("Cl".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
IAtomType type = getAtomType("Cl.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("Cl.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("Cl.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -1)) {
IAtomType type = getAtomType("Cl.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("Cl.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}else if (maxBondOrder == IBond.Order.SINGLE){
IAtomType type = getAtomType("Cl.plus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +3) && atomContainer.getConnectedBondsCount(atom) == 4) {
IAtomType type = getAtomType("Cl.perchlorate.charged");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedBondsCount(atom) == 1 ||
atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("Cl");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
int doubleBonds = countAttachedDoubleBonds(atomContainer, atom);
if (atomContainer.getConnectedBondsCount(atom) == 3 &&
doubleBonds == 2) {
IAtomType type = getAtomType("Cl.chlorate");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atomContainer.getConnectedBondsCount(atom) == 4 &&
doubleBonds == 3) {
IAtomType type = getAtomType("Cl.perchlorate");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if ("Br".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
IAtomType type = getAtomType("Br.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("Br.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("Br.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -1)) {
IAtomType type = getAtomType("Br.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("Br.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}else if (maxBondOrder == IBond.Order.SINGLE){
IAtomType type = getAtomType("Br.plus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) == 1 ||
atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("Br");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("F".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
IAtomType type = getAtomType("F.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("F.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("F.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() != 0) {
if (atom.getFormalCharge() == -1) {
IAtomType type = getAtomType("F.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("F.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}else if (maxBondOrder == IBond.Order.SINGLE){
IAtomType type = getAtomType("F.plus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if (atomContainer.getConnectedBondsCount(atom) == 1 ||
atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("F");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("I".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1) {
IAtomType type = getAtomType("I.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("I.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) <= 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.SINGLE) {
IAtomType type = getAtomType("I.plus.radical");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
} else if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() != 0) {
if (atom.getFormalCharge() == -1) {
if (atomContainer.getConnectedAtomsCount(atom) == 0) {
IAtomType type = getAtomType("I.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("I.minus.5");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atom.getFormalCharge() == 1) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("I.plus.sp2");
if (isAcceptable(atom, atomContainer, type)) return type;
}else if (maxBondOrder == IBond.Order.SINGLE){
IAtomType type = getAtomType("I.plus.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if (atomContainer.getConnectedBondsCount(atom) == 3) {
int doubleBondCount = countAttachedDoubleBonds(atomContainer, atom);
if (doubleBondCount == 2) {
IAtomType type = getAtomType("I.5");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) == 2) {
IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom);
if (maxBondOrder == IBond.Order.DOUBLE) {
IAtomType type = getAtomType("I.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if (atomContainer.getConnectedBondsCount(atom) == 1 ||
atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("I");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveCommonSalts(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if ("Na".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1)) {
IAtomType type = getAtomType("Na.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) &&
atomContainer.getConnectedAtomsCount(atom) == 1) {
IAtomType type = getAtomType("Na");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Ca".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Ca.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Mg".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Mg.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Fe".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Fe.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Co".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Co.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Co.metallic");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Cu".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Cu.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Mn".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Mn.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Pt".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Pt.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
int neighbors = atomContainer.getConnectedAtomsCount(atom);
if (neighbors == 4) {
IAtomType type = getAtomType("Pt.4");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (neighbors == 6) {
IAtomType type = getAtomType("Pt.6");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if ("Ni".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +2)) {
IAtomType type = getAtomType("Ni.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0) &&
atomContainer.getConnectedAtomsCount(atom) <= 2) {
IAtomType type = getAtomType("Ni");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("K".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1)) {
IAtomType type = getAtomType("K.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) {
IAtomType type = getAtomType("K.metallic");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("W".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("W.metallic");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveOrganometallicCenters(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if ("Hg".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -1)) {
IAtomType type = getAtomType("Hg.minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Po".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if (atomContainer.getConnectedBondsCount(atom) == 2) {
IAtomType type = getAtomType("Po");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Zn".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if (atomContainer.getConnectedBondsCount(atom) == 2 &&
(atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Zn");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() != CDKConstants.UNSET ||
atom.getFormalCharge() == 2) {
IAtomType type = getAtomType("Zn.2plus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Sn".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0 &&
atomContainer.getConnectedBondsCount(atom) <= 4)) {
IAtomType type = getAtomType("Sn.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("As".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == +1 &&
atomContainer.getConnectedBondsCount(atom) <= 4)) {
IAtomType type = getAtomType("As.plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0 &&
atomContainer.getConnectedBondsCount(atom) <= 3)) {
IAtomType type = getAtomType("As");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Ti".equals(atom.getSymbol())) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -3 &&
atomContainer.getConnectedBondsCount(atom) == 6) {
IAtomType type = getAtomType("Ti.3minus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0) &&
atomContainer.getConnectedBondsCount(atom) == 4) {
IAtomType type = getAtomType("Ti.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("V".equals(atom.getSymbol())) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -3 &&
atomContainer.getConnectedBondsCount(atom) == 6) {
IAtomType type = getAtomType("V.3minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Al".equals(atom.getSymbol())) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 3 &&
atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("Al.3plus");
if (isAcceptable(atom, atomContainer, type)) return type;
} else if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0 &&
atomContainer.getConnectedBondsCount(atom) == 3){
IAtomType type = getAtomType("Al");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Sc".equals(atom.getSymbol())) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == -3 &&
atomContainer.getConnectedBondsCount(atom) == 6) {
IAtomType type = getAtomType("Sc.3minus");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Cr".equals(atom.getSymbol())) {
if (atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0 &&
atomContainer.getConnectedBondsCount(atom) == 6) {
IAtomType type = getAtomType("Cr");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveNobelGases(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if ("He".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("He");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Ne".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Ne");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Ar".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Ar");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Kr".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Kr");
if (isAcceptable(atom, atomContainer, type)) return type;
}
} else if ("Xe".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
if (atomContainer.getConnectedBondsCount(atom) == 0) {
IAtomType type = getAtomType("Xe");
if (isAcceptable(atom, atomContainer, type)) return type;
} else {
IAtomType type = getAtomType("Xe.3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
} else if ("Rn".equals(atom.getSymbol())) {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() == CDKConstants.UNSET ||
atom.getFormalCharge() == 0)) {
IAtomType type = getAtomType("Rn");
if (isAcceptable(atom, atomContainer, type)) return type;
}
}
return null;
}
private IAtomType perceiveSilicon(IAtomContainer atomContainer, IAtom atom) throws CDKException {
if (hasOneSingleElectron(atomContainer, atom)) {
// no idea how to deal with this yet
return null;
} else if ((atom.getFormalCharge() != CDKConstants.UNSET &&
atom.getFormalCharge() == 0 &&
atomContainer.getConnectedBondsCount(atom) <= 4)) {
IAtomType type = getAtomType("Si.sp3");
if (isAcceptable(atom, atomContainer, type)) return type;
}
return null;
}
private int countAttachedDoubleBonds(IAtomContainer container, IAtom atom) {
return countAttachedDoubleBonds(container, atom, null);
}
private boolean hasAromaticBond(IAtomContainer container, IAtom atom) {
List<IBond> neighbors = container.getConnectedBondsList(atom);
for (IBond bond : neighbors) {
if (bond.getFlag(CDKConstants.ISAROMATIC)) return true;
}
return false;
}
/**
* Count the number of doubly bonded atoms.
*
* @param container the molecule in which to look
* @param atom the atom being looked at
* @param symbol If not null, then it only counts the double bonded atoms which
* match the given symbol.
* @return the number of doubly bonded atoms
*/
private int countAttachedDoubleBonds(IAtomContainer container, IAtom atom, String symbol) {
// count the number of double bonded oxygens
List<IBond> neighbors = container.getConnectedBondsList(atom);
int neighborcount = neighbors.size();
int doubleBondedAtoms = 0;
for (int i=neighborcount-1;i>=0;i--) {
if (neighbors.get(i).getOrder() == CDKConstants.BONDORDER_DOUBLE) {
IBond bond = neighbors.get(i);
if (bond.getAtomCount() == 2 && bond.contains(atom)) {
if (symbol != null) {
if (bond.getAtom(0).getSymbol().equals(symbol) ||
bond.getAtom(1).getSymbol().equals(symbol)) {
doubleBondedAtoms++;
}
} else {
doubleBondedAtoms++;
}
}
}
}
return doubleBondedAtoms;
}
private IAtomType getAtomType(String identifier) throws CDKException {
IAtomType type = factory.getAtomType(identifier);
type.setValency((Integer)type.getProperty(CDKConstants.PI_BOND_COUNT) +
type.getFormalNeighbourCount());
return type;
}
private boolean isAcceptable(IAtom atom, IAtomContainer container, IAtomType type) {
if (mode == REQUIRE_EXPLICIT_HYDROGENS) {
// make sure no implicit hydrogens were assumed
int actualContainerCount = container.getConnectedAtomsCount(atom);
int requiredContainerCount = type.getFormalNeighbourCount();
if (actualContainerCount != requiredContainerCount)
return false;
} else if (atom.getHydrogenCount() != CDKConstants.UNSET) {
// confirm correct neighbour count
int connectedAtoms = container.getConnectedAtomsCount(atom);
int hCount = atom.getHydrogenCount();
int actualNeighbourCount = connectedAtoms + hCount;
int requiredNeighbourCount = type.getFormalNeighbourCount();
if (actualNeighbourCount > requiredNeighbourCount)
return false;
}
// confirm correct bond orders
if (type.getProperty(CDKConstants.PI_BOND_COUNT) != null && container.getMaximumBondOrder(atom).ordinal() + 1 > (Integer) type.getProperty(CDKConstants.PI_BOND_COUNT) + 1)
return false;
// confirm correct valency
if (type.getValency() != CDKConstants.UNSET && container.getBondOrderSum(atom) > type.getValency())
return false;
// confirm correct formal charge
if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != type.getFormalCharge())
return false;
return true;
}
private boolean isHueckelNumber(int electronCount) {
return (electronCount % 4 == 2) && (electronCount >= 2);
}
}