2
* International Chemical Identifier (InChI)
4
* Software version 1.03
7
* Originally developed at NIST
8
* Modifications and additions by IUPAC and the InChI Trust
10
* The InChI library and programs are free software developed under the
11
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
12
* you can redistribute this software and/or modify it under the terms of
13
* the GNU Lesser General Public License as published by the Free Software
15
* http://www.opensource.org/licenses/lgpl-2.1.php
23
/*#define CHECK_WIN32_VC_HEAP*/
26
#if( READ_INCHI_STRING == 1 )
51
#define INC_ADD_EDGE 64
52
/***********************************************************************************************/
53
int FixRestoredStructureStereo( INCHI_MODE cmpInChI, ICR *icr, INCHI_MODE cmpInChI2, ICR *icr2,
54
ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
55
StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
56
ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
57
inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp,
58
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
60
/*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
61
/* at2 should be the most recently restored atom, Fixed-H */
62
int i, j, k, delta, tot_succes, max_success, cur_success, ret = 0;
63
int err, iOrigInChI, iRevrInChI;
64
int j12, v1, v2, e, vRad;
65
BNS_VERTEX *pv1, *pv2, *pvRad;
67
EDGE_LIST AllChargeEdges, CurrEdges, NFlowerEdges, OtherNFlowerEdges, FixedStereoEdges, AllRadList;
68
EDGE_LIST TautMinusEdges[2]; /* 0 -> O & O(+), 1=> N & N(+) */
70
Vertex vPathStart, vPathEnd;
71
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
72
INChI_Stereo *pStereoInChI, *pStereo2InChI, *pStereoRevrs, *pStereo2Revrs;
76
/* currently being processed layer */
77
pStereoInChI = (pInChI[0]->StereoIsotopic &&
78
pInChI[0]->StereoIsotopic->nNumberOfStereoBonds +
79
pInChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
80
pInChI[0]->StereoIsotopic : pInChI[0]->Stereo;
82
/* mobile-H layer in case of Fixed-H */
83
pStereo2InChI = (pStruct->bMobileH == TAUT_YES || !pInChI[1] ||
84
!pInChI[1]->nNumberOfAtoms || pInChI[1]->bDeleted)?
86
(pInChI[1]->StereoIsotopic &&
87
pInChI[1]->StereoIsotopic->nNumberOfStereoBonds +
88
pInChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
89
pInChI[1]->StereoIsotopic :
92
/* currently being processed layer */
93
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
94
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
95
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
96
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
98
/* mobile-H layer in case of Fixed-H */
99
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
100
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
102
(pStruct->pOneINChI[1]->StereoIsotopic &&
103
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
104
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
105
pStruct->pOneINChI[1]->StereoIsotopic :
106
pStruct->pOneINChI[1]->Stereo;
110
AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
111
AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
112
AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
113
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
114
AllocEdgeList( &FixedStereoEdges, EDGE_LIST_CLEAR );
115
AllocEdgeList( &AllRadList, EDGE_LIST_CLEAR );
117
AllocEdgeList( TautMinusEdges+0, EDGE_LIST_CLEAR );
118
AllocEdgeList( TautMinusEdges+1, EDGE_LIST_CLEAR );
120
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
121
if ( cmpInChI & IDIF_PROBLEM ) {
122
ret = RI_ERR_PROGR; /* severe restore problem */
132
if ( pStruct->bMobileH == TAUT_NON ) {
133
/* these indexes are used to compare Mobile-H InChI */
134
iOrigInChI = (pInChI[1] && pInChI[1]->nNumberOfAtoms && !pInChI[1]->bDeleted)? 1 : 0;
135
iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
141
memset ( icr2, 0, sizeof(*icr2) );
142
if ( iRevrInChI || iOrigInChI ) {
143
/* additional mobile-H compare in case of Fixed-H */
144
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
145
if ( cmpInChI & IDIF_PROBLEM ) {
146
ret = RI_ERR_PROGR; /* severe restore problem */
156
if ( !(cmpInChI & IDIFF_SB) && !(cmpInChI2 & IDIFF_SB) ) {
159
/* need to temporarily remove fixing of stereogenic bonds */
160
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
161
pv1 = pBNS->vert + i;
162
for ( j = 0; j < at2[i].valence; j ++ ) {
163
pe = pBNS->edge + (e=pv1->iedge[j]);
164
if ( j == pe->neighbor1 ) {
165
/* do not store same bond 2 times */
166
if ( (pe->forbidden & forbidden_stereo_edge_mask) &&
167
(ret = AddToEdgeList( &FixedStereoEdges, e, INC_ADD_EDGE ) ) ) {
177
if ( (cmpInChI & IDIF_SB_MISS) && (!cmpInChI2 || (cmpInChI2 & IDIF_SB_MISS)) &&
178
0 < (max_success = pBNS->tot_st_cap - pBNS->tot_st_flow) ) {
179
/*----------------------------------------------------*/
180
/* case 01: extra stereogenic bond, radical present */
181
/* X=N-O* => X=N=O and eliminate radical */
182
/*----------------------------------------------------*/
184
BNS_VERTEX *pvO, *pvN;
187
RemoveForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
189
for ( i = 0; i < icr->num_sb_in2_only && cur_success < max_success; i ++ ) {
190
j12 = icr->sb_in2_only[i];
191
pv1 = pBNS->vert + (v1 = pStereoInChI->nBondAtom1[j12]-1);
192
pv2 = pBNS->vert + (v2 = pStereoInChI->nBondAtom2[j12]-1);
193
for ( k = 0; k < at2[v1].valence; k ++ ) {
194
pe = pBNS->edge + (e = pv1->iedge[k]);
195
if ( v2 == (pe->neighbor12 ^ v1) )
196
break; /* the edge has been found */
198
if ( k == at2[v1].valence ) {
204
pv1->st_edge.flow --;
205
pv2->st_edge.flow --;
206
pe->flow --; /* new radical on v2 */
208
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
209
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
211
pv1->st_edge.flow ++;
212
pv2->st_edge.flow ++;
213
pe->flow ++; /* remove new radical on v2 */
215
if ( ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && (v2 == vPathStart || v2 == vPathEnd) ) {
216
vRad = (v2 == vPathStart)? vPathEnd : vPathStart;
219
pv2->st_edge.flow --;
220
pv1->st_edge.flow --;
221
pe->flow --; /* new radical on v1 */
223
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
224
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
226
pv2->st_edge.flow ++;
227
pv1->st_edge.flow ++;
228
pe->flow ++; /* remove new radical on v1 */
229
if ( ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && (v1 == vPathStart || v1 == vPathEnd) ) {
230
vRad = (v1 == vPathStart)? vPathEnd : vPathStart;
233
if ( vRad == NO_VERTEX ) {
234
continue; /* radical did not affect this bond */
236
pvRad = pBNS->vert + vRad;
238
if ( pVA[vRad].cNumValenceElectrons == 6 && at2[vRad].valence == 1 &&
239
(peRad = pBNS->edge + pvRad->iedge[0])->flow == 0 &&
240
pVA[aN = peRad->neighbor12 ^ vRad].cNumValenceElectrons == 5 &&
241
at2[aN].valence == 2 ) {
242
/*------------------------------------------------------------
243
Fix Metal disconnection/normalization inconsistency :
244
disconnected restored
245
R=N(+)-M R=N--M R=N + M R=N + M
247
O(-) O O O* <- radical
249
The correct R=N + M(+)
252
--------------------------------------------------------------*/
253
pvN = pBNS->vert + aN;
259
pvO->st_edge.flow ++;
261
pvN->st_edge.flow ++;
262
pBNS->tot_st_cap += 1;
263
pBNS->tot_st_flow += 2;
266
/* all other radicals that affect stereo */
267
delta = pvRad->st_edge.cap - pvRad->st_edge.flow;
268
pvRad->st_edge.cap -= delta;
269
pBNS->tot_st_cap -= delta;
273
SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
275
tot_succes += cur_success;
276
/* recalculate InChI from the structure */
277
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
278
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
281
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
285
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
289
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
290
if ( cmpInChI & IDIF_PROBLEM ) {
291
ret = RI_ERR_PROGR; /* severe restore problem */
299
memset ( icr2, 0, sizeof(*icr2) );
300
if ( iRevrInChI || iOrigInChI ) {
301
/* additional mobile-H compare in case of Fixed-H */
302
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
303
if ( cmpInChI & IDIF_PROBLEM ) {
304
ret = RI_ERR_PROGR; /* severe restore problem */
313
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
314
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
315
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
316
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
319
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
320
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
322
(pStruct->pOneINChI[1]->StereoIsotopic &&
323
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
324
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
325
pStruct->pOneINChI[1]->StereoIsotopic :
326
pStruct->pOneINChI[1]->Stereo;
332
if ( !(cmpInChI & IDIF_SB_MISS) && (cmpInChI2 & IDIF_SB_MISS) &&
333
icr2->num_sb_in2_only &&
334
0 < (max_success = pBNS->tot_st_cap - pBNS->tot_st_flow) ) {
335
/*----------------------------------------------------*/
336
/* case 02: missing stereogenic bond in Mobile-H only */
337
/* X=N-O* => X=N=O and eliminate radical */
338
/*----------------------------------------------------*/
339
int retC, ret2C, retS, ret2S;
340
INCHI_MODE cmpInChI_Prev, cmpInChI2_Prev;
341
ICR icr_Prev, icr2_Prev;
346
cmpInChI_Prev = cmpInChI;
347
cmpInChI2_Prev = cmpInChI2;
348
for ( i = AllRadList.num_edges = 0; i < pStruct->num_atoms; i ++ ) {
349
if ( pBNS->vert[i].st_edge.cap - pBNS->vert[i].st_edge.flow == 1 &&
350
(ret = AddToEdgeList( &AllRadList, i, INC_ADD_EDGE ) ) ) {
354
for ( i = 0; i < AllRadList.num_edges; i ++ ) {
355
j = AllRadList.pnEdges[i];
356
pBNS->vert[j].st_edge.cap -= 1;
357
pBNS->tot_st_cap -= 1;
359
/*-------------------------------------------------*/
360
/* re-create InChI and see whether it looks better */
361
/*-------------------------------------------------*/
362
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
363
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
366
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
370
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
374
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
375
if ( cmpInChI & IDIF_PROBLEM ) {
376
ret = RI_ERR_PROGR; /* severe restore problem */
384
memset ( icr2, 0, sizeof(*icr2) );
385
if ( iRevrInChI || iOrigInChI ) {
386
/* additional mobile-H compare in case of Fixed-H */
387
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
388
if ( cmpInChI & IDIF_PROBLEM ) {
389
ret = RI_ERR_PROGR; /* severe restore problem */
397
retC = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_CONSTIT );
398
retS = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_STEREO );
399
ret2C = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_CONSTIT );
400
ret2S = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_STEREO );
409
for ( i = 0; i < AllRadList.num_edges; i ++ ) {
410
j = AllRadList.pnEdges[i];
411
pBNS->vert[j].st_edge.cap += 1;
412
pBNS->tot_st_cap += 1;
415
/*-------------------------------------------------*/
416
/* re-create InChI-- return to previous state */
417
/*-------------------------------------------------*/
418
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
419
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
422
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
426
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
430
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
431
if ( cmpInChI & IDIF_PROBLEM ) {
432
ret = RI_ERR_PROGR; /* severe restore problem */
440
memset ( icr2, 0, sizeof(*icr2) );
441
if ( iRevrInChI || iOrigInChI ) {
442
/* additional mobile-H compare in case of Fixed-H */
443
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
444
if ( cmpInChI & IDIF_PROBLEM ) {
445
ret = RI_ERR_PROGR; /* severe restore problem */
453
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
454
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
455
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
456
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
459
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
460
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
462
(pStruct->pOneINChI[1]->StereoIsotopic &&
463
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
464
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
465
pStruct->pOneINChI[1]->StereoIsotopic :
466
pStruct->pOneINChI[1]->Stereo;
472
if ( pStruct->bMobileH == TAUT_NON && (cmpInChI & IDIF_SB_EXTRA_UNDF) &&
473
pStruct->endpoint ) {
474
/*------------------------------------------------------*/
475
/* case 03: extra stereogenic bond in Fixed-H only */
476
/* in Mobile-H this bond is not stereogenic. */
477
/* Since this bond parity is not known, it is UNDEFINED */
478
/*------------------------------------------------------*/
479
int bDone, num_endpoints;
481
TautMinusEdges[0].num_edges = 0;
482
TautMinusEdges[1].num_edges = 0;
483
AllChargeEdges.num_edges = 0;
484
/* in1 => in restored structure; in2 => in original InChI */
485
for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
486
j12 = icr->sb_undef_in1_only[i];
487
pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
488
pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
490
if ( pStereo2Revrs ) {
491
/* reject if it is extra in Mobile-H also */
492
if ( icr2->num_sb_undef_in1_only ) {
493
for ( j = 0; j < icr2->num_sb_undef_in1_only; j ++ ) {
494
k = icr2->sb_undef_in1_only[j];
495
if ( v1 == pStereo2Revrs->nBondAtom1[k] &&
496
v2 == pStereo2Revrs->nBondAtom2[k] ) {
500
if ( j < icr->num_sb_in1_only ) {
501
continue; /* extra stereobond in Mobile H also */
505
/* reject if it is a stereobond in Mobile-H also */
506
if ( pStereo2InChI && pStereo2InChI->nNumberOfStereoBonds ) {
507
for ( j = 0; j < pStereo2InChI->nNumberOfStereoBonds; j ++ ) {
508
if ( v1 == pStereo2InChI->nBondAtom1[j] &&
509
v2 == pStereo2InChI->nBondAtom1[j] ) {
513
if ( j < pStereo2InChI->nNumberOfStereoBonds ) {
514
continue; /* ignore this extra stereo bond: it is in Mobile-H */
517
/* find the edge between v1 and v2 */
518
for ( k = 0; k < at2[v1].valence; k ++ ) {
519
pe = pBNS->edge + (e = pv1->iedge[k]);
520
if ( v2 == (pe->neighbor12 ^ v1) )
521
break; /* the edge has been found */
523
if ( k == at2[v1].valence ) {
527
/* Fix all charges except negative charges on tautomeric endpoints */
528
if ( !AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges ) {
529
for ( j = 0; j < pStruct->num_atoms; j ++ ) {
530
if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
531
if ( !pStruct->endpoint[j] ) {
532
if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
536
if ( pVA[j].cNumValenceElectrons == 6 ) {
538
if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
543
if (ret = AddToEdgeList( TautMinusEdges+1, k, INC_ADD_EDGE ) ) {
548
if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
549
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
552
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
553
if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
554
NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
556
if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
557
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
567
/* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
568
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
569
for ( k = 1, bDone = 0; k < 4 && !bDone; k ++ ) {
570
/* fix tautomeric charges */
571
num_endpoints = (TautMinusEdges+0)->num_edges + (TautMinusEdges+1)->num_edges;
573
/* fix charges on O */
574
SetForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
575
num_endpoints -= (TautMinusEdges+0)->num_edges;
578
SetForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
579
num_endpoints -= (TautMinusEdges+1)->num_edges;
581
if ( num_endpoints >= 2 ) {
583
pv1 = pBNS->vert + (v1 = pe->neighbor1);
584
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
586
pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
587
pe->flow -= delta; /* decrement stereobond order */
588
pv1->st_edge.flow -= delta;
589
pv2->st_edge.flow -= delta;
590
pBNS->tot_st_flow -= 2*delta;
592
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
593
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
595
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
596
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
597
/* Negative charge has been moved, no change in number of charges */
598
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
601
cur_success ++; /* 01 */
605
pe->forbidden &= ~forbidden_edge_mask;
607
pv1->st_edge.flow += delta;
608
pv2->st_edge.flow += delta;
609
pBNS->tot_st_flow += 2*delta;
612
/* unfix tautomeric charges */
614
RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
616
RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
618
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
622
tot_succes += cur_success;
623
/* recalculate InChI from the structure */
624
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
625
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
628
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
632
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
636
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
637
if ( cmpInChI & IDIF_PROBLEM ) {
638
ret = RI_ERR_PROGR; /* severe restore problem */
646
memset ( icr2, 0, sizeof(*icr2) );
647
if ( iRevrInChI || iOrigInChI ) {
648
/* additional mobile-H compare in case of Fixed-H */
649
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
650
if ( cmpInChI & IDIF_PROBLEM ) {
651
ret = RI_ERR_PROGR; /* severe restore problem */
659
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
660
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
661
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
662
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
665
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
666
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
668
(pStruct->pOneINChI[1]->StereoIsotopic &&
669
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
670
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
671
pStruct->pOneINChI[1]->StereoIsotopic :
672
pStruct->pOneINChI[1]->Stereo;
678
if ( (cmpInChI & IDIF_SB_EXTRA_UNDF) ) {
679
/*------------------------------------------------------*/
680
/* case 04: extra stereogenic bond */
681
/* Since this bond parity is not known, it is UNDEFINED */
682
/*------------------------------------------------------*/
683
int bDone, num_endpoints;
685
TautMinusEdges[0].num_edges = 0;
686
TautMinusEdges[1].num_edges = 0;
687
AllChargeEdges.num_edges = 0;
688
/* in1 => in restored structure; in2 => in original InChI */
689
for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
690
j12 = icr->sb_undef_in1_only[i];
691
pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
692
pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
694
/* find the edge between v1 and v2 */
695
for ( k = 0; k < at2[v1].valence; k ++ ) {
696
pe = pBNS->edge + (e = pv1->iedge[k]);
697
if ( v2 == (pe->neighbor12 ^ v1) )
698
break; /* the edge has been found */
700
if ( k == at2[v1].valence ) {
704
if ( pStereo2Revrs ) {
705
/* reject if it is not extra in Mobile-H also */
706
if ( icr2->num_sb_undef_in1_only ) {
707
for ( j = 0; j < icr2->num_sb_undef_in1_only; j ++ ) {
708
k = icr2->sb_undef_in1_only[j];
709
if ( v1 == pStereo2Revrs->nBondAtom1[k] &&
710
v2 == pStereo2Revrs->nBondAtom2[k] ) {
714
if ( j == icr->num_sb_in1_only ) {
715
continue; /* extra stereobond only in Fixed-H, not in Mobile H also */
720
/* Fix all charges except negative charges on tautomeric endpoints */
721
if ( !AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges ) {
722
for ( j = 0; j < pStruct->num_atoms; j ++ ) {
723
if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
724
if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
728
if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
729
int bMayBeUnfixed = !at2[j].num_H && !(pStruct->endpoint && pStruct->endpoint[j]);
730
if ( bMayBeUnfixed && pVA[j].cNumValenceElectrons == 6 ||
731
pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber > 1 ) {
733
if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
737
if ( bMayBeUnfixed &&
738
pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 ) {
740
if (ret = AddToEdgeList( TautMinusEdges+1, k, INC_ADD_EDGE ) ) {
744
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
748
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
749
if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
750
NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
751
if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
752
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
762
/* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
763
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
764
for ( k = 1, bDone = 0; k < 4 && !bDone; k ++ ) {
765
/* fix positive charges on heteroatoms */
766
num_endpoints = (TautMinusEdges+0)->num_edges + (TautMinusEdges+1)->num_edges;
768
/* fix charges on O */
769
SetForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
770
num_endpoints -= (TautMinusEdges+0)->num_edges;
773
/* fix charges on N */
774
SetForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
775
num_endpoints -= (TautMinusEdges+1)->num_edges;
777
if ( num_endpoints >= 2 ) {
779
pv1 = pBNS->vert + (v1 = pe->neighbor1);
780
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
782
pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
783
pe->flow -= delta; /* decrement stereobond order */
784
pv1->st_edge.flow -= delta;
785
pv2->st_edge.flow -= delta;
786
pBNS->tot_st_flow -= 2*delta;
788
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
789
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
791
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
792
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
793
/* Negative charge has been moved, no change in number of charges */
794
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
797
cur_success ++; /* 01 */
801
pe->forbidden &= ~forbidden_edge_mask;
803
pv1->st_edge.flow += delta;
804
pv2->st_edge.flow += delta;
805
pBNS->tot_st_flow += 2*delta;
808
/* unfix tautomeric charges */
810
RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
812
RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
814
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
818
tot_succes += cur_success;
819
/* recalculate InChI from the structure */
820
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
821
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
824
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
828
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
832
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
833
if ( cmpInChI & IDIF_PROBLEM ) {
834
ret = RI_ERR_PROGR; /* severe restore problem */
842
memset ( icr2, 0, sizeof(*icr2) );
843
if ( iRevrInChI || iOrigInChI ) {
844
/* additional mobile-H compare in case of Fixed-H */
845
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
846
if ( cmpInChI & IDIF_PROBLEM ) {
847
ret = RI_ERR_PROGR; /* severe restore problem */
855
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
856
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
857
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
858
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
861
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
862
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
864
(pStruct->pOneINChI[1]->StereoIsotopic &&
865
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
866
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
867
pStruct->pOneINChI[1]->StereoIsotopic :
868
pStruct->pOneINChI[1]->Stereo;
874
if ( pStruct->bMobileH == TAUT_YES &&
875
(cmpInChI & IDIF_SB_EXTRA_UNDF &&
876
!pStruct->ti.num_t_groups)
877
/*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/) {
878
/*----------------------------------------------------------*/
879
/* case 05: extra stereogenic bond on =NH2(+), (B, Mobile-H)*/
881
/* original: N(+)=-N< -> N--==N/ */
883
/* double bond is marked as */
884
/* not stereogenic due to */
885
/* its change during proton */
886
/* removal => No Stereo bond */
887
/* (=NH may be tautomeric) */
890
/* original: N=-N(+)< -> N--==N/ */
892
/* double bond was not */
893
/* changed during proton */
894
/* In Fixed-H this bond removal => Undef Stereo */
895
/* may not be stereogenic (=NH is not tautomeric) */
896
/* (a) due to (+) movement */
897
/* (b) due to symmetry (2H), even if isotopic */
899
/* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
901
/* Mobile-H: Add H(+) to =NH and move the charge to =N- */
902
/* to eliminate Undef stereo */
903
/* Move charge from N to -NH2 to create */
905
/* Since this bond parity is not known, it is UNDEFINED */
907
/* Solution: Add H(+) to =NH and move charge to -N= */
909
/*----------------------------------------------------------*/
910
int aN, aC, i1, i2, vPlusMinus;
911
AllChargeEdges.num_edges = 0;
912
/* in1 => in restored structure; in2 => in original InChI */
913
for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
914
j12 = icr->sb_undef_in1_only[i];
915
pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
916
pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
917
/* indicators of -NH: */
918
i1 = at2[v1].valence == 1 && at2[v1].num_H == 1 && !at2[v1].endpoint &&
919
pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
920
i2 = at2[v2].valence == 1 && at2[v2].num_H == 1 && !at2[v2].endpoint &&
921
pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
922
if ( !i1 && !i2 || i1 && i2 ) {
925
/* find the edge between v1 and v2 */
926
for ( k = 0; k < at2[v1].valence; k ++ ) {
927
pe = pBNS->edge + (e = pv1->iedge[k]);
928
if ( v2 == (pe->neighbor12 ^ v1) )
929
break; /* the edge has been found */
931
if ( k == at2[v1].valence ) {
935
if ( pe->flow != 1 ) {
936
continue; /* already charged */
938
aN = i1? v1 : v2; /* -NH atom */
939
aC = i1? v2 : v1; /* neighbor */
940
/* Replace =NH with -NH2
941
Create such a charge on some -N< that may be moved to NH2 to remove H(+):
943
from: HN=C-=-N=(+vert)-Y=(+super)-(+/-)
944
to: 2HN-C*-=-N=(+vert)-Y=(+super)-(+/-)*
946
2HN-C=-=N(+)-(+vert)=Y-(+super)=(+/-)
948
vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 0 );
949
if ( NO_VERTEX == vPlusMinus ) {
950
break; /* cannot do anything */
952
/* increase edges to -Y-(+/-)-Y- capacities */
954
for ( i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1 ++ ) {
955
i2 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
956
for ( k = 0; k < pBNS->vert[i2].num_adj_edges; k ++ ) {
957
pBNS->edge[pBNS->vert[i2].iedge[k]].cap += delta;
960
/* Fix all charges except (+) on -N< */
961
if ( !AllChargeEdges.num_edges ) {
962
for ( j = 0; j < pStruct->num_atoms; j ++ ) {
963
if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
964
if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
968
if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
969
if ( pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
970
!at2[j].num_H && at2[j].valence == 3 &&
971
!(at2[j].endpoint || pStruct->endpoint && pStruct->endpoint[j]) ) {
972
; /* do not fix -N< or =N(+)< */
975
if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
979
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
980
if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
981
NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
982
if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
983
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
991
/* Make bond to =NH single, add radical to aC */
992
pe->flow -= delta; /* make single bond */
993
pBNS->vert[aN].st_edge.flow -= delta;
994
pBNS->vert[aN].st_edge.cap -= delta; /* avoid radical on N */
995
pBNS->vert[aC].st_edge.flow -= delta; /* create radical on C */
996
pBNS->vert[vPlusMinus].st_edge.cap += delta; /* create radical on (+/-) */
997
pBNS->tot_st_flow -= 2*delta;
999
if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
1002
/* pBNS->tot_st_cap is unchanged */
1003
/* find all aC edges except pe to fix them */
1004
/* 2. Check whether it would work and do if it would */
1005
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1007
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1008
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1010
if ( ret == 1 && (vPathEnd == vPlusMinus && vPathStart == aC ||
1011
vPathEnd == aC && vPathStart == vPlusMinus) && nDeltaCharge == 1 ) {
1012
/* Negative charge has been moved, no change in number of charges */
1013
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1016
/* 3. Add H to -NH and register increaded charge */
1017
pStruct->at[aN].num_H ++;
1018
pTCGroups->total_charge ++;
1019
cur_success ++; /* 01 */
1022
pe->flow += delta; /* make single bond */
1023
pBNS->vert[aN].st_edge.flow += delta;
1024
pBNS->vert[aN].st_edge.cap += delta; /* avoid radical on N */
1025
pBNS->vert[aC].st_edge.flow += delta; /* create radical on C */
1026
pBNS->vert[vPlusMinus].st_edge.cap -= delta; /* create radical on (+/-) */
1027
pBNS->tot_st_flow += 2*delta;
1028
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1029
AllChargeEdges.num_edges --; /* remove pe from the list */
1030
CurrEdges.num_edges = 0;
1031
continue; /* should not happen */
1033
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1034
AllChargeEdges.num_edges --; /* remove pe from the list */
1035
CurrEdges.num_edges = 0;
1038
if ( cur_success ) {
1039
tot_succes += cur_success;
1040
/* recalculate InChI from the structure */
1041
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1042
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1045
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1049
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1053
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
1054
if ( cmpInChI & IDIF_PROBLEM ) {
1055
ret = RI_ERR_PROGR; /* severe restore problem */
1063
memset ( icr2, 0, sizeof(*icr2) );
1064
if ( iRevrInChI || iOrigInChI ) {
1065
/* additional mobile-H compare in case of Fixed-H */
1066
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1067
if ( cmpInChI & IDIF_PROBLEM ) {
1068
ret = RI_ERR_PROGR; /* severe restore problem */
1076
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
1077
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1078
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
1079
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
1082
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1083
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
1085
(pStruct->pOneINChI[1]->StereoIsotopic &&
1086
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1087
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
1088
pStruct->pOneINChI[1]->StereoIsotopic :
1089
pStruct->pOneINChI[1]->Stereo;
1095
if ( pStruct->bMobileH == TAUT_NON && pStereo2Revrs /* added check 2006-04-05 */ &&
1096
(cmpInChI2 & IDIF_SB_EXTRA_UNDF &&
1097
!pStruct->ti.num_t_groups)
1098
/*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/) {
1099
/*----------------------------------------------------------*/
1100
/* case 06: extra stereogenic bond on =NH2(+), (B, Fixed-H) */
1101
/* H H =========== */
1102
/* original: N(+)=-N< -> N--==N(+)< */
1104
/* double bond in Mobile-H */
1105
/* layer has Undef stereo */
1108
/* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
1110
/* Mobile-H: Add H(+) to =NH and move the charge to =N- */
1111
/* to eliminate Undef stereo */
1112
/* Move charge from N to -NH2 to create */
1114
/* Since this bond parity is not known, it is UNDEFINED */
1116
/* Solution: Move (+) from -NH2(+) to othe -N< */
1118
/*----------------------------------------------------------*/
1119
int aN, aC, i1, i2, ePlus;
1121
AllChargeEdges.num_edges = 0;
1122
/* in1 => in restored structure; in2 => in original InChI */
1123
for ( i = 0; i < icr2->num_sb_undef_in1_only; i ++ ) {
1124
j12 = icr2->sb_undef_in1_only[i];
1125
pv1 = pBNS->vert + (v1 = pStereo2Revrs->nBondAtom1[j12]-1);
1126
pv2 = pBNS->vert + (v2 = pStereo2Revrs->nBondAtom2[j12]-1);
1127
/* indicators of -NH: */
1128
i1 = at2[v1].valence == 1 && at2[v1].num_H == 2 && !at2[v1].endpoint &&
1129
pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
1130
i2 = at2[v2].valence == 1 && at2[v2].num_H == 2 && !at2[v2].endpoint &&
1131
pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
1132
if ( !i1 && !i2 || i1 && i2 ) {
1135
/* find the edge between v1 and v2 */
1136
for ( k = 0; k < at2[v1].valence; k ++ ) {
1137
pe = pBNS->edge + (e = pv1->iedge[k]);
1138
if ( v2 == (pe->neighbor12 ^ v1) )
1139
break; /* the edge has been found */
1141
if ( k == at2[v1].valence ) {
1142
ret = RI_ERR_SYNTAX;
1145
if ( pe->flow != 1 ) {
1146
continue; /* already charged */
1148
aN = i1? v1 : v2; /* -NH atom */
1149
aC = i1? v2 : v1; /* neighbor */
1150
if ( 0 > (ePlus = pVA[aN].nCPlusGroupEdge-1) ||
1151
(pePlus = pBNS->edge + ePlus)->flow || /* must be (+) charged */
1152
pePlus->forbidden ) {
1155
/* Move (+) from =NH2(+) to some other -N<
1157
/* Fix all charges except (+) on -N< */
1158
if ( !AllChargeEdges.num_edges ) {
1159
for ( j = 0; j < pStruct->num_atoms; j ++ ) {
1160
if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
1161
if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
1165
if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
1166
if ( pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
1167
!at2[j].num_H && at2[j].valence == 3 &&
1168
!(at2[j].endpoint || pStruct->endpoint && pStruct->endpoint[j]) ) {
1169
; /* do not fix -N< or =N(+)< */
1172
if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
1176
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
1177
if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
1178
NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
1179
if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
1180
if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
1188
/* pePlus edge is already fixed; unfix it */
1189
/* To decrement (+) on =NH2(+) decrement its double bond order */
1193
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1194
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1198
pv1->st_edge.flow -= delta;
1199
pv2->st_edge.flow -= delta;
1200
pBNS->tot_st_flow -= 2*delta;
1202
pe->forbidden |= forbidden_edge_mask;
1203
pePlus->forbidden &= ~forbidden_edge_mask;
1205
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1206
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1208
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1209
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
1210
/* (+)charge was just moved, no change in number of charges */
1211
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1214
cur_success ++; /* 01 */
1217
pe->flow += delta; /* roll back */
1218
pv1->st_edge.flow += delta;
1219
pv2->st_edge.flow += delta;
1220
pBNS->tot_st_flow += 2*delta;
1222
pe->forbidden &= ~forbidden_edge_mask;
1223
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1226
if ( cur_success ) {
1227
tot_succes += cur_success;
1228
/* recalculate InChI from the structure */
1229
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1230
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1233
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1237
if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1241
cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr2, &err );
1242
if ( cmpInChI & IDIF_PROBLEM ) {
1243
ret = RI_ERR_PROGR; /* severe restore problem */
1251
memset ( icr2, 0, sizeof(*icr2) );
1252
if ( iRevrInChI || iOrigInChI ) {
1253
/* additional mobile-H compare in case of Fixed-H */
1254
cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1255
if ( cmpInChI & IDIF_PROBLEM ) {
1256
ret = RI_ERR_PROGR; /* severe restore problem */
1264
pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
1265
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1266
pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
1267
pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
1270
pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1271
!pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
1273
(pStruct->pOneINChI[1]->StereoIsotopic &&
1274
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1275
pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
1276
pStruct->pOneINChI[1]->StereoIsotopic :
1277
pStruct->pOneINChI[1]->Stereo;
1284
SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
1285
AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
1286
AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
1287
AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
1288
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
1289
AllocEdgeList( &FixedStereoEdges, EDGE_LIST_FREE );
1290
AllocEdgeList( &AllRadList, EDGE_LIST_FREE ); /* eliminate memory leak */
1291
AllocEdgeList( TautMinusEdges+0, EDGE_LIST_FREE );
1292
AllocEdgeList( TautMinusEdges+1, EDGE_LIST_FREE );