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