~ubuntu-branches/ubuntu/maverick/cdk/maverick

« back to all changes in this revision

Viewing changes to src/org/openscience/cdk/tools/SaturationChecker.java

  • Committer: Bazaar Package Importer
  • Author(s): Paul Cager
  • Date: 2008-04-09 21:17:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080409211753-46lmjw5z8mx5pd8d
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $RCSfile$
 
2
 *  $Author: egonw $
 
3
 *  $Date: 2007-03-14 18:33:52 +0100 (Wed, 14 Mar 2007) $
 
4
 *  $Revision: 8121 $
 
5
 *
 
6
 *  Copyright (C) 2001-2007  The Chemistry Development Kit (CDK) project
 
7
 *
 
8
 *  Contact: cdk-devel@lists.sourceforge.net
 
9
 *
 
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.
 
18
 *
 
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.
 
23
 *
 
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.
 
27
 *
 
28
 */
 
29
package org.openscience.cdk.tools;
 
30
 
 
31
import java.io.IOException;
 
32
import java.util.Iterator;
 
33
import java.util.List;
 
34
 
 
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;
 
49
 
 
50
/**
 
51
 * Provides methods for checking whether an atoms valences are saturated with
 
52
 * respect to a particular atom type.
 
53
 *
 
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).
 
57
 *
 
58
 * @author     steinbeck
 
59
 * @author  Egon Willighagen
 
60
 * @cdk.created    2001-09-04
 
61
 *
 
62
 * @cdk.keyword    saturation
 
63
 * @cdk.keyword    atom, valency
 
64
 * 
 
65
 * @cdk.module     valencycheck
 
66
 */
 
67
public class SaturationChecker implements IValencyChecker, IDeduceBondOrderTool {
 
68
 
 
69
        AtomTypeFactory structgenATF;
 
70
 
 
71
        private LoggingTool logger;
 
72
 
 
73
        public SaturationChecker() throws IOException, ClassNotFoundException
 
74
        {
 
75
                logger = new LoggingTool(this);
 
76
        }
 
77
 
 
78
    /**
 
79
     * @param builder the ChemObjectBuilder implementation used to construct the AtomType's.
 
80
     */
 
81
    protected AtomTypeFactory getAtomTypeFactory(IChemObjectBuilder builder) throws CDKException {
 
82
        if (structgenATF == null) {
 
83
            try {
 
84
                structgenATF = AtomTypeFactory.getInstance(
 
85
                    "org/openscience/cdk/config/data/structgen_atomtypes.xml", 
 
86
                    builder
 
87
                );
 
88
            } catch (Exception exception) {
 
89
                logger.debug(exception);
 
90
                throw new CDKException("Could not instantiate AtomTypeFactory!", exception);
 
91
            }
 
92
        }
 
93
        return structgenATF;
 
94
    }
 
95
 
 
96
        public boolean hasPerfectConfiguration(IAtom atom, IAtomContainer ac) throws CDKException
 
97
        {
 
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)
 
102
      return true;
 
103
                logger.debug("*** Checking for perfect configuration ***");
 
104
                try
 
105
                {
 
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)
 
110
                {
 
111
                }
 
112
                for (int f = 0; f < atomTypes.length; f++)
 
113
                {
 
114
                        if (bondOrderSum == atomTypes[f].getBondOrderSum() && 
 
115
                maxBondOrder == atomTypes[f].getMaxBondOrder())
 
116
                        {
 
117
                                try
 
118
                                {
 
119
                                        logger.debug("Atom " + ac.getAtomNumber(atom) + " has perfect configuration");
 
120
                                } catch (Exception exc)
 
121
                                {
 
122
                                }
 
123
                                return true;
 
124
                        }
 
125
                }
 
126
                try
 
127
                {
 
128
                        logger.debug("*** Atom " + ac.getAtomNumber(atom) + " has imperfect configuration ***");
 
129
                } catch (Exception exc)
 
130
                {
 
131
                }
 
132
                return false;
 
133
        }
 
134
 
 
135
    /**
 
136
     * Determines of all atoms on the AtomContainer are saturated.
 
137
     */
 
138
        public boolean isSaturated(IAtomContainer container) throws CDKException {
 
139
        return allSaturated(container);
 
140
    }
 
141
        public boolean allSaturated(IAtomContainer ac) throws CDKException
 
142
        {
 
143
        logger.debug("Are all atoms saturated?");
 
144
        for (int f = 0; f < ac.getAtomCount(); f++) {
 
145
            if (!isSaturated(ac.getAtom(f), ac)) {
 
146
                return false;
 
147
            }
 
148
        }
 
149
        return true;
 
150
    }
 
151
 
 
152
    /**
 
153
     * Returns wether a bond is unsaturated. A bond is unsaturated if 
 
154
     * <b>both</b> Atoms in the bond are unsaturated.
 
155
     */
 
156
    public boolean isUnsaturated(IBond bond, IAtomContainer atomContainer) throws CDKException {
 
157
 
 
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);
 
162
        }
 
163
        return isUnsaturated;
 
164
    }
 
165
    
 
166
    /**
 
167
     * Returns wether a bond is saturated. A bond is saturated if 
 
168
     * <b>both</b> Atoms in the bond are saturated.
 
169
     */
 
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);
 
175
        }
 
176
        return isSaturated;
 
177
    }
 
178
    
 
179
    /**
 
180
     * Checks wether an Atom is saturated by comparing it with known AtomTypes.
 
181
     */
 
182
        public boolean isSaturated(IAtom atom, IAtomContainer ac) throws CDKException {
 
183
                IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
 
184
        if(atomTypes.length==0)
 
185
          return true;
 
186
        double bondOrderSum = ac.getBondOrderSum(atom);
 
187
        double maxBondOrder = ac.getMaximumBondOrder(atom);
 
188
        int hcount = atom.getHydrogenCount();
 
189
        int charge = atom.getFormalCharge();
 
190
        try {
 
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) {
 
196
            logger.debug(exc);
 
197
        }
 
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 ! ***");
 
202
                    return true;
 
203
                }
 
204
        }
 
205
        logger.debug("*** Bad ! ***");
 
206
        return false;
 
207
    }
 
208
 
 
209
        /**
 
210
         * Checks if the current atom has exceeded its bond order sum value.
 
211
         *
 
212
         * @param  atom The Atom to check
 
213
         * @param  ac   The atomcontainer context
 
214
         * @return      oversaturated or not
 
215
         */
 
216
        public boolean isOverSaturated(IAtom atom, IAtomContainer ac) throws CDKException
 
217
        {
 
218
                IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
 
219
    if(atomTypes.length==0)
 
220
      return false;
 
221
                double bondOrderSum = ac.getBondOrderSum(atom);
 
222
                double maxBondOrder = ac.getMaximumBondOrder(atom);
 
223
                int hcount = atom.getHydrogenCount();
 
224
                int charge = atom.getFormalCharge();
 
225
                try
 
226
                {
 
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)
 
232
                {
 
233
                }
 
234
                for (int f = 0; f < atomTypes.length; f++)
 
235
                {
 
236
                        if (bondOrderSum - charge + hcount > atomTypes[f].getBondOrderSum())
 
237
                        {
 
238
                                logger.debug("*** Good ! ***");
 
239
                                return true;
 
240
                        }
 
241
                }
 
242
                logger.debug("*** Bad ! ***");
 
243
                return false;
 
244
        }
 
245
    
 
246
        /**
 
247
         * Returns the currently maximum formable bond order for this atom.
 
248
         *
 
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
 
252
         */
 
253
        public double getCurrentMaxBondOrder(IAtom atom, IAtomContainer ac) throws CDKException
 
254
        {
 
255
                IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
 
256
    if(atomTypes.length==0)
 
257
      return 0;
 
258
                double bondOrderSum = ac.getBondOrderSum(atom);
 
259
                int hcount = atom.getHydrogenCount();
 
260
                double max = 0;
 
261
                double current = 0;
 
262
                for (int f = 0; f < atomTypes.length; f++)
 
263
                {
 
264
                        current = hcount + bondOrderSum;
 
265
                        if (atomTypes[f].getBondOrderSum() - current > max)
 
266
                        {
 
267
                                max = atomTypes[f].getBondOrderSum() - current;
 
268
                        }
 
269
                }
 
270
                return max;
 
271
        }
 
272
 
 
273
 
 
274
    /**
 
275
     * Resets the bond orders of all atoms to 1.0.
 
276
     */
 
277
    public void unsaturate(IAtomContainer atomContainer) {
 
278
        Iterator bonds = atomContainer.bonds();
 
279
        while (bonds.hasNext()) {
 
280
                ((IBond)bonds.next()).setOrder(CDKConstants.BONDORDER_SINGLE);
 
281
        }
 
282
    }
 
283
    
 
284
    /**
 
285
     * Resets the bond order of the Bond to 1.0.
 
286
     */
 
287
    public void unsaturateBonds(IAtomContainer container) {
 
288
        Iterator bonds = container.bonds();
 
289
        while (bonds.hasNext()) ((IBond)bonds.next()).setOrder(1.0);
 
290
    }
 
291
 
 
292
        /**
 
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
 
296
         *
 
297
         * @cdk.keyword bond order, calculation
 
298
     * @cdk.created 2003-10-03
 
299
         */
 
300
    public void newSaturate(IAtomContainer atomContainer) throws CDKException {
 
301
        logger.info("Saturating atomContainer by adjusting bond orders...");
 
302
        boolean allSaturated = allSaturated(atomContainer);
 
303
        if (!allSaturated) {
 
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"))){
 
309
                int atomtohandle=0;
 
310
                if(bonds[i].getAtom(0).getSymbol().equals("N"))
 
311
                  atomtohandle=1;
 
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)){
 
316
                    bond.setOrder(2);
 
317
                    bonds[i].setOrder(1);
 
318
                    break;
 
319
                  }
 
320
                }
 
321
              }
 
322
            }
 
323
            if (!succeeded) {
 
324
                throw new CDKException("Could not saturate this atomContainer!");
 
325
            }
 
326
        }
 
327
    }
 
328
 
 
329
    /**
 
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
 
333
     */
 
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];
 
339
 
 
340
            // determine bonds left
 
341
            int leftBondCount = bonds.length-1;
 
342
            IBond[] leftBonds = new IBond[leftBondCount];
 
343
            System.arraycopy(bonds, 1, leftBonds, 0, leftBondCount);
 
344
 
 
345
            // examine this bond
 
346
            if (isUnsaturated(bond, atomContainer)) {
 
347
                // either this bonds should be saturated or not
 
348
                
 
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);
 
354
                } else {
 
355
                    bondsAreFullySaturated = false;
 
356
                }
 
357
 
 
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);
 
363
                    if (couldSaturate) {
 
364
                        if (leftBondCount > 0) {
 
365
                            logger.debug("Recursing with saturated bond with #bonds: " + leftBondCount);
 
366
                            bondsAreFullySaturated = newSaturate(leftBonds, atomContainer);
 
367
                        } else {
 
368
                            bondsAreFullySaturated = true;
 
369
                        }
 
370
                    } else {
 
371
                        bondsAreFullySaturated = false;
 
372
                        // no need to recurse, because we already know that this bond
 
373
                        // unsaturated does not work
 
374
                    }
 
375
                }
 
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);
 
381
                } else {
 
382
                    bondsAreFullySaturated = true;
 
383
                }
 
384
            } else {
 
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);
 
391
                } else {
 
392
                    bondsAreFullySaturated = !isUnsaturated(bond, atomContainer);
 
393
                }
 
394
            }
 
395
        }
 
396
        logger.debug("Is bond set fully saturated?: " + bondsAreFullySaturated);
 
397
        logger.debug("Returning to level: " + (bonds.length + 1));
 
398
        return bondsAreFullySaturated;
 
399
    }
 
400
    
 
401
    /**
 
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
 
405
     */
 
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;
 
435
                            }
 
436
                        }
 
437
                    }
 
438
                }
 
439
            }
 
440
        }
 
441
        return isSaturated(bond, atomContainer);
 
442
    }
 
443
 
 
444
    /**
 
445
     * Determines if the atom can be of type AtomType.
 
446
     */
 
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!");
 
451
           return true;
 
452
        }
 
453
        logger.debug("    No Match");
 
454
        return false;
 
455
    }
 
456
 
 
457
    /**
 
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
 
462
     *
 
463
     */
 
464
    public void saturate(IAtomContainer atomContainer) throws CDKException {
 
465
        /* newSaturate(atomContainer);
 
466
    }
 
467
    public void oldSaturate(AtomContainer atomContainer) throws CDKException { */
 
468
        IAtom partner = null;
 
469
                IAtom atom = null;
 
470
                java.util.List partners = null;
 
471
                IAtomType[] atomTypes1 = null;
 
472
                IAtomType[] atomTypes2 = null;
 
473
                IBond bond = null;
 
474
                for (int i = 1; i < 4; i++)
 
475
                {
 
476
                        // handle atoms with degree 1 first and then proceed to higher order
 
477
                        for (int f = 0; f < atomContainer.getAtomCount(); f++)
 
478
                        {
 
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)
 
485
          {
 
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++)
 
489
              {
 
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)
 
494
                  return;
 
495
                if (atomContainer.getBond(partner,atom).getFlag(CDKConstants.ISAROMATIC) && atomContainer.getBondOrderSum(partner) < atomTypes2[0].getBondOrderSum() - partner.getHydrogenCount())
 
496
                {
 
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());
 
502
                  break;
 
503
                }
 
504
              }
 
505
            }
 
506
            if (atomContainer.getBondOrderSum(atom) < atomTypes1[0].getBondOrderSum() - atom.getHydrogenCount())
 
507
            {
 
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++)
 
511
              {
 
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)
 
516
                  return;
 
517
                if (atomContainer.getBondOrderSum(partner) < atomTypes2[0].getBondOrderSum() - partner.getHydrogenCount())
 
518
                {
 
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());
 
524
                  break;
 
525
                }
 
526
              }
 
527
            }
 
528
          }
 
529
                                }
 
530
                        }
 
531
                }
 
532
    }
 
533
    
 
534
        public void saturateRingSystems(IAtomContainer atomContainer) throws CDKException
 
535
        {
 
536
                IRingSet rs = new SSSRFinder(atomContainer.getBuilder().newMolecule(atomContainer)).findSSSR();
 
537
                List ringSets = RingPartitioner.partitionRings(rs);
 
538
                IAtomContainer ac = null;
 
539
                IAtom atom = null;
 
540
                int temp[];
 
541
                for (int f = 0; f < ringSets.size(); f++)
 
542
                {
 
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++)
 
549
                                {
 
550
                                        atom = ac.getAtom(g);
 
551
                                        temp[g] = atom.getHydrogenCount();
 
552
                                        atom.setHydrogenCount(atomContainer.getConnectedBondsCount(atom) - ac.getConnectedBondsCount(atom) - temp[g]);
 
553
                                }
 
554
                                saturate(ac);
 
555
                                for (int g = 0; g < ac.getAtomCount(); g++)
 
556
                                {
 
557
                                        atom = ac.getAtom(g);
 
558
                                        atom.setHydrogenCount(temp[g]);
 
559
                                }
 
560
                        }
 
561
                }
 
562
        }
 
563
        
 
564
        /*
 
565
         * Recursivly fixes bond orders in a molecule for 
 
566
         * which only connectivities but no bond orders are know.
 
567
         *
 
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.
 
571
         */
 
572
        /*private boolean recursiveBondOrderFix(Molecule molecule, int bondNumber)
 
573
        {       
 
574
 
 
575
                Atom partner = null;
 
576
                Atom atom = null;
 
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())
 
583
                {       
 
584
                        Bond bond = molecule.getBondAt(f);
 
585
                }
 
586
                else 
 
587
                {
 
588
                        return true;
 
589
                }
 
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++)
 
596
                {
 
597
                        oldBondOrder = bond.getOrder()
 
598
                        bond.setOrder(f);
 
599
                        if (!isOverSaturated(atom, molecule) && !isOverSaturated(partner, molecule))
 
600
                        {
 
601
                                if (!recursiveBondOrderFix(molecule, bondNumber + 1)) break;
 
602
                                        
 
603
                        }
 
604
                        else
 
605
                        {
 
606
                                bond.setOrder(oldBondOrder);
 
607
                                return false;   
 
608
                        }
 
609
                }
 
610
                return true;
 
611
        }*/
 
612
 
 
613
        /**
 
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.
 
618
         *
 
619
         * @param  atom      Description of the Parameter
 
620
         * @param  container Description of the Parameter
 
621
         * @return           Description of the Return Value
 
622
         * @see              AtomTypeFactory
 
623
         */
 
624
        public int calculateNumberOfImplicitHydrogens(IAtom atom, IAtomContainer container) throws CDKException {
 
625
        return this.calculateNumberOfImplicitHydrogens(atom, container, false);
 
626
    }
 
627
    
 
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);
 
631
    }
 
632
 
 
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
 
639
        );
 
640
    }
 
641
    
 
642
    /**
 
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.
 
647
         *
 
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
 
652
         */
 
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());
 
660
        } else {
 
661
            logger.info("Calculating number of missing hydrogen atoms");
 
662
            // get default atom
 
663
            IAtomType[] atomTypes = getAtomTypeFactory(atom.getBuilder()).getAtomTypes(atom.getSymbol());
 
664
            if(atomTypes.length==0 && throwExceptionForUnknowAtom)
 
665
              return 0;
 
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)
 
677
                            subtractOne=false;
 
678
                    }
 
679
                    if(subtractOne)
 
680
                        missingHydrogen--;
 
681
                }
 
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());
 
686
            } else {
 
687
                logger.warn("Could not find atom type for ", atom.getSymbol());
 
688
            }
 
689
        }
 
690
        return missingHydrogen;
 
691
    }
 
692
 
 
693
}
 
694