rino 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/ichiqueu.c
ADDED
@@ -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 /* } */
|