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