rino 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 /* } */
|