rino 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/ext/extconf.rb +1 -24
- data/ext/libinchi.so +0 -0
- data/ext/src/aux2atom.h +120 -39
- data/ext/src/comdef.h +3 -3
- data/ext/src/dispstru.c +2547 -0
- data/ext/src/dispstru.h +73 -0
- data/ext/src/extr_ct.h +5 -2
- data/ext/src/ichi.h +27 -11
- data/ext/src/ichi_bns.c +1800 -254
- data/ext/src/ichi_bns.h +205 -4
- data/ext/src/ichican2.c +197 -86
- data/ext/src/ichicano.c +8 -13
- data/ext/src/ichicano.h +2 -2
- data/ext/src/ichicans.c +11 -6
- data/ext/src/ichicant.h +2 -2
- data/ext/src/ichicomn.h +2 -2
- data/ext/src/ichicomp.h +19 -4
- data/ext/src/ichidrp.h +9 -5
- data/ext/src/ichierr.h +5 -3
- data/ext/src/ichiisot.c +2 -2
- data/ext/src/ichimain.c +461 -0
- data/ext/src/ichimain.h +23 -15
- data/ext/src/ichimak2.c +6 -6
- data/ext/src/ichimake.c +843 -42
- data/ext/src/ichimake.h +4 -2
- data/ext/src/ichimap1.c +5 -5
- data/ext/src/ichimap2.c +2 -2
- data/ext/src/ichimap4.c +34 -21
- data/ext/src/ichinorm.c +11 -5
- data/ext/src/ichinorm.h +3 -2
- data/ext/src/ichiparm.c +2 -2
- data/ext/src/ichiparm.h +232 -30
- data/ext/src/ichiprt1.c +35 -11
- data/ext/src/ichiprt2.c +78 -7
- data/ext/src/ichiprt3.c +300 -120
- data/ext/src/ichiqueu.c +17 -2
- data/ext/src/ichiread.c +6932 -0
- data/ext/src/ichiring.c +3 -2
- data/ext/src/ichiring.h +2 -2
- data/ext/src/ichirvr1.c +4891 -0
- data/ext/src/ichirvr2.c +6344 -0
- data/ext/src/ichirvr3.c +5499 -0
- data/ext/src/ichirvr4.c +3177 -0
- data/ext/src/ichirvr5.c +1166 -0
- data/ext/src/ichirvr6.c +1287 -0
- data/ext/src/ichirvr7.c +2319 -0
- data/ext/src/ichirvrs.h +882 -0
- data/ext/src/ichisize.h +2 -2
- data/ext/src/ichisort.c +5 -5
- data/ext/src/ichister.c +281 -86
- data/ext/src/ichister.h +9 -3
- data/ext/src/ichitaut.c +208 -9
- data/ext/src/ichitaut.h +13 -11
- data/ext/src/ichitime.h +16 -2
- data/ext/src/inchicmp.h +107 -0
- data/ext/src/inpdef.h +6 -3
- data/ext/src/libinchi_wrap.c +912 -0
- data/ext/src/lreadmol.h +34 -31
- data/ext/src/mode.h +244 -7
- data/ext/src/mol2atom.c +1060 -0
- data/ext/src/mol2atom.h +31 -0
- data/ext/src/readinch.c +239 -0
- data/ext/src/readmol.c +28 -0
- data/ext/src/{e_readmol.h → readmol.h} +7 -9
- data/ext/src/runichi.c +251 -177
- data/ext/src/strutil.c +444 -238
- data/ext/src/strutil.h +150 -11
- data/ext/src/util.c +176 -118
- data/ext/src/util.h +15 -3
- data/lib/rino.rb +71 -3
- data/test/test.rb +33 -4
- metadata +22 -34
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/e_0dstereo.c +0 -3014
- data/ext/src/e_0dstereo.h +0 -31
- data/ext/src/e_comdef.h +0 -57
- data/ext/src/e_ctl_data.h +0 -147
- data/ext/src/e_ichi_io.c +0 -498
- data/ext/src/e_ichi_io.h +0 -40
- data/ext/src/e_ichi_parms.c +0 -37
- data/ext/src/e_ichi_parms.h +0 -41
- data/ext/src/e_ichicomp.h +0 -50
- data/ext/src/e_ichierr.h +0 -40
- data/ext/src/e_ichimain.c +0 -593
- data/ext/src/e_ichisize.h +0 -43
- data/ext/src/e_inchi_atom.c +0 -75
- data/ext/src/e_inchi_atom.h +0 -33
- data/ext/src/e_inpdef.h +0 -41
- data/ext/src/e_mode.h +0 -706
- data/ext/src/e_mol2atom.c +0 -649
- data/ext/src/e_readinch.c +0 -58
- data/ext/src/e_readmol.c +0 -54
- data/ext/src/e_readstru.c +0 -251
- data/ext/src/e_readstru.h +0 -33
- data/ext/src/e_util.c +0 -284
- data/ext/src/e_util.h +0 -61
- data/ext/src/ichilnct.c +0 -286
- data/ext/src/inchi_api.h +0 -670
- data/ext/src/inchi_dll.c +0 -1480
- data/ext/src/inchi_dll.h +0 -34
- data/ext/src/inchi_dll_main.c +0 -23
- data/ext/src/inchi_dll_main.h +0 -31
- data/ext/src/ruby_inchi_main.c +0 -558
data/ext/src/ichirvr5.c
ADDED
@@ -0,0 +1,1166 @@
|
|
1
|
+
/*
|
2
|
+
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
|
+
* International Chemical Identifier (InChI)
|
4
|
+
* Version 1
|
5
|
+
* Software version 1.01
|
6
|
+
* July 21, 2006
|
7
|
+
* Developed at NIST
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <string.h>
|
13
|
+
|
14
|
+
/*#define CHECK_WIN32_VC_HEAP*/
|
15
|
+
#include "mode.h"
|
16
|
+
|
17
|
+
#if( READ_INCHI_STRING == 1 )
|
18
|
+
|
19
|
+
#include "ichi.h"
|
20
|
+
#include "ichitime.h"
|
21
|
+
|
22
|
+
#include "inpdef.h"
|
23
|
+
#include "ichimain.h"
|
24
|
+
#include "ichierr.h"
|
25
|
+
#include "comdef.h"
|
26
|
+
#include "ichiring.h"
|
27
|
+
#include "extr_ct.h"
|
28
|
+
#include "ichitaut.h"
|
29
|
+
#include "ichinorm.h"
|
30
|
+
#include "util.h"
|
31
|
+
|
32
|
+
#include "ichicomp.h"
|
33
|
+
#include "ichister.h"
|
34
|
+
|
35
|
+
#include "ichi_bns.h"
|
36
|
+
|
37
|
+
#include "strutil.h"
|
38
|
+
|
39
|
+
#include "ichirvrs.h"
|
40
|
+
|
41
|
+
|
42
|
+
#define INC_ADD_EDGE 64
|
43
|
+
/***********************************************************************************************/
|
44
|
+
int GetPlusMinusVertex( BN_STRUCT *pBNS, ALL_TC_GROUPS *pTCGroups, int bCheckForbiddenPlus, int bCheckForbiddenMinus )
|
45
|
+
{
|
46
|
+
int k, ePlusSuper, eMinusSuper, vPlusSuper, vMinusSuper, vPlusMinus1 = NO_VERTEX, vPlusMinus2 = NO_VERTEX;
|
47
|
+
BNS_EDGE *pEdge;
|
48
|
+
if ( (k = pTCGroups->nGroup[TCG_Plus]) >= 0 &&
|
49
|
+
(ePlusSuper = pTCGroups->pTCG[k].nForwardEdge) > 0 &&
|
50
|
+
(vPlusSuper = pTCGroups->pTCG[k].nVertexNumber) >= pBNS->num_atoms &&
|
51
|
+
!((pEdge=pBNS->edge + ePlusSuper)->forbidden && bCheckForbiddenPlus) ) {
|
52
|
+
|
53
|
+
vPlusMinus1 = pEdge->neighbor12 ^ vPlusSuper;
|
54
|
+
}
|
55
|
+
if ( (k = pTCGroups->nGroup[TCG_Minus]) >= 0 &&
|
56
|
+
(eMinusSuper = pTCGroups->pTCG[k].nForwardEdge) > 0 &&
|
57
|
+
(vMinusSuper = pTCGroups->pTCG[k].nVertexNumber) >= pBNS->num_atoms &&
|
58
|
+
!((pEdge=pBNS->edge + eMinusSuper)->forbidden && bCheckForbiddenMinus) ) {
|
59
|
+
|
60
|
+
vPlusMinus2 = pEdge->neighbor12 ^ eMinusSuper;
|
61
|
+
}
|
62
|
+
if ( bCheckForbiddenPlus && NO_VERTEX == vPlusMinus1 ||
|
63
|
+
bCheckForbiddenMinus && NO_VERTEX == vPlusMinus2 ) {
|
64
|
+
return NO_VERTEX;
|
65
|
+
}
|
66
|
+
return (NO_VERTEX != vPlusMinus1)? vPlusMinus1 : vPlusMinus2;
|
67
|
+
}
|
68
|
+
/***********************************************************************************************/
|
69
|
+
int bIsUnsatCarbonInASmallRing( inp_ATOM *at2, VAL_AT *pVA, int iat, BFS_Q *pbfsq, int min_ring_size )
|
70
|
+
{
|
71
|
+
int j, nCurRingSize, nMinRingSize;
|
72
|
+
if ( min_ring_size < 5 ) {
|
73
|
+
/* =C= in a small ring */
|
74
|
+
if ( at2[iat].valence == 2 &&
|
75
|
+
pVA[iat].cMinRingSize <= 5 &&
|
76
|
+
at2[iat].chem_bonds_valence == 4 ) {
|
77
|
+
return 1;
|
78
|
+
}
|
79
|
+
} else {
|
80
|
+
if ( at2[iat].valence == 2 &&
|
81
|
+
pVA[iat].cMinRingSize &&
|
82
|
+
pVA[iat].cMinRingSize <= min_ring_size &&
|
83
|
+
at2[iat].chem_bonds_valence == 3 ) {
|
84
|
+
return 1;
|
85
|
+
}
|
86
|
+
nCurRingSize = nMinRingSize = min_ring_size+1;
|
87
|
+
if ( (at2[iat].valence == 2 || at2[iat].valence == 3) &&
|
88
|
+
at2[iat].chem_bonds_valence == at2[iat].valence+1 ) {
|
89
|
+
for ( j = 0; j < at2[iat].valence; j ++ ) {
|
90
|
+
nCurRingSize = is_bond_in_Nmax_memb_ring( at2, iat, j, pbfsq->q,
|
91
|
+
pbfsq->nAtomLevel,
|
92
|
+
pbfsq->cSource, (AT_RANK)nMinRingSize /* max ring size */ );
|
93
|
+
if ( 0 < nCurRingSize && nCurRingSize < nMinRingSize ) {
|
94
|
+
nMinRingSize = nCurRingSize;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
return (0 <= nCurRingSize)? (nMinRingSize <= min_ring_size) : nCurRingSize;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return 0;
|
101
|
+
}
|
102
|
+
/***********************************************************************************************/
|
103
|
+
int FixMobileHRestoredStructure(ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
|
104
|
+
StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
|
105
|
+
ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
|
106
|
+
inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp, int bHasSomeFixedH,
|
107
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
|
108
|
+
{
|
109
|
+
/*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
|
110
|
+
/* at2 should be the most recently restored atom, Fixed-H */
|
111
|
+
int i, j, k, iat, delta, tot_succes, cur_success, ret = 0;
|
112
|
+
CMP2MHINCHI c2i;
|
113
|
+
CMP2MHINCHI *pc2i = &c2i;
|
114
|
+
|
115
|
+
EDGE_LIST AllChargeEdges, CurrEdges, CurrEdges2, CurrEdges3, TautEdges, NFlowerEdges, OtherNFlowerEdges, FixedLargeRingStereoEdges;
|
116
|
+
EDGE_LIST *pEdgeList = NULL;
|
117
|
+
|
118
|
+
EdgeIndex e;
|
119
|
+
BNS_EDGE *pe;
|
120
|
+
Vertex v1, v2, vPlusMinus;
|
121
|
+
BNS_VERTEX *pv1, *pv2;
|
122
|
+
|
123
|
+
Vertex vPathStart, vPathEnd;
|
124
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
125
|
+
|
126
|
+
int nNumRunBNS = 0, forbidden_edge_mask_inv = ~forbidden_edge_mask;
|
127
|
+
|
128
|
+
INCHI_HEAPCHK
|
129
|
+
|
130
|
+
AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
|
131
|
+
AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
|
132
|
+
AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
|
133
|
+
AllocEdgeList( &CurrEdges2, EDGE_LIST_CLEAR );
|
134
|
+
AllocEdgeList( &CurrEdges3, EDGE_LIST_CLEAR );
|
135
|
+
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
|
136
|
+
AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_CLEAR );
|
137
|
+
AllocEdgeList( &TautEdges, EDGE_LIST_CLEAR );
|
138
|
+
|
139
|
+
tot_succes = 0;
|
140
|
+
|
141
|
+
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
|
142
|
+
goto exit_function; /* no fixed-H found */
|
143
|
+
}
|
144
|
+
/* taut group edges */
|
145
|
+
for ( i = 0; i < pTCGroups->num_tgroups; i ++ ) {
|
146
|
+
pv1 = pBNS->vert + (v1=pTCGroups->pTCG[i].nVertexNumber); /* t-group vertex */
|
147
|
+
for ( j = 0; j < pv1->num_adj_edges; j ++ ) {
|
148
|
+
/* e, pe - tautomeric atom edge; pv2 - endpoint vertex */
|
149
|
+
/* Note: pe, pv2, v1 are not used here; they are to show how to traverse t-group */
|
150
|
+
pv2 = pBNS->vert + (pe = pBNS->edge + (e=pv1->iedge[j]))->neighbor1;
|
151
|
+
if ( ret = AddToEdgeList( &TautEdges, e, INC_ADD_EDGE ) ) {
|
152
|
+
goto exit_function;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
/* charge and flower edges */
|
157
|
+
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
|
158
|
+
if ( (e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
|
159
|
+
(ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE )) ) {
|
160
|
+
goto exit_function;
|
161
|
+
}
|
162
|
+
if ( (e=pVA[i].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
|
163
|
+
if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
|
164
|
+
goto exit_function;
|
165
|
+
}
|
166
|
+
|
167
|
+
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
|
168
|
+
if ( pVA[i].cNumValenceElectrons == 5 && !pVA[i].cMetal && /* N, P, As */
|
169
|
+
NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
|
170
|
+
|
171
|
+
if ( !pBNS->edge[j].forbidden && pBNS->edge[j].flow ) {
|
172
|
+
if ( ret = AddToEdgeList( &AllChargeEdges, j, INC_ADD_EDGE ) ) {
|
173
|
+
goto exit_function;
|
174
|
+
}
|
175
|
+
if ( ret = AddToEdgeList( &NFlowerEdges, j, INC_ADD_EDGE ) ) {
|
176
|
+
goto exit_function;
|
177
|
+
}
|
178
|
+
} else {
|
179
|
+
if ( ret = AddToEdgeList( &OtherNFlowerEdges, j, INC_ADD_EDGE ) ) {
|
180
|
+
goto exit_function;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
}
|
186
|
+
}
|
187
|
+
if ( forbidden_stereo_edge_mask ) {
|
188
|
+
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
|
189
|
+
for ( j = 0; j < at2[i].valence; j ++ ) {
|
190
|
+
if ( pBNS->edge[k = pBNS->vert[i].iedge[j]].forbidden == forbidden_stereo_edge_mask ) {
|
191
|
+
int nMinRingSize = is_bond_in_Nmax_memb_ring( at2, i, j, pStruct->pbfsq->q,
|
192
|
+
pStruct->pbfsq->nAtomLevel,
|
193
|
+
pStruct->pbfsq->cSource, 99 /* max ring size */ );
|
194
|
+
if ( 0 < nMinRingSize && (ret = AddToEdgeList( &FixedLargeRingStereoEdges, k, INC_ADD_EDGE ))) {
|
195
|
+
goto exit_function;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
INCHI_HEAPCHK
|
203
|
+
|
204
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
205
|
+
goto exit_function;
|
206
|
+
}
|
207
|
+
INCHI_HEAPCHK
|
208
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
209
|
+
goto exit_function;
|
210
|
+
}
|
211
|
+
|
212
|
+
INCHI_HEAPCHK
|
213
|
+
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) &&
|
218
|
+
pc2i->nNumTgDBNMinusRevrs + pc2i->nNumTgNHMinusRevrs == 0 && pc2i->nNumTgOMinusInChI &&
|
219
|
+
!(pTCGroups->pTCG[0].tg_RestoreFlags & TGRF_MINUS_FIRST) ) {
|
220
|
+
/*----------------------------------------------------*/
|
221
|
+
/* case 01: restored has -O(-) and does not have N(-) */
|
222
|
+
/* endpoints defined by the original InChI */
|
223
|
+
/* restored has single taut. group or more */
|
224
|
+
/* tautomeric endpoints. */
|
225
|
+
/* Solution: move (-) from endp. -O(-) to endpoints N */
|
226
|
+
/*----------------------------------------------------*/
|
227
|
+
pTCGroups->pTCG[0].tg_RestoreFlags |= TGRF_MINUS_FIRST;
|
228
|
+
/* recalculate InChI from the structure */
|
229
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
230
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
231
|
+
goto exit_function;
|
232
|
+
}
|
233
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
234
|
+
goto exit_function;
|
235
|
+
}
|
236
|
+
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
|
237
|
+
goto exit_function; /* no fixed-H found */
|
238
|
+
}
|
239
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
240
|
+
goto exit_function;
|
241
|
+
}
|
242
|
+
if ( !pc2i->bHasDifference ) {
|
243
|
+
goto exit_function; /* nothing to do */
|
244
|
+
}
|
245
|
+
}
|
246
|
+
if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) &&
|
247
|
+
pc2i->nNumTgDBNMinusRevrs + pc2i->nNumTgNHMinusRevrs == 0 && pc2i->nNumTgOMinusInChI == 0 ) {
|
248
|
+
/*-------------------------------------------------------*/
|
249
|
+
/* case 02: restored has no -O(-) and does not have N(-) */
|
250
|
+
/* restored has single taut. group or more */
|
251
|
+
/* tautomeric endpoints. */
|
252
|
+
/* Solution: >N-AB=N- => >N(+)=AB-NH- (add H(+)) */
|
253
|
+
/* Solution: >N-AB=NH => >N(+)=AB-NH2 (add H(+)) */
|
254
|
+
/* SB_N_III DB_N_III */
|
255
|
+
/*-------------------------------------------------------*/
|
256
|
+
int iat_SB_N_III[MAX_DIFF_MOBH], iat_DB_N_III[MAX_DIFF_MOBH];
|
257
|
+
int num_SB_N_III = 0, num_DB_N_III = 0, k1, k2;
|
258
|
+
CurrEdges.num_edges = 0;
|
259
|
+
cur_success = 0;
|
260
|
+
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
|
261
|
+
iat = i;
|
262
|
+
if ( pVA[iat].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
|
263
|
+
!at2[iat].endpoint && !at2[iat].charge && !at2[iat].radical ) {
|
264
|
+
if ( num_DB_N_III < MAX_DIFF_MOBH && !at2[iat].num_H &&
|
265
|
+
at2[iat].valence == 2 &&
|
266
|
+
at2[iat].chem_bonds_valence == 3 &&
|
267
|
+
!at2[iat].sb_parity[0] && /* do not eliminate stereobonds */
|
268
|
+
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
|
269
|
+
pBNS->edge[e].cap && !pBNS->edge[e].flow ) {
|
270
|
+
/* -N= */
|
271
|
+
iat_DB_N_III[ num_DB_N_III ++ ] = iat;
|
272
|
+
} else
|
273
|
+
if ( num_DB_N_III < MAX_DIFF_MOBH && 1 == at2[iat].num_H &&
|
274
|
+
at2[iat].valence == 1 &&
|
275
|
+
at2[iat].chem_bonds_valence == 2 &&
|
276
|
+
!at2[iat].sb_parity[0] && /* do not eliminate stereobonds */
|
277
|
+
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
|
278
|
+
pBNS->edge[e].cap && !pBNS->edge[e].flow ) {
|
279
|
+
/* -N= */
|
280
|
+
iat_DB_N_III[ num_DB_N_III ++ ] = iat;
|
281
|
+
} else
|
282
|
+
if ( num_SB_N_III < MAX_DIFF_MOBH && !at2[iat].num_H &&
|
283
|
+
at2[iat].valence == 3 &&
|
284
|
+
at2[iat].chem_bonds_valence == 3 &&
|
285
|
+
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
|
286
|
+
pBNS->edge[e].cap && pBNS->edge[e].flow) {
|
287
|
+
/* -N< */
|
288
|
+
iat_SB_N_III[ num_SB_N_III ++ ] = iat;
|
289
|
+
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
|
290
|
+
goto exit_function;
|
291
|
+
}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
if ( num_DB_N_III && num_SB_N_III ) {
|
296
|
+
EdgeIndex ieMinus;
|
297
|
+
BNS_EDGE *peMinus;
|
298
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
299
|
+
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
|
300
|
+
for ( i = 0; i < num_DB_N_III && !cur_success; i ++ ) {
|
301
|
+
iat = iat_DB_N_III[ i ];
|
302
|
+
e = pBNS->edge[k1=pBNS->vert[iat].iedge[0]].flow? k1 :
|
303
|
+
pBNS->edge[k2=pBNS->vert[iat].iedge[1]].flow? k2 : NO_VERTEX;
|
304
|
+
if ( e == NO_VERTEX ) {
|
305
|
+
continue; /* should not happen */
|
306
|
+
}
|
307
|
+
ieMinus = pVA[iat].nCMinusGroupEdge-1;
|
308
|
+
peMinus = pBNS->edge + ieMinus;
|
309
|
+
pe = pBNS->edge + e;
|
310
|
+
if ( !pe->flow )
|
311
|
+
continue;
|
312
|
+
pv1 = pBNS->vert + (v1 = pe->neighbor1);
|
313
|
+
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
|
314
|
+
|
315
|
+
pe->forbidden |= forbidden_edge_mask; /* fix double bond */
|
316
|
+
peMinus->forbidden &= forbidden_edge_mask_inv; /* allow negative charge */
|
317
|
+
delta = 1;
|
318
|
+
pe->flow -= delta; /* remove (-) from AB-O(-) */
|
319
|
+
pv1->st_edge.flow -= delta;
|
320
|
+
pv2->st_edge.flow -= delta;
|
321
|
+
pBNS->tot_st_flow -= 2*delta;
|
322
|
+
|
323
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
324
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
325
|
+
|
326
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
327
|
+
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
|
328
|
+
/* Added (-)charge -N= and (+) to -N< => nDeltaCharge == 2 */
|
329
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
330
|
+
if ( ret > 0 ) {
|
331
|
+
nNumRunBNS ++;
|
332
|
+
cur_success ++; /* 01 */
|
333
|
+
|
334
|
+
/* eliminate (-) charge and add H */
|
335
|
+
pv1 = pBNS->vert + (v1 = peMinus->neighbor1); /* atom */
|
336
|
+
pv2 = pBNS->vert + (v2 = peMinus->neighbor12 ^ v1);/* (=) vertex */
|
337
|
+
/* effectively eliminate (-) edge by setting its cap=flow= 0 */
|
338
|
+
peMinus->cap --;
|
339
|
+
peMinus->flow --;
|
340
|
+
pv1->st_edge.cap --;
|
341
|
+
pv1->st_edge.flow --;
|
342
|
+
pv2->st_edge.cap --;
|
343
|
+
pv2->st_edge.flow --;
|
344
|
+
pBNS->tot_st_flow -= 2;
|
345
|
+
pBNS->tot_st_cap -= 2;
|
346
|
+
/* add H */
|
347
|
+
pStruct->at[iat].num_H ++;
|
348
|
+
/* register total charge increase */
|
349
|
+
pTCGroups->total_charge ++;
|
350
|
+
pStruct->nNumRemovedProtonsByRevrs -= 1;
|
351
|
+
}
|
352
|
+
} else {
|
353
|
+
pe->forbidden &= forbidden_edge_mask_inv;
|
354
|
+
peMinus->forbidden |= forbidden_edge_mask;
|
355
|
+
pe->flow += delta;
|
356
|
+
pv1->st_edge.flow += delta;
|
357
|
+
pv2->st_edge.flow += delta;
|
358
|
+
pBNS->tot_st_flow += 2*delta;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
362
|
+
CurrEdges.num_edges = 0; /* clear current edge list */
|
363
|
+
|
364
|
+
if ( cur_success ) {
|
365
|
+
tot_succes += cur_success;
|
366
|
+
/* recalculate InChI from the structure */
|
367
|
+
/* recalculate InChI from the structure */
|
368
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
369
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
370
|
+
goto exit_function;
|
371
|
+
}
|
372
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
373
|
+
goto exit_function;
|
374
|
+
}
|
375
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
376
|
+
goto exit_function;
|
377
|
+
}
|
378
|
+
if ( !pc2i->bHasDifference ) {
|
379
|
+
goto exit_function; /* nothing to do */
|
380
|
+
}
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) && /* ADP */
|
385
|
+
pc2i->nNumTgMInChI == 0 && pc2i->nNumTgNInChI && pc2i->nNumTgOInChI ) {
|
386
|
+
/*-------------------------------------------------------*/
|
387
|
+
/* case 03: restored has N and O endpoints, no (-) endp */
|
388
|
+
/* case 04: original has single taut. group or more */
|
389
|
+
/* tautomeric endpoints. */
|
390
|
+
/* Solution: 1. Move taut attachment from O to N */
|
391
|
+
/* Solution: 2. Replace the attachment with (-) */
|
392
|
+
/* SB_N_III DB_N_III */
|
393
|
+
/*-------------------------------------------------------*/
|
394
|
+
/*
|
395
|
+
int iat_SB_N_III[MAX_DIFF_MOBH], iat_DB_N_III[MAX_DIFF_MOBH];
|
396
|
+
int num_SB_N_III = 0, num_DB_N_III = 0, k1, k2,
|
397
|
+
*/
|
398
|
+
int itg, j1, j2, bAction = 0;
|
399
|
+
BNS_VERTEX *pTg, *pvEndp, *pvEndp2, *pvCent;
|
400
|
+
Vertex vEndp, vEndp2, vCent;
|
401
|
+
BNS_EDGE *peTg, *peTg2, *peCent1, *peCent2;
|
402
|
+
EdgeIndex eTg, eTg2;
|
403
|
+
|
404
|
+
CurrEdges.num_edges = 0;
|
405
|
+
CurrEdges2.num_edges = 0;
|
406
|
+
cur_success = 0;
|
407
|
+
|
408
|
+
/* 1st attempt: -NH-=O => -N(-)-=O or -N=-OH => -N(-)-=O */
|
409
|
+
for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
|
410
|
+
pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
|
411
|
+
for ( i = 0; i < pTg->num_adj_edges && !cur_success; i ++ ) {
|
412
|
+
pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
|
413
|
+
eTg2 = -1;
|
414
|
+
if ( pVA[vEndp].cNumValenceElectrons == 6 && peTg->cap ) {
|
415
|
+
/* endpoint -OH or =O found; search for a possible centerpoint */
|
416
|
+
for ( j1 = 0; j1 < at2[vEndp].valence && eTg2 < 0; j1 ++ ) {
|
417
|
+
peCent1 = pBNS->edge + pvEndp->iedge[j1]; /* edge from O to a centerpoint */
|
418
|
+
pvCent = pBNS->vert + (vCent = peCent1->neighbor12 ^ vEndp); /* centerpoint */
|
419
|
+
if ( at2[vCent].endpoint || !peCent1->cap ||
|
420
|
+
peCent1->flow + (peTg->cap == peTg->flow) != 1 ) {
|
421
|
+
continue;
|
422
|
+
}
|
423
|
+
/* search for another endpoint, N, around vCent */
|
424
|
+
for ( j2 = 0; j2 < at2[vCent].valence; j2 ++ ) {
|
425
|
+
peCent2 = pBNS->edge + pvCent->iedge[j2];
|
426
|
+
pvEndp2 = pBNS->vert + (vEndp2 = peCent2->neighbor12 ^ vCent);
|
427
|
+
if ( !peCent2->cap || peCent2->flow+peCent1->flow != 1 ||
|
428
|
+
at2[vEndp2].endpoint != itg+1 ||
|
429
|
+
pVA[vEndp2].cNumValenceElectrons != 5 ||
|
430
|
+
0 > (j=pVA[vEndp2].nTautGroupEdge-1) ||
|
431
|
+
(peTg2 = pBNS->edge + j)->forbidden ||
|
432
|
+
peCent2->flow + (peTg2->cap == peTg2->flow) != 1 ) {
|
433
|
+
continue;
|
434
|
+
}
|
435
|
+
eTg2 = j;
|
436
|
+
break; /* found OH-C=N- or O=C-NH- */
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
440
|
+
if ( eTg2 >= 0 ) {
|
441
|
+
/*--------------------------------------------
|
442
|
+
tg tg
|
443
|
+
eTg //\ eTg2 eTg / \\eTg2
|
444
|
+
// \ / \\
|
445
|
+
vEndp HO--C==N vEndp2 --> vEndp O==C--NH vEndp2
|
446
|
+
^ ^ ^ ^ ^ ^
|
447
|
+
eCent1 | eCent2 eCent1 | eCent2
|
448
|
+
vCent vCent
|
449
|
+
|
450
|
+
additional action: -OH-C=N- => O=C-NH-
|
451
|
+
-------------------------------------------*/
|
452
|
+
if ( 0 == peTg->cap - peTg->flow && 1 == peTg2->cap - peTg2->flow &&
|
453
|
+
0 == peCent1->flow && 1 == peCent2->flow ) {
|
454
|
+
peTg->flow --; /* 03 prepare */
|
455
|
+
peTg2->flow ++;
|
456
|
+
peCent2->flow --;
|
457
|
+
peCent1->flow ++;
|
458
|
+
bAction |= 1; /* switched H position */
|
459
|
+
}
|
460
|
+
if ( 1 == peTg->cap - peTg->flow && 0 == peTg2->cap - peTg2->flow &&
|
461
|
+
1 == peCent1->flow && 0 == peCent2->flow ) {
|
462
|
+
/* replace -NH- with -N(-)- */
|
463
|
+
pTCGroups->pTCG[itg].tg_num_H --;
|
464
|
+
pTCGroups->pTCG[itg].tg_num_Minus ++;
|
465
|
+
pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
|
466
|
+
pTCGroups->pTCG[itg].tg_set_Minus = vEndp2+1;
|
467
|
+
pStruct->ti.t_group[itg].num[1] ++; /* increment number of (-), keep number of taut attachments */
|
468
|
+
pTCGroups->total_charge --;
|
469
|
+
pTCGroups->tgroup_charge --;
|
470
|
+
pStruct->nNumRemovedProtonsByRevrs += 1;
|
471
|
+
bAction |= 2; /* single NH (at2[vEndp2]) replaced with N(-) */
|
472
|
+
cur_success ++; /* 03/04 */
|
473
|
+
}
|
474
|
+
}
|
475
|
+
}
|
476
|
+
}
|
477
|
+
|
478
|
+
if ( 0 == pc2i->nNumTgNHInChI+ pc2i->nNumTgNH2InChI && pc2i->nNumTgOHInChI && !cur_success ) {
|
479
|
+
/* transfer an attachement to N */
|
480
|
+
for ( itg = 0; itg < pTCGroups->num_tgroups; itg ++ ) {
|
481
|
+
pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
|
482
|
+
for ( i = 0; i < pTg->num_adj_edges; i ++ ) {
|
483
|
+
pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
|
484
|
+
if ( pVA[vEndp].cNumValenceElectrons == 6 &&
|
485
|
+
at2[vEndp].valence == at2[vEndp].chem_bonds_valence &&
|
486
|
+
peTg->flow && peTg->flow == peTg->cap ) {
|
487
|
+
/* endpoint -OH found; save the tautomeric group edge */
|
488
|
+
if ( ret = AddToEdgeList( &CurrEdges, eTg, INC_ADD_EDGE ) ) {
|
489
|
+
goto exit_function;
|
490
|
+
}
|
491
|
+
} else
|
492
|
+
if ( pVA[vEndp].cNumValenceElectrons == 5 &&
|
493
|
+
pVA[vEndp].cPeriodicRowNumber == 1 &&
|
494
|
+
at2[vEndp].valence + 1 == at2[vEndp].chem_bonds_valence &&
|
495
|
+
peTg->cap && peTg->flow + 1 == peTg->cap ) {
|
496
|
+
/* endpoint -N= or =NH found, check for -N=-OH */
|
497
|
+
e = -1;
|
498
|
+
for ( j1 = 0; j1 < at2[vEndp].valence && e < 0; j1 ++ ) {
|
499
|
+
peCent1 = pBNS->edge + pvEndp->iedge[j1];
|
500
|
+
if ( peCent1->flow == 1 ) {
|
501
|
+
/* double bond */
|
502
|
+
pvCent = pBNS->vert + (vCent = peCent1->neighbor12 ^ vEndp);
|
503
|
+
if ( at2[vCent].endpoint )
|
504
|
+
continue;
|
505
|
+
for ( j2 = 0; j2 < at2[vCent].valence; j2 ++ ) {
|
506
|
+
peCent2 = pBNS->edge + pvCent->iedge[j2];
|
507
|
+
pvEndp2 = pBNS->vert + (vEndp2 = peCent2->neighbor12 ^ vCent);
|
508
|
+
if ( peCent2->flow || at2[vEndp2].endpoint != itg+1 ||
|
509
|
+
pVA[vEndp2].cNumValenceElectrons != 6 ||
|
510
|
+
0 >= (e=pVA[vEndp2].nTautGroupEdge-1) ||
|
511
|
+
pBNS->edge[e].forbidden || !pBNS->edge[e].flow ) {
|
512
|
+
e = -1;
|
513
|
+
continue;
|
514
|
+
}
|
515
|
+
/*********************/
|
516
|
+
/* found -N=X-OH */
|
517
|
+
/* vEndp ^ vEndp2 */
|
518
|
+
/* vCent */
|
519
|
+
/*********************/
|
520
|
+
/* save this -OH taut edge */
|
521
|
+
if ( ret = AddToEdgeList( &CurrEdges2, e, INC_ADD_EDGE ) ) {
|
522
|
+
goto exit_function;
|
523
|
+
}
|
524
|
+
break;
|
525
|
+
}
|
526
|
+
}
|
527
|
+
}
|
528
|
+
if ( e < 0 && (ret = AddToEdgeList( &CurrEdges, eTg, INC_ADD_EDGE )) ) {
|
529
|
+
goto exit_function;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
}
|
533
|
+
}
|
534
|
+
/* rearrange the flows */
|
535
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
536
|
+
SetForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
|
537
|
+
SetForbiddenEdgeMask( pBNS, &CurrEdges2, forbidden_edge_mask );
|
538
|
+
pEdgeList = CurrEdges2.num_edges? &CurrEdges2 : CurrEdges.num_edges? &CurrEdges : NULL;
|
539
|
+
|
540
|
+
for ( i = 0; pEdgeList && i < pEdgeList->num_edges && !cur_success; i ++ ) {
|
541
|
+
pe = pBNS->edge + pEdgeList->pnEdges[i]; /* pe->flow = 1 <=> -OH */
|
542
|
+
if ( !pe->flow )
|
543
|
+
continue;
|
544
|
+
pv1 = pBNS->vert + (v1 = pe->neighbor1); /* -OH atom */
|
545
|
+
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); /* t-group vertex */
|
546
|
+
/* locate the t-group */
|
547
|
+
for ( itg = 0; itg < pTCGroups->num_tgroups; itg ++ ) {
|
548
|
+
if ( v2 == pTCGroups->pTCG[itg].nVertexNumber ) {
|
549
|
+
break;
|
550
|
+
}
|
551
|
+
}
|
552
|
+
if ( itg == pTCGroups->num_tgroups ) {
|
553
|
+
/* tgroup not found -- should not happen */
|
554
|
+
continue;
|
555
|
+
}
|
556
|
+
|
557
|
+
delta = 1;
|
558
|
+
pe->flow -= delta; /* add one attachment to */
|
559
|
+
pv1->st_edge.flow -= delta;
|
560
|
+
pv2->st_edge.flow -= delta;
|
561
|
+
pBNS->tot_st_flow -= 2*delta;
|
562
|
+
|
563
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
564
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
565
|
+
|
566
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
567
|
+
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
|
568
|
+
/* Added (-)charge -N= and (+) to -N< => nDeltaCharge == 2 */
|
569
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
570
|
+
if ( ret > 0 ) {
|
571
|
+
nNumRunBNS ++;
|
572
|
+
cur_success ++; /* 03 */
|
573
|
+
/* replace -NH- with -N(-)- */
|
574
|
+
pTCGroups->pTCG[itg].tg_num_H --;
|
575
|
+
pTCGroups->pTCG[itg].tg_num_Minus ++;
|
576
|
+
pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
|
577
|
+
pStruct->ti.t_group[itg].num[1] ++;
|
578
|
+
pTCGroups->total_charge --;
|
579
|
+
pTCGroups->tgroup_charge --;
|
580
|
+
pStruct->nNumRemovedProtonsByRevrs += 1;
|
581
|
+
bAction |= 4; /* H in the 1st available NH was replaced with (-) */
|
582
|
+
}
|
583
|
+
} else {
|
584
|
+
pe->flow += delta;
|
585
|
+
pv1->st_edge.flow += delta;
|
586
|
+
pv2->st_edge.flow += delta;
|
587
|
+
pBNS->tot_st_flow += 2*delta;
|
588
|
+
}
|
589
|
+
}
|
590
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
591
|
+
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
|
592
|
+
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
|
593
|
+
} else
|
594
|
+
if ( pc2i->nNumTgNHInChI+ pc2i->nNumTgNH2InChI && pc2i->nNumTgOInChI && !cur_success ) {
|
595
|
+
/* change an attachement to N from H to (-) */
|
596
|
+
for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
|
597
|
+
pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
|
598
|
+
for ( i = 0; i < pTg->num_adj_edges && !cur_success; i ++ ) {
|
599
|
+
pvEndp2 = pBNS->vert + (vEndp2 = (peTg = pBNS->edge + pTg->iedge[i])->neighbor1);
|
600
|
+
if ( pVA[vEndp2].cNumValenceElectrons == 5 && pVA[vEndp2].cPeriodicRowNumber == 1 &&
|
601
|
+
at2[vEndp2].valence == at2[vEndp2].chem_bonds_valence &&
|
602
|
+
peTg->flow && peTg->flow == peTg->cap ) {
|
603
|
+
/* endpoint -NHn found; change its charge */
|
604
|
+
cur_success ++; /* 04 */
|
605
|
+
/* replace -NH- with -N(-)- */
|
606
|
+
pTCGroups->pTCG[itg].tg_num_H --;
|
607
|
+
pTCGroups->pTCG[itg].tg_num_Minus ++;
|
608
|
+
pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
|
609
|
+
pTCGroups->pTCG[itg].tg_set_Minus = vEndp2 + 1;
|
610
|
+
pStruct->ti.t_group[itg].num[1] ++;
|
611
|
+
pTCGroups->total_charge --;
|
612
|
+
pTCGroups->tgroup_charge --;
|
613
|
+
pStruct->nNumRemovedProtonsByRevrs += 1;
|
614
|
+
bAction |= 8; /* manually set (-) charge to NH atom, vEndp2 */
|
615
|
+
}
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
if ( cur_success ) {
|
620
|
+
tot_succes += cur_success;
|
621
|
+
/* recalculate InChI from the structure */
|
622
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
623
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
624
|
+
goto exit_function;
|
625
|
+
}
|
626
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
627
|
+
goto exit_function;
|
628
|
+
}
|
629
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
630
|
+
goto exit_function;
|
631
|
+
}
|
632
|
+
if ( pStruct->One_ti.num_t_groups == 1 && pStruct->One_ti.t_group[0].num[1] ) {
|
633
|
+
/* this method did not work: no alt path from N(-) to =O */
|
634
|
+
itg = 0;
|
635
|
+
if ( bAction & (8 | 2 ) ) {
|
636
|
+
/* roll back NH -> N(-) replacement; H move from OH to N is not undone */
|
637
|
+
pTCGroups->pTCG[itg].tg_num_H ++;
|
638
|
+
pTCGroups->pTCG[itg].tg_num_Minus --;
|
639
|
+
pTCGroups->pTCG[itg].tg_RestoreFlags &= ~TGRF_MINUS_FIRST;
|
640
|
+
pTCGroups->pTCG[itg].tg_set_Minus = 0;
|
641
|
+
pStruct->ti.t_group[itg].num[1] --;
|
642
|
+
pTCGroups->total_charge ++;
|
643
|
+
pTCGroups->tgroup_charge ++;
|
644
|
+
pStruct->nNumRemovedProtonsByRevrs -= 1;
|
645
|
+
cur_success --;
|
646
|
+
} else
|
647
|
+
if ( bAction & 4 ) {
|
648
|
+
pTCGroups->pTCG[itg].tg_num_H ++;
|
649
|
+
pTCGroups->pTCG[itg].tg_num_Minus --;
|
650
|
+
pTCGroups->pTCG[itg].tg_RestoreFlags &= ~TGRF_MINUS_FIRST;
|
651
|
+
pStruct->ti.t_group[itg].num[1] --;
|
652
|
+
pTCGroups->total_charge ++;
|
653
|
+
pTCGroups->tgroup_charge ++;
|
654
|
+
pStruct->nNumRemovedProtonsByRevrs -= 1;
|
655
|
+
cur_success --;
|
656
|
+
} else {
|
657
|
+
ret = RI_ERR_PROGR;
|
658
|
+
goto exit_function;
|
659
|
+
}
|
660
|
+
/* recalculate InChI from the structure */
|
661
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
662
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
663
|
+
goto exit_function;
|
664
|
+
}
|
665
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
666
|
+
goto exit_function;
|
667
|
+
}
|
668
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
669
|
+
goto exit_function;
|
670
|
+
}
|
671
|
+
}
|
672
|
+
if ( !pc2i->bHasDifference ) {
|
673
|
+
goto exit_function; /* nothing to do */
|
674
|
+
}
|
675
|
+
}
|
676
|
+
}
|
677
|
+
|
678
|
+
if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) && /* ADP */
|
679
|
+
pc2i->nNumTgMInChI == 0 && (pc2i->nNumTgNInChI || pc2i->nNumTgOInChI) &&
|
680
|
+
NO_VERTEX != (vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 1 )) ) {
|
681
|
+
/*---------------------------------------------------------------------------*/
|
682
|
+
/* case 05: restored has N endpoints, no (-) endpoints */
|
683
|
+
/* original has single taut. group or more */
|
684
|
+
/* tautomeric endpoints. */
|
685
|
+
/* Solution: Find -N< and allow (+) charge change */
|
686
|
+
/* Fix all charges and taut attachments exept */
|
687
|
+
/* =N- and =O (taut. endpoints) */
|
688
|
+
/* Increment st_edge.cap on (+/-) vertex => add (+) charge to -N< */
|
689
|
+
/* Increment tot. charge in other places */
|
690
|
+
/* Increment t-group st_edge.cap */
|
691
|
+
/* Run BNS */
|
692
|
+
/* */
|
693
|
+
/* (+/-)* (+/-) Result: */
|
694
|
+
/* | || */
|
695
|
+
/* | || - Added (+) to -N< */
|
696
|
+
/* (+)super (+)super - Added attachment point to O */
|
697
|
+
/* || | */
|
698
|
+
/* || => | To make this attachment H, */
|
699
|
+
/* (Y) (Y) increment */
|
700
|
+
/* | || pTCGroups->pTCG[itg].tg_num_H */
|
701
|
+
/* | || */
|
702
|
+
/* (+)hetero (+)hetero Technical details: */
|
703
|
+
/* \\ \ increase capacities of */
|
704
|
+
/* N N(+) edges to (+/-) otherwise */
|
705
|
+
/* | || flow may not be able to */
|
706
|
+
/* *(t)--O=R. (t)==O-R. increase */
|
707
|
+
/* */
|
708
|
+
/* */
|
709
|
+
/*---------------------------------------------------------------------------*/
|
710
|
+
int itg;
|
711
|
+
BNS_VERTEX *pTg, *pvEndp;
|
712
|
+
Vertex vEndp, vTg;
|
713
|
+
BNS_EDGE *peTg;
|
714
|
+
EdgeIndex eTg;
|
715
|
+
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
|
716
|
+
|
717
|
+
CurrEdges.num_edges = 0;
|
718
|
+
CurrEdges2.num_edges = 0;
|
719
|
+
cur_success = 0;
|
720
|
+
/* find -N< and non-taut =N- or =O */
|
721
|
+
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
|
722
|
+
iat = nCanon2AtnoRevrs[i];
|
723
|
+
/* -N< */
|
724
|
+
if ( !at2[iat].endpoint && !at2[iat].charge && !at2[iat].radical && !at2[iat].num_H &&
|
725
|
+
pVA[i].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
|
726
|
+
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && pBNS->edge[e].flow && !pBNS->edge[e].forbidden) {
|
727
|
+
|
728
|
+
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
|
729
|
+
goto exit_function;
|
730
|
+
}
|
731
|
+
}
|
732
|
+
}
|
733
|
+
if ( !CurrEdges.num_edges ) {
|
734
|
+
goto exit_case_05;
|
735
|
+
}
|
736
|
+
/* find taut -N= and =O */
|
737
|
+
for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
|
738
|
+
CurrEdges2.num_edges = 0;
|
739
|
+
pTg = pBNS->vert + (vTg = pTCGroups->pTCG[itg].nVertexNumber);
|
740
|
+
for ( i = 0; i < pTg->num_adj_edges; i ++ ) {
|
741
|
+
pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
|
742
|
+
if ( at2[vEndp].charge || at2[vEndp].radical || peTg->cap - peTg->flow != 1 ) {
|
743
|
+
continue;
|
744
|
+
}
|
745
|
+
/* t-group edges to -N= and =O */
|
746
|
+
if ( ret = AddToEdgeList( &CurrEdges2, eTg, INC_ADD_EDGE ) ) {
|
747
|
+
goto exit_function;
|
748
|
+
}
|
749
|
+
}
|
750
|
+
if ( !CurrEdges2.num_edges ) {
|
751
|
+
goto exit_case_05;
|
752
|
+
}
|
753
|
+
/* fix all charge edges except -N< and all taut. edges except =O and =N- */
|
754
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
755
|
+
SetForbiddenEdgeMask( pBNS, &TautEdges, forbidden_edge_mask );
|
756
|
+
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
|
757
|
+
RemoveForbiddenEdgeMask( pBNS, &CurrEdges2, forbidden_edge_mask );
|
758
|
+
delta = 1;
|
759
|
+
/* Increment st_edge.cap on (+/-) vertex */
|
760
|
+
pBNS->vert[vPlusMinus].st_edge.cap += delta;
|
761
|
+
/* Increment st_edge.cap on t-group */
|
762
|
+
pTg->st_edge.cap += delta;
|
763
|
+
/* total cap count */
|
764
|
+
pBNS->tot_st_cap += 2*delta;
|
765
|
+
|
766
|
+
v1 = vPlusMinus;
|
767
|
+
v2 = vTg;
|
768
|
+
|
769
|
+
/* increase capacities of edges to Y */
|
770
|
+
for ( i = 0; i < pBNS->vert[vPlusMinus].num_adj_edges; i ++ ) {
|
771
|
+
j = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i]].neighbor12 ^ vPlusMinus;
|
772
|
+
for ( k = 0; k < pBNS->vert[j].num_adj_edges; k ++ ) {
|
773
|
+
pBNS->edge[pBNS->vert[j].iedge[k]].cap += delta;
|
774
|
+
}
|
775
|
+
}
|
776
|
+
|
777
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
778
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
779
|
+
|
780
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
781
|
+
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
|
782
|
+
/* Added (+)charge to -N< => nDeltaCharge == 1 */
|
783
|
+
/* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
|
784
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
785
|
+
if ( ret > 0 ) {
|
786
|
+
nNumRunBNS ++;
|
787
|
+
cur_success ++; /* 01 */
|
788
|
+
/* update bookkeeping */
|
789
|
+
pTCGroups->total_charge += delta;
|
790
|
+
pTCGroups->pTCG[itg].edges_cap += delta;
|
791
|
+
pTCGroups->pTCG[itg].tg_num_H += delta;
|
792
|
+
pStruct->nNumRemovedProtonsByRevrs -= delta;
|
793
|
+
}
|
794
|
+
} else {
|
795
|
+
pBNS->vert[vPlusMinus].st_edge.cap -= delta;
|
796
|
+
pTg->st_edge.cap -= delta;
|
797
|
+
/*pTCGroups->pTCG[itg].edges_cap -= delta;*/ /* ???bug??? - commented out 2006-03-22 */
|
798
|
+
pBNS->tot_st_cap -= 2*delta;
|
799
|
+
/* decrease capacities of edges to Y */
|
800
|
+
for ( i = 0; i < pBNS->vert[vPlusMinus].num_adj_edges; i ++ ) {
|
801
|
+
j = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i]].neighbor12 ^ vPlusMinus;
|
802
|
+
for ( k = 0; k < pBNS->vert[j].num_adj_edges; k ++ ) {
|
803
|
+
pBNS->edge[pBNS->vert[j].iedge[k]].cap -= delta;
|
804
|
+
}
|
805
|
+
}
|
806
|
+
}
|
807
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
808
|
+
RemoveForbiddenEdgeMask( pBNS, &TautEdges, forbidden_edge_mask );
|
809
|
+
}
|
810
|
+
if ( cur_success ) {
|
811
|
+
tot_succes += cur_success;
|
812
|
+
/* recalculate InChI from the structure */
|
813
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
814
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
815
|
+
goto exit_function;
|
816
|
+
}
|
817
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
818
|
+
goto exit_function;
|
819
|
+
}
|
820
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
821
|
+
goto exit_function;
|
822
|
+
}
|
823
|
+
if ( !pc2i->bHasDifference ) {
|
824
|
+
goto exit_function; /* nothing to do */
|
825
|
+
}
|
826
|
+
}
|
827
|
+
|
828
|
+
exit_case_05:;
|
829
|
+
}
|
830
|
+
|
831
|
+
while ( pc2i->nNumDiffMobH && pc2i->nChargeMobHRevrs > pc2i->nChargeMobHInChI ) {
|
832
|
+
/*----------------------------------------------------*/
|
833
|
+
/* case 06: restored has extra H attached to -O(-) */
|
834
|
+
/* while the chrge should be on C, most pro- */
|
835
|
+
/* bably in a small ring.ut. group or more */
|
836
|
+
/* tautomeric endpoints. */
|
837
|
+
/* Solution: move (-) from O to C */
|
838
|
+
/*----------------------------------------------------*/
|
839
|
+
int iO, mode;
|
840
|
+
EdgeIndex e2;
|
841
|
+
BNS_EDGE *pe2;
|
842
|
+
cur_success = 0;
|
843
|
+
for ( i = 0; !cur_success && i < pc2i->len_c2at; i ++ ) {
|
844
|
+
|
845
|
+
if ( pc2i->c2at[i].nMobHRevrs == pc2i->c2at[i].nMobHInChI + 1 &&
|
846
|
+
pc2i->c2at[i].nNumHRevrs == pc2i->c2at[i].nMobHInChI &&
|
847
|
+
!pc2i->c2at[i].endptInChI && !pc2i->c2at[i].endptRevrs &&
|
848
|
+
at2[iO = pc2i->c2at[i].atomNumber].charge == -1 &&
|
849
|
+
0 <= (e=pVA[iO].nCMinusGroupEdge-1) && (pe=pBNS->edge+e)->flow ) {
|
850
|
+
|
851
|
+
/* try suitable atoms C */
|
852
|
+
/* first look for =C= in a small ring */
|
853
|
+
|
854
|
+
for( mode = 4; !cur_success && mode <= 8; mode ++ ) {
|
855
|
+
|
856
|
+
if ( mode == 8 )
|
857
|
+
mode = 99;
|
858
|
+
|
859
|
+
for ( iat = 0; !cur_success && iat < pStruct->num_atoms; iat ++ ) {
|
860
|
+
|
861
|
+
if ( !at2[iat].charge && !at2[iat].radical &&
|
862
|
+
pVA[iat].cNumValenceElectrons == 4 &&
|
863
|
+
0 <= (e2=pVA[iat].nCMinusGroupEdge-1) && !(pe2=pBNS->edge+e2)->flow &&
|
864
|
+
0 < bIsUnsatCarbonInASmallRing( at2, pVA, iat, pStruct->pbfsq, mode ) ) {
|
865
|
+
|
866
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
867
|
+
/* allow negative charge on the chosen carbon */
|
868
|
+
pe2->forbidden &= forbidden_edge_mask_inv;
|
869
|
+
|
870
|
+
delta = 1;
|
871
|
+
if ( !pe->flow )
|
872
|
+
continue;
|
873
|
+
pv1 = pBNS->vert + (v1 = pe->neighbor1);
|
874
|
+
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
|
875
|
+
pe->flow -= delta;
|
876
|
+
pv1->st_edge.flow -= delta;
|
877
|
+
pv2->st_edge.flow -= delta;
|
878
|
+
pBNS->tot_st_flow -= 2*delta;
|
879
|
+
|
880
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
881
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
882
|
+
|
883
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
884
|
+
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
|
885
|
+
/* Added (-)charge to unsaturated C => nDeltaCharge == 2 */
|
886
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
887
|
+
if ( ret > 0 ) {
|
888
|
+
nNumRunBNS ++;
|
889
|
+
cur_success ++; /* 01 */
|
890
|
+
tot_succes += cur_success;
|
891
|
+
}
|
892
|
+
} else {
|
893
|
+
pe->forbidden |= forbidden_edge_mask;
|
894
|
+
pe->flow += delta;
|
895
|
+
pv1->st_edge.flow += delta;
|
896
|
+
pv2->st_edge.flow += delta;
|
897
|
+
pBNS->tot_st_flow += 2*delta;
|
898
|
+
}
|
899
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
900
|
+
}
|
901
|
+
}
|
902
|
+
}
|
903
|
+
}
|
904
|
+
}
|
905
|
+
if ( cur_success ) {
|
906
|
+
/* recalculate InChI from the structure */
|
907
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
908
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
909
|
+
goto exit_function;
|
910
|
+
}
|
911
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
912
|
+
goto exit_function;
|
913
|
+
}
|
914
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
915
|
+
goto exit_function;
|
916
|
+
}
|
917
|
+
if ( !pc2i->bHasDifference ) {
|
918
|
+
goto exit_function; /* nothing to do */
|
919
|
+
}
|
920
|
+
} else {
|
921
|
+
break;
|
922
|
+
}
|
923
|
+
}
|
924
|
+
if ( pc2i->len_c2at && pc2i->nChargeMobHRevrs > pc2i->nChargeMobHInChI ) {
|
925
|
+
/*------------------------------------------------------------------*/
|
926
|
+
/* case 07: -NO2 are to be tautomeric but they are not AND */
|
927
|
+
/* InChI has a SINGLE tautomeric group */
|
928
|
+
/* */
|
929
|
+
/* (-)O (-)O */
|
930
|
+
/* Solution: convert \ \ */
|
931
|
+
/* N-X=...-Z(-) => N(+)=X- ...=Z */
|
932
|
+
/* // / */
|
933
|
+
/* O (-)O */
|
934
|
+
/* */
|
935
|
+
/* O O */
|
936
|
+
/* or \\ \\ */
|
937
|
+
/* N-X=...-Z(-) => N=X- ...=Z */
|
938
|
+
/* // / */
|
939
|
+
/* O (-)O */
|
940
|
+
/* */
|
941
|
+
/* */
|
942
|
+
/* (a) move (-) from other tautomeric atom to O in O=N-X */
|
943
|
+
/* or from other atom that has to be tautomeric */
|
944
|
+
/* but is not */
|
945
|
+
/* (b) create (+) [ion pair creation] on N as in */
|
946
|
+
/* */
|
947
|
+
/* OH OH */
|
948
|
+
/* / / */
|
949
|
+
/* -C=N => =C-N(+) */
|
950
|
+
/* \\ \\ */
|
951
|
+
/* O O */
|
952
|
+
/* */
|
953
|
+
/*------------------------------------------------------------------*/
|
954
|
+
int num_DB_O = 0;
|
955
|
+
short iat_DB_O[MAX_DIFF_FIXH], iat_NO2[MAX_DIFF_FIXH];
|
956
|
+
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
|
957
|
+
/*
|
958
|
+
AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
|
959
|
+
*/
|
960
|
+
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[0] &&
|
961
|
+
pStruct->pOne_norm_data[0]->at)? pStruct->pOne_norm_data[0]->at : NULL;
|
962
|
+
|
963
|
+
int iN, one_success;
|
964
|
+
BNS_EDGE *peDB_O_Minus;
|
965
|
+
int neigh, nNumO, nNumOthers;
|
966
|
+
#define CHG_SET_WRONG_TAUT_N 0
|
967
|
+
#define CHG_SET_WRONG_TAUT_O 1
|
968
|
+
#define CHG_SET_WRONG_TAUT_ALL 2
|
969
|
+
#define CHG_LAST_SET 2 /* the last index in trying */
|
970
|
+
#define CHG_SET_O_FIXED 3
|
971
|
+
#define CHG_SET_NUM 4
|
972
|
+
EDGE_LIST ChangeableEdges[CHG_SET_NUM];
|
973
|
+
memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
|
974
|
+
/* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
|
975
|
+
/*
|
976
|
+
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
|
977
|
+
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
|
978
|
+
*/
|
979
|
+
CurrEdges.num_edges = 0; /* clear current edge list */
|
980
|
+
cur_success = 0;
|
981
|
+
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
|
982
|
+
iat = nCanon2AtnoRevrs[i];
|
983
|
+
if ( /* orig. InChI info: taut in orig. InChI =O located in -NO2 that is not taut in Reconstructed InChI */
|
984
|
+
num_DB_O < MAX_DIFF_FIXH &&
|
985
|
+
pVA[iat].cNumValenceElectrons == 6 /* O, S, Se, Te */ &&
|
986
|
+
(!at2[iat].endpoint /*|| pc2i->c2at[i].nMobHInChI*/) &&
|
987
|
+
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
|
988
|
+
at2[iat].num_H == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
|
989
|
+
/* reversed structure info: */
|
990
|
+
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) /*|| pc2i->c2at[i].nMobHRevrs*/ &&
|
991
|
+
!at2[iat].charge &&
|
992
|
+
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 &&
|
993
|
+
/* find whether it belongs to NO2 */
|
994
|
+
pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
|
995
|
+
at2[iN].valence == 3 && (at2[iN].charge == 0 || at2[iN].charge == 1) &&
|
996
|
+
at2[iN].chem_bonds_valence == 5 - at2[iN].charge ) {
|
997
|
+
/* find the second O */
|
998
|
+
nNumO = nNumOthers = 0;
|
999
|
+
for ( k = 0; k < at2[iN].valence; k ++ ) {
|
1000
|
+
neigh = at2[iN].neighbor[k];
|
1001
|
+
if ( neigh == iat ) {
|
1002
|
+
continue;
|
1003
|
+
}
|
1004
|
+
if ( pVA[neigh].cNumValenceElectrons == 6 &&
|
1005
|
+
!at2[neigh].endpoint &&
|
1006
|
+
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[neigh].endpoint) &&
|
1007
|
+
at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
|
1008
|
+
at2[neigh].radical == 0 && (at2[neigh].charge == 0 || at2[neigh].charge == -1) &&
|
1009
|
+
at2[neigh].chem_bonds_valence - at2[neigh].charge == 2) {
|
1010
|
+
nNumO ++;
|
1011
|
+
} else
|
1012
|
+
if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
|
1013
|
+
at2[neigh].valence > 1 &&
|
1014
|
+
at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
|
1015
|
+
nNumOthers ++;
|
1016
|
+
}
|
1017
|
+
}
|
1018
|
+
if ( nNumO != 1 || nNumOthers != 1 ) {
|
1019
|
+
continue;
|
1020
|
+
}
|
1021
|
+
for ( k = 0; k < num_DB_O; k ++ ) {
|
1022
|
+
if ( iat_NO2[k] == iN ) {
|
1023
|
+
break;
|
1024
|
+
}
|
1025
|
+
}
|
1026
|
+
if ( k == num_DB_O ) {
|
1027
|
+
iat_NO2[num_DB_O] = iN;
|
1028
|
+
iat_DB_O[num_DB_O ++] = iat;
|
1029
|
+
}
|
1030
|
+
/* save the =O (-)-edge to avoid interference */
|
1031
|
+
if ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ) {
|
1032
|
+
goto exit_case_07;
|
1033
|
+
}
|
1034
|
+
}
|
1035
|
+
}
|
1036
|
+
if ( num_DB_O ) {
|
1037
|
+
/* search for falsely tautomeric negatively charged atoms N and O */
|
1038
|
+
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
|
1039
|
+
iat = pc2i->c2at[i].atomNumber;
|
1040
|
+
if ( pc2i->c2at[i].endptRevrs && !pc2i->c2at[i].endptInChI &&
|
1041
|
+
pc2i->c2at[i].nAtChargeRevrs == - 1 &&
|
1042
|
+
0 <= (e=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
|
1043
|
+
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) ) {
|
1044
|
+
if ( pc2i->c2at[i].nValElectr == 6 ) {
|
1045
|
+
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_O], e, INC_ADD_EDGE ) ) {
|
1046
|
+
goto exit_case_07;
|
1047
|
+
}
|
1048
|
+
} else
|
1049
|
+
if ( pc2i->c2at[i].nValElectr == 5 ) {
|
1050
|
+
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_N], e, INC_ADD_EDGE ) ) {
|
1051
|
+
goto exit_case_07;
|
1052
|
+
}
|
1053
|
+
}
|
1054
|
+
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_ALL], e, INC_ADD_EDGE ) ) {
|
1055
|
+
goto exit_case_07;
|
1056
|
+
}
|
1057
|
+
}
|
1058
|
+
}
|
1059
|
+
/* ------- finally, try to move charges from O=N --------------*/
|
1060
|
+
for ( i = 0; i < num_DB_O; i ++ ) {
|
1061
|
+
int nDeltaChargeExpected;
|
1062
|
+
one_success = 0;
|
1063
|
+
delta = 1;
|
1064
|
+
iat = iat_DB_O[i];
|
1065
|
+
peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
|
1066
|
+
pe = pBNS->edge + pBNS->vert[iat].iedge[0];
|
1067
|
+
|
1068
|
+
if ( !pe->flow )
|
1069
|
+
continue;
|
1070
|
+
pv1 = pBNS->vert + (v1 = pe->neighbor1);
|
1071
|
+
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
|
1072
|
+
|
1073
|
+
pe->forbidden |= forbidden_edge_mask;
|
1074
|
+
|
1075
|
+
pe->flow -= delta;
|
1076
|
+
pv1->st_edge.flow -= delta;
|
1077
|
+
pv2->st_edge.flow -= delta;
|
1078
|
+
pBNS->tot_st_flow -= 2*delta;
|
1079
|
+
|
1080
|
+
for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
|
1081
|
+
if ( !ChangeableEdges[k].num_edges ) {
|
1082
|
+
continue;
|
1083
|
+
}
|
1084
|
+
nDeltaChargeExpected = 0;
|
1085
|
+
|
1086
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
1087
|
+
RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask );
|
1088
|
+
/* allow (-) charge to move to N=O */
|
1089
|
+
peDB_O_Minus->forbidden &= forbidden_edge_mask_inv;
|
1090
|
+
|
1091
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
1092
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
1093
|
+
|
1094
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
1095
|
+
vPathEnd == v2 && vPathStart == v1) &&
|
1096
|
+
nDeltaCharge == nDeltaChargeExpected ) {
|
1097
|
+
/* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
|
1098
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1099
|
+
if ( ret > 0 ) {
|
1100
|
+
nNumRunBNS ++;
|
1101
|
+
one_success ++; /* 07 */
|
1102
|
+
}
|
1103
|
+
}
|
1104
|
+
INCHI_HEAPCHK
|
1105
|
+
}
|
1106
|
+
cur_success += one_success;
|
1107
|
+
|
1108
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
1109
|
+
pe->forbidden &= forbidden_edge_mask_inv;
|
1110
|
+
|
1111
|
+
if ( !one_success ) {
|
1112
|
+
pe->flow += delta;
|
1113
|
+
pv1->st_edge.flow += delta;
|
1114
|
+
pv2->st_edge.flow += delta;
|
1115
|
+
pBNS->tot_st_flow += 2*delta;
|
1116
|
+
}
|
1117
|
+
}
|
1118
|
+
}
|
1119
|
+
exit_case_07:
|
1120
|
+
for ( i = 0; i < CHG_SET_NUM; i ++ ) {
|
1121
|
+
AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
CurrEdges.num_edges = 0; /* clear current edge list */
|
1125
|
+
if ( cur_success ) {
|
1126
|
+
tot_succes += cur_success;
|
1127
|
+
/* recalculate InChI from the structure */
|
1128
|
+
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
1129
|
+
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
|
1130
|
+
goto exit_function;
|
1131
|
+
}
|
1132
|
+
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
|
1133
|
+
goto exit_function;
|
1134
|
+
}
|
1135
|
+
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
|
1136
|
+
goto exit_function;
|
1137
|
+
}
|
1138
|
+
if ( !pc2i->bHasDifference ) {
|
1139
|
+
goto exit_function; /* nothing to do */
|
1140
|
+
}
|
1141
|
+
}
|
1142
|
+
#undef CHG_SET_NOOH
|
1143
|
+
#undef CHG_SET_WRONG_TAUT
|
1144
|
+
#undef CHG_SET_TAUT
|
1145
|
+
#undef CHG_LAST_SET
|
1146
|
+
#undef CHG_SET_O_FIXED
|
1147
|
+
#undef CHG_SET_NUM
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
|
1151
|
+
|
1152
|
+
exit_function:
|
1153
|
+
AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
|
1154
|
+
AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
|
1155
|
+
AllocEdgeList( &CurrEdges2, EDGE_LIST_FREE );
|
1156
|
+
AllocEdgeList( &CurrEdges3, EDGE_LIST_FREE );
|
1157
|
+
AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
|
1158
|
+
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
|
1159
|
+
AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_FREE );
|
1160
|
+
AllocEdgeList( &TautEdges, EDGE_LIST_FREE );
|
1161
|
+
|
1162
|
+
|
1163
|
+
return ret;
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
#endif
|