rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,1003 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <string.h>
12
+
13
+ #include "mode.h"
14
+
15
+ #include "inpdef.h"
16
+ #include "extr_ct.h"
17
+ #include "ichitaut.h"
18
+ #include "ichi_bns.h"
19
+ /*******************************************************************/
20
+
21
+ #if( FIND_RING_SYSTEMS == 1 ) /* { */
22
+
23
+ /* local prototypes */
24
+ int are_alt_bonds( U_CHAR *bonds, int len );
25
+ int AddBondsPos( inp_ATOM *atom, T_BONDPOS *BondPosTmp, int nNumBondPosTmp, T_BONDPOS *BondPos, int nMaxNumBondPos, int nNumBondPos );
26
+ int AddEndPoints( T_ENDPOINT *EndPointTmp, int nNumNewEndPoint, T_ENDPOINT *EndPoint, int nMaxNumEndPoint, int nNumEndPoint);
27
+
28
+
29
+
30
+
31
+
32
+ /******************************************
33
+ *
34
+ * Tautomerism in 5- and 6-member rings
35
+ *
36
+ ******************************************/
37
+
38
+ const int NONE = (AT_RANK)~0;
39
+
40
+
41
+ /*
42
+ 1,5 Tautomerism in 6-member alt ring:
43
+
44
+ /=\ /==\
45
+ HN C=O <-> N C-OH
46
+ \=/ \\-//
47
+
48
+
49
+ 1,2 Tautomerism in 5-member ring:
50
+
51
+
52
+ HN--X N==X
53
+ | \\ | \
54
+ | Z <-> | Z
55
+ | / | //
56
+ N==Y HN--Y
57
+
58
+
59
+ 1,4 tautomerism in 7-member ring
60
+
61
+ /C==D //C-D
62
+ O=B \ HO-B \\
63
+ | E <-> | E
64
+ HO-A // O=A /
65
+ \\G-F \\G-F
66
+
67
+
68
+ 1,4 tautomerism in 5-member ring
69
+
70
+
71
+ O=B--C O-B==C
72
+ | \\ | \
73
+ | D <-> | D
74
+ | / | //
75
+ HO-A==E HO=A--E
76
+
77
+ */
78
+ typedef int CHECK_DFS_RING( inp_ATOM *atom, DFS_PATH *DfsPath, int nLenDfsPath, int nStartAtomNeighbor,
79
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
80
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
81
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
82
+ int *pnNumEndPoint, int *pnNumBondPos,
83
+ struct BalancedNetworkStructure *pBNS, struct BalancedNetworkData *pBD, int num_atoms );
84
+
85
+ typedef int CHECK_CENTERPOINT ( inp_ATOM *atom, int iat );
86
+
87
+ #if( REPLACE_ALT_WITH_TAUT == 1 )
88
+ #define REPLACE_THE_BOND(X) ( (X) == BOND_SINGLE || (X) == BOND_DOUBLE || (X) == BOND_ALTERN || (X) == BOND_ALT12NS )
89
+ #else
90
+ #define REPLACE_THE_BOND(X) ( (X) == BOND_SINGLE || (X) == BOND_DOUBLE )
91
+ #endif
92
+
93
+
94
+
95
+ CHECK_DFS_RING Check7MembTautRing;
96
+ CHECK_DFS_RING Check6MembTautRing;
97
+ CHECK_DFS_RING Check5MembTautRing;
98
+
99
+ int DFS_FindTautInARing( inp_ATOM *atom, int nStartAtom, int nStartAtomNeighbor,
100
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
101
+ int nCycleLen,
102
+ AT_RANK *nDfsPathPos, DFS_PATH *DfsPath,
103
+ CHECK_DFS_RING *CheckDfsRing, CHECK_CENTERPOINT *CheckCenterPoint,
104
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
105
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
106
+ int *pnNumEndPoint, int *pnNumBondPos,
107
+ struct BalancedNetworkStructure *pBNS, struct BalancedNetworkData *pBD, int num_atoms );
108
+
109
+ int bIsCenterPointStrict( inp_ATOM *atom, int iat )
110
+ {
111
+ if ( atom[iat].valence == atom[iat].chem_bonds_valence ) {
112
+ int endpoint_valence = get_endpoint_valence(atom[iat].el_number);
113
+ if ( endpoint_valence && (endpoint_valence > atom[iat].valence && /* added a check for negative charge or H 3-31-03 */
114
+ (atom[iat].num_H || atom[iat].charge == -1) ||
115
+ !atom[iat].charge && atom[iat].c_point) ) {
116
+ return 1; /* may appear to be tautomeric or chargable
117
+ (this increases chem_bonds_valence), should be explored */
118
+ }
119
+ return 0;
120
+ }
121
+ if (atom[iat].valence+1 == atom[iat].chem_bonds_valence &&
122
+ is_centerpoint_elem_strict( atom[iat].el_number ) ) {
123
+ return 1;
124
+ }
125
+ return 0;
126
+ }
127
+ /********************************************************************************/
128
+ int nGet14TautIn7MembAltRing( inp_ATOM *atom, int nStartAtom, int nStartAtomNeighbor,
129
+ int nStartAtomNeighborEndpoint, int nStartAtomNeighborNeighborEndpoint,
130
+ AT_RANK *nDfsPathPos, DFS_PATH *DfsPath, int nMaxLenDfsPath,
131
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
132
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
133
+ int *pnNumEndPoint, int *pnNumBondPos,
134
+ struct BalancedNetworkStructure *pBNS,
135
+ struct BalancedNetworkData *pBD, int num_atoms )
136
+ {
137
+ int nRet;
138
+
139
+ *pnNumEndPoint = 0;
140
+ *pnNumBondPos = 0;
141
+
142
+ if ( nMaxLenDfsPath <= 7 ) {
143
+ return -1; /* path is too short */
144
+ }
145
+
146
+ nRet = DFS_FindTautInARing( atom, nStartAtom, nStartAtomNeighbor,
147
+ nStartAtomNeighborEndpoint, nStartAtomNeighborNeighborEndpoint, 7,
148
+ nDfsPathPos, DfsPath,
149
+ Check7MembTautRing, bIsCenterPointStrict,
150
+ EndPoint, nMaxNumEndPoint,
151
+ BondPos, nMaxNumBondPos,
152
+ pnNumEndPoint, pnNumBondPos,
153
+ pBNS, pBD, num_atoms
154
+ );
155
+
156
+
157
+ return nRet;
158
+ }
159
+ /********************************************************************************/
160
+ int nGet14TautIn5MembAltRing( inp_ATOM *atom, int nStartAtom, int nStartAtomNeighbor,
161
+ int nStartAtomNeighborEndpoint, int nStartAtomNeighborNeighborEndpoint,
162
+ AT_RANK *nDfsPathPos, DFS_PATH *DfsPath, int nMaxLenDfsPath,
163
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
164
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
165
+ int *pnNumEndPoint, int *pnNumBondPos,
166
+ struct BalancedNetworkStructure *pBNS,
167
+ struct BalancedNetworkData *pBD, int num_atoms )
168
+ {
169
+ int nRet;
170
+
171
+ *pnNumEndPoint = 0;
172
+ *pnNumBondPos = 0;
173
+
174
+ if ( nMaxLenDfsPath <= 5 ) {
175
+ return -1; /* path is too short */
176
+ }
177
+
178
+ nRet = DFS_FindTautInARing( atom, nStartAtom, nStartAtomNeighbor,
179
+ nStartAtomNeighborEndpoint, nStartAtomNeighborNeighborEndpoint, 5,
180
+ nDfsPathPos, DfsPath,
181
+ Check7MembTautRing, bIsCenterPointStrict,
182
+ EndPoint, nMaxNumEndPoint,
183
+ BondPos, nMaxNumBondPos,
184
+ pnNumEndPoint, pnNumBondPos,
185
+ pBNS, pBD, num_atoms
186
+ );
187
+
188
+
189
+ return nRet;
190
+ }
191
+
192
+ /********************************************************************************/
193
+ int nGet12TautIn5MembAltRing( inp_ATOM *atom, int nStartAtom, int nStartAtomNeighbor,
194
+ AT_RANK *nDfsPathPos, DFS_PATH *DfsPath, int nMaxLenDfsPath,
195
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
196
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
197
+ int *pnNumEndPoint, int *pnNumBondPos,
198
+ struct BalancedNetworkStructure *pBNS,
199
+ struct BalancedNetworkData *pBD, int num_atoms )
200
+ {
201
+ int nRet;
202
+
203
+ *pnNumEndPoint = 0;
204
+ *pnNumBondPos = 0;
205
+
206
+ if ( nMaxLenDfsPath <= 5 ) {
207
+ return -1; /* path is too short */
208
+ }
209
+
210
+ nRet = DFS_FindTautInARing( atom, nStartAtom, nStartAtomNeighbor, -1, -1, 5,
211
+ nDfsPathPos, DfsPath,
212
+ Check5MembTautRing, bIsCenterPointStrict,
213
+ EndPoint, nMaxNumEndPoint,
214
+ BondPos, nMaxNumBondPos,
215
+ pnNumEndPoint, pnNumBondPos,
216
+ pBNS, pBD, num_atoms
217
+ );
218
+ return nRet;
219
+ }
220
+
221
+ /********************************************************************************/
222
+ int nGet15TautIn6MembAltRing( inp_ATOM *atom, int nStartAtom, AT_RANK *nDfsPathPos,
223
+ DFS_PATH *DfsPath, int nMaxLenDfsPath,
224
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
225
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
226
+ int *pnNumEndPoint, int *pnNumBondPos,
227
+ struct BalancedNetworkStructure *pBNS,
228
+ struct BalancedNetworkData *pBD, int num_atoms )
229
+ {
230
+ int nRet;
231
+
232
+ *pnNumEndPoint = 0;
233
+ *pnNumBondPos = 0;
234
+
235
+ if ( nMaxLenDfsPath <= 7 ) {
236
+ return -1; /* path is too short */
237
+ }
238
+
239
+ nRet = DFS_FindTautInARing( atom, nStartAtom, -1, -1, -1, 6,
240
+ nDfsPathPos, DfsPath,
241
+ Check6MembTautRing, bIsCenterPointStrict,
242
+ EndPoint, nMaxNumEndPoint,
243
+ BondPos, nMaxNumBondPos,
244
+ pnNumEndPoint, pnNumBondPos,
245
+ pBNS, pBD, num_atoms
246
+ );
247
+ return nRet;
248
+ }
249
+ /********************************************************************************/
250
+ /* DFS version */
251
+ #define MAX_DFS_DEPTH 16
252
+
253
+ /********************************************************************************/
254
+ int DFS_FindTautInARing( inp_ATOM *atom, int nStartAtom, int nStartAtomNeighbor,
255
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
256
+ int nCycleLen,
257
+ AT_RANK *nDfsPathPos, DFS_PATH *DfsPath,
258
+ CHECK_DFS_RING *CheckDfsRing, CHECK_CENTERPOINT *CheckCenterPoint,
259
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
260
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
261
+ int *pnNumEndPoint, int *pnNumBondPos,
262
+ struct BalancedNetworkStructure *pBNS,
263
+ struct BalancedNetworkData *pBD, int num_atoms )
264
+ {
265
+ /* Depth First Search */
266
+ /* Ignore all atoms not belonging to the current ring system (=biconnected component) */
267
+ AT_RANK nMinLenDfsPath;
268
+ int j, cur_at, nxt_at, prv_at;
269
+ int nLenDfsPath, nNumFound, ret;
270
+ AT_RANK nRingSystem;
271
+ int nDoNotTouchAtom1 = -1, nDoNotTouchAtom2 = -1;
272
+
273
+ nLenDfsPath=0;
274
+ nNumFound=0;
275
+
276
+ nCycleLen --;
277
+
278
+ DfsPath[nLenDfsPath].at_no = cur_at = nStartAtom;
279
+ DfsPath[nLenDfsPath].bond_type = 0;
280
+ DfsPath[nLenDfsPath].bond_pos = -1;
281
+ nDfsPathPos[cur_at] = nLenDfsPath+1; /* mark */
282
+ nRingSystem = atom[nStartAtom].nRingSystem;
283
+ nMinLenDfsPath = 0;
284
+ if ( nStartAtomNeighbor2 >= 0 ) {
285
+ nDoNotTouchAtom1 = (int)atom[cur_at].neighbor[nStartAtomNeighbor2];
286
+ }
287
+
288
+
289
+ /* add the first neighbor to the 2nd tree position if required */
290
+ if ( nStartAtomNeighbor >= 0 ) {
291
+ j = nStartAtomNeighbor;
292
+ prv_at = cur_at;
293
+ cur_at = atom[prv_at].neighbor[j];
294
+ DfsPath[nLenDfsPath].bond_type = (atom[prv_at].bond_type[j] & ~BOND_MARK_ALL);
295
+ DfsPath[nLenDfsPath].bond_pos = j;
296
+
297
+ nLenDfsPath ++;
298
+
299
+ DfsPath[nLenDfsPath].at_no = cur_at;
300
+ DfsPath[nLenDfsPath].bond_type = 0;
301
+ DfsPath[nLenDfsPath].bond_pos = -1;
302
+ nDfsPathPos[cur_at] = nLenDfsPath+1;
303
+ nMinLenDfsPath ++;
304
+ if ( nStartAtomNeighborNeighbor >= 0 ) {
305
+ nDoNotTouchAtom2 = (int)atom[cur_at].neighbor[nStartAtomNeighborNeighbor];
306
+ }
307
+ }
308
+
309
+ /* MAIN DFS CYCLE: may find one and the same t-group 2 times; saves only one instance */
310
+ /* traverse *all* paths starting at atom[nStartAtom]; max. path length = (nCycleLen+1) */
311
+ while ( nLenDfsPath >= nMinLenDfsPath ) {
312
+ j = ++DfsPath[nLenDfsPath].bond_pos;
313
+ if ( j < atom[cur_at=(int)DfsPath[nLenDfsPath].at_no].valence ) {
314
+ DfsPath[nLenDfsPath].bond_type = (atom[cur_at].bond_type[j] & ~BOND_MARK_ALL);
315
+ nxt_at = (int)atom[cur_at].neighbor[j];
316
+ if ( nxt_at == nDoNotTouchAtom1 ||
317
+ nxt_at == nDoNotTouchAtom2 ) {
318
+ ; /* ignore */
319
+ } else
320
+ if ( nDfsPathPos[nxt_at] ) {
321
+ /* found a ring closure or a step backwards */
322
+ if ( 1 == nDfsPathPos[nxt_at] && nLenDfsPath == nCycleLen ) {
323
+ /* we have found the cycle; check it */
324
+ ret = (*CheckDfsRing)( atom, DfsPath, nLenDfsPath, nStartAtomNeighbor,
325
+ nStartAtomNeighbor2, nStartAtomNeighborNeighbor,
326
+ EndPoint, nMaxNumEndPoint, BondPos, nMaxNumBondPos,
327
+ pnNumEndPoint, pnNumBondPos,
328
+ pBNS, pBD, num_atoms
329
+ );
330
+ if ( ret < 0 ) {
331
+ nNumFound = ret;
332
+ goto clear_path;
333
+ }
334
+ nNumFound += ret;
335
+
336
+ }
337
+ } else
338
+ if ( !(*CheckCenterPoint)( atom, nxt_at ) ) {
339
+ ; /* cannot advance to a non-centerpoint; ignore */
340
+ } else
341
+ if ( nLenDfsPath < nCycleLen ) {
342
+ /* advance */
343
+ nLenDfsPath ++;
344
+ cur_at = nxt_at;
345
+ DfsPath[nLenDfsPath].at_no = cur_at;
346
+ DfsPath[nLenDfsPath].bond_type = 0;
347
+ DfsPath[nLenDfsPath].bond_pos = -1;
348
+ nDfsPathPos[cur_at] = nLenDfsPath+1; /* mark */
349
+ }
350
+ } else {
351
+ /* retract */
352
+ nDfsPathPos[(int)DfsPath[nLenDfsPath].at_no] = 0;
353
+ nLenDfsPath --;
354
+ }
355
+ }
356
+ clear_path:
357
+ while ( 0 <= nLenDfsPath ) {
358
+ nDfsPathPos[(int)DfsPath[nLenDfsPath].at_no] = 0;
359
+ nLenDfsPath --;
360
+ }
361
+ return nNumFound;
362
+ }
363
+
364
+ /*******************************************
365
+ * check if bonds are alternating */
366
+ int are_alt_bonds( U_CHAR *bonds, int len )
367
+ {
368
+ U_CHAR next_bond;
369
+ int i, bAnyBond, bTautBondPresent=BOND_ALTERN;
370
+ if ( len < 2 || bonds[0] == BOND_TRIPLE || bonds[0] == BOND_ALT_13 ) {
371
+ return 0;
372
+ }
373
+ next_bond = bonds[0]==BOND_SINGLE? BOND_DOUBLE : bonds[0]==BOND_DOUBLE? BOND_SINGLE : 0;
374
+ if ( bonds[0] == BOND_TAUTOM ) {
375
+ bTautBondPresent= BOND_TAUTOM;
376
+ next_bond = 0;
377
+ } else {
378
+ next_bond = bonds[0]==BOND_SINGLE? BOND_DOUBLE : bonds[0]==BOND_DOUBLE? BOND_SINGLE : 0;
379
+ }
380
+
381
+ for ( i = 1; i < len; i ++ ) {
382
+ if ( bonds[i] == BOND_TAUTOM ) {
383
+ bTautBondPresent = BOND_TAUTOM;
384
+ bAnyBond = 1;
385
+ } else {
386
+ bAnyBond = (bonds[i] == BOND_ALTERN || bonds[i] == BOND_ALT12NS);
387
+ }
388
+ if ( next_bond ) {
389
+ if ( bonds[i] == next_bond || bAnyBond ) {
390
+ next_bond = (next_bond == BOND_SINGLE)? BOND_DOUBLE : BOND_SINGLE;
391
+ continue;
392
+ }
393
+ return 0;
394
+ } else
395
+ if ( bonds[i] == BOND_SINGLE ) {
396
+ next_bond = BOND_DOUBLE;
397
+ continue;
398
+ } else
399
+ if ( bonds[i] == BOND_DOUBLE ) {
400
+ next_bond = BOND_SINGLE;
401
+ continue;
402
+ } else
403
+ if ( !bAnyBond ) {
404
+ return 0;
405
+ }
406
+ }
407
+ return !next_bond? bTautBondPresent :
408
+ (next_bond == BOND_SINGLE)? BOND_DOUBLE : BOND_SINGLE; /* bond to the end atom */
409
+ }
410
+
411
+ /********************************************************************************/
412
+ int AddBondsPos( inp_ATOM *atom, T_BONDPOS *BondPosTmp, int nNumBondPosTmp, T_BONDPOS *BondPos,
413
+ int nMaxNumBondPos, int nNumBondPos )
414
+ {
415
+ int i, j, k, cur_at, nxt_at;
416
+ /* add opposite direction bonds to BondPosTmp */
417
+ for ( j = 0; j < nNumBondPosTmp; j += 2 ) {
418
+ cur_at = BondPosTmp[j].nAtomNumber;
419
+ nxt_at = atom[cur_at].neighbor[(int)BondPosTmp[j].neighbor_index];
420
+ for ( k = 0; k < atom[nxt_at].valence; k ++ ) {
421
+ if ( cur_at == atom[nxt_at].neighbor[k] ) {
422
+ BondPosTmp[j+1].nAtomNumber = nxt_at;
423
+ BondPosTmp[j+1].neighbor_index = k;
424
+ break;
425
+ }
426
+ }
427
+ }
428
+ /* add new tautomeric bonds */
429
+ for ( j = 0; j < nNumBondPosTmp; j += 2 ) {
430
+ for ( i = 0; i < nNumBondPos; i ++ ) {
431
+ if ( BondPos[i].nAtomNumber == BondPosTmp[j].nAtomNumber &&
432
+ BondPos[i].neighbor_index == BondPosTmp[j].neighbor_index ||
433
+ BondPos[i].nAtomNumber == BondPosTmp[j+1].nAtomNumber &&
434
+ BondPos[i].neighbor_index == BondPosTmp[j+1].neighbor_index ) {
435
+ break; /* bond has already been added */
436
+ }
437
+ }
438
+ if ( i == nNumBondPos ) {
439
+ if ( i > nMaxNumBondPos ) {
440
+ return -1; /* overflow */
441
+ }
442
+ BondPos[nNumBondPos ++] = BondPosTmp[j];
443
+ }
444
+ }
445
+ return nNumBondPos;
446
+ }
447
+ /********************************************************************************/
448
+ int AddEndPoints( T_ENDPOINT *EndPointTmp, int nNumNewEndPoint, T_ENDPOINT *EndPoint,
449
+ int nMaxNumEndPoint, int nNumEndPoint)
450
+ {
451
+ int i, j;
452
+ /* add new endpoints */
453
+ for ( j = 0; j < nNumNewEndPoint; j ++ ) {
454
+ for ( i = 0; i < nNumEndPoint; i ++ ) {
455
+ if ( EndPoint[i].nAtomNumber == EndPointTmp[j].nAtomNumber ) {
456
+ break;
457
+ }
458
+ }
459
+ if ( i == nNumEndPoint ) {
460
+ if ( i > nMaxNumEndPoint ) {
461
+ return -1; /* overflow */
462
+ }
463
+ EndPoint[nNumEndPoint ++] = EndPointTmp[j];
464
+ }
465
+ }
466
+ return nNumEndPoint;
467
+ }
468
+ /********************************************************************************/
469
+ /*
470
+
471
+ 1,4 tautomerism in 7-member ring
472
+
473
+ /C==D //C-D A=DfsPath[0].at_no
474
+ O=B \ HO-B \\ B=DfsPath[1].at_no
475
+ | E <-> | E nStartAtomNeighbor2: from A to HO
476
+ HO-A // O=A / nStartAtomNeighborNeighbor: from B to O
477
+ \\G-F \\G-F
478
+
479
+
480
+ 1,4 tautomerism in 5-member ring
481
+
482
+
483
+ O=B--C O-B==C
484
+ | \\ | \
485
+ | D <-> | D
486
+ | / | //
487
+ HO-A==E HO=A--E
488
+
489
+ */
490
+ /********************************************************************************/
491
+ int Check7MembTautRing( inp_ATOM *atom, DFS_PATH *DfsPath, int nLenDfsPath, int nStartAtomNeighbor,
492
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
493
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
494
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
495
+ int *pnNumEndPoint, int *pnNumBondPos,
496
+ struct BalancedNetworkStructure *pBNS,
497
+ struct BalancedNetworkData *pBD, int num_atoms )
498
+ {
499
+ #define PATH_LEN 8
500
+
501
+ int i, j, k, /*m,*/ nNumEndPoint, nNumEndPointTmp, nNumBondPos, nNumBondPosTmp;
502
+ int endpoint, /*nMobile, nMobile1, nMobile2,*/ o1_at, o2_at;
503
+ int ret;
504
+ U_CHAR path_bonds[PATH_LEN+1], bond_type;
505
+ T_ENDPOINT EndPointTmp[2];
506
+ T_BONDPOS BondPosTmp[2*PATH_LEN];
507
+ ENDPOINT_INFO eif1, eif2;
508
+ int nErr=0;
509
+
510
+
511
+ if ( nLenDfsPath + 2 > PATH_LEN ) {
512
+ return -1; /* too long path */
513
+ }
514
+ if ( nLenDfsPath != 6 && nLenDfsPath != 4 ) {
515
+ return -1; /* wrong call */
516
+ }
517
+
518
+
519
+ nNumBondPos = *pnNumBondPos;
520
+ nNumEndPoint = *pnNumEndPoint;
521
+ nNumBondPosTmp = 0;
522
+ nNumEndPointTmp = 0;
523
+ ret = 0;
524
+
525
+ o1_at = atom[(int)DfsPath[1].at_no].neighbor[nStartAtomNeighborNeighbor];
526
+ o2_at = atom[(int)DfsPath[0].at_no].neighbor[nStartAtomNeighbor2];
527
+ /*
528
+ nMobile1 = (atom[o1_at].charge == -1) + atom[o1_at].num_H;
529
+ nMobile2 = (atom[o2_at].charge == -1) + atom[o2_at].num_H;
530
+ */
531
+ if ( !nGetEndpointInfo( atom, o1_at, &eif1 ) ||
532
+ !nGetEndpointInfo( atom, o2_at, &eif2 ) ) {
533
+ return 0;
534
+ }
535
+
536
+ /* save endpoints */
537
+ for ( j = 0; j < 2; j ++ ) {
538
+ endpoint = j? o2_at : o1_at;
539
+ if ( !atom[endpoint].endpoint ) {
540
+ AddAtom2num( EndPointTmp[nNumEndPointTmp].num, atom, endpoint, 2 ); /* fill out */
541
+ AddAtom2DA( EndPointTmp[nNumEndPointTmp].num_DA, atom, endpoint, 2 );
542
+ /*
543
+ nMobile = j? nMobile2 : nMobile1;
544
+ } else {
545
+ nMobile = 0;
546
+ }
547
+ if ( nMobile ) {
548
+ EndPointTmp[nNumEndPointTmp].num[1] = (atom[endpoint].charge == -1);
549
+ EndPointTmp[nNumEndPointTmp].num[0] = nMobile;
550
+ for ( m = 0; m < T_NUM_ISOTOPIC; m ++ ) {
551
+ EndPointTmp[nNumEndPointTmp].num[T_NUM_NO_ISOTOPIC+m] = atom[endpoint].num_iso_H[NUM_H_ISOTOPES-m-1];
552
+ }
553
+ */
554
+ } else {
555
+ memset( EndPointTmp + nNumEndPointTmp, 0, sizeof(EndPointTmp[0]) );
556
+ }
557
+ EndPointTmp[nNumEndPointTmp].nAtomNumber = endpoint;
558
+ EndPointTmp[nNumEndPointTmp].nGroupNumber = atom[endpoint].endpoint;
559
+ EndPointTmp[nNumEndPointTmp].nEquNumber = 0;
560
+ nNumEndPointTmp ++;
561
+ }
562
+
563
+
564
+ /* extract bonds */
565
+ k = (int)DfsPath[1].at_no;
566
+ bond_type = (atom[k].bond_type[nStartAtomNeighborNeighbor] & ~BOND_MARK_ALL);
567
+ path_bonds[0] = bond_type;
568
+ if ( REPLACE_THE_BOND( bond_type ) ) {
569
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = k;
570
+ BondPosTmp[nNumBondPosTmp].neighbor_index = nStartAtomNeighborNeighbor;
571
+ nNumBondPosTmp += 2;
572
+ }
573
+ for ( i = 1; i <= nLenDfsPath; i ++ ) {
574
+ bond_type = DfsPath[i].bond_type;
575
+ path_bonds[i] = bond_type;
576
+ if ( REPLACE_THE_BOND( bond_type ) ) {
577
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = DfsPath[i].at_no;
578
+ BondPosTmp[nNumBondPosTmp].neighbor_index = DfsPath[i].bond_pos;
579
+ nNumBondPosTmp += 2;
580
+ }
581
+ }
582
+ bond_type = (atom[(int)DfsPath[0].at_no].bond_type[nStartAtomNeighbor2] & ~BOND_MARK_ALL);
583
+ path_bonds[i++] = bond_type;
584
+ if ( REPLACE_THE_BOND( bond_type ) ) {
585
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = DfsPath[0].at_no;
586
+ BondPosTmp[nNumBondPosTmp].neighbor_index = nStartAtomNeighbor2;
587
+ nNumBondPosTmp += 2;
588
+ }
589
+
590
+ if ( !are_alt_bonds( path_bonds, i ) ) {
591
+ return 0;
592
+ }
593
+
594
+ /* path_bonds is from at_n1 to at_n2 */
595
+ if ( !(j=are_alt_bonds( path_bonds, i )) ) {
596
+ return 0;
597
+ }
598
+ /* j is a bond type of the last bond to o2_at, the first bond from o1_at is 2-j if j=1 or 2 */
599
+
600
+ /* single bond at o2_at: it should have a mobile atom, o1_at should not */
601
+ if ( j == BOND_SINGLE && (!atom[o2_at].endpoint && !eif2.cDonor || !atom[o1_at].endpoint && !eif1.cAcceptor) ||
602
+ /* double bond at o2_at: it should not have a mobile atom, o1_at should */
603
+ j == BOND_DOUBLE && (!atom[o2_at].endpoint && !eif2.cAcceptor || !atom[o1_at].endpoint && !eif1.cDonor) ) {
604
+ return 0; /* bond pattern does not fit */
605
+ }
606
+
607
+
608
+ nNumBondPos = AddBondsPos( atom, BondPosTmp, nNumBondPosTmp, BondPos, nMaxNumBondPos, nNumBondPos );
609
+ nNumEndPoint = AddEndPoints( EndPointTmp, nNumEndPointTmp, EndPoint, nMaxNumEndPoint, nNumEndPoint);
610
+
611
+ if ( nNumBondPos >= 0 && nNumEndPoint >= 0 ) {
612
+ if (ret = (nNumBondPos > *pnNumBondPos) || (nNumEndPoint > *pnNumEndPoint)) {
613
+ *pnNumBondPos = nNumBondPos ;
614
+ *pnNumEndPoint = nNumEndPoint ;
615
+ }
616
+ }
617
+
618
+ if ( ret ) {
619
+ /* finally check whether the bonds allow moving the hydrogens */
620
+ if ( (atom[o1_at].endpoint != atom[o2_at].endpoint || !atom[o1_at].endpoint) ) {
621
+ nErr = bExistsAnyAltPath( pBNS, pBD, atom, num_atoms, o1_at, o2_at, ALT_PATH_MODE_TAUTOM );
622
+ if ( nErr <= 0 )
623
+ return nErr;
624
+ }
625
+ }
626
+
627
+ return ret;
628
+
629
+
630
+ #undef PATH_LEN
631
+ }
632
+
633
+ /********************************************************************************/
634
+ /*
635
+ 1,5 Tautomerism in 6-member alt ring:
636
+
637
+ /=\ /==\ N = DfsPath[0].at_no
638
+ HN C=O <-> N C-OH C = DfsPath[3].at_no
639
+ \=/ \\-//
640
+
641
+ */
642
+ /********************************************************************************/
643
+ /* check if a tautomeric 6-member ring has been found */
644
+ int Check6MembTautRing( inp_ATOM *atom, DFS_PATH *DfsPath, int nLenDfsPath, int nStartAtomNeighbor,
645
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
646
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
647
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
648
+ int *pnNumEndPoint, int *pnNumBondPos,
649
+ struct BalancedNetworkStructure *pBNS,
650
+ struct BalancedNetworkData *pBD, int num_atoms )
651
+ {
652
+ #define PATH_LEN 4
653
+ int i, j, k, /*m,*/ nNumBondPos, nNumEndPoint;
654
+ int nNumEndPointTmp, nNumBondPosTmp, o_at, ret;
655
+ /* int num_taut_endpoints, num_H; */
656
+ int middle_pos;
657
+ int nMobile, endpoint, endpoint_valence, chem_bonds_valence;
658
+ int nMobile1, endpoint_valence1; /* o_at */
659
+ int nMobile2, endpoint_valence2; /* n_at */
660
+ int nxt_at;
661
+ int n_at;
662
+ U_CHAR path_bonds[2][PATH_LEN+1], bond_type;
663
+ T_ENDPOINT EndPointTmp[2];
664
+ T_BONDPOS BondPosTmp[4*PATH_LEN];
665
+ ENDPOINT_INFO eif1, eif2;
666
+
667
+ if ( nStartAtomNeighbor >= 0 || nStartAtomNeighbor2 >= 0 || nStartAtomNeighborNeighbor >= 0 )
668
+ return -1; /* wrong call */
669
+
670
+ if ( nLenDfsPath != 5 )
671
+ return -1; /* wrong call */
672
+
673
+ nNumBondPos = *pnNumBondPos;
674
+ nNumEndPoint = *pnNumEndPoint;
675
+ nNumBondPosTmp = 0;
676
+ nNumEndPointTmp = 0;
677
+ ret = 0;
678
+
679
+ n_at = (int)DfsPath[0].at_no; /* -N= or -NH- atom */
680
+ nxt_at = DfsPath[middle_pos = (nLenDfsPath+1)/2].at_no; /* must have tautomeric neighbor -OH or =O or -NH2 or =NH */
681
+
682
+ if ( atom[nxt_at].valence != 3
683
+ #if( TAUT_RINGS_ATTACH_CHAIN == 1 )
684
+ || !atom[nxt_at].bCutVertex
685
+ #endif
686
+ ) {
687
+ return 0;
688
+ }
689
+
690
+ for ( i = 0; i < atom[nxt_at].valence; i ++ ) {
691
+ o_at = atom[nxt_at].neighbor[i];
692
+ if ( o_at != DfsPath[middle_pos-1].at_no && o_at != DfsPath[middle_pos+1].at_no ) {
693
+ break; /* >=O or />-OH has been found */
694
+ }
695
+ }
696
+ if ( i == atom[nxt_at].valence ) {
697
+ return 0; /* no neighboring atom >=O or />-OH */
698
+ }
699
+ bond_type = (atom[nxt_at].bond_type[i] & ~BOND_MARK_ALL);
700
+ if ( bond_type != BOND_SINGLE &&
701
+ bond_type != BOND_DOUBLE &&
702
+ bond_type != BOND_TAUTOM &&
703
+ bond_type != BOND_ALT12NS &&
704
+ bond_type != BOND_ALTERN ) {
705
+ return 0;
706
+ }
707
+
708
+ /* check whether the two atoms already belong to one tautomeric group */
709
+ #if( TAUT_IGNORE_EQL_ENDPOINTS == 1 )
710
+ if ( atom[n_at].endpoint && atom[n_at].endpoint == atom[o_at].endpoint ) {
711
+ return 0;
712
+ }
713
+ #endif
714
+ /* check =O valence; must be 2 for O, S, Se or 3 for N */
715
+ if ( !(endpoint_valence1=nGetEndpointInfo( atom, o_at, &eif1 )) )
716
+ {
717
+ return 0; /* n_at has been checked in MarkTautomerGroups(...) */
718
+ }
719
+ /*
720
+ if ( 2 != endpoint_valence1 )
721
+ return 0; // accept only O, S, Se
722
+ */
723
+ /* check hydrogens/endpoints */
724
+ nMobile1 = atom[o_at].num_H + (atom[o_at].charge==-1);
725
+ if ( bond_type == BOND_SINGLE && !eif1.cDonor && !atom[o_at].endpoint )
726
+ return 0;
727
+ /* not needed since nGetEndpointInfo returned non-zero
728
+ if ( nMobile1 + atom[o_at].chem_bonds_valence != endpoint_valence1 )
729
+ return 0;
730
+ */
731
+
732
+ if ( !(endpoint_valence2=nGetEndpointInfo( atom, n_at, &eif2 ) ) ) {
733
+ return 0; /* should not happen here */
734
+ }
735
+ nMobile2 = atom[n_at].num_H + (atom[n_at].charge==-1);
736
+
737
+ nMobile = 0;
738
+
739
+ /* can mobile group move from o_at to n_at? */
740
+ nMobile += (atom[o_at].endpoint || eif1.cDonor) && /* from o_at */
741
+ bond_type != BOND_DOUBLE &&
742
+ ( atom[n_at].endpoint || /* to n_at */
743
+ eif2.cNeutralBondsValence > atom[n_at].valence );
744
+ /* can mobile group move from n_at to o_at? */
745
+ nMobile += (atom[n_at].endpoint || eif2.cDonor) && /* from n_at */
746
+ (atom[o_at].endpoint || /* to o_at */
747
+ eif1.cNeutralBondsValence > atom[o_at].valence ) &&
748
+ bond_type != BOND_SINGLE;
749
+
750
+
751
+ if ( !nMobile )
752
+ return 0;
753
+ /*
754
+ num_H = atom[n_at].num_H + atom[o_at].num_H;
755
+ num_taut_endpoints = (0!=atom[n_at].endpoint) + (0!=atom[o_at].endpoint); // if O, N already are endpoints
756
+ if ( num_H != 1 && num_taut_endpoints != 2 && !(num_H==2 && num_taut_endpoints >= 1) ) {
757
+ return 0;
758
+ }
759
+ */
760
+ /* extract -OH bond */
761
+ nNumBondPosTmp = 0;
762
+
763
+ path_bonds[0][0] = path_bonds[1][0] = bond_type;
764
+ if ( REPLACE_THE_BOND( bond_type ) ) {
765
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = nxt_at; /* accumulate bonds to be */
766
+ BondPosTmp[nNumBondPosTmp].neighbor_index = i; /* marked as tautomeric */
767
+ nNumBondPosTmp += 2; /* leave room for the same bond in the opposite direction */
768
+ }
769
+
770
+ /* extract other bonds */
771
+ /* path_bonds[] contents:
772
+
773
+
774
+ O OH OH
775
+ || | |
776
+ / \ // \ / \\
777
+ || || <--> | || <--> || |
778
+ \ / \\ / \ //
779
+ NH N N
780
+
781
+ path[0]: O=NH-=- OH-N... OH.N...
782
+ path[1] O=NH-=- OH-N... OH.N...
783
+ bonds are all bonds all bonds
784
+ single and are either are either
785
+ double alt or taut alt or taut
786
+ */
787
+ for ( j = 0; j < middle_pos; j ++ ) {
788
+ for ( i = 0; i < 2; i ++ ) {
789
+ /* k = i? j : middle_pos-1-j; */
790
+ k = i? middle_pos+j : middle_pos-1-j;
791
+ /* i=0: from O neighbor i=0: down to N, i=1: up to N */
792
+ bond_type = DfsPath[k].bond_type;
793
+
794
+ path_bonds[i][j+1] = bond_type;
795
+ if ( REPLACE_THE_BOND( bond_type ) ) {
796
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = DfsPath[k].at_no; /* accumulate bonds to be */
797
+ BondPosTmp[nNumBondPosTmp].neighbor_index = DfsPath[k].bond_pos; /* marked as tautomeric */
798
+ nNumBondPosTmp += 2; /* leave room for the same bond in the opposite direction */
799
+ }
800
+ }
801
+ }
802
+ if ( !are_alt_bonds( path_bonds[0], middle_pos+1 ) || !are_alt_bonds( path_bonds[1], middle_pos+1 ) ) {
803
+ return 0;
804
+ }
805
+
806
+ /* finally check whether the bonds allow moving the hydrogens */
807
+ if ( (atom[o_at].endpoint != atom[n_at].endpoint || !atom[o_at].endpoint) ) {
808
+ int nErr;
809
+ nErr = bExistsAnyAltPath( pBNS, pBD, atom, num_atoms, n_at, o_at, ALT_PATH_MODE_TAUTOM );
810
+ if ( nErr <= 0 )
811
+ return nErr;
812
+ }
813
+ /* save endpoints */
814
+ for ( j = 0; j < 2; j ++ ) {
815
+ endpoint = j? n_at : /* =N- 2 */
816
+ o_at; /* -OH 1 */
817
+ if ( !atom[endpoint].endpoint ) { /* not a known endpoint */
818
+ endpoint_valence = j? endpoint_valence2 : endpoint_valence1;
819
+ chem_bonds_valence = j? eif2.cNeutralBondsValence : eif1.cNeutralBondsValence;
820
+ /* endpoint_valence = get_endpoint_valence( atom[endpoint].el_number ); */
821
+ nMobile = j? nMobile2 : nMobile1;
822
+ /* nMobile = (atom[endpoint].charge == -1) + atom[endpoint].num_H; */
823
+ /* if ( nMobile + atom[endpoint].chem_bonds_valence != endpoint_valence ) -- fixed 02-06-2003*/
824
+ if ( nMobile + chem_bonds_valence != endpoint_valence )
825
+ return 0; /* abnormal endpoint valence; ignore. */
826
+ AddAtom2num( EndPointTmp[nNumEndPointTmp].num, atom, endpoint, 2 ); /* fill out */
827
+ AddAtom2DA( EndPointTmp[nNumEndPointTmp].num_DA, atom, endpoint, 2 );
828
+ /*
829
+ EndPointTmp[nNumEndPointTmp].num[1] = (atom[endpoint].charge == -1);
830
+ EndPointTmp[nNumEndPointTmp].num[0] = nMobile;
831
+ for ( m = 0; m < T_NUM_ISOTOPIC; m ++ ) {
832
+ EndPointTmp[nNumEndPointTmp].num[T_NUM_NO_ISOTOPIC+m] = atom[endpoint].num_iso_H[NUM_H_ISOTOPES-m-1];
833
+ }
834
+ */
835
+ } else { /* already an endpoint */ /* **now it is wrong:** no mobile atom/charge at this endpoint */
836
+ memset( EndPointTmp + nNumEndPointTmp, 0, sizeof(EndPointTmp[0]) );
837
+ }
838
+ EndPointTmp[nNumEndPointTmp].nAtomNumber = endpoint;
839
+ EndPointTmp[nNumEndPointTmp].nGroupNumber = atom[endpoint].endpoint;
840
+ EndPointTmp[nNumEndPointTmp].nEquNumber = 0;
841
+
842
+ nNumEndPointTmp ++;
843
+ }
844
+ /* add collected tautomeric bonds and endpoints to the input/output data */
845
+ nNumBondPos = AddBondsPos( atom, BondPosTmp, nNumBondPosTmp, BondPos, nMaxNumBondPos, nNumBondPos );
846
+ nNumEndPoint = AddEndPoints( EndPointTmp, nNumEndPointTmp, EndPoint, nMaxNumEndPoint, nNumEndPoint);
847
+
848
+ if ( nNumBondPos >= 0 && nNumEndPoint >= 0 ) {
849
+ if (ret = (nNumBondPos > *pnNumBondPos) || (nNumEndPoint > *pnNumEndPoint)) {
850
+ *pnNumBondPos = nNumBondPos ;
851
+ *pnNumEndPoint = nNumEndPoint ;
852
+ }
853
+ }
854
+ return ret;
855
+
856
+ #undef PATH_LEN
857
+ }
858
+
859
+
860
+ /********************************************************************************/
861
+ /*
862
+
863
+ 1,4 tautomerism in 5-member ring
864
+
865
+
866
+ O=N2-C O-N2=C N1 = DfsPath[0].at_no
867
+ | \\ | \ N2 = DfsPath[1].at_no
868
+ | D <-> | D
869
+ | / | //
870
+ HO-N1=E HO=N1-E
871
+
872
+ */
873
+ /********************************************************************************/
874
+ /* check if a tautomeric 5-member ring (pyrazole derivatives) has been found */
875
+ int Check5MembTautRing( inp_ATOM *atom, DFS_PATH *DfsPath, int nLenDfsPath, int nStartAtomNeighbor,
876
+ int nStartAtomNeighbor2, int nStartAtomNeighborNeighbor,
877
+ T_ENDPOINT *EndPoint, int nMaxNumEndPoint,
878
+ T_BONDPOS *BondPos, int nMaxNumBondPos,
879
+ int *pnNumEndPoint, int *pnNumBondPos,
880
+ struct BalancedNetworkStructure *pBNS,
881
+ struct BalancedNetworkData *pBD, int num_atoms )
882
+ {
883
+ #define PATH_LEN 4
884
+ int i, j, /*m,*/ nMobile, nMobile1, nMobile2;
885
+ int num_taut_endpoints, nNumBondPos, nNumBondPosTmp, nNumEndPoint, nNumEndPointTmp, ret;
886
+ int endpoint;
887
+ int n1_at = (int)DfsPath[0].at_no;
888
+ int n2_at = (int)DfsPath[1].at_no;
889
+ U_CHAR path_bonds[PATH_LEN+1], bond_type;
890
+ T_ENDPOINT EndPointTmp[2];
891
+ T_BONDPOS BondPosTmp[2*PATH_LEN];
892
+ ENDPOINT_INFO eif1, eif2;
893
+
894
+ /* the two root atoms (atom[n1_at] and atom[n2_at]) cannot belong */
895
+ /* to one and the same tautomeric group: it has been verified in MarkTautomerGroups() */
896
+
897
+ /* check hydrogens/endpoints */
898
+ if ( nLenDfsPath != 4 ) {
899
+ return 0; /* program error */
900
+ }
901
+ if ( nStartAtomNeighbor2 >= 0 || nStartAtomNeighborNeighbor >= 0 )
902
+ return 0; /* program error: wrong call */
903
+
904
+ nNumBondPos = *pnNumBondPos;
905
+ nNumEndPoint = *pnNumEndPoint;
906
+ nNumEndPointTmp = 0;
907
+ nNumBondPosTmp = 0;
908
+ ret = 0;
909
+
910
+ if ( !nGetEndpointInfo( atom, n1_at, &eif1 ) ||
911
+ !nGetEndpointInfo( atom, n2_at, &eif2 ) ) {
912
+ return 0;
913
+ }
914
+
915
+ nMobile1 = atom[n1_at].num_H + (atom[n1_at].charge==-1);
916
+ nMobile2 = atom[n2_at].num_H + (atom[n2_at].charge==-1);
917
+ nMobile = nMobile1 + nMobile2;
918
+ num_taut_endpoints = (0!=atom[n1_at].endpoint) + (0!=atom[n2_at].endpoint); /* if both N atoms already are endpoints */
919
+ /*
920
+ if ( !(nMobile == 1 || num_taut_endpoints == 2) && !(nMobile>1 && num_taut_endpoints >= 1) ) {
921
+ return 0;
922
+ }
923
+ */
924
+ if ( num_taut_endpoints == 0 && nMobile != 1 ) {
925
+ return 0;
926
+ }
927
+
928
+ /* finally check whether the bonds allow moving the hydrogens */
929
+ if ( (atom[n1_at].endpoint != atom[n2_at].endpoint || !atom[n1_at].endpoint) ) {
930
+ int nErr;
931
+ nErr = bExistsAnyAltPath( pBNS, pBD, atom, num_atoms, n1_at, n2_at, ALT_PATH_MODE_TAUTOM );
932
+ if ( nErr <= 0 )
933
+ return nErr;
934
+ }
935
+
936
+ /* save endpoints */
937
+ for ( j = 0; j < 2; j ++ ) {
938
+ endpoint = j? n1_at : n2_at;
939
+ if ( !atom[endpoint].endpoint ) { /* not a known endpoint */
940
+ /*
941
+ nMobile = (atom[endpoint].charge == -1) + atom[endpoint].num_H;
942
+ } else {
943
+ nMobile = 0;
944
+ }
945
+ if ( nMobile ) {
946
+ */
947
+ AddAtom2num( EndPointTmp[nNumEndPointTmp].num, atom, endpoint, 2 ); /* fill out */
948
+ AddAtom2DA( EndPointTmp[nNumEndPointTmp].num_DA, atom, endpoint, 2 );
949
+ /*
950
+ EndPointTmp[nNumEndPointTmp].num[1] = (atom[endpoint].charge == -1);
951
+ EndPointTmp[nNumEndPointTmp].num[0] = nMobile;
952
+ for ( m = 0; m < T_NUM_ISOTOPIC; m ++ ) {
953
+ EndPointTmp[nNumEndPointTmp].num[T_NUM_NO_ISOTOPIC+m] = atom[endpoint].num_iso_H[NUM_H_ISOTOPES-m-1];
954
+ }
955
+ */
956
+ } else {
957
+ memset( EndPointTmp + nNumEndPointTmp, 0, sizeof(EndPointTmp[0]) );
958
+ }
959
+ EndPointTmp[nNumEndPointTmp].nAtomNumber = endpoint;
960
+ EndPointTmp[nNumEndPointTmp].nGroupNumber = atom[endpoint].endpoint;
961
+ EndPointTmp[nNumEndPointTmp].nEquNumber = 0;
962
+
963
+ nNumEndPointTmp ++;
964
+ }
965
+
966
+ /* extract bonds */
967
+ nNumBondPosTmp = 0;
968
+ for ( i = 1; i <= nLenDfsPath; i ++ ) {
969
+ bond_type = DfsPath[i].bond_type;
970
+ path_bonds[i-1] = bond_type;
971
+ if ( REPLACE_THE_BOND( bond_type ) ) {
972
+ BondPosTmp[nNumBondPosTmp].nAtomNumber = DfsPath[i].at_no;
973
+ BondPosTmp[nNumBondPosTmp].neighbor_index = DfsPath[i].bond_pos;
974
+ nNumBondPosTmp += 2;
975
+ }
976
+ }
977
+ /* path_bonds is from at_n2 to at_n1 */
978
+ if ( !(i=are_alt_bonds( path_bonds, nLenDfsPath )) ) {
979
+ return 0;
980
+ }
981
+ /* i is a bond type of the last bond to at_n1, the first bond from at_n2 is 2-i if i=1 or 2 */
982
+
983
+ /* single bond at n1_at: it should have a mobile atom, n2_at should not */
984
+ if ( i == BOND_SINGLE && (!atom[n1_at].endpoint && !eif1.cDonor || !atom[n2_at].endpoint && !eif2.cAcceptor ) ||
985
+ /* double bond at n1_at: it should not have a mobile atom, n2_at should */
986
+ i == BOND_DOUBLE && (!atom[n1_at].endpoint && !eif1.cAcceptor || !atom[n2_at].endpoint && !eif2.cDonor) ) {
987
+ return 0; /* bond pattern does not fit */
988
+ }
989
+
990
+ nNumBondPos = AddBondsPos( atom, BondPosTmp, nNumBondPosTmp, BondPos, nMaxNumBondPos, nNumBondPos );
991
+ nNumEndPoint = AddEndPoints( EndPointTmp, nNumEndPointTmp, EndPoint, nMaxNumEndPoint, nNumEndPoint);
992
+
993
+ if ( nNumBondPos >= 0 && nNumEndPoint >= 0 ) {
994
+ if (ret = (nNumBondPos > *pnNumBondPos) || (nNumEndPoint > *pnNumEndPoint)) {
995
+ *pnNumBondPos = nNumBondPos ;
996
+ *pnNumEndPoint = nNumEndPoint ;
997
+ }
998
+ }
999
+ return ret;
1000
+
1001
+ #undef PATH_LEN
1002
+ }
1003
+ #endif /* } */