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/ichirvr4.c
ADDED
@@ -0,0 +1,3177 @@
|
|
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
|
+
/********************** Forbid carbon charge edges ***********************************/
|
43
|
+
int ForbidCarbonChargeEdges( BN_STRUCT *pBNS, ALL_TC_GROUPS *pTCGroups, EDGE_LIST *pCarbonChargeEdges, int forbidden_edge_mask )
|
44
|
+
{
|
45
|
+
#define MAX_NUM_CARBON_CHARGE_EDGES 2
|
46
|
+
int nType, i, k, ret;
|
47
|
+
BNS_EDGE *pEdge;
|
48
|
+
if ( ret = AllocEdgeList( pCarbonChargeEdges, MAX_NUM_CARBON_CHARGE_EDGES ) ) {
|
49
|
+
goto exit_function;
|
50
|
+
}
|
51
|
+
pCarbonChargeEdges->num_edges = 0;
|
52
|
+
for ( i = 0; i < MAX_NUM_CARBON_CHARGE_EDGES; i ++ ) {
|
53
|
+
switch( i ) {
|
54
|
+
case 0:
|
55
|
+
nType = TCG_Plus_C0;
|
56
|
+
break;
|
57
|
+
case 1:
|
58
|
+
nType = TCG_Minus_C0;
|
59
|
+
break;
|
60
|
+
default:
|
61
|
+
ret = RI_ERR_PROGR;
|
62
|
+
goto exit_function;
|
63
|
+
}
|
64
|
+
if ( (k = pTCGroups->nGroup[nType]) >= 0 ) {
|
65
|
+
k = pTCGroups->pTCG[k].nForwardEdge;
|
66
|
+
if ( k > 0 ) {
|
67
|
+
pEdge = pBNS->edge + k;
|
68
|
+
if ( !(pEdge->forbidden & forbidden_edge_mask) ) {
|
69
|
+
pEdge->forbidden |= forbidden_edge_mask;
|
70
|
+
if ( ret = AddToEdgeList( pCarbonChargeEdges, k, 0 ) ) {
|
71
|
+
goto exit_function;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
} else {
|
75
|
+
ret = RI_ERR_PROGR;
|
76
|
+
goto exit_function;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
ret = pCarbonChargeEdges->num_edges;
|
81
|
+
exit_function:
|
82
|
+
return ret;
|
83
|
+
#undef MAX_NUM_CARBON_CHARGE_EDGES
|
84
|
+
}
|
85
|
+
/******************************************************************************************************/
|
86
|
+
int ForbidNintrogenPlus2BondsInSmallRings( BN_STRUCT *pBNS, inp_ATOM *at, int num_at,
|
87
|
+
VAL_AT *pVA, int min_ring_size, ALL_TC_GROUPS *pTCGroups,
|
88
|
+
EDGE_LIST *pNplus2BondsEdges, int forbidden_edge_mask )
|
89
|
+
{
|
90
|
+
int i, j, ret;
|
91
|
+
BNS_EDGE *e;
|
92
|
+
|
93
|
+
ret = 0;
|
94
|
+
/* --- forbid edges that allow to make =N(+)= or #N(+)- in small ring */
|
95
|
+
for ( i = 0; i < num_at; i ++ ) {
|
96
|
+
if ( at[i].valence == 2 &&
|
97
|
+
!at[i].num_H && !at[i].endpoint &&
|
98
|
+
pVA[i].cNumValenceElectrons == 5 &&
|
99
|
+
pVA[i].cPeriodicRowNumber == 1 &&
|
100
|
+
!pVA[i].cMaxFlowToMetal && pVA[i].nCPlusGroupEdge > 0 &&
|
101
|
+
pVA[i].cnListIndex > 0 && cnList[pVA[i].cnListIndex-1].bits == cn_bits_MNP &&
|
102
|
+
pVA[i].cMinRingSize && pVA[i].cMinRingSize <= min_ring_size ) {
|
103
|
+
|
104
|
+
e = pBNS->edge + (j = pVA[i].nCPlusGroupEdge - 1);
|
105
|
+
if ( !(e->forbidden & forbidden_edge_mask) ) {
|
106
|
+
e->forbidden |= forbidden_edge_mask;
|
107
|
+
if ( ret = AddToEdgeList( pNplus2BondsEdges, j, 128 ) ) {
|
108
|
+
goto exit_function;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
ret = 0;
|
114
|
+
exit_function:
|
115
|
+
return ret;
|
116
|
+
}
|
117
|
+
|
118
|
+
/*************************************************************************************************
|
119
|
+
Problem: Formula in InChI from the reversed structure has less H than in the input InChI
|
120
|
+
Solutions:
|
121
|
+
|
122
|
+
(a) | |
|
123
|
+
-B(-)-NH-=..-=N(+)< => -B(-)-NH(+)=-..=-N< (H is not removed from the ion pair)
|
124
|
+
| |
|
125
|
+
|
126
|
+
| |
|
127
|
+
(b) >N(+)=-=...-=N-NH => >N-=-...=-N(+)-NH (charge from onium cannot be moved to remove H+)
|
128
|
+
| |
|
129
|
+
*************************************************************************************************/
|
130
|
+
int FixLessHydrogenInFormula( BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct, inp_ATOM *at,
|
131
|
+
inp_ATOM *at2, inp_ATOM *atf, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
132
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask )
|
133
|
+
{
|
134
|
+
int iBPlus=NO_VERTEX, iNV=NO_VERTEX, iNH = NO_VERTEX, neigh;
|
135
|
+
EDGE_LIST NewlyFixedEdges;
|
136
|
+
int ret, i, j;
|
137
|
+
int num_at = pStruct->num_atoms;
|
138
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
139
|
+
/* for RunBnsTestOnce */
|
140
|
+
Vertex vPathStart, vPathEnd;
|
141
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
142
|
+
|
143
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_CLEAR );
|
144
|
+
if ( ret = AllocEdgeList( &NewlyFixedEdges, 2*num_at ) ) {
|
145
|
+
goto exit_function;
|
146
|
+
}
|
147
|
+
for ( i = 0; i < num_at; i ++ ) {
|
148
|
+
if ( (j = pVA[i].nCMinusGroupEdge-1) >= 0 ) {
|
149
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
150
|
+
goto exit_function;
|
151
|
+
}
|
152
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
153
|
+
}
|
154
|
+
if ( (j = pVA[i].nCPlusGroupEdge-1) >= 0 ) {
|
155
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
156
|
+
goto exit_function;
|
157
|
+
}
|
158
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
/* extra H has been removed; check non-tautomeric atoms */
|
162
|
+
for ( i = 0; i < num_at; i ++ ) {
|
163
|
+
if ( !at2[i].endpoint && !pVA[i].cMetal &&
|
164
|
+
pVA[i].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
|
165
|
+
at2[i].num_H == atf[i].num_H + 1) {
|
166
|
+
/* H was removed from N */
|
167
|
+
iNH = i;
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
}
|
171
|
+
if ( 0 <= iNH && iNH < num_at ) {
|
172
|
+
/* check neighbors for | |
|
173
|
+
(a) -B(+)- or (b) =N-
|
174
|
+
| |
|
175
|
+
*/
|
176
|
+
for ( j = 0; j < at2[i].valence; j ++ ) {
|
177
|
+
neigh = at2[iNH].neighbor[j];
|
178
|
+
if ( at2[neigh].valence == 4 ) {
|
179
|
+
if ( at2[neigh].charge == -1 && at2[neigh].chem_bonds_valence == 4 &&
|
180
|
+
!at2[neigh].radical && !at[neigh].num_H ) {
|
181
|
+
iBPlus = neigh;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
if ( 0 <= iNH && iNH < num_at ) {
|
187
|
+
int bond_type_at2;
|
188
|
+
int bond_type_atf;
|
189
|
+
int num_bonds_in_path = 0;
|
190
|
+
int delta = -1, nxt = iNH, prv = NO_VERTEX, nxt_is_NPlus;
|
191
|
+
/* the changed bond to the dehydrogenated atom H should have greater order */
|
192
|
+
/* delta = (new bond order in atf[]) - (restored bond order in at2[]) */
|
193
|
+
nxt_is_NPlus = 0;
|
194
|
+
do {
|
195
|
+
i = nxt;
|
196
|
+
nxt = NO_VERTEX;
|
197
|
+
delta = -delta;
|
198
|
+
for ( j = 0; j < at2[i].valence; j ++ ) {
|
199
|
+
bond_type_at2 = at2[i].bond_type[j] & BOND_TYPE_MASK; /* restored bond */
|
200
|
+
bond_type_atf = atf[i].bond_type[j] & BOND_TYPE_MASK; /* normalized bond */
|
201
|
+
nxt_is_NPlus = 0;
|
202
|
+
if ( (bond_type_atf - bond_type_at2 == delta || bond_type_atf == BOND_ALT12NS) &&
|
203
|
+
BOND_TYPE_SINGLE <= bond_type_at2 + delta && bond_type_at2 + delta <= BOND_TYPE_TRIPLE &&
|
204
|
+
!at2[(int)at2[i].neighbor[j]].cFlags ) {
|
205
|
+
prv = i;
|
206
|
+
nxt = at2[i].neighbor[j];
|
207
|
+
nxt_is_NPlus = at2[nxt].charge == 1 && atf[nxt].charge == 0 &&
|
208
|
+
pVA[nxt].cNumValenceElectrons == 5 && pVA[nxt].cPeriodicRowNumber == 1;
|
209
|
+
at2[i].cFlags |= 1; /* avoid cycling */
|
210
|
+
num_bonds_in_path ++;
|
211
|
+
if ( delta == -1 && at2[prv].valence == 4 && at2[prv].chem_bonds_valence == 5 &&
|
212
|
+
!at2[prv].charge && !at2[prv].radical && pVA[prv].cNumValenceElectrons == 5 &&
|
213
|
+
pVA[prv].nCPlusGroupEdge > 0 ) {
|
214
|
+
iNV = prv;
|
215
|
+
}
|
216
|
+
if ( at2[nxt].charge != atf[nxt].charge ) {
|
217
|
+
if ( (at2[nxt].charge == 1 || atf[nxt].charge == 1) &&
|
218
|
+
pVA[nxt].nCPlusGroupEdge > 0 ) {
|
219
|
+
pBNS->edge[pVA[nxt].nCPlusGroupEdge-1].forbidden &= inv_forbidden_edge_mask;
|
220
|
+
}
|
221
|
+
if ( (at2[nxt].charge == -1 || atf[nxt].charge == -1) &&
|
222
|
+
pVA[nxt].nCMinusGroupEdge > 0 ) {
|
223
|
+
pBNS->edge[pVA[nxt].nCMinusGroupEdge-1].forbidden &= inv_forbidden_edge_mask;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
break; /* found */
|
227
|
+
}
|
228
|
+
}
|
229
|
+
} while ( nxt >= 0 && !( nxt_is_NPlus && delta == -1 ) );
|
230
|
+
for ( i = 0; i < num_at; i ++ ) {
|
231
|
+
at2[i].cFlags = 0;
|
232
|
+
}
|
233
|
+
if ( nxt >= 0 && nxt_is_NPlus && delta == -1 ) {
|
234
|
+
/* a simple alt path from NH-= to =N(+) has been found */
|
235
|
+
if ( iBPlus || iNV ) {
|
236
|
+
/* move (+) charge from N(+) to iNV or, if iBPlus, then to iNH */
|
237
|
+
if ( iNV >= 0 && (j = pVA[iNV].nCPlusGroupEdge-1) > 0 && pBNS->edge[j].flow > 0 ||
|
238
|
+
iNH >= 0 && (j = pVA[iNH].nCPlusGroupEdge-1) > 0 && pBNS->edge[j].flow > 0 ) {
|
239
|
+
int ieFlower;
|
240
|
+
BNS_EDGE *pe = pBNS->edge + j, *peFlower = NULL;
|
241
|
+
Vertex v1 = pe->neighbor1;
|
242
|
+
Vertex v2 = v1 ^ pe->neighbor12;
|
243
|
+
BNS_VERTEX *pv1 = pBNS->vert + v1;
|
244
|
+
BNS_VERTEX *pv2 = pBNS->vert + v2;
|
245
|
+
|
246
|
+
delta = 1;
|
247
|
+
/* prevent conversion of >N(+)= into N(V) neutral */
|
248
|
+
ieFlower = GetChargeFlowerUpperEdge( pBNS, pVA, pVA[nxt].nCPlusGroupEdge-1 );
|
249
|
+
if ( ieFlower >= 0 ) {
|
250
|
+
peFlower = pBNS->edge + ieFlower;
|
251
|
+
if ( peFlower->flow == delta ) {
|
252
|
+
peFlower->forbidden |= forbidden_edge_mask;
|
253
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, ieFlower, 0 )) {
|
254
|
+
goto exit_function;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
}
|
258
|
+
pe->forbidden |= forbidden_edge_mask;
|
259
|
+
pe->flow -= delta;
|
260
|
+
pv1->st_edge.flow -= delta;
|
261
|
+
pv2->st_edge.flow -= delta;
|
262
|
+
pBNS->tot_st_flow -= 2*delta;
|
263
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
264
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
265
|
+
if ( ret < 0 ) {
|
266
|
+
goto exit_function;
|
267
|
+
}
|
268
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
269
|
+
vPathEnd == v2 && vPathStart == v1) &&
|
270
|
+
nDeltaCharge <= 0 /* charge moving to this atom disappers*/ ) {
|
271
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
272
|
+
(*pnNumRunBNS) ++;
|
273
|
+
if ( ret < 0 ) {
|
274
|
+
goto exit_function;
|
275
|
+
} else
|
276
|
+
if ( ret == 1 ) {
|
277
|
+
*pnTotalDelta += ret;
|
278
|
+
} else {
|
279
|
+
ret = RI_ERR_PROGR;
|
280
|
+
goto exit_function;
|
281
|
+
}
|
282
|
+
} else {
|
283
|
+
ret = 0;
|
284
|
+
pe->flow += delta;
|
285
|
+
pv1->st_edge.flow += delta;
|
286
|
+
pv2->st_edge.flow += delta;
|
287
|
+
pBNS->tot_st_flow += 2*delta;
|
288
|
+
}
|
289
|
+
|
290
|
+
}
|
291
|
+
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
exit_function:
|
296
|
+
/* remove bond fixation */
|
297
|
+
RemoveForbiddenEdgeMask( pBNS, &NewlyFixedEdges, forbidden_edge_mask );
|
298
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_FREE );
|
299
|
+
return ret;
|
300
|
+
}
|
301
|
+
/***********************************************************************************************
|
302
|
+
|
303
|
+
|
304
|
+
X=Y-O(-) => X(-)-Y=O
|
305
|
+
|
306
|
+
|
307
|
+
************************************************************************************************/
|
308
|
+
int FixMoreHydrogenInFormula( BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct, inp_ATOM *at,
|
309
|
+
inp_ATOM *at2, inp_ATOM *atf, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
310
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask )
|
311
|
+
{
|
312
|
+
int iNH = NO_VERTEX, neigh, neigh2;
|
313
|
+
EDGE_LIST NewlyFixedEdges;
|
314
|
+
int ret, i, j, k, k2, delta;
|
315
|
+
int num_at = pStruct->num_atoms;
|
316
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
317
|
+
Vertex v1, v2;
|
318
|
+
/* for RunBnsTestOnce */
|
319
|
+
Vertex vPathStart, vPathEnd;
|
320
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
321
|
+
BNS_EDGE *pe, *pe2;
|
322
|
+
|
323
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_CLEAR );
|
324
|
+
if ( ret = AllocEdgeList( &NewlyFixedEdges, 2*num_at ) ) {
|
325
|
+
goto exit_function;
|
326
|
+
}
|
327
|
+
/* fix all charges */
|
328
|
+
for ( i = 0; i < num_at; i ++ ) {
|
329
|
+
if ( (j = pVA[i].nCMinusGroupEdge-1) >= 0 ) {
|
330
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
331
|
+
goto exit_function;
|
332
|
+
}
|
333
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
334
|
+
}
|
335
|
+
if ( (j = pVA[i].nCPlusGroupEdge-1) >= 0 ) {
|
336
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
337
|
+
goto exit_function;
|
338
|
+
}
|
339
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
340
|
+
}
|
341
|
+
}
|
342
|
+
|
343
|
+
/* H(+) has been added to -O(-); check non-tautomeric atoms */
|
344
|
+
for ( i = 0; i < num_at; i ++ ) {
|
345
|
+
if ( !(pStruct->bMobileH? at2[i].endpoint : pStruct->endpoint[i]) && !pVA[i].cMetal &&
|
346
|
+
at2[i].num_H + 1 == atf[i].num_H && /* normalization added H ??? What would happen in Fixed-H case?*/
|
347
|
+
(k = pVA[i].nCMinusGroupEdge-1) >= 0 &&
|
348
|
+
pBNS->edge[k].flow == 1 && /* atom had (-) charge before preprocessing */
|
349
|
+
at2[i].charge == -1 && atf[i].charge == 0 && /* and has no charge after preprocessing */
|
350
|
+
at2[i].valence == 1 && at2[i].chem_bonds_valence == 1 && /* connected by a single bond */
|
351
|
+
pVA[i].cNumValenceElectrons == 6 && /* atom is O, S, Se, Te */
|
352
|
+
at2[neigh=at2[i].neighbor[0]].chem_bonds_valence > at2[neigh].valence
|
353
|
+
/* atom's single neighbor has multiple bond(s)*/
|
354
|
+
) {
|
355
|
+
/* H(+) was added to O in Y=X-O(-), where X is the only neighbor of O, X=neigh, Y=neigh2 */
|
356
|
+
iNH = i;
|
357
|
+
for ( j = 0; j < at2[neigh].valence; j ++ ) {
|
358
|
+
neigh2 = at2[neigh].neighbor[j];
|
359
|
+
if ( neigh2 != iNH && !at2[neigh2].endpoint &&
|
360
|
+
!pBNS->edge[(int)pBNS->vert[neigh].iedge[j]].forbidden &&
|
361
|
+
4 <= pVA[neigh2].cNumValenceElectrons &&
|
362
|
+
pVA[neigh2].cNumValenceElectrons <= 5 && /* neig2 is C or N */
|
363
|
+
(k2 = pVA[neigh2].nCMinusGroupEdge-1) >= 0 &&
|
364
|
+
!pBNS->edge[k2].flow /* negative charge may be moved to neigh2 */ ) {
|
365
|
+
break;
|
366
|
+
}
|
367
|
+
}
|
368
|
+
if ( j < at2[neigh].valence ) {
|
369
|
+
delta = 1;
|
370
|
+
pe = pBNS->edge + k; /* -O(-) negative charge edge; flow = 1 */
|
371
|
+
pe2 = pBNS->edge + k2; /* X charge edge; flow = 0 */
|
372
|
+
v1 = pe->neighbor1;
|
373
|
+
v2 = pe->neighbor12 ^ v1;
|
374
|
+
pe->flow -= delta;
|
375
|
+
pBNS->vert[v1].st_edge.flow -= delta;
|
376
|
+
pBNS->vert[v2].st_edge.flow -= delta;
|
377
|
+
pBNS->tot_st_flow -= 2*delta;
|
378
|
+
pe2->forbidden &= inv_forbidden_edge_mask; /* allow the charge to move */
|
379
|
+
|
380
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
381
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
382
|
+
if ( ret < 0 ) {
|
383
|
+
goto exit_function;
|
384
|
+
}
|
385
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
386
|
+
vPathEnd == v2 && vPathStart == v1) &&
|
387
|
+
nDeltaCharge <= 1 ) {
|
388
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
389
|
+
(*pnNumRunBNS) ++;
|
390
|
+
if ( ret < 0 ) {
|
391
|
+
goto exit_function;
|
392
|
+
} else
|
393
|
+
if ( ret ) {
|
394
|
+
*pnTotalDelta += ret;
|
395
|
+
} else {
|
396
|
+
ret = RI_ERR_PROGR;
|
397
|
+
}
|
398
|
+
break;
|
399
|
+
} else {
|
400
|
+
/* the attempt has failed; restore the flow */
|
401
|
+
ret = 0;
|
402
|
+
pe->flow += delta;
|
403
|
+
pBNS->vert[v1].st_edge.flow += delta;
|
404
|
+
pBNS->vert[v2].st_edge.flow += delta;
|
405
|
+
pBNS->tot_st_flow += 2*delta;
|
406
|
+
}
|
407
|
+
}
|
408
|
+
}
|
409
|
+
}
|
410
|
+
exit_function:
|
411
|
+
/* remove bond fixation */
|
412
|
+
RemoveForbiddenEdgeMask( pBNS, &NewlyFixedEdges, forbidden_edge_mask );
|
413
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_FREE );
|
414
|
+
return ret;
|
415
|
+
}
|
416
|
+
#if( FIX_ADD_PROTON_FOR_ADP == 1 )
|
417
|
+
/******************************************************************************************************/
|
418
|
+
int FixAddProtonForADP( BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct, inp_ATOM *at,
|
419
|
+
inp_ATOM *at2, inp_ATOM *atf, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups, ICR *picr,
|
420
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask )
|
421
|
+
{
|
422
|
+
int iBPlus=NO_VERTEX, iNV=NO_VERTEX, iNH = NO_VERTEX, neigh, neigh2;
|
423
|
+
EDGE_LIST NewlyFixedEdges;
|
424
|
+
int ret, i, j, k, k2, delta;
|
425
|
+
int num_at = pStruct->num_atoms;
|
426
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
427
|
+
Vertex v1, v2;
|
428
|
+
/* for RunBnsTestOnce */
|
429
|
+
Vertex vPathStart, vPathEnd;
|
430
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
431
|
+
BNS_EDGE *pe, *pe2;
|
432
|
+
|
433
|
+
ret = 0;
|
434
|
+
/*
|
435
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_CLEAR );
|
436
|
+
|
437
|
+
for ( i = 0; i < num_at; i ++ ) {
|
438
|
+
if ( at2[i].radical == RADICAL_DOUBLET && at2[i].endpoint ) {
|
439
|
+
pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;
|
440
|
+
ret = 1;
|
441
|
+
break;
|
442
|
+
}
|
443
|
+
}
|
444
|
+
*/
|
445
|
+
return ret;
|
446
|
+
}
|
447
|
+
#endif
|
448
|
+
/******************************************************************************************************
|
449
|
+
OH OH
|
450
|
+
/ /
|
451
|
+
-NH => -NH(+) to eliminate false tautomerism. S(IV) or N(V) or P(V) may be a centerpoint
|
452
|
+
\\ \
|
453
|
+
O O(-)
|
454
|
+
*******************************************************************************************************/
|
455
|
+
int FixRemoveExtraTautEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct, inp_ATOM *at,
|
456
|
+
inp_ATOM *at2, inp_ATOM *atf, inp_ATOM *atn, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups, ICR *picr,
|
457
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask )
|
458
|
+
{
|
459
|
+
EDGE_LIST NewlyFixedEdges;
|
460
|
+
int ret, i, j, k, delta, centerpoint, endpoint1, endpoint2;
|
461
|
+
int num_at = pStruct->num_atoms;
|
462
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
463
|
+
Vertex v1, v2;
|
464
|
+
/* for RunBnsTestOnce */
|
465
|
+
Vertex vPathStart, vPathEnd;
|
466
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
467
|
+
BNS_EDGE *pe, *pe2;
|
468
|
+
|
469
|
+
ret = 0;
|
470
|
+
|
471
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_CLEAR );
|
472
|
+
if ( ret = AllocEdgeList( &NewlyFixedEdges, 2*num_at ) ) {
|
473
|
+
goto exit_function;
|
474
|
+
}
|
475
|
+
/* fix all charges */
|
476
|
+
for ( i = 0; i < num_at; i ++ ) {
|
477
|
+
if ( (j = pVA[i].nCMinusGroupEdge-1) >= 0 ) {
|
478
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
479
|
+
goto exit_function;
|
480
|
+
}
|
481
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
482
|
+
}
|
483
|
+
if ( (j = pVA[i].nCPlusGroupEdge-1) >= 0 ) {
|
484
|
+
if ( ret = AddToEdgeList( &NewlyFixedEdges, j, 0 )) {
|
485
|
+
goto exit_function;
|
486
|
+
}
|
487
|
+
pBNS->edge[j].forbidden |= forbidden_edge_mask;
|
488
|
+
}
|
489
|
+
}
|
490
|
+
|
491
|
+
for ( i = 0; i < picr->num_endp_in1_only; i ++ ) {
|
492
|
+
endpoint1 = picr->endp_in1_only[i]-1;
|
493
|
+
if ( at2[endpoint1].valence == at2[endpoint1].chem_bonds_valence ||
|
494
|
+
pVA[endpoint1].nCMinusGroupEdge <= 0 ) {
|
495
|
+
continue;
|
496
|
+
}
|
497
|
+
/* find centerpoint */
|
498
|
+
for ( j = 0; j < at2[endpoint1].valence; j ++ ) {
|
499
|
+
if ( BOND_TYPE_DOUBLE == ( BOND_TYPE_MASK & at2[endpoint1].bond_type[j] ) ) {
|
500
|
+
centerpoint = at2[endpoint1].neighbor[j];
|
501
|
+
if ( at2[centerpoint].charge || pVA[centerpoint].nCPlusGroupEdge <= 0 ||
|
502
|
+
!is_centerpoint_elem( at2[centerpoint].el_number ) ) {
|
503
|
+
continue;
|
504
|
+
}
|
505
|
+
/* -- the centerpoint as depicted has no ChargeStruct flower ---
|
506
|
+
m = GetChargeFlowerUpperEdge( pBNS, pVA, pVA[centerpoint].nCPlusGroupEdge-1 );
|
507
|
+
if ( m < 0 || pBNS->edge[m].flow ) {
|
508
|
+
continue;
|
509
|
+
}
|
510
|
+
*/
|
511
|
+
/* find 2nd endpoint */
|
512
|
+
for ( k = 0; k < at2[centerpoint].valence; k ++ ) {
|
513
|
+
if ( BOND_TYPE_SINGLE != ( BOND_TYPE_MASK & at2[centerpoint].bond_type[k] ) ) {
|
514
|
+
continue;
|
515
|
+
}
|
516
|
+
endpoint2 = at2[centerpoint].neighbor[k];
|
517
|
+
if ( !at2[endpoint2].endpoint && atn[endpoint2].endpoint ) {
|
518
|
+
break;
|
519
|
+
}
|
520
|
+
}
|
521
|
+
if ( k == at2[centerpoint].valence ) {
|
522
|
+
continue;
|
523
|
+
}
|
524
|
+
/* the centerpoint and two extra endpoints have been found */
|
525
|
+
pe = pBNS->edge + pVA[centerpoint].nCPlusGroupEdge - 1;
|
526
|
+
if ( !pe->flow ) {
|
527
|
+
continue;
|
528
|
+
}
|
529
|
+
pe2 = pBNS->edge + pVA[endpoint1].nCMinusGroupEdge - 1;
|
530
|
+
if ( pe2->flow ) {
|
531
|
+
continue;
|
532
|
+
}
|
533
|
+
delta = 1;
|
534
|
+
v1 = pe->neighbor1;
|
535
|
+
v2 = pe->neighbor12 ^ v1;
|
536
|
+
pe->flow -= delta;
|
537
|
+
pBNS->vert[v1].st_edge.flow -= delta;
|
538
|
+
pBNS->vert[v2].st_edge.flow -= delta;
|
539
|
+
pBNS->tot_st_flow -= 2*delta;
|
540
|
+
pe2->forbidden &= inv_forbidden_edge_mask; /* allow the charge to move */
|
541
|
+
|
542
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
543
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
544
|
+
if ( ret < 0 ) {
|
545
|
+
goto exit_function;
|
546
|
+
}
|
547
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
548
|
+
vPathEnd == v2 && vPathStart == v1) &&
|
549
|
+
nDeltaCharge <= 1 ) {
|
550
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
551
|
+
(*pnNumRunBNS) ++;
|
552
|
+
if ( ret < 0 ) {
|
553
|
+
goto exit_function;
|
554
|
+
} else
|
555
|
+
if ( ret ) {
|
556
|
+
*pnTotalDelta += ret;
|
557
|
+
} else {
|
558
|
+
ret = RI_ERR_PROGR;
|
559
|
+
}
|
560
|
+
goto exit_function;
|
561
|
+
} else {
|
562
|
+
ret = 0;
|
563
|
+
pe->flow += delta;
|
564
|
+
pBNS->vert[v1].st_edge.flow += delta;
|
565
|
+
pBNS->vert[v2].st_edge.flow += delta;
|
566
|
+
pBNS->tot_st_flow += 2*delta;
|
567
|
+
pe2->forbidden |= forbidden_edge_mask;
|
568
|
+
}
|
569
|
+
}
|
570
|
+
}
|
571
|
+
}
|
572
|
+
|
573
|
+
exit_function:
|
574
|
+
/* remove bond fixation */
|
575
|
+
RemoveForbiddenEdgeMask( pBNS, &NewlyFixedEdges, forbidden_edge_mask );
|
576
|
+
AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_FREE );
|
577
|
+
return ret;
|
578
|
+
}
|
579
|
+
/*************************************************************************/
|
580
|
+
int FillOutExtraFixedHDataRestr( StrFromINChI *pStruct )
|
581
|
+
{
|
582
|
+
int i, j, k, len, ret = 0;
|
583
|
+
AT_NUMB *pNum;
|
584
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
585
|
+
if ( pStruct->pOneINChI_Aux[i] ) {
|
586
|
+
pNum = (pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd &&
|
587
|
+
pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd[0])?
|
588
|
+
pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd:
|
589
|
+
(pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd &&
|
590
|
+
pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd[0])?
|
591
|
+
pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd : NULL;
|
592
|
+
} else {
|
593
|
+
pNum = NULL;
|
594
|
+
}
|
595
|
+
if ( pNum ) {
|
596
|
+
len = pStruct->num_atoms * sizeof(pStruct->nCanon2Atno[0][0]);
|
597
|
+
if ( !pStruct->nCanon2Atno[i] &&
|
598
|
+
!(pStruct->nCanon2Atno[i] = (AT_NUMB *)inchi_malloc( len )) ||
|
599
|
+
!pStruct->nAtno2Canon[i] &&
|
600
|
+
!(pStruct->nAtno2Canon[i] = (AT_NUMB *)inchi_malloc( len ))) {
|
601
|
+
ret = RI_ERR_ALLOC;
|
602
|
+
goto exit_function;
|
603
|
+
}
|
604
|
+
|
605
|
+
INCHI_HEAPCHK
|
606
|
+
|
607
|
+
memcpy( pStruct->nCanon2Atno[i], pNum, len ); /* ??? the next for(...) fills it out */
|
608
|
+
|
609
|
+
INCHI_HEAPCHK
|
610
|
+
|
611
|
+
for ( j = 0; j < pStruct->num_atoms; j ++ ) {
|
612
|
+
k = pNum[j]-1; /* atom number */
|
613
|
+
pStruct->nCanon2Atno[i][j] = (AT_NUMB)k;
|
614
|
+
pStruct->nAtno2Canon[i][k] = (AT_NUMB)j;
|
615
|
+
INCHI_HEAPCHK
|
616
|
+
}
|
617
|
+
} else
|
618
|
+
if ( !i ) {
|
619
|
+
ret = RI_ERR_PROGR;
|
620
|
+
goto exit_function;
|
621
|
+
} else {
|
622
|
+
if ( pStruct->nCanon2Atno[i] ) {
|
623
|
+
inchi_free( pStruct->nCanon2Atno[i] );
|
624
|
+
pStruct->nCanon2Atno[i] = NULL;
|
625
|
+
}
|
626
|
+
INCHI_HEAPCHK
|
627
|
+
if ( pStruct->nAtno2Canon[i] ) {
|
628
|
+
inchi_free( pStruct->nAtno2Canon[i] );
|
629
|
+
pStruct->nAtno2Canon[i] = NULL;
|
630
|
+
}
|
631
|
+
INCHI_HEAPCHK
|
632
|
+
}
|
633
|
+
}
|
634
|
+
|
635
|
+
exit_function:
|
636
|
+
return ret;
|
637
|
+
}
|
638
|
+
/*************************************************************************/
|
639
|
+
int FillOutExtraFixedHDataInChI( StrFromINChI *pStruct, INChI *pInChI[] )
|
640
|
+
{
|
641
|
+
int ret = 0;
|
642
|
+
/*--- allocate memory for Mobile/Fixed-H data from the input InChI ---*/
|
643
|
+
if ( NULL == pStruct->endpoint ) {
|
644
|
+
pStruct->endpoint = (AT_NUMB *)inchi_calloc(pStruct->num_atoms, sizeof(pStruct->endpoint[0]));
|
645
|
+
} else {
|
646
|
+
memset( pStruct->endpoint, 0, pStruct->num_atoms * sizeof(pStruct->endpoint[0] ) );
|
647
|
+
}
|
648
|
+
if ( NULL == pStruct->fixed_H ) {
|
649
|
+
pStruct->fixed_H = (S_CHAR *)inchi_malloc(pStruct->num_atoms * sizeof(pStruct->fixed_H[0]));
|
650
|
+
}
|
651
|
+
if ( !pStruct->endpoint || !pStruct->fixed_H ) {
|
652
|
+
ret = RI_ERR_ALLOC;
|
653
|
+
goto exit_function;
|
654
|
+
}
|
655
|
+
/*--- fill out Mobile/Fixed-H data from the input InChI ---*/
|
656
|
+
GetTgroupInfoFromInChI( &pStruct->ti, NULL, pStruct->endpoint, pInChI[1] );
|
657
|
+
if ( pInChI[0]->nNum_H_fixed ) {
|
658
|
+
memcpy( pStruct->fixed_H, pInChI[0]->nNum_H_fixed, pStruct->num_atoms * sizeof(pStruct->fixed_H[0]) );
|
659
|
+
} else {
|
660
|
+
memset( pStruct->fixed_H, 0, pStruct->num_atoms * sizeof(pStruct->fixed_H[0]) );
|
661
|
+
}
|
662
|
+
|
663
|
+
exit_function:
|
664
|
+
return ret;
|
665
|
+
}
|
666
|
+
/***********************************************************************************************/
|
667
|
+
int FillOutCMP2FHINCHI( StrFromINChI *pStruct, inp_ATOM *at2, VAL_AT *pVA, INChI *pInChI[], CMP2FHINCHI *pc2i )
|
668
|
+
{
|
669
|
+
int ret = 0, i, j;
|
670
|
+
int bFixHRevrsExists = pInChI[1] && pInChI[1]->nNumberOfAtoms > 0 && !pInChI[1]->bDeleted;
|
671
|
+
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
|
672
|
+
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
|
673
|
+
S_CHAR *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
|
674
|
+
/* atom number in structure that produced original InChI is atom number in all inp_ATOM *atoms */
|
675
|
+
/* atom number in structure that produced restored InChI is in nAtomRevrs[]: */
|
676
|
+
AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
|
677
|
+
S_CHAR *pnMobHInChI = (pInChI[1] && pInChI[1]->nNum_H)? pInChI[1]->nNum_H :
|
678
|
+
(pInChI[0] && pInChI[0]->nNum_H)? pInChI[0]->nNum_H : NULL;
|
679
|
+
S_CHAR *pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
|
680
|
+
pStruct->pOneINChI[1]->nNum_H :
|
681
|
+
(pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
|
682
|
+
pStruct->pOneINChI[0]->nNum_H : NULL;
|
683
|
+
int nNumTgHInChI, nNumTgMInChI, nNumTgHRevrs, nNumTgMRevrs;
|
684
|
+
memset( pc2i, 0, sizeof(*pc2i) );
|
685
|
+
pc2i->nNumTgInChI = pStruct->ti.num_t_groups;
|
686
|
+
pc2i->nNumTgRevrs = pStruct->One_ti.num_t_groups;
|
687
|
+
pc2i->bHasDifference |= pc2i->nNumTgInChI != pc2i->nNumTgRevrs;
|
688
|
+
|
689
|
+
pc2i->nNumRemHInChI = pStruct->nNumRemovedProtonsMobHInChI;
|
690
|
+
pc2i->nNumRemHRevrs = pStruct->One_ti.tni.nNumRemovedProtons;
|
691
|
+
pc2i->bHasDifference |= pc2i->nNumRemHInChI != pc2i->nNumRemHRevrs;
|
692
|
+
|
693
|
+
pc2i->bFixedHLayerExistsRevrs = bFixHRevrsExists;
|
694
|
+
pc2i->bHasDifference |= !bFixHRevrsExists;
|
695
|
+
|
696
|
+
for ( i = 0; i < pStruct->ti.num_t_groups && i < pStruct->One_ti.num_t_groups; i ++ ) {
|
697
|
+
nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
|
698
|
+
nNumTgMInChI = pStruct->ti.t_group[i].num[1];
|
699
|
+
nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
|
700
|
+
nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
|
701
|
+
|
702
|
+
pc2i->bHasDifference |= nNumTgHInChI != nNumTgHRevrs;
|
703
|
+
pc2i->bHasDifference |= nNumTgMInChI != nNumTgMRevrs;
|
704
|
+
|
705
|
+
if ( pStruct->ti.t_group[i].nNumEndpoints ==
|
706
|
+
pStruct->One_ti.t_group[i].nNumEndpoints ) {
|
707
|
+
|
708
|
+
if ( nNumTgHInChI != nNumTgHRevrs ) {
|
709
|
+
pc2i->nNumTgDiffH ++;
|
710
|
+
}
|
711
|
+
if ( nNumTgMInChI != nNumTgMRevrs ) {
|
712
|
+
pc2i->nNumTgDiffMinus ++;
|
713
|
+
}
|
714
|
+
}
|
715
|
+
pc2i->bHasDifference |= pStruct->ti.t_group[i].nNumEndpoints !=
|
716
|
+
pStruct->One_ti.t_group[i].nNumEndpoints;
|
717
|
+
|
718
|
+
pc2i->nNumTgHInChI += nNumTgHInChI;
|
719
|
+
pc2i->nNumTgMInChI += nNumTgMInChI;
|
720
|
+
pc2i->nNumTgHRevrs += nNumTgHRevrs;
|
721
|
+
pc2i->nNumTgMRevrs += nNumTgMRevrs;
|
722
|
+
|
723
|
+
}
|
724
|
+
for ( ; i < pStruct->ti.num_t_groups; i ++ ) {
|
725
|
+
nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
|
726
|
+
nNumTgMInChI = pStruct->ti.t_group[i].num[1];
|
727
|
+
pc2i->nNumTgHInChI += nNumTgHInChI;
|
728
|
+
pc2i->nNumTgMInChI += nNumTgMInChI;
|
729
|
+
pc2i->bHasDifference |= 1;
|
730
|
+
}
|
731
|
+
for ( ; i < pStruct->One_ti.num_t_groups; i ++ ) {
|
732
|
+
nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
|
733
|
+
nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
|
734
|
+
pc2i->nNumTgHRevrs += nNumTgHRevrs;
|
735
|
+
pc2i->nNumTgMRevrs += nNumTgMRevrs;
|
736
|
+
pc2i->bHasDifference |= 1;
|
737
|
+
|
738
|
+
}
|
739
|
+
for ( i = j = 0; i < pStruct->num_atoms; i ++ ) {
|
740
|
+
/* i = original InChI canonical number - 1 */
|
741
|
+
/* k = atom number from InChI created out of restored Fixed-H structure */
|
742
|
+
int iCanonRevrs = nAtno2CanonRevrs[i];
|
743
|
+
int endptInChI = pStruct->endpoint[i]; /* endpoint in InChI */
|
744
|
+
int endptRevrs = at_Mobile_H_Revrs? at_Mobile_H_Revrs[i].endpoint : 0;
|
745
|
+
int nFixHInChI = pStruct->fixed_H[i];
|
746
|
+
int nFixHRevrs = num_Fixed_H_Revrs? num_Fixed_H_Revrs[iCanonRevrs]:0;
|
747
|
+
int nMobHInChI = pnMobHInChI? pnMobHInChI[i]:0;
|
748
|
+
int nMobHRevrs = pnMobHRevrs? pnMobHRevrs[iCanonRevrs]:0;
|
749
|
+
if ( /*(!endptInChI || !endptRevrs) &&*/ (nFixHInChI != nFixHRevrs ) ||
|
750
|
+
(!endptInChI != !endptRevrs) || nMobHInChI != nMobHRevrs ) {
|
751
|
+
/* in InChI or reversed InChI atom[i] is not tautomeric */
|
752
|
+
/* and number of fixed-H on the atom[i] differs */
|
753
|
+
if ( j >= MAX_DIFF_FIXH ) {
|
754
|
+
ret = RI_ERR_PROGR;
|
755
|
+
goto exit_function;
|
756
|
+
}
|
757
|
+
pc2i->c2at[j].endptInChI = endptInChI;
|
758
|
+
pc2i->c2at[j].endptRevrs = endptRevrs;
|
759
|
+
pc2i->bHasDifference |= !endptInChI != !endptRevrs;
|
760
|
+
pc2i->c2at[j].atomNumber = i;
|
761
|
+
pc2i->c2at[j].nValElectr = pVA[i].cNumValenceElectrons;
|
762
|
+
pc2i->c2at[j].nPeriodNum = pVA[i].cPeriodicRowNumber;
|
763
|
+
pc2i->c2at[j].nFixHInChI = nFixHInChI;
|
764
|
+
pc2i->c2at[j].nFixHRevrs = nFixHRevrs;
|
765
|
+
pc2i->bHasDifference |= nFixHInChI != nFixHRevrs;
|
766
|
+
pc2i->c2at[j].nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H[i] :
|
767
|
+
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H[i] : 0;
|
768
|
+
pc2i->c2at[j].nMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
|
769
|
+
pStruct->pOneINChI[1]->nNum_H[iCanonRevrs] :
|
770
|
+
(pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
|
771
|
+
pStruct->pOneINChI[0]->nNum_H[iCanonRevrs] : 0;
|
772
|
+
pc2i->nNumDiffMobH += (nMobHInChI != nMobHRevrs && !endptRevrs && !endptInChI);
|
773
|
+
pc2i->bHasDifference |= nMobHInChI != nMobHRevrs;
|
774
|
+
pc2i->c2at[j].nNumHRevrs = at2[i].num_H;
|
775
|
+
pc2i->c2at[j].nAtChargeRevrs = at2[i].charge;
|
776
|
+
j ++;
|
777
|
+
}
|
778
|
+
pc2i->nNumEndpInChI += (endptInChI != 0);
|
779
|
+
pc2i->nNumEndpRevrs += (endptRevrs != 0);
|
780
|
+
|
781
|
+
if ( !pVA[i].cMetal ) {
|
782
|
+
pc2i->nChargeFixHRevrsNonMetal += at2[i].charge;
|
783
|
+
pc2i->nChargeMobHRevrsNonMetal += at_Mobile_H_Revrs? at_Mobile_H_Revrs[i].charge : 0;
|
784
|
+
}
|
785
|
+
|
786
|
+
/*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
|
787
|
+
}
|
788
|
+
pc2i->nChargeFixHInChI = pInChI[0]? pInChI[0]->nTotalCharge : 0;
|
789
|
+
pc2i->nChargeMobHInChI = pInChI[1]? pInChI[1]->nTotalCharge : 0;
|
790
|
+
|
791
|
+
pc2i->nChargeMobHRevrs = pStruct->pOneINChI[1]? pStruct->pOneINChI[1]->nTotalCharge :
|
792
|
+
pStruct->pOneINChI[0]? pStruct->pOneINChI[0]->nTotalCharge : 0;
|
793
|
+
pc2i->nChargeFixHRevrs = pStruct->pOneINChI[0]? pStruct->pOneINChI[0]->nTotalCharge : 0;
|
794
|
+
|
795
|
+
pc2i->bHasDifference |= pc2i->nChargeFixHInChI != pc2i->nChargeFixHRevrs;
|
796
|
+
pc2i->bHasDifference |= pc2i->nChargeMobHInChI != pc2i->nChargeMobHRevrs;
|
797
|
+
|
798
|
+
exit_function:
|
799
|
+
pc2i->len_c2at = j;
|
800
|
+
|
801
|
+
return ret;
|
802
|
+
}
|
803
|
+
/***********************************************************************************************/
|
804
|
+
int FillOutCMP2MHINCHI( StrFromINChI *pStruct, ALL_TC_GROUPS *pTCGroups, inp_ATOM *at2,
|
805
|
+
VAL_AT *pVA, INChI *pInChI[], CMP2MHINCHI *pc2i )
|
806
|
+
{
|
807
|
+
int ret = 0, i, j, iat;
|
808
|
+
int bFixHRevrsExists = pInChI[1] && pInChI[1]->nNumberOfAtoms > 0 && !pInChI[1]->bDeleted;
|
809
|
+
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[0] &&
|
810
|
+
pStruct->pOne_norm_data[0]->at)? pStruct->pOne_norm_data[0]->at : NULL;
|
811
|
+
/* atom number in structure that produced original InChI is atom number in all inp_ATOM *atoms */
|
812
|
+
/* atom number in structure that produced restored InChI is in nAtomRevrs[]: */
|
813
|
+
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
|
814
|
+
AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
|
815
|
+
S_CHAR *pnMobHInChI = (pInChI[0] && pInChI[0]->nNum_H)? pInChI[0]->nNum_H : NULL;
|
816
|
+
S_CHAR *pnMobHRevrs = (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
|
817
|
+
pStruct->pOneINChI[0]->nNum_H : NULL;
|
818
|
+
int nNumTgHInChI, nNumTgMInChI, nNumTgHRevrs, nNumTgMRevrs;
|
819
|
+
memset( pc2i, 0, sizeof(*pc2i) );
|
820
|
+
pc2i->nNumTgInChI = pStruct->ti.num_t_groups;
|
821
|
+
pc2i->nNumTgRevrs = pStruct->One_ti.num_t_groups;
|
822
|
+
pc2i->bHasDifference |= pc2i->nNumTgInChI != pc2i->nNumTgRevrs;
|
823
|
+
|
824
|
+
pc2i->nNumRemHInChI = pStruct->nNumRemovedProtonsMobHInChI;
|
825
|
+
pc2i->nNumRemHRevrs = pStruct->One_ti.tni.nNumRemovedProtons;
|
826
|
+
/*pc2i->bHasDifference |= pc2i->nNumRemHInChI != pc2i->nNumRemHRevrs;*/
|
827
|
+
|
828
|
+
pc2i->bFixedHLayerExistsRevrs = bFixHRevrsExists;
|
829
|
+
/*pc2i->bHasDifference |= !bFixHRevrsExists;*/
|
830
|
+
|
831
|
+
for ( i = 0; i < pStruct->ti.num_t_groups; i ++ ) {
|
832
|
+
int jFst = pStruct->ti.t_group[i].nFirstEndpointAtNoPos;
|
833
|
+
int jNum = pStruct->ti.t_group[i].nNumEndpoints;
|
834
|
+
int is_N, is_O;
|
835
|
+
for ( j = 0; j < jNum; j ++ ) {
|
836
|
+
iat = pStruct->ti.nEndpointAtomNumber[jFst + j];
|
837
|
+
is_N = pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1;
|
838
|
+
is_O = pVA[iat].cNumValenceElectrons == 6;
|
839
|
+
if ( is_N + is_O != 1 ) {
|
840
|
+
return RI_ERR_SYNTAX;
|
841
|
+
}
|
842
|
+
pc2i->nNumTgNInChI += is_N;
|
843
|
+
pc2i->nNumTgOInChI += is_O;
|
844
|
+
if ( at2[iat].chem_bonds_valence == at2[iat].valence ) {
|
845
|
+
/* donor */
|
846
|
+
if ( is_N ) {
|
847
|
+
/* N */
|
848
|
+
pc2i->nNumTgNHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
849
|
+
pc2i->nNumTgNH2InChI += at2[iat].charge == 0 && at2[iat].num_H == 2;
|
850
|
+
pc2i->nNumTgNMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
851
|
+
pc2i->nNumTgNHMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 1;
|
852
|
+
} else {
|
853
|
+
/* O, S, Se, Te */
|
854
|
+
pc2i->nNumTgOHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
855
|
+
pc2i->nNumTgOMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
856
|
+
}
|
857
|
+
} else
|
858
|
+
if ( at2[iat].chem_bonds_valence == at2[iat].valence+1 ) {
|
859
|
+
/* donor */
|
860
|
+
if ( is_N ) {
|
861
|
+
/* N */
|
862
|
+
pc2i->nNumTgDBNHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
863
|
+
pc2i->nNumTgDBNMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
864
|
+
pc2i->nNumTgDBNInChI += at2[iat].charge == 0 && at2[iat].num_H == 0;
|
865
|
+
} else {
|
866
|
+
/* O, S, Se, Te */
|
867
|
+
pc2i->nNumTgDBOInChI += at2[iat].charge == 0 && at2[iat].num_H == 0;
|
868
|
+
}
|
869
|
+
}
|
870
|
+
}
|
871
|
+
}
|
872
|
+
for ( i = 0; i < pStruct->One_ti.num_t_groups; i ++ ) {
|
873
|
+
int jFst = pStruct->One_ti.t_group[i].nFirstEndpointAtNoPos;
|
874
|
+
int jNum = pStruct->One_ti.t_group[i].nNumEndpoints;
|
875
|
+
int is_N, is_O;
|
876
|
+
for ( j = 0; j < jNum; j ++ ) {
|
877
|
+
iat = nCanon2AtnoRevrs[(int)pStruct->One_ti.nEndpointAtomNumber[jFst + j]];
|
878
|
+
is_N = pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1;
|
879
|
+
is_O = pVA[iat].cNumValenceElectrons == 6;
|
880
|
+
if ( is_N + is_O != 1 ) {
|
881
|
+
return RI_ERR_PROGR;
|
882
|
+
}
|
883
|
+
pc2i->nNumTgNRevrs += is_N;
|
884
|
+
pc2i->nNumTgORevrs += is_O;
|
885
|
+
if ( at2[iat].chem_bonds_valence == at2[iat].valence ) {
|
886
|
+
/* donor */
|
887
|
+
if ( is_N ) {
|
888
|
+
/* N */
|
889
|
+
pc2i->nNumTgNHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
890
|
+
pc2i->nNumTgNH2Revrs += at2[iat].charge == 0 && at2[iat].num_H == 2;
|
891
|
+
pc2i->nNumTgNMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
892
|
+
pc2i->nNumTgNHMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 1;
|
893
|
+
} else {
|
894
|
+
/* O, S, Se, Te */
|
895
|
+
pc2i->nNumTgOHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
896
|
+
pc2i->nNumTgOMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
897
|
+
}
|
898
|
+
} else
|
899
|
+
if ( at2[iat].chem_bonds_valence == at2[iat].valence+1 ) {
|
900
|
+
/* donor */
|
901
|
+
if ( is_N ) {
|
902
|
+
/* N */
|
903
|
+
pc2i->nNumTgDBNHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
|
904
|
+
pc2i->nNumTgDBNMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
|
905
|
+
pc2i->nNumTgDBNRevrs += at2[iat].charge == 0 && at2[iat].num_H == 0;
|
906
|
+
} else {
|
907
|
+
/* O, S, Se, Te */
|
908
|
+
pc2i->nNumTgDBORevrs += at2[iat].charge == 0 && at2[iat].num_H == 0;
|
909
|
+
}
|
910
|
+
}
|
911
|
+
}
|
912
|
+
}
|
913
|
+
|
914
|
+
for ( i = 0; i < pStruct->ti.num_t_groups && i < pStruct->One_ti.num_t_groups; i ++ ) {
|
915
|
+
nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
|
916
|
+
nNumTgMInChI = pStruct->ti.t_group[i].num[1];
|
917
|
+
nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
|
918
|
+
nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
|
919
|
+
|
920
|
+
pc2i->bHasDifference |= nNumTgHInChI != nNumTgHRevrs;
|
921
|
+
pc2i->bHasDifference |= nNumTgMInChI != nNumTgMRevrs;
|
922
|
+
|
923
|
+
if ( pStruct->ti.t_group[i].nNumEndpoints ==
|
924
|
+
pStruct->One_ti.t_group[i].nNumEndpoints ) {
|
925
|
+
|
926
|
+
if ( nNumTgHInChI != nNumTgHRevrs ) {
|
927
|
+
pc2i->nNumTgDiffH ++;
|
928
|
+
}
|
929
|
+
if ( nNumTgMInChI != nNumTgMRevrs ) {
|
930
|
+
pc2i->nNumTgDiffMinus ++;
|
931
|
+
}
|
932
|
+
}
|
933
|
+
pc2i->bHasDifference |= pStruct->ti.t_group[i].nNumEndpoints !=
|
934
|
+
pStruct->One_ti.t_group[i].nNumEndpoints;
|
935
|
+
|
936
|
+
pc2i->nNumTgHInChI += nNumTgHInChI;
|
937
|
+
pc2i->nNumTgMInChI += nNumTgMInChI;
|
938
|
+
pc2i->nNumTgHRevrs += nNumTgHRevrs;
|
939
|
+
pc2i->nNumTgMRevrs += nNumTgMRevrs;
|
940
|
+
|
941
|
+
}
|
942
|
+
for ( ; i < pStruct->ti.num_t_groups; i ++ ) {
|
943
|
+
nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
|
944
|
+
nNumTgMInChI = pStruct->ti.t_group[i].num[1];
|
945
|
+
pc2i->nNumTgHInChI += nNumTgHInChI;
|
946
|
+
pc2i->nNumTgMInChI += nNumTgMInChI;
|
947
|
+
pc2i->bHasDifference |= 1;
|
948
|
+
}
|
949
|
+
for ( ; i < pStruct->One_ti.num_t_groups; i ++ ) {
|
950
|
+
nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
|
951
|
+
nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
|
952
|
+
pc2i->nNumTgHRevrs += nNumTgHRevrs;
|
953
|
+
pc2i->nNumTgMRevrs += nNumTgMRevrs;
|
954
|
+
pc2i->bHasDifference |= 1;
|
955
|
+
|
956
|
+
}
|
957
|
+
for ( i = j = 0; i < pStruct->num_atoms; i ++ ) {
|
958
|
+
/* i = original InChI canonical number - 1 */
|
959
|
+
/* k = atom number from InChI created out of restored Fixed-H structure */
|
960
|
+
int iCanonRevrs = nAtno2CanonRevrs[i];
|
961
|
+
int endptInChI = at2[i].endpoint; /* endpoint in InChI */
|
962
|
+
int endptRevrs = at_Mobile_H_Revrs? at_Mobile_H_Revrs[i].endpoint : 0;
|
963
|
+
int nMobHInChI = pnMobHInChI? pnMobHInChI[i]:0;
|
964
|
+
int nMobHRevrs = pnMobHRevrs? pnMobHRevrs[iCanonRevrs]:0;
|
965
|
+
if ( (!endptInChI != !endptRevrs) || nMobHInChI != nMobHRevrs ) {
|
966
|
+
/* in InChI or reversed InChI atom[i] is not tautomeric */
|
967
|
+
/* and number of fixed-H on the atom[i] differs */
|
968
|
+
if ( j >= MAX_DIFF_FIXH ) {
|
969
|
+
ret = RI_ERR_PROGR;
|
970
|
+
goto exit_function;
|
971
|
+
}
|
972
|
+
pc2i->c2at[j].endptInChI = endptInChI;
|
973
|
+
pc2i->c2at[j].endptRevrs = endptRevrs;
|
974
|
+
pc2i->bHasDifference |= !endptInChI != !endptRevrs;
|
975
|
+
pc2i->c2at[j].atomNumber = i;
|
976
|
+
pc2i->c2at[j].nValElectr = pVA[i].cNumValenceElectrons;
|
977
|
+
pc2i->c2at[j].nPeriodNum = pVA[i].cPeriodicRowNumber;
|
978
|
+
pc2i->c2at[j].nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H[i] :
|
979
|
+
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H[i] : 0;
|
980
|
+
pc2i->c2at[j].nMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
|
981
|
+
pStruct->pOneINChI[1]->nNum_H[iCanonRevrs] :
|
982
|
+
(pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
|
983
|
+
pStruct->pOneINChI[0]->nNum_H[iCanonRevrs] : 0;
|
984
|
+
|
985
|
+
pc2i->nNumDiffMobH += (nMobHInChI != nMobHRevrs && !endptRevrs && !endptInChI);
|
986
|
+
pc2i->bHasDifference |= (nMobHInChI != nMobHRevrs);
|
987
|
+
pc2i->c2at[j].nNumHRevrs = at2[i].num_H;
|
988
|
+
pc2i->c2at[j].nAtChargeRevrs = at2[i].charge;
|
989
|
+
j ++;
|
990
|
+
}
|
991
|
+
pc2i->nNumEndpInChI += (endptInChI != 0);
|
992
|
+
pc2i->nNumEndpRevrs += (endptRevrs != 0);
|
993
|
+
|
994
|
+
if ( !pVA[i].cMetal ) {
|
995
|
+
pc2i->nChargeMobHRevrsNonMetal += (at_Mobile_H_Revrs && !at_Mobile_H_Revrs[i].endpoint)? at_Mobile_H_Revrs[i].charge : 0;
|
996
|
+
}
|
997
|
+
|
998
|
+
|
999
|
+
/*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
|
1000
|
+
}
|
1001
|
+
pc2i->nChargeMobHRevrsNonMetal += pTCGroups->tgroup_charge;
|
1002
|
+
|
1003
|
+
pc2i->nChargeMobHInChI = pInChI[0]? pInChI[0]->nTotalCharge : 0;
|
1004
|
+
|
1005
|
+
pc2i->nChargeMobHRevrs = pStruct->pOneINChI[0]? pStruct->pOneINChI[0]->nTotalCharge : 0;
|
1006
|
+
|
1007
|
+
pc2i->bHasDifference |= pc2i->nChargeMobHInChI != pc2i->nChargeMobHRevrs;
|
1008
|
+
|
1009
|
+
exit_function:
|
1010
|
+
pc2i->len_c2at = j;
|
1011
|
+
|
1012
|
+
return ret;
|
1013
|
+
}
|
1014
|
+
/******************************************************************************************************/
|
1015
|
+
int NormalizeAndCompare(ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
|
1016
|
+
StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
|
1017
|
+
ALL_TC_GROUPS *pTCGroups, INChI *pInChI[], long num_inp, int bHasSomeFixedH,
|
1018
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
|
1019
|
+
{
|
1020
|
+
int i;
|
1021
|
+
int err;
|
1022
|
+
ICR icr, icr2;
|
1023
|
+
int num_norm_endpoints, num_endpoints, num_norm_t_groups, num_mobile, num_norm_mobile, ret = 0;
|
1024
|
+
#if( bRELEASE_VERSION == 0 )
|
1025
|
+
#ifndef INCHI_LIBRARY
|
1026
|
+
const char *szCurHdr = (ip->pSdfValue && ip->pSdfValue[0])? ip->pSdfValue : "???";
|
1027
|
+
int iComponent = pTCGroups->iComponent;
|
1028
|
+
#endif
|
1029
|
+
#endif
|
1030
|
+
T_GROUP_INFO *t_group_info = NULL;
|
1031
|
+
inp_ATOM *at_norm = NULL; /* normalized */
|
1032
|
+
inp_ATOM *at_prep = NULL; /* preprocessed */
|
1033
|
+
INCHI_MODE cmpInChI, cmpInChI2;
|
1034
|
+
int nDeltaPrev, nDeltaCur;
|
1035
|
+
int iOrigInChI, iRevrInChI;
|
1036
|
+
|
1037
|
+
|
1038
|
+
/***********************************************************/
|
1039
|
+
/* normalize and create one component InChI */
|
1040
|
+
/***********************************************************/
|
1041
|
+
ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
1042
|
+
&t_group_info, &at_norm, &at_prep );
|
1043
|
+
if ( ret < 0 ) {
|
1044
|
+
#if( bRELEASE_VERSION == 0 )
|
1045
|
+
#ifndef INCHI_LIBRARY
|
1046
|
+
fprintf( stdout, "\nERROR in MakeOneInchi-1: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
|
1047
|
+
szCurHdr? szCurHdr: "???", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F', ret);
|
1048
|
+
#endif
|
1049
|
+
#endif
|
1050
|
+
goto exit_function;
|
1051
|
+
}
|
1052
|
+
if ( pStruct->bMobileH == TAUT_NON ) {
|
1053
|
+
/* these indexes are used to compare Mobile-H InChI */
|
1054
|
+
iOrigInChI = (pInChI[1] && pInChI[1]->nNumberOfAtoms && !pInChI[1]->bDeleted)? 1 : 0;
|
1055
|
+
iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
|
1056
|
+
} else {
|
1057
|
+
iOrigInChI = 0;
|
1058
|
+
iRevrInChI = 0;
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
/************************************************************/
|
1062
|
+
/* compare */
|
1063
|
+
/************************************************************/
|
1064
|
+
if ( pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr( pStruct )) ) {
|
1065
|
+
goto exit_function;
|
1066
|
+
}
|
1067
|
+
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *a2*/, &icr, &err );
|
1068
|
+
if ( cmpInChI & IDIF_PROBLEM ) {
|
1069
|
+
ret = RI_ERR_PROGR; /* severe restore problem */
|
1070
|
+
goto exit_function;
|
1071
|
+
}
|
1072
|
+
if ( err ) {
|
1073
|
+
ret = RI_ERR_ALLOC;
|
1074
|
+
goto exit_function;
|
1075
|
+
}
|
1076
|
+
/********** InChI from restored structure has LESS hydrogen atoms ******************************/
|
1077
|
+
if ( (cmpInChI & IDIF_LESS_H) && at_prep && 0 < (nDeltaCur = icr.tot_num_H2 - icr.tot_num_H1) ) {
|
1078
|
+
do {
|
1079
|
+
ret = FixLessHydrogenInFormula( pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups,
|
1080
|
+
pnNumRunBNS, pnTotalDelta, forbidden_edge_mask );
|
1081
|
+
if ( ret < 0 ) {
|
1082
|
+
goto exit_function;
|
1083
|
+
}
|
1084
|
+
if ( ret ) {
|
1085
|
+
/* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
|
1086
|
+
ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
1087
|
+
&t_group_info, &at_norm, &at_prep );
|
1088
|
+
if ( ret < 0 ) {
|
1089
|
+
#if( bRELEASE_VERSION == 0 )
|
1090
|
+
#ifndef INCHI_LIBRARY
|
1091
|
+
fprintf( stdout, "\nERROR in MakeOneInchi-2: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
|
1092
|
+
szCurHdr? szCurHdr: "???", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F', ret);
|
1093
|
+
#endif
|
1094
|
+
#endif
|
1095
|
+
goto exit_function;
|
1096
|
+
}
|
1097
|
+
/* compare new InChI to the original InChI */
|
1098
|
+
if ( pStruct->bMobileH == TAUT_NON ) {
|
1099
|
+
iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
|
1100
|
+
} else {
|
1101
|
+
iRevrInChI = 0;
|
1102
|
+
}
|
1103
|
+
if ( pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr( pStruct )) ) {
|
1104
|
+
goto exit_function;
|
1105
|
+
}
|
1106
|
+
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err );
|
1107
|
+
nDeltaPrev = nDeltaCur;
|
1108
|
+
nDeltaCur = icr.tot_num_H2 - icr.tot_num_H1;
|
1109
|
+
} else {
|
1110
|
+
break;
|
1111
|
+
}
|
1112
|
+
} while( (cmpInChI & IDIF_LESS_H) && at_prep && nDeltaCur && nDeltaCur < nDeltaPrev );
|
1113
|
+
}
|
1114
|
+
/********** InChI from restored structure has MORE hydrogen atoms ******************************/
|
1115
|
+
if ( (cmpInChI & IDIF_MORE_H) && at_prep && 0 < (nDeltaCur = icr.tot_num_H1 - icr.tot_num_H2) ) {
|
1116
|
+
do {
|
1117
|
+
ret = FixMoreHydrogenInFormula( pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups,
|
1118
|
+
pnNumRunBNS, pnTotalDelta, forbidden_edge_mask );
|
1119
|
+
if ( ret < 0 ) {
|
1120
|
+
goto exit_function;
|
1121
|
+
}
|
1122
|
+
if ( ret ) {
|
1123
|
+
/* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
|
1124
|
+
ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
1125
|
+
&t_group_info, &at_norm, &at_prep );
|
1126
|
+
if ( ret < 0 ) {
|
1127
|
+
#if( bRELEASE_VERSION == 0 )
|
1128
|
+
#ifndef INCHI_LIBRARY
|
1129
|
+
fprintf( stdout, "\nERROR in MakeOneInchi-3: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
|
1130
|
+
szCurHdr? szCurHdr: "???", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F', ret);
|
1131
|
+
#endif
|
1132
|
+
#endif
|
1133
|
+
goto exit_function;
|
1134
|
+
}
|
1135
|
+
/* compare new InChI to the original InChI */
|
1136
|
+
if ( pStruct->bMobileH == TAUT_NON ) {
|
1137
|
+
iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
|
1138
|
+
} else {
|
1139
|
+
iRevrInChI = 0;
|
1140
|
+
}
|
1141
|
+
if ( pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr( pStruct )) ) {
|
1142
|
+
goto exit_function;
|
1143
|
+
}
|
1144
|
+
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err );
|
1145
|
+
nDeltaPrev = nDeltaCur;
|
1146
|
+
nDeltaCur = icr.tot_num_H1 - icr.tot_num_H2;
|
1147
|
+
} else {
|
1148
|
+
break;
|
1149
|
+
}
|
1150
|
+
} while( (cmpInChI & IDIF_MORE_H) && at_prep && nDeltaCur && nDeltaCur < nDeltaPrev );
|
1151
|
+
}
|
1152
|
+
/***************** Fix non-taut atoms normalized to tautomeric endpoints ***********************/
|
1153
|
+
if ( (cmpInChI & IDIF_EXTRA_TG_ENDP) && at_norm && 0 < (nDeltaCur = icr.num_endp_in1_only) ) {
|
1154
|
+
do {
|
1155
|
+
ret = FixRemoveExtraTautEndpoints( pBNS, pBD, pStruct, at, at2, at_prep, at_norm, pVA, pTCGroups, &icr,
|
1156
|
+
pnNumRunBNS, pnTotalDelta, forbidden_edge_mask );
|
1157
|
+
if ( ret < 0 ) {
|
1158
|
+
goto exit_function;
|
1159
|
+
}
|
1160
|
+
if ( ret ) {
|
1161
|
+
/* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
|
1162
|
+
ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
|
1163
|
+
&t_group_info, &at_norm, &at_prep );
|
1164
|
+
if ( ret < 0 ) {
|
1165
|
+
#if( bRELEASE_VERSION == 0 )
|
1166
|
+
#ifndef INCHI_LIBRARY
|
1167
|
+
fprintf( stdout, "\nERROR in MakeOneInchi-4: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
|
1168
|
+
szCurHdr? szCurHdr: "???", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F', ret);
|
1169
|
+
#endif
|
1170
|
+
#endif
|
1171
|
+
goto exit_function;
|
1172
|
+
}
|
1173
|
+
/* compare new InChI to the original InChI */
|
1174
|
+
if ( pStruct->bMobileH == TAUT_NON ) {
|
1175
|
+
iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
|
1176
|
+
} else {
|
1177
|
+
iRevrInChI = 0;
|
1178
|
+
}
|
1179
|
+
if ( pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr( pStruct )) ) {
|
1180
|
+
goto exit_function;
|
1181
|
+
}
|
1182
|
+
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err );
|
1183
|
+
nDeltaPrev = nDeltaCur;
|
1184
|
+
nDeltaCur = icr.num_endp_in1_only;
|
1185
|
+
} else {
|
1186
|
+
break;
|
1187
|
+
}
|
1188
|
+
} while( (cmpInChI & IDIF_EXTRA_TG_ENDP) && at_norm && nDeltaCur && nDeltaCur < nDeltaPrev );
|
1189
|
+
}
|
1190
|
+
/************************ case of Fixed-H ******************************************************/
|
1191
|
+
|
1192
|
+
if ( pStruct->bMobileH == TAUT_NON ) {
|
1193
|
+
int num_tries = 0;
|
1194
|
+
do {
|
1195
|
+
if ( 0 > (ret = FixFixedHRestoredStructure(ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
|
1196
|
+
&t_group_info, &at_norm, &at_prep, pInChI,
|
1197
|
+
num_inp, bHasSomeFixedH, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
|
1198
|
+
forbidden_stereo_edge_mask) ) ) {
|
1199
|
+
goto exit_function;
|
1200
|
+
}
|
1201
|
+
} while( num_tries ++ < 2 && ret > 0 );
|
1202
|
+
}
|
1203
|
+
/************************ case of Fixed-H ******************************************************/
|
1204
|
+
if ( pStruct->bMobileH == TAUT_YES ) {
|
1205
|
+
if ( 0 > (ret = FixMobileHRestoredStructure(ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
|
1206
|
+
&t_group_info, &at_norm, &at_prep, pInChI,
|
1207
|
+
num_inp, bHasSomeFixedH, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
|
1208
|
+
forbidden_stereo_edge_mask) ) ) {
|
1209
|
+
goto exit_function;
|
1210
|
+
}
|
1211
|
+
}
|
1212
|
+
/**********************************************************************************************/
|
1213
|
+
/* stereo */
|
1214
|
+
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *a2*/, &icr, &err );
|
1215
|
+
if ( cmpInChI & IDIF_PROBLEM ) {
|
1216
|
+
ret = RI_ERR_PROGR; /* severe restore problem */
|
1217
|
+
goto exit_function;
|
1218
|
+
}
|
1219
|
+
if ( err ) {
|
1220
|
+
ret = RI_ERR_ALLOC;
|
1221
|
+
goto exit_function;
|
1222
|
+
}
|
1223
|
+
cmpInChI2 = 0;
|
1224
|
+
memset ( &icr2, 0, sizeof(icr2) );
|
1225
|
+
if ( iRevrInChI || iOrigInChI ) {
|
1226
|
+
/* additional mobile-H compare in case of Fixed-H */
|
1227
|
+
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *a2*/, &icr2, &err );
|
1228
|
+
if ( cmpInChI & IDIF_PROBLEM ) {
|
1229
|
+
ret = RI_ERR_PROGR; /* severe restore problem */
|
1230
|
+
goto exit_function;
|
1231
|
+
}
|
1232
|
+
if ( err ) {
|
1233
|
+
ret = RI_ERR_ALLOC;
|
1234
|
+
goto exit_function;
|
1235
|
+
}
|
1236
|
+
}
|
1237
|
+
ret = FixRestoredStructureStereo( cmpInChI, &icr, cmpInChI2, &icr2,
|
1238
|
+
ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
|
1239
|
+
&t_group_info, &at_norm, &at_prep, pInChI,
|
1240
|
+
num_inp, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
|
1241
|
+
forbidden_stereo_edge_mask);
|
1242
|
+
|
1243
|
+
if ( ret < 0 ) {
|
1244
|
+
goto exit_function;
|
1245
|
+
}
|
1246
|
+
#if( FIX_ADD_PROTON_FOR_ADP == 1 )
|
1247
|
+
/************************ check and fix ADP by adding a proton (dummy) *************************/
|
1248
|
+
if ( cmpInChI && pTCGroups->num_tgroups && pBNS->tot_st_cap > pBNS->tot_st_flow ) {
|
1249
|
+
ret = FixAddProtonForADP( pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups, &icr,
|
1250
|
+
pnNumRunBNS, pnTotalDelta, forbidden_edge_mask );
|
1251
|
+
if ( ret < 0 ) {
|
1252
|
+
goto exit_function;
|
1253
|
+
}
|
1254
|
+
}
|
1255
|
+
#endif
|
1256
|
+
/* moved to MakeOneInChIOutOfStrFromINChI():
|
1257
|
+
pStruct->nNumRemovedProtons = (pStruct->iMobileH == TAUT_YES)? pStruct->One_ti.tni.nNumRemovedProtons : 0;
|
1258
|
+
*/
|
1259
|
+
|
1260
|
+
/* count endpoints */
|
1261
|
+
num_endpoints = 0;
|
1262
|
+
num_norm_endpoints = 0;
|
1263
|
+
num_norm_t_groups = 0;
|
1264
|
+
num_mobile = 0;
|
1265
|
+
num_norm_mobile = 0;
|
1266
|
+
at_norm = pStruct->pOne_norm_data[0]->at;
|
1267
|
+
for ( i = 0; i < pTCGroups->num_tgroups; i ++ ) {
|
1268
|
+
num_endpoints += pTCGroups->pTCG[i].num_edges;
|
1269
|
+
num_mobile += pTCGroups->pTCG[i].tg_num_H + pTCGroups->pTCG[i].tg_num_Minus;
|
1270
|
+
}
|
1271
|
+
|
1272
|
+
if ( t_group_info ) {
|
1273
|
+
/* after canonicalization, t_group_info->t_group[i].num[0] = number of H */
|
1274
|
+
/* t_group_info->t_group[i].num[1] = number of (-) */
|
1275
|
+
for ( i = 0; i < t_group_info->num_t_groups; i ++ ) {
|
1276
|
+
if ( t_group_info->t_group[i].num[0] ) {
|
1277
|
+
num_norm_t_groups ++;
|
1278
|
+
num_norm_endpoints += t_group_info->t_group[i].nNumEndpoints;
|
1279
|
+
num_norm_mobile += t_group_info->t_group[i].num[0]+t_group_info->t_group[i].num[1];
|
1280
|
+
}
|
1281
|
+
}
|
1282
|
+
}
|
1283
|
+
#if( bRELEASE_VERSION == 0 )
|
1284
|
+
#ifndef INCHI_LIBRARY
|
1285
|
+
if ( num_norm_t_groups != pTCGroups->num_tgroups || num_norm_endpoints != num_endpoints ) {
|
1286
|
+
/* need aggressive (de)protonation */
|
1287
|
+
/* pStruct->bExtract |= EXTRACT_STRUCT_NUMBER; */
|
1288
|
+
fprintf( stdout, "NORMCOMP: %s comp=%d %c%c: InChI/NormRvrs NumTg=%d/%d NumEndp=%d/%d\n",
|
1289
|
+
(*ip).pSdfValue, (*pTCGroups).iComponent,
|
1290
|
+
pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F',
|
1291
|
+
pTCGroups->num_tgroups, num_norm_t_groups,
|
1292
|
+
num_endpoints, num_norm_endpoints );
|
1293
|
+
|
1294
|
+
}
|
1295
|
+
#endif
|
1296
|
+
#endif
|
1297
|
+
|
1298
|
+
exit_function:
|
1299
|
+
|
1300
|
+
for( i = 0; i < TAUT_NUM; i ++ ) {
|
1301
|
+
Free_INChI( &pStruct->pOneINChI[i] );
|
1302
|
+
Free_INChI_Aux( &pStruct->pOneINChI_Aux[i] );
|
1303
|
+
FreeInpAtomData( pStruct->pOne_norm_data[i] );
|
1304
|
+
if ( pStruct->pOne_norm_data[i] ) {
|
1305
|
+
inchi_free( pStruct->pOne_norm_data[i] );
|
1306
|
+
pStruct->pOne_norm_data[i] = NULL;
|
1307
|
+
}
|
1308
|
+
}
|
1309
|
+
free_t_group_info( &pStruct->One_ti );
|
1310
|
+
return ret;
|
1311
|
+
}
|
1312
|
+
/******************************************************************************************************/
|
1313
|
+
/* Find A=X< where all bonds to X except A=X are marked as stereogenic; temporary allow stereobonds */
|
1314
|
+
/* change and make A=X bonds single */
|
1315
|
+
int CheckAndRefixStereobonds(BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct,
|
1316
|
+
inp_ATOM *at, inp_ATOM *at2, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
1317
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask)
|
1318
|
+
{
|
1319
|
+
int forbidden_edge_stereo = BNS_EDGE_FORBIDDEN_MASK;
|
1320
|
+
int inv_forbidden_edge_stereo = ~forbidden_edge_stereo;
|
1321
|
+
|
1322
|
+
int i, k, ne, j1, j2, num_wrong, num_fixed;
|
1323
|
+
int ret2, retBNS, ret;
|
1324
|
+
int num_at = pStruct->num_atoms;
|
1325
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
1326
|
+
int len_at = num_at + num_deleted_H;
|
1327
|
+
EDGE_LIST FixedEdges, WrongEdges, CarbonChargeEdges;
|
1328
|
+
|
1329
|
+
BNS_EDGE *pEdge;
|
1330
|
+
Vertex v1, v2;
|
1331
|
+
BNS_VERTEX *pv1, *pv2;
|
1332
|
+
|
1333
|
+
ret = 0;
|
1334
|
+
|
1335
|
+
/* to simplify, prepare new at[] from pBNS */
|
1336
|
+
memcpy( at2, at, len_at*sizeof(at2[0]));
|
1337
|
+
pStruct->at = at2;
|
1338
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
1339
|
+
pStruct->at = at;
|
1340
|
+
if ( ret2 < 0 ) {
|
1341
|
+
return ret;
|
1342
|
+
}
|
1343
|
+
|
1344
|
+
num_wrong = 0;
|
1345
|
+
/* find wrong double bonds */
|
1346
|
+
for ( i = 0; i < num_at; i ++ ) {
|
1347
|
+
if ( at2[i].valence == 3 &&
|
1348
|
+
at2[i].chem_bonds_valence - at2[i].valence == 1 &&
|
1349
|
+
at2[i].sb_parity[0] && at2[i].sb_parity[1] && !at2[i].sb_parity[2] &&
|
1350
|
+
(at2[i].bond_type[j1=(int)at2[i].sb_ord[0]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
|
1351
|
+
(at2[i].bond_type[j2=(int)at2[i].sb_ord[1]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
|
1352
|
+
j1 != j2 ) {
|
1353
|
+
|
1354
|
+
num_wrong ++;
|
1355
|
+
}
|
1356
|
+
}
|
1357
|
+
if ( !num_wrong ) {
|
1358
|
+
return 0;
|
1359
|
+
}
|
1360
|
+
num_fixed = 0;
|
1361
|
+
for ( i = 0; i < pBNS->num_bonds; i ++ ) {
|
1362
|
+
pEdge = pBNS->edge + i;
|
1363
|
+
if ( pEdge->forbidden & forbidden_edge_stereo ) {
|
1364
|
+
num_fixed ++;
|
1365
|
+
}
|
1366
|
+
}
|
1367
|
+
|
1368
|
+
/* there may be no fixed stereo bonds at all, see #87607 */
|
1369
|
+
AllocEdgeList( &CarbonChargeEdges, EDGE_LIST_CLEAR );
|
1370
|
+
AllocEdgeList( &FixedEdges, EDGE_LIST_CLEAR );
|
1371
|
+
AllocEdgeList( &WrongEdges, EDGE_LIST_CLEAR );
|
1372
|
+
|
1373
|
+
/* do not goto exit_function before reaching this point: EdgeLists have not been initiated */
|
1374
|
+
|
1375
|
+
if ( 0 > (ret = ForbidCarbonChargeEdges( pBNS, pTCGroups, &CarbonChargeEdges, forbidden_edge_mask ))) {
|
1376
|
+
goto exit_function;
|
1377
|
+
}
|
1378
|
+
if ( (ret = AllocEdgeList( &FixedEdges, num_fixed )) ||
|
1379
|
+
(ret = AllocEdgeList( &WrongEdges, num_wrong )) ) {
|
1380
|
+
goto exit_function;
|
1381
|
+
}
|
1382
|
+
/* collect wrong double bonds and set flow=0 */
|
1383
|
+
for ( i = 0; i < num_at && WrongEdges.num_edges < num_wrong; i ++ ) {
|
1384
|
+
if ( at2[i].valence == 3 &&
|
1385
|
+
at2[i].chem_bonds_valence - at2[i].valence == 1 &&
|
1386
|
+
at2[i].sb_parity[0] && at2[i].sb_parity[1] && !at2[i].sb_parity[2] &&
|
1387
|
+
(at2[i].bond_type[j1=(int)at2[i].sb_ord[0]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
|
1388
|
+
(at2[i].bond_type[j2=(int)at2[i].sb_ord[1]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
|
1389
|
+
j1 != j2 ) {
|
1390
|
+
switch ( j1 + j2 ) {
|
1391
|
+
case 1: /* 0, 1 */
|
1392
|
+
k = 2;
|
1393
|
+
break;
|
1394
|
+
case 2: /* 0, 2 */
|
1395
|
+
k = 1;
|
1396
|
+
break;
|
1397
|
+
case 3: /* 1, 2 */
|
1398
|
+
k = 0;
|
1399
|
+
break;
|
1400
|
+
default:
|
1401
|
+
ret = RI_ERR_PROGR;
|
1402
|
+
goto exit_function;
|
1403
|
+
}
|
1404
|
+
ne = pBNS->vert[i].iedge[k];
|
1405
|
+
pEdge = pBNS->edge + ne;
|
1406
|
+
v1 = pEdge->neighbor1;
|
1407
|
+
v2 = pEdge->neighbor12 ^ v1;
|
1408
|
+
pv1 = pBNS->vert + v1;
|
1409
|
+
pv2 = pBNS->vert + v2;
|
1410
|
+
|
1411
|
+
if ( !pEdge->flow ) {
|
1412
|
+
ret = RI_ERR_PROGR;
|
1413
|
+
goto exit_function;
|
1414
|
+
}
|
1415
|
+
pEdge->flow --;
|
1416
|
+
pEdge->forbidden |= forbidden_edge_mask;
|
1417
|
+
pv1->st_edge.flow --;
|
1418
|
+
pv2->st_edge.flow --;
|
1419
|
+
pBNS->tot_st_flow -= 2;
|
1420
|
+
if ( ret = AddToEdgeList( &WrongEdges, ne, 0 )) {
|
1421
|
+
goto exit_function;
|
1422
|
+
}
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
/* remove forbidden mark from stereo bonds (unfix stereo bonds) */
|
1426
|
+
for ( i = 0; i < pBNS->num_bonds && FixedEdges.num_edges < num_fixed; i ++ ) {
|
1427
|
+
pEdge = pBNS->edge + i;
|
1428
|
+
if ( pEdge->forbidden & forbidden_edge_stereo ) {
|
1429
|
+
pEdge->forbidden &= inv_forbidden_edge_stereo;
|
1430
|
+
FixedEdges.pnEdges[FixedEdges.num_edges ++] = i;
|
1431
|
+
}
|
1432
|
+
}
|
1433
|
+
/* Run BNS to move charges and rearrange bond orders */
|
1434
|
+
retBNS = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1435
|
+
(*pnNumRunBNS) ++;
|
1436
|
+
if ( retBNS < 0 ) {
|
1437
|
+
goto exit_function;
|
1438
|
+
} else
|
1439
|
+
if ( retBNS > 0 ) {
|
1440
|
+
*pnTotalDelta += retBNS;
|
1441
|
+
}
|
1442
|
+
/* remove forbidden_edge_mask and set forbidden_edge_stereo */
|
1443
|
+
RemoveForbiddenEdgeMask( pBNS, &WrongEdges, forbidden_edge_mask );
|
1444
|
+
/* allow carbon charges to change */
|
1445
|
+
RemoveForbiddenEdgeMask( pBNS, &CarbonChargeEdges, forbidden_edge_mask );
|
1446
|
+
/* fix previously unfixed stereo bonds */
|
1447
|
+
SetForbiddenEdgeMask( pBNS, &FixedEdges, forbidden_edge_stereo );
|
1448
|
+
/* Run BNS again in case not all edge flows are maximal */
|
1449
|
+
ret2 = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1450
|
+
(*pnNumRunBNS) ++;
|
1451
|
+
if ( ret2 < 0 ) {
|
1452
|
+
goto exit_function;
|
1453
|
+
} else
|
1454
|
+
if ( ret2 > 0 ) {
|
1455
|
+
*pnTotalDelta += retBNS;
|
1456
|
+
}
|
1457
|
+
ret = retBNS;
|
1458
|
+
|
1459
|
+
exit_function:
|
1460
|
+
|
1461
|
+
AllocEdgeList( &CarbonChargeEdges, EDGE_LIST_FREE );
|
1462
|
+
AllocEdgeList( &FixedEdges, EDGE_LIST_FREE );
|
1463
|
+
AllocEdgeList( &WrongEdges, EDGE_LIST_FREE );
|
1464
|
+
|
1465
|
+
return ret;
|
1466
|
+
}
|
1467
|
+
/******************************************************************************************************/
|
1468
|
+
/* Find and eliminate false Mobile-H groups: Cl(=O)3(-O(-)) => Cl(-)(=O)4 */
|
1469
|
+
int MoveChargeToRemoveCenerpoints(BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct,
|
1470
|
+
inp_ATOM *at, inp_ATOM *at2, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
1471
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask)
|
1472
|
+
{
|
1473
|
+
int i, j, neigh, num_endpoints, num_success;
|
1474
|
+
int num_donors, num_acceptors, bond_type, num_donors_O, num_acceptors_O, is_centerpoint_N, num_known_endpoints, num_wrong_neigh;
|
1475
|
+
int ret2, ret_forbid_edges, ret, delta;
|
1476
|
+
int num_at = pStruct->num_atoms;
|
1477
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
1478
|
+
int len_at = num_at + num_deleted_H;
|
1479
|
+
int forbidden_edge_test = BNS_EDGE_FORBIDDEN_TEST;
|
1480
|
+
int bPossiblyIgnore = pStruct->charge >= 0 && (!pTCGroups->num_tgroups || pStruct->iMobileH == TAUT_NON && pStruct->ti.num_t_groups);
|
1481
|
+
S_CHAR MobileChargeNeigh[MAXVAL], DoubleBondAcceptors[MAXVAL], DoubleBondNotONeigh[MAXVAL];
|
1482
|
+
int numMobileChargeNeigh, numDoubleBondAcceptors, numDoubleBondNotONeigh, numOtherDoubleBondOAcceptors=0;
|
1483
|
+
EDGE_LIST ChargeListAllExcept_DB_O;
|
1484
|
+
|
1485
|
+
|
1486
|
+
BNS_EDGE *pEdgeMinus, *pe;
|
1487
|
+
Vertex v1m, v2m;
|
1488
|
+
BNS_VERTEX *pv1m, *pv2m;
|
1489
|
+
ret = 0;
|
1490
|
+
num_success = 0;
|
1491
|
+
|
1492
|
+
/* count O(+)H, N(+)H */
|
1493
|
+
|
1494
|
+
/*
|
1495
|
+
if ( pStruct->charge >= 0 && (!pTCGroups->num_tgroups || pStruct->iMobileH == TAUT_NON && pStruct->ti.num_t_groups) ) {
|
1496
|
+
goto exit_function;
|
1497
|
+
}
|
1498
|
+
*/
|
1499
|
+
if ( ret = AllocEdgeList( &ChargeListAllExcept_DB_O, EDGE_LIST_CLEAR ) ) {
|
1500
|
+
goto exit_function;
|
1501
|
+
}
|
1502
|
+
|
1503
|
+
|
1504
|
+
/* to simplify, prepare new at[] from pBNS */
|
1505
|
+
memcpy( at2, at, len_at*sizeof(at2[0]));
|
1506
|
+
pStruct->at = at2;
|
1507
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
1508
|
+
pStruct->at = at;
|
1509
|
+
if ( ret2 < 0 ) {
|
1510
|
+
ret = ret2;
|
1511
|
+
goto exit_function;
|
1512
|
+
}
|
1513
|
+
#if( FIND_RING_SYSTEMS == 1 )
|
1514
|
+
ret2 = MarkRingSystemsInp( at2, num_at );
|
1515
|
+
if ( ret2 < 0 ) {
|
1516
|
+
ret = ret2;
|
1517
|
+
goto exit_function;
|
1518
|
+
}
|
1519
|
+
#endif
|
1520
|
+
/* mark bonds that cannot be tautomeric; do not forget to remove the marks later */
|
1521
|
+
ret_forbid_edges = SetForbiddenEdges( pBNS, at2, num_at, forbidden_edge_test );
|
1522
|
+
if ( ret_forbid_edges < 0 ) {
|
1523
|
+
ret = ret_forbid_edges;
|
1524
|
+
goto exit_function;
|
1525
|
+
}
|
1526
|
+
|
1527
|
+
for ( i = 0; i < num_at; i ++ ) {
|
1528
|
+
if ( pVA[i].cNumValenceElectrons != 4 && /* not C, Si, Ge */
|
1529
|
+
!(pVA[i].nTautGroupEdge || pStruct->iMobileH == TAUT_NON && pStruct->endpoint && pStruct->endpoint[i] ) &&
|
1530
|
+
!at2[i].num_H && !at2[i].charge && at2[i].valence >= 2 &&
|
1531
|
+
at2[i].valence < at2[i].chem_bonds_valence &&
|
1532
|
+
is_centerpoint_elem( at2[i].el_number ) ) {
|
1533
|
+
|
1534
|
+
is_centerpoint_N = (pVA[i].cNumValenceElectrons == 5 && (pVA[i].cPeriodicRowNumber == 1 || pVA[i].cMetal));
|
1535
|
+
/* look at the neighbors */
|
1536
|
+
numMobileChargeNeigh = numDoubleBondAcceptors = numDoubleBondNotONeigh = num_donors = num_acceptors = 0;
|
1537
|
+
num_donors_O = num_acceptors_O = 0;
|
1538
|
+
num_known_endpoints = num_wrong_neigh = 0;
|
1539
|
+
for ( j = 0, num_endpoints = 0; j < at2[i].valence; j ++ ) {
|
1540
|
+
neigh = at2[i].neighbor[j];
|
1541
|
+
if ( (at2[neigh].endpoint || pStruct->iMobileH == TAUT_NON && pStruct->endpoint && pStruct->endpoint[neigh]) || at2[neigh].charge > 0 ) {
|
1542
|
+
num_known_endpoints ++;
|
1543
|
+
continue;
|
1544
|
+
}
|
1545
|
+
if ( pBNS->edge[pBNS->vert[i].iedge[j]].forbidden & forbidden_edge_test ) {
|
1546
|
+
continue;
|
1547
|
+
}
|
1548
|
+
bond_type = at2[i].bond_type[j] & BOND_TYPE_MASK;
|
1549
|
+
if ( bond_type > BOND_TYPE_DOUBLE ) {
|
1550
|
+
num_wrong_neigh ++;
|
1551
|
+
continue;
|
1552
|
+
}
|
1553
|
+
if ( at2[neigh].num_H && bond_type == BOND_TYPE_SINGLE ) {
|
1554
|
+
break; /* not this case */
|
1555
|
+
}
|
1556
|
+
if ( at2[neigh].chem_bonds_valence - at2[neigh].charge
|
1557
|
+
!= get_endpoint_valence( at2[neigh].el_number ) ) {
|
1558
|
+
if ( bond_type == BOND_TYPE_DOUBLE && pVA[neigh].cNumValenceElectrons != 6 ) {
|
1559
|
+
DoubleBondNotONeigh[numDoubleBondNotONeigh ++] = j;
|
1560
|
+
}
|
1561
|
+
continue;
|
1562
|
+
}
|
1563
|
+
if ( at2[neigh].charge == -1 && bond_type == BOND_TYPE_SINGLE &&
|
1564
|
+
(pVA[neigh].nCMinusGroupEdge < 1 || pBNS->edge[pVA[neigh].nCMinusGroupEdge-1].flow != 1) ) {
|
1565
|
+
break;
|
1566
|
+
}
|
1567
|
+
switch( bond_type ) {
|
1568
|
+
case BOND_TYPE_SINGLE:
|
1569
|
+
if ( at2[neigh].charge != -1 || pVA[neigh].nCMinusGroupEdge <= 0 ) {
|
1570
|
+
num_wrong_neigh ++;
|
1571
|
+
continue;
|
1572
|
+
}
|
1573
|
+
num_donors ++;
|
1574
|
+
num_donors_O += (pVA[neigh].cNumValenceElectrons == 6 && pVA[neigh].cPeriodicRowNumber <= 4);
|
1575
|
+
MobileChargeNeigh[numMobileChargeNeigh ++] = j;
|
1576
|
+
break;
|
1577
|
+
case BOND_TYPE_DOUBLE:
|
1578
|
+
if ( at2[neigh].charge ) {
|
1579
|
+
num_wrong_neigh ++;
|
1580
|
+
continue;
|
1581
|
+
}
|
1582
|
+
DoubleBondAcceptors[numDoubleBondAcceptors ++] = j;
|
1583
|
+
num_acceptors ++;
|
1584
|
+
num_acceptors_O += (pVA[neigh].cNumValenceElectrons == 6 && pVA[neigh].cPeriodicRowNumber <= 4);
|
1585
|
+
}
|
1586
|
+
}
|
1587
|
+
if ( j != at2[i].valence || !num_donors || !num_acceptors ) {
|
1588
|
+
continue;
|
1589
|
+
}
|
1590
|
+
/* special case NOn(-) */
|
1591
|
+
if ( is_centerpoint_N && (num_donors == num_donors_O) && (num_acceptors == num_acceptors_O) ) {
|
1592
|
+
continue;
|
1593
|
+
}
|
1594
|
+
if ( pStruct->iMobileH == TAUT_NON && num_donors == numDoubleBondNotONeigh ) {
|
1595
|
+
/* fix all charges except on =O */
|
1596
|
+
Vertex vPathStart, vPathEnd;
|
1597
|
+
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
1598
|
+
int k, e, num_MovedCharges = 0;
|
1599
|
+
|
1600
|
+
if ( !ChargeListAllExcept_DB_O.num_edges ) {
|
1601
|
+
numOtherDoubleBondOAcceptors = 0;
|
1602
|
+
for ( k = 0; k < num_at; k ++ ) {
|
1603
|
+
if ( 1 == at2[k].valence && pBNS->edge[pBNS->vert[k].iedge[0]].flow &&
|
1604
|
+
!pBNS->edge[pBNS->vert[k].iedge[0]].forbidden &&
|
1605
|
+
!((e=pVA[k].nCMinusGroupEdge-1) >= 0 && pBNS->edge[e].flow) &&
|
1606
|
+
!((e=pVA[k].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].flow) &&
|
1607
|
+
/* 0 == at2[k].charge && */
|
1608
|
+
pVA[k].cNumValenceElectrons == 6 && !pVA[k].cMetal &&
|
1609
|
+
pStruct->endpoint && pStruct->endpoint[k] ||
|
1610
|
+
pStruct->fixed_H && pStruct->fixed_H[k] ) {
|
1611
|
+
numOtherDoubleBondOAcceptors ++; /* do not fix this minus edge */
|
1612
|
+
} else
|
1613
|
+
if ( (e=pVA[k].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].flow &&
|
1614
|
+
!pBNS->edge[e].forbidden &&
|
1615
|
+
( ret = AddToEdgeList( &ChargeListAllExcept_DB_O, e, 64 )) ) {
|
1616
|
+
goto exit_function;
|
1617
|
+
}
|
1618
|
+
if ( (e=pVA[k].nCPlusGroupEdge-1) >= 0 &&
|
1619
|
+
!pBNS->edge[e].forbidden &&
|
1620
|
+
( ret = AddToEdgeList( &ChargeListAllExcept_DB_O, e, 64 )) ) {
|
1621
|
+
goto exit_function;
|
1622
|
+
}
|
1623
|
+
}
|
1624
|
+
}
|
1625
|
+
/* fix double bonds to non-O neighbors connected by double bonds;
|
1626
|
+
we will try to make these bons single */
|
1627
|
+
for ( k = 0; k < numDoubleBondNotONeigh; k ++ ) {
|
1628
|
+
e = pBNS->vert[i].iedge[(int)DoubleBondNotONeigh[k]];
|
1629
|
+
if ( !pBNS->edge[e].forbidden &&
|
1630
|
+
(ret = AddToEdgeList( &ChargeListAllExcept_DB_O, e, 64 ))) {
|
1631
|
+
goto exit_function;
|
1632
|
+
}
|
1633
|
+
}
|
1634
|
+
/* attempt to make DoubleBondNotONeigh[] single */
|
1635
|
+
SetForbiddenEdgeMask( pBNS, &ChargeListAllExcept_DB_O, forbidden_edge_mask);
|
1636
|
+
for ( k = 0; k < numDoubleBondNotONeigh && num_MovedCharges < numMobileChargeNeigh; k ++ ) {
|
1637
|
+
pe = pBNS->edge + pBNS->vert[i].iedge[(int)DoubleBondNotONeigh[k]];
|
1638
|
+
delta = 1;
|
1639
|
+
if ( pe->flow != delta )
|
1640
|
+
continue;
|
1641
|
+
pv1m = pBNS->vert + (v1m = pe->neighbor1);
|
1642
|
+
pv2m = pBNS->vert + (v2m = pe->neighbor12 ^ v1m);
|
1643
|
+
pv1m->st_edge.flow -= delta;
|
1644
|
+
pv2m->st_edge.flow -= delta;
|
1645
|
+
pe->flow -= delta;
|
1646
|
+
pBNS->tot_st_flow -= 2*delta;
|
1647
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
1648
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
1649
|
+
if ( ret < 0 ) {
|
1650
|
+
goto exit_function;
|
1651
|
+
}
|
1652
|
+
if ( ret == 1 && (vPathEnd == v1m && vPathStart == v2m ||
|
1653
|
+
vPathEnd == v2m && vPathStart == v1m) &&
|
1654
|
+
nDeltaCharge == 0 /* (-) moving from one to another atom*/ ) {
|
1655
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1656
|
+
(*pnNumRunBNS) ++;
|
1657
|
+
if ( ret < 0 ) {
|
1658
|
+
goto exit_function;
|
1659
|
+
} else
|
1660
|
+
if ( ret == 1 ) {
|
1661
|
+
*pnTotalDelta += ret;
|
1662
|
+
num_MovedCharges ++;
|
1663
|
+
} else {
|
1664
|
+
ret = RI_ERR_PROGR;
|
1665
|
+
goto exit_function;
|
1666
|
+
}
|
1667
|
+
} else {
|
1668
|
+
ret = 0;
|
1669
|
+
pv1m->st_edge.flow += delta;
|
1670
|
+
pv2m->st_edge.flow += delta;
|
1671
|
+
pe->flow += delta;
|
1672
|
+
pBNS->tot_st_flow += 2*delta;
|
1673
|
+
}
|
1674
|
+
}
|
1675
|
+
RemoveForbiddenEdgeMask( pBNS, &ChargeListAllExcept_DB_O, forbidden_edge_mask);
|
1676
|
+
} else
|
1677
|
+
if ( !bPossiblyIgnore || !num_known_endpoints && !num_wrong_neigh && (num_acceptors_O + num_donors_O) >=3 ) {
|
1678
|
+
/* remove negative charges from the neighbors */
|
1679
|
+
pBNS->vert[i].st_edge.cap += num_donors; /* enough to make all bonds to donors double */
|
1680
|
+
pBNS->tot_st_cap += num_donors;
|
1681
|
+
pVA[i].cInitCharge -= num_donors; /* work no matter what are known charge/valence */
|
1682
|
+
for ( j = 0; j < numMobileChargeNeigh; j ++ ) {
|
1683
|
+
neigh = at2[i].neighbor[ (int)MobileChargeNeigh[j] ];
|
1684
|
+
pEdgeMinus = pBNS->edge + (pVA[neigh].nCMinusGroupEdge-1);
|
1685
|
+
v1m = pEdgeMinus->neighbor1;
|
1686
|
+
v2m = pEdgeMinus->neighbor12 ^ v1m;
|
1687
|
+
pv1m = pBNS->vert + v1m;
|
1688
|
+
pv2m = pBNS->vert + v2m;
|
1689
|
+
delta = pEdgeMinus->flow;
|
1690
|
+
pv1m->st_edge.flow -= delta;
|
1691
|
+
pv2m->st_edge.flow -= delta;
|
1692
|
+
if ( IS_BNS_VT_C_GR( pv1m->type ) ) {
|
1693
|
+
/* irreversible change to ChargeStruct */
|
1694
|
+
pv1m->st_edge.cap -= delta;
|
1695
|
+
} else
|
1696
|
+
if ( IS_BNS_VT_C_GR( pv2m->type ) ) {
|
1697
|
+
/* irreversible change to ChargeStruct */
|
1698
|
+
pv2m->st_edge.cap -= delta;
|
1699
|
+
} else {
|
1700
|
+
ret = RI_ERR_PROGR;
|
1701
|
+
goto exit_function;
|
1702
|
+
}
|
1703
|
+
pBNS->tot_st_cap -= delta;
|
1704
|
+
pBNS->tot_st_flow -= 2*delta;
|
1705
|
+
pEdgeMinus->flow -= delta;
|
1706
|
+
}
|
1707
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1708
|
+
(*pnNumRunBNS) ++;
|
1709
|
+
if ( ret < 0 ) {
|
1710
|
+
goto exit_function;
|
1711
|
+
} else
|
1712
|
+
if ( ret == num_donors ) {
|
1713
|
+
*pnTotalDelta += ret;
|
1714
|
+
num_success ++;
|
1715
|
+
/*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
|
1716
|
+
} else {
|
1717
|
+
ret = RI_ERR_PROGR;
|
1718
|
+
goto exit_function;
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
}
|
1723
|
+
if ( ret_forbid_edges ) {
|
1724
|
+
/* remove the marks */
|
1725
|
+
RemoveForbiddenBondFlowBits( pBNS, forbidden_edge_test );
|
1726
|
+
}
|
1727
|
+
ret = num_success;
|
1728
|
+
exit_function:
|
1729
|
+
AllocEdgeList( &ChargeListAllExcept_DB_O, EDGE_LIST_FREE );
|
1730
|
+
return ret;
|
1731
|
+
}
|
1732
|
+
/******************************************************************************************************/
|
1733
|
+
/* Find and eliminate cases when Mobile H endpoint has radical on it (typical for wrong P(VI)(=O)3OH */
|
1734
|
+
int MakeSingleBondsMetal2ChargedHeteroat(BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct,
|
1735
|
+
inp_ATOM *at, inp_ATOM *at2, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
1736
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask)
|
1737
|
+
{
|
1738
|
+
int i;
|
1739
|
+
|
1740
|
+
int ret2, ret, pass;
|
1741
|
+
int num_at = pStruct->num_atoms;
|
1742
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
1743
|
+
int len_at = num_at + num_deleted_H;
|
1744
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
1745
|
+
|
1746
|
+
int j, k;
|
1747
|
+
int cur_num_edges;
|
1748
|
+
BNS_EDGE *e;
|
1749
|
+
Vertex v1, v2;
|
1750
|
+
|
1751
|
+
EdgeIndex *pFixedEdges;
|
1752
|
+
int nNumEdgesToFix;
|
1753
|
+
|
1754
|
+
ret = 0;
|
1755
|
+
|
1756
|
+
/* to simplify, prepare new at[] from pBNS */
|
1757
|
+
memcpy( at2, at, len_at*sizeof(at2[0]));
|
1758
|
+
pStruct->at = at2;
|
1759
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
1760
|
+
pStruct->at = at;
|
1761
|
+
if ( ret2 < 0 ) {
|
1762
|
+
ret = ret2;
|
1763
|
+
goto exit_function;
|
1764
|
+
}
|
1765
|
+
|
1766
|
+
pFixedEdges = NULL;
|
1767
|
+
|
1768
|
+
nNumEdgesToFix = 0; /* cpunt nNumEdgesToFix only when pass==0 */
|
1769
|
+
cur_num_edges = 0; /* count cur_num_edges only when pass==1; at the end they must be equal */
|
1770
|
+
for ( pass = 0; pass < 2; pass ++ ) {
|
1771
|
+
if ( pass ) {
|
1772
|
+
/* 2nd pass: allocate edge storage */
|
1773
|
+
if ( !nNumEdgesToFix ) {
|
1774
|
+
break; /* nothing to do */
|
1775
|
+
}
|
1776
|
+
pFixedEdges = (EdgeIndex *)inchi_malloc(nNumEdgesToFix * sizeof( pFixedEdges[0] ) );
|
1777
|
+
if ( !pFixedEdges ) {
|
1778
|
+
ret = RI_ERR_ALLOC;
|
1779
|
+
goto exit_function;
|
1780
|
+
}
|
1781
|
+
}
|
1782
|
+
for ( i = 0; i < num_at; i ++ ) {
|
1783
|
+
int neigh;
|
1784
|
+
if ( pVA[i].cMetal ) {
|
1785
|
+
for ( j = 0; j < at2[i].valence; j ++ ) {
|
1786
|
+
neigh = at2[i].neighbor[j];
|
1787
|
+
if ( pVA[neigh].cNumValenceElectrons == 4 &&
|
1788
|
+
pVA[neigh].cPeriodicRowNumber == 1 ) {
|
1789
|
+
continue; /* ignore carbon */
|
1790
|
+
}
|
1791
|
+
if ( at2[i].bond_type[j] > BOND_TYPE_SINGLE && at2[neigh].charge &&
|
1792
|
+
!pVA[neigh].cMetal && pVA[neigh].cnListIndex > 0 ) {
|
1793
|
+
int cnBits = at2[neigh].charge > 0? MAKE_CN_BITS(cn_bits_N, cn_bits_P, 0, 0) :
|
1794
|
+
MAKE_CN_BITS(cn_bits_N, cn_bits_M, 0, 0);
|
1795
|
+
int atBits = cnList[pVA[neigh].cnListIndex-1].bits;
|
1796
|
+
for ( k = 0; k < MAX_NUM_CN_BITS-1; k ++, atBits >>= cn_bits_shift ) { /* ??? */
|
1797
|
+
if ( (atBits & cnBits) == cnBits ) {
|
1798
|
+
break;
|
1799
|
+
}
|
1800
|
+
}
|
1801
|
+
if ( k == MAX_NUM_CN_BITS-1 ) {
|
1802
|
+
continue;
|
1803
|
+
}
|
1804
|
+
if ( pass == 0 ) {
|
1805
|
+
nNumEdgesToFix ++;
|
1806
|
+
} else {
|
1807
|
+
pFixedEdges[ cur_num_edges ++ ] = pBNS->vert[i].iedge[j];
|
1808
|
+
}
|
1809
|
+
}
|
1810
|
+
}
|
1811
|
+
}
|
1812
|
+
}
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
/* restore the initial structures */
|
1816
|
+
memcpy( at2, at, (num_at + num_deleted_H)*sizeof(at2[0]));
|
1817
|
+
|
1818
|
+
if ( nNumEdgesToFix && pFixedEdges ) {
|
1819
|
+
if ( nNumEdgesToFix != cur_num_edges ) {
|
1820
|
+
ret = RI_ERR_PROGR;
|
1821
|
+
goto exit_function;
|
1822
|
+
}
|
1823
|
+
/* change edge flow, fix the edges, and run BNS */
|
1824
|
+
for ( i = 0; i < nNumEdgesToFix; i ++ ) {
|
1825
|
+
e = pBNS->edge + pFixedEdges[i];
|
1826
|
+
v1 = e->neighbor1;
|
1827
|
+
v2 = e->neighbor12 ^ v1;
|
1828
|
+
e->flow --;
|
1829
|
+
e->forbidden |= forbidden_edge_mask;
|
1830
|
+
pBNS->vert[v1].st_edge.flow --;
|
1831
|
+
pBNS->vert[v2].st_edge.flow --;
|
1832
|
+
pBNS->tot_st_flow -= 2;
|
1833
|
+
(*pnTotalDelta) -= 2;
|
1834
|
+
}
|
1835
|
+
/* Run BNS allowing to change any charges */
|
1836
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1837
|
+
(*pnNumRunBNS) ++;
|
1838
|
+
if ( ret < 0 ) {
|
1839
|
+
goto exit_function;
|
1840
|
+
} else {
|
1841
|
+
(*pnTotalDelta) += ret;
|
1842
|
+
}
|
1843
|
+
/* unfix the edges */
|
1844
|
+
for ( i = 0; i < nNumEdgesToFix; i ++ ) {
|
1845
|
+
e = pBNS->edge + pFixedEdges[i];
|
1846
|
+
e->forbidden &= inv_forbidden_edge_mask;
|
1847
|
+
}
|
1848
|
+
if ( ret < 2 * nNumEdgesToFix ) {
|
1849
|
+
/* not all fixes succeeded */
|
1850
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1851
|
+
(*pnNumRunBNS) ++;
|
1852
|
+
if ( ret < 0 ) {
|
1853
|
+
goto exit_function;
|
1854
|
+
} else {
|
1855
|
+
(*pnTotalDelta) += ret;
|
1856
|
+
}
|
1857
|
+
}
|
1858
|
+
}
|
1859
|
+
if ( pFixedEdges ) {
|
1860
|
+
inchi_free( pFixedEdges );
|
1861
|
+
pFixedEdges = NULL;
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
|
1865
|
+
exit_function:
|
1866
|
+
return ret;
|
1867
|
+
}
|
1868
|
+
/**************************************************************************/
|
1869
|
+
/* In Reconnected structure change 'salt bonds' to 'coordination bonds */
|
1870
|
+
/* for example, M-O-C= -> M(+)-O(-)-C= */
|
1871
|
+
/* Defect: instead of NH2-C=O(+)-M it will restore NH2(+)=C-O(-)-M(+) */
|
1872
|
+
/* However, in this release metal-organic compounds do not get much care */
|
1873
|
+
int SaltBondsToCoordBonds(BN_STRUCT *pBNS, BN_DATA *pBD, StrFromINChI *pStruct,
|
1874
|
+
inp_ATOM *at, inp_ATOM *at2, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups,
|
1875
|
+
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask)
|
1876
|
+
{
|
1877
|
+
int i;
|
1878
|
+
|
1879
|
+
int ret2, ret, cur_success;
|
1880
|
+
int num_at = pStruct->num_atoms;
|
1881
|
+
int num_edges = pBNS->num_bonds + 2 * pBNS->num_atoms;
|
1882
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
1883
|
+
int len_at = num_at + num_deleted_H;
|
1884
|
+
int inv_forbidden_edge_mask = ~forbidden_edge_mask;
|
1885
|
+
EDGE_LIST AllChargeEdges;
|
1886
|
+
|
1887
|
+
int j, k, n;
|
1888
|
+
BNS_EDGE *pe, *pePlusMetal, *peMinusO;
|
1889
|
+
BNS_VERTEX *pv1, *pv2, *pvO, *pvM;
|
1890
|
+
Vertex v1, v2, vPlusMinus;
|
1891
|
+
|
1892
|
+
EdgeIndex ie, iePlusMetal, ieMinusO;
|
1893
|
+
|
1894
|
+
Vertex vPathStart, vPathEnd;
|
1895
|
+
int delta, nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
|
1896
|
+
|
1897
|
+
ret = 0;
|
1898
|
+
cur_success = 0;
|
1899
|
+
AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
|
1900
|
+
|
1901
|
+
if ( pStruct->iInchiRec == INCHI_BAS || !pStruct->pSrm->bMetalAddFlower || pStruct->pSrm->nMetalMinBondOrder ) {
|
1902
|
+
goto exit_function;
|
1903
|
+
}
|
1904
|
+
|
1905
|
+
/* to simplify, prepare new at[] from pBNS */
|
1906
|
+
memcpy( at2, at, len_at*sizeof(at2[0]));
|
1907
|
+
pStruct->at = at2;
|
1908
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
1909
|
+
pStruct->at = at;
|
1910
|
+
if ( ret2 < 0 ) {
|
1911
|
+
ret = ret2;
|
1912
|
+
goto exit_function;
|
1913
|
+
}
|
1914
|
+
for ( i = 0; i < num_at; i ++ ) {
|
1915
|
+
if ( bIsMetalSalt( at2, i ) ) {
|
1916
|
+
if ( !AllChargeEdges.num_edges ) {
|
1917
|
+
/*--------- one-time action: fix all bonds, charges, taut. group edges ------------*/
|
1918
|
+
for ( j = 0; j < num_at; j ++ ) {
|
1919
|
+
/* all bonds */
|
1920
|
+
for ( k = 0; k < at2[j].valence; k ++ ) {
|
1921
|
+
n = at2[j].neighbor[k];
|
1922
|
+
if ( n < j && !pBNS->edge[ie = pBNS->vert[j].iedge[k]].forbidden &&
|
1923
|
+
( ret = AddToEdgeList( &AllChargeEdges, ie, num_edges ) ) ) {
|
1924
|
+
goto exit_function;
|
1925
|
+
}
|
1926
|
+
}
|
1927
|
+
/* charge edges */
|
1928
|
+
if ( (ie=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[ie].forbidden &&
|
1929
|
+
(ret = AddToEdgeList( &AllChargeEdges, ie, num_edges ) ) ) {
|
1930
|
+
goto exit_function;
|
1931
|
+
}
|
1932
|
+
if ( (ie=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[ie].forbidden &&
|
1933
|
+
( ret = AddToEdgeList( &AllChargeEdges, ie, num_edges ) ) ) {
|
1934
|
+
goto exit_function;
|
1935
|
+
}
|
1936
|
+
}
|
1937
|
+
/* taut group edges */
|
1938
|
+
for ( j = 0; j < pTCGroups->num_tgroups; j ++ ) {
|
1939
|
+
pv1 = pBNS->vert + (v1=pTCGroups->pTCG[j].nVertexNumber); /* t-group vertex */
|
1940
|
+
for ( k = 0; k < pv1->num_adj_edges; k ++ ) {
|
1941
|
+
/* ie, pe - tautomeric atom edge; pv2 - endpoint vertex */
|
1942
|
+
/* Note: pe, pv2, v1 are not used here; they are to show how to traverse t-group */
|
1943
|
+
pv2 = pBNS->vert + (pe = pBNS->edge + (ie=pv1->iedge[k]))->neighbor1;
|
1944
|
+
if ( ret = AddToEdgeList( &AllChargeEdges, ie, num_edges ) ) {
|
1945
|
+
goto exit_function;
|
1946
|
+
}
|
1947
|
+
}
|
1948
|
+
}
|
1949
|
+
/*---------------------------------------------------------------*/
|
1950
|
+
}
|
1951
|
+
/* replace all single bonds to neutral neighbors with zero-order bonds
|
1952
|
+
allow neighbor charge change to (-1) and metal atom charge increment +1 */
|
1953
|
+
for ( k = 0; k < at2[i].valence; k ++ ) {
|
1954
|
+
n = at2[i].neighbor[k];
|
1955
|
+
pe = pBNS->edge + pBNS->vert[i].iedge[k];
|
1956
|
+
if ( at2[n].charge || at2[i].bond_type[k] != BOND_TYPE_SINGLE ) {
|
1957
|
+
continue;
|
1958
|
+
}
|
1959
|
+
iePlusMetal = pVA[i].nCPlusGroupEdge-1;
|
1960
|
+
ieMinusO = pVA[n].nCMinusGroupEdge-1;
|
1961
|
+
|
1962
|
+
if ( pe->flow != 1 || pe->forbidden || iePlusMetal < 0 ) {
|
1963
|
+
continue;
|
1964
|
+
}
|
1965
|
+
pePlusMetal = pBNS->edge + iePlusMetal;
|
1966
|
+
if ( pePlusMetal->flow <= 0 ) {
|
1967
|
+
continue; /* to add (+) to metal this flow must be decremented */
|
1968
|
+
}
|
1969
|
+
if ( ieMinusO >= 0 ) {
|
1970
|
+
/* usually does not happen */
|
1971
|
+
peMinusO = pBNS->edge + ieMinusO;
|
1972
|
+
|
1973
|
+
if ( peMinusO->flow || pePlusMetal->forbidden || peMinusO->forbidden ) {
|
1974
|
+
continue;
|
1975
|
+
}
|
1976
|
+
|
1977
|
+
/* decrement bond order to 0 */
|
1978
|
+
delta = 1;
|
1979
|
+
pv1 = pBNS->vert + (v1 = pe->neighbor1);
|
1980
|
+
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
|
1981
|
+
|
1982
|
+
pe->flow -= delta;
|
1983
|
+
pv1->st_edge.flow -= delta;
|
1984
|
+
pv2->st_edge.flow -= delta;
|
1985
|
+
pBNS->tot_st_flow -= 2*delta;
|
1986
|
+
|
1987
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
1988
|
+
pePlusMetal->forbidden &= inv_forbidden_edge_mask;
|
1989
|
+
peMinusO->forbidden &= inv_forbidden_edge_mask;
|
1990
|
+
|
1991
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
1992
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
1993
|
+
|
1994
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
1995
|
+
vPathEnd == v2 && vPathStart == v1) /*&& nDeltaCharge > 0*/ ) {
|
1996
|
+
/* (+)charge was just moved, no change in number of charges */
|
1997
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
1998
|
+
if ( ret > 0 ) {
|
1999
|
+
(*pnNumRunBNS) ++;
|
2000
|
+
cur_success ++; /* 01 */
|
2001
|
+
}
|
2002
|
+
} else {
|
2003
|
+
pe->flow += delta; /* roll back */
|
2004
|
+
pv1->st_edge.flow += delta;
|
2005
|
+
pv2->st_edge.flow += delta;
|
2006
|
+
pBNS->tot_st_flow += 2*delta;
|
2007
|
+
}
|
2008
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
2009
|
+
} else
|
2010
|
+
if ( NO_VERTEX != (vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 1 ) ) ) {
|
2011
|
+
/* manually add (-) charge to O and (+) charge to metal */
|
2012
|
+
/* decrement bond order to 0 */
|
2013
|
+
/*---------------------------------------------------------------------------*/
|
2014
|
+
/* */
|
2015
|
+
/* (+/-)* (+/-) Result: */
|
2016
|
+
/* | || */
|
2017
|
+
/* | || - Added (+) to M */
|
2018
|
+
/* (+)super (+)super - Incremented bond M-O */
|
2019
|
+
/* || | */
|
2020
|
+
/* || => | To make this attachment H, */
|
2021
|
+
/* (Y) (Y) increment */
|
2022
|
+
/* | || pTCGroups->pTCG[itg].tg_num_H */
|
2023
|
+
/* | || */
|
2024
|
+
/* (+)metal (+)hetero Technical details: */
|
2025
|
+
/* \\ \ increase capacities of */
|
2026
|
+
/* M M(+) edges to (+/-) otherwise */
|
2027
|
+
/* | || flow may not be able to */
|
2028
|
+
/* -O* -O-O increase */
|
2029
|
+
/* */
|
2030
|
+
/* After that change M=O bond order from 2 to 0 */
|
2031
|
+
/*---------------------------------------------------------------------------*/
|
2032
|
+
int i1, j1, k1;
|
2033
|
+
delta = 1;
|
2034
|
+
pvO = pBNS->vert + n;
|
2035
|
+
pvM = pBNS->vert + i;
|
2036
|
+
/* Increment st_edge.cap on (+/-) vertex */
|
2037
|
+
pBNS->vert[vPlusMinus].st_edge.cap += delta;
|
2038
|
+
/* Increment st_edge.cap on O */
|
2039
|
+
pvO->st_edge.cap += delta;
|
2040
|
+
/* increment cap on M-O edge */
|
2041
|
+
pe->cap += delta;
|
2042
|
+
/* total cap count */
|
2043
|
+
pBNS->tot_st_cap += 2*delta;
|
2044
|
+
|
2045
|
+
v1 = vPlusMinus;
|
2046
|
+
v2 = n; /* atom O */
|
2047
|
+
|
2048
|
+
/* increase capacities of edges to Y */
|
2049
|
+
for ( i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1 ++ ) {
|
2050
|
+
j1 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
|
2051
|
+
for ( k1 = 0; k1 < pBNS->vert[j1].num_adj_edges; k1 ++ ) {
|
2052
|
+
pBNS->edge[pBNS->vert[j1].iedge[k1]].cap += delta;
|
2053
|
+
}
|
2054
|
+
}
|
2055
|
+
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
2056
|
+
pePlusMetal->forbidden &= inv_forbidden_edge_mask;
|
2057
|
+
pe->forbidden &= inv_forbidden_edge_mask;
|
2058
|
+
|
2059
|
+
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
|
2060
|
+
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
|
2061
|
+
cur_success = 0;
|
2062
|
+
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
|
2063
|
+
vPathEnd == v2 && vPathStart == v1) /*&& nDeltaCharge == 1*/ ) {
|
2064
|
+
/* Added (+)charge to -N< => nDeltaCharge == 1 */
|
2065
|
+
/* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
|
2066
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2067
|
+
if ( ret > 0 ) {
|
2068
|
+
(*pnNumRunBNS) ++;
|
2069
|
+
cur_success ++; /* 01 */
|
2070
|
+
}
|
2071
|
+
}
|
2072
|
+
if ( cur_success ) {
|
2073
|
+
/* set bond M=O order = 0 */
|
2074
|
+
if ( pe->flow != 2*delta ) {
|
2075
|
+
ret = RI_ERR_PROGR;
|
2076
|
+
goto exit_function;
|
2077
|
+
}
|
2078
|
+
/* reduce pe bond order by 2*delta */
|
2079
|
+
pe->flow -= 2*delta;
|
2080
|
+
pvO->st_edge.cap -= 2*delta;
|
2081
|
+
pvO->st_edge.flow -= 2*delta;
|
2082
|
+
pvM->st_edge.flow -= 2*delta;
|
2083
|
+
pvM->st_edge.cap -= 2*delta;
|
2084
|
+
pBNS->tot_st_cap -= 3*delta;
|
2085
|
+
pBNS->tot_st_flow -= 4*delta;
|
2086
|
+
/* fix M-O bond order to zero */
|
2087
|
+
pe->cap -= 2*delta;
|
2088
|
+
/* add fixed (-) charge to O */
|
2089
|
+
pVA[n].cInitCharge -= delta;
|
2090
|
+
} else {
|
2091
|
+
/* failed */
|
2092
|
+
pBNS->vert[vPlusMinus].st_edge.cap -= delta;
|
2093
|
+
pvO->st_edge.cap -= delta;
|
2094
|
+
/*pTCGroups->pTCG[itg].edges_cap -= delta;*/ /* ???bug??? - commented out 2006-03-22 */
|
2095
|
+
pBNS->tot_st_cap -= 2*delta;
|
2096
|
+
/* decrease capacities of edges to Y */
|
2097
|
+
for ( i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1 ++ ) {
|
2098
|
+
j1 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
|
2099
|
+
for ( k1 = 0; k1 < pBNS->vert[j1].num_adj_edges; k1 ++ ) {
|
2100
|
+
pBNS->edge[pBNS->vert[j1].iedge[k1]].cap -= delta;
|
2101
|
+
}
|
2102
|
+
}
|
2103
|
+
}
|
2104
|
+
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
|
2105
|
+
}
|
2106
|
+
}
|
2107
|
+
}
|
2108
|
+
}
|
2109
|
+
|
2110
|
+
exit_function:
|
2111
|
+
AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
|
2112
|
+
return ret;
|
2113
|
+
}
|
2114
|
+
#if ( KEEP_METAL_EDGE_FLOW == 1 )
|
2115
|
+
/******************************************************************************************************/
|
2116
|
+
int ForbidMetalCarbonEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_at, VAL_AT *pVA,
|
2117
|
+
ALL_TC_GROUPS *pTCGroups, EDGE_LIST *pMetalCarbonEdges, int forbidden_edge_mask )
|
2118
|
+
{
|
2119
|
+
|
2120
|
+
int i, j, neigh, nNumEdgeMetalCarbon = 0, pass = 0, ret = 0;
|
2121
|
+
BNS_VERTEX *pVert, *pNeigh;
|
2122
|
+
BNS_EDGE *pEdge;
|
2123
|
+
|
2124
|
+
/* count carbon-metal edges */
|
2125
|
+
|
2126
|
+
if ( pTCGroups->num_metal_atoms ) {
|
2127
|
+
fill_ForbiddenEdgesMetalCarbon:
|
2128
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2129
|
+
if ( pVA[i].cMetal && pVA[i].cNumBondsToMetal ) {
|
2130
|
+
pVert = pBNS->vert + i;
|
2131
|
+
for ( j = 0; j < pVert->num_adj_edges; j ++ ) {
|
2132
|
+
pEdge = pBNS->edge + pVert->iedge[j];
|
2133
|
+
neigh = pEdge->neighbor12 ^ i;
|
2134
|
+
pNeigh = pBNS->vert + neigh;
|
2135
|
+
if ( !IS_BNS_VT_ATOM(pNeigh->type) )
|
2136
|
+
continue;
|
2137
|
+
if ( at[neigh].endpoint )
|
2138
|
+
continue;
|
2139
|
+
if ( pVA[neigh].cNumValenceElectrons == 4 && pVA[neigh].cPeriodicRowNumber == 1 &&
|
2140
|
+
pNeigh->st_edge.cap >= at[neigh].valence+1 ) {
|
2141
|
+
if ( pass ) {
|
2142
|
+
if ( ret = AddToEdgeList( pMetalCarbonEdges, pVert->iedge[j], 0 ) ) {
|
2143
|
+
goto exit_function;
|
2144
|
+
}
|
2145
|
+
pEdge->forbidden |= forbidden_edge_mask;
|
2146
|
+
} else {
|
2147
|
+
nNumEdgeMetalCarbon ++;
|
2148
|
+
}
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
}
|
2152
|
+
}
|
2153
|
+
}
|
2154
|
+
if ( !pass && nNumEdgeMetalCarbon ) {
|
2155
|
+
if ( ret = AllocEdgeList( pMetalCarbonEdges, nNumEdgeMetalCarbon ) ) {
|
2156
|
+
goto exit_function;
|
2157
|
+
}
|
2158
|
+
pass ++;
|
2159
|
+
goto fill_ForbiddenEdgesMetalCarbon;
|
2160
|
+
}
|
2161
|
+
}
|
2162
|
+
exit_function:
|
2163
|
+
return ret;
|
2164
|
+
}
|
2165
|
+
#endif
|
2166
|
+
/******************************************************************************************************/
|
2167
|
+
int RunBnsRestore1( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
|
2168
|
+
StrFromINChI *pStruct, VAL_AT *pVA, ALL_TC_GROUPS *pTCGroups, INChI *pInChI[],
|
2169
|
+
long num_inp, int bHasSomeFixedH )
|
2170
|
+
{
|
2171
|
+
int nNumRunBNS = 0;
|
2172
|
+
|
2173
|
+
EDGE_LIST CarbonChargeEdges, MetalCarbonEdges, Nplus2BondsEdges;
|
2174
|
+
|
2175
|
+
int nTotalDelta = 0, ret = 0, tot_num_fixes;
|
2176
|
+
inp_ATOM *at = pStruct->at;
|
2177
|
+
inp_ATOM *at2 = NULL; /* restored structure */
|
2178
|
+
inp_ATOM *at3 = NULL; /* structure for calculating one InChI */
|
2179
|
+
int num_at = pStruct->num_atoms;
|
2180
|
+
int num_deleted_H = pStruct->num_deleted_H;
|
2181
|
+
#ifdef _DEBUG
|
2182
|
+
int ret2;
|
2183
|
+
#endif
|
2184
|
+
|
2185
|
+
#if ( KEEP_METAL_EDGE_FLOW == 1 )
|
2186
|
+
BNS_VERTEX *pVert, *pNeigh;
|
2187
|
+
int j, neigh;
|
2188
|
+
#endif
|
2189
|
+
|
2190
|
+
/* Edge lista initialization */
|
2191
|
+
AllocEdgeList( &CarbonChargeEdges, EDGE_LIST_CLEAR );
|
2192
|
+
AllocEdgeList( &MetalCarbonEdges, EDGE_LIST_CLEAR );
|
2193
|
+
AllocEdgeList( &Nplus2BondsEdges, EDGE_LIST_CLEAR );
|
2194
|
+
|
2195
|
+
if ( pStruct->iMobileH == TAUT_NON &&
|
2196
|
+
( ret = FillOutExtraFixedHDataInChI( pStruct, pInChI ) ) ) {
|
2197
|
+
goto exit_function;
|
2198
|
+
}
|
2199
|
+
|
2200
|
+
if ( !at2 && !(at2 = (inp_ATOM *)inchi_malloc((num_at + num_deleted_H)*sizeof(at2[0]))) ||
|
2201
|
+
!at3 && !(at3 = (inp_ATOM *)inchi_malloc((num_at + num_deleted_H)*sizeof(at3[0])))) {
|
2202
|
+
return RI_ERR_ALLOC;
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
if ( 0 > (ret = ForbidCarbonChargeEdges( pBNS, pTCGroups, &CarbonChargeEdges, BNS_EDGE_FORBIDDEN_TEMP ))) {
|
2206
|
+
goto exit_function;
|
2207
|
+
}
|
2208
|
+
|
2209
|
+
#if ( KEEP_METAL_EDGE_FLOW == 1 )
|
2210
|
+
/* count edges of -C(IV)< carbons connected to metals */
|
2211
|
+
if ( 0 > (ret = ForbidMetalCarbonEdges( pBNS, at, num_at, pVA, pTCGroups, &MetalCarbonEdges, BNS_EDGE_FORBIDDEN_TEMP ))) {
|
2212
|
+
goto exit_function;
|
2213
|
+
}
|
2214
|
+
#endif
|
2215
|
+
if ( 0 > (ret = ForbidNintrogenPlus2BondsInSmallRings( pBNS, at, num_at, pVA, 6,
|
2216
|
+
pTCGroups, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP ) ) ) {
|
2217
|
+
goto exit_function;
|
2218
|
+
}
|
2219
|
+
|
2220
|
+
/*********** Run BNS #1: no charge on carbons and =N= ***************/
|
2221
|
+
if ( Nplus2BondsEdges.num_edges ) {
|
2222
|
+
/* Run BNS leaving carbon charges unchanged */
|
2223
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2224
|
+
nNumRunBNS ++;
|
2225
|
+
if ( ret < 0 ) {
|
2226
|
+
goto exit_function;
|
2227
|
+
} else {
|
2228
|
+
nTotalDelta += ret;
|
2229
|
+
}
|
2230
|
+
RemoveForbiddenEdgeMask( pBNS, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP );
|
2231
|
+
AllocEdgeList( &Nplus2BondsEdges, EDGE_LIST_FREE );
|
2232
|
+
}
|
2233
|
+
#ifdef _DEBUG
|
2234
|
+
/* debug only */
|
2235
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2236
|
+
pStruct->at = at2;
|
2237
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2238
|
+
pStruct->at = at;
|
2239
|
+
#endif
|
2240
|
+
/*************************** extend min ring size to 8 ****************************/
|
2241
|
+
if ( 0 > (ret = ForbidNintrogenPlus2BondsInSmallRings( pBNS, at, num_at, pVA, 8,
|
2242
|
+
pTCGroups, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP ) ) ) {
|
2243
|
+
goto exit_function;
|
2244
|
+
}
|
2245
|
+
if ( Nplus2BondsEdges.num_edges ) {
|
2246
|
+
/* Run BNS leaving carbon charges unchanged */
|
2247
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2248
|
+
nNumRunBNS ++;
|
2249
|
+
if ( ret < 0 ) {
|
2250
|
+
goto exit_function;
|
2251
|
+
} else {
|
2252
|
+
nTotalDelta += ret;
|
2253
|
+
}
|
2254
|
+
RemoveForbiddenEdgeMask( pBNS, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP );
|
2255
|
+
AllocEdgeList( &Nplus2BondsEdges, EDGE_LIST_FREE );
|
2256
|
+
}
|
2257
|
+
#ifdef _DEBUG
|
2258
|
+
/* debug only */
|
2259
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2260
|
+
pStruct->at = at2;
|
2261
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2262
|
+
pStruct->at = at;
|
2263
|
+
#endif
|
2264
|
+
/*******************************************************************/
|
2265
|
+
if ( CarbonChargeEdges.num_edges > 0 ) {
|
2266
|
+
/* Run BNS leaving carbon charges unchanged */
|
2267
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2268
|
+
nNumRunBNS ++;
|
2269
|
+
if ( ret < 0 ) {
|
2270
|
+
goto exit_function;
|
2271
|
+
} else {
|
2272
|
+
nTotalDelta += ret;
|
2273
|
+
}
|
2274
|
+
RemoveForbiddenEdgeMask( pBNS, &CarbonChargeEdges, BNS_EDGE_FORBIDDEN_TEMP );
|
2275
|
+
AllocEdgeList( &CarbonChargeEdges, EDGE_LIST_FREE );
|
2276
|
+
}
|
2277
|
+
#ifdef _DEBUG
|
2278
|
+
/* debug only */
|
2279
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2280
|
+
pStruct->at = at2;
|
2281
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2282
|
+
pStruct->at = at;
|
2283
|
+
#endif
|
2284
|
+
/*******************************************************************/
|
2285
|
+
if ( MetalCarbonEdges.num_edges > 0 ) {
|
2286
|
+
/* Run BNS leaving carbon charges unchanged */
|
2287
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2288
|
+
nNumRunBNS ++;
|
2289
|
+
if ( ret < 0 ) {
|
2290
|
+
goto exit_function;
|
2291
|
+
} else {
|
2292
|
+
nTotalDelta += ret;
|
2293
|
+
}
|
2294
|
+
RemoveForbiddenEdgeMask( pBNS, &MetalCarbonEdges, BNS_EDGE_FORBIDDEN_TEMP );
|
2295
|
+
AllocEdgeList( &MetalCarbonEdges, EDGE_LIST_FREE );
|
2296
|
+
}
|
2297
|
+
/*******************************************************************/
|
2298
|
+
/* Run BNS allowing to change any charges */
|
2299
|
+
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
|
2300
|
+
nNumRunBNS ++;
|
2301
|
+
if ( ret < 0 ) {
|
2302
|
+
goto exit_function;
|
2303
|
+
} else {
|
2304
|
+
nTotalDelta += ret;
|
2305
|
+
}
|
2306
|
+
#ifdef _DEBUG
|
2307
|
+
/* debug only */
|
2308
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2309
|
+
pStruct->at = at2;
|
2310
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2311
|
+
pStruct->at = at;
|
2312
|
+
#endif
|
2313
|
+
|
2314
|
+
#if ( BNS_RAD_SEARCH == 1 )
|
2315
|
+
/******************************************************************/
|
2316
|
+
/* move unfulfilled 'radicals' from ChargeStruct to atoms */
|
2317
|
+
/* and set change charges of affected atoms to fit total charge */
|
2318
|
+
ret = MoveRadToAtomsAddCharges( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups, BNS_EDGE_FORBIDDEN_TEMP );
|
2319
|
+
if ( ret < 0 ) {
|
2320
|
+
goto exit_function;
|
2321
|
+
}
|
2322
|
+
#endif
|
2323
|
+
/**************************************************************/
|
2324
|
+
/**************************************************************/
|
2325
|
+
/***** fix restore inconsistencies *****/
|
2326
|
+
/**************************************************************/
|
2327
|
+
/**************************************************************/
|
2328
|
+
#ifdef _DEBUG
|
2329
|
+
/* debug only */
|
2330
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2331
|
+
pStruct->at = at2;
|
2332
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2333
|
+
pStruct->at = at;
|
2334
|
+
#endif
|
2335
|
+
|
2336
|
+
/* rearrange (+) and (-) edges flow so that there is no (+)flow=0 and (-)flow=1 */
|
2337
|
+
ret = RearrangePlusMinusEdgesFlow( pBNS, pBD, pVA, pTCGroups, BNS_EDGE_FORBIDDEN_TEMP );
|
2338
|
+
if ( ret < 0 ) {
|
2339
|
+
goto exit_function;
|
2340
|
+
}
|
2341
|
+
|
2342
|
+
/*****************************************************************/
|
2343
|
+
/* Increment zero order metal bonds to heteroatoms */
|
2344
|
+
/*****************************************************************/
|
2345
|
+
ret = IncrementZeroOrderBondsToHeteroat( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2346
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2347
|
+
if ( ret < 0 ) {
|
2348
|
+
goto exit_function;
|
2349
|
+
}
|
2350
|
+
|
2351
|
+
#ifdef _DEBUG
|
2352
|
+
/* debug only */
|
2353
|
+
memcpy( at2, at, (pStruct->num_atoms + pStruct->num_deleted_H)*sizeof(at2[0]));
|
2354
|
+
pStruct->at = at2;
|
2355
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2356
|
+
pStruct->at = at;
|
2357
|
+
#endif
|
2358
|
+
|
2359
|
+
#if (MOVE_CHARGES_FROM_HETEREO_TO_METAL == 1 )
|
2360
|
+
/*****************************************************************/
|
2361
|
+
/* move charges from heteroatoms to metal atoms */
|
2362
|
+
/*****************************************************************/
|
2363
|
+
ret = MoveChargeFromHeteroatomsToMetals( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2364
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2365
|
+
if ( ret < 0 ) {
|
2366
|
+
goto exit_function;
|
2367
|
+
}
|
2368
|
+
#endif
|
2369
|
+
/***********************************************************************
|
2370
|
+
NH2 NH2
|
2371
|
+
\ \
|
2372
|
+
C==S(+)- => C(+)-S- where NH2 are not tautomeric
|
2373
|
+
/ /
|
2374
|
+
NH2 NH2
|
2375
|
+
************************************************************************/
|
2376
|
+
ret = MovePlusFromS2DiaminoCarbon( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2377
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2378
|
+
if ( ret < 0 ) {
|
2379
|
+
goto exit_function;
|
2380
|
+
}
|
2381
|
+
/*****************************************************************/
|
2382
|
+
/* Avoid charge separation on heteroatoms */
|
2383
|
+
/*****************************************************************/
|
2384
|
+
ret = EliminateChargeSeparationOnHeteroatoms( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2385
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP, 0);
|
2386
|
+
if ( ret < 0 ) {
|
2387
|
+
goto exit_function;
|
2388
|
+
}
|
2389
|
+
if ( ret ) {
|
2390
|
+
/*charge separation remains; allow changes of stereobonds in a ring and try again */
|
2391
|
+
ret = EliminateChargeSeparationOnHeteroatoms( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2392
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP,
|
2393
|
+
BNS_EDGE_FORBIDDEN_MASK);
|
2394
|
+
if ( ret < 0 ) {
|
2395
|
+
goto exit_function;
|
2396
|
+
}
|
2397
|
+
}
|
2398
|
+
/*****************************************************************/
|
2399
|
+
/* convert N#N(+)-N= into N(-)=N(+)=N- */
|
2400
|
+
/*****************************************************************/
|
2401
|
+
ret = RestoreNNNgroup( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2402
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2403
|
+
if ( ret < 0 ) {
|
2404
|
+
goto exit_function;
|
2405
|
+
}
|
2406
|
+
/*****************************************************************/
|
2407
|
+
/* convert Metal(q)-N(-)-O(-) Metal(q-2)-N=O (local change) */
|
2408
|
+
/*****************************************************************/
|
2409
|
+
ret = FixMetal_Nminus_Ominus( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2410
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2411
|
+
if ( ret < 0 ) {
|
2412
|
+
goto exit_function;
|
2413
|
+
}
|
2414
|
+
/*****************************************************************/
|
2415
|
+
/* convert N(-)=C= into N#C- - */
|
2416
|
+
/*****************************************************************/
|
2417
|
+
ret = RestoreCyanoGroup( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2418
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2419
|
+
if ( ret < 0 ) {
|
2420
|
+
goto exit_function;
|
2421
|
+
}
|
2422
|
+
/*****************************************************************/
|
2423
|
+
/* convert C(+)#N(+)- into C(-)#N(+)- */
|
2424
|
+
/*****************************************************************/
|
2425
|
+
ret = RestoreIsoCyanoGroup( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2426
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2427
|
+
if ( ret < 0 ) {
|
2428
|
+
goto exit_function;
|
2429
|
+
}
|
2430
|
+
/*****************************************************************/
|
2431
|
+
/* eliminate =N(V)= if possible */
|
2432
|
+
/* | */
|
2433
|
+
/*****************************************************************/
|
2434
|
+
ret = EliminateNitrogen5Val3Bonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2435
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2436
|
+
if ( ret < 0 ) {
|
2437
|
+
goto exit_function;
|
2438
|
+
}
|
2439
|
+
|
2440
|
+
/*****************************************************************/
|
2441
|
+
/* | | */
|
2442
|
+
/* convert -S- to =S= if possible */
|
2443
|
+
/* | | */
|
2444
|
+
/*****************************************************************/
|
2445
|
+
ret = Convert_SIV_to_SVI(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2446
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2447
|
+
if ( ret < 0 ) {
|
2448
|
+
goto exit_function;
|
2449
|
+
}
|
2450
|
+
|
2451
|
+
/*****************************************************************/
|
2452
|
+
/* =N(+)=O =N-O(-) */
|
2453
|
+
/* convert => if possible */
|
2454
|
+
/* Metal(q) Metal(q+2) */
|
2455
|
+
/*****************************************************************/
|
2456
|
+
ret = PlusFromDB_N_DB_O_to_Metal(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2457
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2458
|
+
if ( ret < 0 ) {
|
2459
|
+
goto exit_function;
|
2460
|
+
}
|
2461
|
+
|
2462
|
+
/*****************************************************************/
|
2463
|
+
/* forbidden edges prevents required in InChI tautomerism */
|
2464
|
+
/* incorrectly restored mobile H mix separate tautomeric groups */
|
2465
|
+
/* because an edge may not become forbidden */
|
2466
|
+
/* note: removes this 'forbidden_edge' bit from ALL edges */
|
2467
|
+
/*****************************************************************/
|
2468
|
+
ret = MoveMobileHToAvoidFixedBonds( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2469
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2470
|
+
|
2471
|
+
if ( ret < 0 ) {
|
2472
|
+
goto exit_function;
|
2473
|
+
}
|
2474
|
+
/**************************************************************************/
|
2475
|
+
/* 2. Mobile H endpoint has radical on it (typical for wrong P(VI)(=O)3OH */
|
2476
|
+
tot_num_fixes = 0;
|
2477
|
+
if ( pStruct->iMobileH==TAUT_NON ) {
|
2478
|
+
ret = RemoveRadFromMobileHEndpointFixH( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2479
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2480
|
+
} else {
|
2481
|
+
ret = RemoveRadFromMobileHEndpoint( pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2482
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2483
|
+
}
|
2484
|
+
if ( ret < 0 ) {
|
2485
|
+
goto exit_function;
|
2486
|
+
}
|
2487
|
+
tot_num_fixes += ret;
|
2488
|
+
/**************************************************************/
|
2489
|
+
/* make bonds between a charged heteroatom and a metal single */
|
2490
|
+
ret = MakeSingleBondsMetal2ChargedHeteroat(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2491
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2492
|
+
if ( ret < 0 ) {
|
2493
|
+
goto exit_function;
|
2494
|
+
}
|
2495
|
+
/**************************************************************/
|
2496
|
+
/* move (+) charges to >N- and other centerpoints */
|
2497
|
+
ret = MoveChargeToMakeCenerpoints(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2498
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2499
|
+
if ( ret < 0 ) {
|
2500
|
+
goto exit_function;
|
2501
|
+
}
|
2502
|
+
|
2503
|
+
/**************************************************************************/
|
2504
|
+
/* Find and eliminate false Mobile-H groups: Cl(=O)3(-O(-)) => Cl(-)(=O)4 */
|
2505
|
+
ret = MoveChargeToRemoveCenerpoints(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2506
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2507
|
+
if ( ret < 0 ) {
|
2508
|
+
goto exit_function;
|
2509
|
+
}
|
2510
|
+
/**************************************************************************/
|
2511
|
+
/* Find A=X< where all bonds to X except A=X are marked as stereogenic */
|
2512
|
+
/* make bonds A=X single */
|
2513
|
+
ret = CheckAndRefixStereobonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2514
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2515
|
+
if ( ret < 0 ) {
|
2516
|
+
goto exit_function;
|
2517
|
+
}
|
2518
|
+
/**************************************************************************/
|
2519
|
+
/* In Reconnected structure change 'salt bonds' to 'coordination bonds */
|
2520
|
+
/* for example, M-O-C= -> M(+)-O(-)-C= */
|
2521
|
+
/* Defect: instead of NH2-C=O(+)-M it will restore NH2(+)=C-O(-)-M(+) */
|
2522
|
+
/* However, in this release metal-organic compounds do not get much care */
|
2523
|
+
ret = SaltBondsToCoordBonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
|
2524
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
|
2525
|
+
if ( ret < 0 ) {
|
2526
|
+
goto exit_function;
|
2527
|
+
}
|
2528
|
+
/**************************************************************************/
|
2529
|
+
/* Normalize the structure and compare t-groups and stereobonds */
|
2530
|
+
ret = NormalizeAndCompare(ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups, pInChI, num_inp, bHasSomeFixedH,
|
2531
|
+
&nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP, BNS_EDGE_FORBIDDEN_MASK);
|
2532
|
+
if ( ret < 0 ) {
|
2533
|
+
goto exit_function;
|
2534
|
+
}
|
2535
|
+
/**************************************************************************/
|
2536
|
+
/* Create InChI out of the restored structure */
|
2537
|
+
|
2538
|
+
|
2539
|
+
/*ret = nTotalDelta;*/
|
2540
|
+
|
2541
|
+
exit_function:
|
2542
|
+
pStruct->at = at;
|
2543
|
+
pStruct->at2 = at2;
|
2544
|
+
at2 = NULL;
|
2545
|
+
AllocEdgeList( &CarbonChargeEdges, EDGE_LIST_FREE );
|
2546
|
+
AllocEdgeList( &MetalCarbonEdges, EDGE_LIST_FREE );
|
2547
|
+
AllocEdgeList( &Nplus2BondsEdges, EDGE_LIST_FREE );
|
2548
|
+
if ( at2 ) {
|
2549
|
+
inchi_free( at2 );
|
2550
|
+
}
|
2551
|
+
if ( at3 ) {
|
2552
|
+
inchi_free( at3 );
|
2553
|
+
}
|
2554
|
+
|
2555
|
+
return ret;
|
2556
|
+
}
|
2557
|
+
|
2558
|
+
/******************************************************************************************************/
|
2559
|
+
int RestoreAtomMakeBNS( ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, StrFromINChI *pStruct, int iComponent,
|
2560
|
+
int iAtNoOffset, INChI *pInChI[], const char *szCurHdr, long num_inp, int bHasSomeFixedH )
|
2561
|
+
{
|
2562
|
+
int i, j, ret = 0, ret2;
|
2563
|
+
/*int nDelta, nTotalDelta;*/
|
2564
|
+
VAL_AT *pVA = NULL;
|
2565
|
+
VAL_AT va1;
|
2566
|
+
int num_at = pStruct->num_atoms;
|
2567
|
+
inp_ATOM *at = pStruct->at;
|
2568
|
+
ALL_TC_GROUPS TCGroups;
|
2569
|
+
ALL_TC_GROUPS *pTCGroups = &TCGroups;
|
2570
|
+
int nAddEdges2eachAtom = 2, nAddVertices = 0;
|
2571
|
+
|
2572
|
+
BFS_Q bfsq;
|
2573
|
+
|
2574
|
+
/* BNS creation */
|
2575
|
+
BN_STRUCT *pBNS = NULL;
|
2576
|
+
BN_DATA *pBD = NULL;
|
2577
|
+
int nNum_changed_bonds = 0;
|
2578
|
+
int bTreatMoreAtomsAsMetals = 0, bSecondPassNewMetals=0;
|
2579
|
+
int nMaxAddAtoms = 2, nMaxAddEdges = 2, max_altp = BN_MAX_ALTP;
|
2580
|
+
|
2581
|
+
memset( pTCGroups, 0, sizeof(pTCGroups[0]) );
|
2582
|
+
for ( i = 0; i < NUM_TCGROUP_TYPES; i ++ ) {
|
2583
|
+
pTCGroups->nGroup[i] = TCG_None; /* unassigned */
|
2584
|
+
}
|
2585
|
+
pTCGroups->iComponent = iComponent;
|
2586
|
+
pTCGroups->iAtNoOffset = iAtNoOffset;
|
2587
|
+
|
2588
|
+
if ( num_at == 1 ) {
|
2589
|
+
/* single atom -- no bonds to restore */
|
2590
|
+
inp_ATOM *at2 = (inp_ATOM *)inchi_malloc(sizeof(at2[0])*(pStruct->num_atoms+pStruct->num_deleted_H));
|
2591
|
+
inp_ATOM *at3 = (inp_ATOM *)inchi_malloc(sizeof(at3[0])*(pStruct->num_atoms+pStruct->num_deleted_H));
|
2592
|
+
pStruct->at2 = at2;
|
2593
|
+
at[0].charge = pInChI[0]->nTotalCharge;
|
2594
|
+
if ( at2 ) {
|
2595
|
+
memcpy( at2, at, sizeof(at2[0])*(pStruct->num_atoms+pStruct->num_deleted_H));
|
2596
|
+
}
|
2597
|
+
if ( !at2 || !at3 ) {
|
2598
|
+
if ( at3 ) inchi_free( at3 );
|
2599
|
+
return RI_ERR_ALLOC;
|
2600
|
+
}
|
2601
|
+
ret = MakeOneInChIOutOfStrFromINChI( ip, sd, pStruct, pStruct->at2, at3, pTCGroups );
|
2602
|
+
/* clean up */
|
2603
|
+
for( i = 0; i < TAUT_NUM; i ++ ) {
|
2604
|
+
Free_INChI( &pStruct->pOneINChI[i] );
|
2605
|
+
Free_INChI_Aux( &pStruct->pOneINChI_Aux[i] );
|
2606
|
+
FreeInpAtomData( pStruct->pOne_norm_data[i] );
|
2607
|
+
if ( pStruct->pOne_norm_data[i] ) {
|
2608
|
+
inchi_free( pStruct->pOne_norm_data[i] );
|
2609
|
+
pStruct->pOne_norm_data[i] = NULL;
|
2610
|
+
}
|
2611
|
+
}
|
2612
|
+
free_t_group_info( &pStruct->One_ti );
|
2613
|
+
inchi_free( at3 );
|
2614
|
+
|
2615
|
+
return ret;
|
2616
|
+
}
|
2617
|
+
|
2618
|
+
AllocBfsQueue( &bfsq, BFS_Q_CLEAR, 0 );
|
2619
|
+
if ( !(pVA = (VAL_AT *) inchi_calloc( num_at, sizeof( pVA[0] ) ) ) ) {
|
2620
|
+
ret = RI_ERR_ALLOC;
|
2621
|
+
goto exit_function;
|
2622
|
+
}
|
2623
|
+
pStruct->pVA = pVA;
|
2624
|
+
memset( &va1, 0, sizeof(va1) );
|
2625
|
+
pTCGroups->total_charge = pInChI[0]->nTotalCharge;
|
2626
|
+
if ( 0 > ( ret = AllocBfsQueue( &bfsq, num_at, 0 /* min ring size undefined */ ) ) ) {
|
2627
|
+
goto exit_function;
|
2628
|
+
}
|
2629
|
+
pStruct->pbfsq = &bfsq;
|
2630
|
+
|
2631
|
+
if ( pStruct->iMobileH == TAUT_NON && pInChI[1] && pInChI[1]->nNumberOfAtoms > 1 &&
|
2632
|
+
( ret = FillOutpStructEndpointFromInChI( pInChI[1], &pStruct->endpoint )) ) {
|
2633
|
+
goto exit_function;
|
2634
|
+
}
|
2635
|
+
|
2636
|
+
/* mark metal atoms; find min ring sizes for atoms that have 2 bonds */
|
2637
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2638
|
+
pVA[i].cNumValenceElectrons = get_sp_element_type( at[i].el_number, &j );
|
2639
|
+
pVA[i].cPeriodicRowNumber = j;
|
2640
|
+
pVA[i].cPeriodicNumber = at[i].el_number;
|
2641
|
+
pVA[i].cNumValenceElectrons --; /* = -1 d- and f- metals, 0 for H, 1 for Na, 2 for Mg,.. = (ATYPE_Xx-1) */
|
2642
|
+
|
2643
|
+
if ( is_el_a_metal( at[i].el_number ) ) {
|
2644
|
+
if ( pStruct->pSrm->bStereoRemovesMetalFlag ) {
|
2645
|
+
/* treat metal as non-metal if it is stereogenic or has a stereobond */
|
2646
|
+
pVA[i].cMetal = !( at[i].p_parity || at[i].sb_parity[0] );
|
2647
|
+
} else {
|
2648
|
+
pVA[i].cMetal = 1;
|
2649
|
+
}
|
2650
|
+
}
|
2651
|
+
if ( at[i].valence == 2 && !at[i].num_H ) {
|
2652
|
+
pVA[i].cMinRingSize = is_bond_in_Nmax_memb_ring( at, i, 0, bfsq.q, bfsq.nAtomLevel,
|
2653
|
+
bfsq.cSource, 99 /* max ring size */ );
|
2654
|
+
} else {
|
2655
|
+
pVA[i].cMinRingSize = 0;
|
2656
|
+
}
|
2657
|
+
}
|
2658
|
+
/* AllocBfsQueue( &bfsq, BFS_Q_FREE, 0 ); */
|
2659
|
+
|
2660
|
+
repeat_for_new_metals:
|
2661
|
+
/* set valences for the first time; find ChargeValence structures for each atom */
|
2662
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2663
|
+
/* get additional fictitious atoms information */
|
2664
|
+
pVA[i].cInitFreeValences = 0;
|
2665
|
+
ret = GetAtomRestoreInfo( at, i, pVA, pStruct->pSrm, pStruct->bMobileH, pStruct->endpoint );
|
2666
|
+
if ( ret < 0 ) {
|
2667
|
+
goto exit_function;
|
2668
|
+
}
|
2669
|
+
if ( ret == TREAT_ATOM_AS_METAL && !bSecondPassNewMetals && !pVA[i].cMetal ) {
|
2670
|
+
if ( pStruct->pSrm->bStereoRemovesMetalFlag ) {
|
2671
|
+
/* treat metal as non-metal if it is stereogenic or has a stereobond */
|
2672
|
+
pVA[i].cMetal = !( at[i].p_parity || at[i].sb_parity[0] );
|
2673
|
+
} else {
|
2674
|
+
pVA[i].cMetal = 1;
|
2675
|
+
}
|
2676
|
+
if ( pVA[i].cMetal ) {
|
2677
|
+
bTreatMoreAtomsAsMetals ++;
|
2678
|
+
}
|
2679
|
+
}
|
2680
|
+
pTCGroups->charge_on_atoms += pVA[i].cInitCharge;
|
2681
|
+
}
|
2682
|
+
if ( bTreatMoreAtomsAsMetals && !bSecondPassNewMetals ) {
|
2683
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2684
|
+
/* clear all members of pVA[i] except two */
|
2685
|
+
pTCGroups->charge_on_atoms -= pVA[i].cInitCharge;
|
2686
|
+
va1.cMetal = pVA[i].cMetal;
|
2687
|
+
va1.cMinRingSize = pVA[i].cMinRingSize;
|
2688
|
+
va1.cNumValenceElectrons = pVA[i].cNumValenceElectrons;
|
2689
|
+
va1.cPeriodicRowNumber = pVA[i].cPeriodicRowNumber;
|
2690
|
+
va1.cPeriodicNumber = pVA[i].cPeriodicNumber;
|
2691
|
+
pVA[i] = va1;
|
2692
|
+
}
|
2693
|
+
bSecondPassNewMetals = 1;
|
2694
|
+
goto repeat_for_new_metals;
|
2695
|
+
}
|
2696
|
+
|
2697
|
+
/* count atoms, bonds, additional edges and vertices in ChargeValence structures and t-groups */
|
2698
|
+
ret = nCountBnsSizes( at, num_at, nAddEdges2eachAtom, nAddVertices, &pStruct->ti,
|
2699
|
+
pVA, pStruct->pSrm, pTCGroups );
|
2700
|
+
if ( ret < 0 ) {
|
2701
|
+
goto exit_function;
|
2702
|
+
}
|
2703
|
+
|
2704
|
+
/* find and count groups; add counts of all other vertices to be created */
|
2705
|
+
ret = nAddSuperCGroups( pTCGroups );
|
2706
|
+
if ( ret < 0 ) {
|
2707
|
+
goto exit_function;
|
2708
|
+
}
|
2709
|
+
|
2710
|
+
/* create the BNS and fill it with all real atoms */
|
2711
|
+
pBNS = AllocateAndInitTCGBnStruct( pStruct, pVA, pTCGroups,
|
2712
|
+
nMaxAddAtoms, nMaxAddEdges, max_altp, &nNum_changed_bonds );
|
2713
|
+
if ( !pBNS ) {
|
2714
|
+
ret = BNS_OUT_OF_RAM;
|
2715
|
+
goto exit_function;
|
2716
|
+
}
|
2717
|
+
/* add t-groups to the BNS */
|
2718
|
+
ret = AddTGroups2TCGBnStruct( pBNS, pStruct, pVA, pTCGroups, nMaxAddEdges );
|
2719
|
+
if ( ret < 0 ) {
|
2720
|
+
goto exit_function;
|
2721
|
+
}
|
2722
|
+
|
2723
|
+
/* add c-groups to the BNS; adjust charges */
|
2724
|
+
ret = AddCGroups2TCGBnStruct( pBNS, pStruct, pVA, pTCGroups, nMaxAddEdges );
|
2725
|
+
if ( ret < 0 ) {
|
2726
|
+
goto exit_function;
|
2727
|
+
}
|
2728
|
+
|
2729
|
+
/* allocate BNData */
|
2730
|
+
pBD = AllocateAndInitBnData( pBNS->max_vertices + pBNS->max_vertices/2 );
|
2731
|
+
if ( !pBD ) {
|
2732
|
+
ret = BNS_OUT_OF_RAM;
|
2733
|
+
goto exit_function;
|
2734
|
+
}
|
2735
|
+
CheckBnsConsistency( pStruct, pBNS, pVA, pTCGroups, 0 );
|
2736
|
+
|
2737
|
+
/* restore bonds & charges */
|
2738
|
+
ret = RunBnsRestore1( ip, sd, pBNS, pBD, pStruct, pVA, pTCGroups, pInChI, num_inp, bHasSomeFixedH );
|
2739
|
+
if ( ret < 0 ) {
|
2740
|
+
goto exit_function;
|
2741
|
+
}
|
2742
|
+
|
2743
|
+
ret = CheckBnsConsistency( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2744
|
+
#if( bRELEASE_VERSION == 0 )
|
2745
|
+
#ifndef INCHI_LIBRARY
|
2746
|
+
if ( ret ) {
|
2747
|
+
fprintf( stdout, "Msg for: %ld %s comp=%d %c%c\n", num_inp, (szCurHdr && szCurHdr[0])? szCurHdr : "", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F' );
|
2748
|
+
}
|
2749
|
+
if ( pStruct->iMobileH == TAUT_YES && pStruct->nNumRemovedProtons ) {
|
2750
|
+
fprintf( stdout, "REMOVED_PROTONS%+d %ld %s\n", pStruct->nNumRemovedProtons, num_inp, (szCurHdr && szCurHdr[0])? szCurHdr : "" );
|
2751
|
+
/*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
|
2752
|
+
}
|
2753
|
+
if ( pStruct->bExtract & EXTRACT_STRUCT_NUMBER ) {
|
2754
|
+
fprintf( stdout, "EXTRACT: %ld: %s\n", num_inp, (szCurHdr && szCurHdr[0])? szCurHdr : "" );
|
2755
|
+
}
|
2756
|
+
#endif
|
2757
|
+
#endif
|
2758
|
+
{ /* create the final structure in pStruct->at2 */
|
2759
|
+
inp_ATOM *at_tmp = pStruct->at;
|
2760
|
+
pStruct->at = pStruct->at2;
|
2761
|
+
memcpy( pStruct->at, at_tmp, sizeof(pStruct->at[0])*(pStruct->num_atoms + pStruct->num_deleted_H) );
|
2762
|
+
ret2 = CopyBnsToAtom( pStruct, pBNS, pVA, pTCGroups, 1 );
|
2763
|
+
pStruct->at2 = pStruct->at;
|
2764
|
+
pStruct->at = at_tmp;
|
2765
|
+
if ( ret2 < 0 ) {
|
2766
|
+
ret = ret2;
|
2767
|
+
}
|
2768
|
+
}
|
2769
|
+
|
2770
|
+
exit_function:
|
2771
|
+
|
2772
|
+
pStruct->pbfsq = NULL;
|
2773
|
+
AllocBfsQueue( &bfsq, BFS_Q_FREE, 0 );
|
2774
|
+
|
2775
|
+
pBD = DeAllocateBnData( pBD );
|
2776
|
+
pBNS = DeAllocateBnStruct( pBNS );
|
2777
|
+
/*
|
2778
|
+
if ( pVA ) inchi_free( pVA );
|
2779
|
+
*/
|
2780
|
+
if ( pTCGroups->pTCG ) inchi_free( pTCGroups->pTCG );
|
2781
|
+
|
2782
|
+
return ret;
|
2783
|
+
}
|
2784
|
+
/******************************************************************************************************/
|
2785
|
+
int OneInChI2Atom( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd, const char *szCurHdr, long num_inp,
|
2786
|
+
StrFromINChI *pStruct, int iComponent, int iAtNoOffset, int bHasSomeFixedH, INChI *pInChI[])
|
2787
|
+
{
|
2788
|
+
int ret;
|
2789
|
+
INPUT_PARMS *ip, ip_loc;
|
2790
|
+
|
2791
|
+
ip_loc = *ip_inp;
|
2792
|
+
ip = &ip_loc;
|
2793
|
+
|
2794
|
+
sd->pStrErrStruct[0] = '\0';
|
2795
|
+
ret = RestoreAtomConnectionsSetStereo( pStruct, iComponent, iAtNoOffset, pInChI[0], pInChI[1]);
|
2796
|
+
if ( ret < 0 ) {
|
2797
|
+
goto exit_function;
|
2798
|
+
}
|
2799
|
+
ret = SetStereoBondTypesFrom0DStereo( pStruct, pInChI[0]);
|
2800
|
+
if ( ret < 0 ) {
|
2801
|
+
goto exit_function;
|
2802
|
+
}
|
2803
|
+
ret = ReconcileAllCmlBondParities( pStruct->at, pStruct->num_atoms, 0 );
|
2804
|
+
if ( ret < 0 ) {
|
2805
|
+
goto exit_function;
|
2806
|
+
}
|
2807
|
+
/* main InChI restore function */
|
2808
|
+
ret = RestoreAtomMakeBNS( ip, sd, pStruct, iComponent, iAtNoOffset, pInChI, szCurHdr, num_inp, bHasSomeFixedH );
|
2809
|
+
|
2810
|
+
#ifndef INCHI_ANSI_ONLY
|
2811
|
+
if ( (pStruct->num_inp_actual>0? pStruct->num_inp_actual : num_inp) >= ip->first_struct_number &&
|
2812
|
+
( (/*ret > 0 &&*/ ip->bDisplayIfRestoreWarnings ) && pStruct->pXYZ ) ) {
|
2813
|
+
inchiTime ulTStart;
|
2814
|
+
InchiTimeGet( &ulTStart );
|
2815
|
+
DisplayRestoredComponent( pStruct, iComponent, iAtNoOffset, pInChI[0], szCurHdr );
|
2816
|
+
sd->ulStructTime -= InchiTimeElapsed( &ulTStart ); /* subtract display time */
|
2817
|
+
}
|
2818
|
+
#endif
|
2819
|
+
if ( ret < 0 ) {
|
2820
|
+
goto exit_function;
|
2821
|
+
}
|
2822
|
+
if ( (pStruct->num_inp_actual? pStruct->num_inp_actual: num_inp) >= ip->first_struct_number && ret >= 0 ) {
|
2823
|
+
/* remove t-group markings and increment zero-order bonds,
|
2824
|
+
otherwise MakeInChIOutOfStrFromINChI2() woild fail */
|
2825
|
+
/* --- moved to MakeInChIOutOfStrFromINChI2 ---
|
2826
|
+
IncrZeroBondsAndClearEndpts(pStruct->at2, pStruct->num_atoms, iComponent+1);
|
2827
|
+
CopySt2At( pStruct->at2, pStruct->st, pStruct->num_atoms );
|
2828
|
+
*/
|
2829
|
+
/* include all restored structure features in pStruct->at2 */
|
2830
|
+
/* make full InChI out of pStruct->at2, pStruct->num_atoms */
|
2831
|
+
/***************************************************************************************/
|
2832
|
+
/* !!! pStruct->One_InChI etc. were removed at the exit from NormalizeAndCompare() !!! */
|
2833
|
+
/***************************************************************************************/
|
2834
|
+
if ( bHasSomeFixedH && pStruct->iInchiRec == INCHI_REC && pStruct->iMobileH == TAUT_YES &&
|
2835
|
+
!pStruct->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC) ) {
|
2836
|
+
/* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
|
2837
|
+
ip->nMode |= REQ_MODE_BASIC;
|
2838
|
+
}
|
2839
|
+
ret = MakeInChIOutOfStrFromINChI2( ip, sd, pStruct, iComponent, iAtNoOffset, num_inp );
|
2840
|
+
if ( ret >= 0 ) {
|
2841
|
+
;
|
2842
|
+
}
|
2843
|
+
#if( bRELEASE_VERSION == 0 )
|
2844
|
+
#ifndef INCHI_LIBRARY
|
2845
|
+
else {
|
2846
|
+
fprintf( stdout, "\nERROR in MakeInChI-1: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
|
2847
|
+
szCurHdr? szCurHdr: "???", iComponent, pStruct->iInchiRec? 'R':'D', pStruct->iMobileH?'M':'F', ret);
|
2848
|
+
}
|
2849
|
+
#endif
|
2850
|
+
#endif
|
2851
|
+
}
|
2852
|
+
|
2853
|
+
|
2854
|
+
exit_function:
|
2855
|
+
return ret;
|
2856
|
+
}
|
2857
|
+
/********************************************************************************************/
|
2858
|
+
int MakeProtonComponent( StrFromINChI *pStruct, int iComponent, int num_prot )
|
2859
|
+
{
|
2860
|
+
inp_ATOM *at = NULL;
|
2861
|
+
int i;
|
2862
|
+
|
2863
|
+
if ( num_prot <= 0 ) {
|
2864
|
+
return 0;
|
2865
|
+
}
|
2866
|
+
/* allocate */
|
2867
|
+
pStruct->at = (inp_ATOM *) inchi_calloc( num_prot, sizeof(pStruct->at[0]) );
|
2868
|
+
pStruct->at2 = (inp_ATOM *) inchi_calloc( num_prot, sizeof(pStruct->at2[0]) );
|
2869
|
+
if ( !pStruct->at || !pStruct->at2 ) {
|
2870
|
+
return 0;
|
2871
|
+
}
|
2872
|
+
/* create protons */
|
2873
|
+
at = pStruct->at;
|
2874
|
+
/* fill out proton atom info */
|
2875
|
+
for ( i = 0; i < num_prot; i ++ ) {
|
2876
|
+
strcpy( at[i].elname, "H" );
|
2877
|
+
at[i].el_number = EL_NUMBER_H;
|
2878
|
+
at[i].orig_at_number = i+1;
|
2879
|
+
/*
|
2880
|
+
at[i].orig_compt_at_numb = i + 1;
|
2881
|
+
at[i].component = i + 1;
|
2882
|
+
*/
|
2883
|
+
at[i].charge = 1;
|
2884
|
+
}
|
2885
|
+
memcpy( pStruct->at2, at, num_prot * sizeof(pStruct->at2[0]) );
|
2886
|
+
pStruct->bDeleted = 0;
|
2887
|
+
pStruct->num_atoms = num_prot;
|
2888
|
+
pStruct->bMobileH = TAUT_YES;
|
2889
|
+
pStruct->iMobileH = TAUT_YES;
|
2890
|
+
return num_prot;
|
2891
|
+
}
|
2892
|
+
/********************************************************************************************/
|
2893
|
+
int AddRemProtonsInRestrStruct( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd, long num_inp,
|
2894
|
+
int bHasSomeFixedH,
|
2895
|
+
StrFromINChI *pStruct, int num_components,
|
2896
|
+
StrFromINChI *pStructR, int num_componentsR,
|
2897
|
+
NUM_H *nProtonsToBeRemovedByNormFromRevrs, int *recmet_change_balance )
|
2898
|
+
{
|
2899
|
+
int iComp, q, ret = 0;
|
2900
|
+
int num_atoms, tot_num_at, num_deleted_H, num_tg, num_changed, num_deleted_components;
|
2901
|
+
inp_ATOM *at;
|
2902
|
+
INPUT_PARMS *ip, ip_loc;
|
2903
|
+
int num_prot = *nProtonsToBeRemovedByNormFromRevrs;
|
2904
|
+
int delta_recmet_prot, num_prot_prev, bAccumulateChanges=0, nNumProtAddedByRevrs;
|
2905
|
+
INChI_Aux *pINChI_Aux;
|
2906
|
+
INCHI_MODE bNormalizationFlags;
|
2907
|
+
int nChargeRevrs, nChargeInChI;
|
2908
|
+
|
2909
|
+
if ( !num_prot ) {
|
2910
|
+
return 0;
|
2911
|
+
}
|
2912
|
+
delta_recmet_prot = 0;
|
2913
|
+
num_changed = 0;
|
2914
|
+
num_deleted_components = 0;
|
2915
|
+
ip_loc = *ip_inp;
|
2916
|
+
ip = &ip_loc;
|
2917
|
+
/*----------------------------------------------------------------------------------
|
2918
|
+
nLink < 0 && num_componentsR > 0 => This is a Disconnected structure component; it is
|
2919
|
+
same as already processed reconnected one
|
2920
|
+
Do no preicess it
|
2921
|
+
|
2922
|
+
nLink > 0 && num_componentsR > 0 => This is a Disconnected structure component;
|
2923
|
+
(should not happen) It it is a result of (nLink-1)th Reconeected
|
2924
|
+
component disconnection (NOT IMPLEMENTED YET)
|
2925
|
+
|
2926
|
+
nLink = 0 => Process this component. It is either a reconnected
|
2927
|
+
component, or a result of a disconnection (for now)
|
2928
|
+
|
2929
|
+
nLink > 0 && num_componentsR = 0 => This is a Reconnected component that is same as
|
2930
|
+
a disconnected one that will not be processed.
|
2931
|
+
Process and save charge delta.
|
2932
|
+
-----------------------------------------------------------------------------------*/
|
2933
|
+
|
2934
|
+
for ( iComp = 0; iComp < num_components && num_prot; iComp ++ ) {
|
2935
|
+
bAccumulateChanges = 0;
|
2936
|
+
if ( pStruct[iComp].nLink < 0 && num_componentsR > 0 ) {
|
2937
|
+
/* check */
|
2938
|
+
q = -(pStruct[iComp].nLink+1);
|
2939
|
+
if ( !pStructR || !num_componentsR || q >= num_componentsR || pStructR[q].nLink != (iComp+1) ) {
|
2940
|
+
ret = RI_ERR_PROGR;
|
2941
|
+
goto exit_function;
|
2942
|
+
}
|
2943
|
+
continue; /* Disconnected structure component has already been processed as a Reconnected one */
|
2944
|
+
}
|
2945
|
+
|
2946
|
+
at = pStruct[iComp].at2;
|
2947
|
+
num_atoms = pStruct[iComp].num_atoms;
|
2948
|
+
tot_num_at = pStruct[iComp].num_atoms+(num_deleted_H=pStruct[iComp].num_deleted_H);
|
2949
|
+
bAccumulateChanges = ( pStruct[iComp].nLink > 0 && !num_componentsR );
|
2950
|
+
nChargeRevrs = pStruct[iComp].nChargeRevrs;
|
2951
|
+
nChargeInChI = pStruct[iComp].nChargeInChI;
|
2952
|
+
num_deleted_components += (0 != pStruct[iComp].bDeleted);
|
2953
|
+
if ( !at || !num_atoms ) {
|
2954
|
+
continue;
|
2955
|
+
}
|
2956
|
+
/* find whether it is a reconnected structure */
|
2957
|
+
q = bRevInchiComponentExists( pStruct+iComp, INCHI_REC, TAUT_YES, 0 )? INCHI_REC : INCHI_BAS;
|
2958
|
+
/*
|
2959
|
+
q = pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC] &&
|
2960
|
+
pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES] &&
|
2961
|
+
pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES]->nNumberOfAtoms? INCHI_REC : INCHI_BAS;
|
2962
|
+
*/
|
2963
|
+
pINChI_Aux = pStruct[iComp].RevInChI.pINChI_Aux[q][0][TAUT_YES]; /* 0 = 1st component in RevInChI */
|
2964
|
+
/*nNumProtAddedByRevrs = pINChI_Aux->nNumRemovedProtons;*/
|
2965
|
+
nNumProtAddedByRevrs = -pStruct[iComp].nNumRemovedProtonsByRevrs;
|
2966
|
+
bNormalizationFlags = pINChI_Aux->bNormalizationFlags;
|
2967
|
+
num_tg = pINChI_Aux->nNumberOfTGroups;
|
2968
|
+
|
2969
|
+
|
2970
|
+
if ( 0 > ( ret = DisconnectedConnectedH( at, num_atoms, num_deleted_H ) ) ) {
|
2971
|
+
goto exit_function;
|
2972
|
+
}
|
2973
|
+
num_prot_prev = num_prot;
|
2974
|
+
ret = AddRemoveProtonsRestr( at, num_atoms, &num_prot, nNumProtAddedByRevrs,
|
2975
|
+
bNormalizationFlags, num_tg, nChargeRevrs, nChargeInChI );
|
2976
|
+
|
2977
|
+
pStruct[iComp].bPostProcessed = ret;
|
2978
|
+
num_changed += (ret > 0);
|
2979
|
+
if ( ret < 0 ) {
|
2980
|
+
goto exit_function;
|
2981
|
+
}
|
2982
|
+
if ( ret > 0 ) {
|
2983
|
+
/* recalculate InChI; it will reconnect at */
|
2984
|
+
StrFromINChI *pStruct1 = pStruct + iComp;
|
2985
|
+
INCHI_MODE nMode = ip->nMode;
|
2986
|
+
FreeAllINChIArrays( pStruct1->RevInChI.pINChI,
|
2987
|
+
pStruct1->RevInChI.pINChI_Aux,
|
2988
|
+
pStruct1->RevInChI.num_components );
|
2989
|
+
|
2990
|
+
if ( bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
|
2991
|
+
!pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC) ) {
|
2992
|
+
/* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
|
2993
|
+
ip->nMode |= REQ_MODE_BASIC;
|
2994
|
+
}
|
2995
|
+
ret = MakeInChIOutOfStrFromINChI2( ip, sd, pStruct1, 0, 0, num_inp );
|
2996
|
+
ip->nMode = nMode;
|
2997
|
+
if ( ret < 0 ) {
|
2998
|
+
goto exit_function;
|
2999
|
+
}
|
3000
|
+
} else {
|
3001
|
+
if ( 0 > ( ret = ConnectDisconnectedH( at, num_atoms, num_deleted_H ) ) ) {
|
3002
|
+
goto exit_function;
|
3003
|
+
}
|
3004
|
+
}
|
3005
|
+
if ( bAccumulateChanges && recmet_change_balance ) {
|
3006
|
+
/* processed Reconnected layer component that is also present in Disconnected layer */
|
3007
|
+
delta_recmet_prot += num_prot - num_prot_prev;
|
3008
|
+
}
|
3009
|
+
}
|
3010
|
+
|
3011
|
+
iComp = num_components-1;
|
3012
|
+
if ( !bHasSomeFixedH && num_prot > 0 && 1 == num_deleted_components && iComp >= 0 && pStruct[iComp].bDeleted ) {
|
3013
|
+
/* add bare protons to the deleted Mobile-H component; undelete the component */
|
3014
|
+
num_prot_prev = num_prot;
|
3015
|
+
if ( !MakeProtonComponent( pStruct+iComp, iComp, num_prot ) ) {
|
3016
|
+
goto exit_function;
|
3017
|
+
} else {
|
3018
|
+
/* recalculate InChI; it will reconnect at */
|
3019
|
+
StrFromINChI *pStruct1 = pStruct + iComp;
|
3020
|
+
INCHI_MODE nMode = ip->nMode;
|
3021
|
+
num_changed ++;
|
3022
|
+
num_prot = 0;
|
3023
|
+
FreeAllINChIArrays( pStruct1->RevInChI.pINChI,
|
3024
|
+
pStruct1->RevInChI.pINChI_Aux,
|
3025
|
+
pStruct1->RevInChI.num_components );
|
3026
|
+
|
3027
|
+
if ( bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
|
3028
|
+
!pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC) ) {
|
3029
|
+
/* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
|
3030
|
+
ip->nMode |= REQ_MODE_BASIC;
|
3031
|
+
}
|
3032
|
+
ret = MakeInChIOutOfStrFromINChI2( ip, sd, pStruct1, 0, 0, num_inp );
|
3033
|
+
ip->nMode = nMode;
|
3034
|
+
if ( ret < 0 ) {
|
3035
|
+
goto exit_function;
|
3036
|
+
}
|
3037
|
+
if ( bAccumulateChanges && recmet_change_balance ) {
|
3038
|
+
/* processed Reconnected layer component that is also present in Disconnected layer */
|
3039
|
+
delta_recmet_prot += num_prot - num_prot_prev;
|
3040
|
+
}
|
3041
|
+
}
|
3042
|
+
}
|
3043
|
+
*nProtonsToBeRemovedByNormFromRevrs = num_prot;
|
3044
|
+
if ( recmet_change_balance ) {
|
3045
|
+
*recmet_change_balance = delta_recmet_prot;
|
3046
|
+
}
|
3047
|
+
|
3048
|
+
exit_function:
|
3049
|
+
return ret < 0? ret : num_changed;
|
3050
|
+
}
|
3051
|
+
/**********************************************************************************/
|
3052
|
+
int AddRemIsoProtonsInRestrStruct( ICHICONST INPUT_PARMS *ip_inp, STRUCT_DATA *sd, long num_inp, int bHasSomeFixedH,
|
3053
|
+
StrFromINChI *pStruct, int num_components,
|
3054
|
+
StrFromINChI *pStructR, int num_componentsR,
|
3055
|
+
NUM_H pProtonBalance[], NUM_H recmet_change_balance[] )
|
3056
|
+
{
|
3057
|
+
int iComp, q, k, ret = 0, bNotEmpty;
|
3058
|
+
int num_atoms, tot_num_at, num_deleted_H, num_tg, num_changed;
|
3059
|
+
inp_ATOM *at;
|
3060
|
+
NUM_H num_prot[NUM_H_ISOTOPES], delta_recmet_prot[NUM_H_ISOTOPES], num_prot_prev[NUM_H_ISOTOPES];
|
3061
|
+
int bAccumulateChanges;
|
3062
|
+
INChI_Aux *pINChI_Aux;
|
3063
|
+
INChI *pINChI;
|
3064
|
+
INCHI_MODE bNormalizationFlags;
|
3065
|
+
INPUT_PARMS *ip, ip_loc;
|
3066
|
+
|
3067
|
+
ip_loc = *ip_inp;
|
3068
|
+
ip = &ip_loc;
|
3069
|
+
|
3070
|
+
memcpy( num_prot, pProtonBalance, sizeof(num_prot) );
|
3071
|
+
for ( bNotEmpty=0, k = 0; k < NUM_H_ISOTOPES; k ++ ) {
|
3072
|
+
bNotEmpty |= num_prot[k];
|
3073
|
+
}
|
3074
|
+
if ( !bNotEmpty ) {
|
3075
|
+
return 0;
|
3076
|
+
}
|
3077
|
+
memset ( delta_recmet_prot, 0, sizeof(delta_recmet_prot));
|
3078
|
+
num_changed = 0;
|
3079
|
+
/*----------------------------------------------------------------------------------
|
3080
|
+
nLink < 0 && num_componentsR > 0 => This is a Disconnected structure component; it is
|
3081
|
+
same as already processed reconnected one
|
3082
|
+
Do no preicess it
|
3083
|
+
|
3084
|
+
nLink > 0 && num_componentsR > 0 => This is a Disconnected structure component;
|
3085
|
+
(should not happen) It it is a result of (nLink-1)th Reconeected
|
3086
|
+
component disconnection (NOT IMPLEMENTED YET)
|
3087
|
+
|
3088
|
+
nLink = 0 => Process this component. It is either a reconnected
|
3089
|
+
component, or a result of a disconnection (for now)
|
3090
|
+
|
3091
|
+
nLink > 0 && num_componentsR = 0 => This is a Reconnected component that is same as
|
3092
|
+
a disconnected one that will not be processed.
|
3093
|
+
Process and save charge delta.
|
3094
|
+
-----------------------------------------------------------------------------------*/
|
3095
|
+
|
3096
|
+
for ( iComp = 0; iComp < num_components && num_prot; iComp ++ ) {
|
3097
|
+
bAccumulateChanges = 0;
|
3098
|
+
if ( pStruct[iComp].nLink < 0 && num_componentsR > 0 ) {
|
3099
|
+
/* check */
|
3100
|
+
q = -(pStruct[iComp].nLink+1);
|
3101
|
+
if ( !pStructR || !num_componentsR || q >= num_componentsR || pStructR[q].nLink != (iComp+1) ) {
|
3102
|
+
ret = RI_ERR_PROGR;
|
3103
|
+
goto exit_function;
|
3104
|
+
}
|
3105
|
+
continue; /* Disconnected structure component has already been processed as a Reconnected one */
|
3106
|
+
}
|
3107
|
+
|
3108
|
+
at = pStruct[iComp].at2;
|
3109
|
+
num_atoms = pStruct[iComp].num_atoms;
|
3110
|
+
tot_num_at = pStruct[iComp].num_atoms+(num_deleted_H=pStruct[iComp].num_deleted_H);
|
3111
|
+
bAccumulateChanges = ( pStruct[iComp].nLink > 0 && !num_componentsR );
|
3112
|
+
|
3113
|
+
if ( !at || !num_atoms ) {
|
3114
|
+
continue;
|
3115
|
+
}
|
3116
|
+
/* find whether it is a reconnected structure */
|
3117
|
+
q = pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC] &&
|
3118
|
+
pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES] &&
|
3119
|
+
pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES]->nNumberOfAtoms? INCHI_REC : INCHI_BAS;
|
3120
|
+
|
3121
|
+
pINChI_Aux = pStruct[iComp].RevInChI.pINChI_Aux[q][0][TAUT_YES]; /* 0 = 1st component in RevInChI */
|
3122
|
+
pINChI = pStruct[iComp].RevInChI.pINChI[q][0][TAUT_YES]; /* 0 = 1st component in RevInChI */
|
3123
|
+
bNormalizationFlags = pINChI_Aux->bNormalizationFlags;
|
3124
|
+
num_tg = pINChI_Aux->nNumberOfTGroups;
|
3125
|
+
memcpy( num_prot_prev, num_prot, sizeof(num_prot_prev) );
|
3126
|
+
|
3127
|
+
/* pass CONNECTED explicit H to AddRemoveIsoProtonsRestr() for isotopic H addition */
|
3128
|
+
ret = AddRemoveIsoProtonsRestr( at, num_atoms, num_prot, num_tg );
|
3129
|
+
|
3130
|
+
pStruct[iComp].bPostProcessed |= ret;
|
3131
|
+
num_changed += (ret > 0);
|
3132
|
+
if ( ret < 0 ) {
|
3133
|
+
goto exit_function;
|
3134
|
+
}
|
3135
|
+
if ( ret > 0 ) {
|
3136
|
+
StrFromINChI *pStruct1 = pStruct+iComp;
|
3137
|
+
INCHI_MODE nMode = ip->nMode;
|
3138
|
+
/* recalculate InChI; MakeInChIOutOfStrFromINChI2() will reconnect explicit H */
|
3139
|
+
if ( 0 > ( ret = DisconnectedConnectedH( at, num_atoms, num_deleted_H ) ) ) {
|
3140
|
+
goto exit_function;
|
3141
|
+
}
|
3142
|
+
FreeAllINChIArrays( pStruct1->RevInChI.pINChI,
|
3143
|
+
pStruct1->RevInChI.pINChI_Aux,
|
3144
|
+
pStruct1->RevInChI.num_components );
|
3145
|
+
if ( bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
|
3146
|
+
!pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC) ) {
|
3147
|
+
/* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
|
3148
|
+
ip->nMode |= REQ_MODE_BASIC;
|
3149
|
+
}
|
3150
|
+
/* input: disconnected explicit H, output: connected explicit H */
|
3151
|
+
ret = MakeInChIOutOfStrFromINChI2( ip, sd, pStruct1, 0, 0, num_inp );
|
3152
|
+
ip->nMode = nMode;
|
3153
|
+
if ( ret < 0 ) {
|
3154
|
+
goto exit_function;
|
3155
|
+
}
|
3156
|
+
} else {
|
3157
|
+
if ( 0 > ( ret = ConnectDisconnectedH( at, num_atoms, num_deleted_H ) ) ) {
|
3158
|
+
goto exit_function;
|
3159
|
+
}
|
3160
|
+
}
|
3161
|
+
if ( bAccumulateChanges ) {
|
3162
|
+
/* processed Reconnected layer component that is also present in Disconnected layer */
|
3163
|
+
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
|
3164
|
+
delta_recmet_prot[k] += num_prot[k] - num_prot_prev[k];
|
3165
|
+
}
|
3166
|
+
}
|
3167
|
+
}
|
3168
|
+
|
3169
|
+
memcpy ( pProtonBalance, num_prot, sizeof(num_prot) );
|
3170
|
+
if ( recmet_change_balance ) {
|
3171
|
+
memcpy ( recmet_change_balance, delta_recmet_prot, sizeof(delta_recmet_prot) );
|
3172
|
+
}
|
3173
|
+
exit_function:
|
3174
|
+
return ret < 0? ret : num_changed;
|
3175
|
+
}
|
3176
|
+
|
3177
|
+
#endif
|