2
* International Chemical Identifier (InChI)
4
* Software version 1.02
8
* The InChI library and programs are free software developed under the
9
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
10
* you can redistribute this software and/or modify it under the terms of
11
* the GNU Lesser General Public License as published by the Free Software
13
* http://www.opensource.org/licenses/lgpl-license.php
21
/*#define CHECK_WIN32_VC_HEAP*/
24
#if( READ_INCHI_STRING == 1 )
48
#define INC_ADD_EDGE 64
52
/* types for TgDiffHChgFH */
53
#define fNumRPosChgH 0 /* number of positive charges on endpoints that have H in at2[] */
54
#define fNumRPosChgU 1 /* number of positive charges on endpoints that have no H in at2[] */
55
#define fNumRNegChgO 2 /* number of negative charges on O endpoints */
56
#define fNumRNegChgN 3 /* number of negative charges on N endpoints */
57
#define fNumRNeutrlH 4 /* number of neutral endp that have H in at2[] */
59
#define fNumNPosChgH 5 /* number of positive charges on endpoints that have H in atf[] */
60
#define fNumNPosChgU 6 /* number of positive charges on endpoints that have no H in atf[] */
61
#define fNumNNegChgO 7 /* number of negative charges on O endpoints */
62
#define fNumNNegChgN 8 /* number of negative charges on N endpoints */
63
#define fNumNNeutrlH 9 /* number of neutral endp that have H in atf[] */
65
#define fNumAllChgT 10 /* total number of fNum... */
67
typedef struct tagTgDiffHChgFH {
68
short itg; /* t-group index; endpoint = itg+1 */
69
short nNumHInchi; /* number of H in t-group from orig. InChI */
70
short nNumHRevrs; /* number of H in at2[] */
71
short nNumHNorml; /* number of H in Normalized atfMobile_H_Revrs[] */
72
short nNumMInchi; /* number of (-) in InChI */
73
short nNumMRevrs; /* number of (-) in at2[] */
74
short nNumMNorml; /* number of (-) in atf[] */
75
short nNumPRevrs; /* number of (+) in at2[] */
76
short nNumPNorml; /* number of (+) in Normalized atfMobile_H_Revrs[] */
77
short n[fNumAllChgT]; /* all numbers */
78
short i[fNumAllChgT]; /* all indices */
81
/* local prototypes */
82
static int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], int max_tdhc, inp_ATOM at2[], inp_ATOM atf[],
83
AT_NUMB *nCanon2AtnoRevrs, VAL_AT *pVA, T_GROUP_INFO *ti, EDGE_LIST *pAtomIndList );
86
/************************************************************/
87
int bHas_N_V( inp_ATOM *at2, int num_atoms )
89
static U_CHAR el_number_N;
92
el_number_N = get_periodic_table_number( "N" );
94
for ( i = 0; i < num_atoms; i ++ ) {
95
if ( at2[i].el_number == el_number_N && !at2[i].charge &&
96
!at2[i].num_H && !at2[i].radical &&
97
at2[i].chem_bonds_valence == 5 &&
98
(at2[i].valence==3) ) {
104
/*************************************************************************************/
105
int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], int max_tdhc, inp_ATOM at2[],
106
inp_ATOM atf[], AT_NUMB *nCanon2AtnoRevrs, VAL_AT *pVA,
107
T_GROUP_INFO *ti, EDGE_LIST *pAtomIndList )
110
int i, j, iat, itg, itg_prev, num, itg_out, bOverflow;
111
EDGE_LIST IndList; /* type, itg */
112
TgDiffHChgFH cur_tdhc;
114
inp_ATOM *at2i, *atfi;
115
int typeR, typeN, type, ret = 0, nCurIndListLen;
117
AllocEdgeList( &IndList, EDGE_LIST_CLEAR );
118
pAtomIndList->num_edges = 0;
121
memset( tdhc, 0, max_tdhc * sizeof(tdhc[0]) );
123
for ( itg = 0; itg < ti->num_t_groups; itg ++ ) {
124
memset( &cur_tdhc, 0, sizeof(cur_tdhc) );
127
cur_tdhc.nNumHInchi = ti->t_group[itg].num[0] - ti->t_group[itg].num[1];
128
cur_tdhc.nNumMInchi = ti->t_group[itg].num[1];
130
pEndp0 = ti->nEndpointAtomNumber + ti->t_group[itg].nFirstEndpointAtNoPos;
131
nCurIndListLen = IndList.num_edges;
132
for ( j = 0; j < ti->t_group[itg].nNumEndpoints; j ++ ) {
134
iat = nCanon2AtnoRevrs[i];
140
if ( at2i->charge == 1 ) {
142
typeR = fNumRPosChgH;
144
typeR = fNumRPosChgU;
146
cur_tdhc.nNumPRevrs ++;
148
if ( at2i->charge == -1 ) {
149
if ( pVA[iat].cNumValenceElectrons == 6) {
150
typeR = fNumRNegChgO;
152
if ( pVA[iat].cNumValenceElectrons == 5) {
153
typeR = fNumRNegChgN;
155
cur_tdhc.nNumMRevrs ++;
157
if ( at2i->num_H && at2i->valence == at2i->chem_bonds_valence ) {
158
typeR = fNumRNeutrlH;
160
cur_tdhc.nNumHRevrs += at2i->num_H;
162
if ( atfi->charge == 1 ) {
164
typeN = fNumNPosChgH;
166
typeN = fNumNPosChgU;
168
cur_tdhc.nNumPNorml ++;
170
if ( atfi->charge == -1 ) {
171
if ( pVA[iat].cNumValenceElectrons == 6) {
172
typeN = fNumNNegChgO;
174
if ( pVA[iat].cNumValenceElectrons == 5) {
175
typeN = fNumNNegChgN;
177
cur_tdhc.nNumMNorml ++;
179
if ( atfi->num_H && atfi->valence == atfi->chem_bonds_valence ) {
180
typeN = fNumNNeutrlH;
182
cur_tdhc.nNumHNorml += atfi->num_H;
183
if ( at2[iat].charge < 0 || 0 < pVA[iat].nCPlusGroupEdge ) {
185
(ret = AddToEdgeList( &IndList, typeR, INC_ADD_EDGE )) ||
186
(ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE )) ||
187
(ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE )) ) ) {
191
(ret = AddToEdgeList( &IndList, typeN, INC_ADD_EDGE )) ||
192
(ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE )) ||
193
(ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE )) ) ) {
199
if ( cur_tdhc.nNumHNorml == cur_tdhc.nNumHInchi &&
200
cur_tdhc.nNumMNorml == cur_tdhc.nNumMInchi ) {
201
IndList.num_edges = nCurIndListLen; /* t-group seems to be correct */
204
if ( itg_out < max_tdhc ) {
205
tdhc[itg_out ++] = cur_tdhc;
208
IndList.num_edges = nCurIndListLen;
212
/* fill out atom index list */
214
itg_prev = IndList.pnEdges[1]; /* the 1st saved t-group number */
215
for ( type = 0; type < fNumAllChgT; type ++ ) {
217
for ( i = 0; i < itg_out; i ++ ) {
220
tdhc[i].i[type] = -999; /* empty */
221
while( IndList.pnEdges[j+1] == itg ) {
222
if ( IndList.pnEdges[j] == type ) {
224
tdhc[i].i[type] = pAtomIndList->num_edges;
226
if ( ret = AddToEdgeList( pAtomIndList, IndList.pnEdges[j+2], INC_ADD_EDGE )) {
232
tdhc[i].n[type] = num;
238
AllocEdgeList( &IndList, EDGE_LIST_FREE );
256
/***********************************************************************************************/
257
int FixFixedHRestoredStructure(ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
258
StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
259
ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
260
inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp, int bHasSomeFixedH,
261
int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
263
/*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
264
/* at2 should be the most recently restored atom, Fixed-H */
265
int i, j, k, delta, num_try, tot_succes, cur_success, ret = 0, bAllowedNFlowerEdges=0, num_zero_ret;
267
CMP2FHINCHI *pc2i = &c2i;
269
EDGE_LIST AllChargeEdges, CurrEdges, SFlowerEdges, NFlowerEdges, OtherNFlowerEdges, FixedLargeRingStereoEdges;
270
EDGE_LIST AllBondEdges;
275
BNS_VERTEX *pv1, *pv2;
277
Vertex vPathStart, vPathEnd;
278
int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
280
int nNumRunBNS = 0, forbidden_edge_mask_inv = ~forbidden_edge_mask;
284
AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
285
AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
286
AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
287
AllocEdgeList( &SFlowerEdges, EDGE_LIST_CLEAR );
288
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
289
AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_CLEAR );
290
AllocEdgeList( &AllBondEdges, EDGE_LIST_CLEAR );
294
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
295
goto exit_function; /* no fixed-H found */
298
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
299
if ( (e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
300
(ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE )) ) {
303
if ( (e=pVA[i].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
304
if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
308
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
309
if ( pVA[i].cNumValenceElectrons == 5 && !pVA[i].cMetal && /* N, P, As */
310
NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
312
if ( pBNS->edge[j].forbidden ) {
316
if ( pBNS->edge[j].flow ) {
317
if ( ret = AddToEdgeList( &AllChargeEdges, j, INC_ADD_EDGE ) ) {
320
if ( ret = AddToEdgeList( &NFlowerEdges, j, INC_ADD_EDGE ) ) {
324
if ( ret = AddToEdgeList( &OtherNFlowerEdges, j, INC_ADD_EDGE ) ) {
329
/* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
330
if ( pVA[i].cNumValenceElectrons == 6 && !pVA[i].cMetal && /* N, P, As */
331
NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
333
if ( pBNS->edge[j].forbidden ) {
337
if ( pBNS->edge[j].flow ) {
338
if ( ret = AddToEdgeList( &SFlowerEdges, j, INC_ADD_EDGE ) ) {
345
for ( j = 0; j < at2[i].valence; j ++ ) {
346
k = at2[i].neighbor[j];
347
if ( k < i && !pBNS->edge[e=pBNS->vert[i].iedge[j]].forbidden ) {
348
if ( ret = AddToEdgeList( &AllBondEdges, e, INC_ADD_EDGE ) ) {
354
if ( forbidden_stereo_edge_mask ) {
355
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
356
for ( j = 0; j < at2[i].valence; j ++ ) {
357
if ( pBNS->edge[k = pBNS->vert[i].iedge[j]].forbidden == forbidden_stereo_edge_mask ) {
358
int nMinRingSize = is_bond_in_Nmax_memb_ring( at2, i, j, pStruct->pbfsq->q,
359
pStruct->pbfsq->nAtomLevel,
360
pStruct->pbfsq->cSource, 99 /* max ring size */ );
361
if ( 0 < nMinRingSize && (ret = AddToEdgeList( &FixedLargeRingStereoEdges, k, INC_ADD_EDGE ))) {
370
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
374
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
380
if ( !pc2i->bHasDifference ||
381
!pc2i->len_c2at && pc2i->nNumTgRevrs == pc2i->nNumTgInChI &&
382
pc2i->nNumEndpRevrs == pc2i->nNumRemHInChI &&
383
pc2i->nNumEndpRevrs == pc2i->nNumEndpInChI &&
384
!pc2i->nNumTgDiffMinus && !pc2i->nNumTgDiffH ) {
385
goto exit_function; /* nothing to do */
388
/*goto exit_function;*/ /* debug only*/
390
if ( pc2i->len_c2at >= 2 ) {
391
/*----------------------------------------------------*/
392
/* case 01: restored: O=AB-O(-) original: (-)O-AB=O */
393
/* FixH: 0 -1 -1 0 */
395
/* non-taut non-taut */
396
/* O = O, S, Se; charged atoms O are not tautomeric */
397
/* Solution: move (-) from B-O(-) to O=A */
398
/*----------------------------------------------------*/
399
int num_DB_O = 0, num_SB_O_Minus = 0, iat;
400
short iat_DB_O[MAX_DIFF_FIXH], iat_SB_O_Minus[MAX_DIFF_FIXH];
402
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
403
iat = pc2i->c2at[i].atomNumber;
404
if ( pc2i->c2at[i].nValElectr == 6 /* && !pc2i->c2at[i].endptInChI -- mod#1*/ &&
405
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
406
if ( /* orig. InChI info: */
407
num_SB_O_Minus < MAX_DIFF_FIXH &&
408
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
409
/* reversed structure info: */
410
pc2i->c2at[i].nFixHRevrs == -1 && pc2i->c2at[i].nMobHRevrs == 1 &&
411
pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H && /* at2 is Fixed-H */
412
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 ) {
413
iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
414
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
418
if ( /* orig. InChI info: */
419
num_DB_O < MAX_DIFF_FIXH &&
420
pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 &&
421
/* reversed structure info: */
422
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
423
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
424
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
425
iat_DB_O[num_DB_O ++] = iat;
426
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
432
if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O ) ) {
433
/* detected; attempt to fix */
434
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
435
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
437
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
438
iat = iat_SB_O_Minus[i];
439
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
442
pv1 = pBNS->vert + (v1 = pe->neighbor1);
443
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
445
pe->forbidden |= forbidden_edge_mask;
446
pe->flow -= delta; /* remove (-) from AB-O(-) */
447
pv1->st_edge.flow -= delta;
448
pv2->st_edge.flow -= delta;
449
pBNS->tot_st_flow -= 2*delta;
451
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
452
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
454
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
455
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
456
/* Added (-)charge to O=AB => nDeltaCharge == -1 */
457
/* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
458
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
461
cur_success ++; /* 01 */
464
pe->forbidden &= forbidden_edge_mask_inv;
466
pv1->st_edge.flow += delta;
467
pv2->st_edge.flow += delta;
468
pBNS->tot_st_flow += 2*delta;
472
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
473
CurrEdges.num_edges = 0; /* clear current edge list */
476
tot_succes += cur_success;
477
/* recalculate InChI from the structure */
478
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
479
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
482
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
485
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
486
goto exit_function; /* no fixed-H found */
488
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
491
if ( !pc2i->bHasDifference ) {
492
goto exit_function; /* nothing to do */
497
if ( pc2i->len_c2at >= 1 ) {
498
/*--------------------------------------------------------------*/
499
/* case 02: restored: -O(+)=AB-NH2 original: -O-AB=NH2(+) */
502
/* O = P, As, Sb, O, S, Se, F, Cl, Br, I; not taut. in InChI */
503
/* N = N, O, S, Se, Te; has H; tautomeric or not tautomeric */
504
/* Solution: move (+) from O(+) to NH2 */
505
/*--------------------------------------------------------------*/
506
int num_DB_O_Plus = 0, num_SB_NH = 0, iat;
507
short iat_DB_O_Plus[MAX_DIFF_FIXH], iat_SB_NH[MAX_DIFF_FIXH];
508
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
509
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
510
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : NULL;
513
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
514
iat = pc2i->c2at[i].atomNumber;
515
if ( /* orig. InChI info: =NH2(+), =OH(+) */
516
num_SB_NH < MAX_DIFF_FIXH &&
517
(pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1 ||
518
pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
519
/*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */
520
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
521
pc2i->c2at[i].nFixHInChI>0 /*== 1 --modification#2*/ && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
522
/* reversed structure info: */
523
pc2i->c2at[i].nFixHRevrs == 0 && /* pc2i->c2at[i].nMobHRevrs == 0 &&*/
524
pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
525
at2[iat].valence == at2[iat].chem_bonds_valence ) {
526
iat_SB_NH[num_SB_NH ++] = iat;
527
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
532
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
533
iat = nCanon2AtnoRevrs[i];
534
if ( /* in restored atom: charge=+1, no H, has double bond, P, As, O, S, Se, Te, F, Cl, Br, I */
535
num_DB_O_Plus < MAX_DIFF_FIXH &&
536
at2[iat].charge == 1 && !at2[iat].num_H &&
537
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
538
(pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 ||
539
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1) &&
540
/* in orig.InChI: not an endpoint, has no H */
541
!pStruct->endpoint[i] &&
542
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
543
!(nMobHInChI && nMobHInChI[i] ) &&
545
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
546
iat_DB_O_Plus[num_DB_O_Plus ++] = iat;
547
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
552
if ( num_try = inchi_min( num_DB_O_Plus, num_SB_NH ) ) {
553
/* detected; attempt to fix */
554
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
555
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
558
for ( i = 0; i < num_SB_NH && cur_success < num_try; i ++ ) {
560
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
563
pv1 = pBNS->vert + (v1 = pe->neighbor1);
564
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
566
pe->forbidden |= forbidden_edge_mask;
568
pv1->st_edge.flow -= delta;
569
pv2->st_edge.flow -= delta;
570
pBNS->tot_st_flow -= 2*delta;
572
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
573
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
575
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
576
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
577
/* Removed charge from O(+) => nDeltaCharge == -1 */
578
/* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
579
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
582
cur_success ++; /* 02 */
585
num_zero_ret += !ret;
586
pe->forbidden &= forbidden_edge_mask_inv;
588
pv1->st_edge.flow += delta;
589
pv2->st_edge.flow += delta;
590
pBNS->tot_st_flow += 2*delta;
594
if ( num_zero_ret == num_try && !bAllowedNFlowerEdges && NFlowerEdges.num_edges ) {
595
RemoveForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask );
596
bAllowedNFlowerEdges = 1;
597
goto repeat_02_allow_NV;
599
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
600
bAllowedNFlowerEdges = 0;
602
CurrEdges.num_edges = 0; /* clear current edge list */
604
tot_succes += cur_success;
605
/* recalculate InChI from the structure */
606
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
607
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
610
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
613
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
614
goto exit_function; /* no fixed-H found */
616
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
619
if ( !pc2i->bHasDifference ) {
620
goto exit_function; /* nothing to do */
625
if ( pc2i->len_c2at >= 1 && pc2i->nNumTgRevrs == 1 &&
626
(pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1) /* ADP in Revrs */ ) {
627
/*--------------------------------------------------------------*/
628
/* case 03: restored: -N(-)-AB=O original: -N=AB-O(-) */
631
/* O = O, S, Se; N = N; */
632
/* restored atoms are tautomeric; original atoms are not taut. */
633
/* restored struct has 1 t-group; original has less endpoints */
634
/* and possibly >1 t-groups */
635
/* Solution: move (-) from N(-) to =O */
636
/* these atoms are tautomeric in restored structure */
637
/*--------------------------------------------------------------*/
638
int num_SB_N_Minus = 0, num_DB_O = 0, iat;
639
short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
640
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
641
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
642
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
644
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
645
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
648
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
649
iat = pc2i->c2at[i].atomNumber;
650
if ( /* orig. InChI info: -O(-) */
651
num_DB_O < MAX_DIFF_FIXH &&
652
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
653
!pc2i->c2at[i].endptInChI &&
654
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
655
pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 &&
656
/* reversed structure info: */
657
pc2i->c2at[i].endptRevrs &&
658
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
659
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
660
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
661
iat_DB_O[num_DB_O ++] = iat;
662
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
667
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
668
iat = nCanon2AtnoRevrs[i];
669
if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */
670
num_SB_N_Minus < MAX_DIFF_FIXH &&
671
at2[iat].charge == -1 && /*!at2[iat].num_H &&*/
672
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
673
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
674
at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
675
/* in orig.InChI: not an endpoint, has no H */
676
/* !pStruct->endpoint[i] && */
678
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
679
!(nMobHInChI && nMobHInChI[i] ) &&
682
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
683
iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
684
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
689
if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O ) ) {
690
/* detected; attempt to fix */
691
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
692
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
694
for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
695
iat = iat_SB_N_Minus[i];
696
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1; /* 2006-03-03: changed from CPlusGroupEdge */
699
pv1 = pBNS->vert + (v1 = pe->neighbor1);
700
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
702
pe->forbidden |= forbidden_edge_mask;
704
pv1->st_edge.flow -= delta;
705
pv2->st_edge.flow -= delta;
706
pBNS->tot_st_flow -= 2*delta;
708
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
709
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
711
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
712
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
713
/* Added (-) charge to =O => nDeltaCharge == 1 */
714
/* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
715
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
718
cur_success ++; /* 03 */
721
pe->forbidden &= forbidden_edge_mask_inv;
723
pv1->st_edge.flow += delta;
724
pv2->st_edge.flow += delta;
725
pBNS->tot_st_flow += 2*delta;
729
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
731
CurrEdges.num_edges = 0; /* clear current edge list */
733
tot_succes += cur_success;
734
/* recalculate InChI from the structure */
735
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
736
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
739
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
742
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
743
goto exit_function; /* no fixed-H found */
745
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
748
if ( !pc2i->bHasDifference ) {
749
goto exit_function; /* nothing to do */
754
if ( pc2i->nNumTgRevrs == 1 && /* pc2i->nNumRemHInChI < 0 &&*/
755
(pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1) /* ADP in Revrs */ ) {
756
/*--------------------------------------------------------------*/
757
/* case 03a:restored: -N(-)-AB=O original: -N=AB-O(-) */
760
/* O = O, S, Se; N = N; taut */
761
/* restored atoms are tautomeric; original atom is; N may be. */
762
/* restored struct has 1 t-group; original has less endpoints */
763
/* and possibly >1 t-groups */
764
/* Solution: move (-) from N(-) to =O */
765
/* these atoms are tautomeric in restored structure */
766
/*--------------------------------------------------------------*/
767
int num_SB_N_Minus = 0, num_DB_O = 0, iat;
768
short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
769
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
770
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
771
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
772
S_CHAR *pnMobHInChI = (pInChI[1] && pInChI[1]->nNum_H)? pInChI[1]->nNum_H :
773
(pInChI[0] && pInChI[0]->nNum_H)? pInChI[0]->nNum_H : NULL;
774
S_CHAR *pnFixHInChI = pStruct->fixed_H;
777
CurrEdges.num_edges = 0;
778
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
779
iat = nCanon2AtnoRevrs[i];
780
if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */
781
num_SB_N_Minus < MAX_DIFF_FIXH &&
782
at2[iat].charge == -1 && /*!at2[iat].num_H &&*/
783
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
784
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
785
at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
786
/* in orig.InChI: may be an endpoint, has no H */
788
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
789
iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
791
if ( num_DB_O < MAX_DIFF_FIXH &&
792
at2[iat].charge == 0 && /*!at2[iat].num_H &&*/
793
at2[iat].valence+1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
794
pVA[iat].cNumValenceElectrons == 6 &&
795
at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && /* endpoint in Reconstructed */
796
(pStruct->endpoint[i] || /* endpoint or H(+) acceptor in original */
797
pnMobHInChI && pnMobHInChI[i] == 1 && pnFixHInChI && pnFixHInChI[i] == -1 ) &&
799
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
800
iat_DB_O[num_DB_O ++] = iat;
801
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
806
if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O ) ) {
807
/* detected; attempt to fix */
808
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
809
/* allow charge transfer to all found =O */
810
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
812
for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
813
iat = iat_SB_N_Minus[i];
814
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
817
pv1 = pBNS->vert + (v1 = pe->neighbor1);
818
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
820
pe->forbidden |= forbidden_edge_mask;
822
pv1->st_edge.flow -= delta;
823
pv2->st_edge.flow -= delta;
824
pBNS->tot_st_flow -= 2*delta;
826
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
827
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
829
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
830
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
831
/* Added (-) charge to =O => nDeltaCharge == 1 */
832
/* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
833
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
836
cur_success ++; /* 03a */
839
pe->forbidden &= forbidden_edge_mask_inv;
841
pv1->st_edge.flow += delta;
842
pv2->st_edge.flow += delta;
843
pBNS->tot_st_flow += 2*delta;
847
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
849
CurrEdges.num_edges = 0; /* clear current edge list */
851
tot_succes += cur_success;
852
/* recalculate InChI from the structure */
853
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
854
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
857
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
860
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
861
goto exit_function; /* no fixed-H found */
863
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
866
if ( !pc2i->bHasDifference ) {
867
goto exit_function; /* nothing to do */
872
if ( pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 && /* ADP in InChI */
873
(pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
874
/*--------------------------------------------------------------*/
875
/* case 04: restored: OH(+)=AB-O- OH- orig. HO-AB=O(+)- OH- */
876
/* FixH: 1 0 0 1 0 1 */
877
/* MobH: 0 0 1 0 0 0 */
878
/* non-taut. taut taut */
879
/* ADP: one t-group or more endpoints */
880
/* O(+) = N, P, As, As, O, S, Se; OH = N, O, S, Se, Te */
881
/* Solution: move (+) from O(+) to NH2 */
882
/*--------------------------------------------------------------*/
883
int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
884
short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
885
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
886
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
887
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
889
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
890
iat = nCanon2AtnoRevrs[i];
891
if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */
892
num_DB_Charged < MAX_DIFF_FIXH &&
893
at2[iat].charge == 1 && at2[iat].num_H &&
894
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
895
(pVA[iat].cNumValenceElectrons == 6 ||
896
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) &&
897
/* in orig.InChI: an endpoint, has fixed-H */
898
pStruct->endpoint[i] &&
899
(pStruct->fixed_H && pStruct->fixed_H[i]) &&
900
/*!(nMobHInChI && nMobHInChI[i] ) &&*/
902
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
904
iat_DB_Charged[num_DB_Charged ++] = iat;
906
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
910
if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */
911
num_SB_Neutr < MAX_DIFF_FIXH &&
912
at2[iat].charge == 0 && !at2[iat].num_H &&
913
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
914
(pVA[iat].cNumValenceElectrons == 6 ||
915
pVA[iat].cNumValenceElectrons == 5 ) &&
916
/* in orig.InChI: an endpoint, has fixed-H */
917
/* pStruct->endpoint[i] && */
918
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
919
!(nMobHInChI && nMobHInChI[i] ) &&
921
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 &&
922
0 == pBNS->edge[e].forbidden ) {
924
iat_SB_Neutr[num_SB_Neutr ++] = iat;
926
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
931
if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
932
/* detected; attempt to fix */
933
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
934
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
936
for ( i = 0; i < num_SB_Neutr && cur_success < num_try; i ++ ) {
937
iat = iat_SB_Neutr[i];
938
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
941
pv1 = pBNS->vert + (v1 = pe->neighbor1);
942
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
944
pe->forbidden |= forbidden_edge_mask;
946
pv1->st_edge.flow -= delta;
947
pv2->st_edge.flow -= delta;
948
pBNS->tot_st_flow -= 2*delta;
950
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
951
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
953
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
954
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
955
/* Removed charge from O(+) => nDeltaCharge == -1 */
956
/* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
957
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
960
cur_success ++; /* 04 */
963
pe->forbidden &= forbidden_edge_mask_inv;
965
pv1->st_edge.flow += delta;
966
pv2->st_edge.flow += delta;
967
pBNS->tot_st_flow += 2*delta;
971
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
973
CurrEdges.num_edges = 0; /* clear current edge list */
975
tot_succes += cur_success;
976
/* recalculate InChI from the structure */
977
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
978
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
981
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
984
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
985
goto exit_function; /* no fixed-H found */
987
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
990
if ( !pc2i->bHasDifference ) {
991
goto exit_function; /* nothing to do */
996
if ( pc2i->len_c2at > 1 ) {
997
/*--------------------------------------------------------------*/
998
/* case 05: restored: O=AB-NH original:(-)O-AB=NH(+) */
1001
/* O = O, S, Se; N = N, O, S, Se, Te; all atoms not tautomeric */
1002
/* Solution: Separate charges */
1003
/*--------------------------------------------------------------*/
1004
int num_DB_O = 0, num_SB_NH = 0, iat;
1005
short iat_DB_O[MAX_DIFF_FIXH], iat_SB_NH[MAX_DIFF_FIXH];
1007
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1008
iat = pc2i->c2at[i].atomNumber;
1009
if ( /* orig. InChI info: =NH2(+), =OH(+) */
1010
num_SB_NH < MAX_DIFF_FIXH &&
1011
(pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1 ||
1012
pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
1013
!pc2i->c2at[i].endptInChI &&
1014
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
1015
pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
1016
/* reversed structure info: */
1017
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs &&
1018
pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
1019
!pc2i->c2at[i].endptRevrs &&
1020
at2[iat].valence == at2[iat].chem_bonds_valence ) {
1021
iat_SB_NH[num_SB_NH ++] = iat;
1022
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1026
if ( /* orig. InChI info: -O(-) */
1027
num_DB_O < MAX_DIFF_FIXH &&
1028
(pc2i->c2at[i].nValElectr == 6 ) /* O, S, Se, Te */ &&
1029
!pc2i->c2at[i].endptInChI &&
1030
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
1031
pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 &&
1032
/* reversed structure info: */
1033
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
1034
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
1035
!pc2i->c2at[i].endptRevrs &&
1036
at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
1037
iat_DB_O[num_DB_O ++] = iat;
1038
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1043
if ( num_try = inchi_min( num_DB_O, num_SB_NH ) ) {
1044
/* detected; attempt to fix */
1045
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1046
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
1048
for ( i = 0; i < num_SB_NH && cur_success < num_try; i ++ ) {
1050
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
1053
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1054
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1056
pe->forbidden |= forbidden_edge_mask;
1058
pv1->st_edge.flow -= delta;
1059
pv2->st_edge.flow -= delta;
1060
pBNS->tot_st_flow -= 2*delta;
1062
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1063
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1065
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1066
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
1067
/* Added charge to =O => nDeltaCharge == 1 */
1068
/* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
1069
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1072
cur_success ++; /* 05 */
1075
pe->forbidden &= forbidden_edge_mask_inv;
1077
pv1->st_edge.flow += delta;
1078
pv2->st_edge.flow += delta;
1079
pBNS->tot_st_flow += 2*delta;
1083
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1085
CurrEdges.num_edges = 0; /* clear current edge list */
1086
if ( cur_success ) {
1087
tot_succes += cur_success;
1088
/* recalculate InChI from the structure */
1089
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1090
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1093
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1096
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1097
goto exit_function; /* no fixed-H found */
1099
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1102
if ( !pc2i->bHasDifference ) {
1103
goto exit_function; /* nothing to do */
1108
if ( pStruct->fixed_H && pStruct->endpoint && pc2i->nChargeFixHInChI > 0 && pc2i->nChargeFixHInChI > pc2i->nChargeMobHInChI ) {
1109
/*----------------------------------------------------------*/
1110
/* case 06c: restored -NH- or -NH(+) orig: -NH- */
1112
/* Mobile-H 0 0 1 */
1113
/* not tautomeric not tautomeric */
1114
/* has adjacent (+) */
1116
/* Solution: move (+) charges to the -NH- unless it already*/
1117
/* N = N, O, S, Se, Te */
1118
/* has (+) charge blocked by adjacent (+) */
1119
/*----------------------------------------------------------*/
1121
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1123
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1124
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1125
inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
1126
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
1127
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
1128
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1129
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : NULL;
1131
EDGE_LIST CurChargeEdges;
1134
AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
1135
CurrEdges.num_edges = 0;
1136
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1137
/* atoms -NH- from which H(+) were removed by the Normalization in orig. InChI */
1138
iat = pc2i->c2at[i].atomNumber;
1139
if ( (pc2i->c2at[i].nValElectr == 6 ||
1140
pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
1141
!pc2i->c2at[i].endptInChI &&
1142
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
1143
if ( /* orig. InChI info: -NH- */
1144
pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 &&
1145
/* reversed structure info: */
1146
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 1 && /* was not removed */
1147
/*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ at2[iat].num_H && /* at2 is Fixed-H */
1148
at2[iat].valence == at2[iat].chem_bonds_valence ) {
1149
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1155
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
1156
/* find adjacent charged atoms */
1157
iat = nCanon2AtnoRevrs[i];
1158
if ( pStruct->endpoint[i] || at2[iat].charge != 1 || at2[iat].radical || pVA[iat].cMetal ) {
1161
if ( 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow && pVA[iat].cNumValenceElectrons >= 5 ) {
1162
/* positively charged atom */
1163
for ( j = 0; j < at2[iat].valence; j ++ ) {
1164
if ( at2[k=(int)at2[iat].neighbor[j]].charge == 1 && !pVA[k].cMetal &&
1165
0 <= (e2=pVA[k].nCPlusGroupEdge-1) && !pBNS->edge[e2].forbidden && !pBNS->edge[e2].flow) {
1166
if ( 0 > FindInEdgeList( &CurrEdges, e ) &&
1167
0 > FindInEdgeList( &CurChargeEdges, e ) &&
1168
( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) ) ) {
1171
if ( 0 > FindInEdgeList( &CurrEdges, e2 ) &&
1172
0 > FindInEdgeList( &CurChargeEdges, e2 ) &&
1173
( ret = AddToEdgeList( &CurChargeEdges, e2, INC_ADD_EDGE ) ) ) {
1180
if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
1181
/* detected; attempt to fix */
1182
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1183
RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask );
1185
for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
1186
e = CurrEdges.pnEdges[i];
1187
pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
1190
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1191
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1193
pe->flow -= delta; /* add (+) to -NHm */
1194
pv1->st_edge.flow -= delta;
1195
pv2->st_edge.flow -= delta;
1196
pBNS->tot_st_flow -= 2*delta;
1198
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1199
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1201
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1202
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
1203
/* Removed (+)charge from -NH- => nDeltaCharge == -1 */
1204
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
1205
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1208
cur_success ++; /* 06c */
1212
pv1->st_edge.flow += delta;
1213
pv2->st_edge.flow += delta;
1214
pBNS->tot_st_flow += 2*delta;
1218
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1221
CurrEdges.num_edges = 0; /* clear current edge list */
1222
AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
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 ) ) {
1236
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1237
goto exit_function; /* no fixed-H found */
1239
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1242
if ( !pc2i->bHasDifference ) {
1243
goto exit_function; /* nothing to do */
1248
if ( pc2i->len_c2at >= 2 ) {
1249
/*------------------------------------------------------------*/
1250
/* case 06d: restored: XH(+)=-AB-NH orig.: XH-=AB=NH(+) */
1251
/* FixH: 1 1 0 0 1 1 */
1252
/* MobH: 0 taut 1 1 taut 0 */
1255
/* N = N, O, S, Se; atoms N are not tautomeric in orig InChI */
1256
/* X = N, O, S, Se, Te, F, Cl, Br, I; atom X is non-taut */
1257
/* Solution: move (+) from X to NH */
1258
/*------------------------------------------------------------*/
1261
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1262
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1263
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1264
inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
1265
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
1266
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds :
1267
pStruct->pOne_norm_data[TAUT_NON]->at;
1268
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1269
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
1271
EDGE_LIST CurChargeEdges;
1273
AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
1274
CurrEdges.num_edges = 0;
1275
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1276
iat = pc2i->c2at[i].atomNumber;
1278
if ( /* reconstructed: non-taut and (+) */
1279
(pc2i->c2at[i].nMobHRevrs+1 == pc2i->c2at[i].nFixHRevrs &&
1280
pc2i->c2at[i].nFixHRevrs > 0 && !pc2i->c2at[i].endptRevrs &&
1281
pc2i->c2at[i].nAtChargeRevrs == 1 &&
1282
/* original InChI: non-taut & has H or an endpoint, has Fixed H */
1283
(!pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].nMobHInChI == pc2i->c2at[i].nFixHRevrs ||
1284
pc2i->c2at[i].nFixHInChI == pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].endptInChI )) &&
1285
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow) {
1287
if (ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE )) {
1292
if ( /* original InChI: has H and is not an endpoint */
1293
(pc2i->c2at[i].nMobHInChI+1 == pc2i->c2at[i].nFixHInChI &&
1294
pc2i->c2at[i].nFixHInChI > 0 && !pc2i->c2at[i].endptInChI &&
1295
pc2i->c2at[i].nAtChargeRevrs == 0 &&
1296
/* reconstructed InChI: non-taut & has H or an endpoint, has Fixed H */
1297
(!pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs == pc2i->c2at[i].nFixHInChI ||
1298
pc2i->c2at[i].nFixHRevrs == pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].endptRevrs )) &&
1299
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden &&
1300
pBNS->edge[e].flow) {
1302
if (ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE )) {
1307
if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
1308
/* detected; attempt to fix */
1309
int bSFlowerEdgesMayBeForbidden = (SFlowerEdges.num_edges > 0);
1310
int bSFlowerEdgesIsForbidden;
1311
for ( bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden;
1312
0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden -- ) {
1313
if ( bSFlowerEdgesIsForbidden ) {
1314
/* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */
1315
SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
1317
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1318
RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask );
1320
for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
1321
e = CurrEdges.pnEdges[i];
1322
pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
1325
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1326
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1328
pe->flow -= delta; /* add (+) to -NHm */
1329
pv1->st_edge.flow -= delta;
1330
pv2->st_edge.flow -= delta;
1331
pBNS->tot_st_flow -= 2*delta;
1333
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1334
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1336
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1337
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
1338
/* Removed (+)charge from -NH- => nDeltaCharge == -1 */
1339
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
1340
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1343
cur_success ++; /* 06d */
1347
pv1->st_edge.flow += delta;
1348
pv2->st_edge.flow += delta;
1349
pBNS->tot_st_flow += 2*delta;
1353
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1354
RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
1359
CurrEdges.num_edges = 0; /* clear current edge list */
1360
AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
1361
if ( cur_success ) {
1362
tot_succes += cur_success;
1363
/* recalculate InChI from the structure */
1364
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1365
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1368
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1371
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1372
goto exit_function; /* no fixed-H found */
1374
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1377
if ( !pc2i->bHasDifference ) {
1378
goto exit_function; /* nothing to do */
1384
if ( pc2i->len_c2at >= 2 ) {
1385
/*--------------------------------------------------------*/
1386
/* case 06: restored: NHn(+)=AB-NHm orig.: NHn-AB=NHm(+) */
1388
/* MobH: n-1 m n m-1 */
1389
/* N = N, O, S, Se; atoms N are not tautomeric */
1390
/* Solution: move (+) from NHn(+) to NHn */
1391
/*--------------------------------------------------------*/
1392
int num_DB_NHn_Plus = 0, num_SB_NHm_Neutr = 0, iat;
1393
short iat_DB_NHn_Plus[MAX_DIFF_FIXH], iat_SB_NHm_Neutr[MAX_DIFF_FIXH];
1395
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1396
iat = pc2i->c2at[i].atomNumber;
1397
if ( (pc2i->c2at[i].nValElectr == 6 ||
1398
pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
1399
!pc2i->c2at[i].endptInChI &&
1400
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
1401
if ( /* orig. InChI info: NHm */
1402
num_SB_NHm_Neutr < MAX_DIFF_FIXH &&
1403
pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI == 0 &&*/
1404
/* reversed structure info: */
1405
pc2i->c2at[i].nFixHRevrs == 0 && /*pc2i->c2at[i].nMobHRevrs == 1 &&*/
1406
pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && /* at2 is Fixed-H */
1407
at2[iat].valence == at2[iat].chem_bonds_valence ) {
1408
iat_SB_NHm_Neutr[num_SB_NHm_Neutr ++] = iat;
1409
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1413
if ( /* orig. InChI info: */
1414
num_DB_NHn_Plus < MAX_DIFF_FIXH &&
1415
pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI &&*/
1416
/* reversed structure info: */
1417
pc2i->c2at[i].nFixHRevrs == 1 && /*pc2i->c2at[i].nMobHRevrs == 0 &&*/
1418
pc2i->c2at[i].nAtChargeRevrs == 1 && at2[iat].num_H &&
1419
at2[iat].valence < at2[iat].chem_bonds_valence ) {
1420
iat_DB_NHn_Plus[num_DB_NHn_Plus ++] = iat;
1421
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1427
if ( num_try = inchi_min( num_SB_NHm_Neutr, num_DB_NHn_Plus ) ) {
1428
/* detected; attempt to fix */
1429
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1430
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
1432
for ( i = 0; i < num_SB_NHm_Neutr && cur_success < num_try; i ++ ) {
1433
iat = iat_SB_NHm_Neutr[i];
1434
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
1437
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1438
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1440
pe->forbidden |= forbidden_edge_mask;
1441
pe->flow -= delta; /* add (+) to -NHm */
1442
pv1->st_edge.flow -= delta;
1443
pv2->st_edge.flow -= delta;
1444
pBNS->tot_st_flow -= 2*delta;
1446
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1447
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1449
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1450
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
1451
/* Removed (+)charge from -NHn => nDeltaCharge == -1 */
1452
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
1453
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1456
cur_success ++; /* 06 */
1459
pe->forbidden &= forbidden_edge_mask_inv;
1461
pv1->st_edge.flow += delta;
1462
pv2->st_edge.flow += delta;
1463
pBNS->tot_st_flow += 2*delta;
1467
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1469
CurrEdges.num_edges = 0; /* clear current edge list */
1470
if ( cur_success ) {
1471
tot_succes += cur_success;
1472
/* recalculate InChI from the structure */
1473
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1474
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1477
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1480
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1481
goto exit_function; /* no fixed-H found */
1483
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1486
if ( !pc2i->bHasDifference ) {
1487
goto exit_function; /* nothing to do */
1492
if ( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1 ||
1493
pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) &&
1494
pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons &&
1495
pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
1496
/*----------------------------------------------------------*/
1497
/* case 06a: restored: N'(+)=-AB-NH orig.: N'-=AB=NH(+) */
1500
/* single t-group multiple t-groups */
1501
/* N = N, O, S, Se; atoms N are not tautomeric */
1502
/* N' = N atom N' is not tautomeric */
1503
/* Solution: move (+) from N' to NH */
1504
/*----------------------------------------------------------*/
1506
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1508
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1509
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1511
inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
1512
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
1513
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
1514
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1515
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
1516
EDGE_LIST CurChargeEdges;
1518
AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
1519
CurrEdges.num_edges = 0;
1520
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
1521
iat = nCanon2AtnoRevrs[i];
1522
if ( pStruct->endpoint[i] ) {
1526
if ( pStruct->fixed_H[i] && !nMobHInChI[i] &&
1527
at2[iat].charge == 0 && at2[iat].radical == 0 &&
1528
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
1529
(ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) {
1533
if ( at2[iat].charge == 1 && !at2[iat].num_H &&
1534
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
1535
atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 0 &&
1536
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow &&
1537
(ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ))) {
1541
if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
1542
/* detected; attempt to fix */
1543
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1544
RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask );
1546
for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
1547
e = CurrEdges.pnEdges[i];
1548
pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
1551
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1552
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1554
pe->flow -= delta; /* add (+) to -NHm */
1555
pv1->st_edge.flow -= delta;
1556
pv2->st_edge.flow -= delta;
1557
pBNS->tot_st_flow -= 2*delta;
1559
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1560
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1562
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1563
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
1564
/* Removed (+)charge from -NH- => nDeltaCharge == -1 */
1565
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
1566
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1569
cur_success ++; /* 06a */
1573
pv1->st_edge.flow += delta;
1574
pv2->st_edge.flow += delta;
1575
pBNS->tot_st_flow += 2*delta;
1579
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1582
CurrEdges.num_edges = 0; /* clear current edge list */
1583
AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
1584
if ( cur_success ) {
1585
tot_succes += cur_success;
1586
/* recalculate InChI from the structure */
1587
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1588
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1591
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1594
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1595
goto exit_function; /* no fixed-H found */
1597
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1600
if ( !pc2i->bHasDifference ) {
1601
goto exit_function; /* nothing to do */
1605
if ( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1 ||
1606
pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) &&
1607
(pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons ||
1608
pStruct->nNumRemovedProtonsMobHInChI > pStruct->One_ti.tni.nNumRemovedProtons ) &&
1609
pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
1610
/*----------------------------------------------------------*/
1611
/* case 06b: restored: X(+)=-AB-NH orig.: X-=AB=NH(+) */
1612
/* FixH: 0 1 1 0 1 */
1613
/* MobH: 0 0 t 0 0 */
1614
/* single t-group multiple t-groups */
1615
/* or no t-groupd */
1616
/* N = N, O, S, Se; atoms N are not tautomeric */
1617
/* X = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/
1618
/* Solution: move (+) from X to NH */
1619
/*----------------------------------------------------------*/
1621
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1623
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1624
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1626
inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
1627
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
1628
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
1629
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1630
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
1631
EDGE_LIST CurChargeEdges;
1633
AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
1634
CurrEdges.num_edges = 0;
1635
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
1636
iat = nCanon2AtnoRevrs[i];
1637
if ( pStruct->endpoint[i] ) {
1641
if ( pStruct->fixed_H[i] && !nMobHInChI[i] &&
1642
at2[iat].charge == 0 && at2[iat].radical == 0 &&
1643
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
1644
(ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) {
1648
if ( at2[iat].charge == 1 && !at2[iat].num_H &&
1649
(pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cPeriodicRowNumber == 7) &&
1650
atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 1 &&
1651
0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow &&
1652
(ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ))) {
1656
if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
1657
/* detected; attempt to fix */
1658
int bSFlowerEdgesMayBeForbidden = (SFlowerEdges.num_edges > 0);
1659
int bSFlowerEdgesIsForbidden;
1660
for ( bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden;
1661
0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden -- ) {
1662
if ( bSFlowerEdgesIsForbidden ) {
1663
/* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */
1664
SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
1666
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1667
RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask );
1669
for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
1670
e = CurrEdges.pnEdges[i];
1671
pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
1674
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1675
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1677
pe->flow -= delta; /* add (+) to -NHm */
1678
pv1->st_edge.flow -= delta;
1679
pv2->st_edge.flow -= delta;
1680
pBNS->tot_st_flow -= 2*delta;
1682
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1683
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1685
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1686
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
1687
/* Removed (+)charge from -NH- => nDeltaCharge == -1 */
1688
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
1689
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1692
cur_success ++; /* 06b */
1696
pv1->st_edge.flow += delta;
1697
pv2->st_edge.flow += delta;
1698
pBNS->tot_st_flow += 2*delta;
1702
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1703
RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
1708
CurrEdges.num_edges = 0; /* clear current edge list */
1709
AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
1710
if ( cur_success ) {
1711
tot_succes += cur_success;
1712
/* recalculate InChI from the structure */
1713
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1714
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1717
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1720
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1721
goto exit_function; /* no fixed-H found */
1723
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1726
if ( !pc2i->bHasDifference ) {
1727
goto exit_function; /* nothing to do */
1734
if ( pc2i->nNumTgInChI > 1 &&
1735
(pStruct->nNumRemovedProtonsMobHInChI > 0 || pStruct->ti.tni.nNumRemovedProtons > 0 ) &&
1736
pStruct->fixed_H && pStruct->endpoint &&
1737
pStruct->pOne_norm_data[TAUT_YES] && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
1738
/*----------------------------------------------------------*/
1739
/* case 06e:restored: XHn(+)=-AB-YHm orig.: XHn-=AB=YHm(+) */
1742
/* non-taut atoms multiple t-groups */
1744
/* 1. orig. t-group has more H on its endpoints counted */
1745
/* in atf and has no (+) on endpoint that has H */
1746
/* 2. orig. t-group has less H on its endpoints counted */
1747
/* in atf and has (+) on endpoint that has H */
1748
/* in reconstructed struct and less H in atf */
1749
/* Solution: move (+) from (2) to atom in (1) that has H */
1751
/* tg1 reconstr: XHn and more H than in orig t-group */
1753
/* tg2 reconstr: XHm(+) and less H than in */
1754
/* atf: XH(m-1) orig in t-group */
1756
/* N = N, O, S, Se; atoms N are not tautomeric */
1757
/* X = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/
1758
/* Solution: move (+) from X to NH */
1759
/*----------------------------------------------------------*/
1761
int iat, nNumWrongTg, jjoffs, jj, nNum2RemovePlus, nNum2AddPlus, nNum2MovePlus;
1762
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1764
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1765
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1767
inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
1768
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
1769
pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds :
1770
pStruct->pOne_norm_data[TAUT_YES] &&
1771
pStruct->pOne_norm_data[TAUT_YES]->at?
1772
pStruct->pOne_norm_data[TAUT_YES]->at : NULL;
1774
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1775
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
1777
EDGE_LIST CurChargeEdges /* source of (+)*/, EndpList;
1778
TgDiffHChgFH tdhc[MAX_DIFF_FIXH];
1779
BNS_VERTEX *pv1n, *pv2n;
1780
BNS_EDGE *pe1n, *pe2n;
1784
AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
1785
AllocEdgeList( &EndpList, EDGE_LIST_CLEAR );
1786
CurrEdges.num_edges = 0; /* receptors of (+) */
1787
if ( !atfMobile_H_Revrs ) {
1790
nNumWrongTg = FillTgDiffHChgFH( tdhc, MAX_DIFF_FIXH, at2, atfMobile_H_Revrs,
1791
nCanon2AtnoRevrs, pVA, &pStruct->ti, &EndpList );
1792
if ( nNumWrongTg < 1 ) {
1793
goto exit_case_06e; /* for now only transfer (+) from one Mobile-H group to another */
1795
nNum2RemovePlus = nNum2AddPlus = nNum2MovePlus = 0;
1796
for ( i = 0; i < nNumWrongTg; i ++ ) {
1797
/* detect t-group that has extra (+) on H */
1798
if ( tdhc[i].nNumHInchi > tdhc[i].nNumHNorml &&
1799
tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH] ) {
1800
/* count how many (+) to remove */
1801
/* store XH(+) atom numbers */
1802
int nNumNeeded = inchi_min( tdhc[i].nNumHInchi-tdhc[i].nNumHNorml, tdhc[i].n[fNumRPosChgH]);
1803
nNum2RemovePlus += nNumNeeded;
1804
jjoffs = tdhc[i].i[ fNumRPosChgH ];
1805
for ( jj = 0; jj < tdhc[i].n[fNumRPosChgH]; jj ++ ) {
1806
iat = EndpList.pnEdges[ jjoffs + jj ];
1807
e = pVA[iat].nCPlusGroupEdge-1;
1808
if ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) ) {
1813
/* detect t-group that needs (+) on XH to reduce number of H */
1814
if ( tdhc[i].nNumHInchi < tdhc[i].nNumHNorml && tdhc[i].n[fNumRNeutrlH] ) {
1815
/* store XH atom numbers */
1816
int nNumNeeded = inchi_min( tdhc[i].nNumHNorml-tdhc[i].nNumHInchi, tdhc[i].n[fNumRNeutrlH]);
1817
nNum2AddPlus += nNumNeeded;
1818
jjoffs = tdhc[i].i[ fNumRNeutrlH ];
1819
for ( jj = 0; jj < tdhc[i].n[fNumRNeutrlH]; jj ++ ) {
1820
iat = EndpList.pnEdges[ jjoffs + jj ];
1821
e = pVA[iat].nCPlusGroupEdge-1;
1822
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1828
nNum2MovePlus = inchi_min( nNum2RemovePlus, nNum2AddPlus );
1829
if ( CurrEdges.num_edges > 0 && CurChargeEdges.num_edges > 0 ) {
1830
for ( i = 0; 0 < nNum2MovePlus && i < nNumWrongTg; i ++ ) {
1831
/* detect t-group that has extra (+) on H */
1832
if ( tdhc[i].nNumHInchi > tdhc[i].nNumHNorml &&
1833
tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH] ) {
1834
int nNum2Remove = tdhc[i].nNumHInchi - tdhc[i].nNumHNorml;
1835
if ( nNum2Remove < tdhc[i].n[fNumRPosChgH] ) {
1836
nNum2Remove = tdhc[i].n[fNumRPosChgH];
1838
/* store XH(+) atom numbers */
1839
jjoffs = tdhc[i].i[ fNumRPosChgH ];
1840
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1841
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
1842
for ( jj = 0; 0 < nNum2MovePlus && 0 < nNum2Remove && jj < tdhc[i].n[fNumRPosChgH]; jj ++ ) {
1843
iat = EndpList.pnEdges[ jjoffs + jj ];
1844
e = pVA[iat].nCPlusGroupEdge-1;
1845
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
1848
pv1 = pBNS->vert + (v1 = pe->neighbor1);
1849
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1851
for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
1852
pe1n = pBNS->edge + pv1->iedge[j];
1853
if ( pe1n->flow && !pe1n->forbidden ) {
1854
pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
1859
continue; /* not found */
1861
for ( j = pv2->num_adj_edges-2; 0 <= j; j -- ) {
1862
pe2n = pBNS->edge + pv2->iedge[j];
1863
if ( pe2n->flow && !pe2n->forbidden ) {
1864
pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
1869
continue; /* not found */
1872
pe1n->flow -= delta;
1873
pe2n->flow -= delta;
1874
pv1n->st_edge.flow -= delta;
1875
pv2n->st_edge.flow -= delta;
1876
pBNS->tot_st_flow -= 2*delta;
1878
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1879
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1881
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
1882
vPathEnd == v2n && vPathStart == v1n) &&
1883
(nDeltaCharge == 0 || nDeltaCharge == 1) ) {
1884
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1889
cur_success ++; /* 06e */
1893
pe1n->flow += delta;
1894
pe2n->flow += delta;
1895
pv1n->st_edge.flow += delta;
1896
pv2n->st_edge.flow += delta;
1897
pBNS->tot_st_flow += 2*delta;
1899
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1903
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1908
CurrEdges.num_edges = 0; /* clear current edge list */
1909
AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
1910
AllocEdgeList( &EndpList, EDGE_LIST_FREE );
1911
if ( cur_success ) {
1912
tot_succes += cur_success;
1913
/* recalculate InChI from the structure */
1914
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1915
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1918
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1921
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
1922
goto exit_function; /* no fixed-H found */
1924
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
1927
if ( !pc2i->bHasDifference ) {
1928
goto exit_function; /* nothing to do */
1935
if ( pc2i->len_c2at >= 1 ) {
1936
/*--------------------------------------------------------------*/
1937
/* case 07: restored: O(-)-AB=O original: O=AB-O(-) */
1938
/* FixH: 0 0 0 -1 */
1940
/* taut (non-taut) (taut) non-taut */
1941
/* taut (taut) (non-taut) non-taut */
1942
/* O = O, S, Se, Te */
1943
/* Solution: move (-) from O(-)-AB to AB=O */
1944
/*--------------------------------------------------------------*/
1945
int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat;
1946
short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
1947
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1948
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
1949
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
1950
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
1951
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
1953
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1954
iat = pc2i->c2at[i].atomNumber;
1955
if ( /* orig. InChI info: -O(-), non-taut */
1956
num_DB_O_Neutr < MAX_DIFF_FIXH &&
1957
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
1958
!pc2i->c2at[i].endptInChI &&
1959
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
1960
pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 &&
1961
/* reversed structure info: */
1962
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
1963
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
1964
at2[iat].valence < at2[iat].chem_bonds_valence ) {
1965
iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
1966
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1971
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
1972
iat = nCanon2AtnoRevrs[i];
1973
if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */
1974
num_SB_O_Minus < MAX_DIFF_FIXH &&
1975
at2[iat].charge == -1 && !at2[iat].num_H &&
1976
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
1977
pVA[iat].cNumValenceElectrons == 6 &&
1978
at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
1979
/* in orig.InChI: not an endpoint, has no H */
1980
/*pStruct->endpoint[i] && -- modificatuion#1 */
1981
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
1982
!(nMobHInChI && nMobHInChI[i] ) &&
1984
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
1985
iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
1986
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
1991
if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O_Neutr ) ) {
1992
/* detected; attempt to fix */
1993
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1994
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
1996
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
1997
iat = iat_SB_O_Minus[i];
1998
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
2001
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2002
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2004
pe->forbidden |= forbidden_edge_mask;
2006
pv1->st_edge.flow -= delta;
2007
pv2->st_edge.flow -= delta;
2008
pBNS->tot_st_flow -= 2*delta;
2010
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2011
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2013
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2014
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
2015
/* Moved (-) charge to AB=O => nDeltaCharge == 1 */
2016
/* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */
2017
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2020
cur_success ++; /* 07 */
2023
pe->forbidden &= forbidden_edge_mask_inv;
2025
pv1->st_edge.flow += delta;
2026
pv2->st_edge.flow += delta;
2027
pBNS->tot_st_flow += 2*delta;
2031
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2033
CurrEdges.num_edges = 0; /* clear current edge list */
2034
if ( cur_success ) {
2035
tot_succes += cur_success;
2036
/* recalculate InChI from the structure */
2037
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2038
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2041
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2044
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2045
goto exit_function; /* no fixed-H found */
2047
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2050
if ( !pc2i->bHasDifference ) {
2051
goto exit_function; /* nothing to do */
2056
if ( pc2i->len_c2at >= 1 ) {
2057
/*--------------------------------------------------------------*/
2058
/* case 07a: restored: O(-)-N(V)B=O original: O=N(V)B-O(-) */
2059
/* FixH: 0 0 0 -1 */
2061
/* non-taut (non-taut) non-taut non-taut */
2062
/* non-taut (taut) non-taut non-taut */
2063
/* O = O, S, Se, Te */
2064
/* Solution: move (-) from O(-)-AB to AB=O */
2065
/*--------------------------------------------------------------*/
2066
int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat, iN;
2067
short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
2068
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
2069
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
2070
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
2072
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
2073
iat = pc2i->c2at[i].atomNumber;
2074
if ( /* orig. InChI info: -O(-), non-taut */
2075
num_DB_O_Neutr < MAX_DIFF_FIXH &&
2076
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
2077
!pc2i->c2at[i].endptInChI &&
2078
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
2079
pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 &&
2080
/* reversed structure info: */
2081
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
2082
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
2083
at2[iat].valence < at2[iat].chem_bonds_valence ) {
2084
iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
2085
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2090
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
2091
iat = nCanon2AtnoRevrs[i];
2092
if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */
2093
num_SB_O_Minus < MAX_DIFF_FIXH &&
2094
at2[iat].charge == -1 && !at2[iat].num_H &&
2095
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
2096
pVA[iat].cNumValenceElectrons == 6 &&
2097
/*at_Mobile_H_Revrs && !at_Mobile_H_Revrs[iat].endpoint &&*/
2098
/* in orig.InChI: not an endpoint, has no H */
2099
!pStruct->endpoint[i] &&
2100
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2101
!(nMobHInChI && nMobHInChI[i] ) &&
2102
/* has N(V) neighbor */
2103
1 == at2[iat].valence && at2[iN=at2[iat].neighbor[0]].chem_bonds_valence==5 &&
2104
!at2[iN].charge && pVA[iN].cNumValenceElectrons == 5 &&
2106
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
2107
iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
2108
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2113
if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O_Neutr ) ) {
2114
/* detected; attempt to fix */
2115
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2116
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2118
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
2119
iat = iat_SB_O_Minus[i];
2120
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
2123
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2124
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2126
pe->forbidden |= forbidden_edge_mask;
2128
pv1->st_edge.flow -= delta;
2129
pv2->st_edge.flow -= delta;
2130
pBNS->tot_st_flow -= 2*delta;
2132
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2133
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2135
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2136
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
2137
/* Moved (-) charge to AB=O => nDeltaCharge == 1 */
2138
/* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */
2139
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2142
cur_success ++; /* 07 */
2145
pe->forbidden &= forbidden_edge_mask_inv;
2147
pv1->st_edge.flow += delta;
2148
pv2->st_edge.flow += delta;
2149
pBNS->tot_st_flow += 2*delta;
2153
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2155
CurrEdges.num_edges = 0; /* clear current edge list */
2156
if ( cur_success ) {
2157
tot_succes += cur_success;
2158
/* recalculate InChI from the structure */
2159
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2160
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2163
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2166
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2167
goto exit_function; /* no fixed-H found */
2169
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2172
if ( !pc2i->bHasDifference ) {
2173
goto exit_function; /* nothing to do */
2177
if ( /*(pc2i->len_c2at >= 1 || pc2i->nNumRemHRevrs) &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */
2178
(pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
2179
/*----------------------------------------------------------------*/
2180
/* case 08: restored: O(-)-AB=N- OH- orig. O=AB-N(-)- OH- */
2181
/* FixH: 1 0 0 0 0 1 */
2182
/* MobH: 0 0 1 0 0 0 */
2183
/* may be taut or not non-taut taut taut taut */
2184
/* ADP: one t-group or more endpoints */
2185
/* O(-) = S, Se, Te; N = N; */
2186
/* Solution: move (-) from O(-) to =N-; avoid stereogenic DB on N */
2187
/*----------------------------------------------------------------*/
2188
int num_DB_N_Neutr = 0, num_SB_O_Minus = 0, iat;
2189
short iat_DB_N_Neutr[MAX_DIFF_FIXH], iat_SB_O_Minus[MAX_DIFF_FIXH];
2190
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
2191
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
2192
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
2194
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
2195
iat = nCanon2AtnoRevrs[i];
2196
if ( /* in restored atom: charge=-1, has no H, has single bond, O, S, Se, Te */
2197
num_SB_O_Minus < MAX_DIFF_FIXH &&
2198
at2[iat].charge == -1 && !at2[iat].num_H &&
2199
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
2200
pVA[iat].cNumValenceElectrons == 6 &&
2201
/* in orig.InChI: an endpoint, may have fixed-H */
2202
pStruct->endpoint[i] &&
2203
/*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/
2204
!(nMobHInChI && nMobHInChI[i] ) &&
2206
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
2208
iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
2210
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2214
if ( /* in restored atom: charge=0, has no H, has double non-stereogenic bond, N */
2215
num_DB_N_Neutr < MAX_DIFF_FIXH &&
2216
at2[iat].charge == 0 && !at2[iat].num_H && !at2[iat].sb_parity[0] &&
2217
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
2218
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
2219
/* in orig.InChI: an endpoint, has no fixed-H */
2220
pStruct->endpoint[i] &&
2221
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2222
!(nMobHInChI && nMobHInChI[i] ) &&
2224
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 &&
2225
0 == pBNS->edge[e].forbidden ) {
2227
iat_DB_N_Neutr[num_DB_N_Neutr ++] = iat;
2229
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2234
if ( num_try = inchi_min( num_DB_N_Neutr, num_SB_O_Minus ) ) {
2235
/* detected; attempt to fix */
2236
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2237
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2238
/* allow stereobonds in rings change */
2239
if ( forbidden_stereo_edge_mask )
2240
RemoveForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
2243
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
2244
iat = iat_SB_O_Minus[i];
2245
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
2248
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2249
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2251
pe->forbidden |= forbidden_edge_mask;
2253
pv1->st_edge.flow -= delta;
2254
pv2->st_edge.flow -= delta;
2255
pBNS->tot_st_flow -= 2*delta;
2257
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2258
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2260
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2261
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
2262
/* Moved (-) charge to =N- => nDeltaCharge == 1 */
2263
/* Flow change on pe (-)charge edge (atom (-)O-) is not known to RunBnsTestOnce()) */
2264
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2267
cur_success ++; /* 08 */
2270
pe->forbidden &= forbidden_edge_mask_inv;
2272
pv1->st_edge.flow += delta;
2273
pv2->st_edge.flow += delta;
2274
pBNS->tot_st_flow += 2*delta;
2278
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2279
if ( forbidden_stereo_edge_mask )
2280
SetForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
2282
CurrEdges.num_edges = 0; /* clear current edge list */
2283
if ( cur_success ) {
2284
tot_succes += cur_success;
2285
/* recalculate InChI from the structure */
2286
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2287
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2290
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2293
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2294
goto exit_function; /* no fixed-H found */
2296
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2299
if ( !pc2i->bHasDifference ) {
2300
goto exit_function; /* nothing to do */
2305
if ( pc2i->len_c2at >= 2 ) {
2306
/*--------------------------------------------------------*/
2307
/* case 09: restored: NH2(+)=C--NH2 orig.: NH2-C(+)-NH2 */
2308
/* FixH: 2 | 2 0 | 0 */
2310
/* N = N, taut taut non-taut non-taut*/
2311
/* Solution: move (+) from NH2(+) to C */
2312
/*--------------------------------------------------------*/
2315
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
2316
iat = pc2i->c2at[i].atomNumber;
2317
if ( (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
2318
/* orig. InChI info: */
2319
!pc2i->c2at[i].endptInChI &&
2320
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI &&
2321
/* reversed structure info: */
2322
pc2i->c2at[i].endptRevrs &&
2323
pc2i->c2at[i].nFixHRevrs && !pc2i->c2at[i].nMobHRevrs &&
2324
pc2i->c2at[i].nAtChargeRevrs == 1 &&
2325
at2[iat].valence + 1 == at2[iat].chem_bonds_valence &&
2326
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
2327
EdgeIndex eNC = NO_VERTEX, eCPlusC;
2328
int iNH2, iatC, iatNH2, icNH2;
2329
/* found NH2(+)=; locate =C< and find whether it has -NH2 neighbor */
2330
for ( j = 0; j < at2[iat].valence; j ++ ) {
2331
if ( at2[iat].bond_type[j] == BOND_TYPE_DOUBLE )
2334
if ( j == at2[iat].valence )
2336
eNC = pBNS->vert[iat].iedge[j]; /* edge NH2(+)=C */
2337
iatC = at2[iat].neighbor[j];
2338
if ( pVA[iatC].cNumValenceElectrons != 4 || pVA[iatC].cMetal || at2[iatC].charge ||
2339
at2[iatC].valence != 3 || at2[iatC].valence+1 != at2[iatC].chem_bonds_valence ||
2340
(eCPlusC=pVA[iatC].nCPlusGroupEdge-1) < 0 || pBNS->edge[eCPlusC].forbidden)
2342
for ( j = 0; j < at2[iatC].valence; j ++ ) {
2343
iatNH2 = at2[iatC].neighbor[j];
2344
if ( iatNH2 == iat || pVA[iatNH2].cNumValenceElectrons != 5 ||
2345
pVA[iatNH2].cPeriodicRowNumber != 1 || !at2[iatNH2].num_H || at2[iatNH2].charge)
2347
icNH2 = pStruct->nAtno2Canon[0][iatNH2];
2348
for ( iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2 ++ ) {
2349
if ( iatNH2 == pc2i->c2at[iNH2].atomNumber )
2352
if ( iNH2 == pc2i->len_c2at )
2355
if ( (pc2i->c2at[iNH2].nValElectr == 5 && pc2i->c2at[iNH2].nPeriodNum == 1) &&
2356
/* orig. InChI info: */
2357
!pc2i->c2at[iNH2].endptInChI &&
2358
pc2i->c2at[iNH2].nFixHInChI == 0 && pc2i->c2at[iNH2].nMobHInChI &&
2359
/* reversed structure info: */
2360
pc2i->c2at[iNH2].endptRevrs &&
2361
pc2i->c2at[iNH2].nFixHRevrs && !pc2i->c2at[iNH2].nMobHRevrs &&
2362
pc2i->c2at[iNH2].nAtChargeRevrs == 0 &&
2363
at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence ) {
2364
/* we have found NH2(+)=, =C<, and bond between them */
2366
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2369
if ( ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ) ) {
2372
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2373
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2376
pe = pBNS->edge + eNC;
2379
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2380
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2382
pe->forbidden |= forbidden_edge_mask;
2383
pe->flow -= delta; /* add (+) to -NHm */
2384
pv1->st_edge.flow -= delta;
2385
pv2->st_edge.flow -= delta;
2386
pBNS->tot_st_flow -= 2*delta;
2388
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2389
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2391
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2392
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
2393
/* Removed (+)charge from -NHn => nDeltaCharge == -1 */
2394
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
2395
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2398
cur_success ++; /* 09 */
2402
pv1->st_edge.flow += delta;
2403
pv2->st_edge.flow += delta;
2404
pBNS->tot_st_flow += 2*delta;
2407
pe->forbidden &= forbidden_edge_mask_inv;
2408
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2409
CurrEdges.num_edges = 0; /* clear current edge list */
2415
if ( cur_success ) {
2416
tot_succes += cur_success;
2417
/* recalculate InChI from the structure */
2418
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2419
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2422
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2425
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2426
goto exit_function; /* no fixed-H found */
2428
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2431
if ( !pc2i->bHasDifference ) {
2432
goto exit_function; /* nothing to do */
2438
if ( pc2i->len_c2at >= 2 ) {
2439
/*--------------------------------------------------------*/
2440
/* case 10: restored: NH2-X(+)-NH- orig.: NH2(+)=X-NH- */
2443
/* N = N,O,S,Se,Te non-taut non-taut taut taut */
2444
/* Solution: move (+) from X(+) to NH2 or NH */
2445
/*--------------------------------------------------------*/
2448
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
2449
if ( pc2i->c2at[i].nValue )
2451
iat = pc2i->c2at[i].atomNumber;
2452
if ( (pc2i->c2at[i].nValElectr == 6 ||
2453
pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
2454
/* orig. InChI info: */
2455
pc2i->c2at[i].endptInChI &&
2456
pc2i->c2at[i].nFixHInChI && !pc2i->c2at[i].nMobHInChI &&
2457
/* reversed structure info: */
2458
!pc2i->c2at[i].endptRevrs &&
2459
!pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs &&
2460
pc2i->c2at[i].nAtChargeRevrs == 0 &&
2461
at2[iat].valence == at2[iat].chem_bonds_valence &&
2462
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
2464
EdgeIndex eCPlusC, eCPlusNH2, bContinue=1;
2465
int iNH2, iatC, iatNH2, icNH2, j1, j2;
2466
BNS_EDGE *pe_iat, *pe_iNH2;
2467
/* found NH2- locate -X(+) and find whether it has another -NH2 neighbor */
2468
for ( j1 = 0; j1 < at2[iat].valence && bContinue; j1 ++ ) {
2469
if ( at2[iat].bond_type[j1] == BOND_TYPE_SINGLE &&
2470
at2[iatC = at2[iat].neighbor[j1]].charge == 1 &&
2471
(4 <= pVA[iatC].cNumValenceElectrons && pVA[iatC].cNumValenceElectrons <= 6) &&
2472
at2[iatC].valence == at2[iatC].chem_bonds_valence &&
2473
(eCPlusC=pVA[iatC].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eCPlusC].forbidden) {
2474
/* found a candidate for X; find another NH2 */
2475
for ( j2 = 0; j2 < at2[iatC].valence && bContinue; j2 ++ ) {
2476
if ( at2[iatC].bond_type[j2] == BOND_TYPE_SINGLE &&
2477
iat != (iatNH2 = at2[iatC].neighbor[j2]) &&
2478
at2[iatNH2].charge == 0 && at2[iatNH2].num_H &&
2479
(pVA[iatNH2].cNumValenceElectrons==5 || pVA[iatNH2].cNumValenceElectrons==6) &&
2480
at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence &&
2481
(eCPlusNH2=pVA[iatNH2].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eCPlusNH2].forbidden) {
2482
for ( iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2 ++ ) {
2483
if ( iatNH2 != pc2i->c2at[iNH2].atomNumber || pc2i->c2at[iNH2].nValue )
2485
/* check the second -NH */
2486
icNH2 = pStruct->nAtno2Canon[0][iatNH2]; /* canon number -1 */
2487
if ( /* orig. InChI info: */
2488
pc2i->c2at[iNH2].endptInChI &&
2489
pc2i->c2at[iNH2].nFixHInChI && !pc2i->c2at[iNH2].nMobHInChI &&
2490
/* reversed structure info: */
2491
!pc2i->c2at[iNH2].endptRevrs &&
2492
!pc2i->c2at[iNH2].nFixHRevrs && pc2i->c2at[iNH2].nMobHRevrs &&
2493
pc2i->c2at[iNH2].nAtChargeRevrs == 0 ) {
2494
/* we have found NH-X(+)-NH; remove charge from X(+) */
2495
pe_iat = pBNS->edge + pBNS->vert[iat].iedge[j1];
2496
pe_iNH2 = pBNS->edge + pBNS->vert[iatC].iedge[j2];
2497
/* pick up one of -NH to move (+) to it */
2498
if ( !pe_iat->forbidden && pBNS->edge[e].flow ) {
2499
pe = pBNS->edge + e;
2501
if ( !pe_iNH2->forbidden && pBNS->edge[eCPlusNH2].flow ) {
2502
pe = pBNS->edge + eCPlusNH2;
2504
continue; /* none of the two -X(+)- bonds may be changed */
2506
if ( ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ) ) {
2509
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2510
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2513
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2514
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2516
/*pe->forbidden |= forbidden_edge_mask;*/
2517
pe->flow -= delta; /* add (+) to -NHm */
2518
pv1->st_edge.flow -= delta;
2519
pv2->st_edge.flow -= delta;
2520
pBNS->tot_st_flow -= 2*delta;
2522
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2523
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2525
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2526
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
2527
/* Removed (+)charge from -NHn => nDeltaCharge == -1 */
2528
/* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
2529
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2532
cur_success ++; /* 10 */
2534
pc2i->c2at[i].nValue = 1; /* mark as used */
2535
pc2i->c2at[iNH2].nValue = 1; /* mark as used */
2539
pv1->st_edge.flow += delta;
2540
pv2->st_edge.flow += delta;
2541
pBNS->tot_st_flow += 2*delta;
2545
/*pe->forbidden &= forbidden_edge_mask_inv;*/
2546
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2547
CurrEdges.num_edges = 0; /* clear current edge list */
2550
} /* iNH2: pc2i->c2at[iNH2] cycle */
2552
} /* j2: iatC neighbors cycle */
2554
} /* j1: iat neighbors cycle */
2556
} /* i: pc2i->c2at[i] cycle */
2557
if ( cur_success ) {
2559
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
2560
pc2i->c2at[i].nValue = 0;
2563
tot_succes += cur_success;
2564
/* recalculate InChI from the structure */
2565
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2566
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2569
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2572
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2573
goto exit_function; /* no fixed-H found */
2575
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2578
if ( !pc2i->bHasDifference ) {
2579
goto exit_function; /* nothing to do */
2584
if ( /*pc2i->len_c2at >= 1 &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */
2585
(pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
2586
/*--------------------------------------------------------------*/
2587
/* case 11: restored: NH(+)=AB-N< OH- orig. NH-AB=N(+)< OH- */
2588
/* FixH: 0 0 0 1 0 1 */
2589
/* MobH: 1 0 1 0 0 0 */
2590
/* non-taut. taut taut */
2591
/* ADP: one t-group or more endpoints */
2592
/* NH(+)= => N, O, S, Se; -N< => N */
2593
/* Solution: move (+) from NH(+) to -N< */
2594
/*--------------------------------------------------------------*/
2595
int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
2596
short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
2597
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
2598
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
2599
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
2601
/* search for NH(+)= */
2602
/* search for -N< */
2603
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
2604
iat = nCanon2AtnoRevrs[i];
2605
if ( /* in restored atom: charge=0, has no H, has no double bond, N only */
2606
num_DB_Charged < MAX_DIFF_FIXH &&
2607
at2[iat].charge == 1 && at2[iat].num_H &&
2608
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
2609
(pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 ||
2610
pVA[iat].cNumValenceElectrons == 6 ) &&
2611
/* in orig.InChI: an endpoint, has fixed-H */
2612
/*pStruct->endpoint[i] &&*/
2613
(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2614
/*!(nMobHInChI && nMobHInChI[i] ) &&*/
2616
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
2618
iat_DB_Charged[num_DB_Charged ++] = iat;
2620
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2625
if ( /* in restored atom: charge=0, has no H, has no double bond, N only */
2626
num_SB_Neutr < MAX_DIFF_FIXH &&
2627
at2[iat].charge == 0 && !at2[iat].num_H &&
2628
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
2629
(pVA[iat].cNumValenceElectrons == 5 &&
2630
pVA[iat].cPeriodicRowNumber == 1 ) &&
2631
/* in orig.InChI: an endpoint, has fixed-H */
2632
/*pStruct->endpoint[i] &&*/
2633
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2634
!(nMobHInChI && nMobHInChI[i] ) &&
2636
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
2638
iat_SB_Neutr[num_SB_Neutr ++] = iat;
2639
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2644
if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
2645
/* detected; attempt to fix */
2646
BNS_VERTEX *pv1n, *pv2n;
2647
BNS_EDGE *pe1n, *pe2n;
2649
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2650
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2652
for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
2653
iat = iat_DB_Charged[i];
2654
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
2657
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2658
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2660
for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
2661
pe1n = pBNS->edge + pv1->iedge[j];
2662
if ( pe1n->flow && !pe1n->forbidden ) {
2663
pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
2668
continue; /* not found */
2670
for ( j = pv2->num_adj_edges-2; 0 <= j; j -- ) {
2671
pe2n = pBNS->edge + pv2->iedge[j];
2672
if ( pe2n->flow && !pe2n->forbidden ) {
2673
pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
2678
continue; /* not found */
2681
pe1n->flow -= delta;
2682
pe2n->flow -= delta;
2683
pv1n->st_edge.flow -= delta;
2684
pv2n->st_edge.flow -= delta;
2685
pBNS->tot_st_flow -= 2*delta;
2687
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2688
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2690
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
2691
vPathEnd == v2n && vPathStart == v1n) &&
2692
(nDeltaCharge == 0 || nDeltaCharge == 1) ) {
2693
/* before setting flows the structure could be:
2694
[NH+ neigh, v1n]=e1n=[NH+,v1]-pe-[+,v2]=e2n=[another at or its chargeStruct]
2697
[NH+ or ChStr, v1n]=pe1n=[NH+ or ChStr, v1]-pe-[+,v2]=pe2n=[at2 or ChStr, v2n]
2699
NH+(+)edge | N (+) edge: only
2700
| these are not forbidden
2704
After setting flows (* mark radicals, =pe= is forbidden):
2706
*[NH+ or ChStr, v1n]-pe1n-[NH+ or ChStr, v1]=pe=[+,v2]-pe2n-[at2 or ChStr, v2n]*
2708
NH+(+)edge | N (+) edge: only
2709
| these are not forbidden
2714
pe1n and pe2n will or will not change, depending on the structure.
2716
Consider what happens if pe2n changes. It may only increment.
2717
If pe2n flow increments then another (+)edge flow dectrements. If
2718
[at2 or ChStr, v2n] is at2 then at2 charge would change from (+) to 0,
2719
and another N charge would change from 0 to (+), giving tot. change of
2720
number of charges (-1)+(+1)=0. However, if [at2 or ChStr, v2n] is
2721
ChargeStruct then at2 will not be on the alt path and only the creation
2722
of another (+) will be detected.
2724
/* Removed charge from O(+) => nDeltaCharge == -1 */
2725
/* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
2726
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2729
cur_success ++; /* 11 */
2733
pe1n->flow += delta;
2734
pe2n->flow += delta;
2735
pv1n->st_edge.flow += delta;
2736
pv2n->st_edge.flow += delta;
2737
pBNS->tot_st_flow += 2*delta;
2741
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2743
CurrEdges.num_edges = 0; /* clear current edge list */
2744
if ( cur_success ) {
2745
tot_succes += cur_success;
2746
/* recalculate InChI from the structure */
2747
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2748
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2751
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2754
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2755
goto exit_function; /* no fixed-H found */
2757
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2760
if ( !pc2i->bHasDifference ) {
2761
goto exit_function; /* nothing to do */
2766
if ( pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 &&
2767
pc2i->nNumRemHInChI >= -1 && /* 2006-03-03 */
2768
(pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs || pc2i->nNumTgRevrs > 1) /* ADP in InChI */ ) {
2769
/*--------------------------------------------------------------*/
2770
/* case 12: restored: O=AB-N< original: (-)O-AB=N(+)< */
2774
/* O = O, S, Se, N; N = N; */
2775
/* restored atom O is not tautomeric; original atom O is taut. */
2776
/* original struct has 1 t-group; restored has less endpoints */
2777
/* and/or possibly >1 t-groups */
2778
/* Solution: separate charges between O= and -N< */
2779
/* allow moving charge to N(V) to make it N(IV)(+) */
2780
/*--------------------------------------------------------------*/
2784
int num_SB_N_Neutr = 0, num_DB_O = 0, iat, num_N_V=0, bN_V;
2785
short iat_SB_N_Neutr[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
2786
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
2787
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
2788
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
2789
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
2790
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
2792
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
2793
iat = pc2i->c2at[i].atomNumber;
2794
if ( /* orig. InChI info: -O(-) */
2795
num_DB_O < MAX_DIFF_FIXH &&
2796
(pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ ||
2797
pc2i->c2at[i].nValElectr == 5 &&
2798
pc2i->c2at[i].nPeriodNum == 1 /* N */ ) &&
2799
pc2i->c2at[i].endptInChI &&
2800
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
2801
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
2802
/* reversed structure info: */
2803
!pc2i->c2at[i].endptRevrs &&
2804
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
2805
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
2806
((pc2i->c2at[i].nValElectr == 6)?
2807
(at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2):
2808
(pc2i->c2at[i].nValElectr == 5)?
2809
(at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3):
2812
iat_DB_O[num_DB_O ++] = iat;
2814
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2820
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
2821
iat = nCanon2AtnoRevrs[i];
2823
if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */
2824
num_SB_N_Neutr < MAX_DIFF_FIXH &&
2825
at2[iat].charge == 0 && !at2[iat].num_H &&
2826
(at2[iat].valence == at2[iat].chem_bonds_valence ||
2827
(bN_V = at2[iat].valence+2 == at2[iat].chem_bonds_valence)) &&
2829
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
2830
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
2831
/* in orig.InChI: not an endpoint, has no H */
2832
!pStruct->endpoint[i] &&
2833
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2834
!(nMobHInChI && nMobHInChI[i]) &&
2836
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
2838
if ( bOnly_N_V && bN_V &&
2839
NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
2840
!pBNS->edge[j].forbidden && !pBNS->edge[j].flow ) {
2842
/* switch to N(V) only mode */
2843
CurrEdges.num_edges = 0;
2846
iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
2848
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2851
if ( ret = AddToEdgeList( &CurrEdges, j, INC_ADD_EDGE ) ) {
2856
iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
2857
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
2860
/* in addition, permit N(V)=>N(IV)(+) change by allowing charge flower edge change flow */
2861
if ( bN_V && NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
2862
!pBNS->edge[j].forbidden && !pBNS->edge[j].flow ) {
2863
if ( ret = AddToEdgeList( &CurrEdges, j, INC_ADD_EDGE ) ) {
2870
if ( num_try = inchi_min( num_SB_N_Neutr, num_DB_O ) ) {
2871
/* detected; attempt to fix */
2872
BNS_EDGE *pe_CMinus;
2873
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2874
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
2876
for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
2878
pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
2879
pe_CMinus->forbidden &= forbidden_edge_mask_inv;
2881
pe = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/
2884
pv1 = pBNS->vert + (v1 = pe->neighbor1);
2885
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2887
pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */
2889
pv1->st_edge.flow -= delta;
2890
pv2->st_edge.flow -= delta;
2891
pBNS->tot_st_flow -= 2*delta;
2893
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2894
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
2896
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
2897
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
2898
/* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */
2899
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
2902
cur_success ++; /* 12 */
2906
pv1->st_edge.flow += delta;
2907
pv2->st_edge.flow += delta;
2908
pBNS->tot_st_flow += 2*delta;
2910
pe->forbidden &= forbidden_edge_mask_inv; /* allow changes to O=X bond */
2913
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
2915
CurrEdges.num_edges = 0; /* clear current edge list */
2916
if ( cur_success ) {
2917
tot_succes += cur_success;
2918
/* recalculate InChI from the structure */
2919
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
2920
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
2923
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
2926
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
2927
goto exit_function; /* no fixed-H found */
2929
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
2932
if ( !pc2i->bHasDifference ) {
2933
goto exit_function; /* nothing to do */
2945
if ( pc2i->nNumTgDiffMinus /*|| pc2i->nNumTgDiffH */ /* no ADP in InChI needed */ ) {
2946
/*--------------------------------------------------------------*/
2948
/* case 13: restored: O=AB=N= original: (-)O-AB-N(+)= */
2951
/* non-taut taut non-taut */
2952
/* O = O, S, Se, N; N = N, P, ... */
2953
/* t-group in original has same num. endpoints */
2954
/* same num_H and less (-) than in the restored structure */
2955
/* original atom O is tautomeric, N is not taut in both */
2956
/* original struct has 1 t-group; restored has less endpoints */
2957
/* and/or possibly >1 t-groups */
2958
/* Solution: separate charges between O= and -N< */
2959
/* allow moving charge to N(V) to make it N(IV)(+) */
2960
/*--------------------------------------------------------------*/
2962
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
2963
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
2964
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
2966
S_CHAR *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
2967
S_CHAR *pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
2968
pStruct->pOneINChI[1]->nNum_H :
2969
(pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
2970
pStruct->pOneINChI[0]->nNum_H : NULL;
2971
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
2972
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
2974
/* find whether this may help */
2975
for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
2976
if ( pStruct->ti.t_group[itg].nNumEndpoints == pStruct->One_ti.t_group[itg].nNumEndpoints &&
2977
pStruct->ti.t_group[itg].num[0] - pStruct->ti.t_group[itg].num[1] ==
2978
pStruct->One_ti.t_group[itg].num[0] - pStruct->One_ti.t_group[itg].num[1] &&
2979
pStruct->ti.t_group[itg].num[1] > pStruct->One_ti.t_group[itg].num[1]) {
2980
/* restored InChI t-group has more (-) and same number of H */
2982
int num_SB_N_Neutr = 0, num_DB_O = 0, iat;
2983
short iat_SB_N_Neutr[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
2985
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
2986
iat = nCanon2AtnoRevrs[i];
2987
if ( /* orig. InChI info: -O(-) */
2988
num_DB_O < MAX_DIFF_FIXH &&
2989
(pVA[i].cNumValenceElectrons == 6 /* O, S, Se, Te */ ) &&
2990
pStruct->endpoint[i] == itg+1 &&
2991
(e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
2992
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
2993
!(nMobHInChI && nMobHInChI[i]) &&
2994
/* reversed structure info: */
2995
/*!pc2i->c2at[i].endptRevrs &&*/
2996
!(num_Fixed_H_Revrs && num_Fixed_H_Revrs[iat]) &&
2997
!(pnMobHRevrs && pnMobHRevrs[iat]) &&
2998
at2[iat].charge == 0 && at2[iat].num_H == 0 &&
2999
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
3001
iat_DB_O[num_DB_O ++] = iat;
3003
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3008
if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */
3009
num_SB_N_Neutr < MAX_DIFF_FIXH &&
3010
at2[iat].charge == 0 && !at2[iat].num_H &&
3011
/*at2[iat].valence == at2[iat].chem_bonds_valence ||*/
3012
(at2[iat].valence==4 && at2[iat].chem_bonds_valence==5) &&
3014
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber >= 1 &&
3015
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
3016
/* in orig.InChI: not an endpoint, has no H */
3017
!pStruct->endpoint[i] &&
3018
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
3019
!(nMobHInChI && nMobHInChI[i]) &&
3021
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
3023
iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
3024
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3029
if ( num_try = inchi_min( num_SB_N_Neutr, num_DB_O ) ) {
3030
/* detected; attempt to fix */
3031
BNS_EDGE *pe_CMinus;
3032
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3033
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
3035
for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
3037
pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
3038
pe_CMinus->forbidden &= forbidden_edge_mask_inv;
3040
pe = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/
3043
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3044
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3046
pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */
3048
pv1->st_edge.flow -= delta;
3049
pv2->st_edge.flow -= delta;
3050
pBNS->tot_st_flow -= 2*delta;
3052
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3053
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3055
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
3056
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
3057
/* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */
3058
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3061
cur_success ++; /* 13 */
3065
pv1->st_edge.flow += delta;
3066
pv2->st_edge.flow += delta;
3067
pBNS->tot_st_flow += 2*delta;
3069
pe->forbidden &= forbidden_edge_mask_inv; /* allow changes to O=X bond */
3072
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3074
CurrEdges.num_edges = 0; /* clear current edge list */
3075
if ( cur_success ) {
3076
tot_succes += cur_success;
3077
/* recalculate InChI from the structure */
3078
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3079
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3082
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3085
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3086
goto exit_function; /* no fixed-H found */
3088
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3091
if ( !pc2i->bHasDifference ) {
3092
goto exit_function; /* nothing to do */
3105
if ( (pc2i->nNumTgInChI <= 1 &&
3106
pc2i->nNumRemHInChI > pc2i->nNumRemHRevrs || pc2i->len_c2at) &&
3107
bHas_N_V( at2, pStruct->num_atoms) ) {
3108
/*-----------------------------------------------------------------*/
3110
/* case 14: restored:-N=AB=N=CD-XH original: (-)N-AB-N(+)=CD-XH */
3111
/* FixH: 0 0 0/1 0 1 */
3112
/* MobH: 0 0 1/0 0 0 */
3113
/* non-taut n/t any non any */
3115
/* X = O, S, Se, N; N = N */
3116
/* t-group in original may have more (-) than in restored */
3117
/* same num_H and less (-) than in the restored structure */
3118
/* atom N(V)/N(IV)(+) is not taut in both */
3119
/* The following transformation should be possible: */
3121
/* N=AB=N=CD-XH -> (-)N-AB-N-CD=XH(+) */
3122
/* This allows ADP to remove H(+) from -XH */
3123
/* As the result, the original structure has 0 or 1 t-group */
3124
/* Solution: separate charges between -N(III)= and N(V) */
3125
/*-----------------------------------------------------------------*/
3126
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
3127
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
3128
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
3130
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
3131
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
3132
int num_N_V = 0, iat, i1, i2, i3, e1Flower, e1Plus, e2Plus, e2Minus, e3Plus;
3133
int max_success = pc2i->nNumRemHInChI - pc2i->nNumRemHRevrs;
3134
short iat_N_V_Array[MAX_DIFF_FIXH];
3135
EDGE_LIST iat_X_List, iat_N_III_List;
3136
AllocEdgeList( &iat_X_List, EDGE_LIST_CLEAR );
3137
AllocEdgeList( &iat_N_III_List, EDGE_LIST_CLEAR );
3140
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
3141
iat = nCanon2AtnoRevrs[i];
3142
/* search for N(V), 3 bonds */
3143
if ( /* restored structure */
3144
num_N_V < MAX_DIFF_FIXH &&
3145
at2[iat].chem_bonds_valence == 5 && at2[iat].valence == 3 &&
3146
!at2[iat].charge && !at2[iat].radical &&
3147
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
3148
!( at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint ) &&
3150
(e = pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
3151
pBNS->edge[e].flow /* no charge */ &&
3152
NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) && !pBNS->edge[j].forbidden &&
3153
!pBNS->edge[j].flow /* neutral, valence=5 */ &&
3155
!pStruct->endpoint[i] &&
3156
!(nMobHInChI && nMobHInChI[i]) && !pStruct->fixed_H[i] ) {
3157
iat_N_V_Array[num_N_V ++] = iat;
3159
/* search for -N= */
3160
if ( /* restored structure */
3161
at2[iat].chem_bonds_valence == 3 && at2[iat].valence == 2 &&
3162
!at2[iat].charge && !at2[iat].radical &&
3163
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
3164
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint ) &&
3166
(e = pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
3167
!pBNS->edge[e].flow /* no charge */ &&
3169
/*!pStruct->endpoint[i] &&*/
3170
!(nMobHInChI && nMobHInChI[i]) && !pStruct->fixed_H[i] ) {
3172
if ( ret = AddToEdgeList( &iat_N_III_List, iat, 32 ) ) {
3176
/* search for -OH -NH-, -NH2 */
3177
if ( /* restored structure */
3178
at2[iat].chem_bonds_valence == at2[iat].valence &&
3179
!at2[iat].charge && !at2[iat].radical &&
3180
(pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 ||
3181
pVA[iat].cNumValenceElectrons == 6 ) &&
3183
(e = pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
3184
pBNS->edge[e].flow /* no charge */ &&
3186
!(nMobHInChI && nMobHInChI[i]) && pStruct->fixed_H[i] ) {
3188
if ( ret = AddToEdgeList( &iat_X_List, iat, 32 ) ) {
3193
if ( !max_success ) {
3194
max_success = inchi_min( num_N_V, iat_N_III_List.num_edges );
3195
max_success = inchi_min( max_success, iat_X_List.num_edges );
3197
if ( num_N_V && iat_N_III_List.num_edges && iat_X_List.num_edges ) {
3198
for ( i1 = 0; i1 < num_N_V && cur_success < max_success; i1 ++ ) {
3199
int iat_N_V = iat_N_V_Array[i1];
3200
if ( NO_VERTEX == iat_N_V ||
3201
0 >= (e1Plus = pVA[iat_N_V].nCPlusGroupEdge-1) ||
3202
NO_VERTEX == (e1Flower = GetChargeFlowerUpperEdge( pBNS, pVA, e1Plus )) ||
3203
1 != pBNS->edge[e1Plus].flow ||
3204
0 != pBNS->edge[e1Flower].flow ) {
3207
for ( i2 = iat_N_III_List.num_edges-1; 0 <= i2 && cur_success < max_success; i2 -- ) {
3208
int iat_N_III = iat_N_III_List.pnEdges[i2];
3209
if ( NO_VERTEX == iat_N_III ||
3210
0 >= (e2Minus = pVA[iat_N_III].nCMinusGroupEdge-1) ||
3211
0 >= (e2Plus = pVA[iat_N_III].nCPlusGroupEdge-1) ||
3212
0 != pBNS->edge[e2Minus].flow ||
3213
1 != pBNS->edge[e2Plus].flow ) {
3214
/* do not consider this atom anymore */
3215
iat_N_III_List.pnEdges[i2] = NO_VERTEX;
3218
for ( i3 = iat_X_List.num_edges-1; 0 <= i3 && cur_success < max_success; i3 -- ) {
3219
int iat_X = iat_X_List.pnEdges[i3];
3220
BNS_VERTEX *pv1n, *pv2n;
3221
BNS_EDGE *pe1n, *pe2n, *pe1Plus, *pe2Minus, *pe3Plus;
3224
if ( NO_VERTEX == iat_X ||
3225
0 >= (e3Plus = pVA[iat_X].nCPlusGroupEdge-1) ||
3226
1 != pBNS->edge[e3Plus].flow ) {
3227
/* do not consider this atom anymore */
3228
iat_X_List.pnEdges[i3] = NO_VERTEX;
3231
/* all is ready to check whether the following applies:
3232
forbid changes of all charges and N,P,... flowers
3233
allow to change edges: e2Minus, e3Plus
3234
Increment flow in e1Flower
3235
The result should be: increase in number of charges by 2
3237
pe1Plus = pBNS->edge + e1Plus; /* N(V) positive charge edge */
3238
pe2Minus = pBNS->edge + e2Minus; /* =N- negative charge edge */
3239
pe3Plus = pBNS->edge + e3Plus; /* -XH positive charge edge */
3240
pe = pBNS->edge + e1Flower; /* N(V) flower edge */
3241
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3242
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3243
for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
3244
pe1n = pBNS->edge + pv1->iedge[j];
3245
if ( pe1n->flow && !pe1n->forbidden && pe1n != pe1Plus ) {
3246
pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
3251
continue; /* not found -- should not happen */
3252
for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
3253
pe2n = pBNS->edge + pv2->iedge[j];
3254
if ( pe2n->flow && !pe2n->forbidden && pe2n != pe1Plus ) {
3255
pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
3260
continue; /* not found -- should not happen */
3263
pe1n->flow -= delta;
3264
pe2n->flow -= delta;
3265
pv1n->st_edge.flow -= delta;
3266
pv2n->st_edge.flow -= delta;
3267
pBNS->tot_st_flow -= 2*delta;
3269
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3270
SetForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
3272
/* allow two charges to change */
3273
pe2Minus->forbidden &= forbidden_edge_mask_inv;
3274
pe3Plus->forbidden &= forbidden_edge_mask_inv;
3276
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3277
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3282
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
3283
vPathEnd == v2n && vPathStart == v1n) &&
3284
nDeltaCharge == 2 ) {
3290
pe2Minus->forbidden |= forbidden_edge_mask;
3291
pe3Plus->forbidden |= forbidden_edge_mask;
3293
pe1n->flow += delta;
3294
pe2n->flow += delta;
3295
pv1n->st_edge.flow += delta;
3296
pv2n->st_edge.flow += delta;
3297
pBNS->tot_st_flow += 2*delta;
3299
/* test #2: check if charge separation is possible */
3301
pe1n->flow -= delta;
3302
pe2n->flow -= delta;
3303
pv1n->st_edge.flow -= delta;
3304
pv2n->st_edge.flow -= delta;
3305
pBNS->tot_st_flow -= 2*delta;
3307
/* allow two charges (N(V) and N(III)) to change */
3308
pe2Minus->forbidden &= forbidden_edge_mask_inv;
3309
pe1Plus->forbidden &= forbidden_edge_mask_inv;
3311
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3312
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3313
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
3314
vPathEnd == v2n && vPathStart == v1n) &&
3315
nDeltaCharge == 2 ) {
3316
/* success; actually change charges */
3317
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3320
cur_success ++; /* 14 */
3324
/* failed: restore BNS flow */
3326
pe1n->flow += delta;
3327
pe2n->flow += delta;
3328
pv1n->st_edge.flow += delta;
3329
pv2n->st_edge.flow += delta;
3330
pBNS->tot_st_flow += 2*delta;
3334
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3335
RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
3337
/* do not repeat for the same atoms */
3338
iat_N_V_Array[i1] = NO_VERTEX;
3339
iat_N_III_List.pnEdges[i2] = NO_VERTEX;
3340
iat_X_List.pnEdges[i3] = NO_VERTEX;
3356
AllocEdgeList( &iat_X_List, EDGE_LIST_FREE );
3357
AllocEdgeList( &iat_N_III_List, EDGE_LIST_FREE );
3358
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3359
RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
3360
CurrEdges.num_edges = 0; /* clear current edge list */
3364
if ( cur_success ) {
3365
tot_succes += cur_success;
3366
/* recalculate InChI from the structure */
3367
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3368
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3371
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3374
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3375
goto exit_function; /* no fixed-H found */
3377
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3380
if ( !pc2i->bHasDifference ) {
3381
goto exit_function; /* nothing to do */
3387
if ( pc2i->nNumTgMRevrs > pc2i->nNumTgMInChI ||
3388
pc2i->nNumRemHRevrs < pc2i->nNumRemHInChI ||
3389
pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI ||
3390
pc2i->nNumTgInChI <= 1 && pc2i->nNumTgRevrs > pc2i->nNumTgInChI ) {
3391
/*--------------------------------------------------------------*/
3392
/* case 15: restored: -(+)O=AB-N< orig: -O-AB=N(+)< */
3393
/* (a) restored t-groups have more (-) than in original InChI */
3394
/* (b) Mobile-H charge: restored > original InChI *and* */
3395
/* removed H: restored < original InChI */
3396
/* (c) restored t-groups have less endpnoits than in orig InChI */
3397
/* O = O, S, Se, Te; N = N */
3398
/* Solution: move (+) from -O(+)= to -N< */
3399
/*--------------------------------------------------------------*/
3400
int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
3401
short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
3402
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
3403
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
3404
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
3406
/* search for -O(+)= */
3407
/* search for -N< */
3408
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
3409
iat = nCanon2AtnoRevrs[i];
3410
if ( /* -O(+)= in restored atom: charge=1, has no H, a double bond */
3411
num_DB_Charged < MAX_DIFF_FIXH &&
3412
at2[iat].charge == 1 && !at2[iat].num_H &&
3413
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3414
(pVA[iat].cNumValenceElectrons == 6 ) &&
3415
/* in orig.InChI: an endpoint, has fixed-H */
3416
/*pStruct->endpoint[i] &&*/
3417
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
3418
!(nMobHInChI && nMobHInChI[i] ) &&
3420
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
3422
iat_DB_Charged[num_DB_Charged ++] = iat;
3424
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3429
if ( /* -N< in restored atom: charge=0, has no H, has no double bond, N only */
3430
num_SB_Neutr < MAX_DIFF_FIXH &&
3431
at2[iat].charge == 0 && !at2[iat].num_H &&
3432
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3433
(pVA[iat].cNumValenceElectrons == 5 &&
3434
pVA[iat].cPeriodicRowNumber == 1 ) &&
3435
/* in orig.InChI: an endpoint, has fixed-H */
3436
/*pStruct->endpoint[i] &&*/
3437
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
3438
!(nMobHInChI && nMobHInChI[i] ) &&
3440
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
3442
iat_SB_Neutr[num_SB_Neutr ++] = iat;
3443
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3448
if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
3449
/* detected; attempt to fix */
3450
BNS_VERTEX *pv1n, *pv2n;
3451
BNS_EDGE *pe1n, *pe2n;
3453
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3454
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
3456
for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
3457
iat = iat_DB_Charged[i];
3458
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
3461
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3462
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3464
for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
3465
pe1n = pBNS->edge + pv1->iedge[j];
3466
if ( pe1n->flow && !pe1n->forbidden ) {
3467
pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
3472
continue; /* not found */
3474
for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
3475
pe2n = pBNS->edge + pv2->iedge[j];
3476
if ( pe2n->flow && !pe2n->forbidden ) {
3477
pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
3482
continue; /* not found */
3485
pe1n->flow -= delta;
3486
pe2n->flow -= delta;
3487
pv1n->st_edge.flow -= delta;
3488
pv2n->st_edge.flow -= delta;
3489
pBNS->tot_st_flow -= 2*delta;
3491
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3492
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3494
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
3495
vPathEnd == v2n && vPathStart == v1n) &&
3496
(nDeltaCharge == 0 || nDeltaCharge == 1) ) {
3497
/* Moved charge from O(+) to -N< => nDeltaCharge == 1 or 0 if pe2n = -N< charge edge */
3498
/* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
3499
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3502
cur_success ++; /* 15 */
3506
pe1n->flow += delta;
3507
pe2n->flow += delta;
3508
pv1n->st_edge.flow += delta;
3509
pv2n->st_edge.flow += delta;
3510
pBNS->tot_st_flow += 2*delta;
3514
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3516
CurrEdges.num_edges = 0; /* clear current edge list */
3517
if ( cur_success ) {
3518
tot_succes += cur_success;
3519
/* recalculate InChI from the structure */
3520
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3521
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3524
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3527
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3528
goto exit_function; /* no fixed-H found */
3530
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3533
if ( !pc2i->bHasDifference ) {
3534
goto exit_function; /* nothing to do */
3539
if ( pc2i->nNumTgDiffMinus ) {
3540
/*----------------------------------------------------------------*/
3541
/* case 16: restored: O=X-NH(-) orig.: O(-)-X=NH */
3542
/* t-group: (H,-) (2H) */
3543
/* O(-) = S, Se, Te; N = N; */
3544
/* Solution: move (-) from O(-) to -NH(-) */
3545
/*----------------------------------------------------------------*/
3546
int num_SB_N_Minus = 0, num_DB_O_Neutr = 0, iat, itg;
3547
short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
3548
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
3549
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
3550
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
3552
for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
3553
if ( pStruct->ti.t_group[itg].nNumEndpoints != pStruct->One_ti.t_group[itg].nNumEndpoints ||
3554
pStruct->ti.t_group[itg].num[1] >= pStruct->One_ti.t_group[itg].num[1] ) {
3557
CurrEdges.num_edges = num_SB_N_Minus = num_DB_O_Neutr = 0;
3559
for ( j = 0, k = pStruct->One_ti.t_group[itg].nFirstEndpointAtNoPos;
3560
j < pStruct->One_ti.t_group[itg].nNumEndpoints; j ++ ) {
3561
i = pStruct->One_ti.nEndpointAtomNumber[k+j]; /* canonical number in restored struct. */
3562
iat = nCanon2AtnoRevrs[i];
3563
if ( /* in restored atom: charge=0, has no H, has double bond, O, S, Se, Te */
3564
num_DB_O_Neutr < MAX_DIFF_FIXH &&
3565
at2[iat].charge == 0 && !at2[iat].num_H &&
3566
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3567
pVA[iat].cNumValenceElectrons == 6 &&
3568
/* in orig.InChI: an endpoint, may have fixed-H */
3569
pStruct->endpoint[i] &&
3570
/*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/
3571
!(nMobHInChI && nMobHInChI[i] ) &&
3573
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
3575
iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
3577
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3582
if ( /* in restored atom: charge=-1, has H, has double bond, N */
3583
num_SB_N_Minus < MAX_DIFF_FIXH &&
3584
at2[iat].charge == -1 && at2[iat].num_H &&
3585
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3586
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
3587
/* in orig.InChI: an endpoint, has no fixed-H */
3588
pStruct->endpoint[i] &&
3589
(pStruct->fixed_H && pStruct->fixed_H[i]) &&
3590
!(nMobHInChI && nMobHInChI[i] ) &&
3592
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 &&
3593
0 == pBNS->edge[e].forbidden ) {
3595
iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
3597
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3603
if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O_Neutr ) ) {
3604
/* detected; attempt to fix */
3605
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3606
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
3607
/* allow stereobonds in rings change */
3609
if ( forbidden_stereo_edge_mask )
3610
RemoveForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
3613
for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
3614
iat = iat_SB_N_Minus[i];
3615
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
3618
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3619
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3621
/*pe->forbidden |= forbidden_edge_mask;*/
3623
pv1->st_edge.flow -= delta;
3624
pv2->st_edge.flow -= delta;
3625
pBNS->tot_st_flow -= 2*delta;
3627
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3628
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3630
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
3631
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
3632
/* Moved (-) charge to =O => nDeltaCharge == 1 */
3633
/* Flow change on pe (-)charge edge (atom -NH(-)) is not known to RunBnsTestOnce()) */
3634
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3637
cur_success ++; /* 16 */
3640
pe->forbidden &= forbidden_edge_mask_inv;
3642
pv1->st_edge.flow += delta;
3643
pv2->st_edge.flow += delta;
3644
pBNS->tot_st_flow += 2*delta;
3648
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3650
if ( forbidden_stereo_edge_mask )
3651
SetForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
3654
CurrEdges.num_edges = 0; /* clear current edge list */
3655
if ( cur_success ) {
3656
tot_succes += cur_success;
3657
/* recalculate InChI from the structure */
3658
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3659
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3662
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3665
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3666
goto exit_function; /* no fixed-H found */
3668
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3671
if ( !pc2i->bHasDifference ) {
3672
goto exit_function; /* nothing to do */
3678
if ( pc2i->nNumRemHInChI < pc2i->nNumRemHRevrs ) {
3679
/*--------------------------------------------------------------*/
3680
/* case 17: restored: OH(+)=AB-O- orig. HO-AB=O(+)- */
3681
/* number of removed H: n+m n */
3682
/* OH(+) = N, O, S, Se; -O- = P,As,O,S,Se,Te,F,Cl,Br,I */
3683
/* Solution: move (+) from OH(+) to -O- */
3684
/*--------------------------------------------------------------*/
3685
int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
3686
short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
3687
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
3688
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
3689
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
3691
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
3692
iat = nCanon2AtnoRevrs[i];
3693
if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */
3694
num_DB_Charged < MAX_DIFF_FIXH &&
3695
at2[iat].charge == 1 && at2[iat].num_H &&
3696
at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3697
(pVA[iat].cNumValenceElectrons == 6 ||
3698
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) &&
3700
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
3702
iat_DB_Charged[num_DB_Charged ++] = iat;
3704
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3709
if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */
3710
num_SB_Neutr < MAX_DIFF_FIXH &&
3711
at2[iat].charge == 0 && !at2[iat].num_H &&
3712
at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
3713
(pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 ||
3714
pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1 ) &&
3715
/* in orig.InChI: not an endpoint */
3716
!pStruct->endpoint[i] &&
3717
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
3718
!(nMobHInChI && nMobHInChI[i] ) &&
3720
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 &&
3721
0 == pBNS->edge[e].forbidden ) {
3723
iat_SB_Neutr[num_SB_Neutr ++] = iat;
3725
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3730
if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
3731
BNS_VERTEX *pv1n, *pv2n;
3732
BNS_EDGE *pe1n, *pe2n;
3735
num_try = inchi_min( num_try, pc2i->nNumRemHRevrs-pc2i->nNumRemHInChI);
3736
/* detected; attempt to fix */
3737
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3738
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
3740
for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
3741
iat = iat_DB_Charged[i];
3742
pe = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
3745
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3746
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3748
for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
3749
pe1n = pBNS->edge + pv1->iedge[j];
3750
if ( pe1n->flow && !pe1n->forbidden ) {
3751
pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
3756
continue; /* not found */
3758
for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
3759
pe2n = pBNS->edge + pv2->iedge[j];
3760
if ( pe2n->flow && !pe2n->forbidden ) {
3761
pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
3766
continue; /* not found */
3769
pe1n->flow -= delta;
3770
pe2n->flow -= delta;
3771
pv1n->st_edge.flow -= delta;
3772
pv2n->st_edge.flow -= delta;
3773
pBNS->tot_st_flow -= 2*delta;
3775
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3776
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3778
if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
3779
vPathEnd == v2n && vPathStart == v1n) &&
3780
(nDeltaCharge == 0 || nDeltaCharge == 1) ) {
3781
/* Moved charge from OH(+) to -O- => nDeltaCharge == 1 or 0 if pe2n = -O- charge edge */
3782
/* Flow change on pe (+)charge edge (atom OH(+)) is not known to RunBnsTestOnce()) */
3783
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3786
cur_success ++; /* 17 */
3790
pe1n->flow += delta;
3791
pe2n->flow += delta;
3792
pv1n->st_edge.flow += delta;
3793
pv2n->st_edge.flow += delta;
3794
pBNS->tot_st_flow += 2*delta;
3798
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3800
CurrEdges.num_edges = 0; /* clear current edge list */
3801
if ( cur_success ) {
3802
tot_succes += cur_success;
3803
/* recalculate InChI from the structure */
3804
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3805
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3808
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3811
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3812
goto exit_function; /* no fixed-H found */
3814
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3817
if ( !pc2i->bHasDifference ) {
3818
goto exit_function; /* nothing to do */
3823
if ( (pc2i->nNumTgInChI && pStruct->endpoint &&
3824
pc2i->nNumTgMInChI > pc2i->nNumTgMRevrs && pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs ) ) {
3825
/*-----------------------------------------------------------------*/
3827
/* case 18: restored:-N=AB-X -(-)N-AB-X(+) */
3830
/* non non taut non */
3831
/* taut taut taut */
3832
/* X = any heteroatom N=N */
3833
/* t-group in original has (Hn,-m) in the restored: (Hn,-m+1) */
3834
/* same num_H and more (-) than in the restored structure */
3835
/* atom X is not taut in both */
3836
/* Solution: separate charges between -N(III)= and X */
3837
/*-----------------------------------------------------------------*/
3838
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
3839
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
3840
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
3841
int iat, e1, itg, max_success;
3842
CurrEdges.num_edges = 0;
3845
/* search for -N= */
3846
for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
3847
if ( pStruct->ti.t_group[itg].nNumEndpoints <= pStruct->One_ti.t_group[itg].nNumEndpoints ||
3848
pStruct->ti.t_group[itg].num[1] <= pStruct->One_ti.t_group[itg].num[1] ) {
3851
CurrEdges.num_edges = 0;
3853
for ( j = 0, k = pStruct->ti.t_group[itg].nFirstEndpointAtNoPos;
3854
j < pStruct->ti.t_group[itg].nNumEndpoints; j ++ ) {
3855
i = pStruct->ti.nEndpointAtomNumber[k+j]; /* canonical number in restored struct. */
3856
iat = nCanon2AtnoRevrs[i];
3857
if ( !pStruct->endpoint[i] || !at_Mobile_H_Revrs || at_Mobile_H_Revrs[iat].endpoint ||
3858
pVA[i].cNumValenceElectrons != 5 || pVA[i].cPeriodicRowNumber != 1 ||
3859
2 != at2[iat].valence || at2[iat].num_H || at2[iat].radical ||
3860
0 <= (e1=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e1].flow ||
3861
0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow ) {
3865
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
3870
if ( !(max_success = CurrEdges.num_edges) ) {
3874
for ( i = 0; i < pStruct->num_atoms && cur_success < max_success; i ++ ) {
3875
iat = nCanon2AtnoRevrs[i];
3876
if ( pStruct->endpoint[i] || !pVA[i].cNumValenceElectrons || pVA[i].cNumValenceElectrons == 4 ||
3877
at2[iat].num_H || at2[iat].radical ||
3878
0 <= (e1=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e1].flow ||
3879
0 > (e=pVA[iat].nCPlusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow != 1 ) {
3882
/* try to move the charge */
3883
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3884
SetForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
3885
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
3887
pe = pBNS->edge + e;
3890
pv1 = pBNS->vert + (v1 = pe->neighbor1);
3891
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
3895
pv1->st_edge.flow -= delta;
3896
pv2->st_edge.flow -= delta;
3897
pBNS->tot_st_flow -= 2*delta;
3899
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
3900
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
3902
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
3903
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
3904
/* Created (-) charge on -N= => nDeltaCharge == 1 */
3905
/* Flow change on pe (+)charge edge (atom X) is not known to RunBnsTestOnce()) */
3906
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
3909
cur_success ++; /* 18 */
3913
pv1->st_edge.flow += delta;
3914
pv2->st_edge.flow += delta;
3915
pBNS->tot_st_flow += 2*delta;
3920
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3921
RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
3922
CurrEdges.num_edges = 0; /* clear current edge list */
3926
if ( cur_success ) {
3927
tot_succes += cur_success;
3928
/* recalculate InChI from the structure */
3929
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
3930
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
3933
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
3936
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
3937
goto exit_function; /* no fixed-H found */
3939
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
3942
if ( !pc2i->bHasDifference ) {
3943
goto exit_function; /* nothing to do */
3947
if ( pc2i->len_c2at >= 1 ) {
3948
/*--------------------------------------------------------------*/
3949
/* case 19 restored: M--OH original: M(-)==OH(+) */
3950
/* FixH: metal 0 1 */
3952
/* O = O, S, Se, Te; not taut. in InChI */
3953
/* In restored structure has H; tautomeric or not tautomeric */
3954
/* Solution: move (+) from -OH to M; charhe on M may vary */
3955
/*--------------------------------------------------------------*/
3957
EdgeIndex eOHPlus, eMPlus, eMMinus, eOMBond;
3958
BNS_EDGE *peOHPlus, *peMPlus, *peMMinus, *peOMBond;
3959
int iatMetal, ChargeOnMetal, DeltaChargeExpected;
3962
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
3963
iat = pc2i->c2at[i].atomNumber;
3964
if ( /* orig. InChI info: =NH2(+), =OH(+) */
3965
(pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
3966
/*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */
3967
(e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
3968
pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 &&
3969
/* reversed structure info: */
3970
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 1 &&
3971
pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
3972
at2[iat].valence == 1 &&
3973
at2[iat].valence == at2[iat].chem_bonds_valence &&
3975
pVA[iatMetal=at2[iat].neighbor[0]].cMetal &&
3976
(eMPlus=pVA[iatMetal].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eMPlus].forbidden &&
3977
(eMMinus=pVA[iatMetal].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[eMMinus].forbidden &&
3978
!pBNS->edge[eOMBond=pBNS->vert[iat].iedge[0]].forbidden
3981
/* -OH charge edges */
3982
if ( ret = AddToEdgeList( &CurrEdges, iat, INC_ADD_EDGE ) ) {
3987
if ( CurrEdges.num_edges ) {
3989
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
3990
SetForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask );
3991
SetForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask );
3992
for ( i = 0; i < CurrEdges.num_edges; i ++ ) {
3993
/* v1 is -OH, v2 is adjacent to it Metal */
3994
iat = CurrEdges.pnEdges[i];
3995
iatMetal = at2[iat].neighbor[0];
3996
peOHPlus = pBNS->edge + (eOHPlus = pVA[iat].nCPlusGroupEdge-1);
3997
peMPlus = pBNS->edge + (eMPlus = pVA[iatMetal].nCPlusGroupEdge-1);
3998
peMMinus = pBNS->edge + (eMMinus = pVA[iatMetal].nCMinusGroupEdge-1);
3999
peOMBond = pBNS->edge + (eOMBond =pBNS->vert[iat].iedge[0]);
4000
/* remove forbidden edge masks */
4001
peMPlus->forbidden &= forbidden_edge_mask_inv;
4002
peMMinus->forbidden &= forbidden_edge_mask_inv;
4003
peOMBond->forbidden &= forbidden_edge_mask_inv;
4005
ChargeOnMetal = (peMPlus->cap - peMPlus->flow) - peMMinus->flow;
4006
if ( 1 == ChargeOnMetal ) {
4007
/* We are going to subtract 1 from the charge on Metal */
4008
/* Added (+)charge to -OH is not known to RunBnsTestOnce() */
4009
DeltaChargeExpected = -1; /* charge will become = 0 */
4011
if ( 0 == ChargeOnMetal ) {
4012
DeltaChargeExpected = 1; /* charge on Metal will be created */
4014
DeltaChargeExpected = 0;
4021
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4022
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4024
pe->flow -= delta; /* remove (-) from AB-O(-) */
4025
pv1->st_edge.flow -= delta;
4026
pv2->st_edge.flow -= delta;
4027
pBNS->tot_st_flow -= 2*delta;
4029
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4030
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4032
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4033
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == DeltaChargeExpected ) {
4034
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4037
cur_success ++; /* 19 */
4041
pv1->st_edge.flow += delta;
4042
pv2->st_edge.flow += delta;
4043
pBNS->tot_st_flow += 2*delta;
4046
/* set forbidden edge masks back */
4047
peMPlus->forbidden |= forbidden_edge_mask;
4048
peMMinus->forbidden |= forbidden_edge_mask;
4049
peOMBond->forbidden |= forbidden_edge_mask;
4051
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4052
RemoveForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask );
4053
RemoveForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask );
4055
CurrEdges.num_edges = 0; /* clear current edge list */
4056
if ( cur_success ) {
4057
tot_succes += cur_success;
4058
/* recalculate InChI from the structure */
4059
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
4060
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
4063
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
4066
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
4067
goto exit_function; /* no fixed-H found */
4069
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
4072
if ( !pc2i->bHasDifference ) {
4073
goto exit_function; /* nothing to do */
4078
if ( pc2i->len_c2at > 1 && pc2i->nNumTgRevrs && pc2i->nNumTgInChI) {
4079
/*--------------------------------------------------------------*/
4080
/* case 20: restored: O(-)-AB=N- original: O=AB-N(-)- */
4081
/* FixH: 0 0 0 -1 */
4083
/* taut non-taut non-taut taut */
4086
/* O = O, S, Se; N = N, O, S, Se, Te; */
4087
/* restored atoms are taut/non-taut; original are opposite. */
4088
/* Solution: move (-) from O(-) to =N- */
4089
/*--------------------------------------------------------------*/
4090
int num_SB_O_Minus = 0, num_DB_N = 0, iat;
4091
short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_N[MAX_DIFF_FIXH];
4093
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
4095
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4096
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
4097
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
4098
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
4101
CurrEdges.num_edges = 0; /* clear current edge list */
4102
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
4103
iat = pc2i->c2at[i].atomNumber;
4104
if ( /* orig. InChI info: =O or -N= */
4105
num_DB_N < MAX_DIFF_FIXH &&
4106
pc2i->c2at[i].endptInChI &&
4107
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4108
pBNS->edge[e].flow == 0 &&
4109
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
4110
/* if more than 1 t-group are in orig. InChI then do not move (-) to N */
4111
(pc2i->nNumTgInChI == 1 || pc2i->c2at[i].nValElectr == 6) &&
4112
/* reversed structure info: */
4113
!pc2i->c2at[i].endptRevrs &&
4114
pc2i->c2at[i].nFixHRevrs == 0 && /*pc2i->c2at[i].nMobHRevrs == 0 &&*/
4115
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
4116
at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
4117
iat_DB_N[num_DB_N ++] = iat;
4118
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
4122
if ( /* orig. InChI info: -O(-) */
4123
num_SB_O_Minus < MAX_DIFF_FIXH &&
4124
!pc2i->c2at[i].endptInChI &&
4125
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4126
pBNS->edge[e].flow == 1 &&
4127
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
4128
pc2i->c2at[i].nValElectr == 6 &&
4129
/* reversed structure info: */
4130
pc2i->c2at[i].endptRevrs &&
4131
pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 &&
4132
pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H &&
4133
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 ) {
4134
iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
4138
/* search among N that are tautomeric in both cases */
4139
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4140
if ( !pStruct->endpoint[i] ) {
4143
iat = nCanon2AtnoRevrs[i];
4144
if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
4145
num_DB_N < MAX_DIFF_FIXH &&
4146
at2[iat].charge == 0 && !at2[iat].num_H &&
4147
at2[iat].valence + 1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
4148
/* in orig.InChI: an endpoint, has no H */
4149
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
4150
/*!(nMobHInChI && nMobHInChI[i] ) &&*/
4152
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4153
!pBNS->edge[e].flow ) {
4155
iat_DB_N[num_DB_N ++] = iat;
4156
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
4162
if ( num_try = inchi_min( num_SB_O_Minus, num_DB_N ) ) {
4163
/* detected; attempt to fix */
4164
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4165
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
4167
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
4168
iat = iat_SB_O_Minus[i];
4169
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
4172
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4173
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4176
pv1->st_edge.flow -= delta;
4177
pv2->st_edge.flow -= delta;
4178
pBNS->tot_st_flow -= 2*delta;
4180
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4181
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4183
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4184
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
4185
/* Added (-) charge to =N- => nDeltaCharge == 1 */
4186
/* Flow change on pe (-)charge edge (atom -O(-)) is not known to RunBnsTestOnce()) */
4187
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4190
cur_success ++; /* 20 */
4194
pv1->st_edge.flow += delta;
4195
pv2->st_edge.flow += delta;
4196
pBNS->tot_st_flow += 2*delta;
4200
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4202
CurrEdges.num_edges = 0; /* clear current edge list */
4203
if ( cur_success ) {
4204
tot_succes += cur_success;
4205
/* recalculate InChI from the structure */
4206
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
4207
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
4210
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
4213
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
4214
goto exit_function; /* no fixed-H found */
4216
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
4219
if ( !pc2i->bHasDifference ) {
4220
goto exit_function; /* nothing to do */
4224
if ( pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumTgHInChI && pStruct->endpoint ) {
4225
/*--------------------------------------------------------------*/
4228
/* case 21: restored: R=S=O original: R-S=O */
4231
/* All O are taut R is not taut */
4233
/* In addition, another atom O that should have been tautomeric */
4234
/* or has H(+) added in Mobile-H layer is not like that */
4235
/* O = O, S, Se; S=S, Se, Te */
4236
/* Solution: move (-) from O(-) to =O */
4237
/* these atoms are tautomeric in restored structure */
4238
/*--------------------------------------------------------------*/
4239
int num_SB_O_Minus = 0, num_DB_O = 0, iat, iS;
4240
short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_Central[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
4241
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
4242
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4243
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
4245
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
4246
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
4248
CurrEdges.num_edges = 0; /* clear current edge list */
4250
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
4251
iat = pc2i->c2at[i].atomNumber;
4252
if ( /* orig. InChI info: =O */
4253
num_DB_O < MAX_DIFF_FIXH &&
4254
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
4255
(pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) &&
4256
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4257
pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
4258
/* reversed structure info: */
4259
!(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
4260
pc2i->c2at[i].nFixHRevrs == 0 &&
4261
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
4262
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
4263
iat_DB_O[num_DB_O ++] = iat;
4264
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
4269
for ( i = 0; num_DB_O && i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4270
if ( !pStruct->endpoint[i] ) {
4273
iat = nCanon2AtnoRevrs[i];
4274
if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
4275
num_SB_O_Minus < MAX_DIFF_FIXH &&
4276
at2[iat].charge == -1 && !at2[iat].num_H &&
4277
at2[iat].valence == 1 && at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
4278
pVA[iat].cNumValenceElectrons == 6 &&
4279
(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
4280
/* in orig.InChI: an endpoint, has no H */
4281
!(pStruct->fixed_H && pStruct->fixed_H[i]) &&
4282
/*!(nMobHInChI && nMobHInChI[i] ) &&*/
4284
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4285
pBNS->edge[e].flow ) {
4286
int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0, nNumOthers = 0, nNumNegEndp = 0;
4287
/* traverse neighbors of the centerpoint iS */
4288
iS = at2[i].neighbor[0];
4289
for ( j = 0; j < num_SB_O_Minus; j ++ ) {
4290
if ( iat_Central[j] == iS )
4293
if ( j < num_SB_O_Minus ) {
4294
continue; /* have already been there */
4296
for ( j = 0; j < at[iS].valence; j ++ ) {
4297
int bond_type = at2[iS].bond_type[j];
4298
k = at2[iS].neighbor[j];
4302
if ( pStruct->endpoint[k] == pStruct->endpoint[i] ) {
4303
nNumTautSB += ( bond_type == BOND_TYPE_SINGLE );
4304
nNumTautDB += ( bond_type == BOND_TYPE_DOUBLE );
4306
if ( bond_type == BOND_TYPE_DOUBLE ) {
4309
if ( bond_type == BOND_TYPE_SINGLE ) {
4314
if ( at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 &&
4315
at2[k].charge == -1 && pVA[k].cNumValenceElectrons == 6 ) {
4319
if ( !nNumTautSB ) {
4322
if ( !( nNumOtherDB && nNumTautDB ) ) {
4323
continue; /* ignore */
4326
iat_SB_O_Minus[num_SB_O_Minus] = iat;
4327
iat_Central[num_SB_O_Minus ++] = iS;
4330
if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O ) ) {
4331
/* detected; attempt to fix */
4332
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4333
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
4335
for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
4336
iat = iat_SB_O_Minus[i];
4337
pe = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
4340
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4341
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4343
pe->forbidden |= forbidden_edge_mask;
4345
pv1->st_edge.flow -= delta;
4346
pv2->st_edge.flow -= delta;
4347
pBNS->tot_st_flow -= 2*delta;
4349
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4350
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4352
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4353
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
4354
/* Added (-) charge to =O => nDeltaCharge == 1 */
4355
/* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
4356
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4359
cur_success ++; /* 21 */
4363
pv1->st_edge.flow += delta;
4364
pv2->st_edge.flow += delta;
4365
pBNS->tot_st_flow += 2*delta;
4369
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4371
CurrEdges.num_edges = 0; /* clear current edge list */
4372
if ( cur_success ) {
4373
tot_succes += cur_success;
4374
/* recalculate InChI from the structure */
4375
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
4376
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
4379
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
4382
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
4383
goto exit_function; /* no fixed-H found */
4385
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
4388
if ( !pc2i->bHasDifference ) {
4389
goto exit_function; /* nothing to do */
4394
if ( pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) {
4395
/*--------------------------------------------------------------*/
4398
/* case 21a:restored: R=S-R' =X original: R-S-R' -X(-) */
4401
/* All O and X are taut O and X are not taut */
4402
/* it is possible that X is R */
4404
/* O = O, S, Se; S=S, Se, Te; X = N, O, S, Se, Te */
4405
/* Solution: move (-) from O(-) to =X */
4406
/* these atoms are tautomeric in restored structure */
4407
/*--------------------------------------------------------------*/
4410
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
4412
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4413
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
4415
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
4416
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
4418
EDGE_LIST OtherSO, CentralS, SOMinus, MinusAcceptord;
4419
CurrEdges.num_edges = 0; /* clear current edge list */
4420
AllocEdgeList( &OtherSO, EDGE_LIST_CLEAR );
4421
AllocEdgeList( &CentralS, EDGE_LIST_CLEAR );
4422
AllocEdgeList( &SOMinus, EDGE_LIST_CLEAR );
4423
AllocEdgeList( &MinusAcceptord, EDGE_LIST_CLEAR );
4425
if ( !at_Mobile_H_Revrs ) {
4428
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
4429
iat = pc2i->c2at[i].atomNumber;
4430
if ( /* orig. InChI info: -X(-) */
4431
/*num_DB_O < MAX_DIFF_FIXH &&*/
4432
/*pc2i->c2at[i].nValElectr == 6 */ /* O, S, Se, Te */
4433
!pc2i->c2at[i].endptInChI &&
4434
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4435
pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
4436
/* reversed structure info: */
4437
(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
4438
pc2i->c2at[i].nFixHRevrs == 0 &&
4439
/*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ !at2[iat].num_H ) {
4440
if ( pVA[iat].cNumValenceElectrons == 6 && at2[iat].charge == -1 &&
4441
pBNS->edge[e].flow &&
4442
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 &&
4443
pVA[iS=(int)at2[iat].neighbor[0]].cNumValenceElectrons == 6 && pVA[iS].cPeriodicRowNumber > 1 &&
4444
at2[iS].valence >= 4 ) {
4445
/* a candidate for S in -SO2- */
4446
int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0;
4447
int nNumOthers = 0, nNumNegEndp = 0, nNumEndpO = 0;
4448
/* check whether we have already found it */
4449
if ( 0 <= FindInEdgeList( &CentralS, iS ) ) {
4452
for ( j = 0; j < at[iS].valence; j ++ ) {
4453
int bond_type = at2[iS].bond_type[j];
4454
k = at2[iS].neighbor[j];
4458
if ( pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint && !at2[k].endpoint ) {
4459
nNumTautSB += ( bond_type == BOND_TYPE_SINGLE );
4460
nNumTautDB += ( bond_type == BOND_TYPE_DOUBLE );
4461
nNumEndpO += (pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1);
4463
if ( bond_type == BOND_TYPE_DOUBLE ) {
4466
if ( bond_type == BOND_TYPE_SINGLE ) {
4471
if ( at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 &&
4472
at2[k].charge == -1 && pVA[k].cNumValenceElectrons == 6 ) {
4479
if ( nNumTautSB + nNumTautDB + nNumOtherDB <= nNumEndpO ) {
4480
continue; /* ignore */
4482
/* collect double bond taut =O */
4483
for ( j = 0; j < at[iS].valence; j ++ ) {
4484
int bond_type = at2[iS].bond_type[j];
4485
k = at2[iS].neighbor[j];
4486
if ( pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint &&
4487
!at2[k].endpoint && pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1 &&
4488
0 <= (e=pVA[k].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden ) {
4489
if ( bond_type == BOND_TYPE_DOUBLE && !at2[k].charge && !pBNS->edge[e].flow) {
4490
/* charges to be unchanged */
4491
if ( ret = AddToEdgeList( &OtherSO, e, INC_ADD_EDGE ) ) {
4495
if ( bond_type == BOND_TYPE_SINGLE && at2[k].charge == -1 && pBNS->edge[e].flow ) {
4496
/* charges to be removed */
4497
if ( ret = AddToEdgeList( &SOMinus, e, INC_ADD_EDGE ) ) {
4503
if ( ret = AddToEdgeList( &CentralS, iS, INC_ADD_EDGE ) ) {
4507
if ( at2[iat].charge == 0 && !pBNS->edge[e].flow &&
4508
at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
4509
/* changeable charges */
4510
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
4516
/* remove unchangeable from changeable */
4517
for ( i = 0; i < OtherSO.num_edges; i ++ ) {
4518
RemoveFromEdgeListByValue( &CurrEdges, OtherSO.pnEdges[i] );
4521
if ( num_try = inchi_min( SOMinus.num_edges, CurrEdges.num_edges ) ) {
4522
/* detected; attempt to fix */
4523
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4524
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
4526
for ( i = 0; i < SOMinus.num_edges && cur_success < num_try; i ++ ) {
4527
pe = pBNS->edge + SOMinus.pnEdges[i];
4530
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4531
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4533
/*pe->forbidden |= forbidden_edge_mask;*/
4535
pv1->st_edge.flow -= delta;
4536
pv2->st_edge.flow -= delta;
4537
pBNS->tot_st_flow -= 2*delta;
4539
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4540
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4542
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4543
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
4544
/* Added (-) charge to =O => nDeltaCharge == 1 */
4545
/* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
4546
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4549
cur_success ++; /* 21a */
4553
pv1->st_edge.flow += delta;
4554
pv2->st_edge.flow += delta;
4555
pBNS->tot_st_flow += 2*delta;
4559
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4562
CurrEdges.num_edges = 0; /* clear current edge list */
4563
AllocEdgeList( &OtherSO, EDGE_LIST_FREE );
4564
AllocEdgeList( &CentralS, EDGE_LIST_FREE );
4565
AllocEdgeList( &SOMinus, EDGE_LIST_FREE );
4566
AllocEdgeList( &MinusAcceptord, EDGE_LIST_FREE );
4567
if ( cur_success ) {
4568
tot_succes += cur_success;
4569
/* recalculate InChI from the structure */
4570
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
4571
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
4574
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
4577
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
4578
goto exit_function; /* no fixed-H found */
4580
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
4583
if ( !pc2i->bHasDifference ) {
4584
goto exit_function; /* nothing to do */
4589
if ( pc2i->len_c2at ) {
4590
/*------------------------------------------------------------------*/
4591
/* case 22: restored: N(-)=N(+)=C...=O orig: N#N-N=...-O(-) */
4592
/* im InChI -O(-) may have H(+) added by Normalization */
4593
/* or may be tautomeric */
4594
/* Solution: move (-) from N(-) to =O */
4596
/*------------------------------------------------------------------*/
4597
int num_DB_O = 0, iat;
4598
short iat_DB_O[MAX_DIFF_FIXH];
4599
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
4600
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4601
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
4603
BNS_EDGE *peDB_O_Minus;
4605
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
4606
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
4608
CurrEdges.num_edges = 0; /* clear current edge list */
4610
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
4611
iat = pc2i->c2at[i].atomNumber;
4612
if ( /* orig. InChI info: =O */
4613
num_DB_O < MAX_DIFF_FIXH &&
4614
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
4615
(pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) &&
4616
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4617
pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
4618
/* reversed structure info: */
4619
!(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
4620
pc2i->c2at[i].nFixHRevrs == 0 &&
4621
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
4622
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
4623
iat_DB_O[num_DB_O ++] = iat;
4626
for ( i = 0; num_DB_O && i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4627
iat = nCanon2AtnoRevrs[i];
4628
if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
4629
at2[iat].charge == -1 && !at2[iat].num_H &&
4630
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 && !pVA[iat].cMetal &&
4631
pVA[iat].cNumValenceElectrons == 5 &&
4632
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4633
pBNS->edge[e].flow &&
4634
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
4635
pVA[iN2=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
4636
at2[iat].bond_type[0] == BOND_TYPE_DOUBLE &&
4637
at2[iN2].charge == 1 && at2[iN2].valence == 2 && at2[iN2].chem_bonds_valence == 4 &&
4638
pVA[iC=at2[iN2].neighbor[at2[iN2].neighbor[0]==iN2]].cNumValenceElectrons == 4 ) {
4640
if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
4645
if ( num_try = inchi_min( CurrEdges.num_edges, num_DB_O ) ) {
4646
/* detected; attempt to fix */
4647
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4648
RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
4650
for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
4653
peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
4654
pe = pBNS->edge + pBNS->vert[iat].iedge[0];
4657
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4658
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4660
pe->forbidden |= forbidden_edge_mask;
4661
peDB_O_Minus->forbidden &= forbidden_edge_mask_inv;
4664
pv1->st_edge.flow -= delta;
4665
pv2->st_edge.flow -= delta;
4666
pBNS->tot_st_flow -= 2*delta;
4668
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4669
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4671
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4672
vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
4673
/* Added (-) charge to =O and removed from =N(-) => nDeltaCharge == 0 */
4674
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4677
cur_success ++; /* 22 */
4681
pv1->st_edge.flow += delta;
4682
pv2->st_edge.flow += delta;
4683
pBNS->tot_st_flow += 2*delta;
4686
pe->forbidden &= forbidden_edge_mask_inv;
4687
peDB_O_Minus->forbidden |= forbidden_edge_mask;
4689
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4691
CurrEdges.num_edges = 0; /* clear current edge list */
4692
if ( cur_success ) {
4693
tot_succes += cur_success;
4694
/* recalculate InChI from the structure */
4695
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
4696
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
4699
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
4702
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
4703
goto exit_function; /* no fixed-H found */
4705
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
4708
if ( !pc2i->bHasDifference ) {
4709
goto exit_function; /* nothing to do */
4713
if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 ) {
4714
/*------------------------------------------------------------------*/
4715
/* case 23: -NO2 are to be tautomeric but they are not AND */
4716
/* InChI has a SINGLE tautomeric group */
4719
/* Solution: convert \ \ */
4720
/* N-X=...-Z(-) => N(+)=X- ...=Z */
4726
/* N-X=...-Z(-) => N=X- ...=Z */
4731
/* (a) move (-) from other tautomeric atom to O in O=N-X */
4732
/* or from other atom that has to be tautomeric */
4734
/* (b) create (+) [ion pair creation] on N as in */
4738
/* -C=N => =C-N(+) */
4742
/*------------------------------------------------------------------*/
4743
int num_DB_O = 0, iat;
4744
short iat_DB_O[MAX_DIFF_FIXH], iat_NO2[MAX_DIFF_FIXH];
4745
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
4746
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4747
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
4749
inp_ATOM *atfMobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
4750
pStruct->pOne_norm_data[1]->at_fixed_bonds)?
4751
pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
4753
S_CHAR *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
4754
S_CHAR *pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
4755
pStruct->pOneINChI[1]->nNum_H :
4756
(pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
4757
pStruct->pOneINChI[0]->nNum_H : NULL;
4758
int iN, one_success;
4759
BNS_EDGE *peDB_O_Minus;
4760
int neigh, nNumO, nNumOthers;
4761
#define CHG_SET_NOOH 0
4762
#define CHG_SET_WRONG_TAUT 1
4763
#define CHG_SET_TAUT 2
4764
#define CHG_LAST_SET 2 /* the last index in trying */
4765
#define CHG_SET_O_FIXED 3
4766
#define CHG_SET_NUM 4
4767
EDGE_LIST ChangeableEdges[CHG_SET_NUM];
4768
memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
4769
/* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
4771
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
4772
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
4774
CurrEdges.num_edges = 0; /* clear current edge list */
4776
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
4777
iat = pc2i->c2at[i].atomNumber;
4778
if ( /* orig. InChI info: taut in orig. InChI =O located in -NO2 that is not taut in Reconstructed InChI */
4779
num_DB_O < MAX_DIFF_FIXH &&
4780
pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
4781
(pc2i->c2at[i].endptInChI /*|| pc2i->c2at[i].nMobHInChI*/) &&
4782
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
4783
pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
4784
/* reversed structure info: */
4785
!(pc2i->c2at[i].endptRevrs /*|| pc2i->c2at[i].nMobHRevrs*/) &&
4786
pc2i->c2at[i].nFixHRevrs == 0 &&
4787
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
4788
at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 &&
4789
/* find whether it belongs to NO2 */
4790
pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
4791
at2[iN].valence == 3 && (at2[iN].charge == 0 || at2[iN].charge == 1) &&
4792
at2[iN].chem_bonds_valence == 5 - at2[iN].charge ) {
4793
/* find the second O */
4794
nNumO = nNumOthers = 0;
4795
for ( k = 0; k < at2[iN].valence; k ++ ) {
4796
neigh = at2[iN].neighbor[k];
4797
if ( neigh == iat ) {
4800
if ( pVA[neigh].cNumValenceElectrons == 6 &&
4801
pStruct->endpoint[neigh] &&
4802
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[neigh].endpoint) &&
4803
at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
4804
at2[neigh].radical == 0 && (at2[neigh].charge == 0 || at2[neigh].charge == -1) &&
4805
at2[neigh].chem_bonds_valence - at2[neigh].charge == 2) {
4808
if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
4809
at2[neigh].valence > 1 &&
4810
at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
4814
if ( nNumO != 1 || nNumOthers != 1 ) {
4817
for ( k = 0; k < num_DB_O; k ++ ) {
4818
if ( iat_NO2[k] == iN ) {
4822
if ( k == num_DB_O ) {
4823
iat_NO2[num_DB_O] = iN;
4824
iat_DB_O[num_DB_O ++] = iat;
4826
/* save the edge to avoid interference */
4827
if ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ) {
4833
/* 1. search for =N(=O)-OH; assume =N(+)(-O(-))(-OH) does not happen */
4834
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4836
iat = nCanon2AtnoRevrs[i];
4837
if ( !pStruct->endpoint[i] || pVA[i].cNumValenceElectrons != 6 ||
4838
at2[iat].valence != 1 || at2[iat].charge ||
4839
0 > (e = pVA[iat].nCMinusGroupEdge-1) ||
4840
at2[iat].num_H + at2[iat].chem_bonds_valence != 2 ||
4841
pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons != 5 ||
4842
0 > (e = pVA[iN].nCPlusGroupEdge-1) ||
4843
pBNS->edge[e].forbidden || !pBNS->edge[e].flow ||
4844
at2[iN].charge || at2[iN].valence != 3 || at2[iN].chem_bonds_valence != 5) {
4847
/* find the second O, -OH */
4848
nNumO = nNumOthers = 0;
4849
for ( k = 0; k < at2[iN].valence; k ++ ) {
4850
neigh = at2[iN].neighbor[k];
4851
if ( neigh == iat ) {
4854
if ( pVA[neigh].cNumValenceElectrons == 6 &&
4855
pStruct->endpoint[neigh] &&
4856
at2[neigh].valence == 1 && at2[neigh].num_H == 1 &&
4857
at2[neigh].radical == 0 && (at2[neigh].charge == 0 ) ) {
4860
if ( at2[iN].bond_type[k] == BOND_TYPE_DOUBLE &&
4861
at2[neigh].valence >= 2 &&
4862
at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
4866
if ( nNumO != 1 || nNumOthers != 1 ) {
4869
/* save edges to be changed */
4870
if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NOOH], e, INC_ADD_EDGE )) ||
4871
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ))) {
4874
if ( NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
4875
(( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NOOH], j, INC_ADD_EDGE ) ) ||
4876
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ))) {
4880
/* 2. search for (-) atoms that are tautomeric but should not be */
4881
/* or that got H from Normalization but they shouldn't */
4882
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4883
iat = nCanon2AtnoRevrs[i];
4884
if ( at2[iat].charge == -1 &&
4885
!pStruct->endpoint[i] &&
4886
(at_Mobile_H_Revrs &&
4887
(at_Mobile_H_Revrs[i].endpoint || at2[iat].num_H < at_Mobile_H_Revrs[i].num_H )) ) {
4889
if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
4890
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) &&
4891
!pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
4893
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE ) ) ||
4894
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) )
4899
/* negatively charged atom in Reconstructed structure got H(+) from Normalization */
4900
/* and is not tautomeric; in the original structure it is tautomeric */
4901
if ( at2[iat].charge == -1 &&
4902
pStruct->endpoint[i] &&
4903
!(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) &&
4904
(num_Fixed_H_Revrs && num_Fixed_H_Revrs[i] == -1) &&
4905
(pnMobHRevrs && pnMobHRevrs[i] == 1) &&
4906
pStruct->fixed_H[i] == 0 ) {
4908
if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
4909
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) &&
4910
!pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
4912
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE ) ) ||
4913
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) )
4919
/* 3. Search for (-) atoms that are tautomeric */
4920
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
4921
iat = nCanon2AtnoRevrs[i];
4922
if ( pStruct->endpoint[i] &&
4923
(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) &&
4924
at2[iat].charge == -1
4925
/*&& pVA[i].cNumValenceElectrons == 6*/ ) {
4926
if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
4927
!pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
4928
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) &&
4929
( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_TAUT], e, INC_ADD_EDGE ) ) ) {
4934
/* ------- finally, try to move charges from O=N --------------*/
4935
for ( i = 0; i < num_DB_O; i ++ ) {
4936
int nDeltaChargeExpected;
4940
peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
4941
pe = pBNS->edge + pBNS->vert[iat].iedge[0];
4945
pv1 = pBNS->vert + (v1 = pe->neighbor1);
4946
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
4948
pe->forbidden |= forbidden_edge_mask;
4951
pv1->st_edge.flow -= delta;
4952
pv2->st_edge.flow -= delta;
4953
pBNS->tot_st_flow -= 2*delta;
4955
for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
4956
if ( !ChangeableEdges[k].num_edges ) {
4959
nDeltaChargeExpected = (k==CHG_SET_NOOH)? 2 : 0;
4961
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4962
RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask );
4963
/* allow (-) charge to move to N=O */
4964
peDB_O_Minus->forbidden &= forbidden_edge_mask_inv;
4966
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
4967
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
4969
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
4970
vPathEnd == v2 && vPathStart == v1) &&
4971
nDeltaCharge == nDeltaChargeExpected ) {
4972
/* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
4973
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
4976
one_success ++; /* 23 */
4981
cur_success += one_success;
4983
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
4984
pe->forbidden &= forbidden_edge_mask_inv;
4986
if ( !one_success ) {
4988
pv1->st_edge.flow += delta;
4989
pv2->st_edge.flow += delta;
4990
pBNS->tot_st_flow += 2*delta;
4995
for ( i = 0; i < CHG_SET_NUM; i ++ ) {
4996
AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
4999
CurrEdges.num_edges = 0; /* clear current edge list */
5000
if ( cur_success ) {
5001
tot_succes += cur_success;
5002
/* recalculate InChI from the structure */
5003
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
5004
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
5007
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
5010
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
5011
goto exit_function; /* no fixed-H found */
5013
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
5016
if ( !pc2i->bHasDifference ) {
5017
goto exit_function; /* nothing to do */
5021
#undef CHG_SET_WRONG_TAUT
5024
#undef CHG_SET_O_FIXED
5028
if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 ) {
5029
/*------------------------------------------------------------------*/
5030
/* case 24: InChI norm. -N(-)-N(+)(IV) => -N=N(V) prevents tauto- */
5031
/* merism on -N(-)- in case of ADP */
5033
/* Solution: convert N(V)=N- ...=X -> N(IV)(+)-N=...-X(-)*/
5034
/* N(IV)(+)-N(-)-...=X */
5036
/* Orig InChI taut taut, 1 t-group only(ADP?) */
5037
/* Reconstructed struct non-taut possibly not taut */
5039
/* Details: 1a. store next to N(V) (+)edge its flower edge */
5040
/* 1b. store next to N(-) edge NO_VERTEX */
5041
/* 2. Release (-) edges of other missing endpoints or */
5042
/* all endpoints if no other is missing */
5043
/* 3. Decrement flow on (+) edge */
5044
/* if flower edge is stored then expect DeltaCharge=2*/
5045
/* otherwise DeltaCharge = 0 */
5046
/*------------------------------------------------------------------*/
5048
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
5049
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
5050
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
5051
inp_ATOM *atf = (pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds)?
5052
pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
5053
int iN, one_success;
5056
#define CHG_SET_MISSED_TAUT 0
5057
#define CHG_SET_OTHER_TAUT_O 1
5058
#define CHG_SET_OTHER_TAUT_N 2
5059
#define CHG_LAST_SET 2 /* the last index in trying */
5060
#define CHG_SET_NN 3
5061
#define CHG_SET_AVOID 4
5062
#define CHG_SET_NUM 5
5063
EDGE_LIST ChangeableEdges[CHG_SET_NUM];
5064
memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
5065
/* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
5067
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
5068
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
5070
CurrEdges.num_edges = 0; /* clear current edge list */
5072
for ( i = 0; i < pc2i->len_c2at; i ++ ) {
5073
iat = pc2i->c2at[i].atomNumber;
5074
if ( /* orig. InChI info: -N=N(V) */
5075
pc2i->c2at[i].nValElectr == 5 /* N or P */ &&
5076
(pc2i->c2at[i].endptInChI /* only N */) &&
5077
(e1=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e1].forbidden &&
5078
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
5079
/* reversed structure info: */
5080
!pc2i->c2at[i].endptRevrs &&
5081
pc2i->c2at[i].nFixHRevrs == 0 &&
5082
pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
5083
at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3 &&
5084
/* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */
5085
(iN = at2[iat].neighbor[at2[iat].bond_type[0] != BOND_TYPE_DOUBLE],
5086
pVA[iN].cNumValenceElectrons == 5) &&
5087
at2[iN].chem_bonds_valence == 5 &&
5088
at2[iN].charge == 0 && !at2[iN].num_H && !at2[iN].radical &&
5089
0 <= (e=pVA[iN].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
5090
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) {
5092
ef = GetChargeFlowerUpperEdge( pBNS, pVA, e ); /* == NO_VERTEX if N(V) has 4 bonds */
5093
if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE )) ||
5094
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], ef, INC_ADD_EDGE )) ||
5095
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE )) || /* expected nDeltaCharge */
5096
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE )) ||
5097
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) ||
5098
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], ef, INC_ADD_EDGE ))) {
5101
/* mark -N= so that (-) will not be moved to it */
5102
if ( 0 <= (e = pVA[iat].nCMinusGroupEdge) && !pBNS->edge[e].forbidden &&
5103
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) &&
5104
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ))) {
5108
if ( /* orig. InChI info: -N(-)N(IV)(+) */
5110
pc2i->c2at[i].nValElectr == 5 /* N or P */ &&
5111
pc2i->c2at[i].endptInChI /* only N */ &&
5112
(e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
5113
pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
5114
/* reversed structure info: */
5115
!pc2i->c2at[i].endptRevrs &&
5116
pc2i->c2at[i].nFixHRevrs == 0 &&
5117
pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H &&
5118
at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 2 &&
5119
atf[iat].valence == 2 && atf[iat].chem_bonds_valence == 3 &&
5120
/* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */
5121
(iN=atf[iat].neighbor[atf[iat].bond_type[0] != BOND_TYPE_DOUBLE],
5122
pVA[iN].cNumValenceElectrons == 5) &&
5123
at2[iN].charge == 1 && /* double bond neighbor */
5124
at2[iN].chem_bonds_valence == 4 &&
5125
atf[iN].charge == 0 &&
5126
atf[iN].chem_bonds_valence == 5 && /* InChI normalization created N(V)=N- out of N(IV)(+)-N(-)- */
5127
!at2[iN].num_H && !at2[iN].radical &&
5128
0 <= (e=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
5129
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
5131
if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE )) ||
5132
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], NO_VERTEX, INC_ADD_EDGE )) ||
5133
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE )) || /* expected nDeltaCharge */
5134
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ))) {
5139
if ( !ChangeableEdges[CHG_SET_NN].num_edges ) {
5142
/* Collect all relevant tautomeric atoms */
5143
for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
5144
if ( !pStruct->endpoint[i] ) {
5147
iat = nCanon2AtnoRevrs[i];
5148
if ( at2[iat].charge || at2[iat].radical || at2[iat].valence == at2[iat].chem_bonds_valence ) {
5149
continue; /* cannot be an acceptor of (-) */
5151
if ( 0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow ) {
5154
if ( 0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
5155
continue; /* has already been used */
5157
/* missing endpoint */
5158
if ( !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) ) {
5159
if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && (
5160
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT], e, INC_ADD_EDGE )) ||
5161
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))) {
5166
if ( pVA[iat].cNumValenceElectrons == 6 ) {
5167
if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && (
5168
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_O], e, INC_ADD_EDGE )) ||
5169
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))){
5174
if ( pVA[iat].cNumValenceElectrons == 5 ) {
5175
if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && (
5176
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_N], e, INC_ADD_EDGE )) ||
5177
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))){
5182
/* ------- finally, try to move charges from -N(-)-N(+) or to N(V) --------------*/
5183
for ( i = 0; i < ChangeableEdges[CHG_SET_NN].num_edges; i += 3 ) {
5184
int nDeltaChargeExpected;
5187
pe = pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i];
5188
pef = (NO_VERTEX != ChangeableEdges[CHG_SET_NN].pnEdges[i+1])?
5189
pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i+1] : NULL;
5190
nDeltaChargeExpected = ChangeableEdges[CHG_SET_NN].pnEdges[i+2];
5194
pv1 = pBNS->vert + (v1 = pe->neighbor1);
5195
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
5198
pv1->st_edge.flow -= delta;
5199
pv2->st_edge.flow -= delta;
5200
pBNS->tot_st_flow -= 2*delta;
5202
for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
5203
if ( !ChangeableEdges[k].num_edges ) {
5206
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
5207
RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask );
5208
/* allow change of N(V) flower edge */
5210
pef->forbidden &= forbidden_edge_mask_inv;
5213
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
5214
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
5216
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
5217
vPathEnd == v2 && vPathStart == v1) &&
5218
nDeltaCharge == nDeltaChargeExpected ) {
5219
/* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
5220
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
5223
one_success ++; /* 24 */
5228
cur_success += one_success;
5230
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
5232
if ( !one_success ) {
5234
pv1->st_edge.flow += delta;
5235
pv2->st_edge.flow += delta;
5236
pBNS->tot_st_flow += 2*delta;
5240
for ( i = 0; i < CHG_SET_NUM; i ++ ) {
5241
AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
5244
CurrEdges.num_edges = 0; /* clear current edge list */
5245
if ( cur_success ) {
5246
tot_succes += cur_success;
5247
/* recalculate InChI from the structure */
5248
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
5249
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
5252
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
5255
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
5256
goto exit_function; /* no fixed-H found */
5258
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
5261
if ( !pc2i->bHasDifference ) {
5262
goto exit_function; /* nothing to do */
5266
#undef CHG_SET_MISSED_TAUT
5267
#undef CHG_SET_OTHER_TAUT_O
5268
#undef CHG_SET_OTHER_TAUT_N
5270
#undef CHG_SET_AVOID
5274
/* pStruct->nNumRemovedProtonsMobHInChI == pc2i->nNumRemHInChI */
5276
if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 &&
5277
pc2i->nNumRemHRevrs > pc2i->nNumRemHInChI && 0 > pc2i->nNumRemHInChI &&
5278
(pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI ||
5279
pc2i->nNumTgRevrs > pc2i->nNumTgInChI ) ) {
5280
/*------------------------------------------------------------------*/
5281
/* case 25: Restored InChI does not have 2 or more added protons */
5282
/* possibly taut. endpoints are missing */
5283
/* has -N(-O(-))-O(-) group(s) */
5284
/* Original InChI has only one t-group */
5286
/* Solution: convert -N(-O(-))-O(-) -> -N(+)(=O)-O(-) */
5287
/* and direct 2(-) to the missing taut atoms*/
5288
/* at first attempt try to move (-) to N only */
5290
/*------------------------------------------------------------------*/
5292
AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
5293
AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
5294
inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
5295
pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
5297
inp_ATOM *atf = (pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds)?
5298
pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
5300
int iN, neigh, one_success;
5301
EdgeIndex e1, bFirst;
5303
#define CHG_SET_MISSED_TAUT_1 0
5304
#define CHG_SET_MISSED_TAUT_ALL 1
5305
#define CHG_SET_OTHER_TAUT_1 2
5306
#define CHG_SET_OTHER_TAUT_ALL 3
5307
#define CHG_LAST_SET 3 /* the last index in trying */
5308
#define CHG_SET_NO_IN_NO2M2 4
5309
#define CHG_SET_AVOID 5
5310
#define CHG_SET_NUM 6
5311
EDGE_LIST ChangeableEdges[CHG_SET_NUM];
5312
memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
5313
/* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
5315
S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
5316
pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
5318
CurrEdges.num_edges = 0; /* clear current edge list */
5320
/* find all -N(-O(-))-O(-) */
5321
for ( i = 0; i < pStruct->num_atoms; i ++ ) {
5322
iat = nCanon2AtnoRevrs[i];
5323
if ( pStruct->endpoint[i] ) {
5324
if ( 0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden ||
5325
0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
5328
bFirst = ( pVA[iat].cNumValenceElectrons == 5 && pc2i->nNumTgInChI == 1 ||
5329
pVA[iat].cNumValenceElectrons == 6 && pc2i->nNumTgInChI != 1 );
5330
/* many or no t-groups -> try O only first */
5331
/* single t-group -> try only N first */
5332
if ( !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) ) {
5333
/* missed tautomeric endpoint */
5335
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_1], e, INC_ADD_EDGE ))) {
5338
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_ALL], e, INC_ADD_EDGE )) {
5343
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_1], e, INC_ADD_EDGE ))) {
5346
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_ALL], e, INC_ADD_EDGE )) {
5349
if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) {
5353
if ( at2[iat].valence == 1 && at2[iat].charge == -1 &&
5354
pVA[iat].cNumValenceElectrons == 6 &&
5355
pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 && /* -O(-) */
5356
!pStruct->endpoint[nAtno2CanonRevrs[iN]] &&
5357
at2[iN].valence == 3 && at2[iN].chem_bonds_valence == 3 &&
5358
!at2[iN].charge && !at2[iN].radical &&
5359
0 <= (e=pVA[iN].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden &&
5360
pBNS->edge[e].flow && /* NPlus edge */
5361
0 <= (e1 = pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e1].forbidden &&
5362
pBNS->edge[e1].flow && /* OMinus edge */
5363
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) &&
5364
0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1 )) {
5366
int nNumO = 0, nNumOthers = 0;
5367
for ( k = 0; k < at2[iN].valence; k ++ ) {
5368
neigh = at2[iN].neighbor[k];
5369
if ( neigh == iat ) {
5372
if ( pVA[neigh].cNumValenceElectrons == 6 &&
5373
!pStruct->endpoint[neigh] &&
5374
at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
5375
at2[neigh].radical == 0 && at2[neigh].charge == -1 &&
5376
at2[neigh].chem_bonds_valence == 1 ) {
5379
if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
5380
at2[neigh].valence > 1 &&
5381
at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
5385
if ( nNumO != 1 && nNumOthers != 1 ) {
5388
/* save charge edges: NPlus first, OMinus second */
5389
if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e, INC_ADD_EDGE )) ||
5390
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e1, INC_ADD_EDGE )) ||
5391
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) ||
5392
(ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE ))) {
5397
if ( !ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges ||
5398
!ChangeableEdges[CHG_SET_OTHER_TAUT_ALL].num_edges ) {
5401
/* ------- finally, try to move charges from -NO2(2-) or to tautomeric endpoints ----*/
5402
for ( i = 0; i < ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges; i += 2 ) {
5403
int nDeltaChargeExpected = 3;
5404
/* change flow on O(-) to make it neutral; 3 new charges will be created:
5405
N(+), and two (-) on InChI endpoints
5406
alternatively, if we change flow on N to make N(+) then O(-) will
5407
be nutralized (-1 charge) and two (-) charges on taut. endpoints will be
5408
created (+2); the total change in this case would be (-1)+(+2) = +1
5412
pe = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i+1]; /* O(-) edge */
5413
pef = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i]; /* >N- (+) edge */
5417
pv1 = pBNS->vert + (v1 = pe->neighbor1);
5418
pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
5421
pv1->st_edge.flow -= delta;
5422
pv2->st_edge.flow -= delta;
5423
pBNS->tot_st_flow -= 2*delta;
5425
for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
5426
if ( !ChangeableEdges[k].num_edges ) {
5429
SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
5430
RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask );
5431
/* allow change of N(V) flower edge */
5432
pef->forbidden &= forbidden_edge_mask_inv;
5434
ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
5435
&nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
5437
if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
5438
vPathEnd == v2 && vPathStart == v1) &&
5439
nDeltaCharge == nDeltaChargeExpected ) {
5440
/* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
5441
ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
5444
one_success ++; /* 24 */
5449
cur_success += one_success;
5451
RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
5453
if ( !one_success ) {
5455
pv1->st_edge.flow += delta;
5456
pv2->st_edge.flow += delta;
5457
pBNS->tot_st_flow += 2*delta;
5461
for ( i = 0; i < CHG_SET_NUM; i ++ ) {
5462
AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
5465
CurrEdges.num_edges = 0; /* clear current edge list */
5466
if ( cur_success ) {
5467
tot_succes += cur_success;
5468
/* recalculate InChI from the structure */
5469
if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
5470
ppt_group_info, ppat_norm, ppat_prep ) ) ) {
5473
if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
5476
if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
5477
goto exit_function; /* no fixed-H found */
5479
if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
5482
if ( !pc2i->bHasDifference ) {
5483
goto exit_function; /* nothing to do */
5487
#undef CHG_SET_MISSED_TAUT
5488
#undef CHG_SET_OTHER_TAUT_O
5489
#undef CHG_SET_OTHER_TAUT_N
5491
#undef CHG_SET_AVOID
5497
AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
5498
AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
5499
AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
5500
AllocEdgeList( &SFlowerEdges, EDGE_LIST_FREE );
5501
AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
5502
AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_FREE );
5503
AllocEdgeList( &AllBondEdges, EDGE_LIST_FREE );
5504
return ret < 0? ret : (pc2i->bHasDifference && tot_succes);