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