3
* $Date: 2007-03-14 18:33:52 +0100 (Wed, 14 Mar 2007) $
6
* Copyright (C) 2001-2007 The Chemistry Development Kit (CDK) project
8
* Contact: cdk-devel@lists.sourceforge.net
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public License
12
* as published by the Free Software Foundation; either version 2.1
13
* of the License, or (at your option) any later version.
14
* All we ask is that proper credit is given for our work, which includes
15
* - but is not limited to - adding the above copyright notice to the beginning
16
* of your source code files, and to any copyright notice that you may distribute
17
* with programs based on this work.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU Lesser General Public License for more details.
24
* You should have received a copy of the GNU Lesser General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29
package org.openscience.cdk.tools;
31
import java.io.IOException;
32
import java.util.Iterator;
33
import java.util.List;
35
import org.openscience.cdk.CDKConstants;
36
import org.openscience.cdk.config.AtomTypeFactory;
37
import org.openscience.cdk.exception.CDKException;
38
import org.openscience.cdk.interfaces.IAtom;
39
import org.openscience.cdk.interfaces.IAtomContainer;
40
import org.openscience.cdk.interfaces.IAtomType;
41
import org.openscience.cdk.interfaces.IBond;
42
import org.openscience.cdk.interfaces.IChemObjectBuilder;
43
import org.openscience.cdk.interfaces.IPseudoAtom;
44
import org.openscience.cdk.interfaces.IRingSet;
45
import org.openscience.cdk.ringsearch.RingPartitioner;
46
import org.openscience.cdk.ringsearch.SSSRFinder;
47
import org.openscience.cdk.tools.manipulator.BondManipulator;
48
import org.openscience.cdk.tools.manipulator.RingSetManipulator;
51
* Provides methods for checking whether an atoms valences are saturated with
52
* respect to a particular atom type.
54
* <p>Important: this class does not deal with hybridization states, which makes
55
* it fail, for example, for situations where bonds are marked as aromatic (either
56
* 1.5 or single an AROMATIC).
59
* @author Egon Willighagen
60
* @cdk.created 2001-09-04
62
* @cdk.keyword saturation
63
* @cdk.keyword atom, valency
65
* @cdk.module valencycheck
67
public class SaturationChecker implements IValencyChecker, IDeduceBondOrderTool {
69
AtomTypeFactory structgenATF;
71
private LoggingTool logger;
73
public SaturationChecker() throws IOException, ClassNotFoundException
75
logger = new LoggingTool(this);
79
* @param builder the ChemObjectBuilder implementation used to construct the AtomType's.
81
protected AtomTypeFactory getAtomTypeFactory(IChemObjectBuilder builder) throws CDKException {
82
if (structgenATF == null) {
84
structgenATF = AtomTypeFactory.getInstance(
85
"org/openscience/cdk/config/data/structgen_atomtypes.xml",
88
} catch (Exception exception) {
89
logger.debug(exception);
90
throw new CDKException("Could not instantiate AtomTypeFactory!", exception);
96
public boolean hasPerfectConfiguration(IAtom atom, IAtomContainer ac) throws CDKException
98
double bondOrderSum = ac.getBondOrderSum(atom);
99
double maxBondOrder = ac.getMaximumBondOrder(atom);
100
IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
101
if(atomTypes.length==0)
103
logger.debug("*** Checking for perfect configuration ***");
106
logger.debug("Checking configuration of atom " + ac.getAtomNumber(atom));
107
logger.debug("Atom has bondOrderSum = " + bondOrderSum);
108
logger.debug("Atom has max = " + bondOrderSum);
109
} catch (Exception exc)
112
for (int f = 0; f < atomTypes.length; f++)
114
if (bondOrderSum == atomTypes[f].getBondOrderSum() &&
115
maxBondOrder == atomTypes[f].getMaxBondOrder())
119
logger.debug("Atom " + ac.getAtomNumber(atom) + " has perfect configuration");
120
} catch (Exception exc)
128
logger.debug("*** Atom " + ac.getAtomNumber(atom) + " has imperfect configuration ***");
129
} catch (Exception exc)
136
* Determines of all atoms on the AtomContainer are saturated.
138
public boolean isSaturated(IAtomContainer container) throws CDKException {
139
return allSaturated(container);
141
public boolean allSaturated(IAtomContainer ac) throws CDKException
143
logger.debug("Are all atoms saturated?");
144
for (int f = 0; f < ac.getAtomCount(); f++) {
145
if (!isSaturated(ac.getAtom(f), ac)) {
153
* Returns wether a bond is unsaturated. A bond is unsaturated if
154
* <b>both</b> Atoms in the bond are unsaturated.
156
public boolean isUnsaturated(IBond bond, IAtomContainer atomContainer) throws CDKException {
158
IAtom[] atoms = BondManipulator.getAtomArray(bond);
159
boolean isUnsaturated = true;
160
for (int i=0; i<atoms.length; i++) {
161
isUnsaturated = isUnsaturated && !isSaturated(atoms[i], atomContainer);
163
return isUnsaturated;
167
* Returns wether a bond is saturated. A bond is saturated if
168
* <b>both</b> Atoms in the bond are saturated.
170
public boolean isSaturated(IBond bond, IAtomContainer atomContainer) throws CDKException {
171
IAtom[] atoms = BondManipulator.getAtomArray(bond);
172
boolean isSaturated = true;
173
for (int i=0; i<atoms.length; i++) {
174
isSaturated = isSaturated && isSaturated(atoms[i], atomContainer);
180
* Checks wether an Atom is saturated by comparing it with known AtomTypes.
182
public boolean isSaturated(IAtom atom, IAtomContainer ac) throws CDKException {
183
IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
184
if(atomTypes.length==0)
186
double bondOrderSum = ac.getBondOrderSum(atom);
187
double maxBondOrder = ac.getMaximumBondOrder(atom);
188
int hcount = atom.getHydrogenCount();
189
int charge = atom.getFormalCharge();
191
logger.debug("*** Checking saturation of atom ", atom.getSymbol(), "" + ac.getAtomNumber(atom) + " ***");
192
logger.debug("bondOrderSum: " + bondOrderSum);
193
logger.debug("maxBondOrder: " + maxBondOrder);
194
logger.debug("hcount: " + hcount);
195
} catch (Exception exc) {
198
for (int f = 0; f < atomTypes.length; f++) {
199
if (bondOrderSum - charge + hcount == atomTypes[f].getBondOrderSum() &&
200
maxBondOrder <= atomTypes[f].getMaxBondOrder()) {
201
logger.debug("*** Good ! ***");
205
logger.debug("*** Bad ! ***");
210
* Checks if the current atom has exceeded its bond order sum value.
212
* @param atom The Atom to check
213
* @param ac The atomcontainer context
214
* @return oversaturated or not
216
public boolean isOverSaturated(IAtom atom, IAtomContainer ac) throws CDKException
218
IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
219
if(atomTypes.length==0)
221
double bondOrderSum = ac.getBondOrderSum(atom);
222
double maxBondOrder = ac.getMaximumBondOrder(atom);
223
int hcount = atom.getHydrogenCount();
224
int charge = atom.getFormalCharge();
227
logger.debug("*** Checking saturation of atom " + ac.getAtomNumber(atom) + " ***");
228
logger.debug("bondOrderSum: " + bondOrderSum);
229
logger.debug("maxBondOrder: " + maxBondOrder);
230
logger.debug("hcount: " + hcount);
231
} catch (Exception exc)
234
for (int f = 0; f < atomTypes.length; f++)
236
if (bondOrderSum - charge + hcount > atomTypes[f].getBondOrderSum())
238
logger.debug("*** Good ! ***");
242
logger.debug("*** Bad ! ***");
247
* Returns the currently maximum formable bond order for this atom.
249
* @param atom The atom to be checked
250
* @param ac The AtomContainer that provides the context
251
* @return the currently maximum formable bond order for this atom
253
public double getCurrentMaxBondOrder(IAtom atom, IAtomContainer ac) throws CDKException
255
IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
256
if(atomTypes.length==0)
258
double bondOrderSum = ac.getBondOrderSum(atom);
259
int hcount = atom.getHydrogenCount();
262
for (int f = 0; f < atomTypes.length; f++)
264
current = hcount + bondOrderSum;
265
if (atomTypes[f].getBondOrderSum() - current > max)
267
max = atomTypes[f].getBondOrderSum() - current;
275
* Resets the bond orders of all atoms to 1.0.
277
public void unsaturate(IAtomContainer atomContainer) {
278
Iterator bonds = atomContainer.bonds();
279
while (bonds.hasNext()) {
280
((IBond)bonds.next()).setOrder(CDKConstants.BONDORDER_SINGLE);
285
* Resets the bond order of the Bond to 1.0.
287
public void unsaturateBonds(IAtomContainer container) {
288
Iterator bonds = container.bonds();
289
while (bonds.hasNext()) ((IBond)bonds.next()).setOrder(1.0);
293
* Saturates a molecule by setting appropriate bond orders.
294
* This method is known to fail, especially on pyrolle-like compounts.
295
* Consider using import org.openscience.cdk.smiles.DeduceBondSystemTool, which should work better
297
* @cdk.keyword bond order, calculation
298
* @cdk.created 2003-10-03
300
public void newSaturate(IAtomContainer atomContainer) throws CDKException {
301
logger.info("Saturating atomContainer by adjusting bond orders...");
302
boolean allSaturated = allSaturated(atomContainer);
304
IBond[] bonds = new IBond[atomContainer.getBondCount()];
305
for (int i=0; i<bonds.length; i++) bonds[i] = atomContainer.getBond(i);
306
boolean succeeded = newSaturate(bonds, atomContainer);
307
for(int i=0;i<bonds.length;i++){
308
if(bonds[i].getOrder()==2 && bonds[i].getFlag(CDKConstants.ISAROMATIC) && (bonds[i].getAtom(0).getSymbol().equals("N") && bonds[i].getAtom(1).getSymbol().equals("N"))){
310
if(bonds[i].getAtom(0).getSymbol().equals("N"))
312
java.util.List bondstohandle=atomContainer.getConnectedBondsList(bonds[i].getAtom(atomtohandle));
313
for(int k=0;k<bondstohandle.size();k++){
314
IBond bond = (IBond)bondstohandle.get(k);
315
if(bond.getOrder()==1 && bond.getFlag(CDKConstants.ISAROMATIC)){
317
bonds[i].setOrder(1);
324
throw new CDKException("Could not saturate this atomContainer!");
330
* Saturates a set of Bonds in an AtomContainer.
331
* This method is known to fail, especially on pyrolle-like compounts.
332
* Consider using import org.openscience.cdk.smiles.DeduceBondSystemTool, which should work better
334
public boolean newSaturate(IBond[] bonds, IAtomContainer atomContainer) throws CDKException {
335
logger.debug("Saturating bond set of size: " + bonds.length);
336
boolean bondsAreFullySaturated = true;
337
if (bonds.length > 0) {
338
IBond bond = bonds[0];
340
// determine bonds left
341
int leftBondCount = bonds.length-1;
342
IBond[] leftBonds = new IBond[leftBondCount];
343
System.arraycopy(bonds, 1, leftBonds, 0, leftBondCount);
346
if (isUnsaturated(bond, atomContainer)) {
347
// either this bonds should be saturated or not
349
// try to leave this bond unsaturated and saturate the left bondssaturate this bond
350
if (leftBondCount > 0) {
351
logger.debug("Recursing with unsaturated bond with #bonds: " + leftBondCount);
352
bondsAreFullySaturated = newSaturate(leftBonds, atomContainer)
353
&& !isUnsaturated(bond, atomContainer);
355
bondsAreFullySaturated = false;
358
// ok, did it work? if not, saturate this bond, and recurse
359
if (!bondsAreFullySaturated) {
360
logger.debug("First try did not work...");
361
// ok, revert saturating this bond, and recurse again
362
boolean couldSaturate = newSaturate(bond, atomContainer);
364
if (leftBondCount > 0) {
365
logger.debug("Recursing with saturated bond with #bonds: " + leftBondCount);
366
bondsAreFullySaturated = newSaturate(leftBonds, atomContainer);
368
bondsAreFullySaturated = true;
371
bondsAreFullySaturated = false;
372
// no need to recurse, because we already know that this bond
373
// unsaturated does not work
376
} else if (isSaturated(bond, atomContainer)) {
377
logger.debug("This bond is already saturated.");
378
if (leftBondCount > 0) {
379
logger.debug("Recursing with #bonds: " + leftBondCount);
380
bondsAreFullySaturated = newSaturate(leftBonds, atomContainer);
382
bondsAreFullySaturated = true;
385
logger.debug("Cannot saturate this bond");
386
// but, still recurse (if possible)
387
if (leftBondCount > 0) {
388
logger.debug("Recursing with saturated bond with #bonds: " + leftBondCount);
389
bondsAreFullySaturated = newSaturate(leftBonds, atomContainer)
390
&& !isUnsaturated(bond, atomContainer);
392
bondsAreFullySaturated = !isUnsaturated(bond, atomContainer);
396
logger.debug("Is bond set fully saturated?: " + bondsAreFullySaturated);
397
logger.debug("Returning to level: " + (bonds.length + 1));
398
return bondsAreFullySaturated;
402
* Saturate atom by adjusting its bond orders.
403
* This method is known to fail, especially on pyrolle-like compounts.
404
* Consider using import org.openscience.cdk.smiles.DeduceBondSystemTool, which should work better
406
public boolean newSaturate(IBond bond, IAtomContainer atomContainer) throws CDKException {
407
IAtom[] atoms = BondManipulator.getAtomArray(bond);
408
IAtom atom = atoms[0];
409
IAtom partner = atoms[1];
410
logger.debug(" saturating bond: ", atom.getSymbol(), "-", partner.getSymbol());
411
IAtomType[] atomTypes1 = getAtomTypeFactory(bond.getBuilder()).getAtomTypes(atom.getSymbol());
412
IAtomType[] atomTypes2 = getAtomTypeFactory(bond.getBuilder()).getAtomTypes(partner.getSymbol());
413
boolean bondOrderIncreased = true;
414
while (bondOrderIncreased && !isSaturated(bond, atomContainer)) {
415
logger.debug("Can increase bond order");
416
bondOrderIncreased = false;
417
for (int atCounter1=0; atCounter1<atomTypes1.length&& !bondOrderIncreased; atCounter1++) {
418
IAtomType aType1 = atomTypes1[atCounter1];
419
logger.debug(" condidering atom type: ", aType1);
420
if (couldMatchAtomType(atomContainer, atom, aType1)) {
421
logger.debug(" trying atom type: ", aType1);
422
for (int atCounter2=0; atCounter2<atomTypes2.length && !bondOrderIncreased; atCounter2++) {
423
IAtomType aType2 = atomTypes2[atCounter2];
424
logger.debug(" condidering partner type: ", aType1);
425
if (couldMatchAtomType(atomContainer, partner, atomTypes2[atCounter2])) {
426
logger.debug(" with atom type: ", aType2);
427
if (bond.getOrder() >= aType2.getMaxBondOrder() ||
428
bond.getOrder() >= aType1.getMaxBondOrder()) {
429
logger.debug("Bond order not increased: atoms has reached (or exceeded) maximum bond order for this atom type");
430
} else if (bond.getOrder() < aType2.getMaxBondOrder() &&
431
bond.getOrder() < aType1.getMaxBondOrder()) {
432
bond.setOrder(bond.getOrder() + 1);
433
logger.debug("Bond order now " + bond.getOrder());
434
bondOrderIncreased = true;
441
return isSaturated(bond, atomContainer);
445
* Determines if the atom can be of type AtomType.
447
public boolean couldMatchAtomType(IAtomContainer atomContainer, IAtom atom, IAtomType atomType) {
448
logger.debug(" ... matching atom ", atom.getSymbol(), " vs ", atomType);
449
if (atomContainer.getBondOrderSum(atom) + atom.getHydrogenCount() < atomType.getBondOrderSum()) {
450
logger.debug(" Match!");
453
logger.debug(" No Match");
458
* The method is known to fail for certain compounds. For more information, see
459
* cdk.test.limitations package.
460
* This method is known to fail, especially on pyrolle-like compounts.
461
* Consider using import org.openscience.cdk.smiles.DeduceBondSystemTool, which should work better
464
public void saturate(IAtomContainer atomContainer) throws CDKException {
465
/* newSaturate(atomContainer);
467
public void oldSaturate(AtomContainer atomContainer) throws CDKException { */
468
IAtom partner = null;
470
java.util.List partners = null;
471
IAtomType[] atomTypes1 = null;
472
IAtomType[] atomTypes2 = null;
474
for (int i = 1; i < 4; i++)
476
// handle atoms with degree 1 first and then proceed to higher order
477
for (int f = 0; f < atomContainer.getAtomCount(); f++)
479
atom = atomContainer.getAtom(f);
480
logger.debug("symbol: ", atom.getSymbol());
481
atomTypes1 = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
482
if(atomTypes1.length>0){
483
logger.debug("first atom type: ", atomTypes1[0]);
484
if (atomContainer.getConnectedBondsCount(atom) == i)
486
if (atom.getFlag(CDKConstants.ISAROMATIC) && atomContainer.getBondOrderSum(atom) < atomTypes1[0].getBondOrderSum() - atom.getHydrogenCount()){
487
partners = atomContainer.getConnectedAtomsList(atom);
488
for (int g = 0; g < partners.size(); g++)
490
partner = (IAtom)partners.get(g);
491
logger.debug("Atom has " + partners.size() + " partners");
492
atomTypes2 = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(partner.getSymbol());
493
if(atomTypes2.length==0)
495
if (atomContainer.getBond(partner,atom).getFlag(CDKConstants.ISAROMATIC) && atomContainer.getBondOrderSum(partner) < atomTypes2[0].getBondOrderSum() - partner.getHydrogenCount())
497
logger.debug("Partner has " + atomContainer.getBondOrderSum(partner) + ", may have: " + atomTypes2[0].getBondOrderSum());
498
bond = atomContainer.getBond(atom, partner);
499
logger.debug("Bond order was " + bond.getOrder());
500
bond.setOrder(bond.getOrder() + 1);
501
logger.debug("Bond order now " + bond.getOrder());
506
if (atomContainer.getBondOrderSum(atom) < atomTypes1[0].getBondOrderSum() - atom.getHydrogenCount())
508
logger.debug("Atom has " + atomContainer.getBondOrderSum(atom) + ", may have: " + atomTypes1[0].getBondOrderSum());
509
partners = atomContainer.getConnectedAtomsList(atom);
510
for (int g = 0; g < partners.size(); g++)
512
partner = (IAtom)partners.get(g);
513
logger.debug("Atom has " + partners.size() + " partners");
514
atomTypes2 = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(partner.getSymbol());
515
if(atomTypes2.length==0)
517
if (atomContainer.getBondOrderSum(partner) < atomTypes2[0].getBondOrderSum() - partner.getHydrogenCount())
519
logger.debug("Partner has " + atomContainer.getBondOrderSum(partner) + ", may have: " + atomTypes2[0].getBondOrderSum());
520
bond = atomContainer.getBond(atom, partner);
521
logger.debug("Bond order was " + bond.getOrder());
522
bond.setOrder(bond.getOrder() + 1);
523
logger.debug("Bond order now " + bond.getOrder());
534
public void saturateRingSystems(IAtomContainer atomContainer) throws CDKException
536
IRingSet rs = new SSSRFinder(atomContainer.getBuilder().newMolecule(atomContainer)).findSSSR();
537
List ringSets = RingPartitioner.partitionRings(rs);
538
IAtomContainer ac = null;
541
for (int f = 0; f < ringSets.size(); f++)
543
rs = (IRingSet)ringSets.get(f);
544
List containers = RingSetManipulator.getAllAtomContainers(rs);
545
for (int counter=0; counter<containers.size(); counter++) {
546
ac = (IAtomContainer)containers.get(counter);
547
temp = new int[ac.getAtomCount()];
548
for (int g = 0; g < ac.getAtomCount(); g++)
550
atom = ac.getAtom(g);
551
temp[g] = atom.getHydrogenCount();
552
atom.setHydrogenCount(atomContainer.getConnectedBondsCount(atom) - ac.getConnectedBondsCount(atom) - temp[g]);
555
for (int g = 0; g < ac.getAtomCount(); g++)
557
atom = ac.getAtom(g);
558
atom.setHydrogenCount(temp[g]);
565
* Recursivly fixes bond orders in a molecule for
566
* which only connectivities but no bond orders are know.
568
*@ param molecule The molecule to fix the bond orders for
569
*@ param bond The number of the bond to treat in this recursion step
570
*@ return true if the bond order which was implemented was ok.
572
/*private boolean recursiveBondOrderFix(Molecule molecule, int bondNumber)
577
Atom[] partners = null;
578
AtomType[] atomTypes1 = null;
579
AtomType[] atomTypes2 = null;
580
int maxBondOrder = 0;
581
int oldBondOrder = 0;
582
if (bondNumber < molecule.getBondCount())
584
Bond bond = molecule.getBondAt(f);
590
atom = bond.getAtomAt(0);
591
partner = bond.getAtomAt(1);
592
atomTypes1 = atf.getAtomTypes(atom.getSymbol(), atf.ATOMTYPE_ID_STRUCTGEN);
593
atomTypes2 = atf.getAtomTypes(partner.getSymbol(), atf.ATOMTYPE_ID_STRUCTGEN);
594
maxBondOrder = Math.min(atomTypes1[0].getMaxBondOrder(), atomTypes2[0].getMaxBondOrder());
595
for (int f = 1; f <= maxBondOrder; f++)
597
oldBondOrder = bond.getOrder()
599
if (!isOverSaturated(atom, molecule) && !isOverSaturated(partner, molecule))
601
if (!recursiveBondOrderFix(molecule, bondNumber + 1)) break;
606
bond.setOrder(oldBondOrder);
614
* Calculate the number of missing hydrogens by substracting the number of
615
* bonds for the atom from the expected number of bonds. Charges are included
616
* in the calculation. The number of expected bonds is defined by the AtomType
617
* generated with the AtomTypeFactory.
619
* @param atom Description of the Parameter
620
* @param container Description of the Parameter
621
* @return Description of the Return Value
622
* @see AtomTypeFactory
624
public int calculateNumberOfImplicitHydrogens(IAtom atom, IAtomContainer container) throws CDKException {
625
return this.calculateNumberOfImplicitHydrogens(atom, container, false);
628
public int calculateNumberOfImplicitHydrogens(IAtom atom) throws CDKException {
629
java.util.List bonds = new java.util.ArrayList();
630
return this.calculateNumberOfImplicitHydrogens(atom, 0, 0, bonds, false);
633
public int calculateNumberOfImplicitHydrogens(IAtom atom, IAtomContainer container, boolean throwExceptionForUnknowAtom) throws CDKException {
634
return this.calculateNumberOfImplicitHydrogens(atom,
635
container.getBondOrderSum(atom),
636
container.getConnectedSingleElectronsCount(atom),
637
container.getConnectedBondsList(atom),
638
throwExceptionForUnknowAtom
643
* Calculate the number of missing hydrogens by substracting the number of
644
* bonds for the atom from the expected number of bonds. Charges are included
645
* in the calculation. The number of expected bonds is defined by the AtomType
646
* generated with the AtomTypeFactory.
648
* @param atom Description of the Parameter
649
* @param throwExceptionForUnknowAtom Should an exception be thrown if an unknown atomtype is found or 0 returned ?
650
* @return Description of the Return Value
651
* @see AtomTypeFactory
653
public int calculateNumberOfImplicitHydrogens(IAtom atom, double bondOrderSum, double singleElectronSum, java.util.List connectedBonds, boolean throwExceptionForUnknowAtom)
654
throws CDKException {
655
int missingHydrogen = 0;
656
if (atom instanceof IPseudoAtom) {
657
// don't figure it out... it simply does not lack H's
658
} else if (atom.getAtomicNumber() == 1 || atom.getSymbol().equals("H")) {
659
missingHydrogen = (int) (1 - bondOrderSum - singleElectronSum - atom.getFormalCharge());
661
logger.info("Calculating number of missing hydrogen atoms");
663
IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
664
if(atomTypes.length==0 && throwExceptionForUnknowAtom)
666
logger.debug("Found atomtypes: " + atomTypes.length);
667
if (atomTypes.length > 0) {
668
IAtomType defaultAtom = atomTypes[0];
669
logger.debug("DefAtom: ", defaultAtom);
670
missingHydrogen = (int) (defaultAtom.getBondOrderSum() -
671
bondOrderSum - singleElectronSum + atom.getFormalCharge());
672
if (atom.getFlag(CDKConstants.ISAROMATIC)){
673
boolean subtractOne=true;
674
for(int i=0;i<connectedBonds.size();i++){
675
IBond conBond = (IBond)connectedBonds.get(i);
676
if(conBond.getOrder()==2 || conBond.getOrder()==CDKConstants.BONDORDER_AROMATIC)
682
logger.debug("Atom: ", atom.getSymbol());
683
logger.debug(" max bond order: " + defaultAtom.getBondOrderSum());
684
logger.debug(" bond order sum: " + bondOrderSum);
685
logger.debug(" charge : " + atom.getFormalCharge());
687
logger.warn("Could not find atom type for ", atom.getSymbol());
690
return missingHydrogen;