Source code: joelib/util/IsomerismDetection.java
1 ///////////////////////////////////////////////////////////////////////////////
2 // Filename: $RCSfile: IsomerismDetection.java,v $
3 // Purpose: Atom representation.
4 // Language: Java
5 // Compiler: JDK 1.4
6 // Authors: Joerg K. Wegner
7 // Version: $Revision: 1.6 $
8 // $Date: 2003/08/22 15:56:21 $
9 // $Author: wegner $
10 //
11 // Copyright (c) Dept. Computer Architecture, University of Tuebingen, Germany
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation version 2 of the License.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 ///////////////////////////////////////////////////////////////////////////////
22 package joelib.util;
23
24 import joelib.math.XYZVector;
25
26 import joelib.molecule.JOEAtom;
27 import joelib.molecule.JOEBond;
28
29 import joelib.util.iterator.NbrAtomIterator;
30
31 import org.apache.log4j.Category;
32
33
34 /*==========================================================================*
35 * IMPORTS
36 *========================================================================== */
37 /*==========================================================================*
38 * CLASS DECLARATION
39 *========================================================================== */
40
41 /**
42 * Helper class to detect E/Z isomerism.
43 *
44 * @author wegnerj
45 * @license GPL
46 * @cvsversion $Revision: 1.6 $, $Date: 2003/08/22 15:56:21 $
47 */
48 public class IsomerismDetection
49 {
50 //~ Static fields/initializers /////////////////////////////////////////////
51
52 /*-------------------------------------------------------------------------*
53 * private static member variables
54 *------------------------------------------------------------------------- */
55
56 // Obtain a suitable logger.
57 private static Category logger = Category.getInstance(
58 "joelib.util.IsomerismDetection");
59
60 /*-------------------------------------------------------------------------*
61 * public static member variables
62 *------------------------------------------------------------------------- */
63 public static final int EZ_ISOMERISM_UNDEFINED = 0;
64 public static final int CISTRANS_ISOMERISM_UNDEFINED = 0;
65 public static final int Z_ISOMERISM = 1;
66 public static final int E_ISOMERISM = 2;
67 public static final int CIS_ISOMERISM = 1;
68 public static final int TRANS_ISOMERISM = 2;
69
70 //~ Constructors ///////////////////////////////////////////////////////////
71
72 /*-------------------------------------------------------------------------*
73 * constructor
74 *------------------------------------------------------------------------- */
75 public IsomerismDetection()
76 {
77 if (logger.isDebugEnabled())
78 {
79 logger.debug("Initialize " + this.getClass().getName());
80 }
81 }
82
83 //~ Methods ////////////////////////////////////////////////////////////////
84
85 /**
86 * Sets up/down informations for cis/trans isomerism of a double bond.<br>
87 * Cases:<br>
88 * E/trans -- bondUP/doubleBond/bondUP<br>
89 * Z/cis -- bondDOWN/doubleBond/bondUP<br>
90 * <br>
91 * The method gets two heavy atoms with the highest atomic number and sets the corresponding
92 * up/down bond flags for cis/trans isomeres.
93 *
94 *
95 * @param bond the double bond
96 * @return ezType new cis/trans type for this double bond
97 * @see #EZ_ISOMERISM_UNDEFINED
98 * @see #Z_ISOMERISM
99 * @see #E_ISOMERISM
100 * @see #isCisTransBond(JOEBond)
101 * @see #getCisTransFrom2D3D(JOEBond)
102 */
103 public static void setCisTransBond(JOEBond bond, int ezType)
104 {
105 if (!bond.isDouble())
106 {
107 return;
108 }
109
110 JOEAtom begin = bond.getBeginAtom();
111 JOEAtom end = bond.getEndAtom();
112
113 begin.nbrAtomIterator();
114
115 NbrAtomIterator nait = begin.nbrAtomIterator();
116 JOEBond tmpBond;
117 JOEBond beginBond = null;
118 JOEAtom nbrAtom;
119
120 while (nait.hasNext())
121 {
122 nbrAtom = nait.nextNbrAtom();
123 tmpBond = nait.actualBond();
124
125 if (nbrAtom != end)
126 {
127 if ((beginBond == null) ||
128 (nbrAtom.getAtomicNum() > begin.getAtomicNum()))
129 {
130 beginBond = tmpBond;
131 }
132 }
133 }
134
135 nait = end.nbrAtomIterator();
136
137 JOEBond endBond = null;
138
139 while (nait.hasNext())
140 {
141 nbrAtom = nait.nextNbrAtom();
142 tmpBond = nait.actualBond();
143
144 if (nbrAtom != begin)
145 {
146 if ((endBond == null) ||
147 (nbrAtom.getAtomicNum() > end.getAtomicNum()))
148 {
149 endBond = tmpBond;
150 }
151 }
152 }
153
154 if ((beginBond == null) || (endBond == null))
155 {
156 return;
157 }
158
159 if (ezType == Z_ISOMERISM)
160 {
161 beginBond.setDown();
162 endBond.setUp();
163 }
164 else if (ezType == E_ISOMERISM)
165 {
166 beginBond.setUp();
167 endBond.setUp();
168 }
169 }
170
171 /*-------------------------------------------------------------------------*
172 * public static methods
173 *------------------------------------------------------------------------- */
174
175 /**
176 * Checks bonds for cis/trans isomerism using the SMILES flags up/down bond connected to a double bond.<br>
177 * Cases:<br>
178 * E/trans -- bondUP/doubleBond/bondUP<br>
179 * E/trans -- bondDOWN/doubleBond/bondDOWN<br>
180 * Z/cis -- bondUP/doubleBond/bondDOWN<br>
181 * Z/cis -- bondDOWN/doubleBond/bondUP<br>
182 * <br>
183 * This method does not check multiple definitions.
184 * If no up/down informations are available, the {@link #getCisTransFrom2D3D(JOEBond)} method is used
185 * also to get cis/trans informations.
186 * Single bond flags will be not set if a cis/trans double bond is detected.
187 *
188 * @param bond
189 * @return int Z_ISOMERISM for cis, E_ISOMERISM for trans and EZ_ISOMERISM_UNDEFINED for undefined isomerism
190 * @see #EZ_ISOMERISM_UNDEFINED
191 * @see #Z_ISOMERISM
192 * @see #E_ISOMERISM
193 * @see #getCisTransFrom2D3D(JOEBond)
194 */
195 public static int isCisTransBond(JOEBond bond)
196 {
197 return isCisTransBond(bond, false);
198 }
199
200 /**
201 * Checks bonds for cis/trans isomerism using the SMILES flags up/down bond connected to a double bond.<br>
202 * Cases:<br>
203 * E/trans -- bondUP/doubleBond/bondUP<br>
204 * E/trans -- bondDOWN/doubleBond/bondDOWN<br>
205 * Z/cis -- bondUP/doubleBond/bondDOWN<br>
206 * Z/cis -- bondDOWN/doubleBond/bondUP<br>
207 * <br>
208 * This method does not check multiple definitions.
209 * If no up/down informations are available, the {@link #getCisTransFrom2D3D(JOEBond)} method is used
210 * also to get cis/trans informations.
211 *
212 *
213 * @param bond
214 * @param setSingleBondFlags set the single bond flags {@link JOEBond#JOE_TORUP_BOND}/{@link JOEBond#JOE_TORDOWN_BOND}, if <tt>true</tt> and a cis/trans bond is detected.
215 * @return int Z_ISOMERISM for cis, E_ISOMERISM for trans and EZ_ISOMERISM_UNDEFINED for undefined isomerism
216 * @see #EZ_ISOMERISM_UNDEFINED
217 * @see #Z_ISOMERISM
218 * @see #E_ISOMERISM
219 * @see #getCisTransFrom2D3D(JOEBond)
220 */
221 public static int isCisTransBond(JOEBond bond, boolean setSingleBondFlags)
222 {
223 if (!bond.isDouble())
224 {
225 return EZ_ISOMERISM_UNDEFINED;
226 }
227
228 JOEAtom begin = bond.getBeginAtom();
229 JOEAtom end = bond.getEndAtom();
230
231 begin.nbrAtomIterator();
232
233 NbrAtomIterator nait = begin.nbrAtomIterator();
234 JOEBond tmpBond;
235 JOEBond beginBond = null;
236 JOEAtom nbrAtom;
237
238 while (nait.hasNext())
239 {
240 nbrAtom = nait.nextNbrAtom();
241 tmpBond = nait.actualBond();
242
243 if (((tmpBond.getFlags() & JOEBond.JOE_TORUP_BOND) != 0) ||
244 ((tmpBond.getFlags() & JOEBond.JOE_TORDOWN_BOND) != 0))
245 {
246 beginBond = tmpBond;
247
248 break;
249 }
250 }
251
252 nait = end.nbrAtomIterator();
253
254 JOEBond endBond = null;
255
256 while (nait.hasNext())
257 {
258 nbrAtom = nait.nextNbrAtom();
259 tmpBond = nait.actualBond();
260
261 if (((tmpBond.getFlags() & JOEBond.JOE_TORUP_BOND) != 0) ||
262 ((tmpBond.getFlags() & JOEBond.JOE_TORDOWN_BOND) != 0))
263 {
264 endBond = tmpBond;
265
266 break;
267 }
268 }
269
270 if ((beginBond == null) || (endBond == null))
271 {
272 //try to resolve cis/trans isomerism from 2D/3D structure
273 int ez = getCisTransFrom2D3D(bond, setSingleBondFlags);
274
275 return ez;
276 }
277
278 if ((beginBond.isUp() && endBond.isUp()) ||
279 (beginBond.isDown() && endBond.isDown()))
280 {
281 return E_ISOMERISM;
282 }
283
284 if ((beginBond.isDown() && endBond.isUp()) ||
285 (beginBond.isUp() && endBond.isDown()))
286 {
287 return Z_ISOMERISM;
288 }
289
290 return EZ_ISOMERISM_UNDEFINED;
291 }
292
293 /**
294 * Checks bonds for cis/trans isomerism using 2D/3D informations.
295 * Single bond flags will be not set if a cis/trans double bond is detected.
296 *
297 * @param bond
298 * @param setSingleBondFlags set the single bond flags {@link JOEBond#JOE_TORUP_BOND}/{@link JOEBond#JOE_TORDOWN_BOND}, if <tt>true</tt> and a cis/trans bond is detected.
299 * @return int Z_ISOMERISM for cis, E_ISOMERISM for trans and EZ_ISOMERISM_UNDEFINED for undefined isomerism
300 * @see #EZ_ISOMERISM_UNDEFINED
301 * @see #Z_ISOMERISM
302 * @see #E_ISOMERISM
303 * @see #isCisTransBond(JOEBond)
304 */
305 public static int getCisTransFrom2D3D(JOEBond bond)
306 {
307 return getCisTransFrom2D3D(bond);
308 }
309
310 /**
311 * Checks bonds for cis/trans isomerism using 2D/3D informations.
312 *
313 * @param bond
314 * @param setSingleBondFlags set the single bond flags {@link JOEBond#JOE_TORUP_BOND}/{@link JOEBond#JOE_TORDOWN_BOND}, if <tt>true</tt> and a cis/trans bond is detected.
315 * @return int Z_ISOMERISM for cis, E_ISOMERISM for trans and EZ_ISOMERISM_UNDEFINED for undefined isomerism
316 * @see #EZ_ISOMERISM_UNDEFINED
317 * @see #Z_ISOMERISM
318 * @see #E_ISOMERISM
319 * @see #isCisTransBond(JOEBond)
320 */
321 public static int getCisTransFrom2D3D(JOEBond bond,
322 boolean setSingleBondFlags)
323 {
324 if (!bond.isDouble() && bond.isInRing())
325 {
326 return EZ_ISOMERISM_UNDEFINED;
327 }
328
329 JOEAtom begin = bond.getBeginAtom();
330 JOEAtom end = bond.getEndAtom();
331
332 //skip allenes
333 if ((begin.getHyb() == 1) || (end.getHyb() == 1))
334 {
335 return EZ_ISOMERISM_UNDEFINED;
336 }
337
338 begin.nbrAtomIterator();
339
340 NbrAtomIterator nait = begin.nbrAtomIterator();
341 JOEBond tmpBond;
342 JOEBond beginBond = null;
343 JOEAtom nbrAtom;
344 JOEAtom afterBeginAtom = null;
345 JOEAtom afterEndAtom = null;
346 boolean uniqueHeavyAtom = false;
347
348 while (nait.hasNext())
349 {
350 nbrAtom = nait.nextNbrAtom();
351 tmpBond = nait.actualBond();
352
353 if (nbrAtom != end)
354 {
355 if (beginBond == null)
356 {
357 // skip hydrogens
358 if (!nbrAtom.isHydrogen())
359 {
360 beginBond = tmpBond;
361 afterBeginAtom = nbrAtom;
362 uniqueHeavyAtom = true;
363 }
364 }
365 else
366 {
367 // skip hydrogens
368 if (!nbrAtom.isHydrogen())
369 {
370 if (nbrAtom.getAtomicNum() > begin.getAtomicNum())
371 {
372 beginBond = tmpBond;
373 afterBeginAtom = nbrAtom;
374 uniqueHeavyAtom = true;
375 }
376 else if (nbrAtom.getAtomicNum() == begin.getAtomicNum())
377 {
378 uniqueHeavyAtom = false;
379 }
380 }
381 }
382 }
383 }
384
385 //do not use multiple heavy atoms
386 if (uniqueHeavyAtom == false)
387 {
388 beginBond = null;
389 afterBeginAtom = null;
390 }
391
392 nait = end.nbrAtomIterator();
393
394 JOEBond endBond = null;
395
396 while (nait.hasNext())
397 {
398 nbrAtom = nait.nextNbrAtom();
399 tmpBond = nait.actualBond();
400
401 if (nbrAtom != begin)
402 {
403 if (endBond == null)
404 {
405 // skip hydrogens
406 if (!nbrAtom.isHydrogen())
407 {
408 endBond = tmpBond;
409 afterEndAtom = nbrAtom;
410 uniqueHeavyAtom = true;
411 }
412 }
413 else
414 {
415 // skip hydrogens
416 if (!nbrAtom.isHydrogen())
417 {
418 if (nbrAtom.getAtomicNum() > end.getAtomicNum())
419 {
420 endBond = tmpBond;
421 afterEndAtom = nbrAtom;
422 uniqueHeavyAtom = true;
423 }
424 else if (nbrAtom.getAtomicNum() == end.getAtomicNum())
425 {
426 uniqueHeavyAtom = false;
427 }
428 }
429 }
430 }
431 }
432
433 //do not use multiple heavy atoms
434 if (uniqueHeavyAtom == false)
435 {
436 endBond = null;
437 afterEndAtom = null;
438 }
439
440 // one side of the double bond is not really cis/trans !
441 if ((beginBond == null) || (endBond == null))
442 {
443 return EZ_ISOMERISM_UNDEFINED;
444 }
445
446 if (Math.abs(XYZVector.calcTorsionAngle(afterBeginAtom.getVector(),
447 begin.getVector(), end.getVector(),
448 afterEndAtom.getVector())) > 10.0)
449 {
450 if (setSingleBondFlags)
451 {
452 beginBond.setUp();
453 endBond.setUp();
454 }
455
456 return E_ISOMERISM;
457 }
458 else
459 {
460 if (setSingleBondFlags)
461 {
462 beginBond.setDown();
463 endBond.setUp();
464 }
465
466 return Z_ISOMERISM;
467 }
468 }
469 }
470 ///////////////////////////////////////////////////////////////////////////////
471 // END OF FILE.
472 ///////////////////////////////////////////////////////////////////////////////