1 /* Copyright (C) 2007-2015 Egon Willighagen <egonw@users.sf.net> 2 * 2011 Nimish Gopal <nimishg@ebi.ac.uk> 3 * 2011 Syed Asad Rahman <asad@ebi.ac.uk> 4 * 2011 Gilleain Torrance <gilleain.torrance@gmail.com> 5 * 6 * Contact: cdk-devel@lists.sourceforge.net 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, version 2.1. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 package org.openscience.cdk.atomtype; 22 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 import java.util.Hashtable; 26 import java.util.Iterator; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.concurrent.ConcurrentHashMap; 30 31 import org.openscience.cdk.CDKConstants; 32 import org.openscience.cdk.config.AtomTypeFactory; 33 import org.openscience.cdk.exception.CDKException; 34 import org.openscience.cdk.interfaces.IAtom; 35 import org.openscience.cdk.interfaces.IAtomContainer; 36 import org.openscience.cdk.interfaces.IAtomType; 37 import org.openscience.cdk.interfaces.IAtomType.Hybridization; 38 import org.openscience.cdk.interfaces.IBond; 39 import org.openscience.cdk.interfaces.IBond.Order; 40 import org.openscience.cdk.interfaces.IChemObjectBuilder; 41 import org.openscience.cdk.interfaces.IPseudoAtom; 42 import org.openscience.cdk.interfaces.ISingleElectron; 43 import org.openscience.cdk.ringsearch.RingSearch; 44 import org.openscience.cdk.tools.manipulator.BondManipulator; 45 46 /** 47 * Atom Type matcher that perceives atom types as defined in the CDK atom type list 48 * <code>org/openscience/cdk/dict/data/cdk-atom-types.owl</code>. 49 * If there is not an atom type defined for the tested atom, then NULL 50 * is returned. 51 * 52 * @author egonw 53 * @cdk.created 2007-07-20 54 * @cdk.module core 55 * @cdk.githash 56 */ 57 public class CDKAtomTypeMatcher implements IAtomTypeMatcher { 58 59 public final static int REQUIRE_NOTHING = 1; 60 public final static int REQUIRE_EXPLICIT_HYDROGENS = 2; 61 62 private AtomTypeFactory factory; 63 private int mode; 64 65 private final static Object LOCK = new Object(); 66 67 private static Map<Integer, Map<IChemObjectBuilder, CDKAtomTypeMatcher>> factories = new ConcurrentHashMap<>(5); 68 CDKAtomTypeMatcher(IChemObjectBuilder builder, int mode)69 private CDKAtomTypeMatcher(IChemObjectBuilder builder, int mode) { 70 factory = AtomTypeFactory.getInstance("org/openscience/cdk/dict/data/cdk-atom-types.owl", builder); 71 this.mode = mode; 72 } 73 getInstance(IChemObjectBuilder builder)74 public static CDKAtomTypeMatcher getInstance(IChemObjectBuilder builder) { 75 return getInstance(builder, REQUIRE_NOTHING); 76 } 77 getInstance(IChemObjectBuilder builder, int mode)78 public static CDKAtomTypeMatcher getInstance(IChemObjectBuilder builder, int mode) { 79 synchronized (LOCK) { 80 if (!factories.containsKey(mode)) 81 factories.put(mode, new Hashtable<IChemObjectBuilder, CDKAtomTypeMatcher>(1)); 82 if (!factories.get(mode).containsKey(builder)) 83 factories.get(mode).put(builder, new CDKAtomTypeMatcher(builder, mode)); 84 return factories.get(mode).get(builder); 85 } 86 } 87 88 /** {@inheritDoc} */ 89 @Override findMatchingAtomTypes(IAtomContainer atomContainer)90 public IAtomType[] findMatchingAtomTypes(IAtomContainer atomContainer) throws CDKException { 91 return findMatchingAtomTypes(atomContainer, null); 92 } 93 findMatchingAtomTypes(IAtomContainer atomContainer, RingSearch searcher)94 private IAtomType[] findMatchingAtomTypes(IAtomContainer atomContainer, RingSearch searcher) throws CDKException { 95 // cache the ring information 96 if (searcher == null) searcher = new RingSearch(atomContainer); 97 // cache atom bonds 98 Map<IAtom, List<IBond>> connectedBonds = new HashMap<IAtom,List<IBond>>(atomContainer.getAtomCount()); 99 for (IBond bond : atomContainer.bonds()) { 100 for (IAtom atom : bond.atoms()) { 101 List<IBond> atomBonds = connectedBonds.get(atom); 102 if (atomBonds == null) { 103 atomBonds = new ArrayList<>(4); 104 connectedBonds.put(atom, atomBonds); 105 } 106 atomBonds.add(bond); 107 } 108 } 109 110 IAtomType[] types = new IAtomType[atomContainer.getAtomCount()]; 111 int typeCounter = 0; 112 for (IAtom atom : atomContainer.atoms()) { 113 types[typeCounter] = findMatchingAtomType(atomContainer, atom, searcher, connectedBonds.get(atom)); 114 typeCounter++; 115 } 116 return types; 117 } 118 119 /** {@inheritDoc} */ 120 @Override findMatchingAtomType(IAtomContainer atomContainer, IAtom atom)121 public IAtomType findMatchingAtomType(IAtomContainer atomContainer, IAtom atom) throws CDKException { 122 return findMatchingAtomType(atomContainer, atom, null, null); 123 } 124 findMatchingAtomType(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds)125 private IAtomType findMatchingAtomType(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds) throws CDKException { 126 IAtomType type = null; 127 if (atom instanceof IPseudoAtom) { 128 return factory.getAtomType("X"); 129 } 130 if ("C".equals(atom.getSymbol())) { 131 type = perceiveCarbons(atomContainer, atom, searcher, connectedBonds); 132 } else if ("H".equals(atom.getSymbol())) { 133 type = perceiveHydrogens(atomContainer, atom, connectedBonds); 134 } else if ("O".equals(atom.getSymbol())) { 135 type = perceiveOxygens(atomContainer, atom, searcher, connectedBonds); 136 } else if ("N".equals(atom.getSymbol())) { 137 type = perceiveNitrogens(atomContainer, atom, searcher, connectedBonds); 138 } else if ("S".equals(atom.getSymbol())) { 139 type = perceiveSulphurs(atomContainer, atom, searcher, connectedBonds); 140 } else if ("P".equals(atom.getSymbol())) { 141 type = perceivePhosphors(atomContainer, atom, connectedBonds); 142 } else if ("Si".equals(atom.getSymbol())) { 143 type = perceiveSilicon(atomContainer, atom); 144 } else if ("Li".equals(atom.getSymbol())) { 145 type = perceiveLithium(atomContainer, atom); 146 } else if ("B".equals(atom.getSymbol())) { 147 type = perceiveBorons(atomContainer, atom); 148 } else if ("Be".equals(atom.getSymbol())) { 149 type = perceiveBeryllium(atomContainer, atom); 150 } else if ("Cr".equals(atom.getSymbol())) { 151 type = perceiveChromium(atomContainer, atom); 152 } else if ("Se".equals(atom.getSymbol())) { 153 type = perceiveSelenium(atomContainer, atom, connectedBonds); 154 } else if ("Mo".equals(atom.getSymbol())) { 155 type = perceiveMolybdenum(atomContainer, atom); 156 } else if ("Rb".equals(atom.getSymbol())) { 157 type = perceiveRubidium(atomContainer, atom); 158 } else if ("Te".equals(atom.getSymbol())) { 159 type = perceiveTellurium(atomContainer, atom); 160 } else if ("Cu".equals(atom.getSymbol())) { 161 type = perceiveCopper(atomContainer, atom); 162 } else if ("Ba".equals(atom.getSymbol())) { 163 type = perceiveBarium(atomContainer, atom); 164 } else if ("Ga".equals(atom.getSymbol())) { 165 type = perceiveGallium(atomContainer, atom); 166 } else if ("Ru".equals(atom.getSymbol())) { 167 type = perceiveRuthenium(atomContainer, atom); 168 } else if ("Zn".equals(atom.getSymbol())) { 169 type = perceiveZinc(atomContainer, atom); 170 } else if ("Al".equals(atom.getSymbol())) { 171 type = perceiveAluminium(atomContainer, atom); 172 } else if ("Ni".equals(atom.getSymbol())) { 173 type = perceiveNickel(atomContainer, atom); 174 } else if ("Gd".equals(atom.getSymbol())) { 175 type = perceiveGadolinum(atomContainer, atom); 176 } else if ("Ge".equals(atom.getSymbol())) { 177 type = perceiveGermanium(atomContainer, atom); 178 } else if ("Co".equals(atom.getSymbol())) { 179 type = perceiveCobalt(atomContainer, atom); 180 } else if ("Br".equals(atom.getSymbol())) { 181 type = perceiveBromine(atomContainer, atom); 182 } else if ("V".equals(atom.getSymbol())) { 183 type = perceiveVanadium(atomContainer, atom); 184 } else if ("Ti".equals(atom.getSymbol())) { 185 type = perceiveTitanium(atomContainer, atom); 186 } else if ("Sr".equals(atom.getSymbol())) { 187 type = perceiveStrontium(atomContainer, atom); 188 } else if ("Pb".equals(atom.getSymbol())) { 189 type = perceiveLead(atomContainer, atom); 190 } else if ("Tl".equals(atom.getSymbol())) { 191 type = perceiveThallium(atomContainer, atom); 192 } else if ("Sb".equals(atom.getSymbol())) { 193 type = perceiveAntimony(atomContainer, atom); 194 } else if ("Pt".equals(atom.getSymbol())) { 195 type = perceivePlatinum(atomContainer, atom); 196 } else if ("Hg".equals(atom.getSymbol())) { 197 type = perceiveMercury(atomContainer, atom); 198 } else if ("Fe".equals(atom.getSymbol())) { 199 type = perceiveIron(atomContainer, atom); 200 } else if ("Ra".equals(atom.getSymbol())) { 201 type = perceiveRadium(atomContainer, atom); 202 } else if ("Au".equals(atom.getSymbol())) { 203 type = perceiveGold(atomContainer, atom); 204 } else if ("Ag".equals(atom.getSymbol())) { 205 type = perceiveSilver(atomContainer, atom); 206 } else if ("Cl".equals(atom.getSymbol())) { 207 type = perceiveChlorine(atomContainer, atom, connectedBonds); 208 } else if ("In".equals(atom.getSymbol())) { 209 type = perceiveIndium(atomContainer, atom); 210 } else if ("Pu".equals(atom.getSymbol())) { 211 type = perceivePlutonium(atomContainer, atom); 212 } else if ("Th".equals(atom.getSymbol())) { 213 type = perceiveThorium(atomContainer, atom); 214 } else if ("K".equals(atom.getSymbol())) { 215 type = perceivePotassium(atomContainer, atom); 216 } else if ("Mn".equals(atom.getSymbol())) { 217 type = perceiveManganese(atomContainer, atom); 218 } else if ("Mg".equals(atom.getSymbol())) { 219 type = perceiveMagnesium(atomContainer, atom); 220 } else if ("Na".equals(atom.getSymbol())) { 221 type = perceiveSodium(atomContainer, atom); 222 } else if ("As".equals(atom.getSymbol())) { 223 type = perceiveArsenic(atomContainer, atom); 224 } else if ("Cd".equals(atom.getSymbol())) { 225 type = perceiveCadmium(atomContainer, atom); 226 } else if ("Ca".equals(atom.getSymbol())) { 227 type = perceiveCalcium(atomContainer, atom); 228 } else { 229 if (type == null) type = perceiveHalogens(atomContainer, atom, connectedBonds); 230 if (type == null) type = perceiveCommonSalts(atomContainer, atom); 231 if (type == null) type = perceiveOrganometallicCenters(atomContainer, atom); 232 if (type == null) type = perceiveNobelGases(atomContainer, atom); 233 } 234 235 // if no atom type can be assigned we set the atom type to 'X', this flags 236 // to other methods that atom typing was performed but did not yield a match 237 if (type == null) { 238 type = getAtomType("X"); 239 } 240 241 return type; 242 } 243 perceiveGallium(IAtomContainer atomContainer, IAtom atom)244 private IAtomType perceiveGallium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 245 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 246 if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE && atomContainer.getConnectedBondsCount(atom) <= 3) { 247 IAtomType type = getAtomType("Ga"); 248 if (isAcceptable(atom, atomContainer, type)) return type; 249 } else if (atom.getFormalCharge() == 3) { 250 IAtomType type = getAtomType("Ga.3plus"); 251 if (isAcceptable(atom, atomContainer, type)) return type; 252 } 253 return null; 254 } 255 perceiveGermanium(IAtomContainer atomContainer, IAtom atom)256 private IAtomType perceiveGermanium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 257 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 258 if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE && atomContainer.getConnectedBondsCount(atom) <= 4) { 259 IAtomType type = getAtomType("Ge"); 260 if (isAcceptable(atom, atomContainer, type)) return type; 261 } 262 if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 3) { 263 IAtomType type = getAtomType("Ge.3"); 264 if (isAcceptable(atom, atomContainer, type)) return type; 265 } 266 return null; 267 } 268 perceiveSelenium(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds)269 private IAtomType perceiveSelenium(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds) throws CDKException { 270 if ("Se".equals(atom.getSymbol())) { 271 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 272 int doublebondcount = countAttachedDoubleBonds(connectedBonds, atom); 273 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 274 if (atomContainer.getConnectedBondsCount(atom) == 0) { 275 if (atom.getImplicitHydrogenCount() != null && atom.getImplicitHydrogenCount() == 0) { 276 IAtomType type = getAtomType("Se.2"); 277 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 278 } else { 279 IAtomType type = getAtomType("Se.3"); 280 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 281 } 282 } else if (atomContainer.getConnectedBondsCount(atom) == 1) { 283 284 if (doublebondcount == 1) { 285 IAtomType type = getAtomType("Se.1"); 286 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 287 } else if (doublebondcount == 0) { 288 IAtomType type = getAtomType("Se.3"); 289 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 290 } 291 } else if (atomContainer.getConnectedBondsCount(atom) == 2) { 292 if (doublebondcount == 0) { 293 IAtomType type = getAtomType("Se.3"); 294 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 295 } else if (doublebondcount == 2) { 296 IAtomType type = getAtomType("Se.sp2.2"); 297 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 298 } 299 } else if (atomContainer.getConnectedBondsCount(atom) == 3) { 300 IAtomType type = getAtomType("Se.sp3.3"); 301 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 302 } else if (atomContainer.getConnectedBondsCount(atom) == 4) { 303 if (doublebondcount == 2) { 304 IAtomType type = getAtomType("Se.sp3.4"); 305 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 306 } else if (doublebondcount == 0) { 307 IAtomType type = getAtomType("Se.sp3d1.4"); 308 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 309 } 310 } else if (atomContainer.getConnectedBondsCount(atom) == 5) { 311 IAtomType type = getAtomType("Se.5"); 312 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 313 } 314 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 4) 315 && atomContainer.getConnectedBondsCount(atom) == 0) { 316 IAtomType type = getAtomType("Se.4plus"); 317 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 318 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1) 319 && atomContainer.getConnectedBondsCount(atom) == 3) { 320 IAtomType type = getAtomType("Se.plus.3"); 321 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 322 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -2) 323 && atomContainer.getConnectedBondsCount(atom) == 0) { 324 IAtomType type = getAtomType("Se.2minus"); 325 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 326 } 327 } 328 return null; 329 } 330 perceiveTellurium(IAtomContainer atomContainer, IAtom atom)331 private IAtomType perceiveTellurium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 332 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 333 if (!isCharged(atom) && maxBondOrder == IBond.Order.SINGLE && atomContainer.getConnectedBondsCount(atom) <= 2) { 334 IAtomType type = getAtomType("Te.3"); 335 if (isAcceptable(atom, atomContainer, type)) return type; 336 } else if (atom.getFormalCharge() == 4) { 337 if (atomContainer.getConnectedBondsCount(atom) == 0) { 338 IAtomType type = getAtomType("Te.4plus"); 339 if (isAcceptable(atom, atomContainer, type)) return type; 340 } 341 } 342 return null; 343 } 344 perceiveBorons(IAtomContainer atomContainer, IAtom atom)345 private IAtomType perceiveBorons(IAtomContainer atomContainer, IAtom atom) throws CDKException { 346 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 347 if (atom.getFormalCharge() == -1 && maxBondOrder == IBond.Order.SINGLE 348 && atomContainer.getConnectedBondsCount(atom) <= 4) { 349 IAtomType type = getAtomType("B.minus"); 350 if (isAcceptable(atom, atomContainer, type)) return type; 351 } else if (atom.getFormalCharge() == +3 && atomContainer.getConnectedBondsCount(atom) == 4) { 352 IAtomType type = getAtomType("B.3plus"); 353 if (isAcceptable(atom, atomContainer, type)) return type; 354 } else if (atomContainer.getConnectedBondsCount(atom) <= 3) { 355 IAtomType type = getAtomType("B"); 356 if (isAcceptable(atom, atomContainer, type)) return type; 357 } 358 return null; 359 } 360 perceiveBeryllium(IAtomContainer atomContainer, IAtom atom)361 private IAtomType perceiveBeryllium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 362 if (atom.getFormalCharge() == -2 && atomContainer.getMaximumBondOrder(atom) == IBond.Order.SINGLE 363 && atomContainer.getConnectedBondsCount(atom) <= 4) { 364 IAtomType type = getAtomType("Be.2minus"); 365 if (isAcceptable(atom, atomContainer, type)) return type; 366 } else if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 0) { 367 IAtomType type = getAtomType("Be.neutral"); 368 if (isAcceptable(atom, atomContainer, type)) return type; 369 } 370 return null; 371 } 372 perceiveCarbonRadicals(IAtomContainer atomContainer, IAtom atom)373 private IAtomType perceiveCarbonRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException { 374 if (atomContainer.getConnectedBondsCount(atom) == 0) { 375 IAtomType type = getAtomType("C.radical.planar"); 376 if (isAcceptable(atom, atomContainer, type)) return type; 377 } else if (atomContainer.getConnectedBondsCount(atom) <= 3) { 378 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 379 if (maxBondOrder == IBond.Order.SINGLE) { 380 IAtomType type = getAtomType("C.radical.planar"); 381 if (isAcceptable(atom, atomContainer, type)) return type; 382 } else if (maxBondOrder == IBond.Order.DOUBLE) { 383 IAtomType type = getAtomType("C.radical.sp2"); 384 if (isAcceptable(atom, atomContainer, type)) return type; 385 } else if (maxBondOrder == IBond.Order.TRIPLE) { 386 IAtomType type = getAtomType("C.radical.sp1"); 387 if (isAcceptable(atom, atomContainer, type)) return type; 388 } 389 } 390 return null; 391 } 392 perceiveCarbons(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds)393 private IAtomType perceiveCarbons(IAtomContainer atomContainer, IAtom atom, 394 RingSearch searcher, List<IBond> connectedBonds) throws CDKException { 395 if (hasOneSingleElectron(atomContainer, atom)) { 396 return perceiveCarbonRadicals(atomContainer, atom); 397 } 398 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 399 // if hybridization is given, use that 400 if (hasHybridization(atom) && !isCharged(atom)) { 401 if (atom.getHybridization() == Hybridization.SP2) { 402 IAtomType type = getAtomType("C.sp2"); 403 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 404 } else if (atom.getHybridization() == Hybridization.SP3) { 405 IAtomType type = getAtomType("C.sp3"); 406 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 407 } else if (atom.getHybridization() == Hybridization.SP1) { 408 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 409 if (maxBondOrder == Order.TRIPLE) { 410 IAtomType type = getAtomType("C.sp"); 411 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 412 } else { 413 IAtomType type = getAtomType("C.allene"); 414 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 415 } 416 } 417 } else if (isCharged(atom)) { 418 if (atom.getFormalCharge() == 1) { 419 if (connectedBonds.isEmpty()) { 420 IAtomType type = getAtomType("C.plus.sp2"); 421 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 422 } else { 423 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 424 if (maxBondOrder == Order.TRIPLE) { 425 IAtomType type = getAtomType("C.plus.sp1"); 426 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 427 } else if (maxBondOrder == Order.DOUBLE) { 428 IAtomType type = getAtomType("C.plus.sp2"); 429 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 430 } else if (maxBondOrder == Order.SINGLE) { 431 IAtomType type = getAtomType("C.plus.planar"); 432 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 433 } 434 } 435 } else if (atom.getFormalCharge() == -1) { 436 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 437 if (maxBondOrder == Order.SINGLE && connectedBonds.size() <= 3) { 438 if (bothNeighborsAreSp2(atom, atomContainer, connectedBonds) && isRingAtom(atom, atomContainer, searcher)) { 439 IAtomType type = getAtomType("C.minus.planar"); 440 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 441 } 442 IAtomType type = getAtomType("C.minus.sp3"); 443 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 444 } else if (maxBondOrder == Order.DOUBLE 445 && connectedBonds.size() <= 3) { 446 IAtomType type = getAtomType("C.minus.sp2"); 447 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 448 } else if (maxBondOrder == Order.TRIPLE 449 && connectedBonds.size() <= 1) { 450 IAtomType type = getAtomType("C.minus.sp1"); 451 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 452 } 453 } 454 return null; 455 } else if (atom.getFlag(CDKConstants.ISAROMATIC)) { 456 IAtomType type = getAtomType("C.sp2"); 457 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 458 } else if (hasOneOrMoreSingleOrDoubleBonds(connectedBonds)) { 459 IAtomType type = getAtomType("C.sp2"); 460 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 461 } else if (connectedBonds.size() > 4) { 462 // FIXME: I don't perceive carbons with more than 4 connections yet 463 return null; 464 } else { // OK, use bond order info 465 Order maxBondOrder = getMaximumBondOrder(connectedBonds); 466 if (maxBondOrder == Order.QUADRUPLE) { 467 // WTF?? 468 return null; 469 } else if (maxBondOrder == Order.TRIPLE) { 470 IAtomType type = getAtomType("C.sp"); 471 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 472 } else if (maxBondOrder == Order.DOUBLE) { 473 // OK, one or two double bonds? 474 int doubleBondCount = countAttachedDoubleBonds(connectedBonds, atom); 475 if (doubleBondCount == 2) { 476 IAtomType type = getAtomType("C.allene"); 477 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 478 } else if (doubleBondCount == 1) { 479 IAtomType type = getAtomType("C.sp2"); 480 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 481 } 482 } else { 483 if (hasAromaticBond(connectedBonds)) { 484 IAtomType type = getAtomType("C.sp2"); 485 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 486 } 487 IAtomType type = getAtomType("C.sp3"); 488 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 489 } 490 } 491 return null; 492 } 493 getMaximumBondOrder(List<IBond> connectedBonds)494 private Order getMaximumBondOrder(List<IBond> connectedBonds) { 495 IBond.Order max = IBond.Order.SINGLE; 496 for (IBond bond : connectedBonds) { 497 if (bond.getOrder().numeric() > max.numeric()) 498 max = bond.getOrder(); 499 } 500 return max; 501 } 502 hasOneOrMoreSingleOrDoubleBonds(List<IBond> bonds)503 private boolean hasOneOrMoreSingleOrDoubleBonds(List<IBond> bonds) { 504 for (IBond bond : bonds) { 505 if (bond.getFlag(CDKConstants.SINGLE_OR_DOUBLE)) return true; 506 } 507 return false; 508 } 509 hasOneSingleElectron(IAtomContainer atomContainer, IAtom atom)510 private boolean hasOneSingleElectron(IAtomContainer atomContainer, IAtom atom) { 511 if (atomContainer.getSingleElectronCount() == 0) return false; 512 Iterator<ISingleElectron> singleElectrons = atomContainer.singleElectrons().iterator(); 513 while (singleElectrons.hasNext()) { 514 if (singleElectrons.next().contains(atom)) return true; 515 } 516 return false; 517 } 518 countSingleElectrons(IAtomContainer atomContainer, IAtom atom)519 private int countSingleElectrons(IAtomContainer atomContainer, IAtom atom) { 520 // if there are no single electrons at all, then certainly not for any atom 521 if (atomContainer.getSingleElectronCount() == 0) return 0; 522 Iterator<ISingleElectron> singleElectrons = atomContainer.singleElectrons().iterator(); 523 int count = 0; 524 while (singleElectrons.hasNext()) { 525 if (singleElectrons.next().contains(atom)) count++; 526 } 527 return count; 528 } 529 perceiveOxygenRadicals(IAtomContainer atomContainer, IAtom atom)530 private IAtomType perceiveOxygenRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException { 531 if (atom.getFormalCharge() == 0) { 532 if (atomContainer.getConnectedBondsCount(atom) <= 1) { 533 IAtomType type = getAtomType("O.sp3.radical"); 534 if (isAcceptable(atom, atomContainer, type)) return type; 535 } 536 } else if (atom.getFormalCharge() == +1) { 537 if (atomContainer.getConnectedBondsCount(atom) == 0) { 538 IAtomType type = getAtomType("O.plus.radical"); 539 if (isAcceptable(atom, atomContainer, type)) return type; 540 } else if (atomContainer.getConnectedBondsCount(atom) <= 2) { 541 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 542 if (maxBondOrder == IBond.Order.SINGLE) { 543 IAtomType type = getAtomType("O.plus.radical"); 544 if (isAcceptable(atom, atomContainer, type)) return type; 545 } else if (maxBondOrder == IBond.Order.DOUBLE) { 546 IAtomType type = getAtomType("O.plus.sp2.radical"); 547 if (isAcceptable(atom, atomContainer, type)) return type; 548 } 549 } 550 } 551 return null; 552 } 553 isCharged(IAtom atom)554 private boolean isCharged(IAtom atom) { 555 return (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != 0); 556 } 557 hasHybridization(IAtom atom)558 private boolean hasHybridization(IAtom atom) { 559 return atom.getHybridization() != CDKConstants.UNSET; 560 } 561 perceiveOxygens(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds)562 private IAtomType perceiveOxygens(IAtomContainer atomContainer, IAtom atom, 563 RingSearch searcher, List<IBond> connectedBonds) throws CDKException { 564 if (hasOneSingleElectron(atomContainer, atom)) { 565 return perceiveOxygenRadicals(atomContainer, atom); 566 } 567 568 // if hybridization is given, use that 569 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 570 if (hasHybridization(atom) && !isCharged(atom)) { 571 if (atom.getHybridization() == Hybridization.SP2) { 572 int connectedAtomsCount = connectedBonds.size(); 573 if (connectedAtomsCount == 1) { 574 if (isCarboxylate(atomContainer, atom, connectedBonds)) { 575 IAtomType type = getAtomType("O.sp2.co2"); 576 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 577 } else { 578 IAtomType type = getAtomType("O.sp2"); 579 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 580 } 581 } else if (connectedAtomsCount == 2) { 582 IAtomType type = getAtomType("O.planar3"); 583 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 584 } 585 } else if (atom.getHybridization() == Hybridization.SP3) { 586 IAtomType type = getAtomType("O.sp3"); 587 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 588 } else if (atom.getHybridization() == Hybridization.PLANAR3) { 589 IAtomType type = getAtomType("O.planar3"); 590 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 591 } 592 } else if (isCharged(atom)) { 593 if (atom.getFormalCharge() == -1 && connectedBonds.size() <= 1) { 594 if (isCarboxylate(atomContainer, atom, connectedBonds)) { 595 IAtomType type = getAtomType("O.minus.co2"); 596 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 597 } else { 598 IAtomType type = getAtomType("O.minus"); 599 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 600 } 601 } else if (atom.getFormalCharge() == -2 && connectedBonds.size() == 0) { 602 IAtomType type = getAtomType("O.minus2"); 603 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 604 } else if (atom.getFormalCharge() == +1) { 605 if (connectedBonds.size() == 0) { 606 IAtomType type = getAtomType("O.plus"); 607 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 608 } 609 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 610 if (maxBondOrder == Order.DOUBLE) { 611 IAtomType type = getAtomType("O.plus.sp2"); 612 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 613 } else if (maxBondOrder == Order.TRIPLE) { 614 IAtomType type = getAtomType("O.plus.sp1"); 615 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 616 } else { 617 IAtomType type = getAtomType("O.plus"); 618 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 619 } 620 } 621 return null; 622 } else if (connectedBonds.size() > 2) { 623 // FIXME: I don't perceive carbons with more than 4 connections yet 624 return null; 625 } else if (connectedBonds.size() == 0) { 626 IAtomType type = getAtomType("O.sp3"); 627 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 628 } else { // OK, use bond order info 629 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 630 if (maxBondOrder == Order.DOUBLE) { 631 if (isCarboxylate(atomContainer, atom, connectedBonds)) { 632 IAtomType type = getAtomType("O.sp2.co2"); 633 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 634 } else { 635 IAtomType type = getAtomType("O.sp2"); 636 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 637 } 638 } else if (maxBondOrder == Order.SINGLE) { 639 int explicitHydrogens = countExplicitHydrogens(atom, connectedBonds); 640 int connectedHeavyAtoms = connectedBonds.size() - explicitHydrogens; 641 if (connectedHeavyAtoms == 2) { 642 // a O.sp3 which is expected to take part in an aromatic system 643 if (bothNeighborsAreSp2(atom, atomContainer, connectedBonds) && isRingAtom(atom, atomContainer, searcher)) { 644 IAtomType type = getAtomType("O.planar3"); 645 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 646 } 647 IAtomType type = getAtomType("O.sp3"); 648 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 649 } else { 650 IAtomType type = getAtomType("O.sp3"); 651 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 652 } 653 } 654 } 655 return null; 656 } 657 isCarboxylate(IAtomContainer container, IAtom atom, List<IBond> connectedBonds)658 private boolean isCarboxylate(IAtomContainer container, IAtom atom, List<IBond> connectedBonds) { 659 // assumes that the oxygen only has one neighbor (C=O, or C-[O-]) 660 if (connectedBonds.size() != 1) return false; 661 IAtom carbon = connectedBonds.get(0).getOther(atom); 662 if (!"C".equals(carbon.getSymbol())) return false; 663 664 List<IBond> carbonBonds = container.getConnectedBondsList(carbon); 665 if (carbonBonds.size() < 2) return false; 666 int oxygenCount = 0; 667 int singleBondedNegativeOxygenCount = 0; 668 int doubleBondedOxygenCount = 0; 669 for (IBond cBond : carbonBonds) { 670 IAtom neighbor = cBond.getOther(carbon); 671 if ("O".equals(neighbor.getSymbol())) { 672 oxygenCount++; 673 IBond.Order order = cBond.getOrder(); 674 Integer charge = neighbor.getFormalCharge(); 675 if (order == IBond.Order.SINGLE && charge != null && charge == -1) { 676 singleBondedNegativeOxygenCount++; 677 } else if (order == IBond.Order.DOUBLE) { 678 doubleBondedOxygenCount++; 679 } 680 } 681 } 682 return (oxygenCount == 2) && (singleBondedNegativeOxygenCount == 1) && (doubleBondedOxygenCount == 1); 683 } 684 atLeastTwoNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds)685 private boolean atLeastTwoNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds) { 686 int count = 0; 687 for (IBond bond : connectedBonds) { 688 if (bond.getOrder() == Order.DOUBLE || bond.isAromatic()) { 689 count++; 690 } else { 691 IAtom nextAtom = bond.getOther(atom); 692 if (nextAtom.getHybridization() != CDKConstants.UNSET && 693 nextAtom.getHybridization() == Hybridization.SP2) { 694 // OK, it's SP2 695 count++; 696 } else { 697 List<IBond> nextConnectBonds = atomContainer.getConnectedBondsList(nextAtom); 698 if (countAttachedDoubleBonds(nextConnectBonds, nextAtom) > 0) { 699 // OK, it's SP2 700 count++; 701 } 702 } 703 } 704 if (count >= 2) return true; 705 } 706 return false; 707 } 708 bothNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds)709 private boolean bothNeighborsAreSp2(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds) { 710 return atLeastTwoNeighborsAreSp2(atom, atomContainer, connectedBonds); 711 } 712 perceiveNitrogenRadicals(IAtomContainer atomContainer, IAtom atom)713 private IAtomType perceiveNitrogenRadicals(IAtomContainer atomContainer, IAtom atom) throws CDKException { 714 if (atomContainer.getConnectedBondsCount(atom) >= 1 && atomContainer.getConnectedBondsCount(atom) <= 2) { 715 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 716 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 717 if (maxBondOrder == IBond.Order.DOUBLE) { 718 IAtomType type = getAtomType("N.plus.sp2.radical"); 719 if (isAcceptable(atom, atomContainer, type)) return type; 720 } else if (maxBondOrder == IBond.Order.SINGLE) { 721 IAtomType type = getAtomType("N.plus.sp3.radical"); 722 if (isAcceptable(atom, atomContainer, type)) return type; 723 } 724 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 725 if (maxBondOrder == IBond.Order.SINGLE) { 726 IAtomType type = getAtomType("N.sp3.radical"); 727 if (isAcceptable(atom, atomContainer, type)) return type; 728 } else if (maxBondOrder == IBond.Order.DOUBLE) { 729 IAtomType type = getAtomType("N.sp2.radical"); 730 if (isAcceptable(atom, atomContainer, type)) return type; 731 } 732 } 733 } else { 734 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 735 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1 736 && maxBondOrder == IBond.Order.SINGLE) { 737 IAtomType type = getAtomType("N.plus.sp3.radical"); 738 if (isAcceptable(atom, atomContainer, type)) return type; 739 } 740 } 741 return null; 742 } 743 perceiveMolybdenum(IAtomContainer atomContainer, IAtom atom)744 private IAtomType perceiveMolybdenum(IAtomContainer atomContainer, IAtom atom) throws CDKException { 745 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 746 int neighbors = atomContainer.getConnectedBondsCount(atom); 747 if (neighbors == 4) { 748 IAtomType type = getAtomType("Mo.4"); 749 if (isAcceptable(atom, atomContainer, type)) { 750 return type; 751 } 752 } 753 IAtomType type1 = getAtomType("Mo.metallic"); 754 if (isAcceptable(atom, atomContainer, type1)) { 755 return type1; 756 } 757 } 758 return null; 759 } 760 perceiveNitrogens(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds)761 private IAtomType perceiveNitrogens(IAtomContainer atomContainer, IAtom atom, 762 RingSearch searcher, List<IBond> connectedBonds) throws CDKException { 763 // if hybridization is given, use that 764 if (hasOneSingleElectron(atomContainer, atom)) { 765 return perceiveNitrogenRadicals(atomContainer, atom); 766 } 767 768 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 769 if (hasHybridization(atom) && !isCharged(atom)) { 770 if (atom.getHybridization() == Hybridization.SP1) { 771 int neighborCount = connectedBonds.size(); 772 if (neighborCount > 1) { 773 IAtomType type = getAtomType("N.sp1.2"); 774 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 775 } else { 776 IAtomType type = getAtomType("N.sp1"); 777 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 778 } 779 } else if (atom.getHybridization() == Hybridization.SP2) { 780 if (isAmide(atom, atomContainer, connectedBonds)) { 781 IAtomType type = getAtomType("N.amide"); 782 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 783 } else if (isThioAmide(atom, atomContainer, connectedBonds)) { 784 IAtomType type = getAtomType("N.thioamide"); 785 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 786 } 787 // but an sp2 hyb N might N.sp2 or N.planar3 (pyrrole), so check for the latter 788 int neighborCount = connectedBonds.size(); 789 if (neighborCount == 4 && IBond.Order.DOUBLE == getMaximumBondOrder(connectedBonds)) { 790 IAtomType type = getAtomType("N.oxide"); 791 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 792 } else if (neighborCount > 1 && bothNeighborsAreSp2(atom, atomContainer, connectedBonds)) { 793 if (isRingAtom(atom, atomContainer, searcher)) { 794 if (neighborCount == 3) { 795 IBond.Order maxOrder = getMaximumBondOrder(connectedBonds); 796 if (maxOrder == IBond.Order.DOUBLE) { 797 IAtomType type = getAtomType("N.sp2.3"); 798 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 799 } else if (maxOrder == IBond.Order.SINGLE) { 800 IAtomType type = getAtomType("N.planar3"); 801 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 802 } 803 } else if (neighborCount == 2) { 804 IBond.Order maxOrder = getMaximumBondOrder(connectedBonds); 805 if (maxOrder == IBond.Order.SINGLE) { 806 if (atom.getImplicitHydrogenCount() != CDKConstants.UNSET 807 && atom.getImplicitHydrogenCount() == 1) { 808 IAtomType type = getAtomType("N.planar3"); 809 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 810 } else { 811 IAtomType type = getAtomType("N.sp2"); 812 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 813 } 814 } else if (maxOrder == IBond.Order.DOUBLE) { 815 IAtomType type = getAtomType("N.sp2"); 816 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 817 } 818 } 819 } 820 } 821 IAtomType type = getAtomType("N.sp2"); 822 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 823 } else if (atom.getHybridization() == Hybridization.SP3) { 824 IAtomType type = getAtomType("N.sp3"); 825 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 826 } else if (atom.getHybridization() == Hybridization.PLANAR3) { 827 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 828 if (connectedBonds.size() == 3 && maxBondOrder == Order.DOUBLE 829 && countAttachedDoubleBonds(connectedBonds, atom, "O") == 2) { 830 IAtomType type = getAtomType("N.nitro"); 831 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 832 } 833 IAtomType type = getAtomType("N.planar3"); 834 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 835 } 836 } else if (isCharged(atom)) { 837 if (atom.getFormalCharge() == 1) { 838 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 839 if (maxBondOrder == Order.SINGLE || connectedBonds.size() == 0) { 840 if (atom.getHybridization() == IAtomType.Hybridization.SP2) { 841 IAtomType type = getAtomType("N.plus.sp2"); 842 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 843 } 844 IAtomType type = getAtomType("N.plus"); 845 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 846 } else if (maxBondOrder == Order.DOUBLE) { 847 int doubleBonds = countAttachedDoubleBonds(connectedBonds, atom); 848 if (doubleBonds == 1) { 849 IAtomType type = getAtomType("N.plus.sp2"); 850 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 851 } else if (doubleBonds == 2) { 852 IAtomType type = getAtomType("N.plus.sp1"); 853 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 854 } 855 } else if (maxBondOrder == Order.TRIPLE) { 856 if (connectedBonds.size() == 2) { 857 IAtomType type = getAtomType("N.plus.sp1"); 858 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 859 } 860 } 861 } else if (atom.getFormalCharge() == -1) { 862 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 863 if (maxBondOrder == Order.SINGLE) { 864 if (connectedBonds.size() >= 2 && bothNeighborsAreSp2(atom, atomContainer, connectedBonds) 865 && isRingAtom(atom, atomContainer, searcher)) { 866 IAtomType type = getAtomType("N.minus.planar3"); 867 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 868 } else if (connectedBonds.size() <= 2) { 869 IAtomType type = getAtomType("N.minus.sp3"); 870 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 871 } 872 } else if (maxBondOrder == Order.DOUBLE) { 873 if (connectedBonds.size() <= 1) { 874 IAtomType type = getAtomType("N.minus.sp2"); 875 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 876 } 877 } 878 } 879 } else if (connectedBonds.size() > 3) { 880 if (connectedBonds.size() == 4 && countAttachedDoubleBonds(connectedBonds, atom) == 1) { 881 IAtomType type = getAtomType("N.oxide"); 882 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 883 } 884 return null; 885 } else if (connectedBonds.size() == 0) { 886 IAtomType type = getAtomType("N.sp3"); 887 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 888 } else if (hasOneOrMoreSingleOrDoubleBonds(connectedBonds)) { 889 int connectedAtoms = connectedBonds.size() 890 + (atom.getImplicitHydrogenCount() == CDKConstants.UNSET ? 0 : atom.getImplicitHydrogenCount()); 891 if (connectedAtoms == 3) { 892 IAtomType type = getAtomType("N.planar3"); 893 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 894 } 895 IAtomType type = getAtomType("N.sp2"); 896 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 897 } else { // OK, use bond order info 898 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 899 if (maxBondOrder == Order.SINGLE) { 900 if (isAmide(atom, atomContainer, connectedBonds)) { 901 IAtomType type = getAtomType("N.amide"); 902 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 903 } else if (isThioAmide(atom, atomContainer, connectedBonds)) { 904 IAtomType type = getAtomType("N.thioamide"); 905 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 906 } 907 908 List<IBond> heavy = heavyBonds(connectedBonds); 909 910 int expHCount = heavy.size() - connectedBonds.size(); 911 912 if (heavy.size() == 2) { 913 914 if (heavy.get(0).getFlag(CDKConstants.ISAROMATIC) && heavy.get(1).getFlag(CDKConstants.ISAROMATIC)) { 915 916 int hCount = atom.getImplicitHydrogenCount() != null ? atom.getImplicitHydrogenCount() 917 + expHCount : expHCount; 918 if (hCount == 0) { 919 if (maxBondOrder == Order.SINGLE 920 && isSingleHeteroAtom(atom, atomContainer)) { 921 IAtomType type = getAtomType("N.planar3"); 922 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 923 } else { 924 IAtomType type = getAtomType("N.sp2"); 925 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 926 } 927 } else if (hCount == 1) { 928 IAtomType type = getAtomType("N.planar3"); 929 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 930 } 931 } else if (bothNeighborsAreSp2(atom, atomContainer, connectedBonds) && isRingAtom(atom, atomContainer, searcher)) { 932 // a N.sp3 which is expected to take part in an aromatic system 933 IAtomType type = getAtomType("N.planar3"); 934 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 935 } else { 936 IAtomType type = getAtomType("N.sp3"); 937 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 938 } 939 } else if (heavy.size() == 3) { 940 if (bothNeighborsAreSp2(atom, atomContainer, connectedBonds) && isRingAtom(atom, atomContainer, searcher)) { 941 IAtomType type = getAtomType("N.planar3"); 942 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 943 } 944 IAtomType type = getAtomType("N.sp3"); 945 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 946 } else if (heavy.size() == 1) { 947 IAtomType type = getAtomType("N.sp3"); 948 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 949 } else if (heavy.size() == 0) { 950 IAtomType type = getAtomType("N.sp3"); 951 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 952 } 953 } else if (maxBondOrder == Order.DOUBLE) { 954 if (connectedBonds.size() == 3 955 && countAttachedDoubleBonds(connectedBonds, atom, "O") == 2) { 956 IAtomType type = getAtomType("N.nitro"); 957 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 958 } else if (connectedBonds.size() == 3 959 && countAttachedDoubleBonds(connectedBonds, atom) > 0) { 960 IAtomType type = getAtomType("N.sp2.3"); 961 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 962 } 963 IAtomType type = getAtomType("N.sp2"); 964 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 965 } else if (maxBondOrder == Order.TRIPLE) { 966 int neighborCount = connectedBonds.size(); 967 if (neighborCount > 1) { 968 IAtomType type = getAtomType("N.sp1.2"); 969 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 970 } else { 971 IAtomType type = getAtomType("N.sp1"); 972 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 973 } 974 } 975 } 976 return null; 977 } 978 979 /** 980 * Determines whether the bonds (up to two spheres away) are only to non 981 * hetroatoms. Currently used in N.planar3 perception of (e.g. pyrrole). 982 * 983 * @param atom an atom to test 984 * @param container container of the atom 985 * 986 * @return whether the atom's only bonds are to heteroatoms 987 * @see #perceiveNitrogens(IAtomContainer, IAtom, RingSearch, List) 988 */ isSingleHeteroAtom(IAtom atom, IAtomContainer container)989 private boolean isSingleHeteroAtom(IAtom atom, IAtomContainer container) { 990 991 List<IAtom> connected = container.getConnectedAtomsList(atom); 992 993 for (IAtom atom1 : connected) { 994 995 boolean aromatic = container.getBond(atom, atom1).isAromatic(); 996 997 // ignoring non-aromatic bonds 998 if (!aromatic) continue; 999 1000 // found a hetroatom - we're not a single hetroatom 1001 if (!"C".equals(atom1.getSymbol())) return false; 1002 1003 // check the second sphere 1004 for (IAtom atom2 : container.getConnectedAtomsList(atom1)) { 1005 1006 if (!atom2.equals(atom) && container.getBond(atom1, atom2).isAromatic() 1007 && !"C".equals(atom2.getSymbol())) { 1008 return false; 1009 } 1010 1011 } 1012 1013 } 1014 1015 return true; 1016 1017 } 1018 isRingAtom(IAtom atom, IAtomContainer atomContainer, RingSearch searcher)1019 private boolean isRingAtom(IAtom atom, IAtomContainer atomContainer, RingSearch searcher) { 1020 if (searcher == null) searcher = new RingSearch(atomContainer); 1021 return searcher.cyclic(atom); 1022 } 1023 isAmide(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds)1024 private boolean isAmide(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds) { 1025 if (connectedBonds.size() < 1) return false; 1026 for (IBond bond : connectedBonds) { 1027 IAtom neighbor = bond.getOther(atom); 1028 if (neighbor.getSymbol().equals("C")) { 1029 if (countAttachedDoubleBonds(atomContainer.getConnectedBondsList(neighbor), neighbor, "O") == 1) return true; 1030 } 1031 } 1032 return false; 1033 } 1034 isThioAmide(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds)1035 private boolean isThioAmide(IAtom atom, IAtomContainer atomContainer, List<IBond> connectedBonds) { 1036 if (connectedBonds.size() < 1) return false; 1037 for (IBond bond : connectedBonds) { 1038 IAtom neighbor = bond.getOther(atom); 1039 if (neighbor.getSymbol().equals("C")) { 1040 if (countAttachedDoubleBonds(atomContainer.getConnectedBondsList(neighbor), neighbor, "S") == 1) return true; 1041 } 1042 } 1043 return false; 1044 } 1045 countExplicitHydrogens(IAtom atom, List<IBond> connectedBonds)1046 private int countExplicitHydrogens(IAtom atom, List<IBond> connectedBonds) { 1047 int count = 0; 1048 for (IBond bond : connectedBonds) { 1049 IAtom aAtom = bond.getOther(atom); 1050 if (aAtom.getSymbol().equals("H")) { 1051 count++; 1052 } 1053 } 1054 return count; 1055 } 1056 1057 /** 1058 * Filter a bond list keeping only bonds between heavy atoms. 1059 * 1060 * @param bonds a list of bond 1061 * @return the bond list only with heavy bonds 1062 */ heavyBonds(final List<IBond> bonds)1063 private List<IBond> heavyBonds(final List<IBond> bonds) { 1064 final List<IBond> heavy = new ArrayList<IBond>(bonds.size()); 1065 for (final IBond bond : bonds) { 1066 if (!(bond.getBegin().getSymbol().equals("H") && bond.getEnd().getSymbol().equals("H"))) { 1067 heavy.add(bond); 1068 } 1069 } 1070 return heavy; 1071 } 1072 perceiveIron(IAtomContainer atomContainer, IAtom atom)1073 private IAtomType perceiveIron(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1074 if ("Fe".equals(atom.getSymbol())) { 1075 if (hasOneSingleElectron(atomContainer, atom)) { 1076 // no idea how to deal with this yet 1077 return null; 1078 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 0)) { 1079 int neighbors = atomContainer.getConnectedBondsCount(atom); 1080 if (neighbors == 0) { 1081 IAtomType type = getAtomType("Fe.metallic"); 1082 if (isAcceptable(atom, atomContainer, type)) { 1083 return type; 1084 } 1085 } else if (neighbors == 2) { 1086 IAtomType type5 = getAtomType("Fe.2"); 1087 if (isAcceptable(atom, atomContainer, type5)) { 1088 return type5; 1089 } 1090 } else if (neighbors == 3) { 1091 IAtomType type6 = getAtomType("Fe.3"); 1092 if (isAcceptable(atom, atomContainer, type6)) { 1093 return type6; 1094 } 1095 } else if (neighbors == 4) { 1096 IAtomType type7 = getAtomType("Fe.4"); 1097 if (isAcceptable(atom, atomContainer, type7)) { 1098 return type7; 1099 } 1100 } else if (neighbors == 5) { 1101 IAtomType type8 = getAtomType("Fe.5"); 1102 if (isAcceptable(atom, atomContainer, type8)) { 1103 return type8; 1104 } 1105 } else if (neighbors == 6) { 1106 IAtomType type9 = getAtomType("Fe.6"); 1107 if (isAcceptable(atom, atomContainer, type9)) { 1108 return type9; 1109 } 1110 } 1111 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 2)) { 1112 int neighbors = atomContainer.getConnectedBondsCount(atom); 1113 if (neighbors <= 1) { 1114 IAtomType type = getAtomType("Fe.2plus"); 1115 if (isAcceptable(atom, atomContainer, type)) { 1116 return type; 1117 } 1118 } 1119 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 1)) { 1120 int neighbors = atomContainer.getConnectedBondsCount(atom); 1121 1122 if (neighbors == 2) { 1123 IAtomType type0 = getAtomType("Fe.plus"); 1124 if (isAcceptable(atom, atomContainer, type0)) { 1125 return type0; 1126 } 1127 } 1128 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 3)) { 1129 IAtomType type1 = getAtomType("Fe.3plus"); 1130 if (isAcceptable(atom, atomContainer, type1)) { 1131 return type1; 1132 } 1133 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == -2)) { 1134 IAtomType type2 = getAtomType("Fe.2minus"); 1135 if (isAcceptable(atom, atomContainer, type2)) { 1136 return type2; 1137 } 1138 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == -3)) { 1139 IAtomType type3 = getAtomType("Fe.3minus"); 1140 if (isAcceptable(atom, atomContainer, type3)) { 1141 return type3; 1142 } 1143 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == -4)) { 1144 IAtomType type4 = getAtomType("Fe.4minus"); 1145 if (isAcceptable(atom, atomContainer, type4)) { 1146 return type4; 1147 } 1148 } 1149 } 1150 return null; 1151 } 1152 perceiveMercury(IAtomContainer atomContainer, IAtom atom)1153 private IAtomType perceiveMercury(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1154 if ("Hg".equals(atom.getSymbol())) { 1155 if (hasOneSingleElectron(atomContainer, atom)) { 1156 // no idea how to deal with this yet 1157 return null; 1158 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == -1)) { 1159 IAtomType type = getAtomType("Hg.minus"); 1160 if (isAcceptable(atom, atomContainer, type)) { 1161 return type; 1162 } 1163 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 2)) { 1164 IAtomType type = getAtomType("Hg.2plus"); 1165 if (isAcceptable(atom, atomContainer, type)) { 1166 return type; 1167 } 1168 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == +1)) { 1169 int neighbors = atomContainer.getConnectedBondsCount(atom); 1170 if (neighbors <= 1) { 1171 IAtomType type = getAtomType("Hg.plus"); 1172 if (isAcceptable(atom, atomContainer, type)) { 1173 return type; 1174 } 1175 } 1176 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 0)) { 1177 int neighbors = atomContainer.getConnectedBondsCount(atom); 1178 if (neighbors == 2) { 1179 IAtomType type = getAtomType("Hg.2"); 1180 if (isAcceptable(atom, atomContainer, type)) { 1181 return type; 1182 } 1183 } else if (neighbors == 1) { 1184 IAtomType type = getAtomType("Hg.1"); 1185 if (isAcceptable(atom, atomContainer, type)) { 1186 return type; 1187 } 1188 } else if (neighbors == 0) { 1189 IAtomType type = getAtomType("Hg.metallic"); 1190 if (isAcceptable(atom, atomContainer, type)) { 1191 return type; 1192 } 1193 } 1194 } 1195 } 1196 return null; 1197 } 1198 perceiveSulphurs(IAtomContainer atomContainer, IAtom atom, RingSearch searcher, List<IBond> connectedBonds)1199 private IAtomType perceiveSulphurs(IAtomContainer atomContainer, IAtom atom, 1200 RingSearch searcher, List<IBond> connectedBonds) throws CDKException { 1201 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 1202 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1203 int neighborcount = connectedBonds.size(); 1204 if (hasOneSingleElectron(atomContainer, atom)) { 1205 // no idea how to deal with this yet 1206 return null; 1207 } else if (atom.getHybridization() != CDKConstants.UNSET && atom.getHybridization() == Hybridization.SP2 1208 && atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 1209 if (neighborcount == 3) { 1210 IAtomType type = getAtomType("S.inyl.charged"); 1211 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1212 } else { 1213 IAtomType type = getAtomType("S.plus"); 1214 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1215 } 1216 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != 0) { 1217 1218 if (atom.getFormalCharge() == -1 && neighborcount == 1) { 1219 IAtomType type = getAtomType("S.minus"); 1220 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1221 } else if (atom.getFormalCharge() == +1 && neighborcount == 2) { 1222 IAtomType type = getAtomType("S.plus"); 1223 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1224 } else if (atom.getFormalCharge() == +1 && neighborcount == 3) { 1225 IAtomType type = getAtomType("S.inyl.charged"); 1226 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1227 } else if (atom.getFormalCharge() == +2 && neighborcount == 4) { 1228 IAtomType type = getAtomType("S.onyl.charged"); 1229 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1230 } else if (atom.getFormalCharge() == -2 && neighborcount == 0) { 1231 IAtomType type = getAtomType("S.2minus"); 1232 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1233 } 1234 } else if (neighborcount == 0) { 1235 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1236 IAtomType type = getAtomType("S.3"); 1237 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1238 } 1239 } else if (neighborcount == 1) { 1240 if (connectedBonds.get(0).getOrder() == Order.DOUBLE) { 1241 IAtomType type = getAtomType("S.2"); 1242 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1243 } else if (connectedBonds.get(0).getOrder() == Order.SINGLE) { 1244 IAtomType type = getAtomType("S.3"); 1245 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1246 } 1247 } else if (neighborcount == 2) { 1248 if (bothNeighborsAreSp2(atom, atomContainer, connectedBonds) && isRingAtom(atom, atomContainer, searcher)) { 1249 if (countAttachedDoubleBonds(connectedBonds, atom) == 2) { 1250 IAtomType type = getAtomType("S.inyl.2"); 1251 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1252 } else { 1253 IAtomType type = getAtomType("S.planar3"); 1254 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1255 } 1256 } else if (countAttachedDoubleBonds(connectedBonds, atom, "O") == 2) { 1257 IAtomType type = getAtomType("S.oxide"); 1258 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1259 } else if (countAttachedDoubleBonds(connectedBonds, atom) == 2) { 1260 IAtomType type = getAtomType("S.inyl.2"); 1261 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1262 } else if (countAttachedDoubleBonds(connectedBonds, atom) <= 1) { 1263 IAtomType type = getAtomType("S.3"); 1264 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1265 } else if (countAttachedDoubleBonds(connectedBonds, atom) == 0 1266 && countAttachedSingleBonds(connectedBonds, atom) == 2) { 1267 IAtomType type = getAtomType("S.octahedral"); 1268 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1269 } 1270 } else if (neighborcount == 3) { 1271 int doubleBondedAtoms = countAttachedDoubleBonds(connectedBonds, atom); 1272 if (doubleBondedAtoms == 1) { 1273 IAtomType type = getAtomType("S.inyl"); 1274 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1275 } else if (doubleBondedAtoms == 3) { 1276 IAtomType type = getAtomType("S.trioxide"); 1277 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1278 } else if (doubleBondedAtoms == 0) { 1279 IAtomType type = getAtomType("S.anyl"); 1280 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1281 } 1282 } else if (neighborcount == 4) { 1283 // count the number of double bonded oxygens 1284 int doubleBondedOxygens = countAttachedDoubleBonds(connectedBonds, atom, "O"); 1285 int doubleBondedNitrogens = countAttachedDoubleBonds(connectedBonds, atom, "N"); 1286 int doubleBondedSulphurs = countAttachedDoubleBonds(connectedBonds, atom, "S"); 1287 int countAttachedDoubleBonds = countAttachedDoubleBonds(connectedBonds, atom); 1288 1289 if (doubleBondedOxygens + doubleBondedNitrogens == 2) { 1290 IAtomType type = getAtomType("S.onyl"); 1291 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1292 } else if (doubleBondedSulphurs == 1 && doubleBondedOxygens == 1) { 1293 IAtomType type = getAtomType("S.thionyl"); 1294 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1295 } else if (maxBondOrder == Order.SINGLE) { 1296 IAtomType type = getAtomType("S.anyl"); 1297 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1298 } else if (doubleBondedOxygens == 1 && countAttachedDoubleBonds == 1) { 1299 IAtomType type = getAtomType("S.sp3d1"); 1300 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1301 } else if (countAttachedDoubleBonds == 2 && maxBondOrder == Order.DOUBLE) { 1302 IAtomType type = getAtomType("S.sp3.4"); 1303 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1304 } 1305 1306 } else if (neighborcount == 5) { 1307 1308 if (maxBondOrder == Order.DOUBLE) { 1309 1310 IAtomType type = getAtomType("S.sp3d1"); 1311 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1312 } else if (maxBondOrder == Order.SINGLE) { 1313 IAtomType type = getAtomType("S.octahedral"); 1314 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1315 } 1316 } else if (neighborcount == 6) { 1317 if (maxBondOrder == Order.SINGLE) { 1318 IAtomType type = getAtomType("S.octahedral"); 1319 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1320 } 1321 } 1322 return null; 1323 } 1324 perceivePhosphors(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds)1325 private IAtomType perceivePhosphors(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds) throws CDKException { 1326 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 1327 int neighborcount = connectedBonds.size(); 1328 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1329 if (countSingleElectrons(atomContainer, atom) == 3) { 1330 IAtomType type = getAtomType("P.se.3"); 1331 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1332 } else if (hasOneSingleElectron(atomContainer, atom)) { 1333 // no idea how to deal with this yet 1334 return null; 1335 } else if (neighborcount == 0) { 1336 if (atom.getFormalCharge() == null || atom.getFormalCharge().intValue() == 0) { 1337 IAtomType type = getAtomType("P.ine"); 1338 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1339 } 1340 } else if (neighborcount == 1) { 1341 if (atom.getFormalCharge() == null || atom.getFormalCharge().intValue() == 0) { 1342 IAtomType type = getAtomType("P.ide"); 1343 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1344 } 1345 } else if (neighborcount == 3) { 1346 int doubleBonds = countAttachedDoubleBonds(connectedBonds, atom); 1347 if (atom.getFormalCharge() != null && atom.getFormalCharge().intValue() == 1) { 1348 IAtomType type = getAtomType("P.anium"); 1349 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1350 } else if (doubleBonds == 1) { 1351 IAtomType type = getAtomType("P.ate"); 1352 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1353 } else { 1354 IAtomType type = getAtomType("P.ine"); 1355 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1356 } 1357 } else if (neighborcount == 2) { 1358 if (maxBondOrder == Order.DOUBLE) { 1359 if (atom.getFormalCharge() != null && atom.getFormalCharge().intValue() == 1) { 1360 IAtomType type = getAtomType("P.sp1.plus"); 1361 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1362 } else { 1363 IAtomType type = getAtomType("P.irane"); 1364 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1365 } 1366 } else if (maxBondOrder == Order.SINGLE) { 1367 IAtomType type = getAtomType("P.ine"); 1368 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1369 } 1370 } else if (neighborcount == 4) { 1371 // count the number of double bonded oxygens 1372 int doubleBonds = countAttachedDoubleBonds(connectedBonds, atom); 1373 if (atom.getFormalCharge() == 1 && doubleBonds == 0) { 1374 IAtomType type = getAtomType("P.ate.charged"); 1375 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1376 } else if (doubleBonds == 1) { 1377 IAtomType type = getAtomType("P.ate"); 1378 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1379 } 1380 } else if (neighborcount == 5) { 1381 if (atom.getFormalCharge() == null || atom.getFormalCharge().intValue() == 0) { 1382 IAtomType type = getAtomType("P.ane"); 1383 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1384 } 1385 } 1386 return null; 1387 } 1388 perceiveHydrogens(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds)1389 private IAtomType perceiveHydrogens(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds) throws CDKException { 1390 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 1391 int neighborcount = connectedBonds.size(); 1392 if (hasOneSingleElectron(atomContainer, atom)) { 1393 if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) && neighborcount == 0) { 1394 IAtomType type = getAtomType("H.radical"); 1395 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1396 } 1397 return null; 1398 } else if (neighborcount == 2) { 1399 // FIXME: bridging hydrogen as in B2H6 1400 return null; 1401 } else if (neighborcount == 1) { 1402 if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1403 IAtomType type = getAtomType("H"); 1404 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1405 } 1406 } else if (neighborcount == 0) { 1407 if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1408 IAtomType type = getAtomType("H"); 1409 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1410 } else if (atom.getFormalCharge() == 1) { 1411 IAtomType type = getAtomType("H.plus"); 1412 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1413 } else if (atom.getFormalCharge() == -1) { 1414 IAtomType type = getAtomType("H.minus"); 1415 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1416 } 1417 } 1418 return null; 1419 } 1420 perceiveLithium(IAtomContainer atomContainer, IAtom atom)1421 private IAtomType perceiveLithium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1422 int neighborcount = atomContainer.getConnectedBondsCount(atom); 1423 if (neighborcount == 1) { 1424 if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1425 IAtomType type = getAtomType("Li"); 1426 if (isAcceptable(atom, atomContainer, type)) return type; 1427 } 1428 } else if (neighborcount == 0) { 1429 if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1430 IAtomType type = getAtomType("Li.neutral"); 1431 if (isAcceptable(atom, atomContainer, type)) return type; 1432 } 1433 if (atom.getFormalCharge() == +1) { 1434 IAtomType type = getAtomType("Li.plus"); 1435 if (isAcceptable(atom, atomContainer, type)) return type; 1436 } 1437 } 1438 return null; 1439 } 1440 perceiveHalogens(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds)1441 private IAtomType perceiveHalogens(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds) throws CDKException { 1442 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 1443 if ("F".equals(atom.getSymbol())) { 1444 if (hasOneSingleElectron(atomContainer, atom)) { 1445 if (connectedBonds.size() == 0) { 1446 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 1447 IAtomType type = getAtomType("F.plus.radical"); 1448 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1449 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1450 IAtomType type = getAtomType("F.radical"); 1451 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1452 } 1453 } else if (connectedBonds.size() <= 1) { 1454 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1455 if (maxBondOrder == IBond.Order.SINGLE) { 1456 IAtomType type = getAtomType("F.plus.radical"); 1457 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1458 } 1459 } 1460 return null; 1461 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != 0) { 1462 if (atom.getFormalCharge() == -1) { 1463 IAtomType type = getAtomType("F.minus"); 1464 if (isAcceptable(atom, atomContainer, type)) return type; 1465 } else if (atom.getFormalCharge() == 1) { 1466 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1467 if (maxBondOrder == IBond.Order.DOUBLE) { 1468 IAtomType type = getAtomType("F.plus.sp2"); 1469 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1470 } else if (maxBondOrder == IBond.Order.SINGLE) { 1471 IAtomType type = getAtomType("F.plus.sp3"); 1472 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1473 } 1474 } 1475 } else if (connectedBonds.size() == 1 || connectedBonds.size() == 0) { 1476 IAtomType type = getAtomType("F"); 1477 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1478 } 1479 } else if ("I".equals(atom.getSymbol())) { 1480 return perceiveIodine(atomContainer, atom, connectedBonds); 1481 } 1482 1483 return null; 1484 } 1485 perceiveArsenic(IAtomContainer atomContainer, IAtom atom)1486 private IAtomType perceiveArsenic(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1487 if (hasOneSingleElectron(atomContainer, atom)) { 1488 // no idea how to deal with this yet 1489 return null; 1490 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1 && atomContainer 1491 .getConnectedBondsCount(atom) <= 4)) { 1492 IAtomType type = getAtomType("As.plus"); 1493 if (isAcceptable(atom, atomContainer, type)) { 1494 return type; 1495 } 1496 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 1497 int neighbors = atomContainer.getConnectedBondsCount(atom); 1498 if (neighbors == 4) { 1499 IAtomType type = getAtomType("As.5"); 1500 if (isAcceptable(atom, atomContainer, type)) { 1501 return type; 1502 } 1503 } 1504 if (neighbors == 2) { 1505 IAtomType type = getAtomType("As.2"); 1506 if (isAcceptable(atom, atomContainer, type)) { 1507 return type; 1508 } 1509 } 1510 IAtomType type = getAtomType("As"); 1511 if (isAcceptable(atom, atomContainer, type)) { 1512 return type; 1513 } 1514 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +3)) { 1515 IAtomType type = getAtomType("As.3plus"); 1516 if (isAcceptable(atom, atomContainer, type)) { 1517 return type; 1518 } 1519 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -1)) { 1520 IAtomType type = getAtomType("As.minus"); 1521 if (isAcceptable(atom, atomContainer, type)) { 1522 return type; 1523 } 1524 } 1525 return null; 1526 } 1527 perceiveThorium(IAtomContainer atomContainer, IAtom atom)1528 private IAtomType perceiveThorium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1529 if ("Th".equals(atom.getSymbol())) { 1530 if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 0) { 1531 IAtomType type = getAtomType("Th"); 1532 if (isAcceptable(atom, atomContainer, type)) { 1533 return type; 1534 } 1535 } 1536 } 1537 return null; 1538 } 1539 perceiveRubidium(IAtomContainer atomContainer, IAtom atom)1540 private IAtomType perceiveRubidium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1541 if (hasOneSingleElectron(atomContainer, atom)) { 1542 return null; 1543 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 1544 IAtomType type = getAtomType("Rb.plus"); 1545 if (isAcceptable(atom, atomContainer, type)) { 1546 return type; 1547 } 1548 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1549 IAtomType type = getAtomType("Rb.neutral"); 1550 if (isAcceptable(atom, atomContainer, type)) { 1551 return type; 1552 } 1553 } 1554 return null; 1555 } 1556 perceiveCommonSalts(IAtomContainer atomContainer, IAtom atom)1557 private IAtomType perceiveCommonSalts(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1558 if ("Mg".equals(atom.getSymbol())) { 1559 if (hasOneSingleElectron(atomContainer, atom)) { 1560 // no idea how to deal with this yet 1561 return null; 1562 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 1563 IAtomType type = getAtomType("Mg.2plus"); 1564 if (isAcceptable(atom, atomContainer, type)) return type; 1565 } 1566 } else if ("Co".equals(atom.getSymbol())) { 1567 if (hasOneSingleElectron(atomContainer, atom)) { 1568 // no idea how to deal with this yet 1569 return null; 1570 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 1571 IAtomType type = getAtomType("Co.2plus"); 1572 if (isAcceptable(atom, atomContainer, type)) return type; 1573 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +3)) { 1574 IAtomType type = getAtomType("Co.3plus"); 1575 if (isAcceptable(atom, atomContainer, type)) return type; 1576 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1577 IAtomType type = getAtomType("Co.metallic"); 1578 if (isAcceptable(atom, atomContainer, type)) return type; 1579 } 1580 } else if ("W".equals(atom.getSymbol())) { 1581 if (hasOneSingleElectron(atomContainer, atom)) { 1582 // no idea how to deal with this yet 1583 return null; 1584 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1585 IAtomType type = getAtomType("W.metallic"); 1586 if (isAcceptable(atom, atomContainer, type)) return type; 1587 } 1588 } 1589 return null; 1590 } 1591 perceiveCopper(IAtomContainer atomContainer, IAtom atom)1592 private IAtomType perceiveCopper(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1593 if (hasOneSingleElectron(atomContainer, atom)) { 1594 // no idea how to deal with this yet 1595 return null; 1596 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 1597 IAtomType type = getAtomType("Cu.2plus"); 1598 if (isAcceptable(atom, atomContainer, type)) { 1599 return type; 1600 } 1601 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1602 int neighbors = atomContainer.getConnectedBondsCount(atom); 1603 if (neighbors == 1) { 1604 IAtomType type = getAtomType("Cu.1"); 1605 if (isAcceptable(atom, atomContainer, type)) { 1606 return type; 1607 } 1608 } else { 1609 IAtomType type01 = getAtomType("Cu.metallic"); 1610 if (isAcceptable(atom, atomContainer, type01)) { 1611 return type01; 1612 } 1613 } 1614 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 1615 IAtomType type02 = getAtomType("Cu.plus"); 1616 if (isAcceptable(atom, atomContainer, type02)) { 1617 return type02; 1618 } 1619 } 1620 return null; 1621 } 1622 perceiveBarium(IAtomContainer atomContainer, IAtom atom)1623 private IAtomType perceiveBarium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1624 if (hasOneSingleElectron(atomContainer, atom)) { 1625 return null; 1626 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 2)) { 1627 IAtomType type = getAtomType("Ba.2plus"); 1628 if (isAcceptable(atom, atomContainer, type)) { 1629 return type; 1630 } 1631 } 1632 return null; 1633 } 1634 perceiveAluminium(IAtomContainer atomContainer, IAtom atom)1635 private IAtomType perceiveAluminium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1636 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 3) { 1637 int connectedBondsCount = atomContainer.getConnectedBondsCount(atom); 1638 if (connectedBondsCount == 0) { 1639 IAtomType type = getAtomType("Al.3plus"); 1640 if (isAcceptable(atom, atomContainer, type)) { 1641 return type; 1642 } 1643 } 1644 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 1645 && atomContainer.getConnectedBondsCount(atom) == 3) { 1646 IAtomType type = getAtomType("Al"); 1647 if (isAcceptable(atom, atomContainer, type)) { 1648 return type; 1649 } 1650 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3 1651 && atomContainer.getConnectedBondsCount(atom) == 6) { 1652 IAtomType type = getAtomType("Al.3minus"); 1653 if (isAcceptable(atom, atomContainer, type)) { 1654 return type; 1655 } 1656 } 1657 return null; 1658 } 1659 perceiveZinc(IAtomContainer atomContainer, IAtom atom)1660 private IAtomType perceiveZinc(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1661 if (hasOneSingleElectron(atomContainer, atom)) { 1662 // no idea how to deal with this yet 1663 return null; 1664 } else if (atomContainer.getConnectedBondsCount(atom) == 0 1665 && (atom.getFormalCharge() != null && atom.getFormalCharge() == 0)) { 1666 IAtomType type = getAtomType("Zn.metallic"); 1667 if (isAcceptable(atom, atomContainer, type)) return type; 1668 } else if (atomContainer.getConnectedBondsCount(atom) == 0 1669 && (atom.getFormalCharge() != null && atom.getFormalCharge() == 2)) { 1670 IAtomType type = getAtomType("Zn.2plus"); 1671 if (isAcceptable(atom, atomContainer, type)) return type; 1672 } else if (atomContainer.getConnectedBondsCount(atom) == 1 1673 && (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 1674 IAtomType type = getAtomType("Zn.1"); 1675 if (isAcceptable(atom, atomContainer, type)) return type; 1676 } else if (atomContainer.getConnectedBondsCount(atom) == 2 1677 && (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 1678 IAtomType type = getAtomType("Zn"); 1679 if (isAcceptable(atom, atomContainer, type)) return type; 1680 } 1681 return null; 1682 } 1683 perceiveChromium(IAtomContainer atomContainer, IAtom atom)1684 private IAtomType perceiveChromium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1685 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 1686 && atomContainer.getConnectedBondsCount(atom) == 6) { 1687 IAtomType type = getAtomType("Cr"); 1688 if (isAcceptable(atom, atomContainer, type)) { 1689 return type; 1690 } 1691 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 1692 && atomContainer.getConnectedBondsCount(atom) == 4) { 1693 IAtomType type = getAtomType("Cr.4"); 1694 if (isAcceptable(atom, atomContainer, type)) { 1695 return type; 1696 } 1697 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 6 1698 && atomContainer.getConnectedBondsCount(atom) == 0) { 1699 IAtomType type = getAtomType("Cr.6plus"); 1700 if (isAcceptable(atom, atomContainer, type)) { 1701 return type; 1702 } 1703 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 1704 && atomContainer.getConnectedBondsCount(atom) == 0) { 1705 IAtomType type = getAtomType("Cr.neutral"); 1706 if (isAcceptable(atom, atomContainer, type)) { 1707 return type; 1708 } 1709 } else if ("Cr".equals(atom.getSymbol())) { 1710 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 3 1711 && atomContainer.getConnectedBondsCount(atom) == 0) { 1712 IAtomType type = getAtomType("Cr.3plus"); 1713 if (isAcceptable(atom, atomContainer, type)) { 1714 return type; 1715 } 1716 } 1717 } 1718 return null; 1719 } 1720 perceiveOrganometallicCenters(IAtomContainer atomContainer, IAtom atom)1721 private IAtomType perceiveOrganometallicCenters(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1722 if ("Po".equals(atom.getSymbol())) { 1723 if (hasOneSingleElectron(atomContainer, atom)) { 1724 // no idea how to deal with this yet 1725 return null; 1726 } else if (atomContainer.getConnectedBondsCount(atom) == 2) { 1727 IAtomType type = getAtomType("Po"); 1728 if (isAcceptable(atom, atomContainer, type)) return type; 1729 } 1730 } else if ("Sn".equals(atom.getSymbol())) { 1731 if (hasOneSingleElectron(atomContainer, atom)) { 1732 // no idea how to deal with this yet 1733 return null; 1734 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 && atomContainer 1735 .getConnectedBondsCount(atom) <= 4)) { 1736 IAtomType type = getAtomType("Sn.sp3"); 1737 if (isAcceptable(atom, atomContainer, type)) return type; 1738 } 1739 } else if ("Sc".equals(atom.getSymbol())) { 1740 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3 1741 && atomContainer.getConnectedBondsCount(atom) == 6) { 1742 IAtomType type = getAtomType("Sc.3minus"); 1743 if (isAcceptable(atom, atomContainer, type)) return type; 1744 } 1745 } 1746 return null; 1747 } 1748 perceiveNickel(IAtomContainer atomContainer, IAtom atom)1749 private IAtomType perceiveNickel(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1750 if (hasOneSingleElectron(atomContainer, atom)) { 1751 // no idea how to deal with this yet 1752 return null; 1753 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 1754 IAtomType type = getAtomType("Ni.2plus"); 1755 if (isAcceptable(atom, atomContainer, type)) { 1756 return type; 1757 } 1758 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) 1759 && atomContainer.getConnectedBondsCount(atom) == 2) { 1760 IAtomType type = getAtomType("Ni"); 1761 if (isAcceptable(atom, atomContainer, type)) { 1762 return type; 1763 } 1764 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) 1765 && atomContainer.getConnectedBondsCount(atom) == 0) { 1766 IAtomType type = getAtomType("Ni.metallic"); 1767 if (isAcceptable(atom, atomContainer, type)) { 1768 return type; 1769 } 1770 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1) 1771 && atomContainer.getConnectedBondsCount(atom) == 1) { 1772 IAtomType type = getAtomType("Ni.plus"); 1773 if (isAcceptable(atom, atomContainer, type)) { 1774 return type; 1775 } 1776 } 1777 return null; 1778 } 1779 perceiveNobelGases(IAtomContainer atomContainer, IAtom atom)1780 private IAtomType perceiveNobelGases(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1781 if ("He".equals(atom.getSymbol())) { 1782 if (hasOneSingleElectron(atomContainer, atom)) { 1783 // no idea how to deal with this yet 1784 return null; 1785 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1786 IAtomType type = getAtomType("He"); 1787 if (isAcceptable(atom, atomContainer, type)) return type; 1788 } 1789 } else if ("Ne".equals(atom.getSymbol())) { 1790 if (hasOneSingleElectron(atomContainer, atom)) { 1791 // no idea how to deal with this yet 1792 return null; 1793 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1794 IAtomType type = getAtomType("Ne"); 1795 if (isAcceptable(atom, atomContainer, type)) return type; 1796 } 1797 } else if ("Ar".equals(atom.getSymbol())) { 1798 if (hasOneSingleElectron(atomContainer, atom)) { 1799 // no idea how to deal with this yet 1800 return null; 1801 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1802 IAtomType type = getAtomType("Ar"); 1803 if (isAcceptable(atom, atomContainer, type)) return type; 1804 } 1805 } else if ("Kr".equals(atom.getSymbol())) { 1806 if (hasOneSingleElectron(atomContainer, atom)) { 1807 // no idea how to deal with this yet 1808 return null; 1809 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1810 IAtomType type = getAtomType("Kr"); 1811 if (isAcceptable(atom, atomContainer, type)) return type; 1812 } 1813 } else if ("Xe".equals(atom.getSymbol())) { 1814 if (hasOneSingleElectron(atomContainer, atom)) { 1815 // no idea how to deal with this yet 1816 return null; 1817 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1818 if (atomContainer.getConnectedBondsCount(atom) == 0) { 1819 IAtomType type = getAtomType("Xe"); 1820 if (isAcceptable(atom, atomContainer, type)) return type; 1821 } else { 1822 IAtomType type = getAtomType("Xe.3"); 1823 if (isAcceptable(atom, atomContainer, type)) return type; 1824 } 1825 } 1826 } else if ("Rn".equals(atom.getSymbol())) { 1827 if (hasOneSingleElectron(atomContainer, atom)) { 1828 // no idea how to deal with this yet 1829 return null; 1830 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 1831 IAtomType type = getAtomType("Rn"); 1832 if (isAcceptable(atom, atomContainer, type)) return type; 1833 } 1834 } 1835 return null; 1836 } 1837 perceiveSilicon(IAtomContainer atomContainer, IAtom atom)1838 private IAtomType perceiveSilicon(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1839 if (hasOneSingleElectron(atomContainer, atom)) { 1840 // no idea how to deal with this yet 1841 return null; 1842 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1843 if (atomContainer.getConnectedBondsCount(atom) == 2) { 1844 IAtomType type = getAtomType("Si.2"); 1845 if (isAcceptable(atom, atomContainer, type)) return type; 1846 } else if (atomContainer.getConnectedBondsCount(atom) == 3) { 1847 IAtomType type = getAtomType("Si.3"); 1848 if (isAcceptable(atom, atomContainer, type)) return type; 1849 } else if (atomContainer.getConnectedBondsCount(atom) == 4) { 1850 IAtomType type = getAtomType("Si.sp3"); 1851 if (isAcceptable(atom, atomContainer, type)) return type; 1852 } 1853 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -2) { 1854 IAtomType type = getAtomType("Si.2minus.6"); 1855 if (isAcceptable(atom, atomContainer, type)) return type; 1856 } 1857 return null; 1858 } 1859 perceiveManganese(IAtomContainer atomContainer, IAtom atom)1860 private IAtomType perceiveManganese(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1861 if (hasOneSingleElectron(atomContainer, atom)) { 1862 // no idea how to deal with this yet 1863 return null; 1864 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == 0)) { 1865 int neighbors = atomContainer.getConnectedBondsCount(atom); 1866 if (neighbors == 2) { 1867 IAtomType type02 = getAtomType("Mn.2"); 1868 if (isAcceptable(atom, atomContainer, type02)) return type02; 1869 } else if (neighbors == 0) { 1870 IAtomType type03 = getAtomType("Mn.metallic"); 1871 if (isAcceptable(atom, atomContainer, type03)) return type03; 1872 } 1873 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == +2)) { 1874 IAtomType type = getAtomType("Mn.2plus"); 1875 if (isAcceptable(atom, atomContainer, type)) return type; 1876 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == +3)) { 1877 IAtomType type = getAtomType("Mn.3plus"); 1878 if (isAcceptable(atom, atomContainer, type)) return type; 1879 } 1880 return null; 1881 } 1882 perceiveSodium(IAtomContainer atomContainer, IAtom atom)1883 private IAtomType perceiveSodium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1884 if (hasOneSingleElectron(atomContainer, atom)) { 1885 // no idea how to deal with this yet 1886 return null; 1887 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1)) { 1888 IAtomType type = getAtomType("Na.plus"); 1889 if (isAcceptable(atom, atomContainer, type)) return type; 1890 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) 1891 && atomContainer.getConnectedBondsCount(atom) == 1) { 1892 IAtomType type = getAtomType("Na"); 1893 if (isAcceptable(atom, atomContainer, type)) return type; 1894 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) 1895 && atomContainer.getConnectedBondsCount(atom) == 0) { 1896 IAtomType type = getAtomType("Na.neutral"); 1897 if (isAcceptable(atom, atomContainer, type)) return type; 1898 } 1899 return null; 1900 } 1901 perceiveIodine(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds )1902 private IAtomType perceiveIodine(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds ) throws CDKException { 1903 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 1904 if (hasOneSingleElectron(atomContainer, atom)) { 1905 if (connectedBonds.size() == 0) { 1906 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 1907 IAtomType type = getAtomType("I.plus.radical"); 1908 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1909 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1910 IAtomType type = getAtomType("I.radical"); 1911 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1912 } 1913 } else if (connectedBonds.size() <= 1) { 1914 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1915 if (maxBondOrder == IBond.Order.SINGLE) { 1916 IAtomType type = getAtomType("I.plus.radical"); 1917 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1918 } 1919 } 1920 return null; 1921 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() != 0) { 1922 if (atom.getFormalCharge() == -1) { 1923 if (connectedBonds.size() == 0) { 1924 IAtomType type = getAtomType("I.minus"); 1925 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1926 } else { 1927 IAtomType type = getAtomType("I.minus.5"); 1928 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1929 } 1930 } else if (atom.getFormalCharge() == 1) { 1931 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1932 if (maxBondOrder == IBond.Order.DOUBLE) { 1933 IAtomType type = getAtomType("I.plus.sp2"); 1934 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1935 } else if (maxBondOrder == IBond.Order.SINGLE) { 1936 IAtomType type = getAtomType("I.plus.sp3"); 1937 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1938 } 1939 } 1940 } else if (connectedBonds.size() == 3) { 1941 int doubleBondCount = countAttachedDoubleBonds(connectedBonds, atom); 1942 if (doubleBondCount == 2) { 1943 IAtomType type = getAtomType("I.5"); 1944 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1945 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1946 IAtomType type = getAtomType("I.sp3d2.3"); 1947 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1948 } 1949 } else if (connectedBonds.size() == 2) { 1950 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 1951 if (maxBondOrder == IBond.Order.DOUBLE) { 1952 IAtomType type = getAtomType("I.3"); 1953 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1954 } 1955 } else if (connectedBonds.size() <= 1) { 1956 IAtomType type = getAtomType("I"); 1957 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 1958 } 1959 return null; 1960 } 1961 perceiveRuthenium(IAtomContainer atomContainer, IAtom atom)1962 private IAtomType perceiveRuthenium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1963 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) { 1964 IAtomType type = getAtomType("Ru.6"); 1965 if (isAcceptable(atom, atomContainer, type)) return type; 1966 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -2) { 1967 IAtomType type = getAtomType("Ru.2minus.6"); 1968 if (isAcceptable(atom, atomContainer, type)) return type; 1969 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3) { 1970 IAtomType type = getAtomType("Ru.3minus.6"); 1971 if (isAcceptable(atom, atomContainer, type)) return type; 1972 } 1973 return null; 1974 } 1975 perceivePotassium(IAtomContainer atomContainer, IAtom atom)1976 private IAtomType perceivePotassium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1977 if (hasOneSingleElectron(atomContainer, atom)) { 1978 // no idea how to deal with this yet 1979 return null; 1980 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1)) { 1981 IAtomType type = getAtomType("K.plus"); 1982 if (isAcceptable(atom, atomContainer, type)) return type; 1983 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 1984 int neighbors = atomContainer.getConnectedBondsCount(atom); 1985 if (neighbors == 1) { 1986 IAtomType type = getAtomType("K.neutral"); 1987 if (isAcceptable(atom, atomContainer, type)) return type; 1988 } 1989 IAtomType type = getAtomType("K.metallic"); 1990 if (isAcceptable(atom, atomContainer, type)) return type; 1991 } 1992 return null; 1993 } 1994 perceivePlutonium(IAtomContainer atomContainer, IAtom atom)1995 private IAtomType perceivePlutonium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 1996 if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 0) { 1997 IAtomType type = getAtomType("Pu"); 1998 if (isAcceptable(atom, atomContainer, type)) return type; 1999 } 2000 return null; 2001 } 2002 perceiveCadmium(IAtomContainer atomContainer, IAtom atom)2003 private IAtomType perceiveCadmium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2004 if (hasOneSingleElectron(atomContainer, atom)) { 2005 // no idea how to deal with this yet 2006 return null; 2007 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 2008 IAtomType type = getAtomType("Cd.2plus"); 2009 if (isAcceptable(atom, atomContainer, type)) return type; 2010 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 2011 if (atomContainer.getConnectedBondsCount(atom) == 0) { 2012 IAtomType type = getAtomType("Cd.metallic"); 2013 if (isAcceptable(atom, atomContainer, type)) return type; 2014 } else if (atomContainer.getConnectedBondsCount(atom) == 2) { 2015 IAtomType type = getAtomType("Cd.2"); 2016 if (isAcceptable(atom, atomContainer, type)) return type; 2017 } 2018 } 2019 return null; 2020 } 2021 perceiveIndium(IAtomContainer atomContainer, IAtom atom)2022 private IAtomType perceiveIndium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2023 if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 3) { 2024 IAtomType type = getAtomType("In.3"); 2025 if (isAcceptable(atom, atomContainer, type)) return type; 2026 } else if (atom.getFormalCharge() == 3 && atomContainer.getConnectedBondsCount(atom) == 0) { 2027 IAtomType type = getAtomType("In.3plus"); 2028 if (isAcceptable(atom, atomContainer, type)) return type; 2029 } else if (atom.getFormalCharge() == 0 && atomContainer.getConnectedBondsCount(atom) == 1) { 2030 IAtomType type = getAtomType("In.1"); 2031 if (isAcceptable(atom, atomContainer, type)) return type; 2032 } else { 2033 IAtomType type = getAtomType("In"); 2034 if (isAcceptable(atom, atomContainer, type)) return type; 2035 } 2036 return null; 2037 } 2038 perceiveChlorine(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds)2039 private IAtomType perceiveChlorine(IAtomContainer atomContainer, IAtom atom, List<IBond> connectedBonds) throws CDKException { 2040 if (connectedBonds == null) connectedBonds = atomContainer.getConnectedBondsList(atom); 2041 if (hasOneSingleElectron(atomContainer, atom)) { 2042 if (connectedBonds.size() > 1) { 2043 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 2044 IAtomType type = getAtomType("Cl.plus.radical"); 2045 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2046 } 2047 } else if (connectedBonds.size() == 1) { 2048 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 2049 if (maxBondOrder == IBond.Order.SINGLE) { 2050 IAtomType type = getAtomType("Cl.plus.radical"); 2051 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2052 } 2053 } else if (connectedBonds.size() == 0 2054 && (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 2055 IAtomType type = getAtomType("Cl.radical"); 2056 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2057 } 2058 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 2059 int neighborcount = connectedBonds.size(); 2060 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 2061 2062 if (maxBondOrder == IBond.Order.DOUBLE) { 2063 if (neighborcount == 2) { 2064 IAtomType type = getAtomType("Cl.2"); 2065 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2066 } else if (neighborcount == 3) { 2067 IAtomType type = getAtomType("Cl.chlorate"); 2068 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2069 } else if (neighborcount == 4) { 2070 IAtomType type = getAtomType("Cl.perchlorate"); 2071 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2072 } 2073 } else if (neighborcount <= 1) { 2074 IAtomType type = getAtomType("Cl"); 2075 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2076 } 2077 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -1)) { 2078 IAtomType type = getAtomType("Cl.minus"); 2079 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2080 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1) { 2081 IBond.Order maxBondOrder = getMaximumBondOrder(connectedBonds); 2082 if (maxBondOrder == IBond.Order.DOUBLE) { 2083 IAtomType type = getAtomType("Cl.plus.sp2"); 2084 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2085 } else if (maxBondOrder == IBond.Order.SINGLE) { 2086 IAtomType type = getAtomType("Cl.plus.sp3"); 2087 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2088 } 2089 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +3) 2090 && connectedBonds.size() == 4) { 2091 IAtomType type = getAtomType("Cl.perchlorate.charged"); 2092 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2093 } else { 2094 int doubleBonds = countAttachedDoubleBonds(connectedBonds, atom); 2095 if (connectedBonds.size() == 3 && doubleBonds == 2) { 2096 IAtomType type = getAtomType("Cl.chlorate"); 2097 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2098 } else if (connectedBonds.size() == 4 && doubleBonds == 3) { 2099 IAtomType type = getAtomType("Cl.perchlorate"); 2100 if (isAcceptable(atom, atomContainer, type, connectedBonds)) return type; 2101 } 2102 } 2103 return null; 2104 } 2105 perceiveSilver(IAtomContainer atomContainer, IAtom atom)2106 private IAtomType perceiveSilver(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2107 if (hasOneSingleElectron(atomContainer, atom)) { 2108 return null; 2109 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 2110 int neighbors = atomContainer.getConnectedBondsCount(atom); 2111 if (neighbors == 1) { 2112 IAtomType type = getAtomType("Ag.1"); 2113 if (isAcceptable(atom, atomContainer, type)) return type; 2114 } 2115 IAtomType type = getAtomType("Ag.neutral"); 2116 if (isAcceptable(atom, atomContainer, type)) return type; 2117 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 1)) { 2118 IAtomType type = getAtomType("Ag.plus"); 2119 if (isAcceptable(atom, atomContainer, type)) return type; 2120 } 2121 return null; 2122 } 2123 perceiveGold(IAtomContainer atomContainer, IAtom atom)2124 private IAtomType perceiveGold(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2125 if (hasOneSingleElectron(atomContainer, atom)) { 2126 return null; 2127 } 2128 int neighbors = atomContainer.getConnectedBondsCount(atom); 2129 if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) && neighbors == 1) { 2130 IAtomType type = getAtomType("Au.1"); 2131 if (isAcceptable(atom, atomContainer, type)) return type; 2132 } 2133 return null; 2134 } 2135 perceiveRadium(IAtomContainer atomContainer, IAtom atom)2136 private IAtomType perceiveRadium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2137 if (hasOneSingleElectron(atomContainer, atom)) { 2138 return null; 2139 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 2140 IAtomType type = getAtomType("Ra.neutral"); 2141 if (isAcceptable(atom, atomContainer, type)) return type; 2142 } 2143 return null; 2144 } 2145 perceiveCalcium(IAtomContainer atomContainer, IAtom atom)2146 private IAtomType perceiveCalcium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2147 if ("Ca".equals(atom.getSymbol())) { 2148 if (hasOneSingleElectron(atomContainer, atom)) { 2149 // no idea how to deal with this yet 2150 return null; 2151 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 2 && atomContainer 2152 .getConnectedBondsCount(atom) == 0)) { 2153 IAtomType type = getAtomType("Ca.2plus"); 2154 if (isAcceptable(atom, atomContainer, type)) { 2155 return type; 2156 } 2157 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 && atomContainer 2158 .getConnectedBondsCount(atom) == 2)) { 2159 IAtomType type = getAtomType("Ca.2"); 2160 if (isAcceptable(atom, atomContainer, type)) { 2161 return type; 2162 } 2163 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 && atomContainer 2164 .getConnectedBondsCount(atom) == 1)) { 2165 IAtomType type = getAtomType("Ca.1"); 2166 if (isAcceptable(atom, atomContainer, type)) { 2167 return type; 2168 } 2169 } 2170 } 2171 return null; 2172 } 2173 perceivePlatinum(IAtomContainer atomContainer, IAtom atom)2174 private IAtomType perceivePlatinum(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2175 if (hasOneSingleElectron(atomContainer, atom)) { 2176 // no idea how to deal with this yet 2177 return null; 2178 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 2179 int neighbors = atomContainer.getConnectedBondsCount(atom); 2180 if (neighbors == 4) { 2181 IAtomType type = getAtomType("Pt.2plus.4"); 2182 if (isAcceptable(atom, atomContainer, type)) return type; 2183 } else { 2184 IAtomType type = getAtomType("Pt.2plus"); 2185 if (isAcceptable(atom, atomContainer, type)) return type; 2186 } 2187 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 2188 int neighbors = atomContainer.getConnectedBondsCount(atom); 2189 if (neighbors == 2) { 2190 IAtomType type = getAtomType("Pt.2"); 2191 if (isAcceptable(atom, atomContainer, type)) return type; 2192 } else if (neighbors == 4) { 2193 IAtomType type = getAtomType("Pt.4"); 2194 if (isAcceptable(atom, atomContainer, type)) return type; 2195 } else if (neighbors == 6) { 2196 IAtomType type = getAtomType("Pt.6"); 2197 if (isAcceptable(atom, atomContainer, type)) return type; 2198 } 2199 } 2200 return null; 2201 } 2202 perceiveAntimony(IAtomContainer atomContainer, IAtom atom)2203 private IAtomType perceiveAntimony(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2204 if (hasOneSingleElectron(atomContainer, atom)) { 2205 return null; 2206 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 && atomContainer 2207 .getConnectedBondsCount(atom) == 3)) { 2208 IAtomType type = getAtomType("Sb.3"); 2209 if (isAcceptable(atom, atomContainer, type)) return type; 2210 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 && atomContainer 2211 .getConnectedBondsCount(atom) == 4)) { 2212 IAtomType type = getAtomType("Sb.4"); 2213 if (isAcceptable(atom, atomContainer, type)) return type; 2214 } 2215 return null; 2216 } 2217 perceiveGadolinum(IAtomContainer atomContainer, IAtom atom)2218 private IAtomType perceiveGadolinum(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2219 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +3 2220 && atomContainer.getConnectedBondsCount(atom) == 0) { 2221 IAtomType type = getAtomType("Gd.3plus"); 2222 if (isAcceptable(atom, atomContainer, type)) { 2223 return type; 2224 } 2225 } 2226 return null; 2227 } 2228 perceiveMagnesium(IAtomContainer atomContainer, IAtom atom)2229 private IAtomType perceiveMagnesium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2230 if (hasOneSingleElectron(atomContainer, atom)) { 2231 // no idea how to deal with this yet 2232 return null; 2233 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0)) { 2234 int neighbors = atomContainer.getConnectedBondsCount(atom); 2235 if (neighbors == 4) { 2236 IAtomType type = getAtomType("Mg.neutral"); 2237 if (isAcceptable(atom, atomContainer, type)) return type; 2238 } else if (neighbors == 2) { 2239 IAtomType type = getAtomType("Mg.neutral.2"); 2240 if (isAcceptable(atom, atomContainer, type)) return type; 2241 } else if (neighbors == 1) { 2242 IAtomType type = getAtomType("Mg.neutral.1"); 2243 if (isAcceptable(atom, atomContainer, type)) return type; 2244 } else { 2245 IAtomType type = getAtomType("Mg.neutral"); 2246 if (isAcceptable(atom, atomContainer, type)) return type; 2247 } 2248 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 2249 IAtomType type = getAtomType("Mg.2plus"); 2250 if (isAcceptable(atom, atomContainer, type)) return type; 2251 } 2252 return null; 2253 } 2254 perceiveThallium(IAtomContainer atomContainer, IAtom atom)2255 private IAtomType perceiveThallium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2256 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1 2257 && atomContainer.getConnectedBondsCount(atom) == 0) { 2258 IAtomType type = getAtomType("Tl.plus"); 2259 if (isAcceptable(atom, atomContainer, type)) return type; 2260 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 2261 && atomContainer.getConnectedBondsCount(atom) == 0) { 2262 IAtomType type = getAtomType("Tl"); 2263 if (isAcceptable(atom, atomContainer, type)) return type; 2264 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 2265 && atomContainer.getConnectedBondsCount(atom) == 1) { 2266 IAtomType type = getAtomType("Tl.1"); 2267 if (isAcceptable(atom, atomContainer, type)) return type; 2268 } 2269 return null; 2270 } 2271 perceiveLead(IAtomContainer atomContainer, IAtom atom)2272 private IAtomType perceiveLead(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2273 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 2274 && atomContainer.getConnectedBondsCount(atom) == 0) { 2275 IAtomType type = getAtomType("Pb.neutral"); 2276 if (isAcceptable(atom, atomContainer, type)) return type; 2277 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 2 2278 && atomContainer.getConnectedBondsCount(atom) == 0) { 2279 IAtomType type = getAtomType("Pb.2plus"); 2280 if (isAcceptable(atom, atomContainer, type)) return type; 2281 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0 2282 && atomContainer.getConnectedBondsCount(atom) == 1) { 2283 IAtomType type = getAtomType("Pb.1"); 2284 if (isAcceptable(atom, atomContainer, type)) return type; 2285 } 2286 return null; 2287 } 2288 perceiveStrontium(IAtomContainer atomContainer, IAtom atom)2289 private IAtomType perceiveStrontium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2290 if (hasOneSingleElectron(atomContainer, atom)) { 2291 return null; 2292 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 2)) { 2293 IAtomType type = getAtomType("Sr.2plus"); 2294 if (isAcceptable(atom, atomContainer, type)) return type; 2295 } 2296 return null; 2297 } 2298 perceiveTitanium(IAtomContainer atomContainer, IAtom atom)2299 private IAtomType perceiveTitanium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2300 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3 2301 && atomContainer.getConnectedBondsCount(atom) == 6) { 2302 IAtomType type = getAtomType("Ti.3minus"); 2303 if (isAcceptable(atom, atomContainer, type)) return type; 2304 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) 2305 && atomContainer.getConnectedBondsCount(atom) == 4) { 2306 IAtomType type = getAtomType("Ti.sp3"); 2307 if (isAcceptable(atom, atomContainer, type)) return type; 2308 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == 0) 2309 && atomContainer.getConnectedBondsCount(atom) == 2) { 2310 IAtomType type = getAtomType("Ti.2"); 2311 if (isAcceptable(atom, atomContainer, type)) return type; 2312 } 2313 return null; 2314 } 2315 perceiveVanadium(IAtomContainer atomContainer, IAtom atom)2316 private IAtomType perceiveVanadium(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2317 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3 2318 && atomContainer.getConnectedBondsCount(atom) == 6) { 2319 IAtomType type = getAtomType("V.3minus"); 2320 if (isAcceptable(atom, atomContainer, type)) return type; 2321 } else if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == -3 2322 && atomContainer.getConnectedBondsCount(atom) == 4) { 2323 IAtomType type = getAtomType("V.3minus.4"); 2324 if (isAcceptable(atom, atomContainer, type)) return type; 2325 } 2326 return null; 2327 } 2328 perceiveBromine(IAtomContainer atomContainer, IAtom atom)2329 private IAtomType perceiveBromine(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2330 if (hasOneSingleElectron(atomContainer, atom)) { 2331 if (atomContainer.getConnectedBondsCount(atom) == 0) { 2332 if (atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +1) { 2333 IAtomType type = getAtomType("Br.plus.radical"); 2334 if (isAcceptable(atom, atomContainer, type)) return type; 2335 } else if (atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0) { 2336 IAtomType type = getAtomType("Br.radical"); 2337 if (isAcceptable(atom, atomContainer, type)) return type; 2338 } 2339 } else if (atomContainer.getConnectedBondsCount(atom) <= 1) { 2340 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 2341 if (maxBondOrder == IBond.Order.SINGLE) { 2342 IAtomType type = getAtomType("Br.plus.radical"); 2343 if (isAcceptable(atom, atomContainer, type)) return type; 2344 } 2345 } 2346 return null; 2347 } else if (atom.getFormalCharge() != null && atom.getFormalCharge() == -1) { 2348 IAtomType type = getAtomType("Br.minus"); 2349 if (isAcceptable(atom, atomContainer, type)) return type; 2350 } else if (atom.getFormalCharge() != null && atom.getFormalCharge() == 1) { 2351 IBond.Order maxBondOrder = atomContainer.getMaximumBondOrder(atom); 2352 if (maxBondOrder == IBond.Order.DOUBLE) { 2353 IAtomType type = getAtomType("Br.plus.sp2"); 2354 if (isAcceptable(atom, atomContainer, type)) return type; 2355 } else if (maxBondOrder == IBond.Order.SINGLE) { 2356 IAtomType type = getAtomType("Br.plus.sp3"); 2357 if (isAcceptable(atom, atomContainer, type)) return type; 2358 } 2359 } else if (atomContainer.getConnectedBondsCount(atom) == 1 || atomContainer.getConnectedBondsCount(atom) == 0) { 2360 IAtomType type = getAtomType("Br"); 2361 if (isAcceptable(atom, atomContainer, type)) return type; 2362 } else if (atomContainer.getConnectedBondsCount(atom) == 3) { 2363 IAtomType type = getAtomType("Br.3"); 2364 if (isAcceptable(atom, atomContainer, type)) return type; 2365 } 2366 return null; 2367 } 2368 countAttachedDoubleBonds(List<IBond> connectedAtoms, IAtom atom, String symbol)2369 private int countAttachedDoubleBonds(List<IBond> connectedAtoms, IAtom atom, String symbol) { 2370 return countAttachedBonds(connectedAtoms, atom, IBond.Order.DOUBLE, symbol); 2371 } 2372 perceiveCobalt(IAtomContainer atomContainer, IAtom atom)2373 private IAtomType perceiveCobalt(IAtomContainer atomContainer, IAtom atom) throws CDKException { 2374 if (hasOneSingleElectron(atomContainer, atom)) { 2375 // no idea how to deal with this yet 2376 return null; 2377 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +2)) { 2378 IAtomType type = getAtomType("Co.2plus"); 2379 if (isAcceptable(atom, atomContainer, type)) return type; 2380 } else if ((atom.getFormalCharge() != CDKConstants.UNSET && atom.getFormalCharge() == +3)) { 2381 IAtomType type = getAtomType("Co.3plus"); 2382 if (isAcceptable(atom, atomContainer, type)) return type; 2383 } else if ((atom.getFormalCharge() == CDKConstants.UNSET || atom.getFormalCharge() == 0)) { 2384 int neighbors = atomContainer.getConnectedBondsCount(atom); 2385 if (neighbors == 2) { 2386 IAtomType type = getAtomType("Co.2"); 2387 if (isAcceptable(atom, atomContainer, type)) return type; 2388 } else if (neighbors == 4) { 2389 IAtomType type = getAtomType("Co.4"); 2390 if (isAcceptable(atom, atomContainer, type)) return type; 2391 } else if (neighbors == 6) { 2392 IAtomType type = getAtomType("Co.6"); 2393 if (isAcceptable(atom, atomContainer, type)) return type; 2394 } else if (neighbors == 1) { 2395 IAtomType type = getAtomType("Co.1"); 2396 if (isAcceptable(atom, atomContainer, type)) return type; 2397 } else { 2398 IAtomType type = getAtomType("Co.metallic"); 2399 if (isAcceptable(atom, atomContainer, type)) return type; 2400 } 2401 } else if ((atom.getFormalCharge() != null && atom.getFormalCharge() == +1)) { 2402 int neighbors = atomContainer.getConnectedBondsCount(atom); 2403 if (neighbors == 2) { 2404 IAtomType type = getAtomType("Co.plus.2"); 2405 if (isAcceptable(atom, atomContainer, type)) return type; 2406 } else if (neighbors == 4) { 2407 IAtomType type = getAtomType("Co.plus.4"); 2408 if (isAcceptable(atom, atomContainer, type)) return type; 2409 } else if (neighbors == 1) { 2410 IAtomType type = getAtomType("Co.plus.1"); 2411 if (isAcceptable(atom, atomContainer, type)) return type; 2412 } else if (neighbors == 6) { 2413 IAtomType type = getAtomType("Co.plus.6"); 2414 if (isAcceptable(atom, atomContainer, type)) return type; 2415 } else if (neighbors == 5) { 2416 IAtomType type = getAtomType("Co.plus.5"); 2417 if (isAcceptable(atom, atomContainer, type)) return type; 2418 } else { 2419 IAtomType type = getAtomType("Co.plus"); 2420 if (isAcceptable(atom, atomContainer, type)) return type; 2421 } 2422 } 2423 return null; 2424 } 2425 countAttachedDoubleBonds(List<IBond> connectedBonds, IAtom atom)2426 private int countAttachedDoubleBonds(List<IBond> connectedBonds, IAtom atom) { 2427 return countAttachedBonds(connectedBonds, atom, IBond.Order.DOUBLE, null); 2428 } 2429 countAttachedSingleBonds(List<IBond> connectedBonds, IAtom atom)2430 private int countAttachedSingleBonds(List<IBond> connectedBonds, IAtom atom) { 2431 return countAttachedBonds(connectedBonds, atom, IBond.Order.SINGLE, null); 2432 } 2433 hasAromaticBond(List<IBond> connectedBonds)2434 private boolean hasAromaticBond(List<IBond> connectedBonds) { 2435 for (IBond bond : connectedBonds) { 2436 if (bond.isAromatic()) return true; 2437 } 2438 return false; 2439 } 2440 2441 /** 2442 * Count the number of doubly bonded atoms. 2443 * 2444 * @param connectedBonds bonds connected to the atom 2445 * @param atom the atom being looked at 2446 * @param order the desired bond order of the attached bonds 2447 * @param symbol If not null, then it only counts the double bonded atoms which 2448 * match the given symbol. 2449 * @return the number of doubly bonded atoms 2450 */ countAttachedBonds(List<IBond> connectedBonds, IAtom atom, IBond.Order order, String symbol)2451 private int countAttachedBonds(List<IBond> connectedBonds, IAtom atom, IBond.Order order, String symbol) { 2452 // count the number of double bonded oxygens 2453 int neighborcount = connectedBonds.size(); 2454 int doubleBondedAtoms = 0; 2455 for (int i = neighborcount - 1; i >= 0; i--) { 2456 IBond bond = connectedBonds.get(i); 2457 if (bond.getOrder() == order) { 2458 if (bond.getAtomCount() == 2) { 2459 if (symbol != null) { 2460 // if other atom is of the given element (by its symbol) 2461 if (bond.getOther(atom).getSymbol().equals(symbol)) { 2462 doubleBondedAtoms++; 2463 } 2464 } else { 2465 doubleBondedAtoms++; 2466 } 2467 } 2468 } 2469 } 2470 return doubleBondedAtoms; 2471 } 2472 getAtomType(String identifier)2473 private IAtomType getAtomType(String identifier) throws CDKException { 2474 IAtomType type = factory.getAtomType(identifier); 2475 return type; 2476 } 2477 isAcceptable(IAtom atom, IAtomContainer container, IAtomType type)2478 private boolean isAcceptable(IAtom atom, IAtomContainer container, IAtomType type) { 2479 return isAcceptable(atom, container, type, null); 2480 } 2481 isAcceptable(IAtom atom, IAtomContainer container, IAtomType type, List<IBond> connectedBonds)2482 private boolean isAcceptable(IAtom atom, IAtomContainer container, IAtomType type, List<IBond> connectedBonds) { 2483 if (connectedBonds == null) connectedBonds = container.getConnectedBondsList(atom); 2484 if (mode == REQUIRE_EXPLICIT_HYDROGENS) { 2485 // make sure no implicit hydrogens were assumed 2486 int actualContainerCount = connectedBonds.size(); 2487 int requiredContainerCount = type.getFormalNeighbourCount(); 2488 if (actualContainerCount != requiredContainerCount) return false; 2489 } else if (atom.getImplicitHydrogenCount() != CDKConstants.UNSET) { 2490 // confirm correct neighbour count 2491 int connectedAtoms = connectedBonds.size(); 2492 int hCount = atom.getImplicitHydrogenCount(); 2493 int actualNeighbourCount = connectedAtoms + hCount; 2494 int requiredNeighbourCount = type.getFormalNeighbourCount(); 2495 if (actualNeighbourCount > requiredNeighbourCount) return false; 2496 } 2497 2498 // confirm correct bond orders 2499 IBond.Order typeOrder = type.getMaxBondOrder(); 2500 if (typeOrder != null) { 2501 for (IBond bond : connectedBonds) { 2502 IBond.Order order = bond.getOrder(); 2503 if (order != CDKConstants.UNSET && order != IBond.Order.UNSET) { 2504 if (BondManipulator.isHigherOrder(order, typeOrder)) return false; 2505 } else if (bond.getFlag(CDKConstants.SINGLE_OR_DOUBLE)) { 2506 if (typeOrder != IBond.Order.SINGLE && typeOrder != IBond.Order.DOUBLE) return false; 2507 } else { 2508 return false; 2509 } 2510 } 2511 } 2512 2513 // confirm correct valency 2514 if (type.getValency() != CDKConstants.UNSET) { 2515 double valence = container.getBondOrderSum(atom); 2516 if (atom.getImplicitHydrogenCount() != null && 2517 atom.getImplicitHydrogenCount() != 0) 2518 valence += atom.getImplicitHydrogenCount(); 2519 if (valence > type.getValency()) 2520 return false; 2521 } 2522 2523 // confirm correct formal charge 2524 if (atom.getFormalCharge() != CDKConstants.UNSET && !atom.getFormalCharge().equals(type.getFormalCharge())) 2525 return false; 2526 2527 // confirm single electron count 2528 if (type.getProperty(CDKConstants.SINGLE_ELECTRON_COUNT) != null) { 2529 int count = countSingleElectrons(container, atom); 2530 if (count != type.getProperty(CDKConstants.SINGLE_ELECTRON_COUNT, Integer.class).intValue()) 2531 return false; 2532 } 2533 2534 return true; 2535 } 2536 2537 } 2538